1 /* 2 * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.rmi.transport; 27 28 import java.io.IOException; 29 import java.io.ObjectOutput; 30 import java.rmi.MarshalException; 31 import java.rmi.NoSuchObjectException; 32 import java.rmi.Remote; 33 import java.rmi.RemoteException; 34 import java.rmi.server.LogStream; 35 import java.rmi.server.ObjID; 36 import java.rmi.server.RemoteCall; 37 import java.rmi.server.RemoteServer; 38 import java.rmi.server.ServerNotActiveException; 39 import java.security.AccessControlContext; 40 import sun.rmi.runtime.Log; 41 import sun.rmi.server.Dispatcher; 42 import sun.rmi.server.UnicastServerRef; 43 44 /** 45 * Transport abstraction for enabling communication between different 46 * VMs. 47 * 48 * @author Ann Wollrath 49 */ 50 public abstract class Transport { 51 52 /** "transport" package log level */ 53 static final int logLevel = LogStream.parseLevel(getLogLevel()); 54 55 private static String getLogLevel() { 56 return java.security.AccessController.doPrivileged( 57 new sun.security.action.GetPropertyAction("sun.rmi.transport.logLevel")); 58 } 59 60 /* transport package log */ 61 static final Log transportLog = 62 Log.getLog("sun.rmi.transport.misc", "transport", Transport.logLevel); 63 64 /** References the current transport when a call is being serviced */ 65 private static final ThreadLocal currentTransport = new ThreadLocal(); 66 67 /** ObjID for DGCImpl */ 68 private static final ObjID dgcID = new ObjID(ObjID.DGC_ID); 69 70 /** 71 * Returns a <I>Channel</I> that generates connections to the 72 * endpoint <I>ep</I>. A Channel is an object that creates and 73 * manages connections of a particular type to some particular 74 * address space. 75 * @param ep the endpoint to which connections will be generated. 76 * @return the channel or null if the transport cannot 77 * generate connections to this endpoint 78 */ 79 public abstract Channel getChannel(Endpoint ep); 80 81 /** 82 * Removes the <I>Channel</I> that generates connections to the 83 * endpoint <I>ep</I>. 84 */ 85 public abstract void free(Endpoint ep); 86 87 /** 88 * Export the object so that it can accept incoming calls. 89 */ 90 public void exportObject(Target target) throws RemoteException { 91 target.setExportedTransport(this); 92 ObjectTable.putTarget(target); 93 } 94 95 /** 96 * Invoked when an object that was exported on this transport has 97 * become unexported, either by being garbage collected or by 98 * being explicitly unexported. 99 **/ 100 protected void targetUnexported() { } 101 102 /** 103 * Returns the current transport if a call is being serviced, otherwise 104 * returns null. 105 **/ 106 static Transport currentTransport() { 107 return (Transport) currentTransport.get(); 108 } 109 110 /** 111 * Verify that the current access control context has permission to accept 112 * the connection being dispatched by the current thread. The current 113 * access control context is passed as a parameter to avoid the overhead of 114 * an additional call to AccessController.getContext. 115 */ 116 protected abstract void checkAcceptPermission(AccessControlContext acc); 117 118 /** 119 * Service an incoming remote call. When a message arrives on the 120 * connection indicating the beginning of a remote call, the 121 * threads are required to call the <I>serviceCall</I> method of 122 * their transport. The default implementation of this method 123 * locates and calls the dispatcher object. Ordinarily a 124 * transport implementation will not need to override this method. 125 * At the entry to <I>tr.serviceCall(conn)</I>, the connection's 126 * input stream is positioned at the start of the incoming 127 * message. The <I>serviceCall</I> method processes the incoming 128 * remote invocation and sends the result on the connection's 129 * output stream. If it returns "true", then the remote 130 * invocation was processed without error and the transport can 131 * cache the connection. If it returns "false", a protocol error 132 * occurred during the call, and the transport should destroy the 133 * connection. 134 */ 135 public boolean serviceCall(final RemoteCall call) { 136 try { 137 /* read object id */ 138 final Remote impl; 139 ObjID id; 140 141 try { 142 id = ObjID.read(call.getInputStream()); 143 } catch (java.io.IOException e) { 144 throw new MarshalException("unable to read objID", e); 145 } 146 147 /* get the remote object */ 148 Transport transport = id.equals(dgcID) ? null : this; 149 Target target = 150 ObjectTable.getTarget(new ObjectEndpoint(id, transport)); 151 152 if (target == null || (impl = target.getImpl()) == null) { 153 throw new NoSuchObjectException("no such object in table"); 154 } 155 156 final Dispatcher disp = target.getDispatcher(); 157 target.incrementCallCount(); 158 try { 159 /* call the dispatcher */ 160 transportLog.log(Log.VERBOSE, "call dispatcher"); 161 162 final AccessControlContext acc = 163 target.getAccessControlContext(); 164 ClassLoader ccl = target.getContextClassLoader(); 165 166 Thread t = Thread.currentThread(); 167 ClassLoader savedCcl = t.getContextClassLoader(); 168 169 try { 170 t.setContextClassLoader(ccl); 171 currentTransport.set(this); 172 try { 173 java.security.AccessController.doPrivileged( 174 new java.security.PrivilegedExceptionAction<Void>() { 175 public Void run() throws IOException { 176 checkAcceptPermission(acc); 177 disp.dispatch(impl, call); 178 return null; 179 } 180 }, acc); 181 } catch (java.security.PrivilegedActionException pae) { 182 throw (IOException) pae.getException(); 183 } 184 } finally { 185 t.setContextClassLoader(savedCcl); 186 currentTransport.set(null); 187 } 188 189 } catch (IOException ex) { 190 transportLog.log(Log.BRIEF, 191 "exception thrown by dispatcher: ", ex); 192 return false; 193 } finally { 194 target.decrementCallCount(); 195 } 196 197 } catch (RemoteException e) { 198 199 // if calls are being logged, write out exception 200 if (UnicastServerRef.callLog.isLoggable(Log.BRIEF)) { 201 // include client host name if possible 202 String clientHost = ""; 203 try { 204 clientHost = "[" + 205 RemoteServer.getClientHost() + "] "; 206 } catch (ServerNotActiveException ex) { 207 } 208 String message = clientHost + "exception: "; 209 UnicastServerRef.callLog.log(Log.BRIEF, message, e); 210 } 211 212 /* We will get a RemoteException if either a) the objID is 213 * not readable, b) the target is not in the object table, or 214 * c) the object is in the midst of being unexported (note: 215 * NoSuchObjectException is thrown by the incrementCallCount 216 * method if the object is being unexported). Here it is 217 * relatively safe to marshal an exception to the client 218 * since the client will not have seen a return value yet. 219 */ 220 try { 221 ObjectOutput out = call.getResultStream(false); 222 UnicastServerRef.clearStackTraces(e); 223 out.writeObject(e); 224 call.releaseOutputStream(); 225 226 } catch (IOException ie) { 227 transportLog.log(Log.BRIEF, 228 "exception thrown marshalling exception: ", ie); 229 return false; 230 } 231 } 232 233 return true; 234 } 235 }