📄 channelifaceimpl.java
字号:
} //unreferenced() /** * a ref to the wrapped instance is stored here */ transient Object instance; /** * the cookie associated with the stub. it is derived from the 'global' one and can be * propagated to all the stubs created during a single remote method invocation. */ transient private Object _cookie; /** * an array of the interfaces implemented by the <code>instance</code> is cached here * This member is constructed within <code>buildInterfacesTable</code> method and * it is not a subject of modification during the lifetime of the stub. */ String[] interfaces = null; /** * the same kind of cache as the above one, but instead of the names, we keep * the actual <code>Class</code> objects of the implemented interfaces */ Class[] ifaceClasses = null; /** * a private method in which all the super classes are traversed up to the * <code>Object</code> class and all implemented interfaces are collected */ private void buildInterfacesTable() { // an dynamic storage for the classes and ther names Vector supers = new Vector(); Vector superClasses = new Vector(); // we start from the exact instance Class Class current = instance.getClass(); // loop down until we reach the Object while (!current.equals(Object.class)) { // get all the implemented interfaces by this class // these are usually ones found after the 'implements' clause of the class declatarion Class[] ifaces = current.getInterfaces(); for (int i = 0; i < ifaces.length; i++) { // keep them all Class[] ifP = ifaces[i].getInterfaces(); if (ifP != null) { for (int j = 0; j < ifP.length; j++) { if (!supers.contains(ifP[j].getName())) { supers.add(ifP[j].getName()); superClasses.add(ifP[j]); } } } if (!supers.contains(ifaces[i].getName())) { supers.add(ifaces[i].getName()); superClasses.add(ifaces[i]); } } // move down the hirarch chain current = current.getSuperclass(); } // while (class chain) // build the Array storages an dfill them interfaces = new String[supers.size()]; ifaceClasses = new Class[supers.size()]; int i3=0; for (Iterator i = supers.iterator(); i.hasNext(); i3++) { interfaces[i3] = (String)i.next(); ifaceClasses[i3] = (Class)superClasses.get(i3); } // for } //buildInterfacesTable /** * the only constructor availible. it is <code>protected</code> and * so the only way to obtain some instances is through the static <code>createStub()</code> method * * @param instance which is about to be wrapped */ protected ChannelIfaceImpl(Object instance) { // keep the instance this.instance = instance; // fint teh inmlemented interfaces buildInterfacesTable(); // and store the current cookie fro later reference this._cookie = getCurrentCookie(); } //ChannelIfaceImpl /** * <code>getInterfaces<code> is used by the client to obtain a list of the implemented, * by the wrapped instance, interfaces . This list is used to create a dynamic * proxy ont the client side, which is used to invoke any of the methods declared * within these interfaces. * @return an array of Strings with the class names of the implemented interfaces * @throws RemoteException */ public String[] getInterfaces() throws RemoteException { return interfaces; } /** * invoke - invokes a method of an 'instance' via reflection * @param methodDescription a description of the method being invoked * @param args - parameters opassed to the method during the call * @return the result of the invocation or null if the method returns 'void' * @throws RemoteException */ public Object invoke(Object methodDescription, Object[]args) throws RemoteException { // set the thread cookie setCurrentCookie(_cookie); // parse the chat array which holds the method description // as you can see the buffer starts with the name of the method // followed by all the class names of its arguments separated by '|' character java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(new String((char[])methodDescription), "|", false); // a class array used for the method lookup Class[] paramTypes = null; if (args != null) paramTypes = new Class[args.length]; else paramTypes = new Class[0]; //at least one token should be present in the descr. - the method name // keep track of all arguments which are proxies itself so to flush their // batch- job queues. see the 'batch' method description for more on 'batch' jobs Vector batchedParams = new Vector(); final String methodName = tokenizer.nextToken(); try { int i=0; // loop through the tokens forun in the description while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); try { // try to resolve the class by the passed name paramTypes[i] = Class.forName(token); } catch (ClassNotFoundException e) { // not found - probably it is a native type so try to looku in the // 'primitiveTypes' map Object oClass = primitiveTypes.get(token); // in case we do not found it there we shoud rise the 'ClassNotFound' exception. if (oClass == null) throw e; // keep the rsolved class into the param lookup array paramTypes[i] = (Class)oClass; } // catch class not found // let chek if it is a proxy created by the server in some previous moment. // we just lookup them into the associations kept in 'map' member if (args[i] instanceof ChannelIface) { ChannelIface tryAsLocal = getRef((Remote)args[i]); if (tryAsLocal != null) { // we found it there. how lucky we are so pass its wraped the instance directly // instead of its remote wraper if (tryAsLocal instanceof ChannelIfaceImpl) args[i] = ((ChannelIfaceImpl)tryAsLocal).instance; } else { // hmm ... missing - at least we should wrap it in order to args[i] = ChannelIfaceInvocation.wrapIt(args[i]); // because the server can invoke some batchable methods we need to // remember that particular instance so to flush the batchjob queue // right after the server complete the method if (args[i] instanceof Proxy) batchedParams.add(Proxy.getInvocationHandler(args[i])); } } i++; } // if there is an registered prolog action and we have a 'good' cookie to pass // do that the prolog action if (aProlog != null && _cookie != null) { aProlog.doRoutingAction(_cookie); }// Method m = instance.getClass().getMethod(methodName, paramTypes);// m.setAccessible(true); // try to find the method description from the supportrd interfaces. This is made // because the exact instance class can be 'inaccessible' - e.g. with non-public // in such a case we cannot invoke its methods from here, but if we get the // right method from an inmplemented by the instance interface, we safely can invoke it // through reflection. Method m = null; for (int ifaceCount = 0; ifaceCount < ifaceClasses.length; ifaceCount++) { try{ m = ifaceClasses[ifaceCount].getMethod(methodName, paramTypes); } catch (NoSuchMethodException _nsme){ m = null;} if (m != null) { break; } } if (m == null) { // let's check if at least, Object.class has such signature m = Object.class.getMethod(methodName, paramTypes); // if we are unlucky let's thge Exception go up so the user should know } // finally we can invoke it and collect its return value Object result = null;// try { result = m.invoke(instance, args);// } catch (Error e) {// e.printStackTrace();// throw new RuntimeException("Server's Error:"+e.getMessage());// } // if we have some Proxy parameters passed, ensure that their // batched queues are flushed now Iterator iter = batchedParams.iterator(); while (iter.hasNext()) { ChannelIfaceInvocation obj = (ChannelIfaceInvocation)iter.next(); //flush the queue of that argument instance obj.addJob(null); } batchedParams.clear(); batchedParams = null; // if there is an registered epilog action - invoke it with the our current cookie if (anEpilog != null && _cookie != null) { anEpilog.doRoutingAction(_cookie); } // let explore the result a bit. If it do not implement Remote or Serializable // or it is not a natiove one - we can create a stub and return it instead if (result != null && false == result instanceof Remote && false == result.getClass().isPrimitive() && false == result instanceof java.io.Serializable) { result = ChannelIfaceImpl.createStub(result); } // if it is a wrapped proxy - e.g. it was wraped because it is not our for example // unwrap and return the remote iinstance instead. This way we avoid the possability // to wrap an instance multiple times if (result instanceof Proxy) { InvocationHandler iH = Proxy.getInvocationHandler(result); if (iH instanceof ChannelIfaceInvocation) result = ((ChannelIfaceInvocation)iH).remoteInstance; } return result; } catch (InvocationTargetException t) { // if the reflection do not goes smootly - wrap the 'cause' so the client to be // able to find out what was went wrong throw new RemoteException("While invoking "+methodName, t.getCause()); } catch (Exception t) { // in case of any 'normal' exception - route it to client by // wraping it into a remote one - so it can be safely unwraped at client side throw new RemoteException("While invoking "+methodName, t); } // note that only the Exceptions are routed back to the client // so eny Error - derived exception shouldn;t be catched by that code } //invoke /** * <code>gotFinalized()</code> used by the client to notify this stub thet it was * being 'garbage collected' at client side so we ca be quite sure that the * association between this stub and the wraped instance can be safely removed from the storage map * @throws RemoteException */ public void gotFinalized() throws RemoteException { unreferenced(); } /** * here we got the tricky part. * The method <code>batch</code> is used to pass a bunch of methods * that needs to be invoked by this stub with just one RMI call. In such a way we can reduce * the network traffic and long delays because of the time needed by the RMI * to complete a single method call. * Not all invoked methods can be a subject of such batching. We decide to * batch only methods that return 'void' and their arguments are either Serializable * or just a native ones (e.g. char, byte, long, etc.) * the client proxy can decide while it shoud commit the 'batchJob' queue. This * usually can happen if a 'non-void' method or a method with non-Seralizable' or native * arguments is being invoked. In such a case first the queue is flushed and the * that method is passed to the stub here. In order to enable this functionality the wrapped * instance should implement <code>Batchable</code> interface. * * @param jobs an array of Job objects that we need to process at once * each Job object has the method description and array arguments use so wen can invoke it directly * @throws RemoteException that can wrap any of the exception conditions found during the execution */ public void batch(Object[] jobs) throws RemoteException { for (int i = 0; i < jobs.length; i++) { Job job = (Job)jobs[i]; java.io.ByteArrayInputStream buf = new java.io.ByteArrayInputStream(job.serializedArgs);// java.io.BufferedInputStream bufinput = new java.io.BufferedInputStream(buf, 1024); Object[] args = null; try { java.io.ObjectInputStream inputStream = new java.io.ObjectInputStream(buf); args = (Object[])inputStream.readObject(); } catch (ClassNotFoundException ec) { ec.printStackTrace(); } catch (java.io.IOException e) { // should throw na exception here e.printStackTrace(); }// finally {// try {// bufinput.close();// buf.close();// } catch (java.io.IOException eee) {}// } invoke(job.methodDescription, args); } }//batch} //ChannelIfaceImpl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -