blob: dca40c2b08ac729556bea3ef8a1df3f10aac12b3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2010 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.pde.internal.core.target;
import java.io.*;
import java.util.*;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.eclipse.core.runtime.*;
import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.equinox.frameworkadmin.BundleInfo;
import org.eclipse.equinox.p2.engine.IProfile;
import org.eclipse.equinox.p2.engine.IProfileRegistry;
import org.eclipse.equinox.p2.engine.query.IUProfilePropertyQuery;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.core.plugin.TargetPlatform;
import org.eclipse.pde.internal.core.ExternalFeatureModelManager;
import org.eclipse.pde.internal.core.PDECore;
import org.eclipse.pde.internal.core.ifeature.IFeatureModel;
import org.eclipse.pde.internal.core.ifeature.IFeaturePlugin;
import org.eclipse.pde.internal.core.target.provisional.*;
import org.xml.sax.SAXException;
/**
* Target definition implementation.
*
* @since 3.5
*/
public class TargetDefinition implements ITargetDefinition {
// name and description
private String fName;
// included and optional filtering
private NameVersionDescriptor[] fIncluded;
private NameVersionDescriptor[] fOptional;
// arguments
private String fProgramArgs;
private String fVMArgs;
// environment settings
private IPath fJREContainer;
private String fArch;
private String fOS;
private String fWS;
private String fNL;
// bundle containers
private IBundleContainer[] fContainers;
// handle
private ITargetHandle fHandle;
// implicit dependencies
private NameVersionDescriptor[] fImplicit;
// internal settings for UI mode (how content is displayed to the user
private int fUIMode = MODE_PLUGIN;
public static final int MODE_PLUGIN = 0;
public static final int MODE_FEATURE = 1;
// internal caches for feature based targets
private IFeatureModel[] fFeatureModels;
private IResolvedBundle[] fOtherBundles;
/**
* Constructs a target definition based on the given handle.
*/
TargetDefinition(ITargetHandle handle) {
fHandle = handle;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getArch()
*/
public String getArch() {
return fArch;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getBundleContainers()
*/
public IBundleContainer[] getBundleContainers() {
return fContainers;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getNL()
*/
public String getNL() {
return fNL;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getName()
*/
public String getName() {
return fName;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getOS()
*/
public String getOS() {
return fOS;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getProgramArguments()
*/
public String getProgramArguments() {
return fProgramArgs;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getVMArguments()
*/
public String getVMArguments() {
return fVMArgs;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getWS()
*/
public String getWS() {
return fWS;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setArch(java.lang.String)
*/
public void setArch(String arch) {
fArch = arch;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setNL(java.lang.String)
*/
public void setNL(String nl) {
fNL = nl;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setName(java.lang.String)
*/
public void setName(String name) {
fName = name;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setOS(java.lang.String)
*/
public void setOS(String os) {
fOS = os;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setProgramArguments(java.lang.String)
*/
public void setProgramArguments(String args) {
if (args != null && args.length() == 0) {
args = null;
}
fProgramArgs = args;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setVMArguments(java.lang.String)
*/
public void setVMArguments(String args) {
if (args != null && args.length() == 0) {
args = null;
}
fVMArgs = args;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setWS(java.lang.String)
*/
public void setWS(String ws) {
fWS = ws;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setBundleContainers(org.eclipse.pde.internal.core.target.provisional.IBundleContainer[])
*/
public void setBundleContainers(IBundleContainer[] containers) {
// Clear the feature model cache as it is based on the bundle container locations
fFeatureModels = null;
fOtherBundles = null;
if (containers != null && containers.length == 0) {
containers = null;
}
fContainers = containers;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#resolve(org.eclipse.core.runtime.IProgressMonitor)
*/
public IStatus resolve(IProgressMonitor monitor) {
IBundleContainer[] containers = getBundleContainers();
int num = 0;
if (containers != null) {
num = containers.length;
}
SubMonitor subMonitor = SubMonitor.convert(monitor, Messages.TargetDefinition_1, num * 10);
try {
MultiStatus status = new MultiStatus(PDECore.PLUGIN_ID, 0, Messages.TargetDefinition_2, null);
if (containers != null) {
for (int i = 0; i < containers.length; i++) {
if (subMonitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
subMonitor.subTask(Messages.TargetDefinition_4);
IStatus s = containers[i].resolve(this, subMonitor.newChild(10));
if (!s.isOK()) {
status.add(s);
}
}
}
if (status.isOK()) {
return Status.OK_STATUS;
}
return status;
} finally {
subMonitor.done();
if (monitor != null) {
monitor.done();
}
}
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#isResolved()
*/
public boolean isResolved() {
IBundleContainer[] containers = getBundleContainers();
if (containers != null) {
for (int i = 0; i < containers.length; i++) {
IBundleContainer container = containers[i];
if (!container.isResolved()) {
return false;
}
}
}
return true;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getBundleStatus()
*/
public IStatus getBundleStatus() {
if (isResolved()) {
IBundleContainer[] containers = getBundleContainers();
if (containers != null) {
// Check if the containers have any resolution problems
MultiStatus result = new MultiStatus(PDECore.PLUGIN_ID, 0, Messages.TargetDefinition_5, null);
for (int i = 0; i < containers.length; i++) {
IBundleContainer container = containers[i];
IStatus containerStatus = container.getStatus();
if (containerStatus != null && !containerStatus.isOK()) {
result.add(containerStatus);
}
}
// Check if any of the included bundles have problems
// build status from bundle list
IResolvedBundle[] bundles = getBundles();
for (int i = 0; i < bundles.length; i++) {
if (!bundles[i].getStatus().isOK()) {
result.add(bundles[i].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;
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setIncluded(org.eclipse.pde.internal.core.target.provisional.NameVersionDescriptor[])
*/
public void setIncluded(NameVersionDescriptor[] included) {
fIncluded = included;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getIncluded()
*/
public NameVersionDescriptor[] getIncluded() {
return fIncluded;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setOptional(org.eclipse.pde.internal.core.target.provisional.NameVersionDescriptor[])
*/
public void setOptional(NameVersionDescriptor[] optional) {
fOptional = optional;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getOptional()
*/
public NameVersionDescriptor[] getOptional() {
return fOptional;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getBundles()
*/
public IResolvedBundle[] getBundles() {
return getBundles(false);
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getAllBundles()
*/
public IResolvedBundle[] getAllBundles() {
return getBundles(true);
}
/**
* Gathers and returns all or included bundles in this target or <code>null</code> if
* not resolved.
*
* @param allBundles whether to consider all bundles, or just those included/optional
* @return bundles or <code>null</code>
*/
private IResolvedBundle[] getBundles(boolean allBundles) {
if (isResolved()) {
IBundleContainer[] containers = getBundleContainers();
if (containers != null) {
List all = new ArrayList();
for (int i = 0; i < containers.length; i++) {
IBundleContainer container = containers[i];
IResolvedBundle[] bundles = container.getBundles();
for (int j = 0; j < bundles.length; j++) {
IResolvedBundle rb = bundles[j];
all.add(rb);
}
}
IResolvedBundle[] allResolvedBundles = (IResolvedBundle[]) all.toArray(new IResolvedBundle[all.size()]);
if (allBundles) {
return allResolvedBundles;
}
return filterBundles(allResolvedBundles, getIncluded());
}
return new IResolvedBundle[0];
}
return null;
}
private IResolvedBundle[] filterBundles(IResolvedBundle[] bundles, NameVersionDescriptor[] filter) {
if (filter == null) {
// All bundles are included, but still need to check for optional bundles
IBundleContainer parent = fContainers != null && fContainers.length > 0 ? fContainers[0] : null;
return getMatchingBundles(bundles, null, fOptional, parent);
}
if (filter.length == 0) {
return new IResolvedBundle[0];
}
// If there are features, don't set errors for missing bundles as they are caused by missing OS specific fragments
boolean containsFeatures = false;
List included = new ArrayList();
// For feature filters, get the list of included bundles, for bundle filters just add them to the list
for (int i = 0; i < filter.length; i++) {
if (filter[i].getType() == NameVersionDescriptor.TYPE_PLUGIN) {
included.add(filter[i]);
} else if (filter[i].getType() == NameVersionDescriptor.TYPE_FEATURE) {
containsFeatures = true;
IFeatureModel[] features = getFeatureModels();
IFeatureModel bestMatch = null;
for (int j = 0; j < features.length; j++) {
if (features[j].getFeature().getId().equals(filter[i].getId())) {
if (filter[i].getVersion() != null) {
// Try to find an exact feature match
if (filter[i].getVersion().equals(features[j].getFeature().getVersion())) {
// Exact match
bestMatch = features[j];
break;
}
} else if (bestMatch != null) {
// If no version specified take the highest version
Version v1 = Version.parseVersion(features[j].getFeature().getVersion());
Version v2 = Version.parseVersion(bestMatch.getFeature().getVersion());
if (v1.compareTo(v2) > 0) {
bestMatch = features[j];
}
}
if (bestMatch == null) {
// If we can't find a version match, just take any name match
bestMatch = features[j];
}
}
}
// Add the required plugins from the feature to the list of includes
if (bestMatch != null) {
IFeaturePlugin[] plugins = bestMatch.getFeature().getPlugins();
for (int j = 0; j < plugins.length; j++) {
included.add(new NameVersionDescriptor(plugins[j].getId(), plugins[j].getVersion()));
}
}
}
}
// Return matching bundles
IBundleContainer parent = fContainers != null && fContainers.length > 0 ? fContainers[0] : null;
return getMatchingBundles(bundles, (NameVersionDescriptor[]) included.toArray(new NameVersionDescriptor[included.size()]), fOptional, containsFeatures ? null : parent);
}
/**
* Returns bundles from the specified collection that match the symbolic names
* and/or version in the specified criteria. When no version is specified
* the newest version (if any) is selected.
* <p>
* If a parent error container is specified, bundles listed in the included and optional filters that
* are not found in the given collection will be added as IResolvedBundles with error statuses explaining
* the problem. If no parent container is specified, missing included and optional bundles will be ignored.
* </p>
* @param collection bundles to resolve against match criteria
* @param included bundles to include or <code>null</code> if no restrictions
* @param optional optional bundles or <code>null</code> of no optional bundles
* @param errorParentContainer
*
* @return bundles that match this container's restrictions
*/
static IResolvedBundle[] getMatchingBundles(IResolvedBundle[] collection, NameVersionDescriptor[] included, NameVersionDescriptor[] optional, IBundleContainer errorParentContainer) {
if (included == null && optional == null) {
return collection;
}
// map bundles names to available versions
Map bundleMap = new HashMap(collection.length);
for (int i = 0; i < collection.length; i++) {
IResolvedBundle resolved = collection[i];
List list = (List) bundleMap.get(resolved.getBundleInfo().getSymbolicName());
if (list == null) {
list = new ArrayList(3);
bundleMap.put(resolved.getBundleInfo().getSymbolicName(), list);
}
list.add(resolved);
}
List resolved = new ArrayList();
if (included == null) {
for (int i = 0; i < collection.length; i++) {
resolved.add(collection[i]);
}
} else {
for (int i = 0; i < included.length; i++) {
BundleInfo info = new BundleInfo(included[i].getId(), included[i].getVersion(), null, BundleInfo.NO_LEVEL, false);
IResolvedBundle bundle = resolveBundle(bundleMap, info, false, errorParentContainer);
if (bundle != null) {
resolved.add(bundle);
}
}
}
if (optional != null) {
for (int i = 0; i < optional.length; i++) {
BundleInfo option = new BundleInfo(optional[i].getId(), optional[i].getVersion(), null, BundleInfo.NO_LEVEL, false);
IResolvedBundle resolveBundle = resolveBundle(bundleMap, option, true, errorParentContainer);
if (resolveBundle != null) {
IStatus status = resolveBundle.getStatus();
if (status.isOK()) {
// add to list if not there already
if (!resolved.contains(resolveBundle)) {
resolved.add(resolveBundle);
}
} else {
// missing optional bundle - add it to the list
resolved.add(resolveBundle);
}
}
}
}
return (IResolvedBundle[]) resolved.toArray(new IResolvedBundle[resolved.size()]);
}
/**
* Resolves a bundle for the given info from the given map. The map contains
* keys of symbolic names and values are lists of {@link IResolvedBundle}'s available
* that match the names.
* <p>
* If an parent container for errors is provided, if a resolve bundle matching the requirements cannot be found
* a IResolvedBundle will be returned containing an status. If no parent container is specified,
* missing bundles will result in a return value of <code>null</code>
* </p>
*
* @param bundleMap available bundles to resolve against
* @param info name and version to match against
* @param optional whether the bundle is optional
* @param errorParentContainer bundle container the resolved bundle belongs too
* @return resolved bundle or <code>null</code>
*/
private static IResolvedBundle resolveBundle(Map bundleMap, BundleInfo info, boolean optional, IBundleContainer errorParentContainer) {
List list = (List) bundleMap.get(info.getSymbolicName());
if (list != null) {
String version = info.getVersion();
if (version == null || version.equals(BundleInfo.EMPTY_VERSION)) {
// select newest
if (list.size() > 1) {
// sort the list
Collections.sort(list, new Comparator() {
public int compare(Object o1, Object o2) {
BundleInfo b1 = ((IResolvedBundle) o1).getBundleInfo();
BundleInfo b2 = ((IResolvedBundle) o2).getBundleInfo();
return b1.getVersion().compareTo(b2.getVersion());
}
});
}
// select the last one
ResolvedBundle rb = (ResolvedBundle) list.get(list.size() - 1);
rb.setOptional(optional);
return rb;
}
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
IResolvedBundle bundle = (IResolvedBundle) iterator.next();
if (bundle.getBundleInfo().getVersion().equals(version)) {
((ResolvedBundle) bundle).setOptional(optional);
return bundle;
}
}
// VERSION DOES NOT EXIST
if (errorParentContainer == null) {
return null;
}
int sev = IStatus.ERROR;
String message = NLS.bind(Messages.AbstractBundleContainer_1, new Object[] {info.getVersion(), info.getSymbolicName()});
if (optional) {
sev = IStatus.INFO;
message = NLS.bind(Messages.AbstractBundleContainer_2, new Object[] {info.getVersion(), info.getSymbolicName()});
}
return new ResolvedBundle(info, errorParentContainer, new Status(sev, PDECore.PLUGIN_ID, IResolvedBundle.STATUS_VERSION_DOES_NOT_EXIST, message, null), null, optional, false);
}
// DOES NOT EXIST
if (errorParentContainer == null) {
return null;
}
int sev = IStatus.ERROR;
String message = NLS.bind(Messages.AbstractBundleContainer_3, info.getSymbolicName());
if (optional) {
sev = IStatus.INFO;
message = NLS.bind(Messages.AbstractBundleContainer_4, info.getSymbolicName());
}
return new ResolvedBundle(info, errorParentContainer, new Status(sev, PDECore.PLUGIN_ID, IResolvedBundle.STATUS_DOES_NOT_EXIST, message, null), null, optional, false);
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getHandle()
*/
public ITargetHandle getHandle() {
return fHandle;
}
/**
* Build contents from the given stream.
*
* @param stream input stream
* @throws CoreException if an error occurs
*/
void setContents(InputStream stream) throws CoreException {
try {
fArch = null;
fContainers = null;
fImplicit = null;
fJREContainer = null;
fName = null;
fNL = null;
fOS = null;
fProgramArgs = null;
fVMArgs = null;
fWS = null;
TargetDefinitionPersistenceHelper.initFromXML(this, stream);
} catch (ParserConfigurationException e) {
abort(Messages.TargetDefinition_0, e);
} catch (SAXException e) {
abort(Messages.TargetDefinition_0, e);
} catch (IOException e) {
abort(Messages.TargetDefinition_0, e);
}
}
/**
* Persists contents to the given stream.
*
* @param stream output stream
* @throws CoreException if an error occurs
*/
void write(OutputStream stream) throws CoreException {
try {
TargetDefinitionPersistenceHelper.persistXML(this, stream);
} catch (IOException e) {
abort(Messages.TargetDefinition_3, e);
} catch (ParserConfigurationException e) {
abort(Messages.TargetDefinition_3, e);
} catch (TransformerException e) {
abort(Messages.TargetDefinition_3, e);
}
}
/**
* Throws a core exception with the given message and underlying exception (possibly
* <code>null</code>).
*
* @param message message
* @param e underlying cause of the exception or <code>null</code>
* @throws CoreException
*/
private void abort(String message, Exception e) throws CoreException {
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, message, e));
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getImplicitDependencies()
*/
public NameVersionDescriptor[] getImplicitDependencies() {
return fImplicit;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setImplicitDependencies(org.eclipse.pde.internal.core.target.provisional.NameVersionDescriptor[])
*/
public void setImplicitDependencies(NameVersionDescriptor[] bundles) {
if (bundles != null && bundles.length == 0) {
bundles = null;
}
fImplicit = bundles;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#getJREContainer()
*/
public IPath getJREContainer() {
return fJREContainer;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setJREContainer(org.eclipse.core.runtime.IPath)
*/
public void setJREContainer(IPath containerPath) {
fJREContainer = containerPath;
}
/**
* Returns whether the content of this definition is equal to the content of the specified definition.
*
* @param definition
* @return whether the content of this definition is equal to the content of the specified definition
*/
public boolean isContentEqual(ITargetDefinition definition) {
if (isNullOrEqual(getName(), definition.getName()) && isNullOrEqual(getArch(), definition.getArch()) && isNullOrEqual(getNL(), definition.getNL()) && isNullOrEqual(getOS(), definition.getOS()) && isNullOrEqual(getWS(), definition.getWS()) && isNullOrEqual(getProgramArguments(), definition.getProgramArguments()) && isNullOrEqual(getVMArguments(), definition.getVMArguments()) && isNullOrEqual(getJREContainer(), definition.getJREContainer())) {
// Check includes/optional
if (isNullOrEqual(getIncluded(), definition.getIncluded()) && isNullOrEqual(getOptional(), definition.getOptional())) {
// Check containers
IBundleContainer[] c1 = getBundleContainers();
IBundleContainer[] c2 = definition.getBundleContainers();
if (areContainersEqual(c1, c2)) {
// Check implicit dependencies
return isNullOrEqual(getImplicitDependencies(), definition.getImplicitDependencies());
}
}
}
return false;
}
/**
* Returns whether the content of this definition is equivalent to the content of the
* specified definition (excluding name/description).
*
* @param definition
* @return whether the content of this definition is equivalent to the content of the
* specified definition
*/
public boolean isContentEquivalent(ITargetDefinition definition) {
if (isNullOrEqual(getArch(), definition.getArch()) && isNullOrEqual(getNL(), definition.getNL()) && isNullOrEqual(getOS(), definition.getOS()) && isNullOrEqual(getWS(), definition.getWS()) && isArgsNullOrEqual(getProgramArguments(), definition.getProgramArguments()) && isArgsNullOrEqual(getVMArguments(), definition.getVMArguments()) && isNullOrEqual(getJREContainer(), definition.getJREContainer())) {
// Check includes/optional
if (isNullOrEqual(getIncluded(), definition.getIncluded()) && isNullOrEqual(getOptional(), definition.getOptional())) {
// Check containers
IBundleContainer[] c1 = getBundleContainers();
IBundleContainer[] c2 = definition.getBundleContainers();
if (areContainersEqual(c1, c2)) {
// Check implicit dependencies
return isNullOrEqual(getImplicitDependencies(), definition.getImplicitDependencies());
}
}
}
return false;
}
private boolean isNullOrEqual(Object o1, Object o2) {
if (o1 == null) {
return o2 == null;
}
if (o2 == null) {
return false;
}
return o1.equals(o2);
}
/**
* Returns whether the arrays have equal contents or are both <code>null</code>.
*
* @param objects1
* @param objects2
* @return whether the arrays have equal contents or are both <code>null</code>
*/
private boolean isNullOrEqual(Object[] objects1, Object[] objects2) {
if (objects1 == null) {
return objects2 == null;
}
if (objects2 == null) {
return false;
}
if (objects1.length == objects2.length) {
for (int i = 0; i < objects1.length; i++) {
if (!objects1[i].equals(objects2[i])) {
return false;
}
}
return true;
}
return false;
}
private boolean isArgsNullOrEqual(String args1, String args2) {
if (args1 == null) {
return args2 == null;
}
if (args2 == null) {
return false;
}
String[] a1 = DebugPlugin.parseArguments(args1);
String[] a2 = DebugPlugin.parseArguments(args2);
if (a1.length == a2.length) {
for (int i = 0; i < a1.length; i++) {
if (!a1[i].equals(a2[i])) {
return false;
}
}
return true;
}
return false;
}
private boolean areContainersEqual(IBundleContainer[] c1, IBundleContainer[] c2) {
if (c1 == null) {
return c2 == null;
}
if (c2 == null) {
return false;
}
if (c1.length == c2.length) {
for (int i = 0; i < c2.length; i++) {
AbstractBundleContainer ac1 = (AbstractBundleContainer) c1[i];
AbstractBundleContainer ac2 = (AbstractBundleContainer) c2[i];
if (!ac1.isContentEqual(ac2)) {
return false;
}
}
return true;
}
return false;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append(fName != null ? fName : "No Name"); //$NON-NLS-1$
if (fContainers == null) {
buf.append("\n\tNo containers"); //$NON-NLS-1$
} else {
for (int i = 0; i < fContainers.length; i++) {
buf.append("\n\t").append(fContainers.toString()); //$NON-NLS-1$
}
}
buf.append("\nEnv: ").append(fOS).append("/").append(fWS).append("/").append(fArch).append("/").append(fNL); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
buf.append("\nJRE: ").append(fJREContainer); //$NON-NLS-1$
buf.append("\nArgs: ").append(fProgramArgs).append("/").append(fVMArgs); //$NON-NLS-1$ //$NON-NLS-2$
buf.append("\nImplicit: ").append(fImplicit == null ? "null" : Integer.toString(fImplicit.length)); //$NON-NLS-1$ //$NON-NLS-2$
buf.append("\nHandle: ").append(fHandle.toString()); //$NON-NLS-1$
return buf.toString();
}
/**
* Returns whether software site containers are configured to provision for all environments
* versus a single environment.
*
* @return whether all environments will be provisioned
*/
private boolean isAllEnvironments() {
IBundleContainer[] containers = getBundleContainers();
if (containers != null) {
for (int i = 0; i < containers.length; i++) {
if (containers[i] instanceof IUBundleContainer) {
IUBundleContainer iu = (IUBundleContainer) containers[i];
if (iu.getIncludeAllEnvironments()) {
return true;
}
}
}
}
return false;
}
/**
* Returns the mode used to provision this target - slice versus plan or <code>null</code> if
* this target has no software sites.
*
* @return provisioning mode or <code>null</code>
*/
private String getProvisionMode() {
IBundleContainer[] containers = getBundleContainers();
if (containers != null) {
for (int i = 0; i < containers.length; i++) {
if (containers[i] instanceof IUBundleContainer) {
IUBundleContainer iu = (IUBundleContainer) containers[i];
if (iu.getIncludeAllRequired()) {
return TargetDefinitionPersistenceHelper.MODE_PLANNER;
}
return TargetDefinitionPersistenceHelper.MODE_SLICER;
}
}
}
return null;
}
/**
* Returns the profile for the this target handle, creating one if required.
*
* @return profile
* @throws CoreException in unable to retrieve profile
*/
public IProfile getProfile() throws CoreException {
IProfileRegistry registry = AbstractTargetHandle.getProfileRegistry();
if (registry == null) {
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, Messages.AbstractTargetHandle_0));
}
AbstractTargetHandle handle = ((AbstractTargetHandle) getHandle());
String id = handle.getProfileId();
IProfile profile = registry.getProfile(id);
if (profile != null) {
boolean recreate = false;
// check if all environments setting is the same
boolean all = false;
String value = profile.getProperty(AbstractTargetHandle.PROP_ALL_ENVIRONMENTS);
if (value != null) {
all = Boolean.valueOf(value).booleanValue();
if (!Boolean.toString(isAllEnvironments()).equals(value)) {
recreate = true;
}
}
// ensure environment & NL settings are still the same (else we need a new profile)
String property = null;
if (!recreate && !all) {
property = generateEnvironmentProperties();
value = profile.getProperty(IProfile.PROP_ENVIRONMENTS);
if (!property.equals(value)) {
recreate = true;
}
}
// check provisioning mode: slice versus plan
String mode = getProvisionMode();
if (mode != null) {
value = profile.getProperty(AbstractTargetHandle.PROP_PROVISION_MODE);
if (!mode.equals(value)) {
recreate = true;
}
}
if (!recreate) {
property = generateNLProperty();
value = profile.getProperty(IProfile.PROP_NL);
if (!property.equals(value)) {
recreate = true;
}
}
if (!recreate) {
// check top level IU's. If any have been removed from the containers that are
// still in the profile, we need to recreate (rather than uninstall)
IUProfilePropertyQuery propertyQuery = new IUProfilePropertyQuery(AbstractTargetHandle.PROP_INSTALLED_IU, Boolean.toString(true));
IQueryResult queryResult = profile.query(propertyQuery, null);
Iterator iterator = queryResult.iterator();
if (iterator.hasNext()) {
Set installedIUs = new HashSet();
while (iterator.hasNext()) {
IInstallableUnit unit = (IInstallableUnit) iterator.next();
installedIUs.add(new NameVersionDescriptor(unit.getId(), unit.getVersion().toString()));
}
IBundleContainer[] containers = getBundleContainers();
if (containers != null) {
for (int i = 0; i < containers.length; i++) {
if (containers[i] instanceof IUBundleContainer) {
IUBundleContainer bc = (IUBundleContainer) containers[i];
String[] ids = bc.getIds();
Version[] versions = bc.getVersions();
for (int j = 0; j < versions.length; j++) {
installedIUs.remove(new NameVersionDescriptor(ids[j], versions[j].toString()));
}
}
}
}
if (!installedIUs.isEmpty()) {
recreate = true;
}
}
}
if (recreate) {
handle.deleteProfile();
profile = null;
}
}
if (profile == null) {
// create profile
Map properties = new HashMap();
properties.put(IProfile.PROP_INSTALL_FOLDER, AbstractTargetHandle.INSTALL_FOLDERS.append(Long.toString(LocalTargetHandle.nextTimeStamp())).toOSString());
properties.put(IProfile.PROP_CACHE, AbstractTargetHandle.BUNDLE_POOL.toOSString());
properties.put(IProfile.PROP_INSTALL_FEATURES, Boolean.TRUE.toString());
// set up environment & NL properly so OS specific fragments are down loaded/installed
properties.put(IProfile.PROP_ENVIRONMENTS, generateEnvironmentProperties());
properties.put(IProfile.PROP_NL, generateNLProperty());
String mode = getProvisionMode();
if (mode != null) {
properties.put(AbstractTargetHandle.PROP_PROVISION_MODE, mode);
properties.put(AbstractTargetHandle.PROP_ALL_ENVIRONMENTS, Boolean.toString(isAllEnvironments()));
}
profile = registry.addProfile(id, properties);
}
return profile;
}
/**
* Returns the set of feature models available in this target, will return a cached copy if available
*
* @return set of features available in this target, possibly empty.
*/
public IFeatureModel[] getFeatureModels() {
if (fFeatureModels != null) {
return fFeatureModels;
}
IBundleContainer[] containers = getBundleContainers();
String path = null;
if (containers != null && containers.length > 0) {
try {
path = ((AbstractBundleContainer) containers[0]).getLocation(true);
} catch (CoreException e) {
PDECore.log(e);
return new IFeatureModel[0];
}
}
if (path == null) {
path = TargetPlatform.getDefaultLocation();
} else {
try {
IStringVariableManager manager = VariablesPlugin.getDefault().getStringVariableManager();
path = manager.performStringSubstitution(path);
} catch (CoreException e) {
PDECore.log(e);
return new IFeatureModel[0];
}
}
ArrayList additional = new ArrayList();
// secondary containers are considered additional
if (containers != null && containers.length > 1) {
for (int i = 1; i < containers.length; i++) {
try {
additional.add(((AbstractBundleContainer) containers[i]).getLocation(true));
} catch (CoreException e) {
PDECore.log(e);
}
}
}
fFeatureModels = ExternalFeatureModelManager.createModels(path, additional, null);
return fFeatureModels;
}
/**
* Returns the set of IResolvedBundle available in this target that are not part of any features, will return a cached copy if available
*
* @return set of resolved bundles available in this target that don't belong to any features, possibly empty
*/
public IResolvedBundle[] getOtherBundles() {
if (fOtherBundles != null) {
return fOtherBundles;
}
IResolvedBundle[] allBundles = getAllBundles();
Map remaining = new HashMap();
for (int i = 0; i < allBundles.length; i++) {
remaining.put(allBundles[i].getBundleInfo().getSymbolicName(), allBundles[i]);
}
IFeatureModel[] features = getFeatureModels();
for (int i = 0; i < features.length; i++) {
IFeaturePlugin[] plugins = features[i].getFeature().getPlugins();
for (int j = 0; j < plugins.length; j++) {
remaining.remove(plugins[j].getId());
}
}
Collection values = remaining.values();
fOtherBundles = (IResolvedBundle[]) values.toArray(new IResolvedBundle[values.size()]);
return fOtherBundles;
}
/**
* Convenience method to return the set of IFeatureModels that are included in this
* target as well as any other included plug-ins as IResolvedBundles (that are not part
* of the features). Will return <code>null</code> if this target has not been resolved.
*
* @see #getFeatureModels()
* @see #getOtherBundles()
* @return set of IFeatureModels and IResolvedBundles or <code>mull</code>
*/
public Object[] getFeaturesAndBundles() {
if (!isResolved()) {
return null;
}
IFeatureModel[] allFeatures = getFeatureModels();
IResolvedBundle[] allExtraBundles = getOtherBundles();
NameVersionDescriptor[] included = getIncluded();
NameVersionDescriptor[] optional = getOptional();
if (included == null && optional == null) {
Set result = new HashSet();
result.addAll(Arrays.asList(allFeatures));
result.addAll(Arrays.asList(allExtraBundles));
return result.toArray();
}
List result = new ArrayList();
for (int i = 0; i < included.length; i++) {
if (included[i].getType() == NameVersionDescriptor.TYPE_PLUGIN) {
for (int j = 0; j < allExtraBundles.length; j++) {
if (allExtraBundles[j].getBundleInfo().getSymbolicName().equals(included[i].getId())) {
result.add(allExtraBundles[j]);
}
}
} else if (included[i].getType() == NameVersionDescriptor.TYPE_FEATURE) {
for (int j = 0; j < allFeatures.length; j++) {
if (allFeatures[j].getFeature().getId().equals(included[i].getId())) {
result.add(allFeatures[j]);
}
}
}
}
if (optional != null) {
for (int i = 0; i < optional.length; i++) {
for (int j = 0; j < allExtraBundles.length; j++) {
if (allExtraBundles[j].getBundleInfo().getSymbolicName().equals(optional[i].getId())) {
result.add(allExtraBundles[j]);
}
}
}
}
return result.toArray();
}
public int getUIMode() {
return fUIMode;
}
public void setUIMode(int mode) {
fUIMode = mode;
}
/**
* Generates the environment properties string for this target definition's p2 profile.
*
* @return environment properties
*/
private String generateEnvironmentProperties() {
// TODO: are there constants for these keys?
StringBuffer env = new StringBuffer();
String ws = getWS();
if (ws == null) {
ws = Platform.getWS();
}
env.append("osgi.ws="); //$NON-NLS-1$
env.append(ws);
env.append(","); //$NON-NLS-1$
String os = getOS();
if (os == null) {
os = Platform.getOS();
}
env.append("osgi.os="); //$NON-NLS-1$
env.append(os);
env.append(","); //$NON-NLS-1$
String arch = getArch();
if (arch == null) {
arch = Platform.getOSArch();
}
env.append("osgi.arch="); //$NON-NLS-1$
env.append(arch);
return env.toString();
}
/**
* Generates the NL property for this target definition's p2 profile.
*
* @return NL profile property
*/
private String generateNLProperty() {
String nl = getNL();
if (nl == null) {
nl = Platform.getNL();
}
return nl;
}
}