/* * Fix for 4149366: so that downloaded parameter types unmarshalled * for this impl will be compatible with types known only to the * impl class's class loader (when it's not identical to the * exporting thread's context class loader), mark the impl's class * loader as the loader to use as the context class loader in the * server's dispatch thread while a call to this impl is being * processed (unless this exporting thread's context class loader is * a child of the impl's class loader, such as when a registry is * exported by an application, in which case this thread's context * class loader is preferred). */ ClassLoaderthreadContextLoader= Thread.currentThread().getContextClassLoader(); ClassLoaderserverLoader= impl.getClass().getClassLoader(); if (checkLoaderAncestry(threadContextLoader, serverLoader)) { this.ccl = threadContextLoader; } else { this.ccl = serverLoader; }
this.permanent = permanent; if (permanent) { pinImpl(); } }
if (server == null) { if (tcpLog.isLoggable(Log.BRIEF)) { tcpLog.log(Log.BRIEF, "(port " + port + ") create server socket"); }
try { server = ep.newServerSocket(); /* * Don't retry ServerSocket if creation fails since * "port in use" will cause export to hang if an * RMIFailureHandler is not installed. */ Threadt= AccessController.doPrivileged( newNewThreadAction(newAcceptLoop(server), "TCP Accept-" + port, true)); t.start(); } catch (java.net.BindException e) { thrownewExportException("Port already in use: " + port, e); } catch (IOException e) { thrownewExportException("Listen failed on port: " + port, e); }
} else { // otherwise verify security access to existing server socket SecurityManagersm= System.getSecurityManager(); if (sm != null) { sm.checkListen(port); } } }
if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) { DGCImpl.dgcLog.log(Log.VERBOSE, "add object " + oe); }
synchronized (tableLock) { /** * Do nothing if impl has already been collected (see 6597112). Check while * holding tableLock to ensure that Reaper cannot process weakImpl in between * null check and put/increment effects. */ if (target.getImpl() != null) { if (objTable.containsKey(oe)) { thrownewExportException( "internal error: ObjID already in use"); } elseif (implTable.containsKey(weakImpl)) { thrownewExportException("object already exported"); }
privatevoidsetup(UnicastServerRef uref) throws RemoteException { /* Server ref must be created and assigned before remote * object 'this' can be exported. */ ref = uref; uref.exportObject(this, null, true); }
/* Make sure to use the local stub loader for the stub classes. * When loaded by the local loader the load path can be * propagated to remote clients, by the MarshalOutputStream/InStream * pickle methods */ try { Class<?> stubcl = Class.forName(stubname, false, remoteClass.getClassLoader()); Constructor<?> cons = stubcl.getConstructor(stubConsParamTypes); return (RemoteStub) cons.newInstance(newObject[] { ref });
} catch (ClassNotFoundException e) { thrownewStubNotFoundException( "Stub class not found: " + stubname, e); } catch (NoSuchMethodException e) { thrownewStubNotFoundException( "Stub class missing constructor: " + stubname, e); } catch (InstantiationException e) { thrownewStubNotFoundException( "Can't create instance of stub class: " + stubname, e); } catch (IllegalAccessException e) { thrownewStubNotFoundException( "Stub class constructor not public: " + stubname, e); } catch (InvocationTargetException e) { thrownewStubNotFoundException( "Exception creating instance of stub class: " + stubname, e); } catch (ClassCastException e) { thrownewStubNotFoundException( "Stub class not instance of RemoteStub: " + stubname, e); } }
publicvoidsetSkeleton(Remote impl)throws RemoteException { if (!withoutSkeletons.containsKey(impl.getClass())) { try { skel = Util.createSkeleton(impl); } catch (SkeletonNotFoundException e) { /* * Ignore exception for skeleton class not found, because a * skeleton class is not necessary with the 1.2 stub protocol. * Remember that this impl's class does not have a skeleton * class so we don't waste time searching for it again. */ withoutSkeletons.put(impl.getClass(), null); } } }
static Skeleton createSkeleton(Remote object) throws SkeletonNotFoundException { Class<?> cl; try { cl = getRemoteClass(object.getClass()); } catch (ClassNotFoundException ex ) { thrownewSkeletonNotFoundException( "object does not implement a remote interface: " + object.getClass().getName()); }
// now try to load the skeleton based ont he name of the class Stringskelname= cl.getName() + "_Skel"; try { Class<?> skelcl = Class.forName(skelname, false, cl.getClassLoader());
if (host == null || host.length() == 0) { // If host is blank (as returned by "file:" URL in 1.0.2 used in // java.rmi.Naming), try to convert to real local host name so // that the RegistryImpl's checkAccess will not fail. try { host = java.net.InetAddress.getLocalHost().getHostAddress(); } catch (Exception e) { // If that failed, at least try "" (localhost) anyway... host = ""; } }
/* * Create a proxy for the registry with the given host, port, and * client socket factory. If the supplied client socket factory is * null, then the ref type is a UnicastRef, otherwise the ref type * is a UnicastRef2. If the property * java.rmi.server.ignoreStubClasses is true, then the proxy * returned is an instance of a dynamic proxy class that implements * the Registry interface; otherwise the proxy returned is an * instance of the pregenerated stub class for RegistryImpl. **/ LiveRefliveRef= newLiveRef(newObjID(ObjID.REGISTRY_ID), newTCPEndpoint(host, port, csf, null), false); RemoteRefref= (csf == null) ? newUnicastRef(liveRef) : newUnicastRef2(liveRef);
} catch (RemoteException e) { /* * Call did not complete; connection can't be reused. */ clientRefLog.log(Log.BRIEF, "exception: ", e); free(call, false); throw e;
} catch (Error e) { /* If errors occurred, the connection is most likely not * reusable. */ clientRefLog.log(Log.BRIEF, "error: ", e); free(call, false); throw e;
} catch (RuntimeException e) { /* * REMIND: Since runtime exceptions are no longer wrapped, * we can't assue that the connection was left in * a reusable state. Is this okay? */ clientRefLog.log(Log.BRIEF, "exception: ", e); free(call, false); throw e;
} catch (Exception e) { /* * Assume that these other exceptions are user exceptions * and leave the connection in a reusable state. */ clientRefLog.log(Log.BRIEF, "exception: ", e); free(call, true); /* reraise user (and unknown) exceptions. */ throw e; }
/* * Don't free the connection if an exception did not * occur because the stub needs to unmarshal the * return value. The connection will be freed * by a call to the "done" method. */ }
// read return value switch (returnType) { case TransportConstants.NormalReturn: break;
case TransportConstants.ExceptionalReturn: Object ex; try { ex = in.readObject(); } catch (Exception e) { thrownewUnmarshalException("Error unmarshaling return", e); }
// An exception should have been received, // if so throw it, else flag error if (ex instanceof Exception) { exceptionReceivedFromServer((Exception) ex); } else { thrownewUnmarshalException("Return type not Exception"); } // Exception is thrown before fallthrough can occur default: if (Transport.transportLog.isLoggable(Log.BRIEF)) { Transport.transportLog.log(Log.BRIEF, "return code invalid: " + returnType); } thrownewUnmarshalException("Return code invalid"); } }
这个方法用来处理返回的数据,主要和网络相关,我们不需要特别深入研究,不过值得注意的是
1 2 3 4 5 6 7 8 9 10 11
switch (returnType) { case TransportConstants.NormalReturn: break;
case TransportConstants.ExceptionalReturn: Object ex; try { ex = in.readObject(); } catch (Exception e) { thrownewUnmarshalException("Error unmarshaling return", e); }
/* StreamRemoteCall.done() does not actually make use * of conn, therefore it is safe to reuse this * connection before the dirty call is sent for * registered refs. */ ObjectreturnValue= unmarshalValue(rtype, in);
/* we are freeing the connection now, do not free * again or reuse. */ alreadyFreed = true;
/* if we got to this point, reuse must have been true. */ clientRefLog.log(Log.BRIEF, "free connection (reuse = true)");
/* Free the call's connection early. */ ref.getChannel().free(conn, true);
thrownewUnmarshalException("error unmarshalling return", e); } finally { try { call.done(); } catch (IOException e) { /* WARNING: If the conn has been reused early, * then it is too late to recover from thrown * IOExceptions caught here. This code is relying * on StreamRemoteCall.done() not actually * throwing IOExceptions. */ reuse = false; } }
} catch (RuntimeException e) { /* * Need to distinguish between client (generated by the * invoke method itself) and server RuntimeExceptions. * Client side RuntimeExceptions are likely to have * corrupted the call connection and those from the server * are not likely to have done so. If the exception came * from the server the call connection should be reused. */ if ((call == null) || (((StreamRemoteCall) call).getServerException() != e)) { reuse = false; } throw e;
} catch (RemoteException e) { /* * Some failure during call; assume connection cannot * be reused. Must assume failure even if ServerException * or ServerError occurs since these failures can happen * during parameter deserialization which would leave * the connection in a corrupted state. */ reuse = false; throw e;
} catch (Error e) { /* If errors occurred, the connection is most likely not * reusable. */ reuse = false; throw e;
} finally {
/* alreadyFreed ensures that we do not log a reuse that * may have already happened. */ if (!alreadyFreed) { if (clientRefLog.isLoggable(Log.BRIEF)) { clientRefLog.log(Log.BRIEF, "free connection (reuse = " + reuse + ")"); } ref.getChannel().free(conn, reuse); } } }
// if calls are being logged, write out exception if (UnicastServerRef.callLog.isLoggable(Log.BRIEF)) { // include client host name if possible StringclientHost=""; try { clientHost = "[" + RemoteServer.getClientHost() + "] "; } catch (ServerNotActiveException ex) { } Stringmessage= clientHost + "exception: "; UnicastServerRef.callLog.log(Log.BRIEF, message, e); }
/* We will get a RemoteException if either a) the objID is * not readable, b) the target is not in the object table, or * c) the object is in the midst of being unexported (note: * NoSuchObjectException is thrown by the incrementCallCount * method if the object is being unexported). Here it is * relatively safe to marshal an exception to the client * since the client will not have seen a return value yet. */ try { ObjectOutputout= call.getResultStream(false); UnicastServerRef.clearStackTraces(e); out.writeObject(e); call.releaseOutputStream();
publicvoiddispatch(Remote obj, RemoteCall call)throws IOException { // positive operation number in 1.1 stubs; // negative version number in 1.2 stubs and beyond... int num; long op;
try { // read remote call header ObjectInput in; try { in = call.getInputStream(); num = in.readInt(); if (num >= 0) { if (skel != null) { oldDispatch(obj, call, num); return; } else { thrownewUnmarshalException( "skeleton class not found but required " + "for client version"); } } op = in.readLong(); } catch (Exception readEx) { thrownewUnmarshalException("error unmarshalling call header", readEx); } ......
// if calls are being logged, write out object id and operation logCall(obj, skel.getOperations()[op]); unmarshalCustomCallData(in); // dispatch to skeleton for remote object skel.dispatch(obj, call, op, hash);
} catch (Throwable e) { logCallException(e);
ObjectOutputout= call.getResultStream(false); if (e instanceof Error) { e = newServerError( "Error occurred in server thread", (Error) e); } elseif (e instanceof RemoteException) { e = newServerException( "RemoteException occurred in server thread", (Exception) e); } if (suppressStackTraces) { clearStackTraces(e); } out.writeObject(e); } finally { call.releaseInputStream(); // in case skeleton doesn't call.releaseOutputStream(); } }
publicvoiddispatch(Remote obj, RemoteCall call)throws IOException { // positive operation number in 1.1 stubs; // negative version number in 1.2 stubs and beyond... int num; long op;
try { // read remote call header ObjectInput in; try { in = call.getInputStream(); num = in.readInt(); if (num >= 0) { if (skel != null) { oldDispatch(obj, call, num); return; } else { thrownewUnmarshalException( "skeleton class not found but required " + "for client version"); } } op = in.readLong(); } catch (Exception readEx) { thrownewUnmarshalException("error unmarshalling call header", readEx); } ......
if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) { DGCImpl.dgcLog.log(Log.VERBOSE, "add object " + oe); }
synchronized (tableLock) { /** * Do nothing if impl has already been collected (see 6597112). Check while * holding tableLock to ensure that Reaper cannot process weakImpl in between * null check and put/increment effects. */ if (target.getImpl() != null) { if (objTable.containsKey(oe)) { thrownewExportException( "internal error: ObjID already in use"); } elseif (implTable.containsKey(weakImpl)) { thrownewExportException("object already exported"); }
static { /* * "Export" the singleton DGCImpl in a context isolated from * the arbitrary current thread context. */ AccessController.doPrivileged(newPrivilegedAction<Void>() { public Void run() { ClassLoadersavedCcl= Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( ClassLoader.getSystemClassLoader());
/* * Put remote collector object in table by hand to prevent * listen on port. (UnicastServerRef.exportObject would * cause transport to listen.) */ try { dgc = newDGCImpl(); ObjIDdgcID=newObjID(ObjID.DGC_ID); LiveRefref=newLiveRef(dgcID, 0); UnicastServerRefdisp=newUnicastServerRef(ref); Remotestub= Util.createProxy(DGCImpl.class, newUnicastRef(ref), true); disp.setSkeleton(dgc);