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 javax.microedition.io.ConnectionNotFoundException;
030: import javax.microedition.lcdui.Displayable;
031: import javax.microedition.midlet.MIDlet;
032: import com.sun.midp.log.*;
033: import com.sun.midp.configurator.Constants;
034: import com.sun.midp.installer.InternalMIDletSuiteImpl;
035: import com.sun.midp.lcdui.*;
036: import com.sun.midp.midlet.*;
037: import com.sun.midp.midletsuite.*;
038:
039: /**
040: * The first class loaded in VM by midp_run_midlet_with_args to initialize
041: * internal security the internal AMS classes and start a MIDlet suite.
042: */
043: public class CdcMIDletSuiteLoader extends AbstractMIDletSuiteLoader
044: implements ForegroundController, MIDletStateListener,
045: PlatformRequest {
046:
047: /** Disable startup error alerts, uninitialized by default */
048: protected int disableAlerts = -1;
049:
050: /** Holds the ID of the current display, for preempting purposes. */
051: protected int currentDisplayId;
052:
053: /**
054: * Called at the initial start of the VM.
055: * Initializes internal security and any other AMS classes related
056: * classes before starting the MIDlet.
057: *
058: *
059: * @param args arg[0] the suite ID (-1=rommized MIDlet),
060: * arg[1] the class name of the MIDlet,
061: * arg[2-n] optional MIDlet args, the first labled arg-0,
062: * then second arg-1, etc
063: */
064: public static void main(String args[]) {
065: try {
066: CDCInit.init();
067:
068: CdcMIDletSuiteLoader loader = new CdcMIDletSuiteLoader();
069:
070: if (args.length < 1) {
071: System.err.println("The suite ID for the "
072: + "MIDlet suite was not given");
073: throw new IllegalArgumentException("Suite ID absent");
074: }
075:
076: try {
077: loader.suiteId = Integer.parseInt(args[0]);
078: } catch (Throwable t) {
079: throw new IllegalArgumentException("Suite ID: "
080: + t.getMessage());
081: }
082:
083: if (args.length < 2) {
084: System.err.println("The class name for the "
085: + "MIDlet was not given");
086: throw new IllegalArgumentException(
087: "MIDlet class name absent.");
088: }
089:
090: loader.midletClassName = args[1];
091:
092: int numberOfSuiteArgs = args.length - 2;
093:
094: if (numberOfSuiteArgs > 0) {
095: loader.args = new String[numberOfSuiteArgs];
096: for (int i = 0; i < numberOfSuiteArgs; i++) {
097: loader.args[i] = args[i + 2];
098: }
099: }
100:
101: loader.runMIDletSuite();
102: } catch (Throwable t) {
103: t.printStackTrace();
104: }
105: }
106:
107: /**
108: * Extends base class initialization with initializatons
109: * specific for the AMS task
110: */
111: protected void init() {
112: super .init();
113: }
114:
115: /** Creates environment objects needed to AMS task */
116: protected void createSuiteEnvironment() {
117: foregroundController = this ;
118:
119: // creates display container, needs foregroundController
120: super .createSuiteEnvironment();
121:
122: midletStateHandler = MIDletStateHandler.getMidletStateHandler();
123:
124: MIDletSuiteStorage mss = MIDletSuiteStorage
125: .getMIDletSuiteStorage(internalSecurityToken);
126:
127: midletStateHandler.initMIDletStateHandler(
128: internalSecurityToken, this , new CdcMIDletLoader(mss),
129: this );
130: }
131:
132: /**
133: * Inits created MIDlet suite environment objects and global
134: * subsystems needed for all suites.
135: * <p>
136: * The method also loads MIDlet suite paramaters and arguments
137: * from the natively saved <code>CommandState</code> instance.
138: */
139: protected void initSuiteEnvironment() {
140: super .initSuiteEnvironment();
141:
142: // Init internal state from the restored command state
143: externalAppId = 0;
144: midletDisplayName = null;
145: }
146:
147: /**
148: * Creates MIDlet suite instance by suite ID
149: *
150: * @return MIDlet suite to load
151: *
152: * @throws Exception in the case MIDlet suite can not be
153: * created because of a security reasons or some problems
154: * related to suite storage
155: */
156: protected MIDletSuite createMIDletSuite() throws Exception {
157: MIDletSuiteStorage storage;
158: MIDletSuite suite = null;
159:
160: if (suiteId == MIDletSuite.INTERNAL_SUITE_ID) {
161: // assume a class name of a MIDlet in the classpath
162: suite = InternalMIDletSuiteImpl.create(midletDisplayName,
163: suiteId);
164: } else {
165: storage = MIDletSuiteStorage
166: .getMIDletSuiteStorage(internalSecurityToken);
167:
168: suite = storage.getMIDletSuite(suiteId, false);
169: Logging.initLogSettings(suiteId);
170: }
171:
172: return suite;
173: }
174:
175: /** Overrides suite close logic for the AMS task */
176: protected void closeSuite() {
177: super .closeSuite();
178:
179: // shutdown any preempting
180: if (displayEventHandler != null) {
181: displayEventHandler.donePreempting(null);
182: }
183: }
184:
185: /** Gracefully terminates VM with proper return code */
186: protected void exitLoader() {
187: }
188:
189: /**
190: * Displays an exception message to user
191: * @param exceptionMsg the message text
192: */
193: protected void displayException(String exceptionMsg) {
194: System.err.println(exceptionMsg);
195: }
196:
197: /**
198: * Updates CommandState status and displays proper
199: * exception message to user
200: *
201: * @param errorCode generic error code
202: * @param details text with error details
203: */
204: protected void reportError(int errorCode, String details) {
205: String errorMsg = getErrorMessage(errorCode);
206: if (details != null) {
207: errorMsg += "\n\n" + details;
208: }
209:
210: displayException(errorMsg);
211:
212: // Error message is always obtained for logging
213: if (Logging.REPORT_LEVEL <= Logging.ERROR) {
214: Logging
215: .report(Logging.ERROR, LogChannels.LC_CORE,
216: errorMsg);
217: }
218: }
219:
220: /**
221: * Handles exceptions happened during MIDlet suite execution.
222: * @param t exception instance
223: */
224: public void handleException(Throwable t) {
225: t.printStackTrace();
226: int errorCode = getErrorCode(t);
227:
228: if (Logging.TRACE_ENABLED) {
229: Logging
230: .trace(t,
231: "Exception caught in CdcMIDletSuiteLoader");
232: }
233:
234: reportError(errorCode, t.getMessage());
235: }
236:
237: /**
238: * Set foreground display native state, so the native code will know
239: * which display can draw.
240: *
241: * @param displayId Display ID
242: */
243: private native void setForegroundInNativeState(int displayId);
244:
245: /**
246: * Gets AMS error message by generic error code.
247: *
248: * @param errorCode generic error code
249: * @return error message
250: */
251: static protected String getErrorMessage(int errorCode) {
252: switch (errorCode) {
253: case Constants.MIDLET_SUITE_DISABLED:
254: return "MIDlet suite dispabled.";
255:
256: case Constants.MIDLET_SUITE_NOT_FOUND:
257: return "MIDlet suite not found.";
258:
259: case Constants.MIDLET_CLASS_NOT_FOUND:
260: return "MIDlet class not found.";
261:
262: case Constants.MIDLET_INSTANTIATION_EXCEPTION:
263: return "Cannot launch MIDlet due to illegal operation.";
264:
265: case Constants.MIDLET_ILLEGAL_ACCESS_EXCEPTION:
266: return "Cannot launch MIDlet due to illegal operation.";
267:
268: case Constants.MIDLET_OUT_OF_MEM_ERROR:
269: return "Out of memory";
270: }
271:
272: return "MIDlet suite has unexpectedly quit.";
273: }
274:
275: /**
276: * Gets error code by exception type
277: *
278: * @param t exception instance
279: * @return error code
280: */
281: static protected int getErrorCode(Throwable t) {
282: if (t instanceof ClassNotFoundException) {
283: return Constants.MIDLET_CLASS_NOT_FOUND;
284: } else if (t instanceof InstantiationException) {
285: return Constants.MIDLET_INSTANTIATION_EXCEPTION;
286: } else if (t instanceof IllegalAccessException) {
287: return Constants.MIDLET_ILLEGAL_ACCESS_EXCEPTION;
288: } else if (t instanceof OutOfMemoryError) {
289: return Constants.MIDLET_OUT_OF_MEM_ERROR;
290: } else if (t instanceof MIDletSuiteLockedException) {
291: return Constants.MIDLET_INSTALLER_RUNNING;
292: } else {
293: return Constants.MIDLET_CONSTRUCTOR_FAILED;
294: }
295: }
296:
297: // MIDletStateListener
298: /**
299: * Called before a MIDlet is created.
300: * This implementation does nothing.
301: *
302: * @param suite reference to the loaded suite
303: * @param className class name of the MIDlet to be created
304: */
305: public void midletPreStart(MIDletSuite suite, String className) {
306: }
307:
308: /**
309: * Called after a MIDlet is successfully created.
310: * This implementation does nothing.
311: *
312: * @param suite reference to the loaded suite
313: * @param className Class name of the MIDlet
314: * @param externalAppId ID of given by an external application manager
315: */
316: public void midletCreated(MIDletSuite suite, String className,
317: int externalAppId) {
318: }
319:
320: /**
321: * Called before a MIDlet is activated.
322: * This implementation does nothing.
323: *
324: * @param suite reference to the loaded suite
325: * @param className class name of the MIDlet
326: */
327: public void preActivated(MIDletSuite suite, String className) {
328: }
329:
330: /**
331: * Called after a MIDlet is successfully activated. This is after
332: * the startApp method is called.
333: * This implementation does nothing.
334: *
335: * @param suite reference to the loaded suite
336: * @param midlet reference to the MIDlet
337: */
338: public void midletActivated(MIDletSuite suite, MIDlet midlet) {
339: }
340:
341: /**
342: * Called after a MIDlet is successfully paused.
343: * This implementation does nothing.
344: *
345: * @param suite reference to the loaded suite
346: * @param className class name of the MIDlet
347: */
348: public void midletPaused(MIDletSuite suite, String className) {
349: }
350:
351: /**
352: * Called after a MIDlet pauses itself. In this case pauseApp has
353: * not been called.
354: *
355: * @param suite reference to the loaded suite
356: * @param className class name of the MIDlet
357: */
358: public void midletPausedItself(MIDletSuite suite, String className) {
359: }
360:
361: /**
362: * Called when a MIDlet calls MIDlet resume request.
363: *
364: * @param suite reference to the loaded suite
365: * @param className class name of the MIDlet
366: */
367: public void resumeRequest(MIDletSuite suite, String className) {
368: MIDletEventConsumer mec = midletStateHandler
369: .getMIDletEventConsumer(internalSecurityToken,
370: className);
371:
372: if (mec == null) {
373: return;
374: }
375:
376: mec.handleMIDletActivateEvent();
377: }
378:
379: /**
380: * Called after a MIDlet is successfully destroyed.
381: * This implementation does nothing.
382: *
383: * @param suite reference to the loaded suite
384: * @param className class name of the MIDlet
385: */
386: public void midletDestroyed(MIDletSuite suite, String className) {
387: displayContainer.removeDisplay(className);
388: }
389:
390: // ForegroundController
391:
392: /**
393: * Called to register a newly create Display. Must method must
394: * be called before the other methods can be called.
395: * This implementation does nothing.
396: *
397: * @param displayId ID of the Display
398: * @param ownerClassName Class name of the that owns the display
399: *
400: * @return a place holder displayable to used when "getCurrent()==null",
401: * if null is returned an empty form is used
402: */
403: public Displayable registerDisplay(int displayId,
404: String ownerClassName) {
405: currentDisplayId = displayId;
406: return null;
407: }
408:
409: /**
410: * Called to request the foreground.
411: * This implementation does nothing.
412: *
413: * @param displayId ID of the Display
414: * @param isAlert true if the current displayable is an Alert
415: */
416: public void requestForeground(int displayId, boolean isAlert) {
417: ForegroundEventConsumer fc = displayContainer
418: .findForegroundEventConsumer(displayId);
419:
420: if (fc == null) {
421: return;
422: }
423:
424: setForegroundInNativeState(displayId);
425:
426: fc.handleDisplayForegroundNotifyEvent();
427: }
428:
429: /**
430: * Called to request the background.
431: * This implementation does nothing.
432: *
433: * @param displayId ID of the Display
434: */
435: public void requestBackground(int displayId) {
436: ForegroundEventConsumer fc = displayContainer
437: .findForegroundEventConsumer(displayId);
438:
439: if (fc == null) {
440: return;
441: }
442:
443: fc.handleDisplayBackgroundNotifyEvent();
444: }
445:
446: /**
447: * Called to start preempting. The given display will preempt all other
448: * displays for this isolate.
449: *
450: * @param displayId ID of the Display
451: */
452: public void startPreempting(int displayId) {
453: requestBackground(currentDisplayId);
454: requestForeground(displayId, true);
455: }
456:
457: /**
458: * Called to end preempting.
459: *
460: * @param displayId ID of the Display
461: */
462: public void stopPreempting(int displayId) {
463: requestBackground(displayId);
464: requestForeground(currentDisplayId, false);
465: }
466:
467: // Platform Request
468:
469: /*
470: * This is empty.
471: *
472: * @param URL The URL for the platform to load.
473: *
474: * @return true if the MIDlet suite MUST first exit before the
475: * content can be fetched.
476: *
477: * @exception ConnectionNotFoundException if
478: * the platform cannot handle the URL requested.
479: *
480: */
481: public boolean dispatch(String URL)
482: throws ConnectionNotFoundException {
483: throw new ConnectionNotFoundException("not implemented");
484: }
485: }
|