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 java.util.*;
030:
031: import com.sun.cldc.isolate.Isolate;
032:
033: /**
034: * Implements the mechanism to monitor MIDlet suites isolate.
035: * The StartMIDletMonitor provides the isolate references at it gets
036: * a MIDlet create notification from the MIDletProxyList. When an isolate
037: * terminates it notifies the native application manager. The notification is
038: * needed for native auto testers because the notification that the test MIDlet
039: * is destoryed does not indicate that the VM has closed it JAR.
040: */
041: class IsolateMonitor implements MIDletProxyListListener {
042:
043: /** Reference to the ProxyList. */
044: private static MIDletProxyList midletProxyList;
045:
046: /** Reference to the Isolate Monitor. */
047: private static IsolateMonitor monitor;
048:
049: /** Table of isolates indexed by midlet proxies. */
050: private Hashtable isolates;
051:
052: /** What objects should get list changes. */
053: private Vector listeners;
054:
055: /**
056: * Initializes StartMIDletMonitor class.
057: * Shall only be called from AmsUtil.
058: * No need in security checks since it is package private method.
059: *
060: * @param theMIDletProxyList MIDletController's container
061: */
062: static void initClass(MIDletProxyList theMIDletProxyList) {
063:
064: midletProxyList = theMIDletProxyList;
065:
066: monitor = new IsolateMonitor();
067: }
068:
069: /**
070: * Construct a new StartMIDletMonitor instance to track the
071: * process of starting a MIDlet in a new Isolate.
072: * The new instance is appended to the startPending vector
073: * and is registered with the MIDletProxyList to receive
074: * notifications if/when the MIDlet starts/fails to start.
075: */
076: private IsolateMonitor() {
077: isolates = new Hashtable();
078: listeners = new Vector();
079: midletProxyList.addListener(this );
080: }
081:
082: /**
083: * Adds the Isolate associated with a started MIDlet.
084: *
085: * @param proxy proxy of a started MIDlet
086: * @param isolate the Isolate of the started MIDlet, for systems that
087: * run multiple Isolates from a suite concurrently this
088: * may be a duplicate isolate
089: */
090: static void addIsolate(MIDletProxy proxy, Isolate isolate) {
091: synchronized (monitor.isolates) {
092: monitor.isolates.put(proxy, isolate);
093: }
094: }
095:
096: /**
097: * Add a listener for MIDlet suite terminations.
098: *
099: * @param listener Isolate monitor listener
100: */
101: public static void addListener(IsolateMonitorListener listener) {
102: monitor.listeners.addElement(listener);
103: }
104:
105: /**
106: * Called when a MIDlet is added to the list.
107: *
108: * @param midlet The proxy of the MIDlet being added
109: */
110: public void midletAdded(MIDletProxy midlet) {
111: }
112:
113: /**
114: * Called when the state of a MIDlet in the list is updated.
115: *
116: * @param midlet The proxy of the MIDlet that was updated
117: * @param fieldId code for which field of the proxy was updated
118: */
119: public void midletUpdated(MIDletProxy midlet, int fieldId) {
120: }
121:
122: /**
123: * Called when a MIDlet is removed from the list.
124: * If this is the last MIDlet in its isolate then start a termination
125: * notification thread to wait on its isolate.
126: *
127: * @param proxy The proxy of the removed MIDlet
128: */
129: public void midletRemoved(MIDletProxy proxy) {
130: synchronized (isolates) {
131: if (lastInIsolate(proxy)) {
132: startNotificationThread(proxy);
133: }
134:
135: isolates.remove(proxy);
136: }
137: }
138:
139: /**
140: * Called when error occurred while starting a MIDlet object.
141: *
142: * @param externalAppId ID assigned by the external application manager
143: * @param suiteId Suite ID of the MIDlet
144: * @param className Class name of the MIDlet
145: * @param errorCode start error code
146: * @param errorDetails start error details
147: */
148: public void midletStartError(int externalAppId, int suiteId,
149: String className, int errorCode, String errorDetails) {
150: }
151:
152: /**
153: * Determine if a MIDlet is the last MIDlet in an isolate.
154: *
155: * @param proxy proxy of MIDlet
156: *
157: * @return true if the MIDlet is the last MIDlet in the isolate
158: */
159: private boolean lastInIsolate(MIDletProxy proxy) {
160: Isolate isolate = (Isolate)isolates.get(proxy);
161: int midletCount = 0;
162:
163: if (isolate != null) {
164: Enumeration enum = isolates.elements();
165:
166: while (enum.hasMoreElements()) {
167: Isolate current = (Isolate)enum.nextElement();
168:
169: if (current == isolate) {
170: midletCount++;
171: }
172: }
173: }
174:
175: return midletCount == 1;
176: }
177:
178: /**
179: * Start a thread that will wait the MIDlet's isolate to terminate and
180: * then notify the native application manager. This method will also
181: * remove the MIDlet from the monitor's MIDlet list.
182: *
183: * @param proxy proxy of MIDlet
184: */
185: private void startNotificationThread(MIDletProxy proxy) {
186: Isolate isolate = (Isolate) isolates.get(proxy);
187: TerminationNotifier notifier = new TerminationNotifier();
188:
189: notifier.midlet = proxy;
190: notifier.isolate = isolate;
191: notifier.parent = this ;
192:
193: new Thread(notifier).start();
194: }
195:
196: /**
197: * Notifies the listeners that a suite has terminated.
198: *
199: * @param suiteId ID of the MIDlet suite
200: */
201: void notifyListeners(int suiteId) {
202: synchronized (listeners) {
203: for (int i = 0; i < listeners.size(); i++) {
204: IsolateMonitorListener listener = (IsolateMonitorListener) listeners
205: .elementAt(i);
206:
207: listener.suiteTerminated(suiteId);
208: }
209: }
210: }
211: }
212:
213: /**
214: * Waits for an isolate to terminate and then notifies the native app
215: * manager.
216: */
217: class TerminationNotifier implements Runnable {
218: /** MIDlet information. */
219: MIDletProxy midlet;
220:
221: /** Isolate of the MIDlet. */
222: Isolate isolate;
223:
224: /** Parent monitor. */
225: IsolateMonitor parent;
226:
227: /** Performs this classes function. */
228: public void run() {
229: isolate.waitForExit();
230: parent.notifyListeners(midlet.getSuiteId());
231: }
232: }
|