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.lcdui.ForegroundEventProducer;
030: import com.sun.midp.midlet.*;
031: import com.sun.midp.jsr.JSRInitializer;
032: import com.sun.midp.automation.AutomationInitializer;
033: import com.sun.midp.io.j2me.push.PushRegistryInternal;
034: import com.sun.midp.content.CHManager;
035: import com.sun.midp.wma.WMACleanupMonitor;
036: import com.sun.midp.configurator.Constants;
037: import com.sun.midp.i18n.*;
038: import com.sun.midp.log.*;
039:
040: /**
041: * The first class loaded in VM by midp_run_midlet_with_args to initialize
042: * internal security the internal AMS classes and start a MIDlet suite.
043: * <p>
044: * In SVM mode it handles all MIDlet suites (AMS and internal romized,
045: * and application).
046: * <p>
047: * In MVM mode it only handles the first MIDlet suite isolate which is used
048: * by the MIDP AMS and other internal MIDlets.
049: */
050: public class MIDletSuiteLoader extends CldcMIDletSuiteLoader {
051:
052: /** Command state of the MIDlet suite loader */
053: protected CommandState state;
054:
055: /** Disable startup error alerts, uninitialized by default */
056: protected int disableAlerts = -1;
057:
058: /** MIDlet state event producer needed by AMS */
059: protected MIDletEventProducer midletEventProducer;
060:
061: /** Foreground event producer needed by AMS. */
062: protected static ForegroundEventProducer foregroundEventProducer;
063:
064: /** List of MIDlet proxies needed by AMS */
065: protected MIDletProxyList midletProxyList;
066:
067: /**
068: * Extends base class initialization with initializatons
069: * specific for the AMS task
070: */
071: protected void init() {
072: /*
073: * WARNING: Don't add any calls before this !
074: *
075: * Register AMS task ID native global variable.
076: * Since native functions rely on this value to distinguish
077: * whether Java AMS is running, this MUST be called before any
078: * other native functions from this Isolate. I.E. This call
079: * must be the first thing this main make.
080: */
081: MIDletSuiteUtils.registerAmsIsolateId();
082: super .init();
083:
084: }
085:
086: /** Creates environment objects needed to AMS task */
087: protected void createSuiteEnvironment() {
088: super .createSuiteEnvironment();
089:
090: midletEventProducer = new MIDletEventProducer(eventQueue);
091: foregroundEventProducer = new ForegroundEventProducer(
092: eventQueue);
093: midletProxyList = new MIDletProxyList(eventQueue);
094: }
095:
096: /**
097: * Inits global systems common for all started MIDlet suite tasks.
098: * The systems should be initialized only once in the AMS task.
099: */
100: protected void initGlobalSystems() {
101:
102: // Initialize AMS task resources needed for all tasks
103: MIDletSuiteUtils.initAmsResources();
104:
105: // Initialize JSR subsystems
106: JSRInitializer.init();
107:
108: // Initaialize automation API
109: AutomationInitializer.init(eventQueue,
110: midletControllerEventProducer);
111:
112: // Start inbound connection watcher thread.
113: PushRegistryInternal.startListening();
114:
115: // Initialize the Content Handler Monitor of MIDlet exits
116: CHManager.getManager(internalSecurityToken).initCleanupMonitor(
117: midletProxyList);
118:
119: // Initialize WMA's cleanup monitor
120: WMACleanupMonitor.init(midletProxyList);
121: }
122:
123: /**
124: * Inits created MIDlet suite environment objects and global
125: * subsystems needed for all suites.
126: * <p>
127: * The method also loads MIDlet suite paramaters and arguments
128: * from the natively saved <code>CommandState</code> instance.
129: */
130: protected void initSuiteEnvironment() {
131: super .initSuiteEnvironment();
132:
133: AmsUtil.initClass(midletProxyList,
134: midletControllerEventProducer);
135:
136: MIDletProxy.initClass(foregroundEventProducer,
137: midletEventProducer);
138: MIDletProxyList.initClass(midletProxyList);
139:
140: // Listen for start MIDlet requests from the other isolates
141: ExecuteMIDletEventListener.startListening(
142: internalSecurityToken, displayEventHandler, eventQueue);
143:
144: // Init gloabal systems common for all isolates
145: initGlobalSystems();
146: }
147:
148: /**
149: * Sets suite arguments as temporary suite properties.
150: * The implementation extends base class method with
151: * additional properties specific for AMS MIDlet in
152: * the internal suite.
153: */
154: protected void setSuiteProperties() {
155: super .setSuiteProperties();
156:
157: // Handle logo displaying for Manager MIDlet
158: if (suiteId == MIDletSuite.INTERNAL_SUITE_ID) {
159: // Disable logo when startup performance is being
160: // measured or if the logo has been displayed already
161: if (Constants.MEASURE_STARTUP || state.logoDisplayed) {
162: midletSuite.setTempProperty(internalSecurityToken,
163: "logo-displayed", "");
164: } else {
165: state.logoDisplayed = true;
166: }
167: }
168:
169: }
170:
171: /**
172: * The AMS MIDlet started in the suite loader could request for
173: * shutdown, so we need to check it, wait for other MIDlets destroying
174: * and update <code>CommandState</code> with appropriate status.
175: */
176: protected void checkForShutdown() {
177: if (MIDletProxyList.shutdownInProgress()) {
178:
179: // The MIDlet was shutdown by either the OS or the
180: // push system. Set the command state to signal this
181: // to the native AMS code.
182: state.status = CommandState.SHUTDOWN;
183: midletProxyList.waitForShutdownToComplete();
184: } else {
185: state.status = CommandState.OK;
186: }
187: }
188:
189: /** Overrides suite close logic for the AMS task */
190: protected void closeSuite() {
191: /*
192: * The midletSuite is not closed because the other
193: * active threads may be depending on it.
194: * For example, Display uses isTrusted to update
195: * screen icons.
196: * A native finalizer will take care of unlocking
197: * the native locks.
198: */
199: }
200:
201: /**
202: * Extends base class implementatiom with additional actions for main
203: * task shutdown. Update and save <code>CommandState</code> instance
204: * for VM cycling mechanism.
205: */
206: protected void done() {
207: super .done();
208:
209: state.suiteId = MIDletSuite.UNUSED_SUITE_ID;
210: state.midletClassName = null;
211:
212: if (state.status != CommandState.SHUTDOWN) {
213: if (MIDletSuiteUtils.lastMidletSuiteToRun != MIDletSuite.UNUSED_SUITE_ID) {
214:
215: state.lastSuiteId = MIDletSuiteUtils.lastMidletSuiteToRun;
216: state.lastMidletClassName = MIDletSuiteUtils.lastMidletToRun;
217: state.lastArg0 = MIDletSuiteUtils.arg0ForLastMidlet;
218: state.lastArg1 = MIDletSuiteUtils.arg1ForLastMidlet;
219: }
220:
221: // Check to see if we need to run a selected suite next
222: if (MIDletSuiteUtils.nextMidletSuiteToRun != MIDletSuite.UNUSED_SUITE_ID) {
223:
224: state.suiteId = MIDletSuiteUtils.nextMidletSuiteToRun;
225: state.midletClassName = MIDletSuiteUtils.nextMidletToRun;
226:
227: state.arg0 = MIDletSuiteUtils.arg0ForNextMidlet;
228: state.arg1 = MIDletSuiteUtils.arg1ForNextMidlet;
229: state.arg2 = MIDletSuiteUtils.arg2ForNextMidlet;
230:
231: state.runtimeInfo.memoryReserved = MIDletSuiteUtils.memoryReserved;
232: state.runtimeInfo.memoryTotal = MIDletSuiteUtils.memoryTotal;
233: state.runtimeInfo.priority = MIDletSuiteUtils.priority;
234: state.runtimeInfo.profileName = MIDletSuiteUtils.profileName;
235:
236: } else if (state.lastSuiteId != MIDletSuite.UNUSED_SUITE_ID) {
237:
238: state.suiteId = state.lastSuiteId;
239: state.midletClassName = state.lastMidletClassName;
240: state.arg0 = state.lastArg0;
241: state.arg1 = state.lastArg1;
242:
243: /* Avoid an endless loop. */
244: state.lastSuiteId = MIDletSuite.UNUSED_SUITE_ID;
245: state.lastMidletClassName = null;
246: state.lastArg0 = null;
247: state.lastArg1 = null;
248:
249: /*
250: * This could an bad JAD from an auto test suite,
251: * so make sure the status to OK, the native
252: * code will run the last suite.
253: */
254: state.status = CommandState.OK;
255: }
256: }
257:
258: state.save();
259: }
260:
261: /** Gracefully terminates VM with proper return code */
262: protected void exitLoader() {
263: /* Return specific non-zero number so the native AMS code can
264: * know that this is graceful exit and not VM abort. */
265: CommandState.exitInternal(CommandState.MAIN_EXIT);
266: }
267:
268: /**
269: * Displays an exception message to user
270: * @param exceptionMsg the message text
271: */
272: protected void displayException(String exceptionMsg) {
273: MIDletSuiteUtils.displayException(displayEventHandler,
274: exceptionMsg);
275: }
276:
277: /**
278: * Updates CommandState status and displays proper
279: * exception message to user
280: *
281: * @param errorCode generic error code
282: * @param details text with error details
283: */
284: protected void reportError(int errorCode, String details) {
285: state.status = errorCode;
286:
287: // Initialize display alerts state on first error handling
288: if (disableAlerts < 0) {
289: disableAlerts = Configuration.getIntProperty(
290: "DisableStartupErrorAlert", 0);
291: }
292:
293: int msgId = getErrorMessageId(errorCode);
294: String errorMsg = Resource.getString(msgId);
295: if (details != null) {
296: errorMsg += "\n\n" + details;
297: }
298:
299: if (disableAlerts == 0) {
300: displayException(errorMsg);
301: }
302:
303: // Error message is always obtained for logging
304: if (Logging.REPORT_LEVEL <= Logging.ERROR) {
305: Logging
306: .report(Logging.ERROR, LogChannels.LC_CORE,
307: errorMsg);
308: }
309: }
310:
311: /**
312: * Called at the initial start of the VM.
313: * Initializes internal security and any other AMS classes related
314: * classes before starting the MIDlet.
315: *
316: * @param args not used,
317: * a {@link CommandState} object is obtained and
318: * used for arguments
319: */
320: public static void main(String args[]) {
321: try {
322: MIDletSuiteLoader loader = new MIDletSuiteLoader();
323:
324: loader.runMIDletSuite();
325: } catch (Throwable t) {
326: t.printStackTrace();
327: }
328: }
329:
330: /**
331: * Creates class instance and gets suite parameters
332: * from the persistent {@link CommandState} object.
333: */
334: private MIDletSuiteLoader() {
335: // Restore command state transfered to MIDlet suite loader
336: state = CommandState.getCommandState();
337:
338: // Init internal state from the restored command state
339: externalAppId = 0;
340: midletDisplayName = null;
341: args = new String[] { state.arg0, state.arg1, state.arg2 };
342: suiteId = state.suiteId;
343: midletClassName = state.midletClassName;
344:
345: // Release command state argument references
346: state.arg0 = null;
347: state.arg1 = null;
348: state.arg2 = null;
349: }
350: }
|