blob: 572a55b2bea1551303b6a9aff2b16a936ded0f5b [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1996-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.rmi.transport;
27
28import java.io.IOException;
29import java.io.ObjectOutput;
30import java.rmi.MarshalException;
31import java.rmi.NoSuchObjectException;
32import java.rmi.Remote;
33import java.rmi.RemoteException;
34import java.rmi.server.LogStream;
35import java.rmi.server.ObjID;
36import java.rmi.server.RemoteCall;
37import java.rmi.server.RemoteServer;
38import java.rmi.server.ServerNotActiveException;
39import java.security.AccessControlContext;
40import sun.rmi.runtime.Log;
41import sun.rmi.server.Dispatcher;
42import sun.rmi.server.UnicastServerRef;
43
44/**
45 * Transport abstraction for enabling communication between different
46 * VMs.
47 *
48 * @author Ann Wollrath
49 */
50public 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 (String) 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() {
175 public Object 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}