/*
*
*
* 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.lcdui.ForegroundEventProducer;
import com.sun.midp.midlet.*;
import com.sun.midp.jsr.JSRInitializer;
import com.sun.midp.io.j2me.push.PushRegistryInternal;
import com.sun.midp.content.CHManager;
import com.sun.midp.configurator.Constants;
import com.sun.midp.i18n.*;
import com.sun.midp.log.*;
import com.sun.midp.security.SecurityToken;
/**
* The first class loaded in VM by midp_run_midlet_with_args to initialize
* internal security the internal AMS classes and start a MIDlet suite.
* <p>
* In SVM mode it handles all MIDlet suites (AMS and internal romized,
* and application).
* <p>
* In MVM mode it only handles the first MIDlet suite isolate which is used
* by the MIDP AMS and other internal MIDlets.
*/
public class MIDletSuiteLoader extends CldcMIDletSuiteLoader {
/** Command state of the MIDlet suite loader */
protected CommandState state;
/** Disable startup error alerts, uninitialized by default */
protected int disableAlerts = -1;
/** MIDlet state event producer needed by AMS */
protected MIDletEventProducer midletEventProducer;
/** Foreground event producer needed by AMS. */
protected static ForegroundEventProducer foregroundEventProducer;
/** List of MIDlet proxies needed by AMS */
protected MIDletProxyList midletProxyList;
/**
* Extends base class initialization with initializatons
* specific for the AMS task
*/
protected void init() {
/*
* WARNING: Don't add any calls before this !
*
* Register AMS task ID native global variable.
* Since native functions rely on this value to distinguish
* whether Java AMS is running, this MUST be called before any
* other native functions from this Isolate. I.E. This call
* must be the first thing this main make.
*/
MIDletSuiteUtils.registerAmsIsolateId();
super.init();
}
/** Creates environment objects needed to AMS task */
protected void createSuiteEnvironment() {
super.createSuiteEnvironment();
midletEventProducer = new MIDletEventProducer(eventQueue);
foregroundEventProducer = new ForegroundEventProducer(eventQueue);
midletProxyList = new MIDletProxyList(eventQueue);
}
/**
* Inits global systems common for all started MIDlet suite tasks.
* The systems should be initialized only once in the AMS task.
*/
protected void initGlobalSystems() {
// Initialize JSR subsystems
JSRInitializer.init();
// Start inbound connection watcher thread.
PushRegistryInternal.startListening(internalSecurityToken);
// Initialize the Content Handler Monitor of MIDlet exits
CHManager.getManager(internalSecurityToken).init(
midletProxyList, eventQueue);
}
/**
* Inits created MIDlet suite environment objects and global
* subsystems needed for all suites.
* <p>
* The method also loads MIDlet suite paramaters and arguments
* from the natively saved <code>CommandState</code> instance.
*/
protected void initSuiteEnvironment() {
super.initSuiteEnvironment();
AmsUtil.initClass(
midletProxyList, midletControllerEventProducer);
MIDletProxy.initClass(foregroundEventProducer, midletEventProducer);
MIDletProxyList.initClass(midletProxyList);
// Init gloabal systems common for all isolates
initGlobalSystems();
}
/**
* The AMS MIDlet started in the suite loader could request for
* shutdown, so we need to check it, wait for other MIDlets destroying
* and update <code>CommandState</code> with appropriate status.
*/
protected void checkForShutdown() {
if (MIDletProxyList.shutdownInProgress()) {
// The MIDlet was shutdown by either the OS or the
// push system. Set the command state to signal this
// to the native AMS code.
state.status = CommandState.SHUTDOWN;
midletProxyList.waitForShutdownToComplete();
} else {
state.status = CommandState.OK;
}
}
/** Overrides suite close logic for the AMS task */
protected void closeSuite() {
/*
* The midletSuite is not closed because the other
* active threads may be depending on it.
* For example, Display uses isTrusted to update
* screen icons.
* A native finalizer will take care of unlocking
* the native locks.
*/
}
/**
* Extends base class implementation with additional actions for main
* task shutdown. Update and save <code>CommandState</code> instance
* for VM cycling mechanism.
*/
protected void done() {
super.done();
state.suiteId = MIDletSuite.UNUSED_SUITE_ID;
state.midletClassName = null;
if (state.status != CommandState.SHUTDOWN) {
if (MIDletSuiteUtils.lastMidletSuiteToRun !=
MIDletSuite.UNUSED_SUITE_ID) {
state.lastSuiteId = MIDletSuiteUtils.lastMidletSuiteToRun;
state.lastMidletClassName = MIDletSuiteUtils.lastMidletToRun;
state.lastArg0 = MIDletSuiteUtils.arg0ForLastMidlet;
state.lastArg1 = MIDletSuiteUtils.arg1ForLastMidlet;
}
// Check to see if we need to run a selected suite next
if (MIDletSuiteUtils.nextMidletSuiteToRun !=
MIDletSuite.UNUSED_SUITE_ID) {
state.suiteId = MIDletSuiteUtils.nextMidletSuiteToRun;
state.midletClassName = MIDletSuiteUtils.nextMidletToRun;
state.arg0 = MIDletSuiteUtils.arg0ForNextMidlet;
state.arg1 = MIDletSuiteUtils.arg1ForNextMidlet;
state.arg2 = MIDletSuiteUtils.arg2ForNextMidlet;
state.runtimeInfo.memoryReserved =
MIDletSuiteUtils.memoryReserved;
state.runtimeInfo.memoryTotal = MIDletSuiteUtils.memoryTotal;
state.runtimeInfo.priority = MIDletSuiteUtils.priority;
state.runtimeInfo.profileName = MIDletSuiteUtils.profileName;
state.isDebugMode = MIDletSuiteUtils.isDebugMode;
} else if (state.lastSuiteId !=
MIDletSuite.UNUSED_SUITE_ID) {
state.suiteId = state.lastSuiteId;
state.midletClassName = state.lastMidletClassName;
state.arg0 = state.lastArg0;
state.arg1 = state.lastArg1;
/* Avoid an endless loop. */
state.lastSuiteId = MIDletSuite.UNUSED_SUITE_ID;
state.lastMidletClassName = null;
state.lastArg0 = null;
state.lastArg1 = null;
/*
* This could an bad JAD from an auto test suite,
* so make sure the status to OK, the native
* code will run the last suite.
*/
state.status = CommandState.OK;
}
}
state.save();
// Finalize JSR subsystems
JSRInitializer.cleanup();
}
/** Gracefully terminates VM with proper return code */
protected void exitLoader() {
/* Return specific non-zero number so the native AMS code can
* know that this is graceful exit and not VM abort. */
CommandState.exitInternal(CommandState.MAIN_EXIT);
}
/**
* Displays an exception message to user
* @param securityToken security token for displaying System Alert.
* @param exceptionMsg the message text
*/
protected void displayException(SecurityToken securityToken,
String exceptionMsg) {
MIDletSuiteUtils.displayException(internalSecurityToken,
exceptionMsg);
}
/**
* Updates CommandState status and displays proper
* exception message to user
*
* @param errorCode generic error code
* @param details text with error details
*/
protected void reportError(int errorCode, String details) {
state.status = errorCode;
// Initialize display alerts state on first error handling
if (disableAlerts < 0) {
disableAlerts = Configuration.getIntProperty(
"DisableStartupErrorAlert", 0);
}
int msgId = getErrorMessageId(errorCode);
String errorMsg = Resource.getString(msgId);
if (details != null) {
errorMsg += "\n\n" + details;
}
if (disableAlerts == 0) {
displayException(internalSecurityToken, errorMsg);
}
// Error message is always obtained for logging
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR, LogChannels.LC_CORE, errorMsg);
}
}
/**
* Called at the initial start of the VM.
* Initializes internal security and any other AMS classes related
* classes before starting the MIDlet.
*
* @param args not used,
* a {@link CommandState} object is obtained and
* used for arguments
*/
public static void main(String args[]) {
try {
MIDletSuiteLoader loader = new MIDletSuiteLoader();
loader.runMIDletSuite();
} catch (Throwable t) {
t.printStackTrace();
}
}
/**
* Creates class instance and gets suite parameters
* from the persistent {@link CommandState} object.
*/
private MIDletSuiteLoader() {
// Restore command state transfered to MIDlet suite loader
state = CommandState.getCommandState();
// Init internal state from the restored command state
externalAppId = 0;
midletDisplayName = null;
args = new String[] {
state.arg0, state.arg1, state.arg2};
suiteId = state.suiteId;
midletClassName = state.midletClassName;
// Release command state argument references
state.arg0 = null;
state.arg1 = null;
state.arg2 = null;
}
}