/* * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package com.sun.midp.main; import com.sun.midp.midlet.*; import com.sun.midp.security.*; import com.sun.midp.events.EventQueue; import com.sun.midp.lcdui.*; import com.sun.midp.midletsuite.*; import com.sun.midp.configurator.Constants; import com.sun.midp.i18n.ResourceConstants; import com.sun.midp.log.*; import com.sun.midp.publickeystore.WebPublicKeyStore; import com.sun.midp.rms.RmsEnvironment; import com.sun.midp.rms.RecordStoreRegistry; import com.sun.midp.midletsuite.SuiteContainerAdapter; /** * The class presents abstract MIDlet suite loader with routines to prepare * runtime environment for CLDC a suite execution. */ abstract class CldcMIDletSuiteLoader implements MIDletSuiteExceptionListener { /** The ID of the MIDlte suite task Isolate */ protected int isolateId; /** The ID of the AMS task Isolate */ protected int amsIsolateId; /** Suite ID of the MIDlet suite */ protected int suiteId; /** External application ID that can be provided by native AMS */ protected int externalAppId; /** Name of the class to start MIDlet suite execution */ protected String midletClassName; /** Display name of a MIDlet suite */ protected String midletDisplayName; /** The arguments to start MIDlet suite with */ protected String args[]; /** * Inner class to request security token from SecurityInitializer. * SecurityInitializer should be able to check this inner class name. */ static private class SecurityTrusted implements ImplicitlyTrustedClass {} /** This class has a different security domain than the MIDlet suite */ protected static SecurityToken internalSecurityToken = SecurityInitializer.requestToken(new SecurityTrusted()); /** Event queue instance created for this MIDlet suite execution */ protected EventQueue eventQueue; /** * MIDlet suite instance created and properly initialized for * a MIDlet suite invocation. */ protected MIDletSuite midletSuite; /** Foreground Controller adapter. */ protected ForegroundController foregroundController; /** Stores array of active displays for a MIDlet suite isolate. */ protected DisplayContainer displayContainer; /** * Provides interface to lcdui environment. */ protected LCDUIEnvironment lcduiEnvironment; /** Starts and controls MIDlets through the lifecycle states. */ protected MIDletStateHandler midletStateHandler; /** Event producer to send MIDlet state events to the AMS isolate. */ protected MIDletControllerEventProducer midletControllerEventProducer; /** Listener for MIDlet related events (state changes, etc). */ protected MIDletEventListener midletEventListener; /** * Provides interface for display foreground notification, * functionality that can not be publicly added to a javax package. */ protected ForegroundEventListener foregroundEventListener; /** * Reports an error detected during MIDlet suite invocation. * @param errorCode the error code to report */ protected abstract void reportError(int errorCode, String details); /** * Reports an error detected during MIDlet suite invocation. * @param errorCode the error code to report */ protected void reportError(int errorCode) { reportError(errorCode, null); } /** * Sets MIDlet suite arguments as temporary suite properties. * Subclasses can override the method to export any other needed * suite properties. */ protected void setSuiteProperties() { if (args != null) { for (int i = 0; i < args.length; i++) { if (args[i] != null) { midletSuite.setTempProperty( internalSecurityToken, "arg-" + i, args[i]); } } } } /** Core initialization of a MIDlet suite loader */ protected void init() { isolateId = MIDletSuiteUtils.getIsolateId(); amsIsolateId = MIDletSuiteUtils.getAmsIsolateId(); // Hint VM of startup beginning: system init phase MIDletSuiteUtils.vmBeginStartUp(isolateId); WebPublicKeyStore.initKeystoreLocation(internalSecurityToken, Configuration.getProperty("com.sun.midp.publickeystore.WebPublicKeyStore")); // Init security tokens for core subsystems SecurityInitializer.initSystem(); eventQueue = EventQueue.getEventQueue( internalSecurityToken); } /** * Creates all needed objects of a MIDlet suite environment, but * only initialization that is done, will be to pass other created objects, * and the current and AMS isolate IDs. It is mostly event-related * objects, however subclasses can extend the environment with more * specific parts */ protected void createSuiteEnvironment() { midletControllerEventProducer = new MIDletControllerEventProducer( eventQueue, amsIsolateId, isolateId); foregroundController = new CldcForegroundController( midletControllerEventProducer); lcduiEnvironment = new LCDUIEnvironment(internalSecurityToken, eventQueue, isolateId, foregroundController); // creates display container, needs foregroundController if (lcduiEnvironment == null) { throw new RuntimeException("Suite environment not complete."); } displayContainer = lcduiEnvironment.getDisplayContainer(); foregroundEventListener = new ForegroundEventListener( eventQueue, displayContainer); midletStateHandler = MIDletStateHandler.getMidletStateHandler(); midletStateHandler.initMIDletStateHandler( internalSecurityToken, new CldcMIDletStateListener(internalSecurityToken, displayContainer, midletControllerEventProducer)); midletEventListener = new MIDletEventListener( internalSecurityToken, midletStateHandler, eventQueue); SuiteContainerAdapter msc = new SuiteContainerAdapter(MIDletSuiteStorage.getMIDletSuiteStorage(internalSecurityToken)); RmsEnvironment.init(internalSecurityToken, msc); } /** Final actions to finish a MIDlet suite loader */ protected void done() { RecordStoreRegistry.shutdown( internalSecurityToken); eventQueue.shutdown(); } /** * Does all initialization for already created objects of a MIDlet suite * environment. Subclasses can also extend the initialization with * various global system initializations needed for all suites. * The MIDlet suite has been created at this point, so it can be * used to initialize any per suite data. */ protected void initSuiteEnvironment() { lcduiEnvironment.setTrustedState(midletSuite.isTrusted()); } /** * Starts MIDlet suite in the prepared environment * Overrides super method to hint VM of system startup * phase is ended * * @throws Exception can be thrown during execution */ protected void startSuite() throws Exception { // Hint VM of startup finish: system init phase MIDletSuiteUtils.vmEndStartUp(isolateId); midletStateHandler.startSuite( this, midletSuite, externalAppId, midletClassName); } /** Closes suite and unlock native suite locks */ protected void closeSuite() { if (midletSuite != null) { /* When possible, don't wait for the finalizer * to unlock the suite. */ midletSuite.close(); } if (lcduiEnvironment != null) { lcduiEnvironment.shutDown(); } } /** * Checks whether an executed MIDlet suite has requested * for a system shutdown. User MIDlets most probably have * no right for it, however Java AMS MIDlet could do it. */ protected void checkForShutdown() { // IMPL_NOTE: No checks for shutdown by default } /** * Explicitly requests suite loader exit after MIDlet * suite execution is finished and created environment is done. */ protected abstract void exitLoader(); /** * Creates MIDlet suite instance by suite ID * * @return MIDlet suite to load * * @throws Exception in the case MIDlet suite can not be * created because of a security reasons or some problems * related to suite storage */ protected MIDletSuite createMIDletSuite() throws Exception { MIDletSuiteStorage storage = MIDletSuiteStorage.getMIDletSuiteStorage(internalSecurityToken); MIDletSuite suite = storage.getMIDletSuite(suiteId, false); Logging.initLogSettings(suiteId); return suite; } /** * Inits MIDlet suite runtime environment and start a MIDlet * suite with it */ protected void runMIDletSuite() { // WARNING: Don't add any calls before this! // // The core init of a MIDlet suite task should be able // to perform the very first initializations of the environment init(); try { /* * Prepare MIDlet suite environment, classes that only need * the isolate ID can be created here. */ createSuiteEnvironment(); /* Check to see that all of the core object are created. */ if (foregroundController == null || displayContainer == null || midletStateHandler == null) { throw new RuntimeException("Suite environment not complete."); } // Create suite instance ready for start midletSuite = createMIDletSuite(); if (midletSuite == null) { reportError(Constants.MIDLET_SUITE_NOT_FOUND); return; } /* * Now that we have the suite and reserved its resources * we can initialize any classes that need MIDlet Suite * information. */ initSuiteEnvironment(); // Export suite arguments as properties, so well // set any other properties to control a suite setSuiteProperties(); if (Logging.REPORT_LEVEL <= Logging.WARNING) { Logging.report(Logging.WARNING, LogChannels.LC_CORE, "MIDlet suite task starting a suite"); } // Blocking call to start MIDlet suite // in the prepared environment startSuite(); // Check for shutdown possibly requested from the suite checkForShutdown(); if (Logging.REPORT_LEVEL <= Logging.WARNING) { Logging.report(Logging.INFORMATION, LogChannels.LC_CORE, "MIDlet suite loader exiting"); } } catch (Throwable t) { handleException(t); } finally { closeSuite(); done(); exitLoader(); } } /** * Gets error code by exception type * * @param t exception instance * @return error code */ static protected int getErrorCode(Throwable t) { if (t instanceof ClassNotFoundException) { return Constants.MIDLET_CLASS_NOT_FOUND; } else if (t instanceof InstantiationException) { return Constants.MIDLET_INSTANTIATION_EXCEPTION; } else if (t instanceof IllegalAccessException) { return Constants.MIDLET_ILLEGAL_ACCESS_EXCEPTION; } else if (t instanceof OutOfMemoryError) { return Constants.MIDLET_OUT_OF_MEM_ERROR; } else if (t instanceof MIDletSuiteLockedException) { return Constants.MIDLET_INSTALLER_RUNNING; } else { return Constants.MIDLET_CONSTRUCTOR_FAILED; } } /** * Gets AMS error message ID by generic error code * * @param errorCode generic error code * @return AMS error ID */ static protected int getErrorMessageId(int errorCode) { switch (errorCode) { case Constants.MIDLET_SUITE_DISABLED: return ResourceConstants. AMS_MIDLETSUITELDR_MIDLETSUITE_DISABLED; case Constants.MIDLET_SUITE_NOT_FOUND: return ResourceConstants. AMS_MIDLETSUITELDR_MIDLETSUITE_NOTFOUND; case Constants.MIDLET_CLASS_NOT_FOUND: return ResourceConstants. AMS_MIDLETSUITELDR_CANT_LAUNCH_MISSING_CLASS; case Constants.MIDLET_INSTANTIATION_EXCEPTION: return ResourceConstants. AMS_MIDLETSUITELDR_CANT_LAUNCH_ILL_OPERATION; case Constants.MIDLET_ILLEGAL_ACCESS_EXCEPTION: return ResourceConstants. AMS_MIDLETSUITELDR_CANT_LAUNCH_ILL_OPERATION; case Constants.MIDLET_OUT_OF_MEM_ERROR: return ResourceConstants. AMS_MIDLETSUITELDR_QUIT_OUT_OF_MEMORY; default: return ResourceConstants. AMS_MIDLETSUITELDR_UNEXPECTEDLY_QUIT; } } /** * Handles exception occurred during MIDlet suite execution. * @param t exception instance */ public void handleException(Throwable t) { t.printStackTrace(); int errorCode = getErrorCode(t); reportError(errorCode, t.getMessage()); } }