blob: bbfef9fcc2265014da4e980d73875525f2c828e4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 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.impl;
import java.io.File;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.provisional.frameworkadmin.BundleInfo;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.internal.core.ExternalFeatureModelManager;
import org.eclipse.pde.internal.core.PDECore;
import org.eclipse.pde.internal.core.ifeature.*;
import org.eclipse.pde.internal.core.target.provisional.*;
/**
* A container of the bundles contained in a feature.
*
* @since 3.5
*/
public class FeatureBundleContainer extends AbstractBundleContainer {
/**
* Constant describing the type of bundle container
*/
public static final String TYPE = "Feature"; //$NON-NLS-1$
/**
* Feature symbolic name
*/
private String fId;
/**
* Feature version or <code>null</code>
*/
private String fVersion;
/**
* Install location which may contain string substitution variables
*/
private String fHome;
/**
* Constructs a new feature bundle container for the feature at the specified
* location. Plug-ins are resolved in the plug-ins directory of the given home
* directory. When version is unspecified, the most recent version is used.
*
* @param home root directory containing the features directory which
* may contain string substitution variables
* @param name feature symbolic name
* @param version feature version, or <code>null</code> if unspecified
*/
FeatureBundleContainer(String home, String name, String version) {
fId = name;
fVersion = version;
fHome = home;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.impl.AbstractBundleContainer#getLocation(boolean)
*/
public String getLocation(boolean resolve) throws CoreException {
if (resolve) {
return resolveHomeLocation().toOSString();
}
return fHome;
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.impl.AbstractBundleContainer#getType()
*/
public String getType() {
return TYPE;
}
/**
* Returns the symbolic name of the feature this bundle container resolves from
*
* @return string feature id (symbolic name)
*/
public String getFeatureId() {
return fId;
}
/**
* Returns the version of the feature this bundle container resolves from if
* a version was specified.
*
* @return string feature version or <code>null</code>
*/
public String getFeatureVersion() {
return fVersion;
}
/**
* Returns the home location with all variables resolved as a path.
*
* @return resolved home location
* @throws CoreException
*/
private IPath resolveHomeLocation() throws CoreException {
return new Path(resolveVariables(fHome));
}
/**
* Resolves and returns the directory containing the feature.
*
* @return feature directory
* @throws CoreException if unable to resolve
*/
private File resolveFeatureLocation() throws CoreException {
File features = resolveHomeLocation().append("features").toFile(); //$NON-NLS-1$
if (!features.exists() || features.isFile()) {
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(Messages.FeatureBundleContainer_0, features.toString())));
}
// if a specific version is specified, use it
if (fVersion != null) {
StringBuffer buf = new StringBuffer();
String name = buf.append(fId).append("_").append(fVersion).toString(); //$NON-NLS-1$
return new File(features, name);
}
// use most recent version
String[] list = features.list();
List versions = new ArrayList();
StringBuffer buf = new StringBuffer();
String prefix = buf.append(fId).append("_").toString(); //$NON-NLS-1$
for (int i = 0; i < list.length; i++) {
String name = list[i];
if (name.startsWith(prefix)) {
versions.add(name);
}
}
if (versions.isEmpty()) {
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(Messages.FeatureBundleContainer_1, fId)));
}
Collections.sort(versions);
String name = (String) versions.get(versions.size() - 1);
return new File(features, name);
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.impl.AbstractBundleContainer#resolveBundles(org.eclipse.pde.internal.core.target.provisional.ITargetDefinition, org.eclipse.core.runtime.IProgressMonitor)
*/
protected IResolvedBundle[] resolveBundles(ITargetDefinition definition, IProgressMonitor monitor) throws CoreException {
IFeatureModel model = null;
try {
File location = resolveFeatureLocation();
File manifest = new File(location, "feature.xml"); //$NON-NLS-1$
if (!manifest.exists() || !manifest.isFile()) {
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(Messages.FeatureBundleContainer_2, fId)));
}
model = ExternalFeatureModelManager.createModel(manifest);
if (model == null || !model.isLoaded()) {
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(Messages.FeatureBundleContainer_2, fId)));
}
// search bundles in plug-ins directory
ITargetPlatformService service = (ITargetPlatformService) PDECore.getDefault().acquireService(ITargetPlatformService.class.getName());
if (service == null) {
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, Messages.FeatureBundleContainer_4));
}
File dir = new File(manifest.getParentFile().getParentFile().getParentFile(), "plugins"); //$NON-NLS-1$
if (!dir.exists() || !dir.isDirectory()) {
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(Messages.FeatureBundleContainer_5, fId)));
}
IBundleContainer container = service.newDirectoryContainer(dir.getAbsolutePath());
container.resolve(definition, monitor);
IResolvedBundle[] bundles = container.getBundles();
IFeature feature = model.getFeature();
IFeaturePlugin[] plugins = feature.getPlugins();
List matchInfos = new ArrayList(plugins.length);
for (int i = 0; i < plugins.length; i++) {
IFeaturePlugin plugin = plugins[i];
// only include if plug-in matches environment
if (isMatch(definition.getArch(), plugin.getArch(), Platform.getOSArch()) && isMatch(definition.getNL(), plugin.getNL(), Platform.getNL()) && isMatch(definition.getOS(), plugin.getOS(), Platform.getOS()) && isMatch(definition.getWS(), plugin.getWS(), Platform.getWS())) {
matchInfos.add(new BundleInfo(plugin.getId(), plugin.getVersion(), null, BundleInfo.NO_LEVEL, false));
}
}
return AbstractBundleContainer.getMatchingBundles(bundles, (BundleInfo[]) matchInfos.toArray(new BundleInfo[matchInfos.size()]), null);
} finally {
if (model != null) {
model.dispose();
}
}
}
/**
* Returns whether the given target environment setting matches that of a fragments.
*
* @param targetValue value in target definition
* @param fragmentValue value in fragment
* @param runningValue value of current running platform
* @return whether the fragment should be considered
*/
private boolean isMatch(String targetValue, String fragmentValue, String runningValue) {
if (fragmentValue == null) {
// unspecified, so it is a match
return true;
}
if (targetValue == null) {
return runningValue.equals(fragmentValue);
}
return targetValue.equals(fragmentValue);
}
/* (non-Javadoc)
* @see org.eclipse.pde.internal.core.target.impl.AbstractBundleContainer#isContentEqual(org.eclipse.pde.internal.core.target.impl.AbstractBundleContainer)
*/
public boolean isContentEqual(AbstractBundleContainer container) {
if (container instanceof FeatureBundleContainer) {
FeatureBundleContainer fbc = (FeatureBundleContainer) container;
return fHome.equals(fbc.fHome) && fId.equals(fbc.fId) && isNullOrEqual(fVersion, fVersion) && super.isContentEqual(container);
}
return false;
}
private boolean isNullOrEqual(Object o1, Object o2) {
if (o1 == null) {
return o2 == null;
}
if (o2 == null) {
return false;
}
return o1.equals(o2);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
return new StringBuffer().append("Feature ").append(fId).append(' ').append(fVersion).append(' ').append(fHome).append(' ').append(getIncludedBundles() == null ? "All" : Integer.toString(getIncludedBundles().length)).append(" included").toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}