javamanager/javainstaller/installer/javasrc/com/nokia/mj/impl/installer/Installer.java
branchRCL_3
changeset 14 04becd199f91
child 17 0fd27995241b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javamanager/javainstaller/installer/javasrc/com/nokia/mj/impl/installer/Installer.java	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,1496 @@
+/*
+* Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+package com.nokia.mj.impl.installer;
+
+import com.nokia.mj.impl.comms.CommsListener;
+import com.nokia.mj.impl.comms.CommsMessage;
+import com.nokia.mj.impl.comms.CommsPermission;
+import com.nokia.mj.impl.comms.CommsServerEndpoint;
+import com.nokia.mj.impl.installer.captainservice.CaptainService;
+import com.nokia.mj.impl.installer.exetable.ExeBall;
+import com.nokia.mj.impl.installer.exetable.ExeEngine;
+import com.nokia.mj.impl.installer.exetable.ExeTable;
+import com.nokia.mj.impl.installer.applicationregistrator.SifRegistrator;
+import com.nokia.mj.impl.installer.integrityservice.IntegrityService;
+import com.nokia.mj.impl.installer.pushregistrator.PushInfo;
+import com.nokia.mj.impl.installer.pushregistrator.PushRegistrator;
+import com.nokia.mj.impl.installer.storagehandler.OtaStatusHandler;
+import com.nokia.mj.impl.installer.storagehandler.OtaStatusNotification;
+import com.nokia.mj.impl.installer.storagehandler.StorageHandler;
+import com.nokia.mj.impl.installer.storagehandler.SuiteInfo;
+import com.nokia.mj.impl.installer.utils.Args;
+import com.nokia.mj.impl.installer.utils.DriveInfo;
+import com.nokia.mj.impl.installer.utils.FileRoots;
+import com.nokia.mj.impl.installer.utils.FileUtils;
+import com.nokia.mj.impl.installer.utils.InstallerException;
+import com.nokia.mj.impl.installer.utils.InstallerMain;
+import com.nokia.mj.impl.installer.utils.Log;
+import com.nokia.mj.impl.installer.utils.Platform;
+import com.nokia.mj.impl.installer.utils.PlatformUid;
+import com.nokia.mj.impl.installer.utils.SysUtil;
+import com.nokia.mj.impl.installer.utils.ThreadDumper;
+import com.nokia.mj.impl.rt.installer.ApplicationInfoImpl;
+import com.nokia.mj.impl.rt.installer.ApplicationUtilsImpl;
+import com.nokia.mj.impl.rt.support.ApplicationInfo;
+import com.nokia.mj.impl.rt.support.Jvm;
+import com.nokia.mj.impl.rt.support.JvmInternal;
+import com.nokia.mj.impl.rt.support.ThreadEventListener;
+import com.nokia.mj.impl.rt.utils.ExtensionUtil;
+import com.nokia.mj.impl.security.common.Certificate;
+import com.nokia.mj.impl.security.midp.authentication.AuthenticationModule;
+import com.nokia.mj.impl.storage.StorageNames;
+import com.nokia.mj.impl.fileutils.FileOperations;
+import com.nokia.mj.impl.fileutils.FileUtility;
+import com.nokia.mj.impl.utils.StartUpTrace;
+import com.nokia.mj.impl.utils.Tokenizer;
+import com.nokia.mj.impl.utils.Uid;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * JavaInstaller main class. JavaInstaller can be started either with
+ * #main(String[]) or #mainWithResult(String[]) methods. Negative return
+ * values indicate that execution has failed.
+ *
+ * @author Nokia Corporation
+ * @version $Rev: 10413 $
+ */
+public class Installer
+{
+    /** Installer state initial value. */
+    public static final int STATE_UNDEFINED = 0;
+    /** Installer state indicating that installation is ongoing. */
+    public static final int STATE_INSTALLING = 1;
+    /** Installer state indicating that uninstallation is ongoing. */
+    public static final int STATE_UNINSTALLING = 2;
+    /** Installer state indicating that componentinfo operation is ongoing. */
+    public static final int STATE_COMPONENT_INFO = 3;
+
+    /** Return value for successful execution. */
+    public static final int ERR_NONE = 0;
+    /**
+     * Return value indicating error when JavaInstaller is started without
+     * command line parameters or required system properties are not found.
+     */
+    public static final int ERR_NOT_FOUND = -1;
+    /** Return value indicating general error. */
+    public static final int ERR_GENERAL = -2;
+    /** Return value indicating that operation was cancelled. */
+    public static final int ERR_CANCEL = -3;
+    /**
+     * Return value which indicates that installer must not exit with
+     * System.exit(). This return value is only used for internally.
+     */
+    static final int RET_NO_SYSTEM_EXIT = 100;
+
+    // ThreadDumper instance.
+    private static ThreadDumper iThreadDumper = null;
+
+    // Installer CommsServer.
+    private static CommsServerEndpoint iInstallerServer = null;
+
+    // The Uids of the installed Java Applications (MIDlets etc).
+    // Used to return information efficiently to preinstaller, appconverter
+    // and TCK Runner when Installer is running in poll mode.
+    static Uid iInstalledSuite = null;
+    static Uid[] iInstalledApps = {};
+    public static void setInstalledUids(Uid aSuiteUid, Uid[] aAppUids)
+    {
+        iInstalledSuite = aSuiteUid;
+        iInstalledApps = aAppUids;
+    }
+
+    // Installer state.
+    private static int iInstallerState = STATE_UNDEFINED;
+    public static int getInstallerState()
+    {
+        return iInstallerState;
+    }
+
+    // Static cancel method needs access to current execution ball.
+    private static ExeBall iExeBall = null;
+    public static void cancel()
+    {
+        if (iExeBall != null)
+        {
+            Log.log("Installer.cancel: static cancel");
+            iExeBall.cancel();
+        }
+        else
+        {
+            Log.log("Installer.cancel: nothing to cancel");
+        }
+    }
+
+    /** Returns exception which caused installation or uninstallation
+        to fail or null if execution was successful. */
+    public static Exception getExecuteException()
+    {
+        if (iExeBall != null)
+        {
+            return iExeBall.getExecuteException();
+        }
+        return null;
+    }
+
+    /**
+     * Installer main program which exits with System.exit() call.
+     *
+     * @param aArgs command line arguments
+     */
+    public static void main(String[] aArgs)
+    {
+        String traceMsg = "Installer.main starts";
+        StartUpTrace.doTrace(traceMsg);
+        Log.log(traceMsg);
+
+        ExtensionUtil.handleExtensions();
+
+        System.out.println("java.version: " +
+                           System.getProperty("java.version"));
+        System.out.println("java.fullversion: " +
+                           System.getProperty("java.fullversion"));
+
+        try
+        {
+            JvmInternal.setThreadEventListener(new ThreadEventListener()
+            {
+                public void threadStarting(Thread newThread, Thread parentThread) {}
+                public void threadDied(Thread thread) {}
+                public void uncaughtException(Thread thread, Throwable throwable)
+                {
+                    String threadName = null;
+                    if (thread != null)
+                    {
+                        threadName = thread.getName();
+                    }
+                    Log.logError("Installer uncaught exception in " +
+                                 threadName, throwable);
+                }
+            });
+        }
+        catch (Throwable t)
+        {
+            Log.logError("Exception from setThreadEventListener", t);
+        }
+
+        try
+        {
+            iThreadDumper = ThreadDumper.getInstance();
+        }
+        catch (Throwable t)
+        {
+            Log.logError("Exception from ThreadDumper.getInstance", t);
+        }
+
+        try
+        {
+            // Create and start Installer CommsServer.
+            iInstallerServer = new CommsServerEndpoint();
+            iInstallerServer.start(11100);
+            iInstallerServer.registerListener(0, new InstallerListener());
+        }
+        catch (Throwable t)
+        {
+            Log.logError("Exception when creating InstallerServer", t);
+        }
+
+        int exitCode = ERR_NONE;
+
+        if (Platform.isS60())
+        {
+            Log.log("Running on S60 platform");
+            // Set file.separator and path.separator properties for S60.
+            System.setProperty("file.separator", "\\");
+            System.setProperty("path.separator", ";");
+            // Load JavaInstaller native dll.
+            try
+            {
+                Jvm.loadSystemLibrary("javainstaller");
+            }
+            catch (Exception ex)
+            {
+                Log.logError("Loading javainstaller dll failed", ex);
+                exitCode = ERR_NOT_FOUND;
+            }
+        }
+        else
+        {
+            Log.log("Running on Linux platform");
+            // Set file.separator and path.separator properties for Linux.
+            System.setProperty("file.separator", "/");
+            System.setProperty("path.separator", ":");
+        }
+        Log.log("FileUtils.pathSeparator: " + FileUtils.pathSeparator());
+        // Set com.nokia.rt.port system property so that installer
+        // specific ApplicationInfoImpl and ApplicationUtilsImpl
+        // are used.
+        System.setProperty("com.nokia.rt.port", "installer");
+
+        if (exitCode == ERR_NONE)
+        {
+            exitCode = mainWithResult(aArgs);
+        }
+
+        try
+        {
+            // Stop and destroy Installer CommsServer.
+            if (iInstallerServer != null)
+            {
+                iInstallerServer.stop();
+                iInstallerServer.destroy();
+                iInstallerServer = null;
+            }
+        }
+        catch (Throwable t)
+        {
+            Log.logError("Exception when destroying InstallerServer", t);
+        }
+
+        if (iThreadDumper != null)
+        {
+            iThreadDumper.destroy();
+            iThreadDumper = null;
+        }
+
+        // Notify possible runtime listeners that JavaInstaller
+        // is about to exit.
+        ApplicationUtilsImpl.doShutdownImpl();
+        if (exitCode == RET_NO_SYSTEM_EXIT)
+        {
+            traceMsg = "Installer.main exits with no code";
+            Log.log(traceMsg);
+            StartUpTrace.doTrace(traceMsg);
+        }
+        else
+        {
+            // System.exit() must be called for the VM to shut down.
+            // Note that this is forced shutdown, which means that
+            // it is not guaranteed that all finalizers are called.
+            traceMsg = "Installer.main exits with code " + exitCode;
+            Log.log(traceMsg);
+            StartUpTrace.doTrace(traceMsg);
+            System.exit(exitCode);
+        }
+    }
+
+    /**
+     * Installer main program which returns status code indicating
+     * operation result. Negative status codes indicate errors.
+     *
+     * @param aArgs command line arguments
+     * @return status code indicating operation result
+     */
+    public static int mainWithResult(String[] aArgs)
+    {
+        // Clean static variables to ensure they are not left initialized
+        // from previous mainWithResult execution.
+        iInstalledApps = new Uid[0];
+        iInstallerState = STATE_UNDEFINED;
+        iExeBall = null;
+
+        if (aArgs.length < 1)
+        {
+            usage(null);
+            return ERR_NOT_FOUND;
+        }
+
+        String javaBinRoot = System.getProperty("JAVA_BIN_ROOT");
+        if (javaBinRoot == null || javaBinRoot.equals(""))
+        {
+            Log.log("System property JAVA_BIN_ROOT is not defined.");
+            return ERR_NOT_FOUND;
+        }
+        else
+        {
+            Log.log("JAVA_BIN_ROOT=" + javaBinRoot);
+        }
+
+        StartUpTrace.doTrace("Installer.mainWithResult " + aArgs[0] + " begins");
+        StringBuffer buf = new StringBuffer("Java install process started with command: ");
+        for (int i = 0; i < aArgs.length; i++)
+        {
+            buf.append(" ").append(aArgs[i]);
+        }
+        Log.logInfoPrd(buf.toString());
+        Log.logMemory("mainWithResult mem info");
+
+        int exitCode = ERR_NONE;
+        Args args = new Args(aArgs);
+
+        if (iThreadDumper != null)
+        {
+            iThreadDumper.startTimer(10*60*1000); // 10 mins
+        }
+
+        try
+        {
+            // Do IntegrityService rollback every time installer is started.
+            if (args.valueContains("log", "is"))
+            {
+                IntegrityService.setOperationsLogged(true);
+            }
+            if (!IntegrityService.rollback(
+                        FileUtils.getIntegrityServiceRoot()))
+            {
+                Log.logError(
+                    "IntegrityService static rollback failed, isRoot: " +
+                    FileUtils.getIntegrityServiceRoot());
+                exitCode = ERR_GENERAL;
+            }
+
+            boolean silent = (args.get("silent") != null? true: false);
+            InstallationNotifier installationNotifier =
+                new InstallationNotifier();
+            ExeEngine engine = new ExeEngine(installationNotifier);
+            if (aArgs[0].equals("install"))
+            {
+                iInstallerState = STATE_INSTALLING;
+                com.nokia.mj.impl.installer.midp2.install.steps.InstallBall
+                ball = new
+                com.nokia.mj.impl.installer.midp2.install.steps.InstallBall();
+                iExeBall = ball;
+                ball.iArgs = args;
+                ball.setSilent(silent);
+                ball.iInstallationNotifier = installationNotifier;
+                ExeTable table = getMidp2InstallTable();
+                engine.execute(table, ball);
+                if (ball.getExecuteException() != null)
+                {
+                    if (ball.isCancelled())
+                    {
+                        exitCode = ERR_CANCEL;
+                    }
+                    else
+                    {
+                        exitCode = ERR_GENERAL;
+                    }
+                }
+            }
+            else if (aArgs[0].equals("uninstall"))
+            {
+                iInstallerState = STATE_UNINSTALLING;
+                com.nokia.mj.impl.installer.midp2.uninstall.steps.UninstallBall
+                ball = new
+                com.nokia.mj.impl.installer.midp2.uninstall.steps.UninstallBall();
+                iExeBall = ball;
+                ball.iArgs = args;
+                ball.setSilent(silent);
+                ball.iInstallationNotifier = installationNotifier;
+                ExeTable table = getMidp2UninstallTable();
+                engine.execute(table, ball);
+                if (ball.getExecuteException() != null)
+                {
+                    if (ball.isCancelled())
+                    {
+                        exitCode = ERR_CANCEL;
+                    }
+                    else
+                    {
+                        exitCode = ERR_GENERAL;
+                    }
+                }
+            }
+            else if (aArgs[0].equals("componentinfo"))
+            {
+                iInstallerState = STATE_COMPONENT_INFO;
+                exitCode = (new GetComponentInfo()).getComponentInfo(args);
+            }
+            else if (aArgs[0].equals("uninstallall"))
+            {
+                exitCode = uninstallAll(args, aArgs);
+            }
+            else if (aArgs[0].equals("poll"))
+            {
+                exitCode = poll(aArgs);
+            }
+            else if (aArgs[0].equals("rollback"))
+            {
+                // IntegrityService rollback is made in the beginning
+                // of this try block. Do nothing here.
+            }
+            else if (aArgs[0].equals("list"))
+            {
+                list(args);
+            }
+            else if (aArgs[0].equals("launch"))
+            {
+                launch(args);
+            }
+            else if (aArgs[0].equals("test"))
+            {
+                test(args, aArgs);
+            }
+            else if (aArgs[0].equals("help"))
+            {
+                usage(aArgs);
+            }
+            else if (aArgs[0].equals("version"))
+            {
+                version(args);
+            }
+            else if (aArgs[0].equals("register"))
+            {
+                registerProperties(args);
+            }
+            else if (aArgs[0].equals("unregister"))
+            {
+                unregisterProperties(args);
+            }
+            else if (aArgs[0].equals("removealldata"))
+            {
+                exitCode = removeAllData(args);
+            }
+            else
+            {
+                usage(null);
+            }
+        }
+        catch (Throwable t)
+        {
+            Log.logError("Unexpected error", t);
+            exitCode = ERR_GENERAL;
+        }
+
+        // Remove tmp dir from installer private dir if it exists.
+        String installerTmpDir = FileUtils.getInstallerRoot() + "tmp";
+        if ((new FileUtility(installerTmpDir)).isDirectory())
+        {
+            try
+            {
+                boolean result = FileOperations.deleteAll(installerTmpDir);
+                if (result)
+                {
+                    Log.log("Removed " + installerTmpDir);
+                }
+                else
+                {
+                    Log.logWarning("Failed to remove " + installerTmpDir);
+                }
+            }
+            catch (IOException ioe)
+            {
+                Log.logWarning("Failed to remove " + installerTmpDir, ioe);
+            }
+        }
+
+        if (iThreadDumper != null)
+        {
+            iThreadDumper.stopTimer();
+        }
+
+        if (args.get("nosystemexit") != null)
+        {
+            Log.log("System.exit() disabled, ignoring exit code " + exitCode);
+            exitCode = RET_NO_SYSTEM_EXIT;
+        }
+        Log.logMemory("mainWithResult mem info");
+        if (exitCode == ERR_NONE)
+        {
+            Log.logInfoPrd("Java install process exits");
+        }
+        else
+        {
+            Log.logInfoPrd("Java install process exit code " + exitCode);
+        }
+
+        StartUpTrace.doTrace("Installer.mainWithResult " + aArgs[0] + " ends");
+        return exitCode;
+    }
+
+    private static ExeTable getMidp2InstallTable()
+    {
+        ExeTable table = new ExeTable();
+        com.nokia.mj.impl.installer.midp2.install.steps.ConvertIcons
+        convertIconsStep = new
+        com.nokia.mj.impl.installer.midp2.install.steps.ConvertIcons();
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  CreateUi());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  SendInstallerResultMessage());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  SendOtaStatus());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  PrepareInstallation());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  DownloadJad());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  FindJadJar()); // Either jad or jar must be present in
+        // the device for this step.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  GetAttributes());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  GetFromStorage());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  StartProgressNotifications());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  SelectUids()); // Select suite uid and application uids.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  AuthenticateJad()); // This must be the first security
+        // related step.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  GrantJadPermissions()); // Permission granting must be
+        // made after authentication step.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  AuthenticateJar());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  GrantJarPermissions()); // Permission granting must be
+        // made after authentication step.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  CheckDiskSpace());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  WaitForOcsp()); // Wait for OCSP to be completed before
+        // starting download.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  DownloadJar()); // In case dl can be started before
+        // showing confirmation dialog.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  ConfirmInstallation()); // Show UI confirmation dialog.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  DownloadJar()); // If dl has not yet been started, start it now.
+        table.add(convertIconsStep);
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  WaitForDownload());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  GetAttributes()); // For reading jar if not yet done.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  SelectUids()); // Select application uids now that jar is
+        // available.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  CheckDiskSpace()); // Check again now that also jar is available.
+        table.add(convertIconsStep);
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  AuthenticateJar()); // If not yet done, check now that
+        // jar is available.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  GrantJarPermissions());  // Permission granting is made
+        // after authentication step if needed.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  ConfirmPermissions()); // Show UI confirmation dialog.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  HandleCustomAttributes());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  CheckJarPackages());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  StopApplication());
+        // Update new application info in the following steps.
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  AddToStorage());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  RegisterPush());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  RegisterApplication());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  RegisterApplicationToSif());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  CopyAppFiles());
+        if (Platform.isS60())   // PrepareSplashScreen uses eSWT which is
+        {
+            // not available in Linux.
+            table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                      PrepareSplashScreen()); // Create splash screen images
+            // after app dir exists (after CopyAppFiles step).
+        }
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  NotifyJsrPlugins());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  WaitForPermissionsQuery());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  FinalizeInstallation());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  SendOtaStatus());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  SendInstallerResultMessage());
+        table.add(new com.nokia.mj.impl.installer.midp2.install.steps.
+                  WaitForLaunchAppQuery());
+        return table;
+    }
+
+    private static ExeTable getMidp2UninstallTable()
+    {
+        ExeTable table = new ExeTable();
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  CreateUi());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  SendInstallerResultMessage());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  PrepareUninstallation());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  GetFromStorage());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  StartProgressNotifications());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  CheckUninstallationAllowed());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  CheckDiskSpace());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  ConfirmUninstallation()); // Show UI confirmation dialog.
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  StopApplication());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  NotifyJsrPlugins());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  UnregisterApplicationFromSif());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  UnregisterApplication());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  UnregisterPush());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  RemoveSecurityData());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  RemoveFromStorage());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  RemoveAppFiles());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  FinalizeUninstallation());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  SendOtaStatus());
+        table.add(new com.nokia.mj.impl.installer.midp2.uninstall.steps.
+                  SendInstallerResultMessage());
+        return table;
+    }
+
+    /**
+     * Main program for listing installed application suites.
+     */
+    private static void list(Args aArgs)
+    {
+        boolean verbose = (aArgs.get("v") != null? true: false);
+        String otaStatusArg = aArgs.get("otastatus");
+        String systemPropertiesArg = aArgs.get("systemproperties");
+        String storageArg = aArgs.get("storage");
+
+        if (systemPropertiesArg != null)
+        {
+            // CDC code for logging system properties.
+            Hashtable props = System.getProperties();
+            Enumeration e = props.keys();
+            Log.logOut("System properties:");
+            while (e.hasMoreElements())
+            {
+                String key = (String)e.nextElement();
+                String value = (String)props.get(key);
+                Log.logOut(key + ": " + value);
+            }
+        }
+
+        if (storageArg != null)
+        {
+            // List contents of Storage tables.
+            StorageHandler sh = new StorageHandler();
+            String[] tables = getStorageTables(storageArg);
+            for (int i = 0; i < tables.length; i++)
+            {
+                String storageEntriesString =
+                    sh.getStorageEntriesString(tables[i]);
+                if (storageEntriesString != null)
+                {
+                    Log.logOut(storageEntriesString);
+                }
+            }
+            sh.close();
+        }
+
+        if (otaStatusArg != null)
+        {
+            // List pending OTA status notifications.
+            OtaStatusNotification[] notifications =
+                new OtaStatusHandler().getNotifications();
+            if (notifications != null)
+            {
+                for (int i = 0; i < notifications.length; i++)
+                {
+                    Log.logOut(notifications[i].toString() + "\n");
+                }
+            }
+        }
+
+        if (storageArg == null && otaStatusArg == null &&
+                systemPropertiesArg == null)
+        {
+            // By default list installed application suites.
+            SifRegistrator sr = new SifRegistrator();
+            sr.startSession(false);
+            StorageHandler sh = new StorageHandler();
+            Uid[] uids = sh.getSuiteUids();
+            if (uids != null)
+            {
+                for (int i = 0; i < uids.length; i++)
+                {
+                    SuiteInfo si = new SuiteInfo(uids[i]);
+                    if (sh.readSuiteInfo(si))
+                    {
+                        StringBuffer sb = new StringBuffer();
+                        // List SuiteInfo.
+                        if (verbose)
+                        {
+                            sb.append(si.toString());
+                        }
+                        else
+                        {
+                            sb.append(si.toShortString());
+                        }
+                        // List push connections.
+                        sb.append(pushConnectionsToString(si.getApplicationUids()));
+                        if (verbose)
+                        {
+                            // List certificate details.
+                            Certificate[] certs =
+                                AuthenticationModule.getInstance()
+                                .getCertificatesDetails(sh.getSession(),
+                                                        uids[i]);
+                            if (certs != null)
+                            {
+                                for (int j = 0; j < certs.length; j++)
+                                {
+                                    sb.append("Certificate[").append(j).append("]:\n");
+                                    sb.append(certs[j].toString()).append("\n");
+                                }
+                            }
+                        }
+                        Log.logOut(sb.toString());
+                        sr.logComponent(si.getGlobalId());
+                        Vector apps = si.getApplications();
+                        for (int j = 0; j < apps.size(); j++)
+                        {
+                            sr.logComponent(si.getGlobalId(j));
+                        }
+                    }
+                }
+            }
+            sh.close();
+            sr.closeSession();
+        }
+    }
+
+    /**
+     * Returns string containing push connection information for
+     * specified applications.
+     */
+    private static String pushConnectionsToString(Uid[] aAppUids)
+    {
+        StringBuffer result = new StringBuffer();
+        PushRegistrator pushRegistrator = null;
+        try
+        {
+            // Instantiate PushRegistrator implementation.
+            Class clazz = Class.forName(PushInfo.PUSH_REGISTRATOR_CLASS);
+            pushRegistrator = (PushRegistrator)clazz.newInstance();
+        }
+        catch (Exception ex)
+        {
+            // Ignore silently, just return empty string.
+            return result.toString();
+        }
+
+        // Found PushRegistrator, ask PushInfos for each application.
+        for (int i = 0; aAppUids != null && i < aAppUids.length; i++)
+        {
+            PushInfo[] pushInfos =
+                pushRegistrator.getPushInfos(aAppUids[i]);
+            if (pushInfos != null && pushInfos.length > 0)
+            {
+                result.append("Push connections:\n");
+            }
+            for (int j = 0; pushInfos != null && j < pushInfos.length; j++)
+            {
+                result.append("  ").append(pushInfos[j]).append("\n");
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * Returns an array of Storage table names from given
+     * string argument. If argument contains no table names
+     * then names of all Storage tables are returned.
+     */
+    private static String[] getStorageTables(String aStorageArg)
+    {
+        String[] result = null;
+        if (aStorageArg == null || aStorageArg.length() == 0)
+        {
+            result = new String[]
+            {
+                StorageNames.APPLICATION_PACKAGE_TABLE,
+                StorageNames.APPLICATION_TABLE,
+                StorageNames.APPLICATION_PACKAGE_ATTRIBUTES_TABLE,
+                StorageNames.MIDP_PACKAGE_TABLE,
+                StorageNames.MIDP_PERMISSIONS_TABLE,
+                StorageNames.MIDP_FUNC_GRP_SETTINGS_TABLE,
+                StorageNames.PUSH_REGISTRATIONS_TABLE,
+                StorageNames.ALARM_REGISTRATIONS_TABLE,
+                StorageNames.RUNTIME_SETTINGS_TABLE,
+                StorageNames.PREINSTALL_TABLE,
+                //StorageNames.OTA_STATUS_TABLE,
+            };
+        }
+        else
+        {
+            result = Tokenizer.split(aStorageArg, ",");
+        }
+        return result;
+    }
+
+    /**
+     * Main program for uninstalling all installed applications.
+     */
+    private static int uninstallAll(Args aArgs, String[] aStringArgs)
+    {
+        String uidArg = aArgs.get("uid");
+        if (uidArg != null)
+        {
+            Log.log("Uid must not be specified for uninstallall command.");
+            return ERR_GENERAL;
+        }
+        int result = ERR_NONE;
+        StorageHandler sh = new StorageHandler();
+        try
+        {
+            Uid[] uids = sh.getSuiteUids();
+            if (uids != null)
+            {
+                String[] stringArgs = new String[aStringArgs.length + 1];
+                for (int i = 0; i < aStringArgs.length; i++)
+                {
+                    if (aStringArgs[i].equals("uninstallall"))
+                    {
+                        stringArgs[i] = "uninstall";
+                    }
+                    else
+                    {
+                        stringArgs[i] = aStringArgs[i];
+                    }
+                }
+
+                final int NO_DRIVE = -2;
+                int uninstallationDrive = NO_DRIVE;
+                String arg = aArgs.get("drive");
+                if (arg != null)
+                {
+                    uninstallationDrive = aArgs.parseDrive(arg);
+                }
+
+                int countOk = 0, countNok = 0;
+                Log.log("Starting to uninstall " + uids.length +
+                        " applications");
+                for (int i = 0; i < uids.length; i++)
+                {
+                    SuiteInfo suite = new SuiteInfo(uids[i]);
+                    if (sh.readSuiteInfo(suite))
+                    {
+                        int suiteDrive = FileUtils.getDrive(suite.getRootDir());
+                        if (uninstallationDrive != NO_DRIVE &&
+                                uninstallationDrive != suiteDrive)
+                        {
+                            // Drive option has been specified, but current
+                            // suite is from different drive so it must not
+                            // be uninstalled.
+                            Log.log("Application " + uids[i] + " from drive " +
+                                    suiteDrive + " not uninstalled");
+                            break;
+                        }
+                    }
+
+                    stringArgs[stringArgs.length-1] = "-uid=" + uids[i];
+                    int newResult = mainWithResult(stringArgs);
+                    if (newResult != ERR_NONE)
+                    {
+                        countNok++;
+                        result = newResult;
+                        Log.logError("Uninstalling application " + uids[i] +
+                                     " failed, result=" + result);
+                    }
+                    else
+                    {
+                        Log.log("Application " + uids[i] + " uninstalled");
+                        countOk++;
+                    }
+                }
+                Log.log("Successfully uninstalled " + countOk + " applications");
+                if (countNok > 0)
+                {
+                    Log.log("Uninstalling " + countNok + " applications failed");
+                }
+            }
+        }
+        finally
+        {
+            if (sh != null)
+            {
+                sh.close();
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Main program for removing OMJ directories from Java runtime
+     * directory and removing all data from JavaStorage.
+     */
+    private static int removeAllData(Args aArgs)
+    {
+        int result = ERR_NONE;
+        // Remove OMJ data directories.
+        try
+        {
+            Vector driveInfos = new Vector();
+            SysUtil.getUserVisibleDrives(driveInfos);
+            for (int i = 0; i < driveInfos.size(); i++)
+            {
+                DriveInfo driveInfo = (DriveInfo)driveInfos.elementAt(i);
+                int tmpResult = removeAllData(driveInfo.getNumber());
+                if (tmpResult != ERR_NONE)
+                {
+                    result = tmpResult;
+                }
+            }
+        }
+        catch (Throwable t)
+        {
+            Log.logError("Removing data failed", t);
+            result = ERR_GENERAL;
+        }
+        // Remove data from JavaStorage.
+        try
+        {
+            if (!StorageHandler.removeAllData())
+            {
+                result = ERR_GENERAL;
+            }
+        }
+        catch (Throwable t)
+        {
+            Log.logError("Removing JavaStorage data failed", t);
+            result = ERR_GENERAL;
+        }
+        // Remove property definitions.
+        unregisterProperties(aArgs);
+        return result;
+    }
+
+    /**
+     * Removes OMJ directories from Java runtime directory
+     * from specified drive.
+     */
+    private static int removeAllData(int aDrive)
+    {
+        int result = ERR_NONE;
+        String midpRoot = FileRoots.getMidpRoot();
+        String[] privateDirs =
+        {
+            "apps", "installer", "resource", "security"
+        };
+        for (int i = 0; i < privateDirs.length; i++)
+        {
+            String privateDir = FileUtils.setDrive(
+                                    midpRoot + privateDirs[i], aDrive);
+            try
+            {
+                FileUtility file = new FileUtility(privateDir);
+                if (file.isDirectory())
+                {
+                    if (FileOperations.deleteAll(privateDir))
+                    {
+                        Log.log("Removed " + privateDir);
+                    }
+                    else
+                    {
+                        Log.logError("Removing " + privateDir + " failed");
+                        result = ERR_GENERAL;
+                    }
+                }
+            }
+            catch (IOException ioe)
+            {
+                Log.logError("Removing " + privateDir + " failed", ioe);
+                result = ERR_GENERAL;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Main program for starting JavaInstaller in polling mode.
+     * Installer send Comms messages to get actual install/uninstall tasks.
+     */
+    private static int poll(String[] aStringArgs)
+    {
+        CommsInstaller poller = new CommsInstaller(aStringArgs);
+        return poller.run();
+    }
+
+    /**
+     * Main program for launching an application.
+     */
+    private static void launch(Args aArgs)
+    {
+        String uidArg = aArgs.get("uid");
+        if (uidArg == null)
+        {
+            Log.logOut("Uid must be specified for launch command.");
+            return;
+        }
+        Uid uid = PlatformUid.createUid(uidArg);
+        if (uid == null)
+        {
+            Log.logOut("Invalid uid " + uidArg);
+            return;
+        }
+        CaptainService captainService = new CaptainService(false);
+        Log.logOut("Launching application with uid " + uid);
+        captainService.launchApp(uid);
+    }
+
+    /**
+     * Main program for executing tests within JavaInstaller runtime.
+     */
+    private static void test(Args aArgs, String[] aStringArgs)
+    {
+        String mainClass = aArgs.get("mainclass");
+        if (mainClass == null)
+        {
+            Log.logOut("Mainclass must be specified for test command.");
+            return;
+        }
+
+        String domain = aArgs.get("domain");
+        if (domain != null)
+        {
+            ApplicationInfoImpl appInfoImpl =
+                (ApplicationInfoImpl)ApplicationInfo.getInstance();
+            appInfoImpl.setProtectionDomain(domain);
+            Log.logOut("Set protection domain to " +
+                       appInfoImpl.getProtectionDomain());
+        }
+
+        String server = aArgs.get("server");
+        if (server != null)
+        {
+            String serverProperty = "com.nokia.mj.impl.installer.test.server";
+            System.setProperty(serverProperty, server);
+            Log.logOut("Set " + serverProperty + " to " +
+                       System.getProperty(serverProperty));
+        }
+
+        for (int i = 0; i < 10; i++)
+        {
+            String param = aArgs.get("param" + i);
+            if (param != null)
+            {
+                String paramProperty =
+                    "com.nokia.mj.impl.installer.test.param" + i;
+                System.setProperty(paramProperty, param);
+                Log.logOut("Set " + paramProperty + " to " +
+                           System.getProperty(paramProperty));
+            }
+        }
+
+        // Disable ExeBall.ForceExitThread so that also long lasting
+        // tests can be executed.
+        System.setProperty("com.nokia.mj.impl.installer.disableforceexit",
+                           "true");
+
+        try
+        {
+            // Instantiate mainclass and call its main() method.
+            Class clazz = Class.forName(mainClass);
+            InstallerMain instMain = (InstallerMain)clazz.newInstance();
+            Log.logOut("Starting test class " + mainClass);
+            instMain.installerMain(aStringArgs);
+        }
+        catch (Exception ex)
+        {
+            InstallerException.internalError("Running mainclass failed", ex);
+        }
+    }
+
+    /**
+     * Prints usage information to log and system output.
+     */
+    private static void usage(String[] aArgs)
+    {
+        String cmd = "javainstaller";
+        String usageMsg =
+            "Usage: "+cmd+" <command> [options]\n"+
+            "\n"+
+            "where command is one of:\n"+
+            "  help          Prints help on "+cmd+" usage.\n"+
+            "  version       Prints version information.\n"+
+            "  componentinfo Get information of an installed or not\n"+
+            "                installed Java application.\n"+
+            "  install       Install or upgrade Java application suite.\n"+
+            "  uninstall     Uninstall Java application suite.\n"+
+            "  uninstallall  Uninstall all Java application suites.\n"+
+            "  list          List installed Java application suites.\n"+
+            "  launch        Launch an installed Java application.\n"+
+            "  poll          TCK Runner / preinstaller / appconverter optimised mode.\n"+
+            "  rollback      Do only IntegrityService rollback, and nothing else.\n"+
+            "  removealldata Removes all OMJ specific data from Java\n"+
+            "                runtime private directory and JavaStorage.\n"+
+            "  register      Registers all system wide properties installer uses.\n"+
+            "  unregister    Unregisters all system wide properties installer uses.\n"+
+            "  test          Execute test cases within JavaInstaller runtime.\n"+
+            "\n"+
+            "Type '"+cmd+" help <command>' for help on a specific command.\n";
+        if (aArgs == null || aArgs.length <= 1)
+        {
+            Log.logOut(usageMsg);
+            return;
+        }
+
+        String helpCmd =
+            "Gives list of available commands or command specific help.\n"+
+            "\n"+
+            "Usage: "+cmd+" help [command]\n"+
+            "\n"+
+            "where\n"+
+            "  \"command\" is the command to get help for\n";
+
+        String versionCmd =
+            "Prints version information.\n"+
+            "\n"+
+            "Usage: "+cmd+" version\n";
+
+        String componentInfoCmd =
+            "Get information of an installed or not installed Java application.\n"+
+            "\n"+
+            "Usage: "+cmd+" componentinfo [options]\n"+
+            "\n"+
+            "where options are:\n"+
+            "  -jad=jad_file                 Path to Jad file.\n"+
+            "  -jar=jar_file                 Path to Jar file.\n"+
+            "  -charset=charset              Internet standard character set name telling\n"+
+            "                                charset used in Jad file.\n"+
+            "  -uid=uid                      Suite or application uid identifying the\n"+
+            "                                application suite.\n"+
+            "  -commsresult=endpoint         In the end of operation, send\n"+
+            "                                InstallerResultMessage to specified comms\n"+
+            "                                endpoint.\n"+
+            "\n"+
+            "Either -jad, -jar or -uid must be specified, other options are optional.\n";
+
+        String installCmd =
+            "Installs or upgrades Java application suite.\n"+
+            "\n"+
+            "Usage: "+cmd+" install [options]\n"+
+            "\n"+
+            "where options are:\n"+
+            "  -jad=jad_file                 Path or URL to Jad file.\n"+
+            "  -jar=jar_file                 Path or URL to Jar file.\n"+
+            "  -charset=charset              Internet standard character set name telling\n"+
+            "                                charset used in Jad file.\n"+
+            "  -sourceurl=sourceurl          Source URL where given Jad file was\n"+
+            "                                downloaded.\n"+
+            "  -iap=iap_id                   Internet access point to be used in\n"+
+            "                                downloads and status notification posting\n"+
+            "                                during installation.\n"+
+            "  -snap=snap_id                 Service network access point to be used in\n"+
+            "                                downloads and status notification posting\n"+
+            "                                during installation.\n"+
+            "  -drive=target_drive           Installation target drive (C,D,E,...).\n"+
+            "                                This option is valid only in S60 platform.\n"+
+            "  -silent                       Perform silent installation.\n"+
+            "  -upgrade=yes|no               Is upgrade allowed, default is yes.\n"+
+            "  -upgrade_data=yes|no          Retain or remove application private data\n"+
+            "                                in upgrade, default is MIDP specified\n"+
+            "                                behaviour.\n"+
+            "  -overwrite=yes|no             Allow upgrade with the same version,\n"+
+            "                                default is yes.\n"+
+            "  -untrusted=yes|no             Allow installing untrusted application,\n"+
+            "                                default is yes.\n"+
+            "  -ocsp=yes|no                  Perform OCSP, default is yes.\n"+
+            "  -ignore_ocsp_warnings=yes|no  Ignore OCSP warnings, default yes.\n"+
+            "  -download=yes|no              Is download allowed, default is yes.\n"+
+            "  -username=download_username   Username for HTTP authentication.\n"+
+            "  -password=download_password   Password for HTTP authentication.\n"+
+            "  -proxyhost=host               HTTP proxy host.\n"+
+            "  -proxyport=port_number        HTTP proxy port number.\n"+
+            "  -log=is                       Write log entries from IntegrityService\n"+
+            "                                operations.\n"+
+            "  -forcecancel                  Cancel installation before committing\n"+
+            "                                anything. This option is for debugging\n"+
+            "                                purposes only.\n"+
+            "  -captainmsgs=yes|no           If set to no, JavaInstaller will not send\n"+
+            "                                any messages to JavaCaptain during\n"+
+            "                                installation. Default is yes.\n"+
+            "  -skipjarcheck                 Skip application package scanning.\n"+
+            "  -skipotastatus                Skip OTA status handling.\n"+
+            "  -commsresult=endpoint         In the end of operation, send\n"+
+            "                                InstallerResultMessage to specified comms\n"+
+            "                                endpoint.\n"+
+            "\n"+
+            "Either -jad or -jar must be specified, other options are optional.\n";
+
+        String uninstallCmd =
+            "Uninstalls Java application suite.\n"+
+            "\n"+
+            "Usage: "+cmd+" uninstall [options]\n"+
+            "\n"+
+            "where options are:\n"+
+            "  -uid=uid                      Suite or application uid identifying the\n"+
+            "                                suite to be uninstalled.\n"+
+            "  -cid=component_id             Component id identifying the application\n"+
+            "                                to be uninstalled.\n"+
+            "  -iap=iap_id                   Internet access point to be used in\n"+
+            "                                uninstallation status notification posting.\n"+
+            "  -snap=snap_id                 Service network access point to be used in\n"+
+            "                                uninstallation status notification posting.\n"+
+            "  -silent                       Perform silent uninstallation.\n"+
+            "  -log=is                       Write log entries from IntegrityService\n"+
+            "                                operations.\n"+
+            "  -forceuninstall               Forces uninstallation even if uninstallation\n"+
+            "                                is blocked with Nokia-MIDlet-Block-Uninstall\n"+
+            "                                attribute.\n"+
+            "  -forcecancel                  Cancel uninstallation before committing\n"+
+            "                                anything. This option is for debugging\n"+
+            "                                purposes only.\n"+
+            "  -captainmsgs=yes|no           If set to no, JavaInstaller will not send\n"+
+            "                                any messages to JavaCaptain during\n"+
+            "                                uninstallation. Default is yes.\n"+
+            "  -skipotastatus                Skip OTA status handling.\n"+
+            "  -commsresult=endpoint         In the end of operation, send\n"+
+            "                                InstallerResultMessage to specified comms\n"+
+            "                                endpoint.\n"+
+            "\n"+
+            "The -uid option must be specified, other options are optional.\n";
+
+        String uninstallAllCmd =
+            "Uninstalls all installed Java application suites.\n"+
+            "\n"+
+            "Usage: "+cmd+" uninstallall [options]\n"+
+            "\n"+
+            "where options are the same as for uninstall command,\n"+
+            "except that -uid option is not allowed.\n";
+
+        String listCmd =
+            "Lists installed Java applications.\n"+
+            "\n"+
+            "Usage: "+cmd+" list [options]\n"+
+            "\n"+
+            "where options are:\n"+
+            "  -v                            More verbose output.\n"+
+            "  -otastatus                    List pending OTA status notifications.\n"+
+            "  -systemproperties             List system properties.\n"+
+            "  -storage[=tbl1[,tbl2]...]     List contents of storage tables.\n"+
+            "                                If table names are not specified\n"+
+            "                                lists contents of all tables.\n";
+
+        String launchCmd =
+            "Launches an installed Java application.\n"+
+            "\n"+
+            "Usage: "+cmd+" launch [options]\n"+
+            "\n"+
+            "where options are:\n"+
+            "  -uid=uid                      Application uid identifying the\n"+
+            "                                application to be launched.\n";
+
+        String pollCmd =
+            "Uses Comms to get install/uninstall commands from TCK Runner, preinstaller or appconverter.\n"+
+            "\n"+
+            "Usage: "+cmd+" poll -address=(tck|preinstall|convert) [options]\n"+
+            "\n"+
+            "The specified options are used in install/uninstall operations if applicable.\n";
+
+        String rollbackCmd =
+            "Perform IntegrityService rollback, and do nothing else.\n"+
+            "\n"+
+            "Usage: "+cmd+" rollback [options]\n"+
+            "\n"+
+            "where options are:\n"+
+            "  -log=is                       Write log entries from IntegrityService\n"+
+            "                                operations.\n";
+
+        String testCmd =
+            "Execute test cases within JavaInstaller runtime.\n"+
+            "\n"+
+            "Usage: "+cmd+" test [options]\n"+
+            "\n"+
+            "where options are:\n"+
+            "  -mainclass=InstallerMainClass Executes the given InstallerMainClass\n"+
+            "                                in JavaInstaller runtime.\n"+
+            "                                InstallerMainClass must implement\n"+
+            "                                com.nokia.mj.impl.installer.utils.InstallerMain\n"+
+            "                                interface.\n"+
+            "  -domain=protection_domain     Set protection domain in which the tests\n"+
+            "                                are executed. Possible values are:\n"+
+            "                                MFD, OPD, ITPD, UTPD. Default is UTPD.\n";
+
+        String msg = null;
+        for (int i = 1; i < aArgs.length; i++)
+        {
+            if (aArgs[i].equals("help"))
+            {
+                msg = helpCmd;
+            }
+            else if (aArgs[i].equals("version"))
+            {
+                msg = versionCmd;
+            }
+            else if (aArgs[i].equals("componentinfo"))
+            {
+                msg = componentInfoCmd;
+            }
+            else if (aArgs[i].equals("install"))
+            {
+                msg = installCmd;
+            }
+            else if (aArgs[i].equals("uninstall"))
+            {
+                msg = uninstallCmd;
+            }
+            else if (aArgs[i].equals("uninstallall"))
+            {
+                msg = uninstallAllCmd;
+            }
+            else if (aArgs[i].equals("list"))
+            {
+                msg = listCmd;
+            }
+            else if (aArgs[i].equals("launch"))
+            {
+                msg = launchCmd;
+            }
+            else if (aArgs[i].equals("poll"))
+            {
+                msg = pollCmd;
+            }
+            else if (aArgs[i].equals("rollback"))
+            {
+                msg = rollbackCmd;
+            }
+            else if (aArgs[i].equals("removealldata"))
+            {
+                msg = "Removes all OMJ specific data from Java runtime directory and JavaStorage.\n";
+            }
+            else if (aArgs[i].equals("register"))
+            {
+                msg = "Registers all system wide properties installer uses.\n";
+            }
+            else if (aArgs[i].equals("unregister"))
+            {
+                msg = "Unregisters all system wide properties installer uses.\n";
+            }
+            else if (aArgs[i].equals("test"))
+            {
+                msg = testCmd;
+            }
+            else
+            {
+                msg = "Unknown command " + aArgs[i] + "\n";
+            }
+            Log.logOut(msg);
+        }
+    }
+
+    /**
+     * Prints version information to log and system output.
+     */
+    private static void version(Args aArgs)
+    {
+        String versionMsg =
+            ApplicationInfo.getInstance().getName() + " " +
+            ApplicationInfo.getInstance().getVersion() +
+            " for Open Mobile Java\n";
+        // Add OS info
+        versionMsg += "OS: " + System.getProperty("os.name") +
+                      " " + System.getProperty("os.version") + "\n";
+        // Add VM info
+        versionMsg += "VM name: " + System.getProperty("java.vm.name") + "\n";
+        versionMsg += "VM version: " + System.getProperty("java.vm.version") +
+                      " (" + System.getProperty("java.vm.info") + ")\n";
+        versionMsg += "VM vendor: " + System.getProperty("java.vm.vendor") + "\n";
+        // Add runtime info
+        versionMsg += "Runtime: " + System.getProperty("java.runtime.name") +
+                      " " + System.getProperty("java.runtime.version") + "\n";
+        // Add user info
+        //versionMsg += getProperty("user.name");
+        //versionMsg += getProperty("user.home");
+        // Add microedition info
+        versionMsg += getProperty("microedition.platform");
+        versionMsg += getProperty("microedition.configuration");
+        versionMsg += getProperty("microedition.profiles");
+        versionMsg += getProperty("microedition.locale");
+
+        Log.logOut(versionMsg);
+    }
+
+    private static String getProperty(String aName)
+    {
+        StringBuffer buf = new StringBuffer();
+        buf.append(aName).append(": ")
+        .append(System.getProperty(aName)).append("\n");
+        return buf.toString();
+    }
+
+    /**
+     * Registers all system wide properties installer uses.
+     */
+    private static void registerProperties(Args aArgs)
+    {
+        InstallationNotifier.defineProperties();
+    }
+
+    /**
+     * Unregisters all system wide properties installer has registered.
+     */
+    private static void unregisterProperties(Args aArgs)
+    {
+        InstallationNotifier.deleteProperties();
+    }
+
+    private static class InstallerListener implements CommsListener
+    {
+        public void processMessage(CommsMessage aMessage)
+        {
+            try
+            {
+                int result = ERR_GENERAL;
+                Log.log("InstallerListener received " + aMessage);
+                if (aMessage.hasPermission(CommsPermission.INSTALL_APPLICATION))
+                {
+                    int msgId = aMessage.getMessageId();
+                    if (msgId == 603)
+                    {
+                        Installer.cancel();
+                        result = ERR_NONE;
+                    }
+                }
+                else
+                {
+                    Log.logWarning("InstallerListener received message " +
+                                   "with no INSTALL_APPLICATION permission");
+                }
+                CommsMessage response = new CommsMessage();
+                response.replyTo(aMessage);
+                response.setMessageId(604);
+                response.write(result);
+                iInstallerServer.send(response);
+                Log.log("InstallerListener sent " + response);
+            }
+            catch (Throwable t)
+            {
+                Log.logError("InstallerListener error", t);
+            }
+        }
+    }
+}