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.isolate.jvmprocess;
026:
027: import com.sun.jump.isolate.jvmprocess.JUMPIsolateProcess;
028: import com.sun.jump.isolate.jvmprocess.JUMPAppContainer;
029: import com.sun.jump.isolate.jvmprocess.JUMPAppContainerContext;
030: import com.sun.jump.common.JUMPAppModel;
031: import com.sun.jump.common.JUMPProcess;
032: import com.sun.jump.common.JUMPIsolate;
033: import com.sun.jump.common.JUMPProcessProxy;
034: import com.sun.jump.common.JUMPApplication;
035: import com.sun.jump.message.JUMPMessagingService;
036: import com.sun.jump.message.JUMPMessageDispatcher;
037: import com.sun.jump.message.JUMPOutgoingMessage;
038: import com.sun.jump.message.JUMPMessage;
039: import com.sun.jump.message.JUMPMessageResponseSender;
040: import com.sun.jump.message.JUMPMessageReader;
041: import com.sun.jump.os.JUMPOSInterface;
042: import com.sun.jumpimpl.process.JUMPModulesConfig;
043: import com.sun.jumpimpl.process.JUMPProcessProxyImpl;
044: import com.sun.jumpimpl.process.RequestSenderHelper;
045: import com.sun.jump.command.JUMPIsolateLifecycleRequest;
046: import com.sun.jump.command.JUMPExecutiveLifecycleRequest;
047: import com.sun.jump.command.JUMPCommand;
048: import com.sun.jump.command.JUMPRequest;
049: import com.sun.jump.command.JUMPResponse;
050: import com.sun.jump.command.JUMPResponseInteger;
051: import com.sun.jump.message.JUMPMessageHandler;
052: import com.sun.jumpimpl.client.module.windowing.WindowingIsolateClient;
053: import com.sun.jumpimpl.client.module.serviceregistry.ServiceRegistryClient;
054:
055: import java.rmi.Remote;
056: import java.rmi.NotBoundException;
057: import javax.microedition.xlet.XletContext;
058: import javax.microedition.xlet.ixc.IxcRegistry;
059: import com.sun.jumpimpl.ixc.XletContextFactory;
060:
061: import sun.misc.MIDPConfig;
062: import sun.misc.ThreadRegistry;
063:
064: import java.util.Map;
065: import java.util.StringTokenizer;
066:
067: public class JUMPIsolateProcessImpl extends JUMPIsolateProcess
068: implements JUMPMessageHandler, JUMPAppContainerContext {
069: private JUMPProcessProxyImpl pp;
070: private JUMPOSInterface os;
071: private int isolateId;
072: private JUMPProcessProxy execProcess;
073: private JUMPMessageDispatcher disp;
074: private JUMPAppModel appModel;
075: private JUMPAppContainer appContainer;
076: private WindowingIsolateClient windowing;
077: private ServiceRegistryClient serviceRegistry;
078: private Object stateChangeMutex = new Object();
079: private boolean dispatchingStateChange;
080: private boolean exitAfterStateChange;
081: private final KeepAliveMonitor keepAliveMonitor = new KeepAliveMonitor();
082:
083: protected JUMPIsolateProcessImpl() {
084: super ();
085: os = JUMPOSInterface.getInstance();
086: isolateId = os.getProcessID();
087: pp = JUMPProcessProxyImpl.createProcessProxyImpl(isolateId);
088: }
089:
090: public JUMPProcessProxy getExecutiveProcess() {
091: if (execProcess == null) {
092: int epid = os.getExecutiveProcessID();
093: execProcess = JUMPProcessProxyImpl
094: .createProcessProxyImpl(epid);
095: }
096: return execProcess;
097: }
098:
099: public int getProcessId() {
100: return os.getProcessID();
101: }
102:
103: public Map getConfig() {
104: return JUMPModulesConfig.getProperties();
105: }
106:
107: /**
108: * Get app model running in this isolate process
109: */
110: public JUMPAppModel getAppModel() {
111: return appModel;
112: }
113:
114: public synchronized JUMPMessageDispatcher getMessageDispatcher() {
115: if (disp == null) {
116: disp = pp.getMessageDispatcher();
117: }
118: return disp;
119: }
120:
121: public JUMPOutgoingMessage newOutgoingMessage(String mesgType) {
122: return pp.newOutgoingMessage(mesgType);
123: }
124:
125: public JUMPOutgoingMessage newOutgoingMessage(
126: JUMPMessage requestMessage) {
127: return pp.newOutgoingMessage(requestMessage);
128: }
129:
130: public JUMPMessage newMessage(byte[] rawData) {
131: return pp.newMessage(rawData);
132: }
133:
134: public void kill(boolean force) {
135: throw new UnsupportedOperationException();
136: }
137:
138: //
139: // The message handlers do the job.
140: // The message processor thread keeps the JVM alive.
141: //
142: public static void main(String[] args) {
143: try {
144: if (args.length > 1 && args[1] != null) {
145: JUMPModulesConfig.overrideDefaultConfig(args[1]);
146: }
147:
148: // Initialize os interface
149: new com.sun.jumpimpl.os.JUMPOSInterfaceImpl();
150:
151: // Create and register the singleton isolate process
152: JUMPIsolateProcessImpl ipi = new JUMPIsolateProcessImpl();
153:
154: // Register the executive before starting the messaging thread
155: ipi.getExecutiveProcess();
156:
157: JUMPMessageDispatcher d = ipi.getMessageDispatcher();
158:
159: d.registerHandler("mvm/client", ipi);
160: // FIXME: should go away once Ixc is on messaging
161: d.registerHandler("mvm/ixc", ipi);
162:
163: JUMPAppModel appModel = JUMPAppModel.fromName(args[0]);
164: if (appModel == null) {
165: // Unknown app model
166: throw new RuntimeException("Unknown app model "
167: + args[0]);
168: }
169:
170: ipi.initialize(appModel);
171:
172: //
173: // Once registerDirect() completes with success,
174: // we know we can receive messages. Report.
175: //
176: ipi.reportIsolateInitialized();
177:
178: // Keep around the main thread
179: ipi.keepAliveMonitor.startWaiting();
180:
181: } catch (Throwable e) {
182: e.printStackTrace();
183: System.exit(-1);
184: }
185: }
186:
187: public void initialize(JUMPAppModel appModel) {
188: System.err.println("Setting app model to " + appModel);
189: this .appModel = appModel;
190:
191: AppContainerFactoryImpl factory = new AppContainerFactoryImpl();
192:
193: this .appContainer = factory.getAppContainer(appModel, this );
194:
195: this .windowing = new WindowingIsolateClient();
196:
197: System.err.println(this + " config: "
198: + JUMPModulesConfig.getProperties());
199:
200: String classes = (String) getConfig().get(
201: "isolate-init-classes");
202: if (classes != null) {
203: StringTokenizer st = new StringTokenizer(classes, ",");
204: while (st.hasMoreTokens()) {
205: try {
206: Class.forName(st.nextToken()).newInstance();
207: } catch (Exception e) {
208: e.printStackTrace();
209: throw new RuntimeException("Initialization failed");
210: }
211: }
212: }
213: }
214:
215: //
216: // Messages to this VM processed here
217: // For now, all we do is report receipt, send back a success code
218: // Eventually, we should handle generic messages here, and pass on
219: // anything we don't know about to the container to process.
220: //
221: public void handleMessage(JUMPMessage in) {
222: JUMPOutgoingMessage responseMessage;
223: JUMPCommand raw = JUMPRequest.fromMessage(in);
224: String id = raw.getCommandId();
225:
226: System.err.println("RECEIVED MESSAGE TYPE " + id);
227:
228: synchronized (stateChangeMutex) {
229: dispatchingStateChange = true;
230: }
231:
232: try {
233: // Now let's figure out the type
234: if (id.equals(JUMPExecutiveLifecycleRequest.ID_START_APP)) {
235: responseMessage = handleStartAppMessage(in);
236: } else if (id
237: .equals(JUMPExecutiveLifecycleRequest.ID_PAUSE_APP)) {
238: responseMessage = handlePauseAppMessage(in);
239: } else if (id
240: .equals(JUMPExecutiveLifecycleRequest.ID_RESUME_APP)) {
241: responseMessage = handleResumeAppMessage(in);
242: } else if (id
243: .equals(JUMPExecutiveLifecycleRequest.ID_DESTROY_APP)) {
244: responseMessage = handleDestroyAppMessage(in);
245: } else if (id
246: .equals(com.sun.jumpimpl.ixc.IxcMessage.ID_PORT)) {
247: // Tell the isolate about the ixc port.
248: // FIXME: should go away once ixc is on messaging.
249: responseMessage = handleIxcMessage(in);
250: } else {
251: responseMessage = handleUnknownMessage(in);
252: }
253:
254: in.getSender().sendResponseMessage(responseMessage);
255:
256: } catch (Throwable e) {
257: e.printStackTrace();
258: } finally {
259: synchronized (stateChangeMutex) {
260: dispatchingStateChange = false;
261:
262: if (exitAfterStateChange) {
263: System.exit(0);
264: }
265: }
266: }
267: }
268:
269: public void notifyDestroyed(int appId) {
270: //TODO: send message back to executive
271: }
272:
273: public void notifyPaused(int appId) {
274: //TODO: send message back to executive
275: }
276:
277: public void resumeRequest(int appId) {
278: //TODO: send message back to executive
279: }
280:
281: public String getConfigProperty(String key) {
282: return (String) JUMPModulesConfig.getProperties().get(key);
283: }
284:
285: public void terminateIsolate() {
286: synchronized (stateChangeMutex) {
287: if (dispatchingStateChange) {
288: exitAfterStateChange = true;
289: } else {
290: System.exit(0);
291: }
292: }
293: }
294:
295: /**
296: * Report to the executive that we have initialized ourselves
297: */
298: private void reportIsolateInitialized() {
299: JUMPProcessProxy e = getExecutiveProcess();
300: RequestSenderHelper rsh = new RequestSenderHelper(this );
301: String reqId = JUMPIsolateLifecycleRequest.ID_ISOLATE_INITIALIZED;
302: String[] reqArgs = new String[] { Integer.toString(isolateId),
303: "" };
304: JUMPRequest req = new JUMPIsolateLifecycleRequest(reqId, this );
305:
306: rsh.sendRequestAsync(e, req);
307: }
308:
309: /** {@inheritDoc} */
310: public Remote getRemoteService(String name) {
311: return serviceRegistry.getRemoteService(name);
312: }
313:
314: private JUMPOutgoingMessage handleStartAppMessage(JUMPMessage in) {
315: JUMPExecutiveLifecycleRequest elr = (JUMPExecutiveLifecycleRequest) JUMPExecutiveLifecycleRequest
316: .fromMessage(in);
317: byte[] barr = elr.getAppBytes();
318: JUMPApplication app = JUMPApplication.fromByteArray(barr);
319: String[] args = elr.getArgs();
320: System.err.println("START_APP(" + app + ")");
321: int appId = -1;
322:
323: // Notify windowing that application is going to be started before
324: // app container is initialized to set bounds
325: // for the app screen area.
326: windowing.onBeforeApplicationStarted(app);
327:
328: if (appContainer != null) {
329: // The message is telling us to start an application
330: appId = appContainer.startApp(app, args);
331: }
332:
333: // Now wrap this appid in a message and return it
334: JUMPResponseInteger resp;
335: if (appId >= 0) {
336: resp = new JUMPResponseInteger(in.getType(),
337: JUMPResponseInteger.ID_SUCCESS, appId);
338: } else {
339: resp = new JUMPResponseInteger(in.getType(),
340: JUMPResponseInteger.ID_FAILURE, -1);
341: }
342:
343: /*
344: * Now convert JUMPResponse to a message in response
345: * to the incoming message
346: */
347: return resp.toMessageInResponseTo(in, this );
348: }
349:
350: private JUMPOutgoingMessage handlePauseAppMessage(JUMPMessage in) {
351: JUMPExecutiveLifecycleRequest elr = (JUMPExecutiveLifecycleRequest) JUMPExecutiveLifecycleRequest
352: .fromMessage(in);
353: String[] args = elr.getArgs();
354: int appID = Integer.parseInt(args[0]);
355: String responseId;
356:
357: System.err.println("PAUSE_APP(" + appID + ")");
358:
359: try {
360: appContainer.pauseApp(appID);
361: responseId = JUMPResponseInteger.ID_SUCCESS;
362: } catch (Throwable t) {
363: responseId = JUMPResponseInteger.ID_FAILURE;
364: }
365:
366: JUMPResponse resp = new JUMPResponse(in.getType(), responseId);
367:
368: return resp.toMessageInResponseTo(in, this );
369: }
370:
371: private JUMPOutgoingMessage handleResumeAppMessage(JUMPMessage in) {
372: JUMPExecutiveLifecycleRequest elr = (JUMPExecutiveLifecycleRequest) JUMPExecutiveLifecycleRequest
373: .fromMessage(in);
374: String[] args = elr.getArgs();
375: int appID = Integer.parseInt(args[0]);
376: String responseId;
377:
378: System.err.println("RESUME_APP(" + appID + ")");
379:
380: try {
381: appContainer.resumeApp(appID);
382: responseId = JUMPResponseInteger.ID_SUCCESS;
383: } catch (Throwable t) {
384: responseId = JUMPResponseInteger.ID_FAILURE;
385: }
386:
387: JUMPResponse resp = new JUMPResponse(in.getType(), responseId);
388:
389: return resp.toMessageInResponseTo(in, this );
390: }
391:
392: private JUMPOutgoingMessage handleDestroyAppMessage(JUMPMessage in) {
393: JUMPExecutiveLifecycleRequest elr = (JUMPExecutiveLifecycleRequest) JUMPExecutiveLifecycleRequest
394: .fromMessage(in);
395: String[] args = elr.getArgs();
396: int appID = Integer.parseInt(args[0]);
397: boolean unconditional = Boolean.getBoolean(args[1]);
398: System.err.println("DESTROY_APP(" + appID + ")");
399: String responseCode = JUMPResponseInteger.ID_SUCCESS;
400:
401: try {
402: appContainer.destroyApp(appID, unconditional);
403: } catch (Throwable t) {
404: responseCode = JUMPResponseInteger.ID_FAILURE;
405: }
406:
407: JUMPResponse resp = new JUMPResponse(in.getType(), responseCode);
408: return resp.toMessageInResponseTo(in, this );
409: }
410:
411: private JUMPOutgoingMessage handleUnknownMessage(JUMPMessage in) {
412: // Assumption of default message
413: // A utf array, expecting a generic JUMPResponse
414: JUMPMessageReader reader = new JUMPMessageReader(in);
415: System.err.println("Incoming client message:");
416: String[] responseStrings = reader.getUTFArray();
417:
418: for (int j = 0; j < responseStrings.length; j++) {
419: System.err.println(" \"" + responseStrings[j] + "\"");
420: }
421:
422: JUMPOutgoingMessage out = newOutgoingMessage(in);
423: out.addUTFArray(new String[] { "SUCCESS" });
424: return out;
425: }
426:
427: /**
428: * Fetches class loader to use for implementation classes in IXC.
429: *
430: * @return class loader to use
431: */
432: private ClassLoader getImplClassLoader() {
433: return appContainer.getClass().getClassLoader();
434: }
435:
436: /**
437: * Extract port number from the message and tell it to the
438: * service registry client.
439: * FIXME: should be removed once ixc is on messaging.
440: */
441: private JUMPOutgoingMessage handleIxcMessage(JUMPMessage in) {
442: JUMPCommand message = JUMPCommand.fromMessage(in,
443: com.sun.jumpimpl.ixc.IxcMessage.class);
444:
445: int port = Integer.parseInt(message.getCommandData()[0]);
446:
447: serviceRegistry = new ServiceRegistryClient(
448: getImplClassLoader(), port);
449:
450: JUMPResponse resp = new JUMPResponse(in.getType(),
451: JUMPResponseInteger.ID_SUCCESS);
452: return resp.toMessageInResponseTo(in, this );
453: }
454:
455: public void terminateKeepAliveThread() {
456: keepAliveMonitor.terminate();
457: }
458:
459: static class KeepAliveMonitor {
460: private boolean keepAlive = true;
461:
462: public synchronized void startWaiting() {
463: while (keepAlive) {
464: try {
465: this .wait();
466: } catch (InterruptedException e) {
467: /*
468: * Ignore InterruptedException and continue with the loop.
469: * This thread should exit only if terminate() is invoked.
470: */
471: }
472: }
473: }
474:
475: public synchronized void terminate() {
476: keepAlive = false;
477: this.notifyAll();
478: }
479: }
480: }
|