001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: *
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: /**
020: * @author Mikhail A. Markov
021: * @version $Revision: 1.1.2.3 $
022: */package org.apache.harmony.rmi.server;
023:
024: import java.io.BufferedInputStream;
025: import java.io.BufferedOutputStream;
026: import java.io.DataOutputStream;
027: import java.io.IOException;
028: import java.io.InputStream;
029: import java.io.OutputStream;
030: import java.net.Socket;
031: import java.rmi.NoSuchObjectException;
032: import java.rmi.RemoteException;
033: import java.rmi.ServerException;
034: import java.rmi.UnmarshalException;
035: import java.rmi.server.ObjID;
036: import java.rmi.server.UID;
037: import java.security.AccessController;
038: import java.security.PrivilegedActionException;
039: import java.security.PrivilegedExceptionAction;
040:
041: import org.apache.harmony.rmi.common.RMILog;
042: import org.apache.harmony.rmi.common.RMIUtil;
043: import org.apache.harmony.rmi.internal.nls.Messages;
044: import org.apache.harmony.rmi.remoteref.UnicastServerRef;
045: import org.apache.harmony.rmi.transport.Endpoint;
046: import org.apache.harmony.rmi.transport.RMIObjectInputStream;
047: import org.apache.harmony.rmi.transport.RMIObjectOutputStream;
048: import org.apache.harmony.rmi.transport.RMIProtocolConstants;
049:
050: /**
051: * Connection opened on server side when connection from the client is accepted.
052: * It acknowledges RMI protocol version, RMI protocol type etc. and after that
053: * pass the control to the appropriate UnicastServerRef for processing the
054: * remote call itself.
055: *
056: * @author Mikhail A. Markov
057: * @version $Revision: 1.1.2.3 $
058: */
059: public abstract class ServerConnection implements RMIProtocolConstants,
060: Runnable {
061:
062: /** Connected socket. */
063: protected Socket s;
064:
065: /** InputStream open from the socket. */
066: protected InputStream in;
067:
068: /** OutputStream open from the socket. */
069: protected OutputStream out;
070:
071: /** Endpoint which this connection connected to. */
072: protected Endpoint ep;
073:
074: /** ServerConnectionManager managing this connection. */
075: protected ServerConnectionManager mgr;
076:
077: /** Server reference where current remote call is dispatching. */
078: protected UnicastServerRef sref = null;
079:
080: /**
081: * Constructs ServerConnection working through socket specified.
082: *
083: * @param s Socket connected to the client
084: * @param mgr ServerConnectionManager managing this connection
085: *
086: * @throws IOException if an I/O error occurred during getting
087: * input/output streams from specified socket
088: */
089: public ServerConnection(Socket s, ServerConnectionManager mgr)
090: throws IOException {
091: this .s = s;
092: this .mgr = mgr;
093: ep = new Endpoint(s.getInetAddress().getHostAddress(), s
094: .getPort(), mgr.getEndpoint().getClientSocketFactory(),
095: mgr.getEndpoint().getServerSocketFactory());
096: out = new BufferedOutputStream(s.getOutputStream());
097: in = new BufferedInputStream(s.getInputStream());
098: }
099:
100: /**
101: * Acknowledges RMI protocol version, RMI protocol type etc. and wait for
102: * remote calls from client. After call message dispatch call to appropriate
103: * UnicastServerRef for processing.
104: */
105: public void run() {
106: // sets client host for RemoteServer.getClientHost() method
107: ServerConnectionManager.clientHost.set(s.getInetAddress()
108: .getHostAddress());
109:
110: try {
111: // acknowledge protocol
112: if (clientProtocolAck() < 0) {
113: return;
114: }
115:
116: // wait until RMI call msg is received from client or until client
117: // closes the connection
118: while (waitCallMsg() != -1) {
119: RMIObjectInputStream oin = new RMIObjectInputStream(in);
120: final ServerRemoteCall sCall = new ServerRemoteCall(
121: this , oin);
122: ObjID id = null;
123:
124: try {
125: id = ObjID.read(oin);
126: } catch (IOException ioe) {
127: // rmi.74=Unable to read Object ID
128: throw new UnmarshalException(Messages
129: .getString("rmi.74"), //$NON-NLS-1$
130: ioe);
131: }
132: RMIObjectInfo info = ExportManager.getInfo(id);
133: RemoteException exToReturn = null;
134:
135: if (info == null) {
136: sref = null;
137: // rmi.75=No objects with {0} exported.
138: exToReturn = new NoSuchObjectException(Messages
139: .getString("rmi.75", id)); //$NON-NLS-1$
140: } else {
141: sref = info.sref;
142:
143: if (!sref.isSystem()) {
144: mgr.addActiveCall();
145: }
146:
147: if (ServerConnectionManager.transportLog
148: .isLoggable(RMILog.VERBOSE)) {
149: // rmi.76=Dispatch call for processing
150: ServerConnectionManager.transportLog.log(
151: RMILog.VERBOSE, Messages
152: .getString("rmi.76")); //$NON-NLS-1$
153: }
154:
155: // Dispatch the call for processing
156: Thread curThread = Thread.currentThread();
157: ClassLoader curLoader = curThread
158: .getContextClassLoader();
159: curThread.setContextClassLoader(info.loader);
160: final SecurityManager curMgr = System
161: .getSecurityManager();
162:
163: try {
164: AccessController.doPrivileged(
165: new PrivilegedExceptionAction() {
166: public Object run()
167: throws IOException {
168: /*
169: * First check if we can accept
170: * the calls from the given endpoint.
171: */
172: if (curMgr != null) {
173: curMgr.checkAccept(ep
174: .getHost(), ep
175: .getPort());
176: }
177: sref.processCall(sCall);
178: return null;
179: }
180: }, info.acc);
181: } catch (PrivilegedActionException pae) {
182: IOException ioe = (IOException) pae
183: .getException();
184:
185: if (ioe instanceof RemoteException) {
186: // rmi.77=RemoteException occurred in server thread
187: exToReturn = new ServerException(Messages
188: .getString("rmi.77"), //$NON-NLS-1$
189: ioe);
190: } else {
191: throw ioe;
192: }
193: } finally {
194: curThread.setContextClassLoader(curLoader);
195: }
196: }
197:
198: if (exToReturn != null) {
199: sCall.releaseInputStream();
200: if (ServerConnectionManager.transportLog
201: .isLoggable(RMILog.VERBOSE)) {
202: // rmi.log.10B=Return exception to the client: {0}
203: ServerConnectionManager.transportLog.log(
204: RMILog.VERBOSE, Messages.getString(
205: "rmi.log.10B", exToReturn));//$NON-NLS-1$
206: }
207: DataOutputStream dout = new DataOutputStream(out);
208: RMIObjectOutputStream oout;
209:
210: if (sCall.hasResultStream()) {
211: oout = (RMIObjectOutputStream) sCall
212: .getOutputStream();
213: } else {
214: oout = (RMIObjectOutputStream) sCall
215: .getResultStream(false);
216: }
217: oout.writeObject(exToReturn);
218: oout.flush();
219: }
220:
221: if (sref != null) {
222: if (!sref.isSystem()) {
223: mgr.removeActiveCall();
224: }
225: sref = null;
226: }
227: releaseOutputStream();
228: }
229: } catch (IOException ioe) {
230: //ioe.printStackTrace(System.err);
231: } finally {
232: if (sref != null) {
233: if (!sref.isSystem()) {
234: mgr.removeActiveCall();
235: }
236: sref = null;
237: }
238:
239: // stop this thread, close the socket and remove this connection
240: // from the list of active connections in ConnectionManager
241: mgr.stopConnection(this );
242: }
243: }
244:
245: /**
246: * Acknowledges protocol with client side.
247: *
248: * @return acknowledged protocol number
249: *
250: * @throws RemoteException if any I/O exception occurred during protocol
251: * acknowledgement
252: */
253: protected abstract int clientProtocolAck() throws IOException;
254:
255: /**
256: * Waiting until 0x50 code (CALL_MSG) message will be received (this code
257: * will be returned as a result of this method call). If the
258: * connection with the client is closed while waiting for this code, -1
259: * should be returned.
260: *
261: * @return 0x50 code if this code is received from the client or -1 if
262: * the socket was closed while waiting for CALL_MSG code
263: *
264: * @throws IOException if any I/O error occurred while communicating with
265: * client
266: */
267: protected abstract int waitCallMsg() throws IOException;
268:
269: /**
270: * This method should be called when DGC_ACK response was received.
271: * It unregisters the given UID in ClientDGC.
272: *
273: * @param uid UID DGC_ACK response for which was read
274: */
275: protected void dgcUnregisterUID(UID uid) {
276: ClientDGC.unregisterForDGCAck(uid);
277: }
278:
279: /**
280: * Closes this connection.
281: */
282: public void close() {
283: try {
284: s.close();
285: } catch (IOException e) {
286: if (ServerConnectionManager.transportLog
287: .isLoggable(RMILog.VERBOSE)) {
288: // rmi.log.10C=Note: close operation produced exception:
289: ServerConnectionManager.transportLog.log(
290: RMILog.VERBOSE, Messages
291: .getString("rmi.log.10C"), e); //$NON-NLS-1$
292: }
293: }
294: }
295:
296: /**
297: * Returns true if this connection is handling remote call and false
298: * otherwise.
299: *
300: * @return true if this connection is handling remote call and false
301: * otherwise
302: */
303: public boolean hasActiveCall() {
304: return sref != null;
305: }
306:
307: /**
308: * By default does nothing.
309: */
310: public void releaseInputStream() throws IOException {
311: }
312:
313: /**
314: * By default does nothing.
315: */
316: public void releaseOutputStream() throws IOException {
317: }
318:
319: /**
320: * Returns open input stream.
321: *
322: * @return open input stream
323: */
324: public InputStream getInputStream() {
325: return in;
326: }
327:
328: /**
329: * Returns open output stream.
330: *
331: * @return open output stream
332: */
333: public OutputStream getOutputStream() {
334: return out;
335: }
336:
337: /**
338: * Returns string representation of this connection.
339: *
340: * @return string representation of this connection
341: */
342: public String toString() {
343: return RMIUtil.getShortName(getClass())
344: + ": remote endpoint:" + ep; //$NON-NLS-1$
345: }
346: }
|