001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026: package com.sun.midp.jump.isolate;
027:
028: import java.io.File;
029:
030: import java.util.Map;
031:
032: import javax.microedition.io.ConnectionNotFoundException;
033:
034: import javax.microedition.lcdui.Displayable;
035:
036: import javax.microedition.midlet.MIDlet;
037:
038: import com.sun.jump.common.JUMPApplication;
039: import com.sun.jump.common.JUMPAppModel;
040:
041: import com.sun.jump.isolate.jvmprocess.JUMPAppContainer;
042: import com.sun.jump.isolate.jvmprocess.JUMPIsolateProcess;
043:
044: import com.sun.midp.events.EventQueue;
045:
046: import com.sun.midp.jump.MIDletApplication;
047:
048: import com.sun.midp.configurator.Constants;
049:
050: import com.sun.midp.lcdui.*;
051:
052: import com.sun.midp.log.*;
053:
054: import com.sun.midp.main.CDCInit;
055: import com.sun.midp.main.CdcMIDletLoader;
056:
057: import com.sun.midp.midlet.*;
058:
059: import com.sun.midp.midletsuite.*;
060:
061: import com.sun.midp.security.*;
062:
063: /**
064: * Application Container for the MIDlet app model.
065: * <p>
066: * The container uses the system property sun.midp.home.path as the
067: * directory of the MIDP native library and application database.
068: * <p>
069: * The container uses the system property sun.midp.library.name as the
070: * name of the MIDP native library.
071: */
072: public class MIDletContainer extends JUMPAppContainer implements
073: MIDletSuiteExceptionListener, ForegroundController,
074: MIDletStateListener, PlatformRequest, Runnable {
075:
076: /**
077: * Inner class to request security token from SecurityInitializer.
078: * SecurityInitializer should be able to check this inner class name.
079: */
080: private static class SecurityTrusted implements
081: ImplicitlyTrustedClass {
082: }
083:
084: /** This class has a different security domain than the MIDlet suite */
085: private SecurityToken internalSecurityToken;
086:
087: /** True, if an app has been started. */
088: private boolean appStarted;
089:
090: /**
091: * Provides interface for display preemption, creation and other
092: * functionality that can not be publicly added to a javax package.
093: */
094: private DisplayEventHandler displayEventHandler;
095:
096: /** Stores array of active displays for a MIDlet suite isolate. */
097: private DisplayContainer displayContainer;
098:
099: /** Reference to the suite storage. */
100: private MIDletSuiteStorage suiteStorage;
101:
102: /** Starts and controls MIDlets through the lifecycle states. */
103: private MIDletStateHandler midletStateHandler;
104:
105: /**
106: * MIDlet suite instance created and properly initialized for
107: * a MIDlet suite invocation.
108: */
109: private MIDletSuite midletSuite;
110:
111: /** Name of the class to start MIDlet suite execution */
112: private String midletClassName;
113:
114: /** Holds the ID of the current display, for preempting purposes. */
115: private int currentDisplayId;
116:
117: /** Core initialization of a MIDP environment. */
118: public MIDletContainer() {
119: EventQueue eventQueue;
120: DisplayEventProducer displayEventProducer;
121: RepaintEventProducer repaintEventProducer;
122: DisplayEventListener displayEventListener;
123: ItemEventConsumer itemEventConsumer;
124: LCDUIEventListener lcduiEventListener;
125:
126: CDCInit.init();
127:
128: internalSecurityToken = SecurityInitializer
129: .requestToken(new SecurityTrusted());
130:
131: // Init security tokens for core subsystems
132: SecurityInitializer.initSystem();
133:
134: eventQueue = EventQueue.getEventQueue(internalSecurityToken);
135:
136: displayEventHandler = DisplayEventHandlerFactory
137: .getDisplayEventHandler(internalSecurityToken);
138:
139: displayEventProducer = new DisplayEventProducer(eventQueue);
140:
141: repaintEventProducer = new RepaintEventProducer(eventQueue);
142:
143: displayContainer = new DisplayContainer(internalSecurityToken,
144: 0);
145:
146: /*
147: * Because the display handler is implemented in a javax
148: * package it cannot created outside of the package, so
149: * we have to get it after the static initializer of display the class
150: * has been run and then hook up its objects.
151: */
152: displayEventHandler.initDisplayEventHandler(
153: displayEventProducer, this , repaintEventProducer,
154: displayContainer);
155:
156: displayEventListener = new DisplayEventListener(eventQueue,
157: displayContainer);
158:
159: /* Bad style of type casting, but DisplayEventHandlerImpl
160: * implements both DisplayEventHandler & ItemEventConsumer IFs */
161: itemEventConsumer = (ItemEventConsumer) displayEventHandler;
162:
163: lcduiEventListener = new LCDUIEventListener(
164: internalSecurityToken, eventQueue, itemEventConsumer);
165:
166: suiteStorage = MIDletSuiteStorage
167: .getMIDletSuiteStorage(internalSecurityToken);
168:
169: midletStateHandler = MIDletStateHandler.getMidletStateHandler();
170:
171: midletStateHandler.initMIDletStateHandler(
172: internalSecurityToken, this , new CdcMIDletLoader(
173: suiteStorage), this );
174: }
175:
176: /**
177: * Create a MIDlet and call its startApp method.
178: * This method will not return until after the the MIDlet's startApp
179: * method has returned.
180: *
181: * @param app application properties
182: * @param args arguments for the app
183: *
184: * @return runtime application ID or -1 for failure
185: */
186: public synchronized int startApp(JUMPApplication app, String[] args) {
187: try {
188: int suiteId;
189:
190: if (appStarted) {
191: throw new IllegalStateException(
192: "Attempt to start a second app");
193: }
194:
195: appStarted = true;
196:
197: suiteId = MIDletApplication.getMIDletSuiteID(app);
198:
199: midletSuite = suiteStorage.getMIDletSuite(suiteId, false);
200:
201: if (midletSuite == null) {
202: throw new IllegalArgumentException("Suite not found");
203: }
204:
205: Logging.initLogSettings(suiteId);
206:
207: if (!midletSuite.isEnabled()) {
208: throw new IllegalStateException("Suite is disabled");
209: }
210:
211: displayEventHandler.initSuiteData(midletSuite.isTrusted());
212:
213: // set a each arg as property numbered from 0, first arg: "arg-0"
214: if (args != null) {
215: for (int i = 0; i < args.length; i++) {
216: if (args[i] != null) {
217: midletSuite.setTempProperty(
218: internalSecurityToken, "arg-" + i,
219: args[i]);
220: }
221: }
222: }
223:
224: midletClassName = MIDletApplication.getMIDletClassName(app);
225:
226: // IMPL_NOTE: This asynchronous call should be synchronous.
227: new Thread(this ).start();
228: } catch (Exception e) {
229: e.printStackTrace();
230: return -1;
231: }
232:
233: //DEBUG:System.err.println("**started");
234: return 1; // only one app can run in this container at a time
235: }
236:
237: /**
238: * Call a MIDlet's pauseApp method.
239: * This method will not return until after the the MIDlet's pauseApp
240: * method has returned.
241: *
242: * @param the application ID returned from startApp
243: */
244: public void pauseApp(int appId) {
245: try {
246: MIDletEventConsumer mec = midletStateHandler
247: .getMIDletEventConsumer(internalSecurityToken,
248: midletClassName);
249:
250: if (mec == null) {
251: return;
252: }
253:
254: // IMPL_NOTE: This asynchronous call should be synchronous.
255: mec.handleMIDletPauseEvent();
256: } catch (Exception e) {
257: e.printStackTrace();
258: }
259: }
260:
261: /**
262: * Call a MIDlet's startApp method.
263: * This method will not return until after the the MIDlet's startApp
264: * method has returned.
265: *
266: * @param the application ID returned from startApp
267: */
268: public void resumeApp(int appId) {
269: try {
270: MIDletEventConsumer mec = midletStateHandler
271: .getMIDletEventConsumer(internalSecurityToken,
272: midletClassName);
273:
274: if (mec == null) {
275: return;
276: }
277:
278: // IMPL_NOTE: This asynchronous call should be synchronous.
279: mec.handleMIDletActivateEvent();
280:
281: } catch (Exception e) {
282: e.printStackTrace();
283: }
284: }
285:
286: /**
287: * Call a MIDlet's destroyApp method.
288: * This method will not return until after the the MIDlet's startApp
289: * method has returned.
290: * <p>
291: * If force = false and the app did not get destroyed,
292: * then a RuntimeException must be thrown.
293: *
294: * @param appId the application ID returned from startApp
295: * @param force if false, give the app the option of not being destroyed
296: */
297: public void destroyApp(int appId, boolean force) {
298: // IMPL_NOTE: force=false is not supported.
299: try {
300: MIDletEventConsumer mec = midletStateHandler
301: .getMIDletEventConsumer(internalSecurityToken,
302: midletClassName);
303:
304: if (mec == null) {
305: return;
306: }
307:
308: // IMPL_NOTE: This asynchronous call should be synchronous.
309: mec.handleMIDletDestroyEvent();
310:
311: } catch (Exception e) {
312: e.printStackTrace();
313: }
314: }
315:
316: /**
317: * Set foreground display native state, so the native code will know
318: * which display can draw. This method will not be needed when
319: * JUMP uses GCI.
320: *
321: * @param displayId Display ID
322: */
323: private native void setForegroundInNativeState(int displayId);
324:
325: /** Run the MIDletStateHandler. */
326: public void run() {
327: try {
328: midletStateHandler.startSuite(this , midletSuite, 0,
329: midletClassName);
330: midletSuite.close();
331: } catch (Throwable t) {
332: t.printStackTrace();
333: } finally {
334: System.exit(0);
335: }
336: }
337:
338: // MIDletSuiteExceptionListener
339:
340: /**
341: * Handles exception occurred during MIDlet suite execution.
342: * @param t exception instance
343: */
344: public void handleException(Throwable t) {
345: t.printStackTrace();
346: }
347:
348: // MIDletStateListener
349: /**
350: * Called before a MIDlet is created.
351: * This implementation does nothing.
352: *
353: * @param suite reference to the loaded suite
354: * @param className class name of the MIDlet to be created
355: */
356: public void midletPreStart(MIDletSuite suite, String className) {
357: }
358:
359: /**
360: * Called after a MIDlet is successfully created.
361: * This implementation does nothing.
362: *
363: * @param suite reference to the loaded suite
364: * @param className Class name of the MIDlet
365: * @param externalAppId ID of given by an external application manager
366: */
367: public void midletCreated(MIDletSuite suite, String className,
368: int externalAppId) {
369: }
370:
371: /**
372: * Called before a MIDlet is activated.
373: * This implementation does nothing.
374: *
375: * @param suite reference to the loaded suite
376: * @param className class name of the MIDlet
377: */
378: public void preActivated(MIDletSuite suite, String className) {
379: }
380:
381: /**
382: * Called after a MIDlet is successfully activated. This is after
383: * the startApp method is called.
384: * This implementation does nothing.
385: *
386: * @param suite reference to the loaded suite
387: * @param midlet reference to the MIDlet
388: */
389: public void midletActivated(MIDletSuite suite, MIDlet midlet) {
390: }
391:
392: /**
393: * Called after a MIDlet is successfully paused.
394: * This implementation does nothing.
395: *
396: * @param suite reference to the loaded suite
397: * @param className class name of the MIDlet
398: */
399: public void midletPaused(MIDletSuite suite, String className) {
400: }
401:
402: /**
403: * Called after a MIDlet pauses itself. In this case pauseApp has
404: * not been called.
405: *
406: * @param suite reference to the loaded suite
407: * @param className class name of the MIDlet
408: */
409: public void midletPausedItself(MIDletSuite suite, String className) {
410: // IMPL_NOTE: The JUMPApplication API does not support this.
411: }
412:
413: /**
414: * Called when a MIDlet calls MIDlet resume request.
415: *
416: * @param suite reference to the loaded suite
417: * @param className class name of the MIDlet
418: */
419: public void resumeRequest(MIDletSuite suite, String className) {
420: MIDletEventConsumer mec = midletStateHandler
421: .getMIDletEventConsumer(internalSecurityToken,
422: className);
423: // IMPL_NOTE: The JUMPApplication API does not support this.
424: if (mec == null) {
425: return;
426: }
427:
428: mec.handleMIDletActivateEvent();
429: }
430:
431: /**
432: * Called after a MIDlet is successfully destroyed.
433: * This implementation does nothing.
434: *
435: * @param suite reference to the loaded suite
436: * @param className class name of the MIDlet
437: */
438: public void midletDestroyed(MIDletSuite suite, String className) {
439: // IMPL_NOTE: The JUMPApplication API does not support this.
440: }
441:
442: // ForegroundController
443:
444: /**
445: * Called to register a newly create Display. Must method must
446: * be called before the other methods can be called.
447: * This implementation does nothing.
448: *
449: * @param displayId ID of the Display
450: * @param ownerClassName Class name of the that owns the display
451: *
452: * @return a place holder displayable to used when "getCurrent()==null",
453: * if null is returned an empty form is used
454: */
455: public Displayable registerDisplay(int displayId,
456: String ownerClassName) {
457: currentDisplayId = displayId;
458: return null;
459: }
460:
461: /**
462: * Called to request the foreground.
463: * This implementation does nothing.
464: *
465: * @param displayId ID of the Display
466: * @param isAlert true if the current displayable is an Alert
467: */
468: public void requestForeground(int displayId, boolean isAlert) {
469: ForegroundEventConsumer fc = displayContainer
470: .findForegroundEventConsumer(displayId);
471:
472: if (fc == null) {
473: return;
474: }
475:
476: setForegroundInNativeState(displayId);
477:
478: fc.handleDisplayForegroundNotifyEvent();
479: }
480:
481: /**
482: * Called to request the background.
483: * This implementation does nothing.
484: *
485: * @param displayId ID of the Display
486: */
487: public void requestBackground(int displayId) {
488: ForegroundEventConsumer fc = displayContainer
489: .findForegroundEventConsumer(displayId);
490:
491: if (fc == null) {
492: return;
493: }
494:
495: fc.handleDisplayBackgroundNotifyEvent();
496: }
497:
498: /**
499: * Called to start preempting. The given display will preempt all other
500: * displays for this isolate.
501: *
502: * @param displayId ID of the Display
503: */
504: public void startPreempting(int displayId) {
505: requestBackground(currentDisplayId);
506: requestForeground(displayId, true);
507: }
508:
509: /**
510: * Called to end preempting.
511: *
512: * @param displayId ID of the Display
513: */
514: public void stopPreempting(int displayId) {
515: requestBackground(displayId);
516: requestForeground(currentDisplayId, false);
517: }
518:
519: // Platform Request
520:
521: /*
522: * This is empty.
523: *
524: * @param URL The URL for the platform to load.
525: *
526: * @return true if the MIDlet suite MUST first exit before the
527: * content can be fetched.
528: *
529: * @exception ConnectionNotFoundException if
530: * the platform cannot handle the URL requested.
531: *
532: */
533: public boolean dispatch(String URL)
534: throws ConnectionNotFoundException {
535: throw new ConnectionNotFoundException("not implemented");
536: }
537: }
|