blob: 300a2307ae6374525a3d667eb14b8497c3d6c435 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2019 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.internal.target;
import static com.google.common.base.Charsets.UTF_8;
import static java.util.Collections.emptyList;
import static org.eclipse.rcptt.internal.launching.ext.Q7ExtLaunchingPlugin.PLUGIN_ID;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
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.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.emf.common.util.EList;
import org.eclipse.equinox.frameworkadmin.BundleInfo;
import org.eclipse.equinox.internal.launcher.Constants;
import org.eclipse.equinox.internal.simpleconfigurator.utils.SimpleConfiguratorUtils;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository;
import org.eclipse.equinox.p2.repository.artifact.IFileArtifactRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
import org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager;
import org.eclipse.osgi.service.resolver.ResolverError;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.target.ITargetDefinition;
import org.eclipse.pde.core.target.ITargetLocation;
import org.eclipse.pde.core.target.ITargetPlatformService;
import org.eclipse.pde.core.target.TargetBundle;
import org.eclipse.pde.internal.core.PDECore;
import org.eclipse.pde.internal.core.PDEExtensionRegistry;
import org.eclipse.pde.internal.core.PDEState;
import org.eclipse.pde.internal.core.target.IUBundleContainer;
import org.eclipse.pde.internal.core.target.P2TargetUtils;
import org.eclipse.pde.internal.core.target.ProfileBundleContainer;
import org.eclipse.pde.internal.launching.launcher.LaunchValidationOperation;
import org.eclipse.rcptt.internal.launching.Q7LaunchingPlugin;
import org.eclipse.rcptt.internal.launching.ext.AJConstants;
import org.eclipse.rcptt.internal.launching.ext.OSArchitecture;
import org.eclipse.rcptt.internal.launching.ext.Q7ExtLaunchingPlugin;
import org.eclipse.rcptt.launching.ext.AUTInformation;
import org.eclipse.rcptt.launching.ext.OriginalOrderProperties;
import org.eclipse.rcptt.launching.ext.Q7LaunchDelegateUtils;
import org.eclipse.rcptt.launching.injection.Directory;
import org.eclipse.rcptt.launching.injection.Entry;
import org.eclipse.rcptt.launching.injection.InjectionConfiguration;
import org.eclipse.rcptt.launching.injection.UpdateSite;
import org.eclipse.rcptt.launching.internal.target.Q7Target.AutInstall;
import org.eclipse.rcptt.launching.p2utils.P2Utils;
import org.eclipse.rcptt.launching.target.ITargetPlatformHelper;
import org.eclipse.rcptt.launching.target.TargetPlatformManager;
import org.eclipse.rcptt.util.FileUtil;
import org.osgi.framework.Version;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import com.google.common.io.Files;
@SuppressWarnings("restriction")
public class TargetPlatformHelper implements ITargetPlatformHelper {
private static final boolean DEBUG = "true"
.equals(Platform.getDebugOption("org.eclipse.rcptt.launching.ext/debug"));
private static final boolean DEBUG_BUNDLES = "true"
.equals(Platform.getDebugOption("org.eclipse.rcptt.launching.ext/debug/bundles"));
public static final String IDE_APPLICATION = "org.eclipse.ui.ide.workbench";
public static final String APPLICATION_PROPERTY = "eclipse.application"; //$NON-NLS-1$
public static final String PRODUCT_PROPERTY = "eclipse.product"; //$NON-NLS-1$
private static final String ID_PROPERTY = "id"; //$NON-NLS-1$
private static final String OSGI_BUNDLES = "osgi.bundles";
public static final String SIMPLECONFIGURATOR = "org.eclipse.equinox.simpleconfigurator"; //$NON-NLS-1$
private static final String SC_BUNDLES_PATH = "configuration/org.eclipse.equinox.simpleconfigurator/bundles.info"; //$NON-NLS-1$
private IStatus status = Status.OK_STATUS;
private final ITargetDefinition target;
private final ArrayList<ITargetLocation> extra = new ArrayList<ITargetLocation>();
private IPluginModelBase[] models;
private PDEExtensionRegistry registry;
private Q7Target q7target = new Q7Target();
public TargetPlatformHelper(ITargetDefinition target) {
Preconditions.checkNotNull(target);
this.target = target;
initialize();
}
public Q7Target getQ7Target() {
return q7target;
}
public String getUserArea() {
final AutInstall install = getAutInstall();
if (install == null) {
return null;
}
return install.userArea;
}
@Deprecated
/** Use getStatus().isOK() instead */
public boolean isValid() {
return getStatus().isOK();
}
public boolean isResolved() {
if (target != null) {
return target.isResolved();
}
return false;
}
public boolean isInstanceContainerValid() {
return getInstanceContainer() != null
&& getInstanceContainer().getStatus().isOK();
}
public IStatus getStatus() {
if (status == null) {
return new Status(IStatus.ERROR, PLUGIN_ID, "Target platform is unset");
}
return status;
}
@Deprecated
public String getErrorMessage() {
return getNonMultiStatusMessage(getStatus());
}
public String getWarningMessage() {
if (target != null) {
IStatus bundleStatus = getBundleWarningStatus();
return getNonMultiStatusMessage(bundleStatus);
}
return null;
}
public IStatus getBundleStatus() {
ITargetLocation[] containers = getBundleContainers();
if (containers != null) {
// Check if the containers have any resolution problems
MultiStatus result = new MultiStatus(
PDECore.PLUGIN_ID,
0,
org.eclipse.pde.internal.core.target.Messages.TargetDefinition_5,
null);
for (int i = 0; i < containers.length; i++) {
ITargetLocation container = containers[i];
IStatus containerStatus = container.getStatus();
if (containerStatus != null && !containerStatus.isOK()) {
result.add(containerStatus);
}
}
if (!result.isOK()) {
return result;
}
// Check if any of the included bundles have problems
// build status from bundle list
TargetBundle[] bundles = target.getBundles();
for (int i = 0; i < bundles.length; i++) {
TargetBundle bundle = bundles[i];
if (!bundle.getStatus().isOK()) {
BundleInfo info = bundle.getBundleInfo();
URI uri = info.getLocation();
if (uri != null) {
File file = new File(uri);
if (!file.exists()) {
reportUnexistingFile(info);
continue;
}
}
result.add(bundle.getStatus());
}
}
if (result.isOK()) {
// Return generic ok status instead of problem multi-status with
// no children
return Status.OK_STATUS;
}
return result;
}
return Status.OK_STATUS;
}
private void reportUnexistingFile(BundleInfo info) {
// Skip problem of nonexistent file.
Q7LaunchingPlugin.log(Q7LaunchingPlugin.createStatus(IStatus.WARNING,
"Skip nonexistent bundle: " + info.getSymbolicName()
+ ", then resolve configuration.",
null));
}
public IStatus getBundleWarningStatus() {
ITargetLocation[] containers = getBundleContainers();
if (containers != null) {
// Check if the containers have any resolution problems
MultiStatus result = new MultiStatus(
PDECore.PLUGIN_ID,
0,
org.eclipse.pde.internal.core.target.Messages.TargetDefinition_5,
null);
// Check if any of the included bundles have problems
// build status from bundle list
TargetBundle[] bundles = target.getBundles();
for (int i = 0; i < bundles.length; i++) {
TargetBundle bundle = bundles[i];
IStatus status = bundle.getStatus();
if (!status.isOK()) {
BundleInfo info = bundle.getBundleInfo();
URI uri = info.getLocation();
if (uri != null) {
File file = new File(uri);
if (!file.exists()) {
// Skip problem of nonexistent file.
IStatus st = new Status(IStatus.WARNING,
status.getPlugin(), status.getMessage(),
status.getException());
result.add(st);
}
}
}
}
if (result.isOK()) {
// Return generic ok status instead of problem multi-status with
// no children
return Status.OK_STATUS;
}
return result;
}
return Status.OK_STATUS;
}
private String getNonMultiStatusMessage(IStatus st) {
if (st != null && st.isMultiStatus()) {
StringBuilder buf = new StringBuilder();
IStatus[] children = st.getChildren();
for (IStatus iStatus : children) {
if (iStatus.isMultiStatus()) {
String msg = getNonMultiStatusMessage(iStatus);
if (msg != null) {
buf.append(msg).append('\n');
}
}
if (!iStatus.isOK()) {
buf.append(iStatus.getMessage()).append('\n');
}
}
return buf.toString();
}
return st == null ? "" : st.getMessage();
}
private void initialize() {
extra.clear();
q7target = new Q7Target();
if (this.target != null && this.target.getTargetLocations() != null) {
ITargetLocation[] containers = this.target.getTargetLocations();
for (ITargetLocation iUBundleContainer : containers) {
if (iUBundleContainer instanceof ProfileBundleContainer) {
getQ7Target().setInstall(iUBundleContainer);
}
extra.add(iUBundleContainer);
}
}
}
public void setTargetName(String name) {
if (target != null) {
target.setName(name);
}
}
public String getName() {
if (target != null) {
return target.getName();
}
return "";
}
public void save() throws CoreException {
if (!getStatus().isOK())
throw new CoreException(getStatus());
// Remove previous target platforms with same name.
TargetPlatformManager.deleteTargetPlatform(target.getName());
try {
ITargetPlatformService service = PDEHelper.getTargetService();
service.saveTargetDefinition(target);
} catch (CoreException e) {
Q7ExtLaunchingPlugin.getDefault().log(e);
}
}
public String getTargetPlatformProfilePath() {
ProfileBundleContainer container = (ProfileBundleContainer) getInstanceContainer();
if (container == null) {
return "";
}
try {
return container.getLocation(true).toString();
} catch (CoreException e) {
throw new RuntimeException(e);
}
}
public void delete() {
try {
if (target != null && target.getHandle() != null) {
PDEHelper.getTargetService().deleteTarget(target.getHandle());
}
} catch (CoreException e) {
Q7ExtLaunchingPlugin.getDefault().log(e);
}
}
public ITargetDefinition getTarget() {
return target;
}
public void update() {
List<ITargetLocation> newContainers = new ArrayList<ITargetLocation>();
newContainers.addAll(Arrays.asList(target.getTargetLocations()));
if (extra != null) {
newContainers.addAll(extra);
}
target.setTargetLocations(newContainers
.toArray(new ITargetLocation[newContainers.size()]));
models = null;
registry = null;
}
private IPluginModelBase[] getTargetModels() {
calcModels();
return models;
}
@Override
public IPluginModelBase getWeavingHook() {
calcModels();
return weavingHook;
}
private void calcModels() {
if (models == null) {
List<IPluginModelBase> bundles = sumBundles();
weavingHook = filterHooks(bundles);
models = bundles.toArray(new IPluginModelBase[0]);
}
}
private List<IPluginModelBase> sumBundles() {
TargetBundle[] bundles = getTarget().getAllBundles();
if (bundles == null) {
return new ArrayList<IPluginModelBase>();
}
List<URI> uris = new ArrayList<URI>();
for (TargetBundle bundle : bundles) {
uris.add(bundle.getBundleInfo().getLocation());
}
PDEState state = new PDEState(uris.toArray(new URI[uris
.size()]), true, true, new NullProgressMonitor());
final List<IPluginModelBase> targetModels = new ArrayList<IPluginModelBase>(Arrays.asList(state
.getTargetModels()));
if (DEBUG_BUNDLES) {
final List<String> targetModelsLocations = new ArrayList<String>();
for (final IPluginModelBase model : targetModels) {
targetModelsLocations.add(model.getInstallLocation());
}
debug("Bundles: " + targetModelsLocations);
}
return targetModels;
}
private IPluginModelBase filterHooks(List<IPluginModelBase> models) {
List<IPluginModelBase> hooks = new ArrayList<IPluginModelBase>();
for (IPluginModelBase model : models) {
String name = model.getBundleDescription().getSymbolicName();
if (Objects.equal(name, AJConstants.HOOK)) {
hooks.add(model);
}
}
switch (hooks.size()) {
case 0:
// no weaving hook
return null;
case 1:
// one weaving hook, nothing to filter
return hooks.get(0);
default:
// find a hook with the latest version, remove other hooks
IPluginModelBase maxHook = hooks.get(0);
for (int i = 1; i < hooks.size(); i++) {
IPluginModelBase hook = hooks.get(i);
if (hook.getBundleDescription().getVersion()
.compareTo(maxHook.getBundleDescription().getVersion()) > 0) {
maxHook = hook;
}
}
hooks.remove(maxHook);
models.removeAll(hooks);
return maxHook;
}
}
private IPluginModelBase weavingHook;
@SuppressWarnings({ "rawtypes", "unchecked" })
private IStatus validateBundles(IProgressMonitor monitor) {
LaunchValidationOperation validation = new LaunchValidationOperation(
null) {
@Override
protected IPluginModelBase[] getModels() throws CoreException {
return getTargetModels();
}
@Override
protected IExecutionEnvironment[] getMatchingEnvironments()
throws CoreException {
IExecutionEnvironmentsManager manager = JavaRuntime
.getExecutionEnvironmentsManager();
IExecutionEnvironment[] envs = manager
.getExecutionEnvironments();
return envs;
}
};
try {
StringBuilder b = new StringBuilder();
validation.run(monitor);
Map input = validation.getInput();
Set<Map.Entry> entrySet = input.entrySet();
for (Map.Entry e : entrySet) {
Object value = e.getKey();
if (value instanceof ResolverError) {
b.append(value.toString()).append("\n");
}
}
if (b.length() > 0) {
return new Status(IStatus.ERROR, PLUGIN_ID, "Bundle validation failed: " + b.toString());
}
} catch (CoreException e) {
Q7ExtLaunchingPlugin.getDefault().log(e);
return status = e.getStatus();
} catch (OperationCanceledException e) {
return status = Status.CANCEL_STATUS;
}
return status = Status.OK_STATUS;
}
public String[] getProducts() {
if (!isValid()) {
return new String[0];
}
PDEExtensionRegistry reg = getRegistry();
Set<String> result = new TreeSet<String>();
IExtension[] extensions = reg.findExtensions("org.eclipse.core.runtime.products", false); //$NON-NLS-1$
for (int i = 0; i < extensions.length; i++) {
IConfigurationElement[] elements = extensions[i]
.getConfigurationElements();
if (elements.length != 1)
continue;
if (!"product".equals(elements[0].getName())) //$NON-NLS-1$
continue;
String id = extensions[i].getUniqueIdentifier();
if (id != null && id.trim().length() > 0)
result.add(id);
}
return result.toArray(new String[result.size()]);
}
public String[] getApplications() {
if (!isValid()) {
return new String[0];
}
PDEExtensionRegistry reg = getRegistry();
Set<String> result = new TreeSet<String>();
IExtension[] extensions = reg.findExtensions("org.eclipse.core.runtime.applications", false); //$NON-NLS-1$
for (int i = 0; i < extensions.length; i++) {
String id = extensions[i].getUniqueIdentifier();
IConfigurationElement[] elements = extensions[i]
.getConfigurationElements();
if (elements.length != 1)
continue;
String visiblity = elements[0].getAttribute("visible"); //$NON-NLS-1$
boolean visible = visiblity == null ? true
: Boolean.valueOf(visiblity).booleanValue();
if (id != null && visible) {
result.add(id);
}
}
// result.add(IDE_APPLICATION); //$NON-NLS-1$
return result.toArray(new String[result.size()]);
}
private PDEExtensionRegistry getRegistry() {
if (registry == null) {
registry = new PDEExtensionRegistry(getTargetModels());
}
return registry;
}
public IStatus resolve(IProgressMonitor monitor) {
ITargetDefinition target = getTarget();
if (target != null) {
SubMonitor m = SubMonitor.convert(monitor, "Resolving " + getName(), 2);
try {
status = target.resolve(m.newChild(1, SubMonitor.SUPPRESS_NONE));
if (!status.isOK())
return status;
status = validateBundles(m.newChild(1, SubMonitor.SUPPRESS_NONE));
if (!status.isOK())
return status;
return status = getBundleStatus();
} finally {
m.done();
}
}
return status = Status.CANCEL_STATUS;
}
AutInstall getAutInstall() {
final Q7Target target = getQ7Target();
if (target == null) {
return null;
}
return target.getInstall();
}
public OriginalOrderProperties getConfigIniProperties() {
return getAutInstall().getConfig();
}
protected String getEclipseProductFileProperty(String name) {
Properties props = getEclipseProductFileProperties();
return props == null ? null : props.getProperty(name);
}
public Properties getEclipseProductFileProperties() {
File iniFile = new File(getTargetPlatformProfilePath(), ".eclipseproduct"); //$NON-NLS-1$
if (!iniFile.exists())
return null;
Properties pini = new Properties();
FileInputStream fis = null;
try {
fis = new FileInputStream(iniFile);
pini.load(fis);
fis.close();
return pini;
} catch (IOException e) {
Q7ExtLaunchingPlugin.getDefault().log(e);
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException e) {
Q7ExtLaunchingPlugin.getDefault().log(e);
}
}
return null;
}
public String getDefaultApplication() {
String app = getConfigIniProperty(APPLICATION_PROPERTY);
debug("Application from config.ini: " + app);
HashSet<String> apps = new HashSet<String>(
Arrays.asList(getApplications()));
debug("Valid applications: " + apps);
return isValidId(app, apps) ? app
: (isValidId(IDE_APPLICATION, apps) ? IDE_APPLICATION : null);
}
public String getBundlesList() {
String bundles = getConfigIniProperty(OSGI_BUNDLES);
return bundles == null ? org.eclipse.pde.internal.core.TargetPlatformHelper
.getDefaultBundleList()
: org.eclipse.pde.internal.core.TargetPlatformHelper
.stripPathInformation(bundles);
}
protected String getConfigIniProperty(String name) {
Properties config = getConfigIniProperties();
if (config == null) {
return null;
}
return config.getProperty(name);
}
protected boolean isValidId(String id, Set<String> available) {
return id == null ? false : available.contains(id);
}
public String getDefaultProduct() {
Set<String> values = new HashSet<String>(Arrays.asList(getProducts()));
debug("Valid products: " + values);
String product = null;
String productProperty = getConfigIniProperty(PRODUCT_PROPERTY);
if (isValidId(productProperty, values)) {
product = productProperty;
}
debug(PRODUCT_PROPERTY + " from config.ini: " + productProperty);
// Try to load .eclipseproduct file
productProperty = getEclipseProductFileProperty(ID_PROPERTY);
if (isValidId(productProperty, values)) {
product = productProperty;
}
debug(ID_PROPERTY + " from config.ini: " + productProperty);
// Try to load from application ini file
List<File> iniFiles = getAppIniFiles();
for (File file : iniFiles) {
productProperty = readProductFromIniFile(file);
if (isValidId(productProperty, values)) {
product = productProperty;
}
debug("Product from " + file + ": " + productProperty);
}
return product;
}
public ITargetLocation[] getBundleContainers() {
if (target == null) {
return new ITargetLocation[0];
}
ITargetLocation[] bundleContainers = target.getTargetLocations();
if (bundleContainers == null) {
return new ITargetLocation[0];
}
return bundleContainers;
}
// Repository for all update site injections
@SuppressWarnings("unused")
private IFileArtifactRepository repository;
public IStatus applyInjection(InjectionConfiguration configuration,
IProgressMonitor monitor) {
// remove the "host" from bundles, it is handled in a separate, special
// way
Iterables.removeAll(extra, Arrays.asList(getInstanceContainer()));
EList<Entry> entries = configuration.getEntries();
monitor.beginTask("Apply injection plugins", 20 + entries.size() * 20);
for (Entry entry : entries) {
SubProgressMonitor mon = new SubProgressMonitor(monitor, 20);
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
IStatus result = new Status(IStatus.ERROR, PLUGIN_ID, "Unknown injection type: "
+ entry.getClass().getName());
if (entry instanceof UpdateSite) {
result = processUpdateSite(mon, (UpdateSite) entry);
} else if (entry instanceof Directory) {
result = processDirectory((Directory) entry);
}
if (result.matches(IStatus.ERROR | IStatus.CANCEL)) {
return result;
}
}
update();
IStatus resolveStatus = resolve(monitor);
if (!resolveStatus.isOK()) {
return resolveStatus;
}
if (getWeavingHook() == null) {
return status = createError("No org.eclipse.weaving hook plugin");
}
try {
save();
} catch (CoreException e) {
return e.getStatus();
}
return Status.OK_STATUS;
}
private IStatus processDirectory(Directory entry) {
String path = entry.getPath();
MultiStatus rv = new MultiStatus(PLUGIN_ID, 0, "Processing " + path, null);
if (path.startsWith("platform:///")) {
// if path is platform uri, lets resolve it to file
try {
URL resolve = FileLocator.resolve(URI.create(path).toURL());
path = resolve.getPath();
} catch (MalformedURLException e) {
rv.add(new Status(IStatus.WARNING, PLUGIN_ID, e.getMessage(), e));
} catch (IOException e) {
rv.add(new Status(IStatus.WARNING, PLUGIN_ID, e.getMessage(), e));
}
}
ITargetLocation container = PDEHelper.getTargetService()
.newDirectoryLocation(path);
extra.add(container);
return Status.OK_STATUS;
}
private static final IStatus createError(String message) {
return createError(message, null);
}
private static final IStatus createError(String message, Throwable error) {
if (message == null && error != null) {
message = error.getMessage();
}
return new Status(IStatus.ERROR, PLUGIN_ID, message, error);
}
private IStatus processUpdateSite(IProgressMonitor monitor, UpdateSite site) {
try {
URI uri = URI.create(
Platform.getOS().equals(Platform.OS_WIN32) ? site.getUri().replace('\\', '/') : site.getUri());
IMetadataRepository repository = PDEHelper.safeLoadRepository(uri,
monitor);
IArtifactRepository artifactRepository = PDEHelper
.safeLoadArtifactRepository(uri, monitor);
if (repository == null || artifactRepository == null) {
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
return createError("Failed to load update site:" + uri);
}
List<IInstallableUnit> unitsToInstall = new ArrayList<IInstallableUnit>();
// Query for all entries and then choose required.
IQuery<IInstallableUnit> finalQuery = P2Utils.createQuery(site);
IQueryResult<IInstallableUnit> result = repository.query(finalQuery,
monitor);
Set<IInstallableUnit> availableUnits = result.toSet();
if (site.isAllUnits()) {
unitsToInstall.addAll(availableUnits);
} else {
P2Utils.expandFeatures(monitor, repository, availableUnits);
Set<String> unitIDs = P2Utils.mapUnitsToId(availableUnits);
Set<String> missingUnits = new HashSet<String>(site.getUnits());
missingUnits.removeAll(unitIDs);
if (!missingUnits.isEmpty()) { // Some units are not available
return createError("Few units are not available:"
+ Arrays.toString(missingUnits.toArray()));
}
unitsToInstall.addAll(availableUnits);
}
if (unitsToInstall.size() > 0) {
IInstallableUnit[] unitsAsArray = unitsToInstall
.toArray(new IInstallableUnit[unitsToInstall.size()]);
URI[] uriArray = new URI[] { uri };
ITargetLocation container = PDEHelper.getTargetService()
.newIULocation(unitsAsArray, uriArray,
IUBundleContainer.INCLUDE_ALL_ENVIRONMENTS);
extra.add(container);
}
// Lets mirror all required artifacts into bundle pool, since we don't
// really trust P2.
IFileArtifactRepository filesRepository = P2TargetUtils
.getBundlePool();
List<IInstallableUnit> toInstall = new ArrayList<IInstallableUnit>();
toInstall.addAll(unitsToInstall);
P2Utils.installUnits(monitor, artifactRepository, filesRepository,
toInstall, 10, null, false, P2Utils.getProvisioningAgent());
MultiStatus rv = new MultiStatus(PLUGIN_ID, 0, "Failed to install next units from repository: "
+ repository.getName(), null);
if (toInstall.size() > 0) {
// Not all plugins are installed.
for (IInstallableUnit u : toInstall) {
rv.add(createError(u.getId()));
}
return rv;
}
} catch (CoreException e) {
return e.getStatus();
}
return Status.OK_STATUS;
}
public Map<String, String> getIniEnvironment() {
List<File> iniFiles = getAppIniFiles();
Map<String, String> result = new HashMap<String, String>();
for (File file : iniFiles) {
Map<String, String> envs = readEnvironmentFromIniFile(file);
if (envs != null) {
result.putAll(envs);
}
}
return result;
}
public String getIniVMArgs() {
List<File> iniFiles = getAppIniFiles();
for (File file : iniFiles) {
String vmArgs = readVMArgsFromIniFile(file);
if (vmArgs != null) {
return vmArgs;
}
}
return null;
}
private List<File> getAppIniFiles() {
List<File> iniFiles = new ArrayList<File>();
if (getInstanceContainer() == null) {
return iniFiles;
}
File installDirectory = new File(getTargetPlatformProfilePath());
if (!installDirectory.exists()) {
return iniFiles;
}
if (Platform.getOS().equals(Platform.OS_MACOSX)) {
File[] listFiles = installDirectory.listFiles();
for (File file : listFiles) {
if (file.getName().contains(".app")) {
installDirectory = new File(file, "/Contents/MacOS");
break;
}
}
}
File eclipseIniFile = new File(installDirectory, "eclipse.ini"); //$NON-NLS-1$
if (eclipseIniFile.exists()) {
iniFiles.add(eclipseIniFile);
return iniFiles;
}
File[] list = installDirectory.listFiles();
if (list != null) {
for (File file : list) {
if (file.getName().endsWith(".ini")) {
iniFiles.add(file);
}
}
}
return iniFiles;
}
private String readProductFromIniFile(File eclipseIniFile) {
BufferedReader in = null;
if (eclipseIniFile.exists()) {
try {
in = new BufferedReader(new FileReader(eclipseIniFile));
String str;
while ((str = in.readLine()) != null) {
if (str.trim().equals("-product")) { //$NON-NLS-1$
String product = in.readLine();
if (product != null) {
return product.trim();
}
}
}
} catch (IOException e) {
Q7ExtLaunchingPlugin.getDefault().log(e);
} finally {
if (in != null)
try {
in.close();
} catch (IOException e) {
Q7ExtLaunchingPlugin.getDefault().log(e);
}
}
}
return null;
}
private String readLauncherLibraryFromIniFile(File eclipseIniFile) {
BufferedReader in = null;
try {
if (eclipseIniFile.exists()) {
in = new BufferedReader(new FileReader(eclipseIniFile));
String str;
while ((str = in.readLine()) != null) {
if (str.trim().equals("--launcher.library")) { //$NON-NLS-1$
String result = in.readLine();
if (result != null) {
return result.trim();
}
}
}
}
} catch (IOException e) {
Q7ExtLaunchingPlugin.getDefault().log(e);
} finally {
FileUtil.safeClose(in);
}
return null;
}
private static final String GTK_VERSION = "--launcher.GTK_version";
private static final String VMARGS = "-vmargs";
private static final String VM = "-vm";
private List<String> parseIniFile(File eclipseIni) {
if (eclipseIni == null || !eclipseIni.exists()) {
return emptyList();
}
List<String> result = new ArrayList<String>();
try {
for (String line : Files.readLines(eclipseIni, UTF_8)) {
line = line.trim();
if (line.length() > 0 && line.charAt(0) != '#') {
result.add(line);
}
}
} catch (IOException e) {
Q7ExtLaunchingPlugin.getDefault().log(e);
}
return result;
}
private String getVmArg(File eclipseIniFile) {
List<String> lines = parseIniFile(eclipseIniFile);
int vmIndex = lines.indexOf("-vm") + 1;
return vmIndex == 0 || vmIndex == lines.size() ? null
: lines.get(vmIndex);
}
public String getVmFromIniFile() {
for (File file : getAppIniFiles()) {
String result = getVmArg(file);
if (result != null) {
return result;
}
}
return null;
}
private Map<String, String> readEnvironmentFromIniFile(File eclipseIniFile) {
if (!eclipseIniFile.exists()) {
return null;
}
List<String> lines = parseIniFile(eclipseIniFile);
Map<String, String> envs = new HashMap<String, String>();
// mirror GTK_VERSION parameter processing
// from org.eclipse.equinox.executable.feature / library / eclipse.c
// see more:
// https://git.eclipse.org/r/plugins/gitiles/equinox/rt.equinox.framework/+/master/features/org.eclipse.equinox.executable.feature/library/eclipse.c
int gtkVersionIdx = lines.indexOf(GTK_VERSION);
if (gtkVersionIdx != -1 && Platform.getOS().equals(Platform.OS_LINUX)) {
String gtkVersion = lines.get(gtkVersionIdx + 1);
if ("2".equals(gtkVersion)) {
envs.put("SWT_GTK3", "0");
} else {
envs.put("SWT_GTK3", "1");
}
}
return envs;
}
private String readVMArgsFromIniFile(File eclipseIniFile) {
if (!eclipseIniFile.exists()) {
return null;
}
List<String> lines = parseIniFile(eclipseIniFile);
int vmargsIndex = lines.indexOf(VMARGS);
if (vmargsIndex == -1) {
return null;
}
lines = lines.subList(vmargsIndex + 1, lines.size());
int vmIndex = lines.indexOf(VM);
if (vmIndex != -1) {
lines.subList(vmIndex, Math.min(vmIndex + 2, lines.size())).clear();
}
if (lines.isEmpty()) {
return null;
}
removeUnsupportedVMArgs(lines);
return Q7LaunchDelegateUtils.joinCommandArgs(lines);
}
private static final String VMARG_ADD_MODULES = "--add-modules";
private static final String VMARG_PERMIT_ILLEGAL_ACCESS = "--permit-illegal-access";
private void removeUnsupportedVMArgs(List<String> lines) {
String[] javaVersions = getJavaVersions();
// remove args was added into .ini file to support java 9
// see more: https://bugs.eclipse.org/bugs/show_bug.cgi?id=493761
if ((getMajorVersion(javaVersions) == 1 && getMinorVersion(javaVersions) < 9)
|| getMajorVersion(javaVersions) < 9) {
Iterator<String> iterator = lines.iterator();
while (iterator.hasNext()) {
String line = iterator.next();
if (line.startsWith(VMARG_ADD_MODULES)
|| line.startsWith(VMARG_PERMIT_ILLEGAL_ACCESS)) {
iterator.remove();
}
}
}
}
private static String[] getJavaVersions() {
String javaVersion = System.getProperty("java.version");
return javaVersion.split("\\.|-"); // '.' and '-' are separators
}
private static int getMajorVersion(String[] versions) {
if (versions.length < 1) {
return 0;
}
try {
return Integer.valueOf(versions[0]);
} catch (NumberFormatException e) {
return 0;
}
}
private static int getMinorVersion(String[] versions) {
if (versions.length < 2) {
return 0;
}
try {
return Integer.valueOf(versions[1]);
} catch (NumberFormatException e) {
return 0;
}
}
public String getTemplateConfigLocation() {
File iniFile = new File(getTargetPlatformProfilePath(), "configuration/config.ini"); //$NON-NLS-1$
if (!iniFile.exists())
return null;
return iniFile.getAbsolutePath();
}
public OSArchitecture detectArchitecture(
boolean preferCurrentVmArchitecture, StringBuilder detectMsg) {
// http://stackoverflow.com/a/808314
final boolean isCurrentVm64 = System.getProperty("os.arch", "not null")
.contains("64");
boolean has32 = false;
boolean has64 = false;
String launcher64 = null;
String launcher32 = null;
List<File> iniFiles = getAppIniFiles();
IPath targetPlatformProfilePath = new Path(
getTargetPlatformProfilePath());
Set<String> availableLaunchers = new HashSet<String>();
String os = Platform.getOS();
for (File file : iniFiles) {
String launcherLibrary = readLauncherLibraryFromIniFile(file);
if (launcherLibrary != null && launcherLibrary.contains(os)) {
String configPath = new Path(file.getAbsolutePath())
.removeFirstSegments(
targetPlatformProfilePath.segmentCount())
.setDevice(null).toOSString();
if (launcherLibrary.contains("x86_64")) {
has64 = true;
launcher64 = "launcher library\n\t\"" + launcherLibrary
+ "\" specified in config file: " + configPath;
} else if (launcherLibrary.contains("x86")
|| launcherLibrary.contains("cocoa.macosx")) {
has32 = true;
launcher32 = "launcher library\n\t\"" + launcherLibrary
+ "\" specified in config file: " + configPath;
}
}
}
if (!has32 && !has64) {
TargetBundle[] bundles = target.getAllBundles();
for (TargetBundle b : bundles) {
BundleInfo info = b.getBundleInfo();
String name = info.getSymbolicName();
if (name != null && name.startsWith("org.eclipse.equinox.launcher")) {
URI location = info.getLocation();
if (location == null || location.getPath() == null) {
continue;
}
String pathString = new Path(info.getLocation().getPath())
.removeFirstSegments(targetPlatformProfilePath.segmentCount()).toOSString();
if (name.contains("x86_64")) {
if (name.contains(os)) {
has64 = true;
launcher64 = "Equinox launcher\n\t- " + pathString;
} else {
availableLaunchers.add("\t- " + pathString);
}
} else if (name.contains("x86")
|| name.contains("cocoa.macosx")) {
if (name.contains(os)) {
has32 = true;
launcher32 = "Equinox launcher\n\t- " + pathString;
} else {
availableLaunchers.add("\t- " + pathString);
}
}
}
}
}
if (has32 && !has64) {
if (detectMsg != null) {
detectMsg.append("32bit arch is selected because AUT uses "
+ launcher32);
}
return OSArchitecture.x86;
} else if (!has32 && has64) {
if (detectMsg != null) {
detectMsg.append("64bit arch is selected because AUT uses "
+ launcher64);
}
return OSArchitecture.x86_64;
} else if (preferCurrentVmArchitecture && has32 && has64) {
OSArchitecture result = isCurrentVm64 ? OSArchitecture.x86_64
: OSArchitecture.x86;
if (detectMsg != null && result.equals(OSArchitecture.x86)) {
detectMsg
.append("32bit arch is selected because\n- JVM is 32bit\n- AUT contains both launcher plugins\n\t-"
+ launcher32 + "\n\t-" + launcher64);
}
if (detectMsg != null && result.equals(OSArchitecture.x86_64)) {
detectMsg
.append("64bit arch is selected because\n- JVM is 64bit\n- AUT contains both launcher plugins\n\t-"
+ launcher32 + "\n\t-" + launcher64);
}
return result;
} else {
if (detectMsg != null) {
detectMsg
.append("Cannot find appropriate Equinox launcher library.\n");
if (availableLaunchers.size() > 0) {
detectMsg.append("Available launchers:\n");
for (String s : availableLaunchers) {
detectMsg.append(s).append("\n");
}
}
}
return OSArchitecture.Unknown;
}
}
private Map<String, String> getRunlevelsFromSimpleConfigurator() {
Map<String, String> result = new HashMap<String, String>();
if (getTargetPlatformProfilePath() == null) {
return result;
}
File infoFile = new File(getTargetPlatformProfilePath(),
SC_BUNDLES_PATH);
if (!infoFile.exists()) {
return result;
}
InputStream input = null;
try {
input = new FileInputStream(infoFile);
for (org.eclipse.equinox.internal.simpleconfigurator.utils.BundleInfo bi : (List<org.eclipse.equinox.internal.simpleconfigurator.utils.BundleInfo>) SimpleConfiguratorUtils
.readConfiguration(input, infoFile.toURI())) {
String name = bi.getSymbolicName();
if (name != null) {
result.put(name, String.format("%d:%b", bi.getStartLevel(), bi.isMarkedAsStarted()));
}
}
} catch (Throwable e) {
FileUtil.safeClose(input);
}
return result;
}
public Map<String, String> getRunlevelsMap() {
Map<String, String> result = new HashMap<String, String>();
String osgiBundles = getConfigIniProperty(OSGI_BUNDLES);
if (osgiBundles == null) {
return result;
}
if (osgiBundles.contains(SIMPLECONFIGURATOR)) {
return getRunlevelsFromSimpleConfigurator();
}
// AUT uses bundles specified in osgiBundlesProperty
StringTokenizer tokenizer = new StringTokenizer(osgiBundles, ","); //$NON-NLS-1$
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
int index = token.indexOf('@');
String id = index != -1 ? token.substring(0, index) : token;
String tk = token.substring(index + 1);
if (tk.indexOf(":") == -1) {
tk = tk + ":default";
}
result.put(id, tk);
}
return result;
}
public String getRuntimeVersion() {
if (target != null && target.isResolved()) {
String version = "";
Version runtimeBundle = getBundleVersion("org.eclipse.rcptt.tesla.swt");
if (runtimeBundle != null) {
version = runtimeBundle.toString();
if (runtimeBundle.getQualifier().equals("qualifier")) {
// This is for development
version = version + System.currentTimeMillis();
}
}
return version;
}
return "unknown";
}
private Version getBundleVersion(String name) {
if (target != null && target.isResolved()) {
ITargetLocation[] containers = target.getTargetLocations();
for (ITargetLocation iBundleContainer : containers) {
TargetBundle[] bundles = iBundleContainer.getBundles();
if (bundles != null) {
for (TargetBundle iResolvedBundle : bundles) {
BundleInfo info = iResolvedBundle.getBundleInfo();
if (Objects.equal(info.getSymbolicName(), name)) {
return new Version(info.getVersion());
}
}
}
if (iBundleContainer instanceof IUBundleContainer) {
IUBundleContainer ct = (IUBundleContainer) iBundleContainer;
try {
Field ids = IUBundleContainer.class
.getDeclaredField("fIds");
Field versions = IUBundleContainer.class
.getDeclaredField("fVersions");
ids.setAccessible(true);
versions.setAccessible(true);
String[] idsValue = (String[]) ids.get(ct);
org.eclipse.equinox.p2.metadata.Version[] versionsValue = (org.eclipse.equinox.p2.metadata.Version[]) versions
.get(ct);
for (int i = 0; i < idsValue.length; i++) {
String n = idsValue[i];
if (n != null && n.equals(name)) {
return new Version(versionsValue[i].toString());
}
}
} catch (Throwable e) {
Q7ExtLaunchingPlugin.status(
"Failed to check runtime version", e);
}
}
}
}
return null;
}
public String getEquinoxStartupPath(String packageName) {
IPluginModelBase[] targetModels = getTargetModels();
for (IPluginModelBase plugin : targetModels) {
if (plugin.getPluginBase().getId().equals(packageName)) {
String location = plugin.getInstallLocation();
if (new File(location).isFile()) {
return location;
}
}
}
return null;
}
ProfileBundleContainer getInstanceContainer() {
final AutInstall install = getAutInstall();
if (install == null) {
return null;
}
return install.container;
}
public void setBundleContainers(ITargetLocation[] containers) {
target.setTargetLocations(containers);
initialize();
}
@Override
public String toString() {
return (getName() == null ? "No name" : getName()) + " " + getTargetPlatformProfilePath();
}
@Override
public Map<String, org.eclipse.equinox.p2.metadata.Version> getVersions() throws CoreException {
if (!getStatus().isOK())
throw new CoreException(getStatus());
return AUTInformation.getInformationMap(target);
}
private static final String PROP_CONFIG_AREA = "osgi.configuration.area"; //$NON-NLS-1$
private static final String PROP_SHARED_CONFIG_AREA = "osgi.sharedConfiguration.area"; //$NON-NLS-1$
private static final String PROP_CONFIG_CASCADED = "osgi.configuration.cascaded"; //$NON-NLS-1$
// for variable substitution
public static final String VARIABLE_DELIM_STRING = "$"; //$NON-NLS-1$
public static final char VARIABLE_DELIM_CHAR = '$';
private static final String ECLIPSE = "eclipse"; //$NON-NLS-1$
private static final String PRODUCT_SITE_MARKER = ".eclipseproduct"; //$NON-NLS-1$
private static final String PRODUCT_SITE_ID = "id"; //$NON-NLS-1$
private static final String PRODUCT_SITE_VERSION = "version"; //$NON-NLS-1$
private static final String PROP_OS = "osgi.os"; //$NON-NLS-1$
private static final String PROP_WS = "osgi.ws"; //$NON-NLS-1$
private static final String PROP_ARCH = "osgi.arch"; //$NON-NLS-1$
private static final String CONFIG_DIR = "configuration/"; //$NON-NLS-1$
private static final String CONFIG_FILE = "config.ini"; //$NON-NLS-1$
private static final String NONE = "@none"; //$NON-NLS-1$
private static final String NO_DEFAULT = "@noDefault"; //$NON-NLS-1$
private static final String USER_HOME = "@user.home"; //$NON-NLS-1$
private static final String USER_DIR = "@user.dir"; //$NON-NLS-1$
private static final String PROP_USER_HOME = "user.home"; //$NON-NLS-1$
private static final String PROP_USER_DIR = "user.dir"; //$NON-NLS-1$
private static final String FILE_SCHEME = "file:"; //$NON-NLS-1$
public static OriginalOrderProperties processConfiguration(AutInstall autInstall) {
URL baseConfigurationLocation = null;
OriginalOrderProperties baseConfiguration = null;
String location = null;
if (baseConfigurationLocation == null)
try {
baseConfigurationLocation = new URL(autInstall.getInstallLocationURL(), CONFIG_DIR);
} catch (MalformedURLException e) {
// leave baseConfigurationLocation null
}
baseConfiguration = loadConfiguration(baseConfigurationLocation);
if (baseConfiguration != null) {
// if the base sets the install area then use that value if the property. We know the
// property is not already set.
location = baseConfiguration.getProperty(PROP_CONFIG_AREA);
}
// Now we know where the base configuration is supposed to be. Go ahead and load
// it and merge into the System properties. Then, if cascaded, read the parent configuration.
// Note that in a cascaded situation, the user configuration may be ignored if the parent
// configuration has changed since the user configuration has been written.
// Note that the parent may or may not be the same parent as we read above since the
// base can define its parent. The first parent we read was either defined by the user
// on the command line or was the one in the install dir.
// if the config or parent we are about to read is the same as the base config we read above,
// just reuse the base
OriginalOrderProperties configuration = baseConfiguration;
final URL configUrl = getConfigurationLocation(location, autInstall.getInstallLocation());
if (configuration == null || !configUrl.equals(baseConfigurationLocation))
configuration = loadConfiguration(configUrl);
if (configuration == null) {
Q7ExtLaunchingPlugin.getDefault().info("File config.ini from folder \"" + configUrl + "\" was not read");
return baseConfiguration;
}
String configurationArea = configUrl.getFile();
int index = configurationArea.lastIndexOf("/");
if (index == configurationArea.length() - 1) {
configurationArea = configurationArea.substring(0, index);
index = configurationArea.lastIndexOf("/");
}
autInstall.userArea = configurationArea.substring(0, index + 1);
if ("false".equalsIgnoreCase(configuration.getProperty(PROP_CONFIG_CASCADED))) { //$NON-NLS-1$
configuration.remove(PROP_SHARED_CONFIG_AREA);
return configuration;
} else {
URL sharedConfigURL = buildLocation(configuration.getProperty(PROP_SHARED_CONFIG_AREA), null, "", //$NON-NLS-1$
autInstall.getInstallLocation().getAbsolutePath());
if (sharedConfigURL == null)
try {
// there is no shared config value so compute one
sharedConfigURL = new URL(autInstall.getInstallLocationURL(), CONFIG_DIR);
} catch (MalformedURLException e) {
// leave sharedConfigurationLocation null
}
// if the parent location is different from the config location, read it too.
if (sharedConfigURL != null) {
if (sharedConfigURL.equals(configUrl)) {
// After all we are not in a shared configuration setup.
// - remove the property to show that we do not have a parent
// - merge configuration with the system properties
return configuration;
} else {
// if the parent we are about to read is the same as the base config we read above,
// just reuse the base
OriginalOrderProperties sharedConfiguration = baseConfiguration;
if (!sharedConfigURL.equals(baseConfigurationLocation)) {
sharedConfiguration = loadConfiguration(sharedConfigURL);
}
configuration.remove(PROP_SHARED_CONFIG_AREA);
return mergeProperties(sharedConfiguration, configuration);
}
}
}
return null;
}
private static OriginalOrderProperties loadConfiguration(URL url) {
OriginalOrderProperties result = null;
try {
url = new URL(url, CONFIG_FILE);
} catch (MalformedURLException e) {
return result;
}
try {
if (url != null)
result = OriginalOrderProperties.load(url);
} catch (IOException e) {
}
return substituteVars(result);
}
private static OriginalOrderProperties substituteVars(OriginalOrderProperties result) {
if (result == null) {
// nothing todo.
return null;
}
for (Enumeration<?> eKeys = result.keys(); eKeys.hasMoreElements();) {
Object key = eKeys.nextElement();
if (key instanceof String) {
String value = result.getProperty((String) key);
if (value != null)
result.put(key, substituteVars(value));
}
}
return result;
}
private static String substituteVars(String path) {
StringBuffer buf = new StringBuffer(path.length());
StringTokenizer st = new StringTokenizer(path, VARIABLE_DELIM_STRING, true);
boolean varStarted = false; // indicates we are processing a var subtitute
String var = null; // the current var key
while (st.hasMoreElements()) {
String tok = st.nextToken();
if (VARIABLE_DELIM_STRING.equals(tok)) {
if (!varStarted) {
varStarted = true; // we found the start of a var
var = ""; //$NON-NLS-1$
} else {
// we have found the end of a var
String prop = null;
// get the value of the var from system properties
if (var != null && var.length() > 0)
prop = System.getProperty(var);
if (prop == null) {
try {
// try using the System.getenv method if it exists (bug 126921)
Method getenv = System.class.getMethod("getenv", new Class[] { String.class }); //$NON-NLS-1$
prop = (String) getenv.invoke(null, new Object[] { var });
} catch (Throwable t) {
// do nothing;
// on 1.4 VMs this throws an error
// on J2ME this method does not exist
}
}
if (prop != null) {
// found a value; use it
buf.append(prop);
} else {
// could not find a value append the var; keep delemiters
buf.append(VARIABLE_DELIM_CHAR);
buf.append(var == null ? "" : var); //$NON-NLS-1$
buf.append(VARIABLE_DELIM_CHAR);
}
varStarted = false;
var = null;
}
} else {
if (!varStarted)
buf.append(tok); // the token is not part of a var
else
var = tok; // the token is the var key; save the key to process when we find the end token
}
}
if (var != null)
// found a case of $var at the end of the path with no trailing $; just append it as is.
buf.append(VARIABLE_DELIM_CHAR).append(var);
return buf.toString();
}
private static URL getConfigurationLocation(String configurationArea, File installLocation) {
URL configurationLocation = buildLocation(configurationArea, null, "", installLocation.getAbsolutePath()); //$NON-NLS-1$
if (configurationLocation == null)
configurationLocation = buildURL(computeDefaultConfigurationLocation(installLocation), true,
installLocation.getAbsolutePath());
return configurationLocation;
}
private static URL buildLocation(String location, URL defaultLocation, String userDefaultAppendage,
String installArea) {
URL result = null;
// if the instance location is not set, predict where the workspace will be and
// put the instance area inside the workspace meta area.
if (location == null)
result = defaultLocation;
else if (location.equalsIgnoreCase(NONE))
return null;
else if (location.equalsIgnoreCase(NO_DEFAULT))
result = buildURL(location, true, installArea);
else {
if (location.startsWith(USER_HOME)) {
String base = substituteVar(location, USER_HOME, PROP_USER_HOME);
location = new File(base, userDefaultAppendage).getAbsolutePath();
} else if (location.startsWith(USER_DIR)) {
String base = substituteVar(location, USER_DIR, PROP_USER_DIR);
location = new File(base, userDefaultAppendage).getAbsolutePath();
}
result = buildURL(location, true, installArea);
}
return result;
}
private static String substituteVar(String source, String var, String prop) {
String value = System.getProperty(prop, ""); //$NON-NLS-1$
return value + source.substring(var.length());
}
public static URL buildURL(String spec, boolean trailingSlash, String installArea) {
if (spec == null)
return null;
if (File.separatorChar == '\\')
spec = spec.trim();
boolean isFile = spec.startsWith(FILE_SCHEME);
try {
if (isFile) {
File toAdjust = new File(spec.substring(5));
toAdjust = resolveFile(toAdjust, installArea);
if (toAdjust.isDirectory())
return adjustTrailingSlash(toAdjust.toURI().toURL(), trailingSlash);
return toAdjust.toURI().toURL();
}
return new URL(spec);
} catch (MalformedURLException e) {
// if we failed and it is a file spec, there is nothing more we can do
// otherwise, try to make the spec into a file URL.
if (isFile)
return null;
try {
File toAdjust = new File(spec);
if (toAdjust.isDirectory())
return adjustTrailingSlash(toAdjust.toURI().toURL(), trailingSlash);
return toAdjust.toURI().toURL();
} catch (MalformedURLException e1) {
return null;
}
}
}
private static File resolveFile(File toAdjust, String installArea) {
if (!toAdjust.isAbsolute()) {
if (installArea != null) {
if (installArea.startsWith(FILE_SCHEME))
toAdjust = new File(installArea.substring(5), toAdjust.getPath());
else if (new File(installArea).exists())
toAdjust = new File(installArea, toAdjust.getPath());
}
}
return toAdjust;
}
private static URL adjustTrailingSlash(URL url, boolean trailingSlash) throws MalformedURLException {
String file = url.getFile();
if (trailingSlash == (file.endsWith("/"))) //$NON-NLS-1$
return url;
file = trailingSlash ? file + "/" : file.substring(0, file.length() - 1); //$NON-NLS-1$
return new URL(url.getProtocol(), url.getHost(), file);
}
private static String computeDefaultConfigurationLocation(File installLocation) {
// 1) We store the config state relative to the 'eclipse' directory if possible
// 2) If this directory is read-only
// we store the state in <user.home>/.eclipse/<application-id>_<version> where <user.home>
// is unique for each local user, and <application-id> is the one
// defined in .eclipseproduct marker file. If .eclipseproduct does not
// exist, use "eclipse" as the application-id.
String configurationLocation = null;
if (canWrite(installLocation))
configurationLocation = installLocation.getAbsolutePath();
else
// We can't write in the eclipse install dir so try for some place in the user's home dir
configurationLocation = computeDefaultUserAreaLocation(installLocation);
return configurationLocation + File.separator + CONFIG_DIR;
}
private static boolean canWrite(File installDir) {
if (installDir.canWrite() == false)
return false;
if (!installDir.isDirectory())
return false;
File fileTest = null;
try {
// we use the .dll suffix to properly test on Vista virtual directories
// on Vista you are not allowed to write executable files on virtual directories like "Program Files"
fileTest = File.createTempFile("writableArea", ".dll", installDir); //$NON-NLS-1$ //$NON-NLS-2$
} catch (IOException e) {
return false;
} finally {
if (fileTest != null)
fileTest.delete();
}
return true;
}
private static String computeDefaultUserAreaLocation(File installDir) {
// we store the state in <user.home>/.eclipse/<application-id>_<version> where <user.home>
// is unique for each local user, and <application-id> is the one
// defined in .eclipseproduct marker file. If .eclipseproduct does not
// exist, use "eclipse" as the application-id.
String installDirHash = getInstallDirHash(installDir);
String appName = "." + ECLIPSE; //$NON-NLS-1$
File eclipseProduct = new File(installDir, PRODUCT_SITE_MARKER);
if (eclipseProduct.exists()) {
Properties props = new Properties();
try {
props.load(new FileInputStream(eclipseProduct));
String appId = props.getProperty(PRODUCT_SITE_ID);
if (appId == null || appId.trim().length() == 0)
appId = ECLIPSE;
String appVersion = props.getProperty(PRODUCT_SITE_VERSION);
if (appVersion == null || appVersion.trim().length() == 0)
appVersion = ""; //$NON-NLS-1$
appName += File.separator + appId + "_" + appVersion + "_" + installDirHash; //$NON-NLS-1$ //$NON-NLS-2$
} catch (IOException e) {
// Do nothing if we get an exception. We will default to a standard location
// in the user's home dir.
// add the hash to help prevent collisions
appName += File.separator + installDirHash;
}
} else {
// add the hash to help prevent collisions
appName += File.separator + installDirHash;
}
appName += '_' + OS_WS_ARCHToString();
String userHome = System.getProperty(PROP_USER_HOME);
return new File(userHome, appName).getAbsolutePath(); // $NON-NLS-1$
}
private static String OS_WS_ARCHToString() {
return getOS() + '_' + getWS() + '_' + getArch();
}
private static String getWS() {
String osgiWs = System.getProperty(PROP_WS);
if (osgiWs != null)
return osgiWs;
String osName = getOS();
if (osName.equals(Constants.OS_WIN32))
return Constants.WS_WIN32;
if (osName.equals(Constants.OS_LINUX))
return Constants.WS_GTK;
if (osName.equals(Constants.OS_MACOSX))
return Constants.WS_COCOA;
if (osName.equals(Constants.OS_HPUX))
return Constants.WS_GTK;
if (osName.equals(Constants.OS_AIX))
return Constants.WS_GTK;
if (osName.equals(Constants.OS_SOLARIS))
return Constants.WS_GTK;
if (osName.equals(Constants.OS_QNX))
return Constants.WS_PHOTON;
return Constants.WS_UNKNOWN;
}
private static String getOS() {
String osgiOs = System.getProperty(PROP_OS);
if (osgiOs != null)
return osgiOs;
String osName = System.getProperties().getProperty("os.name"); //$NON-NLS-1$
if (osName.regionMatches(true, 0, Constants.OS_WIN32, 0, 3))
return Constants.OS_WIN32;
// EXCEPTION: All mappings of SunOS convert to Solaris
if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_SUNOS))
return Constants.OS_SOLARIS;
if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_LINUX))
return Constants.OS_LINUX;
if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_QNX))
return Constants.OS_QNX;
if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_AIX))
return Constants.OS_AIX;
if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_HPUX))
return Constants.OS_HPUX;
if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_OS400))
return Constants.OS_OS400;
if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_OS390))
return Constants.OS_OS390;
if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_ZOS))
return Constants.OS_ZOS;
// os.name on Mac OS can be either Mac OS or Mac OS X
if (osName.regionMatches(true, 0, Constants.INTERNAL_OS_MACOSX, 0, Constants.INTERNAL_OS_MACOSX.length()))
return Constants.OS_MACOSX;
return Constants.OS_UNKNOWN;
}
private static String getArch() {
String osgiArch = System.getProperty(PROP_ARCH);
if (osgiArch != null)
return osgiArch;
String name = System.getProperties().getProperty("os.arch");//$NON-NLS-1$
// Map i386 architecture to x86
if (name.equalsIgnoreCase(Constants.INTERNAL_ARCH_I386))
return Constants.ARCH_X86;
// Map amd64 architecture to x86_64
else if (name.equalsIgnoreCase(Constants.INTERNAL_AMD64))
return Constants.ARCH_X86_64;
return name;
}
private static String getInstallDirHash(File installDir) {
// compute an install dir hash to prevent configuration area collisions with other eclipse installs
int hashCode;
try {
hashCode = installDir.getCanonicalPath().hashCode();
} catch (IOException ioe) {
// fall back to absolute path
hashCode = installDir.getAbsolutePath().hashCode();
}
if (hashCode < 0)
hashCode = -(hashCode);
String installDirHash = String.valueOf(hashCode);
return installDirHash;
}
private static OriginalOrderProperties mergeProperties(OriginalOrderProperties source,
OriginalOrderProperties userConfiguration) {
if (userConfiguration != null) {
source.setBeginAdd(true);
source.putAll(userConfiguration);
}
return source;
}
private static void debug(String message) {
if (DEBUG) {
Q7ExtLaunchingPlugin.getDefault().info(message);
}
}
}