FileDocCategorySizeDatePackage
CommandProcessor.javaAPI DocJ2ME MIDP 2.013282Thu Nov 07 12:02:26 GMT 2002com.sun.midp.main

CommandProcessor.java

/*
 * @(#)CommandProcessor.java	1.27 02/10/03 @(#)
 *
 * Copyright (c) 2001-2002 Sun Microsystems, Inc.  All rights reserved.
 * PROPRIETARY/CONFIDENTIAL
 * Use is subject to license terms.
 */

package com.sun.midp.main;

import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.lang.String;

import com.sun.midp.midlet.MIDletSuite;
import com.sun.midp.midlet.Scheduler;

import com.sun.midp.midletsuite.Installer;
import com.sun.midp.midletsuite.InvalidJadException;

/**
 * Performs basic MIDlet Suite management commands.
 * <p>
 * The <code>Main</code> class performs four basic operations:
 * <ul>
 * <li>Application installation
 * <li>Application removal
 * <li>Application listing
 * <li>Application execution
 * </ul>
 * <p>
 * Together, these operations are refered to as the Java Application
 * Manager or <em>JAM</em>.
 *
 */
public class CommandProcessor {
    /** return value from Main, so we know that Main exited normally */
    static final int MAIN_EXIT = 2001;

    /** status for success */
    static final int OK = 0;

    /** status when an error occurs */
    static final int ERROR = -1;

    /** status when the MIDlet suite is not found */
    static final int MIDLET_SUITE_NOT_FOUND = -2;

    /** command code for exit */
    static final int EXIT        = 1;

    /** command code for Graphical MIDlet Suite Manager in a dev environment */
    static final int MANAGE      = 2;

    /** command code for installing a suite */
    static final int INSTALL     = 3;

    /** command code for installing and running a suite */
    static final int INSTALL_RUN = 4;

    /** command code for running a suite */
    static final int RUN         = 5;

    /** command code for removing a suite */
    static final int REMOVE      = 6;

    /** command code for listing all installed suites in dev environment */
    static final int LIST        = 7;

    /** command code for running a class directly */
    static final int RUN_CLASS   = 8;

    /** command code for listing the only the storage names of suites  */
    static final int STORAGE_NAMES = 9;

    /** whether-or-not we are peforming a command */
    private static boolean performing = false;

    /** Application Installer */
    private static Installer installer = null;

    /**
     * Perform the specified command.
     * <p>
     * The operation is specified in the initialCommand field of the
     * command state. The nextCommand state will be set to next command or
     * EXIT. The status will also be set.
     * <p>
     * The command state also contains the arguments needed a command.
     * <pre>
     * Command     Argument(s)
     * ----------- -----------
     * install     suiteURL
     * remove      suiteStorageName
     * run         suiteStorageName and optionally (midletName and runOnce)
     * install-run suiteURL and optionally (midletName, autotest, and runOnce)
     * </pre>
     * <p>
     * The <code>list</code> command displays a list of the currently
     * installed applications.
     * <p>
     * The <code>install</code> command will install the given application.
     * The URL used for installation must point to a valid application
     * descriptor file. Only HTTP URLs are accepted. If any errors were
     * encountered during installtion, the status will be ERROR or
     * MIDLET_SUITE_NOT_FOUND. if forceOverwrite in the command state is
     * set MIDlet suite will be forcibly installed. See
     * <a href="Installer.html#installJad(java.lang.String, boolean)">
     * Installer.installJad()</a> for a description.
     * <p>
     * The <code>remove</code> command will remove the given application
     * suite or storage used when running single class of local descriptor.
     * If you specify the special keywork <code>all</code> as the
     * suite name, <em>all</em> application suites will be removed.
     * <p>
     * The <code>run</code> command will execute the given MIDlet from
     * a suite, or if not MIDlet is given, let the user select one.
     * If runOnce in the command state is the next command will be
     * remove.
     * <p>
     * The <code>install-run</code> command performs the <code>install</code>
     * and then the <code>run</code> command. If autotest and runOnce are
     * set in the command state, then after removing the suite the next
     * command will be install. The autotest cycle is broken when the 
     * suite at the URL is not found.
     *
     * @param state command state containing the command to perform and
     *      any arguments that the command may require.
     *
     * @exception IOException is thrown, if an error occurs fetching the 
     *              descriptor or jar file
     * @exception InvalidJadException is thrown, if an error is detected in the 
     *                  descriptor file
     * @exception ClassNotFoundException is thrown, if the desginated MIDlet is 
     *                    not  found in the downloaded bundle
     * @exception InstantiationException is thrown, installer can not be 
     *                    constructed
     * @exception IllegalAccessException is thrown,if the caller does not have 
     *              sufficient authority  to perorm the requested 
     *              operation
     */
    public static void perform(CommandState state) throws IOException,
            InvalidJadException, ClassNotFoundException,
            InstantiationException, IllegalAccessException {

        String nextMidletSuiteToRun;

        // don't run twice, a sneaky untrusted MIDlet may try this
        if (performing) {
            return;
        }

        performing = true;

        // we need to get the installer now, before the security level drops
        if (installer == null) {
            installer = Installer.getInstaller();
        }

        dispatch(state);

        nextMidletSuiteToRun = installer.getNextMIDletSuiteToRun();
        if (nextMidletSuiteToRun != null) {
            state.nextCommand = RUN;
            state.suiteStorageName = nextMidletSuiteToRun;

            // the run method should clear this
            state.midletName = installer.getNextMIDletToRun();
        }

        performing = false;
    }

