001: /*
002: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License version
007: * 2 only, as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful, but
010: * WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * General Public License version 2 for more details (a copy is
013: * included at /legal/license.txt).
014: *
015: * You should have received a copy of the GNU General Public License
016: * version 2 along with this work; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
018: * 02110-1301 USA
019: *
020: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
021: * Clara, CA 95054 or visit www.sun.com if you need additional
022: * information or have any questions.
023: */
024:
025: package com.sun.jumpimpl.ixc;
026:
027: import java.io.DataInputStream;
028: import java.io.DataOutputStream;
029: import java.io.InputStream;
030: import java.io.OutputStream;
031: import java.io.ObjectOutputStream;
032: import java.io.ObjectInputStream;
033: import java.io.IOException;
034: import java.lang.reflect.Array;
035: import java.lang.reflect.InvocationTargetException;
036: import java.lang.reflect.Method;
037: import java.net.ServerSocket;
038: import java.net.Socket;
039: import java.rmi.Remote;
040: import java.security.AccessController;
041: import java.security.AccessControlContext;
042: import java.security.PrivilegedAction;
043: import java.security.PrivilegedExceptionAction;
044: import java.security.PrivilegedActionException;
045: import java.util.HashMap;
046: import sun.security.action.GetIntegerAction;
047:
048: import javax.microedition.xlet.*;
049: import javax.microedition.xlet.ixc.*;
050:
051: /*
052: * This is VM-wide singleton class for accepting incoming
053: * connections from other clients, with it's ServerSocket.
054: * It's used for receiving IXC method invocation requests.
055: * This ServerSocket's port number is included in the RemoteRef
056: * of the objects exported by this VM's xlet(s).
057: */
058:
059: public class ConnectionReceiver implements Runnable {
060:
061: private static int execVMServicePort;
062: private static boolean initialized = false;
063: private static ServerSocket serverSocket;
064: private static boolean debug = false; // Enable/disable debug output
065:
066: private ConnectionReceiver(final int port) {
067: serverSocket = (ServerSocket) AccessController
068: .doPrivileged(new PrivilegedAction() {
069: public Object run() {
070: ServerSocket socket = null;
071: try {
072: if (port == 0) {
073: socket = new ServerSocket();
074: socket.bind(null);
075: } else {
076: socket = new ServerSocket(port);
077: }
078: } catch (IOException e) {
079: System.err
080: .println("Error opening ServerSocket");
081: e.printStackTrace();
082: }
083: return socket;
084: }
085: });
086:
087: if (serverSocket != null)
088: new Thread(this ).start();
089: }
090:
091: public synchronized static void setExecVMServicePort(int portNumber) {
092: if (initialized) {
093: throw new InternalError("ExecutiveVM port already set: "
094: + getExecVMServicePort());
095: }
096: execVMServicePort = portNumber;
097: initialized = true;
098: }
099:
100: public synchronized static int getExecVMServicePort() {
101: if (!initialized) {
102: throw new InternalError("ExecutiveVM port not yet set");
103: }
104: return execVMServicePort;
105: }
106:
107: /*
108: * Starts the executive VM ServerSocket.
109: * Should only be called in the ExecutiveVM.
110: */
111: public static void startExecVMService() {
112: setExecVMServicePort(getLocalServicePort());
113: }
114:
115: /*
116: * Starts the ConnectionReceiver if necessary, and returns the local
117: * VM's ServerSocket.
118: */
119: static int getLocalServicePort() {
120: if (serverSocket == null) {
121: new ConnectionReceiver(0);
122: }
123:
124: return serverSocket.getLocalPort();
125: }
126:
127: private static void debugOut(String s) {
128: System.out.println("ConnectionReceiver: " + s);
129: }
130:
131: // Waits for the connection request to come to this ServerSocket.
132: public void run() {
133: Socket clientSocket = null;
134:
135: while (true) {
136: if (debug)
137: debugOut("ConnectionReceiver waiting for new connection");
138:
139: final ServerSocket finalSocket = serverSocket;
140: clientSocket = (Socket) AccessController
141: .doPrivileged(new PrivilegedAction() {
142: public Object run() {
143: try {
144: Socket s = serverSocket.accept();
145: s.setReuseAddress(true);
146: return s;
147: } catch (IOException e) {
148: e.printStackTrace();
149: }
150: return null;
151: }
152: });
153:
154: if (clientSocket != null) {
155: // Connected - execute the method invocation in this vm.
156: if (debug)
157: debugOut("Connected with " + clientSocket);
158: Runnable executor = new RemoteMethodExecutor(
159: clientSocket);
160: WorkerThreadPool
161: .execute(Thread.NORM_PRIORITY, executor);
162: }
163: }
164: }
165:
166: // Handles each incoming connection request.
167: class RemoteMethodExecutor implements Runnable {
168: Socket clientSocket;
169:
170: public RemoteMethodExecutor(Socket s) {
171: clientSocket = s;
172: }
173:
174: // Executed by the worker thread.
175: public void run() {
176:
177: InputStream in = null;
178: OutputStream out = null;
179:
180: boolean isExecutiveIxcRegistry = false;
181:
182: try {
183:
184: /**
185: * Invocation request comes in this order.
186: * 1.The object ID (long).
187: * 2.The method ID (long).
188: * 3.Parameters marshalled out (if needed)
189: */
190: in = clientSocket.getInputStream();
191:
192: DataInputStream din = new DataInputStream(in);
193: long objectID = din.readLong();
194: long methodID = din.readLong();
195:
196: Object remoteObject = null;
197: Method method = null;
198: Object returnValue = null;
199: boolean hasExceptionThrown = false;
200:
201: if (debug)
202: debugOut("Obtained ObjectID and methodID");
203:
204: // First, find the object.
205: ExportedObject exportedObject = ExportedObject
206: .findExportedObject(objectID);
207:
208: if (exportedObject != null) {
209: remoteObject = exportedObject.remoteObject;
210: isExecutiveIxcRegistry = (remoteObject instanceof JUMPExecIxcRegistryRemote);
211: }
212:
213: if (debug)
214: debugOut("Found corresponding Object "
215: + remoteObject
216: + ", isExecutiveIxcRegistry="
217: + isExecutiveIxcRegistry);
218:
219: if (remoteObject == null) {
220: /* problem here */
221: hasExceptionThrown = true;
222: returnValue = new StubException(
223: "Cannot find corresponding ExportedObject:"
224: + objectID);
225: }
226:
227: // Next, find the method
228: if (remoteObject != null) {
229: method = exportedObject
230: .findExportedMethod(methodID);
231: if (method == null) {
232: /* problem here */
233: hasExceptionThrown = true;
234: returnValue = new StubException(
235: "Cannot find corresponding method:"
236: + methodID);
237: }
238: }
239:
240: if (debug)
241: debugOut("Found corresponding method " + method);
242:
243: // If both object and method are found, read params and invoke
244: if (method != null) {
245:
246: Class[] paramTypes = method.getParameterTypes();
247: Object[] paramObjects = new Object[paramTypes.length];
248:
249: try {
250: if (paramTypes.length > 0) {
251:
252: IxcInputStream oin = new IxcInputStream(in,
253: exportedObject.context,
254: isExecutiveIxcRegistry);
255:
256: for (int i = 0; i < paramObjects.length; i++) {
257: paramObjects[i] = oin.readObject();
258: if (debug)
259: debugOut("Read param " + i + " : "
260: + paramObjects[i]);
261: }
262: }
263:
264: // Need to find out the client's AccessControlContext,
265: // so that the method invocation can happen in the proper
266: // security context.
267: AccessControlContext acc = AccessController
268: .getContext();
269: returnValue = invokeMethod(method,
270: remoteObject, paramObjects, acc);
271:
272: } catch (StubException se) { // Error in importing parameters
273: hasExceptionThrown = true;
274: returnValue = se;
275: } catch (ClassCastException cce) { // Error in parameter deserialization
276: hasExceptionThrown = true;
277: returnValue = cce;
278: } catch (InvocationTargetException ite) { // Method invocation error
279: hasExceptionThrown = true;
280: returnValue = ite.getCause();
281: } catch (IllegalAccessException iae) { // Method invocation error
282: hasExceptionThrown = true;
283: returnValue = iae;
284: } catch (IllegalArgumentException iage) { // Method invocation error
285: hasExceptionThrown = true;
286: returnValue = iage;
287: } catch (Throwable e) {
288: hasExceptionThrown = true;
289: returnValue = e;
290: }
291: }
292:
293: if (debug)
294: debugOut("Done invoking, marshalling out results");
295: if (debug)
296: debugOut("hasExceptionThrown = "
297: + hasExceptionThrown);
298: if (debug && hasExceptionThrown)
299: debugOut("Exception: " + returnValue);
300:
301: out = clientSocket.getOutputStream();
302:
303: /**
304: * Invocation results are sent out in this order.
305: * 1.Whether the method invocation ended abnormally (bool).
306: * 2.Return value (In normal ending, object or NullObject
307: * for null return, else the corresponding Throwable)
308: */
309:
310: IxcOutputStream oout = new IxcOutputStream(out,
311: exportedObject.context, isExecutiveIxcRegistry);
312:
313: oout.writeBoolean(hasExceptionThrown);
314: oout.writeObject(returnValue);
315:
316: if (debug)
317: debugOut("Done with this RMI, closing the output");
318: Thread.sleep(200);
319:
320: oout.flush();
321: in.close();
322: oout.close();
323:
324: } catch (Exception e) {
325: System.out
326: .println("Caught exception while processing method invocation");
327: e.printStackTrace();
328: }
329:
330: try {
331: clientSocket.shutdownInput();
332: clientSocket.shutdownOutput();
333: clientSocket.close();
334: } catch (Exception e) {
335: //e.printStackTrace();
336: }
337: }
338: }
339:
340: private Object invokeMethod(final Method method,
341: final Object remoteObject, final Object[] paramObjects,
342: final AccessControlContext xletACC)
343: throws InvocationTargetException, IllegalAccessException,
344: IllegalArgumentException {
345:
346: try {
347: return AccessController.doPrivileged(
348: new PrivilegedExceptionAction() {
349: public Object run()
350: throws InvocationTargetException,
351: IllegalAccessException {
352: return method.invoke(remoteObject,
353: paramObjects);
354: }
355: }, xletACC);
356: } catch (PrivilegedActionException e) {
357: Exception ex = e.getException();
358: if (ex instanceof InvocationTargetException)
359: throw (InvocationTargetException) ex;
360: if (ex instanceof IllegalAccessException)
361: throw (IllegalAccessException) ex;
362: if (ex instanceof IllegalArgumentException)
363: throw (IllegalArgumentException) ex;
364:
365: throw new RuntimeException("Error in invoking: " + ex);
366: }
367: }
368: }
369:
370: // Placeholder for sending NULL across the socket connection.
371: class NullObject implements java.io.Serializable {
372: }
|