This framework facilitates construction of installers for laying down bits onto a target machine.

See:
          Description

Packages
com.instantiations.installer.core  
com.instantiations.installer.core.eclipse  
com.instantiations.installer.core.model  
com.instantiations.installer.core.operations  
com.instantiations.installer.core.steps  

 

This framework facilitates construction of installers for laying down bits onto a target machine. This framework is focused solely on interacting with the user and installing data; Provisioning, packaging, and automating the process of assembling the installer are expressly outside the scope of this framework.

These installers are currently self contained, having both installation behavior and data to be installed, although the framework can be extended to pull data from remote sources as part of the installation process. The bulk of the installer, written in java, is optionally wrappered in a native executable used to either locate or deliver a suitable java virutal machine and then start the java based installer. The resulting installer can interact with the user as a traditional installer using an SWT/JFace based wizard, as a console based installer, or even headlessly where all installation options are described in an options file. The framework could easily be extended to interact with the user using a Swing based wizard rather than an SWT/JFace based wizard if so desired.

Constructing an installer involves writing a main class to describe the information to be gathered and the operations necessary to install the data onto the target machine (see example below). The information to be gathered is described using IInstallStep subclasses and placed into an instance of InstallOptions. A sequence of InstallOperations is constructed to perform the actual installation of bits onto the target machine based upon the com.instantiations.installer.core.InstallOptions selected. The RunOperationsStep is used to execute the InstallOperations. This approach separates the collection of installation information from the acutall installation so that different inputs (wizard, console, headless) will drive the same installation operations. 

An InstallerFactory instantiates a subclass of Installer to interpret these IInstallSteps and gather the information necessary for the installtion. Which installer is instantiated depends upon the command line options choosen when the installer is launched. One installer subclass will interact with the user using a traditional wizard based interface while another gathers information using a console window.

During the RunOperationsStep, the InstallOperations are executed and a log file generated containing a complete list of the operations that were performed during installation. The CreateUninstallerOperation creates an uninstaller that, when executed at a later time, reads the installation log generated by the RunOperationsStep and performs the inverse operation resulting in the removal of the application from the target machine.

Some operations such as RegisterProductOperation are resolved during execution to platform specific operations and behavior. Other platform specific information and behavior can be accessed via Platform.getPlatform().

Installers for Eclipse extensions can use EclipseInstallation to locate existing installations of Eclipse based applications. ChooseEclipseStep and more generically ChooseProductStep prompt the user for which Eclipse based applications are to be extended while LinkProductOperationlinks the applications.

Example

The main() method in a typical installer main class involves: 

   options = new InstallOptions(getClass(), "install.properties");
options.setUninstall(isUninstaller());
//options.setNobackup(true);
initInstallDir();
options.parseCommandOptions(args);
  • instantiating a new installer based upon the installation options (wizard, console, headless)
   installer = InstallerFactory.createInstaller(options);
  • setting up the install steps and install operations based upon whether this is an installation or uninstallation
   if (options.isInstall())
createInstall();
else
createUninstall();
  • and then running the installer
   installer.run();

In the code above, after the InstallOptions have been instantiated, the isUninstaller method determines whether or not the code should be installing or uninstalling. This method determines whether or not the code is being installed or unstalled based upon whether or not the data is contained within this instance of the installer or if this installer is a data-less copy of the installer generated by CreateUninstallerOperation. Installation or uninstallation can be overridden by an option on the command line read as parsed by the parseCommandOptions method in the code above.

    protected boolean isUninstaller() {
        String selfPath = System.getProperty(Context.INSTALLER_JAR_PROPERTY);
        if (selfPath == null) {
            return false;
        }

        try {
            ZipFile image = new ZipFile(selfPath);
            ZipEntry installImage = image.getEntry(INSTALL_IMAGE);
            if (installImage == null) {
                return true;
            }
        }
        catch (IOException ex) {
            return false;
        }
        return false;
    }

The directory into which the product is installed is determined at time of execution:

    protected String initInstallDir() {
        IPlatform platform = Platform.getPlatform();
        if (platform == null)
            return null;
        String[] productLocations;
        try {
            productLocations = platform.readPreviousProductInstallLocations(options);
        }
        catch (Exception e) {
            if (options.isVerbose())
                e.printStackTrace();
            return null;
        }
        if (productLocations == null || productLocations.length == 0)
            return null;
        String installDir = productLocations[productLocations.length - 1];
        if (options.isVerbose())
            System.out.println("Setting InstallDir to prior installation: " + installDir);
        options.set(InstallOptions.OPTION_INSTALL_DIR, installDir);
        return installDir;
    }

Once the InstallOptions have been initialized and a new installer instantiated by the InstallerFactory, either the createInstall method is called

    protected void createInstall() {
        installer.setTitle(options.getString("InstallerTitle"));
        welcomeStep();
        licenseStep();
        installDirStep();
        chooseProductStep();
        chooseEclipseStep();
        checkEclipseRunning();
        cleanConfigStep();
        removeEmbeddedInstallStep();
        verifyInstallStep();
        installCodeStep();
        installResultStep();
        installCompleteStep();
    }

or the createUninstall method is called

    protected void createUninstall() {
    installer.setTitle(options.getString(InstallOptions.OPTION_PRODUCT_NAME) + " Uninstaller");
        verifyUninstallStep();
        uninstallCodeStep();
        uninstallCompletStep();
    }

The installDirStep() describes prompting the user for the application's installation location:

    protected String initInstallDir() {
        IPlatform platform = Platform.getPlatform();
        if (platform == null)
            return null;
        String[] productLocations;
        try {
            productLocations = platform.readPreviousProductInstallLocations(options);
        }
        catch (Exception e) {
            if (options.isVerbose())
                e.printStackTrace();
            return null;
        }
        if (productLocations == null || productLocations.length == 0)
            return null;
        String installDir = productLocations[productLocations.length - 1];
        if (options.isVerbose())
            System.out.println("Setting InstallDir to prior installation: " + installDir);
        options.set(InstallOptions.OPTION_INSTALL_DIR, installDir);
        return installDir;
    }

The installCodeStep method constructs IInstallSteps to lay down the bits on the disk based upon the InstallOptions.

    protected RunOperationsStep installCodeStep() {
        final RunOperationsStep step = new RunOperationsStep(installer) {
            public void aboutToStep() {
                try {
                    createInstallOperations(this);
                }
                catch (IOException e) {
                    showException(e);
                }
            }
        };
        initStep(step, "InstallCode");
        installer.add(step);
        return step;
    }
    protected void createInstallOperations(RunOperationsStep step) throws IOException {

        // Assemble install operations
        String selfPath = System.getProperty(Context.INSTALLER_JAR_PROPERTY);

        // The file containing code to be delivered
        ZipFile image = new ZipFile(selfPath);

        // The directory into which the product will be installed
        File installDir = new File(options.getString(InstallOptions.OPTION_INSTALL_DIR));

        // Get subproducts to be installed
        SubProduct[] subProducts = getSubProductsToInstall();

// Build the install operations
        for (int j = 0; j < subProducts.length; j++) {
            SubProduct each = subProducts[j];
            String relInstallPath = each.getInstallDirName() + File.separator + "E-" + eclipseTargetAlt;
            File installSubDir = new File(installDir, relInstallPath);
            ZipEntry[] entries = each.getEntries(image);
            for (int k = 0; k < entries.length; k++)
                step.add(new ExtractDirectoryOperation(image, entries[k], installSubDir));
        }

        String primaryProductDirName = getPrimaryProduct().getInstallDirName();
        File primaryProductDir = new File(installDir, primaryProductDirName);

        step.add(new CreateUninstallerOperation(primaryProductDir, CreateUninstallerOperation.UNINSTALL_JAR,
            INSTALL_IMAGE));
        step.add(new RegisterProductOperation(options, primaryProductDirName + File.separator
            + CreateUninstallerOperation.UNINSTALL_JAR));
    }

The verifyUninstallStep method describes prompting the user to confirm the uninstall, while the uninstallCodeStep method constructs IInstallSteps to remove the bits from the disk. The UninstallOperation operation referenced below reads the install log file and performs the inverse operation resulting in the removal of the application from the target machine.

    protected RunOperationsStep uninstallCodeStep() {
        final RunOperationsStep step = new RunOperationsStep(installer) {
            public void aboutToStep() {
                createUninstallOperations(this);
            }
        };
        step.setDescription("Uninstalling...");
        installer.add(step);
        return step;
    }

    protected void createUninstallOperations(RunOperationsStep step) {
        // Assemble uninstall operations
        String selfPath = System.getProperty(Context.INSTALLER_JAR_PROPERTY);
        File self = new File(selfPath);
        File logFile = new File(self.getParentFile(), CreateUninstallerOperation.INSTALL_LOG);

        step.add(new UninstallOperation(logFile));
    }

Related Documentation

For overviews, tutorials, examples, guides, and tool documentation, please see: