com.codesourcery.internal.installer.InstallManager.java Source code

Java tutorial

Introduction

Here is the source code for com.codesourcery.internal.installer.InstallManager.java

Source

/*******************************************************************************
 *  Copyright (c) 2014 Mentor Graphics and others.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  which accompanies this distribution, and is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 * 
 *  Contributors:
 *     Mentor Graphics - initial API and implementation
 *******************************************************************************/
package com.codesourcery.internal.installer;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.program.Program;

import com.codesourcery.installer.IInstallAction;
import com.codesourcery.installer.IInstallData;
import com.codesourcery.installer.IInstallDescription;
import com.codesourcery.installer.IInstallManager;
import com.codesourcery.installer.IInstallManifest;
import com.codesourcery.installer.IInstallMode;
import com.codesourcery.installer.IInstallModule;
import com.codesourcery.installer.IInstallProduct;
import com.codesourcery.installer.IInstallWizardPage;
import com.codesourcery.installer.IInstalledProduct;
import com.codesourcery.installer.IProductRange;
import com.codesourcery.installer.InstallPageTitle;
import com.codesourcery.installer.Installer;
import com.codesourcery.installer.LaunchItem;
import com.codesourcery.installer.LaunchItem.LaunchItemType;
import com.codesourcery.installer.ui.InstallWizardPage;
import com.codesourcery.internal.installer.actions.InstallIUAction;

/**
 * This class manages install operations.
 * Call {@link #setInstallLocation(IPath)} to set the install location.
 */
public class InstallManager implements IInstallManager {
    /** Cleanup progress work */
    private static final int CLEANUP_PROGRESS = 10;
    /** Uninstall setup progress work */
    private static final int UNINSTALL_SETUP_PROGRESS = 10;
    /** Product progress work */
    private static final int PRODUCT_PROGRESS = 100;
    /** Install registry filename */
    private static final String INSTALL_REGISTRY_FILENAME = ".registry";
    /** Installed product to update with installation */
    private IInstalledProduct installedProduct;

    /**
     * Locations manager
     */
    private LocationsManager locationsManager = new LocationsManager();
    /**
     * Install description
     */
    private IInstallDescription installDescription;
    /**
     * Install manifest
     */
    private IInstallManifest installManifest;
    /**
     * Install modules
     */
    IInstallModule[] modules;
    /**
     * Install location
     */
    private IPath installLocation;
    /**
     * Install mode
     */
    private InstallMode installMode;
    /**
     * Install registry
     */
    private InstallRegistry installRegistry = new InstallRegistry();

    /**
     * Constructor
     */
    public InstallManager() {
        // Create default new install manifest
        installManifest = new InstallManifest();
        // Load install locations
        locationsManager.load();
        // Install registry
        installRegistry = new InstallRegistry();
        IPath path = Installer.getDefault().getDataFolder().append(INSTALL_REGISTRY_FILENAME);
        if (path.toFile().exists()) {
            try {
                installRegistry.load(path);
            } catch (CoreException e) {
                Installer.log(e);
            }
        }

    }

    /**
     * Disposes of the install manager.
     */
    public void dispose() {
        // Save install locations
        getLocationsManager().save();
        // Save install registry
        try {
            IPath path = Installer.getDefault().getDataFolder().append(INSTALL_REGISTRY_FILENAME);
            getInstallRegistry().save(path);
        } catch (Exception e) {
            Installer.log(e);
        }
    }

    @Override
    public void setInstallDescription(IInstallDescription installDescription) {
        this.installDescription = installDescription;
    }

    @Override
    public IInstallDescription getInstallDescription() {
        return installDescription;
    }

    @Override
    public void setInstallManifest(IInstallManifest installManifest) {
        this.installManifest = installManifest;
    }

    @Override
    public IInstallManifest getInstallManifest() {
        return installManifest;
    }

    /**
     * Returns the locations manager.
     * 
     * @return Locations manager
     */
    private LocationsManager getLocationsManager() {
        return locationsManager;
    }

    /**
     * Returns the install registry.
     * 
     * @return Install registry
     */
    private InstallRegistry getInstallRegistry() {
        return installRegistry;
    }

