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.main;
028:
029: import com.sun.midp.log.Logging;
030: import com.sun.midp.log.LogChannels;
031:
032: import com.sun.cldc.isolate.Isolate;
033:
034: import java.util.Vector;
035:
036: /**
037: * Implements the mechanism to monitor the startup of a MIDlet.
038: * It keeps track of which MIDlets are being started
039: * and are not yet in the MIDletProxyList.
040: * The information is used to avoid starting the same
041: * MIDlet twice.
042: */
043: class StartMIDletMonitor implements MIDletProxyListListener {
044:
045: /**
046: * Reference to the ProxyList.
047: */
048: private static MIDletProxyList midletProxyList;
049:
050: /**
051: * Vector of pending start requests.
052: */
053: private static Vector startPending = new Vector();
054:
055: /**
056: * The id of the MIDlet suite being started.
057: */
058: private int suiteId;
059:
060: /**
061: * The midlet of the MIDlet being started.
062: */
063: private String midlet;
064:
065: /**
066: * The IsolateID of the MIDlet being started.
067: */
068: private Isolate isolate;
069:
070: /**
071: * Initializes StartMIDletMonitor class.
072: * Shall only be called from AmsUtil.
073: * No need in security checks since it is package private method.
074: *
075: * @param theMIDletProxyList MIDletController's container
076: */
077: static void initClass(MIDletProxyList theMIDletProxyList) {
078:
079: midletProxyList = theMIDletProxyList;
080: }
081:
082: /**
083: * Construct a new StartMIDletMonitor instance to track the
084: * process of starting a MIDlet in a new Isolate.
085: * The new instance is appended to the startPending vector
086: * and is registered with the MIDletProxyList to receive
087: * notifications if/when the MIDlet starts/fails to start.
088: *
089: * @param id ID of an installed suite
090: * @param midletClassName class name of MIDlet to invoke
091: */
092: private StartMIDletMonitor(int id, String midletClassName) {
093: suiteId = id;
094: midlet = midletClassName;
095: startPending.addElement(this );
096: midletProxyList.addListener(this );
097: }
098:
099: /**
100: * Sets the Isolate associated with this starting MIDlet.
101: * It is used to cleanup the Isolate if the start does not
102: * start correctly.
103: *
104: * @param newIsolate the Isolate used to start the MIDlet
105: */
106: void setIsolate(Isolate newIsolate) {
107: isolate = newIsolate;
108: }
109:
110: /**
111: * Check if the MIDlet is already in the ProxyList or is
112: * already being started. If so, return.
113: * If not, start it. Register with the proxy list and
114: * cleanup when the start of the MIDlet
115: * succeeds (and is now in the ProxyList) or
116: * fails (and is eligible to be started again).
117: *
118: * @param id ID of an installed suite
119: * @param midlet class name of MIDlet to invoke; may be null
120: * @return the new StartMIDletMonitor to allow the MIDlet to be started;
121: * null if the MIDlet is already active or being started
122: */
123: static StartMIDletMonitor okToStart(int id, String midlet) {
124: synchronized (startPending) {
125:
126: // Verify that the requested MIDlet is not already running
127: // (is not in the MIDletProxyList)
128: if (midletProxyList.isMidletInList(id, midlet)) {
129: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
130: Logging.report(Logging.WARNING,
131: LogChannels.LC_CORE,
132: "MIDlet already running; execute ignored");
133: }
134: return null;
135: }
136:
137: /*
138: * Find the StartMIDletMonitor instance
139: * to track the startup, (if any)
140: */
141: StartMIDletMonitor start = findMonitor(id, midlet);
142: if (start == null) {
143: // Not already starting; register new start
144: start = new StartMIDletMonitor(id, midlet);
145: } else {
146: // MIDlet is already started; return null
147: start = null;
148: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
149: Logging.report(Logging.WARNING,
150: LogChannels.LC_CORE,
151: "MIDlet already started; execute ignored");
152: }
153: }
154: return start;
155: }
156: }
157:
158: /**
159: * Scan the startPending list for a matching id and MIDlet.
160: * The caller must synchronize using {@link #startPending}.
161: * If <code>midlet</code> is null then it only checks to see
162: * if the suite is started and returns any monitor for the suite.
163: * To prevent using stale Isolate state; check that the Isolate (if any)
164: * has not terminated.
165: *
166: * @param id ID of an installed suite
167: * @param midlet class name of MIDlet to invoke
168: * @return a StartMIDletMonitor entry with id and midlet;
169: * otherwise <code>null</code>
170: */
171: private static StartMIDletMonitor findMonitor(int id, String midlet) {
172: for (int i = 0; i < startPending.size(); i++) {
173: StartMIDletMonitor pending = (StartMIDletMonitor) startPending
174: .elementAt(i);
175: // If there is a terminated Isolate in the list, clean it up
176: if (pending.isolate != null
177: && pending.isolate.isTerminated()) {
178: // Isolate is not alive, clean the pending entry
179: startPending.removeElementAt(i);
180: midletProxyList.removeListener(pending);
181: // Recheck the element at the same index
182: i--;
183: continue; // keep looking
184: }
185:
186: if (id == pending.suiteId
187: && (midlet == null || midlet.equals(pending.midlet))) {
188: return pending;
189: }
190: }
191: return null;
192: }
193:
194: /**
195: * Cleanup the matching entry in the startPending list.
196: * Once removed; the MIDlet will be eligible to be started
197: * again.
198: * @param id ID of an installed suite of the notifying MIDlet
199: * @param midlet class name of MIDlet of the notifying MIDlet
200: */
201: private void cleanupPending(int id, String midlet) {
202: synchronized (startPending) {
203: // If the notification is for this monitor
204: if (id == suiteId
205: && (midlet == null || midlet.equals(midlet))) {
206: // Remove from the startPending list
207: startPending.removeElement(this );
208:
209: // Remove the instance as a listener of the MIDletProxyList
210: midletProxyList.removeListener(this );
211: }
212: }
213: }
214:
215: /**
216: * Called when a MIDlet is added to the list.
217: * If there's a match in the startPending list clean it up.
218: *
219: * @param midlet The proxy of the MIDlet being added
220: */
221: public void midletAdded(MIDletProxy midlet) {
222: IsolateMonitor.addIsolate(midlet, isolate);
223: cleanupPending(midlet.getSuiteId(), midlet.getClassName());
224: }
225:
226: /**
227: * Called when the state of a MIDlet in the list is updated.
228: * If there's a match in the startPending list clean it up.
229: *
230: * @param midlet The proxy of the MIDlet that was updated
231: * @param fieldId code for which field of the proxy was updated
232: */
233: public void midletUpdated(MIDletProxy midlet, int fieldId) {
234: }
235:
236: /**
237: * Called when a MIDlet is removed from the list.
238: * If there's a match in the startPending list clean it up.
239: *
240: * @param midlet The proxy of the removed MIDlet
241: */
242: public void midletRemoved(MIDletProxy midlet) {
243: cleanupPending(midlet.getSuiteId(), midlet.getClassName());
244: }
245:
246: /**
247: * Called when error occurred while starting a MIDlet object.
248: * If there's a match in the startPending list clean it up.
249: *
250: * @param externalAppId ID assigned by the external application manager
251: * @param suiteId Suite ID of the MIDlet
252: * @param className Class name of the MIDlet
253: * @param errorCode start error code
254: * @param errorDetails start error details
255: */
256: public void midletStartError(int externalAppId, int suiteId,
257: String className, int errorCode, String errorDetails) {
258: cleanupPending(suiteId, className);
259: }
260: }
|