blob: 3bbd85028fa6d5ddead272f87b31a4ffda696cfe [file] [log] [blame]
/*******************************************************************************
* /*******************************************************************************
* * 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(),
target.getTarget(), 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";
}