    @Override
    public void setInstallLocation(IPath path) throws CoreException {
        getInstallDescription().setRootLocation(path);

        // Load existing manifest if available
        loadManifest(path);

        // Location changed
        if ((path == null) || !path.equals(installLocation)) {
            // Remove old location
            if (installLocation != null) {
                RepositoryManager.getDefault().stopAgent();
                if (!getInstallMode().isUpdate() && !getInstallMode().isUpgrade()) {
                    getLocationsManager().deleteInstallLocation(installLocation);
                }
            }
            this.installLocation = path;

            // Create new location
            if (installLocation != null) {
                if (!getInstallMode().isUpdate() && !getInstallMode().isUpgrade()) {
                    getLocationsManager().createInstallLocation(installLocation);
                }
                // Create new P2 agent
                // Note, if this is not an existing installation, it will result 
                // in agent files being created in the location.
                RepositoryManager.getDefault().createAgent(getInstallDescription().getInstallLocation());
            }
        }
    }

    @Override
    public IPath getInstallLocation() {
        return installLocation;
    }

    /**
     * Sets the install mode.
     * 
     * @param installMode Install mode
     */
    public void setInstallMode(InstallMode installMode) {
        this.installMode = installMode;
    }

    @Override
    public IInstallMode getInstallMode() {
        return installMode;
    }

    @Override
    public void install(IInstallData installData, IProgressMonitor monitor) throws CoreException {
        // Installation mode
        InstallMode mode = (InstallMode) Installer.getDefault().getInstallManager().getInstallMode();

        // Check for existing version of product
        IInstallProduct product = getExistingProduct(getInstallManifest());

        // Get install actions
        IInstallAction[] actions = getInstallActions(installData);

        // Remove existing product if required
        if (!mode.isUpdate()) {
            if (product != null) {
                // Uninstall actions of existing product that require it
                for (IInstallAction action : product.getActions()) {
                    if (action.uninstallOnUpgrade()) {
                        if (isActionSupported(action)) {
                            action.run(RepositoryManager.getDefault().getAgent(), product, new InstallMode(false),
                                    new NullProgressMonitor());
                        }
                    }

                    if (monitor.isCanceled())
                        break;
                }
                // Remove existing product
                getInstallManifest().removeProduct(product);
                product = null;
            }
        }

        // Create new product
        if (product == null) {
            product = new InstallProduct(getInstallDescription().getProductId(),
                    getInstallDescription().getProductName(), getInstallDescription().getProductVersionString(),
                    getInstallDescription().getRootLocation(), getInstallDescription().getInstallLocation());
        }

        // Compute action ticks
        int totalActionWork = 0;
        for (IInstallAction action : actions) {
            if (isActionSupported(action)) {
                totalActionWork += action.getProgressWeight();
            }
        }

        monitor.beginTask("", totalActionWork + CLEANUP_PROGRESS + UNINSTALL_SETUP_PROGRESS);

        // Install
        int index;
        for (index = 0; index < actions.length; index++) {
            IInstallAction action = actions[index];
            if (isActionSupported(action)) {
                // Run action
                SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, action.getProgressWeight());
                action.run(RepositoryManager.getDefault().getAgent(), product, mode, subMonitor);

                // Add the action to the product unless the installation mode
                // is update or it is the install IU's action
                if (!getInstallMode().isUpdate() || !(action instanceof InstallIUAction)) {
                    product.addAction(action);
                }
            }
            if (monitor.isCanceled())
                break;
        }