    /**
     * Dispatches the command for processing.
     *
     * @param state command state containing the command to perform and
     *      any arguments that the command may require.
     */
    private static void dispatch(CommandState state) throws IOException,
            InvalidJadException, ClassNotFoundException,
            InstantiationException, IllegalAccessException {
        int currentCommand;

        currentCommand = state.nextCommand;
        state.nextCommand = EXIT;

        if (currentCommand == INSTALL || currentCommand == INSTALL_RUN) {
            install(state);
        } else if (currentCommand == RUN) {
            // keep the Manager around if that was initial command
            if (state.initialCommand == MANAGE) {
                state.nextCommand = MANAGE;
            }

            run(state);
        } else if (currentCommand == REMOVE) {
            remove(state);
        }
    }

    /**
     * Installs a MIDlet Suite.
     *
     * @param state command state containing the URL of the suite to install
     *
     * @exception IllegalArgumentException if the JAD URL in the state is
     *   not valid
     */
    private static void install(CommandState state) throws IOException,
            InvalidJadException {
        try {
            state.status = ERROR;

            if (state.securityDomain != null) {
                installer.setUnsignedSecurityDomain(state.securityDomain);
            }

            // save the suite name for "run" command
            state.suiteStorageName = installer.installJad(state.suiteURL,
                                            state.forceOverwrite,
                                            state.removeRMS, null);
            state.status = OK;

            // this may be a one of a set of commands to execute
            if (state.initialCommand == INSTALL_RUN) {
                state.nextCommand = RUN;
            }

            return;
        } catch (InvalidJadException ije) {
            if (ije.getReason() == InvalidJadException.INVALID_JAD_URL) {
                state.status = MIDLET_SUITE_NOT_FOUND;
                throw new IllegalArgumentException("The JAD URL is not valid");
            }

            if (ije.getReason() == InvalidJadException.JAD_SERVER_NOT_FOUND ||
                ije.getReason() == InvalidJadException.JAD_NOT_FOUND) {

                state.status = MIDLET_SUITE_NOT_FOUND;

                if (state.autotest && state.suiteStorageName != null) {
                    // This end of the tests, remove the last test installed
                    state.nextCommand = REMOVE;
                }

                return;
            }

            if (ije.getReason() == InvalidJadException.INVALID_JAD_TYPE) {
                // media type of JAD was wrong, it could be a JAR
                String mediaType = (String)ije.getExtraData();

                if (Installer.JAR_MT_1.equals(mediaType) ||
                        Installer.JAR_MT_2.equals(mediaType)) {
                    // re-run as a JAR only install
                    state.suiteStorageName =
                        installer.installJar(state.suiteURL,
                                             state.forceOverwrite,
                                             state.removeRMS, null);
                    state.status = OK;

                    // this may be a one of a set of commands to execute
                    if (state.initialCommand == INSTALL_RUN) {
                        state.nextCommand = RUN;
                    }

                    return;
                }
            }

            throw ije;
        } catch (IllegalArgumentException iae) {
            // the suite was not found be case of an illegal argument
            state.status = MIDLET_SUITE_NOT_FOUND;
            throw iae;
        } finally {
            if (state.status == ERROR) {
                // during autotest mode, only exit if we cannot get the suite
                if (state.autotest) {
                    state.nextCommand = INSTALL;
                }
            }
        }
    }

    /**
     * Runs a MIDlet suite.
     *
     * @param state command state containing the name of the suite to run
     */
    private static void run(CommandState state) throws
        ClassNotFoundException, InstantiationException,
            IllegalAccessException {

        MIDletSuite midletSuite;

        // Note: the install command creates the suite storage names

        state.status = ERROR;

        if (state.suiteStorageName == null) {
            throw new IllegalArgumentException("The storage name for the " +
                "MIDlet suite was not given");
        }

        if (state.midletName != null || state.midletNumber == null) {
            String temp = state.midletName;

            /*
             * When autotesting push, both the number and name may both be set
             * remove the launched suite name for the next test.
             */
            state.midletName = null;

            midletSuite = installer.getMIDletSuite(state.suiteStorageName,
                                                   temp);

        } else {
            int midletNumber;

            try {
                midletNumber = Integer.parseInt(state.midletNumber);
            } catch (NumberFormatException nfe) {
                throw new IllegalArgumentException("The value for " +
                    "MIDlet number was not formatted properly");
            }

            midletSuite = installer.getMIDletSuite(state.suiteStorageName,
                                                   midletNumber);
        }

        if (midletSuite == null) {
            state.status = MIDLET_SUITE_NOT_FOUND;
            return;
        }

        // remove any run once suites
        if (state.runOnce) {
            state.nextCommand = REMOVE;
        } else if (state.autotest) {
            state.nextCommand = INSTALL;
        }

        // run MIDlets til there are none
        if (!Scheduler.getScheduler().schedule(midletSuite)) {
            // The system is shutting down
            state.nextCommand = EXIT;
        }

        state.status = OK;
    }

    /**
     * Removes a MIDlet Suite.
     *
     * @param state command state containing the name of the suite to remove
     *
     * @exception IllegalArgumentException if storage name in the state is
     *    null
     */
    private static void remove(CommandState state) {
        state.status = ERROR;

        if (state.suiteStorageName == null) {
            throw new IllegalArgumentException("No suite specified");
        }
        
        if (state.suiteStorageName.equals("all")) {
            String suite[] = installer.list();
            for (int i = 0; i < suite.length; i++) {
                installer.remove(suite[i]);
            }
        } else {
            installer.remove(state.suiteStorageName);
        }

        state.status = OK;

        return;
    }

    /** This class is not meant to be instatiated */
    private CommandProcessor() {
    }
}