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:
027: package com.sun.midp.midlet;
028:
029: import javax.microedition.midlet.MIDlet;
030: import javax.microedition.midlet.MIDletStateChangeException;
031:
032: import com.sun.midp.security.Permissions;
033: import com.sun.midp.security.SecurityToken;
034:
035: import com.sun.midp.log.Logging;
036: import com.sun.midp.log.LogChannels;
037:
038: /**
039: * The MIDletStateHandler starts and controls MIDlets through the lifecycle
040: * states.
041: * MIDlets are created using its no-arg Constructor. Once created
042: * a MIDlet is sequenced through the <code>ACTIVE</code>,
043: * <code>PAUSED</code>, and <code>DESTROYED</code> states.
044: * <p>
045: * The MIDletStateHandler is a singleton for the suite being run and
046: * is retrieved with getMIDletStateHandler(). This allow the
047: * MIDletStateHandler to be the anchor of trust internally for the MIDP API,
048: * restricted methods can obtain the MIDletStateHandler for a MIDlet suite
049: * inorder to check the properties and actions of a suite.
050: * Because of this, there MUST only be one a MIDlet suite per
051: * MIDletStateHandler. In addition a method can assume that the application
052: * manager is the caller if there is no suite started.</p>
053: * <p>
054: * The MIDlet methods are protected in the javax.microedition.midlet package
055: * so the MIDletStateHandler can not call them directly. The MIDletState
056: * object and
057: * MIDletTunnel subclass class allow the MIDletStateHandler to hold the state
058: * of the
059: * MIDlet and to invoke methods on it. The MIDletState instance is created
060: * by the MIDlet when it is constructed.
061: * <p>
062: * This implementation of the MIDletStateHandler introduces
063: * extra internal MIDlet states to allow processing of MIDlet
064: * requested state changes in the control thread and serialized with
065: * other state changes. The additional states are:
066: * <UL>
067: * <LI> <code>ACTIVE_PENDING</code> - The MIDlet is still PAUSED but
068: * will be <code>ACTIVE</code> after startApp is called when the state is
069: * next processed.
070: * <LI> <code>PAUSE_PENDING</code> - The MIDlet is still ACTIVE but
071: * will be <code>PAUSED</code> after pauseApp is called when the state is
072: * next processed.
073: * <LI> <code>DESTROY_PENDING</code> - Indicates that the MIDlet needs
074: * to be <code>DESTROYED</code>. The MIDlet's destroyApp has not yet been
075: * called.
076: * </UL>
077: * The MIDletStateHandler loops, looking for MIDlets that require state changes
078: * and making the requested changes including calling methods in
079: * the MIDlet to make the change.
080: * <p>
081: * When a MIDlet's state is changed to <code>ACTIVE</code>,
082: * <code>PAUSED</code>, or <code>DESTROYED</code> the MIDlet state listener
083: * is notified of the change, which in turn sends the notification onto
084: * the central AMS.
085: *
086: * @see MIDlet
087: * @see MIDletPeer
088: * @see MIDletLoader
089: * @see MIDletStateHandler
090: */
091:
092: public class MIDletStateHandler {
093: /** the current MIDlet suite. */
094: private MIDletSuite midletSuite;
095: /** loads the MIDlets from a suite's JAR in a VM specific way. */
096: private MIDletLoader midletLoader;
097: /** array of MIDlets. */
098: private MIDletPeer[] midlets;
099: /** current number of MIDlets [0..n-1]. */
100: private int nmidlets;
101: /** next index to be scanned by selectForeground. */
102: private int scanIndex;
103:
104: /** The event handler of all MIDlets in an Isolate. */
105: private static MIDletStateHandler stateHandler;
106: /** The listener for the state of all MIDlets in an Isolate. */
107: private static MIDletStateListener listener;
108:
109: /** Serializes the creation of MIDlets. */
110: private static Object createMIDletLock = new Object();
111:
112: /** New MIDlet peer waiting for the next MIDlet created to claim it. */
113: private static MIDletPeer newMidletPeer;
114:
115: /** MIDlet peer for MIDlet being constructed but not registered yet. */
116: private MIDletPeer underConstructionPeer;
117:
118: /**
119: * Construct a new MIDletStateHandler object.
120: */
121: private MIDletStateHandler() {
122: nmidlets = 0;
123:
124: // start with 5 empty slots, we will add more if needed
125: midlets = new MIDletPeer[5];
126: }
127:
128: /**
129: * Gets the MIDletStateHandler that manages the lifecycle states of
130: * MIDlets running in an Isolate.
131: * <p>
132: * If the instance of the MIDletStateHandler has already been created
133: * it is returned. If not it is created.
134: * The instance becomes the MIDletStateHandler for this suite.
135: * <p>
136: * The fact that there is one handler per Isolate
137: * is a security feature. Also a security feature, is that
138: * getMIDletStateHandler is
139: * static, so API can find out what suite is calling, if in the future
140: * multiple suites can be run in the same VM, the MIDlet state handler
141: * for each suite
142: * should be loaded in a different classloader or have some other way
143: * having multiple instances of static class data.
144: *
145: * @return the MIDlet state handler for this Isolate
146: */
147: public static synchronized MIDletStateHandler getMidletStateHandler() {
148: /*
149: * If the midlet state handler has not been created, create one now.
150: */
151: if (stateHandler == null) {
152: /* This is the default scheduler class */
153: stateHandler = new MIDletStateHandler();
154: }
155:
156: return stateHandler;
157: }
158:
159: /**
160: * Initializes MIDlet State Handler.
161: *
162: * @param token security token for initilaization
163: * @param theMIDletStateListener processes MIDlet states in a
164: * VM specific way
165: * @param theMidletLoader loads a MIDlet in a VM specific way
166: * @param thePlatformRequestHandler the platform request handler
167: */
168: public void initMIDletStateHandler(SecurityToken token,
169: MIDletStateListener theMIDletStateListener,
170: MIDletLoader theMidletLoader,
171: PlatformRequest thePlatformRequestHandler) {
172:
173: token.checkIfPermissionAllowed(Permissions.AMS);
174:
175: listener = theMIDletStateListener;
176: midletLoader = theMidletLoader;
177:
178: MIDletPeer.initClass(this , listener, thePlatformRequestHandler);
179: }
180:
181: /**
182: * Starts a MIDlet from outside of the package.
183: *
184: * @param classname name of MIDlet class
185: * @param displayName name to show the user
186: *
187: * @exception SecurityException if the suite does not have the
188: * AMS permission.
189: * @exception ClassNotFoundException is thrown, if the MIDlet main class is
190: * not found
191: * @exception InstantiationException is thrown, if the MIDlet can not be
192: * created
193: * @exception IllegalAccessException is thrown, if the MIDlet is not
194: * permitted to perform a specific operation
195: */
196: public void startMIDlet(String classname, String displayName)
197: throws ClassNotFoundException, InstantiationException,
198: IllegalAccessException {
199: startMIDlet(0, classname, displayName);
200: }
201:
202: /**
203: * Starts a MIDlet from outside of the package.
204: *
205: * @param externalAppId ID of given by an external application manager
206: * @param classname name of MIDlet class
207: * @param displayName name to show the user
208: *
209: * @exception SecurityException if the suite does not have the
210: * AMS permission.
211: * @exception ClassNotFoundException is thrown, if the MIDlet main class is
212: * not found
213: * @exception InstantiationException is thrown, if the MIDlet can not be
214: * created
215: * @exception IllegalAccessException is thrown, if the MIDlet is not
216: * permitted to perform a specific operation
217: */
218: public void startMIDlet(int externalAppId, String classname,
219: String displayName) throws ClassNotFoundException,
220: InstantiationException, IllegalAccessException {
221:
222: midletSuite.checkIfPermissionAllowed(Permissions.AMS);
223: createAndRegisterMIDlet(externalAppId, classname);
224: }
225:
226: /**
227: * Starts a MIDlet from outside of the package.
228: *
229: * @param token security token of the caller
230: * @param classname name of MIDlet class
231: * @param displayName name to show the user
232: *
233: * @exception SecurityException if the caller does not have the
234: * AMS permission.
235: * @exception ClassNotFoundException is thrown, if the MIDlet main class is
236: * not found
237: * @exception InstantiationException is thrown, if the MIDlet can not be
238: * created
239: * @exception IllegalAccessException is thrown, if the MIDlet is not
240: * permitted to perform a specific operation
241: */
242: public void startMIDlet(SecurityToken token, String classname,
243: String displayName) throws ClassNotFoundException,
244: InstantiationException, IllegalAccessException {
245: startMIDlet(token, 0, classname, displayName);
246: }
247:
248: /**
249: * Starts a MIDlet from outside of the package.
250: *
251: * @param token security token of the caller
252: * @param externalAppId ID of given by an external application manager
253: * @param classname name of MIDlet class
254: * @param displayName name to show the user
255: *
256: * @exception SecurityException if the caller does not have the
257: * AMS permission.
258: * @exception ClassNotFoundException is thrown, if the MIDlet main class is
259: * not found
260: * @exception InstantiationException is thrown, if the MIDlet can not be
261: * created
262: * @exception IllegalAccessException is thrown, if the MIDlet is not
263: * permitted to perform a specific operation
264: */
265: public void startMIDlet(SecurityToken token, int externalAppId,
266: String classname, String displayName)
267: throws ClassNotFoundException, InstantiationException,
268: IllegalAccessException {
269:
270: token.checkIfPermissionAllowed(Permissions.AMS);
271: createAndRegisterMIDlet(externalAppId, classname);
272: }
273:
274: /**
275: * Gets the class name first midlet in the list of running MIDlets.
276: *
277: * @return the classname or null if no midlet are running
278: */
279: public String getFirstRunningMidlet() {
280: synchronized (this ) {
281: if (nmidlets <= 0) {
282: return null;
283: }
284:
285: return midlets[0].midlet.getClass().getName();
286: }
287: }
288:
289: /**
290: * Registers a MIDlet being constructed.
291: *
292: * @param midlet to be registered with this state handler
293: */
294: private void register(MIDlet midlet) {
295: synchronized (this ) {
296: MIDletPeer state = MIDletPeer.getMIDletPeer(midlet);
297:
298: /*
299: * If a MIDlet of the same class is already running
300: * Make the existing MIDlet current so that startSuite()
301: * will run it
302: */
303: int i = findMIDletByClass(state);
304: if (i >= 0) {
305: state.setState(MIDletPeer.DESTROY_PENDING);
306: // Fall into adding it to the list so destroyApp
307: // can be called at a reasonable time.
308: }
309:
310: // Grow the list if necessary
311: if (nmidlets >= midlets.length) {
312: MIDletPeer[] n = new MIDletPeer[nmidlets + 5];
313: System.arraycopy(midlets, 0, n, 0, nmidlets);
314: midlets = n;
315: }
316:
317: // Add it to the end of the list
318: midlets[nmidlets++] = state;
319:
320: // MIDlet peer is registered now
321: underConstructionPeer = null;
322:
323: this .notify();
324: }
325: }
326:
327: /**
328: * Creates and register MIDlet with VM notification
329: * of the MIDlet's startup phase.
330: *
331: * @param externalAppId ID of given by an external application manager
332: * @param classname name of MIDlet class
333: *
334: * @exception ClassNotFoundException if the MIDlet class is
335: * not found
336: * @exception InstantiationException if the MIDlet cannot be
337: * created
338: * @exception IllegalAccessException if the MIDlet is not
339: * permitted to perform a specific operation
340: */
341: private void createAndRegisterMIDlet(int externalAppId,
342: String classname) throws ClassNotFoundException,
343: InstantiationException, IllegalAccessException {
344:
345: listener.midletPreStart(getMIDletSuite(), classname);
346: register(createMIDlet(externalAppId, classname));
347: }
348:
349: /**
350: * Provides a object with a mechanism to retrieve
351: * <code>MIDletSuite</code> being run.
352: *
353: * @return MIDletSuite being run
354: */
355: public MIDletSuite getMIDletSuite() {
356: return midletSuite;
357: }
358:
359: /**
360: * Runs MIDlets until there are none.
361: * Handle any pending state transitions of any MIDlet.
362: * If there are none, wait for transitions.
363: * If there is no foreground MIDlet select one that is ACTIVE and
364: * has setCurrent != null.
365: * <p>
366: * If the foreground MIDlet changes from the ACTIVE_FOREGROUND state
367: * it automatically looses the foreground and and new one is selected.
368: *
369: * @param exceptionHandler the handler for midlet execution exceptions.
370: * @param aMidletSuite the current midlet suite
371: * @param externalAppId ID of given by an external application manager
372: * @param classname name of MIDlet class
373: *
374: * @exception ClassNotFoundException is thrown, if the MIDlet main class is
375: * not found
376: * @exception InstantiationException is thrown, if the MIDlet can not be
377: * created
378: * @exception IllegalAccessException is thrown, if the MIDlet is not
379: * permitted to perform a specific operation
380: */
381: public void startSuite(
382: MIDletSuiteExceptionListener exceptionHandler,
383: MIDletSuite aMidletSuite, int externalAppId,
384: String classname) throws ClassNotFoundException,
385: InstantiationException, IllegalAccessException {
386:
387: if (midletSuite != null) {
388: throw new RuntimeException(
389: "There is already a MIDlet Suite running.");
390:
391: }
392:
393: midletSuite = aMidletSuite;
394: createAndRegisterMIDlet(externalAppId, classname);
395:
396: /*
397: * Until there are no MIDlets
398: * Scan all the MIDlets looking for state changes.
399: */
400: while (nmidlets > 0) {
401: try {
402: MIDletPeer curr;
403: int state;
404:
405: /*
406: * A MIDlet can change the MIDlet concurrently.
407: * the MIDlet state handler this is used to
408: * synchronize these changes. However any calls to outside of
409: * this package should NOT be done holding
410: * "this".
411: * For this reason there are 2 phases each with a switch
412: * statement to process a state.
413: *
414: * The state is obtained and changed before the work is
415: * done so that when "this" is released to
416: * perform external calls for that state, any state change done
417: * by the MIDlet concurrently are not lost.
418: */
419:
420: synchronized (this ) {
421: /*
422: * Find the highest priority state of any MIDlet and
423: * process, but do not hold the lock while processing
424: * to avoid deadlocks with LCDUI and event handling.
425: * Perform state changes with a lock so
426: * no state changes are lost.
427: */
428: curr = selectByPriority();
429: state = curr.getState();
430:
431: switch (state) {
432: case MIDletPeer.ACTIVE:
433: // fall through
434: case MIDletPeer.PAUSED:
435: // Wait for some change in the state of a MIDlet
436: // that needs attention
437: try {
438: this .wait();
439: } catch (InterruptedException e) {
440:
441: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
442: Logging.report(Logging.WARNING,
443: LogChannels.LC_AMS,
444: "InterruptedException "
445: + "during mutex wait");
446: }
447: }
448:
449: continue;
450:
451: case MIDletPeer.ACTIVE_PENDING:
452: // Start the MIDlet
453: curr.setStateWithoutNotify(MIDletPeer.ACTIVE);
454: break;
455:
456: case MIDletPeer.PAUSE_PENDING:
457: // The system wants the MIDlet paused
458: curr.setStateWithoutNotify(MIDletPeer.PAUSED);
459: break;
460:
461: case MIDletPeer.DESTROY_PENDING:
462: curr
463: .setStateWithoutNotify(MIDletPeer.DESTROYED);
464: break;
465:
466: case MIDletPeer.DESTROYED:
467: unregister(curr);
468: break;
469:
470: default:
471: throw new Error("Illegal MIDletPeer state "
472: + curr.getState());
473: }
474: }
475:
476: /** perform work that may block outside of "this" */
477: switch (state) {
478: case MIDletPeer.ACTIVE_PENDING:
479: try {
480: listener.preActivated(getMIDletSuite(), curr
481: .getMIDlet().getClass().getName());
482:
483: curr.startApp();
484: } catch (Throwable ex) {
485: if (Logging.TRACE_ENABLED) {
486: Logging.trace(ex,
487: "startApp threw an Exception");
488: }
489: curr.setState(MIDletPeer.DESTROY_PENDING);
490: exceptionHandler.handleException(ex);
491: break;
492: }
493:
494: /*
495: * The actual state of the MIDlet is already active.
496: * But any notifications done after startApp call.
497: */
498: listener.midletActivated(getMIDletSuite(), curr
499: .getMIDlet());
500: break;
501:
502: case MIDletPeer.PAUSE_PENDING:
503: try {
504: curr.pauseApp();
505: } catch (Throwable ex) {
506: if (Logging.TRACE_ENABLED) {
507: Logging.trace(ex,
508: "pauseApp threw an Exception");
509: }
510:
511: curr.setState(MIDletPeer.DESTROY_PENDING);
512: exceptionHandler.handleException(ex);
513: break;
514: }
515:
516: /*
517: * The actual state of the MIDlet is already paused.
518: * But any notifications done after pauseApp() call.
519: */
520: listener.midletPaused(getMIDletSuite(), curr
521: .getMIDlet().getClass().getName());
522:
523: break;
524:
525: case MIDletPeer.DESTROY_PENDING:
526: // If the MIDlet is in the DESTROY_PENDING state
527: // call its destroyApp method to clean it up.
528: try {
529: // Tell the MIDlet to cleanup.
530: curr.destroyApp(true);
531: } catch (MIDletStateChangeException ex) {
532: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
533: Logging
534: .report(
535: Logging.WARNING,
536: LogChannels.LC_AMS,
537: "destroyApp threw a "
538: + "MIDletStateChangeException");
539: }
540: exceptionHandler.handleException(ex);
541: } catch (Throwable ex) {
542: if (Logging.TRACE_ENABLED) {
543: Logging.trace(ex,
544: "destroyApp threw an Exception");
545: }
546: exceptionHandler.handleException(ex);
547: }
548: break;
549:
550: case MIDletPeer.DESTROYED:
551: listener.midletDestroyed(getMIDletSuite(), curr
552: .getMIDlet().getClass().getName());
553: break;
554: }
555: } catch (Throwable ex) {
556: if (Logging.TRACE_ENABLED) {
557: Logging.trace(ex, "Exception in startSuite");
558: }
559: exceptionHandler.handleException(ex);
560: }
561: }
562: }
563:
564: /**
565: * Destroys all running MIDlets in this suite only. This method is only
566: * used by the push registry in single VM mode.
567: */
568: public void destroySuite() {
569: synchronized (this ) {
570: for (int i = 0; i < nmidlets; i++) {
571: if (midlets[i].getState() != MIDletPeer.DESTROYED) {
572: midlets[i]
573: .setStateWithoutNotify(MIDletPeer.DESTROY_PENDING);
574: }
575: }
576:
577: this .notify();
578: }
579: }
580:
581: /**
582: * Checks if the named <code>MIDlet</code> has already been instantiated.
583: * @param name class name of <code>MIDlet</code> to test if
584: * currently run
585: * @return <code>true</code> if an instance of the MIDlet is already
586: * running
587: */
588: public boolean isRunning(String name) {
589: boolean found = false;
590: synchronized (this ) {
591: if (underConstructionPeer != null
592: && underConstructionPeer.getMIDlet().getClass()
593: .getName().equals(name)) {
594: found = true;
595: } else {
596: for (int i = 0; i < nmidlets; i++) {
597: if (midlets[i].getMIDlet().getClass().getName()
598: .equals(name)) {
599: // found only if has not been destroyed
600: found = (midlets[i].getState() != MIDletPeer.DESTROYED);
601: break;
602: }
603: }
604: }
605: }
606: return found;
607: }
608:
609: /**
610: * Gets MIDlet event consumer of the named <code>MIDlet</code>.
611: *
612: * @param token security token for authorizing the caller
613: * @param name class name of <code>MIDlet</code>
614: *
615: * @return reference of the MIDlet event consumer
616: */
617: public MIDletEventConsumer getMIDletEventConsumer(
618: SecurityToken token, String name) {
619: token.checkIfPermissionAllowed(Permissions.AMS);
620:
621: synchronized (this ) {
622: for (int i = 0; i < nmidlets; i++) {
623: if (midlets[i].getMIDlet().getClass().getName().equals(
624: name)) {
625: return midlets[i];
626: }
627: }
628: }
629:
630: return null;
631: }
632:
633: /**
634: * Looks through the current MIDlets and select one to
635: * be processed.
636: * <p>Note: that this method is called while synchronized on "this"
637: * @return the MIDlet to process next
638: */
639: private MIDletPeer selectByPriority() {
640: MIDletPeer found = null; // Chosen MIDletPeer
641: int state = -1; // the state of the chosen MIDlet
642:
643: /*
644: * Find the most desirable MIDlet based on its state
645: * The higher state values are preferred because they
646: * are needed for cleanup.
647: */
648: for (int i = nmidlets - 1; i >= 0; i--) {
649:
650: // make sure index is inside current array, favoring the end
651: if (scanIndex < 0 || scanIndex >= nmidlets)
652: scanIndex = nmidlets - 1;
653:
654: // Pick this MIDlet if the state is higher priority
655: int s = midlets[scanIndex].getState();
656: if (s > state) {
657: found = midlets[scanIndex];
658: state = s;
659: }
660: scanIndex--;
661: }
662: return found;
663: }
664:
665: /**
666: * Removes a MIDlet from the list if it is there,
667: * otherwise ignore the request.
668: * Call only while synchronized on "this".
669: * @param m the MIDlet to remove
670: */
671: private void unregister(MIDletPeer m) {
672: // Find it in the list and switch the last one for it.
673: for (int i = 0; i < nmidlets; i++) {
674: if (m == midlets[i]) {
675: // Switch the last MIDlet into that offset.
676: midlets[i] = midlets[nmidlets - 1];
677:
678: // null out from array and remove from map to allow for GC
679: midlets[--nmidlets] = null;
680: break;
681: }
682: }
683: }
684:
685: /**
686: * Finds a MIDlet in the list by it class.
687: * Only a single MIDlet of a class can be active at
688: * a time.
689: * Must be called synchronized on "this".
690: * @param m the MIDlet to find
691: * @return the index in the array of MIDlets.
692: * return -1 if the MIDlet is not found.
693: */
694: private int findMIDletByClass(MIDletPeer m) {
695: // Find it in the list
696: for (int i = 0; i < nmidlets; i++) {
697: if (m.getMIDlet().getClass() == midlets[i].getMIDlet()
698: .getClass()) {
699: return i;
700: }
701: }
702: return -1;
703: }
704:
705: /**
706: * Creates a MIDlet.
707: *
708: * @param externalAppId ID of given by an external application manager
709: * @param classname name of MIDlet class
710: *
711: * @return newly created MIDlet
712: *
713: * @exception ClassNotFoundException if the MIDlet class is
714: * not found
715: * @exception InstantiationException if the MIDlet cannot be
716: * created
717: * @exception IllegalAccessException if the MIDlet is not
718: * permitted to perform a specific operation
719: */
720: private MIDlet createMIDlet(int externalAppId, String classname)
721: throws ClassNotFoundException, InstantiationException,
722: IllegalAccessException {
723: MIDlet midlet = null;
724:
725: synchronized (createMIDletLock) {
726: /*
727: * Just in case there is a hole we have not found.
728: * Make sure there is not a new MIDlet state already created.
729: */
730: if (newMidletPeer != null) {
731: throw new SecurityException("Recusive MIDlet creation");
732: }
733:
734: newMidletPeer = new MIDletPeer();
735: underConstructionPeer = newMidletPeer;
736: try {
737: /*
738: * We can send a MIDlet create event because the peer that
739: * the AMS uses has been created.
740: */
741: listener.midletCreated(getMIDletSuite(), classname,
742: externalAppId);
743:
744: try {
745: midlet = midletLoader.newInstance(getMIDletSuite(),
746: classname);
747: return midlet;
748: } finally {
749: if (midlet == null) {
750: /*
751: * The MIDlet was not constructed, send destroy
752: * notification to remove the peer from any lists.
753: */
754: listener.midletDestroyed(getMIDletSuite(),
755: classname);
756: }
757: }
758: } finally {
759: /* Make sure the creation window is closed. */
760: newMidletPeer = null;
761: }
762: }
763: }
764:
765: /**
766: * Called by the MIDlet constructor to a new MIDletPeer object.
767: *
768: * @param token security token for authorizing the caller
769: * @param m the MIDlet for which this state is being created;
770: * must not be <code>null</code>.
771: * @return the preallocated MIDletPeer for the MIDlet being constructed by
772: * {@link #createMIDlet}
773: *
774: * @exception SecurityException AMS permission is not granted and
775: * if is constructor is not being called in the context of
776: * <code>createMIDlet</code>.
777: */
778: public static MIDletPeer newMIDletPeer(SecurityToken token, MIDlet m) {
779: token.checkIfPermissionAllowed(Permissions.MIDP);
780:
781: synchronized (createMIDletLock) {
782: MIDletPeer temp;
783:
784: if (newMidletPeer == null) {
785: throw new SecurityException(
786: "MIDlet not constructed by createMIDlet.");
787: }
788:
789: temp = newMidletPeer;
790: newMidletPeer = null;
791: temp.midlet = m;
792: return temp;
793: }
794: }
795:
796: /**
797: * Retrieves current state of the MIDlet given.
798: * @param midlet the MIDlet of interest
799: * @return the MIDlet state as defined in MIDletPeer class
800: */
801: public static int getMIDletState(MIDlet midlet) {
802: return MIDletPeer.getMIDletPeer(midlet).getState();
803: }
804: }
|