        // Installation cancelled - clean up
        if (monitor.isCanceled()) {
            monitor.setTaskName(InstallMessages.CleanupInstallation);

            if (getInstallManifest().getProducts().length == 0) {
                mode.setRootUninstall(true);
            }

            // Uninstall performed actions
            for (int rollbackIndex = 0; rollbackIndex <= index; rollbackIndex++) {
                if (isActionSupported(actions[rollbackIndex])) {
                    actions[rollbackIndex].run(RepositoryManager.getDefault().getAgent(), product, mode,
                            new NullProgressMonitor());
                }
            }

            // Remove product directory
            SubMonitor removeProgress = SubMonitor.convert(monitor, CLEANUP_PROGRESS);
            removeProductDirectory(product, removeProgress);
        }
        // Installation completed
        else {
            monitor.worked(CLEANUP_PROGRESS);

            // Update install manifest
            getInstallManifest().addProduct(product);
            // Update install registry
            if (getInstallDescription().getUseInstallRegistry()) {
                getInstallRegistry().addProduct(new InstalledProduct(product.getId(), product.getName(),
                        product.getVersionString(), product.getLocation()));
            }

            // Install manifest path
            IPath uninstallLocation = getInstallDescription().getRootLocation()
                    .append(IInstallConstants.UNINSTALL_DIRECTORY);
            IPath manifestPath = uninstallLocation.append(IInstallConstants.INSTALL_MANIFEST_FILENAME);

            // Setup uninstaller
            try {
                if (!mode.isUpdate()) {
                    String[] uninstallFiles = getInstallDescription().getUninstallFiles();
                    if (uninstallFiles != null) {
                        // If there is an existing uninstaller, remove it to ensure
                        // the latest version is included.
                        if (uninstallLocation.toFile().exists()) {
                            try {
                                FileUtils.deleteDirectory(uninstallLocation.toFile());
                            } catch (IOException e) {
                                Installer.fail(InstallMessages.Error_CopyInstaller, e);
                            }
                        }
                        // Copy installer
                        if (!manifestPath.toFile().exists()) {
                            copyInstaller(uninstallLocation, new NullProgressMonitor());
                        }
                    }
                }
            } catch (Exception e) {
                Installer.log(e);
            }

            // Save manifest
            getInstallManifest().save(manifestPath.toFile());
        }

        monitor.worked(UNINSTALL_SETUP_PROGRESS);
        monitor.done();
    }

    @Override
    public void uninstall(IInstallProduct[] products, IProgressMonitor monitor) throws CoreException {
        SubMonitor progress = SubMonitor.convert(monitor,
                products.length * PRODUCT_PROGRESS + products.length * PRODUCT_PROGRESS);

        InstallMode mode = (InstallMode) Installer.getDefault().getInstallManager().getInstallMode();

        // Removing all products
        if (getInstallManifest().getProducts().length == products.length) {
            mode.setRootUninstall(true);
        }

        if (!mode.isRootUninstall()) {
            // Update manifest
            getInstallManifest().save();
        }

        // Run product actions
        for (IInstallProduct product : products) {
            RepositoryManager.getDefault().createAgent(product.getInstallLocation());

            int work = PRODUCT_PROGRESS / product.getActions().length;
            for (IInstallAction action : product.getActions()) {
                if (isActionSupported(action)) {
                    action.run(RepositoryManager.getDefault().getAgent(), product, mode, progress.newChild(work));
                }
                if (monitor.isCanceled())
                    break;
            }

            if (monitor.isCanceled())
                break;

            // Remove product from manifest
            getInstallManifest().removeProduct(product);
            // Remove product from install registry
            getInstallRegistry().removeProduct(product.getId());

            // Remove product directory
            removeProductDirectory(product, progress.newChild(PRODUCT_PROGRESS));
        }

        if (!mode.isRootUninstall()) {
            // Update manifest
            getInstallManifest().save();
        }
    }

    @Override
    public void launch(LaunchItem item) throws CoreException {
        IPath installLocation = getInstallDescription().getRootLocation();

        try {
            String program;
            // Executable item
            if (item.getType() == LaunchItemType.EXECUTABLE) {
                IPath toRun = installLocation.append(item.getPath());
                if (!toRun.toFile().exists())
                    Installer.fail(InstallMessages.Error_FileNotFound + toRun.toOSString());

                // Add paths to environment and launch.
                ProcessBuilder pb = new ProcessBuilder();
                String[] paths = installDescription.getEnvironmentPaths();

                if (paths != null) {
                    Map<String, String> env = pb.environment();
                    String pathKey = "PATH";
                    String pathVar = env.get(pathKey);

                    if (pathVar == null) {
                        pathVar = "";
                    }

                    for (String path : paths) {
                        IPath resolvedPath = installDescription.getRootLocation().append(path);
                        pathVar = resolvedPath.toString() + File.pathSeparatorChar + pathVar;
                    }
                    env.put(pathKey, pathVar);
                }

                program = toRun.toOSString();
                pb.command(program);
                pb.start();
            }
            // File item
            else if (item.getType() == LaunchItemType.FILE) {
                IPath toRun = installLocation.append(item.getPath());
                if (!toRun.toFile().exists())
                    Installer.fail(InstallMessages.Error_FileNotFound + toRun.toOSString());

                program = "file://" + toRun.toOSString();
                Program.launch(program);
            }
            // HTML item
            else if (item.getType() == LaunchItemType.HTML) {
                program = item.getPath();
                Program.launch(program);
            } else {
                throw new NullPointerException(InstallMessages.Error_NoLaunchItemType);
            }
        } catch (Exception e) {
            Installer.fail(NLS.bind(InstallMessages.Error_LaunchFailed0, item.getPath()), e);
        }
        // SWT Program.launch() can throw an UnsatisfiedLinkError if it is
        // unable to launch the file.
        catch (UnsatisfiedLinkError e) {
            Installer.fail(NLS.bind(InstallMessages.Error_LaunchFailed0, item.getPath()), e);
        }
    }

    /**
     * Returns the wizard pages from all install modules.  This method ensures
     * that wizard pages with the same name are not returned.
     * 
     * @return Wizard pages
     */
    protected IInstallWizardPage[] getModulePages() {
        // Filter duplicated named pages, maintain order
        LinkedHashMap<String, IInstallWizardPage> pages = new LinkedHashMap<String, IInstallWizardPage>();
        for (IInstallModule module : getModules()) {
            IInstallWizardPage[] modulePages = module.getInstallPages(getInstallMode());
            if (modulePages != null) {
                for (IInstallWizardPage modulePage : modulePages) {
                    pages.put(modulePage.getName(), modulePage);
                }
            }
        }
        return pages.values().toArray(new IInstallWizardPage[pages.size()]);
    }

    @Override
    public IInstallWizardPage[] getWizardPages() {
        if (getInstallDescription() == null)
            return new IInstallWizardPage[0];

        ArrayList<IInstallWizardPage> pages = new ArrayList<IInstallWizardPage>();

        // Wizard page order
        String[] wizardPageNames = getInstallDescription().getWizardPagesOrder();
        // First pages to insert
        IInstallWizardPage[] firstPages = wizardPageNames != null ? new IInstallWizardPage[wizardPageNames.length]
                : new IInstallWizardPage[0];
        // Remaining pages to insert
        ArrayList<IInstallWizardPage> remainingPages = new ArrayList<IInstallWizardPage>();

        // Page titles
        InstallPageTitle[] pageTitles = getInstallDescription().getPageTitles();

        IInstallWizardPage[] modulePages = getModulePages();
        // Loop through pages from all modules
        for (IInstallWizardPage modulePage : modulePages) {
            // Verify page base class
            if (modulePage instanceof InstallWizardPage) {
                InstallWizardPage page = (InstallWizardPage) modulePage;

                // Set page title if available
                if (pageTitles != null) {
                    for (InstallPageTitle pageTitle : pageTitles) {
                        if (pageTitle.getPageName().equals(modulePage.getName())) {
                            page.setPageLabel(pageTitle.getPageTitle());
                            break;
                        }
                    }
                }

                // Check if the page is found in the order
                int pos = -1;
                if (wizardPageNames != null) {
                    for (int index = 0; index < wizardPageNames.length; index++) {
                        String modulePageName = modulePage.getName();
                        if ((modulePageName != null) && modulePageName.equals(wizardPageNames[index])) {
                            pos = index;
                            break;
                        }
                    }
                }
                // First page
                if (pos != -1) {
                    firstPages[pos] = modulePage;
                }
                // Remaining page
                else {
                    remainingPages.add(modulePage);
                }
            } else {
                Installer.log(modulePage.getName() + " does not extend InstallWizardPage.");
            }
        }
        // Add first pages
        for (IInstallWizardPage page : firstPages) {
            if (page != null) {
                pages.add(page);
            }
        }
        // Add remaining pages
        for (IInstallWizardPage page : remainingPages) {
            pages.add(page);
        }

        return pages.toArray(new IInstallWizardPage[pages.size()]);
    }

    /**
     * Returns all wizard pages that are currently supported.
     * 
     * @return Supported wizard pages
     */
    public IInstallWizardPage[] getSupportedWizardPages() {
        ArrayList<IInstallWizardPage> supportedPages = new ArrayList<IInstallWizardPage>();
        IWizardPage[] pages = getWizardPages();
        for (IWizardPage page : pages) {
            if (page instanceof IInstallWizardPage) {
                IInstallWizardPage wizardPage = (IInstallWizardPage) page;
                if (wizardPage.isSupported()) {
                    supportedPages.add(wizardPage);
                }
            }
        }

        return supportedPages.toArray(new IInstallWizardPage[supportedPages.size()]);
    }

    /**
     * Loads the install manifest from the
     * install location if available.
     * 
     * @param installLocation Install location
     */
    private void loadManifest(IPath installLocation) {
        try {
            if (getInstallDescription() != null) {
                InstallManifest existingManifest = InstallManifest.loadManifest(installLocation);
                if (existingManifest != null) {
                    setInstallManifest(existingManifest);

                    if (installMode != null) {
                        // If patch then setup update mode
                        if (installMode.isPatch()) {
                            installMode.setUpdate();
                        }
                        // Else if install then set update or upgrade based
                        // on the existing version
                        else {
                            // Check for existing version of product
                            IInstallProduct existingProduct = existingManifest
                                    .getProduct(getInstallDescription().getProductId());
                            if (existingProduct != null) {
                                // Update same version
                                if (existingProduct.getVersionString()
                                        .equals(getInstallDescription().getProductVersionString())) {
                                    installMode.setUpdate();
                                }
                                // Upgrade different version
                                else {
                                    installMode.setUpgrade();
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            Installer.log(e);
        }
    }

    /**
     * Returns if an action is supported on the platform.
     * 
     * @param action Action
     * @return <code>true</code> if the action is supported
     */
    private boolean isActionSupported(IInstallAction action) {
        return action.isSupported(Platform.getOS(), Platform.getOSArch());
    }

    /**
     * Schedules the product directory to be removed on shutdown.
     * If all products are removed, the root installation directory is
     * also removed.
     * 
     * @param product Product
     * @param monitor Progress monitor
     * @throws CoreException on failure to remove product directory
     */
    private void removeProductDirectory(IInstallProduct product, IProgressMonitor monitor) throws CoreException {
        if (getInstallManifest().getProducts().length == 0) {
            getLocationsManager().deleteProductLocation(product, monitor);
        }
    }

    /**
     * Returns the registered install modules that are specified in the
     * install description.
     * 
     * @return Install modules
     */
    private IInstallModule[] getModules() {
        if (modules == null) {
            String[] ids = installDescription.getModuleIDs();
            List<String> idList = (ids != null && ids.length > 0) ? Arrays.asList(ids) : null;
            modules = ContributorRegistry.getDefault().getModules(idList);
            // Initialize modules
            for (IInstallModule module : modules) {
                module.init(getInstallDescription());
            }
        }

        return modules;
    }

    /**
     * Returns the collection of install actions sorted according to their
     * install phase, pre-install actions first, followed by install actions,
     * followed by post-install actions.
     * 
     * @param installData Install data
     * @return Sorted install actions
     */
    private IInstallAction[] getInstallActions(IInstallData installData) {
        List<IInstallAction> actions = new ArrayList<IInstallAction>();
        for (IInstallModule module : getModules()) {
            IInstallAction[] moduleActions = module.getInstallActions(RepositoryManager.getDefault().getAgent(),
                    installData, getInstallMode());
            if (moduleActions != null) {
                actions.addAll(Arrays.asList(moduleActions));
            }
        }

        // Sort the actions according to their install phase attributes.
        Collections.sort(actions, new Comparator<IInstallAction>() {
            @Override
            public int compare(IInstallAction o1, IInstallAction o2) {
                return o1.getInstallPhase().ordinal() - o2.getInstallPhase().ordinal();
            }
        });

        return actions.toArray(new IInstallAction[actions.size()]);
    }

    /**
     * Copies the installer to a location.
     * 
     * @param location Destination location
     * @param monitor Progress monitor
     * @throws CoreException on failure
     */
    private void copyInstaller(IPath destinationLocation, IProgressMonitor monitor) throws CoreException {
        try {
            File uninstallDirectory = destinationLocation.toFile();
            if (!uninstallDirectory.exists()) {
                uninstallDirectory.mkdirs();
            }

            String[] uninstallFiles = getInstallDescription().getUninstallFiles();
            if (uninstallFiles != null) {
                for (String uninstallFile : uninstallFiles) {
                    String destinationFileName = uninstallFile;
                    String srcFileName = uninstallFile;

                    // Parse file name for ":" if renaming of destination file is desired.
                    if (uninstallFile.contains(":")) {
                        srcFileName = uninstallFile.substring(0, uninstallFile.indexOf(":"));
                        destinationFileName = uninstallFile.substring(uninstallFile.indexOf(":") + 1);
                    }

                    IPath destPath = destinationLocation.append(destinationFileName);
                    File srcFile = Installer.getDefault().getInstallFile(srcFileName);
                    if (srcFile.exists()) {
                        File destFile = destPath.toFile();

                        if (srcFile.isDirectory()) {
                            FileUtils.copyDirectory(srcFile, destFile);
                        } else {
                            FileUtils.copyFile(srcFile, destFile);
                        }

                        // Set permissions
                        destFile.setExecutable(srcFile.canExecute(), false);
                        destFile.setReadable(srcFile.canRead(), false);
                        destFile.setWritable(srcFile.canWrite(), false);
                    }
                }
            }
        } catch (Exception e) {
            Installer.log(
                    "Failed to copy installer.  This could be because you are running from the Eclipse workbench and the exported RCP binary files are not available.");
        }
    }

    @Override
    public void setInstalledProduct(IInstalledProduct product) throws CoreException {
        this.installedProduct = product;
        if (product != null) {
            setInstallLocation(product.getInstallLocation());
        }
    }

    @Override
    public IInstalledProduct getInstalledProduct() {
        return installedProduct;
    }

    @Override
    public IInstalledProduct getInstalledProduct(String id) {
        return getInstallRegistry().getProduct(id);
    }

    @Override
    public IInstalledProduct[] getInstalledProducts() {
        return getInstallRegistry().getProducts();
    }

    @Override
    public IInstalledProduct[] getInstalledProducts(IProductRange[] ranges, boolean uniqueLocations) {
        ArrayList<IInstalledProduct> products = new ArrayList<IInstalledProduct>();
        HashMap<IPath, IInstalledProduct> locations = new HashMap<IPath, IInstalledProduct>();

        for (IProductRange range : ranges) {
            IInstalledProduct product = getInstallRegistry().getProduct(range.getId());
            if (product != null) {
                // Any product version or product version is in range
                if ((range.getVersionRange() == null) || range.getVersionRange().isIncluded(product.getVersion())) {
                    if (uniqueLocations)
                        locations.put(product.getInstallLocation(), product);
                    else
                        products.add(product);
                }
            }

        }

        if (uniqueLocations) {
            Collection<IInstalledProduct> values = locations.values();
            return values.toArray(new IInstalledProduct[values.size()]);
        } else {
            return products.toArray(new IInstalledProduct[products.size()]);
        }
    }

    @Override
    public IInstallProduct getExistingProduct(IInstallManifest manifest) {
        IInstallProduct product = null;

        if (manifest != null) {
            // If patch then find existing product that matches
            if (getInstallMode().isPatch()) {
                // If an installed product has been set, look up its product
                // in the manifest
                if (getInstalledProduct() != null) {
                    product = getInstallManifest().getProduct(getInstalledProduct().getId());
                }
                // Else find a product match in the manifest
                else {
                    IProductRange[] ranges = getInstallDescription().getRequires();
                    IInstallProduct[] existingProducts = null;
                    // If any product is applicable
                    if (ranges == null) {
                        existingProducts = getInstallManifest().getProducts();
                    }
                    // Find products in range
                    else {
                        existingProducts = getInstallManifest().getProducts(ranges);
                    }
                    // Use first product that matches
                    if ((existingProducts != null) && (existingProducts.length > 0)) {
                        product = existingProducts[0];
                    }
                }
            }
            // Else get existing product in manifest for product being installed
            else {
                product = manifest.getProduct(getInstallDescription().getProductId());
            }
        }

        return product;
    }
}