org.eclipse.rcptt.launching.rap.RcpttRapLaunchDelegate.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.rcptt.launching.rap.RcpttRapLaunchDelegate.java

Source

/*******************************************************************************
 * /*******************************************************************************
 *  * Copyright (c) 2009, 2016 Xored Software Inc 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:
 *  *     Xored Software Inc - initial API and implementation and/or initial documentation
 *  *******************************************************************************/
package org.eclipse.rcptt.launching.rap;

import static org.eclipse.rcptt.internal.launching.ext.AJConstants.OSGI_FRAMEWORK_EXTENSIONS;
import static org.eclipse.rcptt.launching.rap.Activator.PLUGIN_ID;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.IStatusHandler;
import org.eclipse.debug.core.model.RuntimeProcess;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.IVMInstallType;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.pde.core.plugin.IFragmentModel;
import org.eclipse.pde.core.plugin.IPluginBase;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.plugin.ModelEntry;
import org.eclipse.pde.core.plugin.PluginRegistry;
import org.eclipse.pde.internal.build.IPDEBuildConstants;
import org.eclipse.pde.internal.launching.PDEMessages;
import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper;
import org.eclipse.pde.internal.launching.launcher.LaunchArgumentsHelper;
import org.eclipse.pde.internal.launching.launcher.LaunchConfigurationHelper;
import org.eclipse.pde.internal.launching.launcher.LauncherUtils;
import org.eclipse.pde.internal.launching.launcher.VMHelper;
import org.eclipse.pde.launching.EquinoxLaunchConfiguration;
import org.eclipse.pde.launching.IPDELauncherConstants;
import org.eclipse.rcptt.internal.launching.aut.LaunchInfoCache;
import org.eclipse.rcptt.internal.launching.aut.LaunchInfoCache.CachedInfo;
import org.eclipse.rcptt.internal.launching.ext.AJConstants;
import org.eclipse.rcptt.internal.launching.ext.IBundlePoolConstansts;
import org.eclipse.rcptt.internal.launching.ext.JDTUtils;
import org.eclipse.rcptt.internal.launching.ext.OSArchitecture;
import org.eclipse.rcptt.internal.launching.ext.Q7ExtLaunchingPlugin;
import org.eclipse.rcptt.internal.launching.ext.Q7TargetPlatformManager;
import org.eclipse.rcptt.internal.launching.ext.UpdateVMArgs;
import org.eclipse.rcptt.launching.IQ7Launch;
import org.eclipse.rcptt.launching.common.Q7LaunchingCommon;
import org.eclipse.rcptt.launching.events.AutEventManager;
import org.eclipse.rcptt.launching.ext.BundleStart;
import org.eclipse.rcptt.launching.ext.OriginalOrderProperties;
import org.eclipse.rcptt.launching.ext.Q7ExternalLaunchDelegate;
import org.eclipse.rcptt.launching.ext.Q7ExternalLaunchDelegate.BundlesToLaunch;
import org.eclipse.rcptt.launching.ext.Q7LaunchDelegateUtils;
import org.eclipse.rcptt.launching.internal.target.TargetPlatformHelper;
import org.eclipse.rcptt.launching.target.ITargetPlatformHelper;
import org.eclipse.rcptt.launching.target.TargetPlatformManager;
import org.eclipse.rcptt.tesla.core.TeslaLimits;
import org.eclipse.rcptt.util.FileUtil;

import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;

@SuppressWarnings("restriction")
public class RcpttRapLaunchDelegate extends EquinoxLaunchConfiguration {
    private static final String OSGI_BUNDLES = "osgi.bundles"; //$NON-NLS-1$
    // VM argument contants
    private static final String VMARG_PORT = "-Dorg.osgi.service.http.port="; //$NON-NLS-1$
    private static final String VMARG_DEVELOPMENT_MODE = "-Dorg.eclipse.rap.rwt.developmentMode="; //$NON-NLS-1$
    private static final String VMARG_SESSION_TIMEOUT = "-Dorg.eclipse.equinox.http.jetty.context.sessioninactiveinterval="; //$NON-NLS-1$
    private static final String VMARG_CONTEXT_PATH = "-Dorg.eclipse.equinox.http.jetty.context.path="; //$NON-NLS-1$
    private static final int CONNECT_TIMEOUT = 20000; // 20 Seconds
    static final String SLASH = "/"; //$NON-NLS-1$

    private BrowserLauncher browser;
    private ILaunch launch;
    private RAPLaunchConfig config;
    private int port;
    private final boolean testMode;

    public RcpttRapLaunchDelegate() {
        this.testMode = false;
    }

