This framework facilitates construction of installers for laying
down bits onto a target machine.
See:
Description
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.
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: