Java tutorial
/******************************************************************************* * /******************************************************************************* * * 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"; }