    @Override
    public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor)
            throws CoreException {

        SubMonitor submonitor = doPreLaunch(configuration, launch, monitor);
        submonitor = SubMonitor.convert(submonitor, 2000);
        Q7RapLaunchMonitor waiter = new Q7RapLaunchMonitor(launch);

        try {
            super.launch(configuration, mode, launch, submonitor.newChild(1000));
            waiter.wait(submonitor.newChild(1000), TeslaLimits.getAUTStartupTimeout() / 1000, new Runnable() {
                @Override
                public void run() {
                    try {
                        if (config.getOpenBrowser()) {
                            registerBrowserOpener();
                        }
                    } catch (CoreException e) {
                        throw new RuntimeException("Browser not open"); //$NON-NLS-1$
                    }
                }
            });
        } catch (CoreException e) {
            Activator.getDefault().errorLog("RCPTT: Failed to launch RAP AUT: " + configuration.getName(), e); //$NON-NLS-1$
            waiter.handle(e);
            // no need to throw exception in case of cancel
            if (!e.getStatus().matches(IStatus.CANCEL)) {
                throw e;
            }
        } catch (RuntimeException e) {
            Activator.getDefault().errorLog("RCPTT: Failed to launch RAP AUT: " + configuration.getName(), e); //$NON-NLS-1$
            waiter.handle(e);
            throw e;
        } finally {

            waiter.dispose();
            submonitor.done();
            monitor.done();
        }
    }

    @Override
    protected void manageLaunch(ILaunch launch) {
        // remove base PDE laucher
    }

    public SubMonitor doPreLaunch(ILaunchConfiguration config, ILaunch launch, IProgressMonitor monitor)
            throws CoreException {
        this.launch = launch;
        this.browser = new BrowserLauncher();
        this.config = new RAPLaunchConfig(config);

        SubMonitor subMonitor;
        subMonitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN);
        terminateIfRunning(subMonitor);
        subMonitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN);
        warnIfPortBusy(subMonitor);
        subMonitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN);
        port = determinePort(subMonitor);

        return subMonitor;
    }

    protected void doPreLaunchCkeck(ILaunchConfiguration configuration, ILaunch launch, IProgressMonitor monitor)
            throws CoreException {
        boolean autoValidate = configuration.getAttribute(IPDELauncherConstants.AUTOMATIC_VALIDATE, false);
        SubMonitor subMonitor = SubMonitor.convert(monitor, autoValidate ? 3 : 4);
        if (autoValidate) {
            validatePluginDependencies(configuration, subMonitor.split(1));
        }
        validateProjectDependencies(configuration, subMonitor.split(1));
        LauncherUtils.setLastLaunchMode(launch.getLaunchMode());
        clear(configuration, subMonitor.split(1));
        launch.setAttribute(IPDELauncherConstants.CONFIG_LOCATION, getConfigDir(configuration).toString());
        synchronizeManifests(configuration, subMonitor.split(1));
    }

    @Override
    protected void preLaunchCheck(ILaunchConfiguration configuration, ILaunch launch, IProgressMonitor monitor)
            throws CoreException {
        SubMonitor subm = SubMonitor.convert(monitor, 100);
        doPreLaunchCkeck(configuration, launch, subm.newChild(50));

        if (monitor.isCanceled()) {
            return;
        }

        CachedInfo info = LaunchInfoCache.getInfo(configuration);
        ITargetPlatformHelper target = (ITargetPlatformHelper) info.target;

        BundlesToLaunch bundlesToLaunch = Q7ExternalLaunchDelegate.collectBundlesCheck(target.getQ7Target(),
                subm.newChild(50), configuration);

        Q7ExternalLaunchDelegate.setBundlesToLaunch(info, bundlesToLaunch);

        Q7ExternalLaunchDelegate.removeDuplicatedModels(bundlesToLaunch.fModels, target.getQ7Target());

        setDelegateFields(this, bundlesToLaunch.fModels, bundlesToLaunch.fAllBundles);

        // Copy all additional configuration area folders into PDE new
        // configuration location.
        copyConfiguratonFiles(configuration, info);
        monitor.done();
    }

    private void copyConfiguratonFiles(final ILaunchConfiguration configuration, CachedInfo info)
            throws CoreException {
        String targetPlatformPath = ((ITargetPlatformHelper) info.target).getTargetPlatformProfilePath();
        File configFolder = new File(targetPlatformPath, "configuration"); //$NON-NLS-1$
        if (!configFolder.exists())
            return;

        Set<String> filter = new HashSet<String>(Arrays.asList(new String(".p2;" + //
                "org.eclipse.core.runtime;" //
                + "org.eclipse.equinox.app;" //
                + "org.eclipse.equinox.simpleconfigurator;" //
                + "org.eclipse.equinox.source;" //
                + "org.eclipse.osgi;" //
                + "org.eclipse.ui.intro.universal;" //
                + "org.eclipse.update;" //
                + "config.ini;" //
                + ".settings;" //
                + "org.eclipse.help.base"//
        ).split(";")));
        File target = getConfigDir(configuration);
        File[] listFiles = configFolder.listFiles();
        for (File file : listFiles) {
            if (!filter.contains(file.getName())) {
                if (file.isDirectory()) {
                    FileUtil.copyFiles(file, new File(target, file.getName()));
                } else {
                    FileUtil.copyFiles(file, target);
                }
            }
        }
    }

    public static void setDelegateFields(EquinoxLaunchConfiguration delegate, Map<IPluginModelBase, String> models,
            Map<String, IPluginModelBase> allBundles) throws CoreException {
        Throwable ex;
        try {
            Field field = EquinoxLaunchConfiguration.class.getDeclaredField("fModels");
            field.setAccessible(true);
            field.set(delegate, models);

            field = EquinoxLaunchConfiguration.class.getDeclaredField("fAllBundles");
            field.setAccessible(true);
            field.set(delegate, allBundles);

            return;
        } catch (IllegalAccessException e) {
            ex = e;
        } catch (SecurityException e) {
            ex = e;
        } catch (NoSuchFieldException e) {
            ex = e;
        }
        throw new CoreException(createStatus("Failed to inject bundles", ex)); //$NON-NLS-1$
    }

    private static Status createStatus(String message, Throwable ex) {
        return new Status(IStatus.ERROR, Activator.PLUGIN_ID, message, ex);
    }

    @Override
    public boolean preLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor)
            throws CoreException {
        if (monitor.isCanceled()) {
            return false;
        }

        if (!super.preLaunchCheck(configuration, mode, monitor))
            return false;

        waitForClearBundlePool(monitor);

        final CachedInfo info = LaunchInfoCache.getInfo(configuration);
        if (info.target != null) {
            return true;
        }

        final ITargetPlatformHelper target = Q7TargetPlatformManager.getTarget(configuration,
                SubMonitor.convert(monitor, 2));

        if (monitor.isCanceled()) {
            removeTargetPlatform(configuration);
            return false;
        }

        info.target = target;
        final MultiStatus error = new MultiStatus(Q7ExtLaunchingPlugin.PLUGIN_ID, 0,
                "Target platform initialization failed  for " + configuration.getName(), null); //$NON-NLS-1$
        error.add(target.getStatus());

        if (!error.isOK()) {
            if (monitor.isCanceled()) {
                removeTargetPlatform(configuration);
                return false;
            }
            Q7ExtLaunchingPlugin.log(error);
            removeTargetPlatform(configuration);
            throw new CoreException(error);
        }

        boolean haveAUT = false;

        OSArchitecture configArch = null;
        StringBuilder detectMsg = new StringBuilder();

        OSArchitecture architecture = ((configArch == null)
                ? ((ITargetPlatformHelper) info.target).detectArchitecture(true, detectMsg)
                : configArch);

        IVMInstall install = VMHelper.getVMInstall(configuration);

        OSArchitecture jvmArch = JDTUtils.detect(install);

        if (jvmArch.equals(architecture)
                || (jvmArch.equals(OSArchitecture.x86_64) && (JDTUtils.canRun32bit(install)))) {
            haveAUT = true;
        }

        if (!haveAUT && architecture != OSArchitecture.Unknown
                && target.detectArchitecture(false, new StringBuilder()) == OSArchitecture.Unknown) {
            haveAUT = true;
        }

        if (!haveAUT) {
            // Let's search for configuration and update JVM if possible.
            haveAUT = updateJVM(configuration, architecture, ((ITargetPlatformHelper) info.target));

            if (!haveAUT) {
                // try to register current JVM, it may help
                JDTUtils.registerCurrentJVM();
                haveAUT = updateJVM(configuration, architecture, ((ITargetPlatformHelper) info.target));
            }

        }
        if (!haveAUT) {
            removeTargetPlatform(configuration);
            throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "", null));
        }
        return true;
    }

    private void waitForClearBundlePool(IProgressMonitor monitor) {
        try {
            Job.getJobManager().join(IBundlePoolConstansts.CLEAN_BUNDLE_POOL_JOB, SubMonitor.convert(monitor, 1));
        } catch (Exception e1) {
        }
    }

    private void removeTargetPlatform(ILaunchConfiguration configuration) throws CoreException {
        String targetPlatformName = Q7TargetPlatformManager.getTargetPlatformName(configuration);
        Q7TargetPlatformManager.delete(targetPlatformName);
        LaunchInfoCache.remove(configuration);
        TargetPlatformManager.deleteTargetPlatform(targetPlatformName);
    }

    @Override
    public String[] getVMArguments(ILaunchConfiguration config) throws CoreException {
        CachedInfo info = LaunchInfoCache.getInfo(config);
        if (info.vmArgs != null) {
            return info.vmArgs;
        }

        List<String> args = new ArrayList<String>();
        // ORDER IS CRUCIAL HERE:
        // Override VM arguments that are specified manually with the values
        // necessary for the RAP launcher
        args.add("-Declipse.ignoreApp=true");
        args.add("-Dosgi.noShutdown=true");
        args.addAll(Arrays.asList(super.getVMArguments(config)));
        args.addAll(getRAPVMArguments());

        // Filter some PDE parameters
        Iterables.removeIf(args, new Predicate<String>() {
            public boolean apply(String input) {
                if (input.contains("-Declipse.pde.launch=true")) {
                    return true;
                }
                return false;
            }
        });

        args.add("-Dq7id=" + launch.getAttribute(IQ7Launch.ATTR_AUT_ID));
        args.add("-Dq7EclPort=" + AutEventManager.INSTANCE.getPort());

        TargetPlatformHelper target = (TargetPlatformHelper) ((ITargetPlatformHelper) info.target);

        IPluginModelBase hook = target.getWeavingHook();
        if (hook == null) {
            throw new CoreException(Q7ExtLaunchingPlugin.status("No " + AJConstants.HOOK + " plugin")); //$NON-NLS-1$ //$NON-NLS-2$
        }

        // Append all other properties from original config file
        OriginalOrderProperties properties = target.getConfigIniProperties();

        args = UpdateVMArgs.addHook(args, hook, properties.getProperty(OSGI_FRAMEWORK_EXTENSIONS));

        args.add("-Declipse.vmargs=" + Joiner.on("\n").join(args) + "\n");

        info.vmArgs = args.toArray(new String[args.size()]);
        return info.vmArgs;
    }

    @Override
    public String[] getProgramArguments(ILaunchConfiguration configuration) throws CoreException {

        CachedInfo info = LaunchInfoCache.getInfo(configuration);
        final ITargetPlatformHelper target = (ITargetPlatformHelper) info.target;
        if (info.programArgs != null) {
            return info.programArgs;
        }

        final List<String> programArguments = new ArrayList<String>();
        programArguments.addAll(Arrays.asList(super.getProgramArguments(configuration)));
        String dataLocationResolved = getResolvedDataLoacation();
        if (dataLocationResolved.length() > 0) {
            programArguments.addAll(Arrays.asList("-data", dataLocationResolved));
        }
        try {
            // Correct osgi.install.area property key
            File config = new File(getConfigDir(configuration), "config.ini");
            final Properties props = readProperty(config);

            File location = target.getQ7Target().getInstallLocation();
            if (location != null) {
                props.setProperty("osgi.install.area", location.getAbsolutePath()); //$NON-NLS-1$
            }

            // Append all other properties from original config file
            final OriginalOrderProperties properties = target.getConfigIniProperties();
            final String property = properties.getProperty(OSGI_BUNDLES);

            final boolean autostart = configuration.getAttribute(IPDELauncherConstants.DEFAULT_AUTO_START, true);
            props.setProperty(OSGI_BUNDLES, computeOSGiBundles(info, autostart, property)); // $NON-NLS-1$

            properties.setBeginAdd(true);
            properties.putAll(props);

            writeProperty(config, properties);
        } catch (IOException e) {
            throw new CoreException(Q7ExtLaunchingPlugin.status(e));
        }
        String override = configuration.getAttribute(IQ7Launch.OVERRIDE_SECURE_STORAGE, (String) null);
        if (override == null || "true".equals(override)) {
            // Override existing parameter
            programArguments.add("-eclipse.keyring");
            programArguments
                    .add(getConfigDir(configuration).toString() + IPath.SEPARATOR + SECURE_STORAGE_FILE_NAME);
        }

        IVMInstall install = VMHelper.getVMInstall(configuration);
        programArguments.add("-vm");
        programArguments.add(install.getInstallLocation().toString());

        info.programArgs = programArguments.toArray(new String[programArguments.size()]);

        return info.programArgs;

    }

    public static Map<IPluginModelBase, String> getTargetBundleMap(String bundles) throws CoreException {
        Map<IPluginModelBase, String> map = new HashMap<IPluginModelBase, String>();
        StringTokenizer tok = new StringTokenizer(bundles, ","); //$NON-NLS-1$
        while (tok.hasMoreTokens()) {
            String token = tok.nextToken();
            int index = token.indexOf('@');
            if (index < 0) { // if no start levels, assume default
                token = token.concat("@default:default"); //$NON-NLS-1$
                index = token.indexOf('@');
            }
            String idVersion = token.substring(0, index);
            int versionIndex = idVersion.indexOf(BundleLauncherHelper.VERSION_SEPARATOR);
            String id = (versionIndex > 0) ? idVersion.substring(0, versionIndex) : idVersion;
            String version = (versionIndex > 0) ? idVersion.substring(versionIndex + 1) : null;
            ModelEntry entry = PluginRegistry.findEntry(id);
            if (entry != null) {
                IPluginModelBase[] models = entry.getExternalModels();
                for (IPluginModelBase model : models) {
                    if (model.isEnabled()) {
                        IPluginBase base = model.getPluginBase();
                        // match only if...
                        // a) if we have the same version
                        // b) no version
                        // c) all else fails, if there's just one bundle available, use it
                        if (base.getVersion().equals(version) || version == null || models.length == 1)
                            addBundleToMap(map, model, token.substring(index + 1));
                    }
                }
            }
        }
        return map;
    }

    private static void addBundleToMap(Map<IPluginModelBase, String> map, IPluginModelBase bundle, String sl) {
        BundleDescription desc = bundle.getBundleDescription();
        boolean defaultsl = (sl == null || sl.equals("default:default")); //$NON-NLS-1$
        if (desc != null && defaultsl) {
            String runLevelText = BundleLauncherHelper.resolveSystemRunLevelText(bundle);
            String autoText = BundleLauncherHelper.resolveSystemAutoText(bundle);
            if (runLevelText != null && autoText != null) {
                map.put(bundle, runLevelText + ":" + autoText); //$NON-NLS-1$
            } else {
                map.put(bundle, sl);
            }
        } else {
            map.put(bundle, sl);
        }

    }

    private static String computeOSGiBundles(CachedInfo info, boolean autostart, String defaultBundles)
            throws CoreException {
        final Map<IPluginModelBase, BundleStart> lastversion = getBundlesToLaunch(info).latestVersionsOnly;
        final Map<String, IPluginModelBase> bundles = new LinkedHashMap<String, IPluginModelBase>(
                lastversion.size());
        final Set<IPluginModelBase> models = lastversion.keySet();
        for (IPluginModelBase model : models) {
            bundles.put(model.getPluginBase().getId(), model);
        }

        if (bundles.containsKey(IPDEBuildConstants.BUNDLE_SIMPLE_CONFIGURATOR)) {
            return Q7LaunchDelegateUtils.computeOSGiBundles(lastversion);
        } else {
            final StringBuffer buffer = new StringBuffer();
            final Iterator<IPluginModelBase> iter = models.iterator();

            Map<IPluginModelBase, String> defaultModels = getTargetBundleMap(defaultBundles);
            while (iter.hasNext()) {
                IPluginModelBase model = iter.next();
                String id = model.getPluginBase().getId();
                if (!IPDEBuildConstants.BUNDLE_OSGI.equals(id)) {
                    if (buffer.length() > 0)
                        buffer.append(","); //$NON-NLS-1$
                    buffer.append(LaunchConfigurationHelper.getBundleURL(model, true));

                    // fragments must not be started or have a start level
                    if (model instanceof IFragmentModel)
                        continue;

                    String startData = getStartData(model, defaultModels);
                    if (startData != null)
                        appendStartData(buffer, startData, autostart);
                }
            }
            return buffer.toString();
        }
    }

    private static final String ASPECTJ_BUNDLE = "org.eclipse.equinox.weaving.aspectj";
    private static final String SERVLETBRIDGE = "org.eclipse.equinox.servletbridge.extensionbundle";

    private static String getStartData(IPluginModelBase model, Map<IPluginModelBase, String> defaultModels) {
        final String id = model.getBundleDescription().getName();
        if (SERVLETBRIDGE.equals(id)) {
            return null;
        }
        if ("org.eclipse.equinox.ds".equals(id)) {
            return "1:true";
        }
        if (ASPECTJ_BUNDLE.equals(id)) {
            return "1:true";
        }

        if (defaultModels.containsKey(model)) {
            return defaultModels.get(model);
        }

        return "default:default";
    }

    private static void appendStartData(StringBuffer buffer, String startData, boolean defaultAuto) {
        int index = startData.indexOf(':');
        String level = index > 0 ? startData.substring(0, index) : "default"; //$NON-NLS-1$
        String auto = index > 0 && index < startData.length() - 1 ? startData.substring(index + 1) : "default"; //$NON-NLS-1$
        if ("default".equals(auto)) //$NON-NLS-1$
            auto = Boolean.toString(defaultAuto);
        if (!level.equals("default") || "true".equals(auto)) //$NON-NLS-1$ //$NON-NLS-2$
            buffer.append("@"); //$NON-NLS-1$

        if (!level.equals("default")) { //$NON-NLS-1$
            buffer.append(level);
            if ("true".equals(auto)) //$NON-NLS-1$
                buffer.append(":"); //$NON-NLS-1$
        }
        if ("true".equals(auto)) { //$NON-NLS-1$
            buffer.append("start"); //$NON-NLS-1$
        }
    }

    private void writeProperty(File config, OriginalOrderProperties properties)
            throws FileNotFoundException, IOException {
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(config));
        properties.store(out, "Configuration File");
        out.close();
    }

    private Properties readProperty(File config) throws FileNotFoundException, IOException {
        Properties props = new Properties();

        BufferedInputStream in = new BufferedInputStream(new FileInputStream(config));
        props.load(in);
        in.close();
        return props;
    }

    private static final String SECURE_STORAGE_FILE_NAME = "secure_storage";

    public static BundlesToLaunch getBundlesToLaunch(CachedInfo info) {
        return (BundlesToLaunch) info.data.get("bundlesToLaunch");
    }

    private String getResolvedDataLoacation() throws CoreException {
        String dataLocation = config.getDataLocation();
        return resolveVariables(dataLocation);
    }

    private String resolveVariables(String dataLocation) throws CoreException {
        VariablesPlugin variablePlugin = VariablesPlugin.getDefault();
        IStringVariableManager stringVariableManager = variablePlugin.getStringVariableManager();
        return stringVariableManager.performStringSubstitution(dataLocation);
    }

    private List<String> getRAPVMArguments() throws CoreException {
        List<String> arguments = new ArrayList<String>();
        arguments.add(VMARG_PORT + port);
        arguments.add(VMARG_DEVELOPMENT_MODE + config.getDevelopmentMode());
        if (config.getUseSessionTimeout()) {
            arguments.add(VMARG_SESSION_TIMEOUT + config.getSessionTimeout());
        } else {
            arguments.add(VMARG_SESSION_TIMEOUT + RAPLaunchConfig.MIN_SESSION_TIMEOUT);
        }
        if (config.getUseManualContextPath()) {
            String contextPath = config.getContextPath();
            if (!contextPath.startsWith(SLASH)) {
                contextPath = SLASH + contextPath;
            }
            if (contextPath.endsWith(SLASH)) {
                contextPath = contextPath.substring(0, contextPath.length() - 1);
            }
            arguments.add(VMARG_CONTEXT_PATH + contextPath);
        }
        return arguments;
    }

    static final IStatus STATUS = new Status(IStatus.INFO, PLUGIN_ID, 601, "", null); //$NON-NLS-1$

    private void warnIfPortBusy(SubMonitor monitor) throws CoreException {
        monitor.beginTask("Checking manual port", IProgressMonitor.UNKNOWN);
        try {
            if (config.getUseManualPort() && isPortBusy(config.getPort())) {
                DebugPlugin debugPlugin = DebugPlugin.getDefault();
                IStatusHandler prompter = debugPlugin.getStatusHandler(promptStatus);
                if (prompter != null) {
                    IStatus status = STATUS;
                    Object resolution = prompter.handleStatus(status, config);
                    if (Boolean.FALSE.equals(resolution)) {
                        String text = "Port {0,number,\\#} in use. Launch ''{1}'' interrupted by user.";
                        Object[] args = new Object[] { new Integer(config.getPort()), config.getName() };
                        String msg = MessageFormat.format(text, args);
                        String pluginId = PLUGIN_ID;
                        Status infoStatus = new Status(IStatus.INFO, pluginId, msg);
                        throw new CoreException(infoStatus);
                    }
                }
            }
        } finally {
            monitor.done();
        }
    }

    private int determinePort(IProgressMonitor monitor) throws CoreException {
        int result;
        monitor.beginTask("Determining port number", IProgressMonitor.UNKNOWN);
        try {
            if (config.getUseManualPort()) {
                result = config.getPort();
            } else {
                result = findFreePort();
            }
        } finally {
            monitor.done();
        }
        return result;
    }

    private static int findFreePort() throws CoreException {
        try {
            ServerSocket server = new ServerSocket(0);
            try {
                return server.getLocalPort();
            } finally {
                server.close();
            }
        } catch (IOException e) {
            String msg = "Could not obtain a free port number."; //$NON-NLS-1$
            String pluginId = PLUGIN_ID;
            Status status = new Status(IStatus.ERROR, pluginId, msg, e);
            throw new CoreException(status);
        }
    }

    private static boolean isPortBusy(int port) {
        ServerSocket server = null;
        try {
            server = new ServerSocket(port);
        } catch (IOException e1) {
            // assume that port is occupied when getting here
        }
        if (server != null) {
            try {
                server.close();
            } catch (IOException e) {
                // ignore
            }
        }
        return server == null;
    }

    private URL getUrl() throws CoreException {
        try {
            String url = URLBuilder.fromLaunchConfig(config, port, testMode);
            return new URL(url);
        } catch (MalformedURLException e) {
            String msg = "Invalid URL."; //$NON-NLS-1$
            String pluginId = PLUGIN_ID;
            Status status = new Status(IStatus.ERROR, pluginId, 0, msg, e);
            throw new CoreException(status);
        }
    }

    private void terminateIfRunning(IProgressMonitor monitor) throws CoreException {
        monitor.beginTask("Terminating previous launch", IProgressMonitor.UNKNOWN);
        try {
            ILaunch runningLaunch = findRunning();
            if (runningLaunch != null) {
                terminate(runningLaunch);
            }
        } finally {
            monitor.done();
        }
    }

    private ILaunch findRunning() {
        ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
        ILaunch[] runningLaunches = launchManager.getLaunches();
        ILaunch result = null;
        for (int i = 0; result == null && i < runningLaunches.length; i++) {
            ILaunch runningLaunch = runningLaunches[i];
            if (runningLaunch != launch && config.getName().equals(getLaunchName(runningLaunch))
                    && !runningLaunch.isTerminated()) {
                result = runningLaunches[i];
            }
        }
        return result;
    }

    private static String getLaunchName(ILaunch launch) {
        ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration();
        // the launch config might be null (e.g. if deleted) even though there
        // still exists a launch for that config
        return launchConfiguration == null ? null : launchConfiguration.getName();
    }

    private static void terminate(final ILaunch previousLaunch) throws DebugException {
        final Object signal = new Object();
        final boolean[] terminated = { false };
        final DebugPlugin debugPlugin = DebugPlugin.getDefault();
        debugPlugin.addDebugEventListener(new IDebugEventSetListener() {
            public void handleDebugEvents(DebugEvent[] events) {
                for (DebugEvent event : events) {
                    if (isTerminateEventFor(event, previousLaunch)) {
                        debugPlugin.removeDebugEventListener(this);
                        synchronized (signal) {
                            terminated[0] = true;
                            signal.notifyAll();
                        }
                    }
                }
            }
        });
        previousLaunch.terminate();
        try {
            synchronized (signal) {
                if (!terminated[0]) {
                    signal.wait();
                }
            }
        } catch (InterruptedException e) {
            // ignore
        }
    }

    private static boolean isTerminateEventFor(DebugEvent event, ILaunch launch) {
        boolean result = false;
        if (event.getKind() == DebugEvent.TERMINATE && event.getSource() instanceof RuntimeProcess) {
            RuntimeProcess process = (RuntimeProcess) event.getSource();
            result = process.getLaunch() == launch;
        }
        return result;
    }

    private void waitForHttpService(IProgressMonitor monitor) {
        SubMonitor subMonitor = SubMonitor.convert(monitor, 1);
        subMonitor.beginTask("Waiting for HTTP service", IProgressMonitor.UNKNOWN);
        try {
            long start = System.currentTimeMillis();
            boolean canConnect = false;
            boolean interrupted = false;
            while (System.currentTimeMillis() - start <= CONNECT_TIMEOUT && !canConnect && !interrupted
                    && !monitor.isCanceled() && !launch.isTerminated()) {
                try {
                    Socket socket = new Socket(URLBuilder.getHost(), port);
                    socket.close();
                    canConnect = true;
                } catch (Exception e) {
                    // http service not yet started - wait a bit
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException ie) {
                        interrupted = true;
                    }
                }
            }
        } finally {
            subMonitor.done();
        }
    }

    @Override
    protected boolean saveBeforeLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor)
            throws CoreException {
        if (isHeadless(configuration)) {
            return true;
        }
        return super.saveBeforeLaunch(configuration, mode, monitor);
    }

    @Override
    public boolean finalLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor)
            throws CoreException {
        if (isHeadless(configuration)) {
            return true;
        }
        return super.finalLaunchCheck(configuration, mode, monitor);
    }

    @Override
    public String[] getClasspath(ILaunchConfiguration configuration) throws CoreException {
        String[] classpath = constructClasspath(configuration);
        if (classpath == null) {
            String message = PDEMessages.WorkbenchLauncherConfigurationDelegate_noStartup;
            throw new CoreException(LauncherUtils.createErrorStatus(message));
        }

        return classpath;

    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private String[] constructClasspath(ILaunchConfiguration configuration) throws CoreException {
        CachedInfo info = LaunchInfoCache.getInfo(configuration);
        ITargetPlatformHelper target = (ITargetPlatformHelper) info.target;

        String jarPath = target.getEquinoxStartupPath(IPDEBuildConstants.BUNDLE_EQUINOX_LAUNCHER);

        if (jarPath == null)
            return null;

        ArrayList entries = new ArrayList();
        entries.add(jarPath);

        String bootstrap = configuration.getAttribute(IPDELauncherConstants.BOOTSTRAP_ENTRIES, ""); //$NON-NLS-1$
        StringTokenizer tok = new StringTokenizer(getSubstitutedString(bootstrap), ","); //$NON-NLS-1$
        while (tok.hasMoreTokens())
            entries.add(tok.nextToken().trim());
        return (String[]) entries.toArray(new String[entries.size()]);

    }

    private static String getSubstitutedString(String text) throws CoreException {
        if (text == null)
            return ""; //$NON-NLS-1$
        IStringVariableManager mgr = VariablesPlugin.getDefault().getStringVariableManager();
        return mgr.performStringSubstitution(text);
    }

    @Override
    public void clear(ILaunchConfiguration configuration, IProgressMonitor monitor) throws CoreException {
        clearDataLocation(configuration, monitor);
        super.clear(configuration, monitor);
    }

    private static boolean isHeadless(ILaunchConfiguration configuration) throws CoreException {
        return configuration.getAttribute(IQ7Launch.ATTR_HEADLESS_LAUNCH, false);
    }

    private void clearDataLocation(ILaunchConfiguration configuration, IProgressMonitor monitor)
            throws CoreException {
        String resolvedDataLocation = getResolvedDataLoacation();
        boolean isCleared = LauncherUtils.clearWorkspace(configuration, resolvedDataLocation, monitor);
        if (!isCleared) {
            throw new CoreException(Status.CANCEL_STATUS);
        }
    }

    private void registerBrowserOpener() {
        final String jobTaskName = "Starting client application";
        Job job = new Job(jobTaskName) {
            @Override
            protected IStatus run(IProgressMonitor monitor) {
                String taskName = jobTaskName;
                monitor.beginTask(taskName, 2);
                try {
                    waitForHttpService(monitor);
                    monitor.worked(1);
                    if (!launch.isTerminated()) {
                        openBrowser(monitor);
                    }
                } finally {
                    monitor.done();
                }
                return Status.OK_STATUS;
            }
        };
        job.schedule();
    }

    private void openBrowser(IProgressMonitor monitor) {
        SubMonitor subMonitor = SubMonitor.convert(monitor, 1);
        subMonitor.beginTask("Starting client application", IProgressMonitor.UNKNOWN);
        try {
            URL url = null;
            try {
                url = getUrl();
                browser.launch(url, config);
            } catch (CoreException e) {
                String msg = MessageFormat.format("Failed to open browser for URL ''{0}''.", new Object[] { url });
                Activator.getDefault().errorLog(msg, e);
            }
        } finally {
            subMonitor.done();
        }
    }

    private static boolean updateJVM(ILaunchConfiguration configuration, OSArchitecture architecture,
            ITargetPlatformHelper target) throws CoreException {
        IVMInstall jvmInstall = null;
        OSArchitecture jvmArch = OSArchitecture.Unknown;
        IVMInstallType[] types = JavaRuntime.getVMInstallTypes();
        boolean haveArch = false;
        for (IVMInstallType ivmInstallType : types) {
            IVMInstall[] installs = ivmInstallType.getVMInstalls();
            for (IVMInstall ivmInstall : installs) {
                jvmArch = JDTUtils.detect(ivmInstall);
                if (jvmArch.equals(architecture)
                        || (jvmArch.equals(OSArchitecture.x86_64) && JDTUtils.canRun32bit(ivmInstall))) {
                    jvmInstall = ivmInstall;
                    haveArch = true;
                    break;
                }
            }
        }
        if (haveArch) {
            ILaunchConfigurationWorkingCopy workingCopy = configuration.getWorkingCopy();

            String vmArgs = workingCopy.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS,
                    Q7LaunchDelegateUtils.getJoinedVMArgs(target, null));

            OSArchitecture configArch;
            String archAttrValue = configuration.getAttribute(Q7LaunchingCommon.ATTR_ARCH, "");
            if (archAttrValue.isEmpty())
                configArch = null;
            else
                configArch = OSArchitecture.valueOf(archAttrValue);

            OSArchitecture autArch = configArch == null ? target.detectArchitecture(true, null) : configArch;

            // there is no -d32 on Windows
            if (!autArch.equals(jvmArch) && Platform.getOS().equals(Platform.OS_MACOSX)) {
                if (vmArgs != null && !vmArgs.contains(ATTR_D32)) {
                    vmArgs += " " + ATTR_D32;
                } else {
                    vmArgs = ATTR_D32;
                }
            }
            if (vmArgs != null && vmArgs.length() > 0) {
                vmArgs = UpdateVMArgs.updateAttr(vmArgs);
                workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, vmArgs);
            }

            workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_JRE_CONTAINER_PATH,
                    String.format("org.eclipse.jdt.launching.JRE_CONTAINER/%s/%s",
                            jvmInstall.getVMInstallType().getId(), jvmInstall.getName()));

            String programArgs = workingCopy.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,
                    LaunchArgumentsHelper.getInitialProgramArguments().trim());
            if (programArgs.contains("${target.arch}")) {
                programArgs = programArgs.replace("${target.arch}", autArch.name());
            } else {
                if (programArgs.contains("-arch")) {
                    int pos = programArgs.indexOf("-arch ") + 6;
                    int len = 6;
                    int pos2 = programArgs.indexOf("x86_64", pos);
                    if (pos2 == -1) {
                        len = 3;
                        pos2 = programArgs.indexOf("x86", pos);
                    }
                    if (pos2 != -1) {
                        programArgs = programArgs.substring(0, pos) + autArch.name()
                                + programArgs.substring(pos2 + len, programArgs.length());
                    }
                } else {
                    programArgs = programArgs + " -arch " + autArch.name();
                }
            }
            if (programArgs.length() > 0) {
                workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, programArgs);
            }
            workingCopy.doSave();
            return true;
        }
        return false;
    }

    private static final String ATTR_D32 = "-d32";
}