blob: 8dfac1465b17db8d2cd5e879ec1d0d7296c37c97 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM - Initial API and implementation
*******************************************************************************/
package org.eclipse.pde.internal.build.builder;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import org.eclipse.core.internal.boot.PlatformURLHandler;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.p2.publisher.eclipse.FeatureEntry;
import org.eclipse.osgi.service.resolver.*;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.internal.build.*;
import org.eclipse.pde.internal.build.site.PDEState;
import org.osgi.framework.Filter;
public class ClasspathComputer3_0 implements IClasspathComputer, IPDEBuildConstants, IXMLConstants, IBuildPropertiesConstants {
public class ClasspathElement {
private final String path;
private final String subPath;
private String accessRules;
/**
* Create a ClasspathElement object
* @param path
* @param accessRules
* @throws NullPointerException if path is null
*/
protected ClasspathElement(String path, String subPath, String accessRules) {
if (path == null)
throw new NullPointerException();
this.path = path;
this.subPath = subPath;
this.accessRules = accessRules;
}
@Override
public String toString() {
return path;
}
public String getPath() {
return path;
}
public String getSubPath() {
return subPath;
}
public String getAccessRules() {
return accessRules;
}
public String getAbsolutePath() {
File f = new File(path);
if (f.isAbsolute()) {
try {
return f.getCanonicalPath();
} catch (IOException e) {
return path;
}
}
f = new File(modelLocation, path);
try {
return f.getCanonicalPath();
} catch (IOException e) {
return f.getPath();
}
}
public void addRules(String newRule) {
if (accessRules.equals("") || accessRules.equals(newRule)) //$NON-NLS-1$
return;
if (!newRule.equals("")) { //$NON-NLS-1$
String join = accessRules.substring(0, accessRules.length() - EXCLUDE_ALL_RULE.length() - 1);
newRule = join + newRule.substring(1);
}
accessRules = newRule;
return;
}
/**
* ClasspathElement objects are equal if they have the same path.
* Access rules are not considered.
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof ClasspathElement) {
ClasspathElement element = (ClasspathElement) obj;
if (!path.equals(element.getPath()))
return false;
if (subPath != null && subPath.equals(element.getSubPath()))
return false;
return true;
}
return false;
}
@Override
public int hashCode() {
int result = path.hashCode();
return 13 * result + ((subPath == null) ? 0 : subPath.hashCode());
}
}
private static String normalize(String path) {
if (path == null)
return null;
//always use '/' as a path separator to help with comparing paths in equals
return path.replaceAll("\\\\", "/"); //$NON-NLS-1$ //$NON-NLS-2$
}
private static final String EXCLUDE_ALL_RULE = "?**/*"; //$NON-NLS-1$
private final ModelBuildScriptGenerator generator;
private Map<String, String> visiblePackages = null;
private Map<String, ClasspathElement> pathElements = null;
private boolean allowBinaryCycles = false;
private Set<Long> requiredIds = null;
protected String modelLocation = null;
public ClasspathComputer3_0(ModelBuildScriptGenerator modelGenerator) {
this.generator = modelGenerator;
}
/**
* Compute the classpath for the given jar.
* The path returned conforms to Parent / Prerequisite / Self
*
* @param model the plugin containing the jar compiled
* @param jar the jar for which the classpath is being compiled
* @return String the classpath
* @throws CoreException
*/
@Override
public List<Object> getClasspath(BundleDescription model, ModelBuildScriptGenerator.CompiledEntry jar) throws CoreException {
List<Object> classpath = new ArrayList<>(20);
List<BundleDescription> pluginChain = new ArrayList<>(10); //The list of plugins added to detect cycle
modelLocation = generator.getLocation(model);
Set<BundleDescription> addedPlugins = new HashSet<>(10); //The set of all the plugins already added to the classpath (this allows for optimization)
pathElements = new HashMap<>();
visiblePackages = getVisiblePackages(model);
requiredIds = new HashSet<>();
allowBinaryCycles = AbstractScriptGenerator.getPropertyAsBoolean(IBuildPropertiesConstants.PROPERTY_ALLOW_BINARY_CYCLES);
//PREREQUISITE
addPrerequisites(model, classpath, modelLocation, pluginChain, addedPlugins);
//SELF
addSelf(model, jar, classpath, modelLocation, pluginChain, addedPlugins);
recordRequiredIds(model);
return classpath;
}
private void recordRequiredIds(BundleDescription model) {
Properties bundleProperties = null;
bundleProperties = (Properties) model.getUserObject();
if (bundleProperties == null) {
bundleProperties = new Properties();
model.setUserObject(bundleProperties);
}
StringBuffer buffer = new StringBuffer();
for (Iterator<Long> iterator = requiredIds.iterator(); iterator.hasNext();) {
buffer.append(iterator.next().toString());
buffer.append(':');
}
bundleProperties.setProperty(PROPERTY_REQUIRED_BUNDLE_IDS, buffer.toString());
}
private Map<String, String> getVisiblePackages(BundleDescription model) {
Map<String, String> packages = new HashMap<>(20);
StateHelper helper = Platform.getPlatformAdmin().getStateHelper();
addVisiblePackagesFromState(helper, model, packages);
if (model.getHost() != null)
addVisiblePackagesFromState(helper, (BundleDescription) model.getHost().getSupplier(), packages);
return packages;
}
private void addVisiblePackagesFromState(StateHelper helper, BundleDescription model, Map<String, String> packages) {
ExportPackageDescription[] exports = helper.getVisiblePackages(model);
for (int i = 0; i < exports.length; i++) {
BundleDescription exporter = exports[i].getExporter();
if (exporter == null)
continue;
boolean discouraged = helper.getAccessCode(model, exports[i]) == StateHelper.ACCESS_DISCOURAGED;
String pattern = exports[i].getName().replaceAll("\\.", "/") + "/*"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
String rule = (discouraged ? '~' : '+') + pattern;
String packagesKey = exporter.getSymbolicName() + "_" + exporter.getVersion(); //$NON-NLS-1$
String rules = packages.get(packagesKey);
if (rules != null) {
if (rules.indexOf(rule) == -1)
rules = rules + File.pathSeparator + rule;
} else {
rules = rule;
}
packages.put(packagesKey, rules);
}
}
/**
* Add the specified plugin (including its jars) and its fragments
* @param plugin
* @param classpath
* @param location
* @throws CoreException
*/
private void addPlugin(BundleDescription plugin, List<Object> classpath, String location) throws CoreException {
boolean allFragments = true;
String patchInfo = generator.getSite(false).getRegistry().getPatchData().get(Long.valueOf(plugin.getBundleId()));
if (patchInfo != null && plugin != generator.getModel()) {
addFragmentsLibraries(plugin, classpath, location, false, false);
allFragments = false;
}
requiredIds.add(Long.valueOf(plugin.getBundleId()));
addRuntimeLibraries(plugin, classpath, location);
addFragmentsLibraries(plugin, classpath, location, true, allFragments);
}
/**
* Add the runtime libraries for the specified plugin.
* @param model
* @param classpath
* @param baseLocation
* @throws CoreException
*/
private void addRuntimeLibraries(BundleDescription model, List<Object> classpath, String baseLocation) throws CoreException {
String[] libraries = getClasspathEntries(model);
String root = generator.getLocation(model);
IPath base = Utils.makeRelative(new Path(root), new Path(baseLocation));
Properties modelProps = getBuildPropertiesFor(model);
if (modelProps != AbstractScriptGenerator.MissingProperties.getInstance())
ModelBuildScriptGenerator.specialDotProcessing(modelProps, libraries);
for (int i = 0; i < libraries.length; i++) {
addDevEntries(model, baseLocation, classpath, Utils.getArrayFromString(modelProps.getProperty(PROPERTY_OUTPUT_PREFIX + libraries[i])), modelProps);
addPathAndCheck(model, base, libraries[i], modelProps, classpath);
}
}
/**
* Add all fragments of the given plugin
* @param plugin
* @param classpath
* @param baseLocation
* @throws CoreException
*/
private void addFragmentsLibraries(BundleDescription plugin, List<Object> classpath, String baseLocation, boolean afterPlugin, boolean all) throws CoreException {
// if plugin is not a plugin, it's a fragment and there is no fragment for a fragment. So we return.
BundleDescription[] fragments = plugin.getFragments();
if (fragments == null)
return;
for (int i = 0; i < fragments.length; i++) {
if (fragments[i] == generator.getModel())
continue;
if (matchFilter(fragments[i]) == false)
continue;
requiredIds.add(Long.valueOf(fragments[i].getBundleId()));
if (!afterPlugin && isPatchFragment(fragments[i])) {
addPluginLibrariesToFragmentLocations(plugin, fragments[i], classpath, baseLocation);
addRuntimeLibraries(fragments[i], classpath, baseLocation);
continue;
}
if ((afterPlugin && !isPatchFragment(fragments[i])) || all) {
addRuntimeLibraries(fragments[i], classpath, baseLocation);
addPluginLibrariesToFragmentLocations(plugin, fragments[i], classpath, baseLocation);
continue;
}
}
}
private boolean isPatchFragment(BundleDescription fragment) throws CoreException {
return generator.getSite(false).getRegistry().getPatchData().get(Long.valueOf(fragment.getBundleId())) != null;
}
/**
* There are cases where the plug-in only declares a library but the real JAR is under
* a fragment location. This method gets all the plugin libraries and place them in the
* possible fragment location.
*
* @param plugin
* @param fragment
* @param classpath
* @param baseLocation
* @throws CoreException
*/
private void addPluginLibrariesToFragmentLocations(BundleDescription plugin, BundleDescription fragment, List<Object> classpath, String baseLocation) throws CoreException {
//TODO This methods causes the addition of a lot of useless entries. See bug #35544
//If we reintroduce the test below, we reintroduce the problem 35544
// if (fragment.getRuntime() != null)
// return;
String[] libraries = getClasspathEntries(plugin);
String root = generator.getLocation(fragment);
IPath base = Utils.makeRelative(new Path(root), new Path(baseLocation));
Properties modelProps = getBuildPropertiesFor(fragment);
for (int i = 0; i < libraries.length; i++) {
addPathAndCheck(fragment, base, libraries[i], modelProps, classpath);
}
}
private Properties getBuildPropertiesFor(BundleDescription bundle) {
try {
Properties bundleProperties = AbstractScriptGenerator.readProperties(generator.getLocation(bundle), PROPERTIES_FILE, IStatus.OK);
if (Utils.isStringIn(generator.getClasspathEntries(bundle), ModelBuildScriptGenerator.DOT) != -1) {
String sourceFolder = bundleProperties.getProperty(PROPERTY_SOURCE_PREFIX + ModelBuildScriptGenerator.DOT);
if (sourceFolder != null) {
bundleProperties.setProperty(PROPERTY_SOURCE_PREFIX + ModelBuildScriptGenerator.EXPANDED_DOT, sourceFolder);
bundleProperties.remove(PROPERTY_SOURCE_PREFIX + ModelBuildScriptGenerator.DOT);
}
String outputValue = bundleProperties.getProperty(PROPERTY_OUTPUT_PREFIX + ModelBuildScriptGenerator.DOT);
if (outputValue != null) {
bundleProperties.setProperty(PROPERTY_OUTPUT_PREFIX + ModelBuildScriptGenerator.EXPANDED_DOT, outputValue);
bundleProperties.remove(PROPERTY_OUTPUT_PREFIX + ModelBuildScriptGenerator.DOT);
}
}
return bundleProperties;
} catch (CoreException e) {
//ignore
}
return null;
}
// Add a path into the classpath for a given model
// pluginId the plugin we are adding to the classpath
// basePath : the relative path between the plugin from which we are adding the classpath and the plugin that is requiring this entry
// classpath : The classpath in which we want to add this path
private void addPathAndCheck(BundleDescription model, IPath basePath, String libraryName, Properties modelProperties, List<Object> classpath) {
String pluginKey = model != null ? model.getSymbolicName() + "_" + model.getVersion() : null; //$NON-NLS-1$
String rules = ""; //$NON-NLS-1$
//only add access rules to libraries that are not part of the current bundle
//and are not this bundle's host if we are a fragment
BundleDescription currentBundle = generator.getModel();
if (model != null && model != currentBundle && (currentBundle.getHost() == null || currentBundle.getHost().getSupplier() != model)) {
String packageKey = pluginKey;
if (model.isResolved() && model.getHost() != null) {
BundleDescription host = (BundleDescription) model.getHost().getSupplier();
packageKey = host.getSymbolicName() + "_" + host.getVersion(); //$NON-NLS-1$
}
if (visiblePackages.containsKey(packageKey)) {
rules = "[" + visiblePackages.get(packageKey) + File.pathSeparator + EXCLUDE_ALL_RULE + "]"; //$NON-NLS-1$ //$NON-NLS-2$
} else {
rules = "[" + EXCLUDE_ALL_RULE + "]"; //$NON-NLS-1$//$NON-NLS-2$
}
}
String path = null;
String subPath = null;
Path libraryPath = new Path(libraryName);
if (libraryPath.isAbsolute()) {
path = libraryPath.toOSString();
} else if ("jar".equalsIgnoreCase(basePath.getFileExtension())) { //$NON-NLS-1$
if ("jar".equalsIgnoreCase(libraryPath.getFileExtension())) //$NON-NLS-1$
subPath = libraryPath.toOSString();
path = basePath.toOSString();
} else {
path = basePath.append(libraryPath).toOSString();
}
path = ModelBuildScriptGenerator.replaceVariables(path, pluginKey == null ? false : generator.getCompiledElements().contains(pluginKey));
String secondaryPath = null;
if (generator.getCompiledElements().contains(pluginKey)) {
if (modelProperties == null || modelProperties.getProperty(IBuildPropertiesConstants.PROPERTY_SOURCE_PREFIX + libraryName) != null)
path = Utils.getPropertyFormat(PROPERTY_BUILD_RESULT_FOLDER) + '/' + path;
secondaryPath = Utils.getPropertyFormat(PROPERTY_BUILD_RESULT_FOLDER) + "/../" + model.getSymbolicName() + '_' + model.getVersion() + '/' + libraryName; //$NON-NLS-1$
}
addClasspathElementWithRule(classpath, path, subPath, rules);
if (secondaryPath != null) {
addClasspathElementWithRule(classpath, secondaryPath, null, rules);
}
}
private void addClasspathElementWithRule(List<Object> classpath, String path, String subPath, String rules) {
path = normalize(path);
subPath = normalize(subPath);
String elementsKey = subPath != null ? path + '/' + subPath : path;
ClasspathElement existing = pathElements.get(elementsKey);
if (existing != null) {
existing.addRules(rules);
} else {
ClasspathElement element = new ClasspathElement(path, subPath, rules);
classpath.add(element);
pathElements.put(elementsKey, element);
}
}
private void addSelf(BundleDescription model, ModelBuildScriptGenerator.CompiledEntry jar, List<Object> classpath, String location, List<BundleDescription> pluginChain, Set<BundleDescription> addedPlugins) throws CoreException {
// If model is a fragment, we need to add in the classpath the plugin to which it is related
HostSpecification host = model.getHost();
if (host != null) {
BundleDescription[] hosts = host.getHosts();
for (int i = 0; i < hosts.length; i++)
addPluginAndPrerequisites(hosts[i], classpath, location, pluginChain, addedPlugins);
}
// Add the libraries
Properties modelProperties = generator.getBuildProperties();
String jarOrder = (String) modelProperties.get(PROPERTY_JAR_ORDER);
if (jarOrder == null) {
// if no jar order was specified in build.properties, we add all the libraries but the current one
// based on the order specified by the plugin.xml. Both library that we compile and .jar provided are processed
String[] libraries = getClasspathEntries(model);
if (libraries != null) {
for (int i = 0; i < libraries.length; i++) {
String libraryName = libraries[i];
if (jar.getName(false).equals(libraryName))
continue;
boolean isSource = (modelProperties.getProperty(PROPERTY_SOURCE_PREFIX + libraryName) != null);
if (isSource) {
addDevEntries(model, location, classpath, Utils.getArrayFromString(modelProperties.getProperty(PROPERTY_OUTPUT_PREFIX + libraryName)), modelProperties);
}
//Potential pb: here there maybe a nasty case where the libraries variable may refer to something which is part of the base
//but $xx$ will replace it by the $xx instead of $basexx. The solution is for the user to use the explicitly set the content
// of its build.property file
addPathAndCheck(model, Path.EMPTY, libraryName, modelProperties, classpath);
}
}
} else {
// otherwise we add all the predecessor jars
String[] order = Utils.getArrayFromString(jarOrder);
for (int i = 0; i < order.length; i++) {
if (order[i].equals(jar.getName(false)))
break;
addDevEntries(model, location, classpath, Utils.getArrayFromString((String) modelProperties.get(PROPERTY_OUTPUT_PREFIX + order[i])), modelProperties);
addPathAndCheck(model, Path.EMPTY, order[i], modelProperties, classpath);
}
// Then we add all the "pure libraries" (the one that does not contain source)
String[] libraries = getClasspathEntries(model);
for (int i = 0; i < libraries.length; i++) {
String libraryName = libraries[i];
if (modelProperties.get(PROPERTY_SOURCE_PREFIX + libraryName) == null) {
//Potential pb: if the pure library is something that is being compiled (which is supposetly not the case, but who knows...)
//the user will get $basexx instead of $ws
addPathAndCheck(model, Path.EMPTY, libraryName, modelProperties, classpath);
}
}
}
// add extra classpath if it exists. this code is kept for backward compatibility
String extraClasspath = (String) modelProperties.get(PROPERTY_JAR_EXTRA_CLASSPATH);
if (extraClasspath != null) {
String[] extra = Utils.getArrayFromString(extraClasspath, ";,"); //$NON-NLS-1$
for (int i = 0; i < extra.length; i++) {
//Potential pb: if the path refers to something that is being compiled (which is supposetly not the case, but who knows...)
//the user will get $basexx instead of $ws
String[] toAdd = computeExtraPath(extra[i], classpath, location);
if (toAdd != null && toAdd.length == 2)
addPathAndCheck(null, new Path(toAdd[0]), toAdd[1], modelProperties, classpath);
}
}
// add extra classpath if it is specified for the given jar
String[] jarSpecificExtraClasspath = jar.getExtraClasspath();
for (int i = 0; i < jarSpecificExtraClasspath.length; i++) {
//Potential pb: if the path refers to something that is being compiled (which is supposetly not the case, but who knows...)
//the user will get $basexx instead of $ws
String[] toAdd = computeExtraPath(jarSpecificExtraClasspath[i], classpath, location);
if (toAdd != null && toAdd.length == 2)
addPathAndCheck(null, new Path(toAdd[0]), toAdd[1], modelProperties, classpath);
}
}
/**
* Convenience method that compute the relative classpath of extra.classpath entries
* @param url a url
* @param location location used as a base location to compute the relative path
* @return String the relative path
* @throws CoreException
*/
private String[] computeExtraPath(String url, List<Object> classpath, String location) throws CoreException {
String relativePath = null;
String[] urlfragments = Utils.getArrayFromString(url, "/"); //$NON-NLS-1$
// A valid platform url for a plugin has a leat 3 segments.
if (urlfragments.length > 2 && urlfragments[0].equals(PlatformURLHandler.PROTOCOL + PlatformURLHandler.PROTOCOL_SEPARATOR)) {
String bundleLocation = null;
BundleDescription bundle = null;
if (urlfragments[1].equalsIgnoreCase(PLUGIN) || urlfragments[1].equalsIgnoreCase(FRAGMENT)) {
bundle = generator.getSite(false).getRegistry().getResolvedBundle(urlfragments[2]);
if (bundle == null) {
String message = NLS.bind(Messages.exception_url, generator.getModel().getSymbolicName() + '/' + generator.getPropertiesFileName() + ": " + url); //$NON-NLS-1$
MultiStatus status = new MultiStatus(PI_PDEBUILD, EXCEPTION_MALFORMED_URL, message, null);
message = NLS.bind(Messages.exception_missingElement, urlfragments[2]);
status.add(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_PLUGIN_MISSING, message, null));
throw new CoreException(status);
}
if (urlfragments.length == 3) {
addPlugin(bundle, classpath, location);
return null;
}
bundleLocation = generator.getLocation(bundle);
if (bundleLocation != null) {
String entry = urlfragments[3];
for (int i = 4; i < urlfragments.length; i++) {
entry += '/' + urlfragments[i];
}
return new String[] {Utils.makeRelative(new Path(bundleLocation), new Path(location)).toOSString(), entry};
}
} else if (urlfragments[1].equalsIgnoreCase("resource")) { //$NON-NLS-1$
String message = NLS.bind(Messages.exception_url, generator.getModel().getSymbolicName() + '/' + generator.getPropertiesFileName() + ": " + url); //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_MALFORMED_URL, message, null));
}
}
// Then it's just a regular URL, or just something that will be added at the end of the classpath for backward compatibility.......
try {
URL extraURL = new URL(url);
try {
relativePath = Utils.makeRelative(new Path(FileLocator.resolve(extraURL).getFile()), new Path(location)).toOSString();
} catch (IOException e) {
String message = NLS.bind(Messages.exception_url, generator.getModel().getSymbolicName() + '/' + generator.getPropertiesFileName() + ": " + url); //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_MALFORMED_URL, message, e));
}
} catch (MalformedURLException e) {
relativePath = url;
//TODO remove this backward compatibility support for as soon as we go to 2.2 and put back the exception
// String message = Policy.bind("exception.url", PROPERTIES_FILE + "::"+url); //$NON-NLS-1$ //$NON-NLS-2$
// throw new CoreException(new Status(IStatus.ERROR,PI_PDEBUILD, IPDEBuildConstants.EXCEPTION_MALFORMED_URL, message,e));
}
return new String[] {relativePath, ""}; //$NON-NLS-1$
}
//Add the prerequisite of a given plugin (target)
private void addPrerequisites(BundleDescription target, List<Object> classpath, String baseLocation, List<BundleDescription> pluginChain, Set<BundleDescription> addedPlugins) throws CoreException {
if (pluginChain.contains(target)) {
if (allowBinaryCycles && isAllowableCycle(target, pluginChain)) {
return;
}
// else exception
String cycleString = ""; //$NON-NLS-1$
for (Iterator<BundleDescription> iter = pluginChain.iterator(); iter.hasNext();)
cycleString += iter.next().toString() + ", "; //$NON-NLS-1$
cycleString += target.toString();
String message = NLS.bind(Messages.error_pluginCycle, cycleString);
throw new CoreException(new Status(IStatus.ERROR, IPDEBuildConstants.PI_PDEBUILD, EXCEPTION_CLASSPATH_CYCLE, message, null));
}
if (addedPlugins.contains(target)) //the plugin we are considering has already been added
return;
// add libraries from pre-requisite plug-ins. Don't worry about the export flag
// as all required plugins may be required for compilation.
BundleDescription[] requires = PDEState.getDependentBundles(target);
pluginChain.add(target);
for (int i = 0; i < requires.length; i++) {
addPluginAndPrerequisites(requires[i], classpath, baseLocation, pluginChain, addedPlugins);
}
pluginChain.remove(target);
addedPlugins.add(target);
}
/* We can allow a cycle if it only contains 1 bundle that needs to be built and the rest are binary. */
private boolean isAllowableCycle(BundleDescription target, List<BundleDescription> pluginChain) {
boolean haveNonBinary = false;
boolean inCycle = false;
for (Iterator<BundleDescription> iterator = pluginChain.iterator(); iterator.hasNext();) {
BundleDescription bundle = iterator.next();
if (bundle == target) {
inCycle = true;
haveNonBinary = !Utils.isBinary(bundle);
continue;
}
if (inCycle && !Utils.isBinary(bundle)) {
if (haveNonBinary)
return false;
haveNonBinary = true;
}
}
return true;
}
/**
* The pluginChain parameter is used to keep track of possible cycles. If prerequisite is already
* present in the chain it is not included in the classpath.
*
* @param target : the plugin for which we are going to introduce
* @param classpath
* @param baseLocation
* @param pluginChain
* @param addedPlugins
* @throws CoreException
*/
private void addPluginAndPrerequisites(BundleDescription target, List<Object> classpath, String baseLocation, List<BundleDescription> pluginChain, Set<BundleDescription> addedPlugins) throws CoreException {
if (matchFilter(target) == false)
return;
addPlugin(target, classpath, baseLocation);
addPrerequisites(target, classpath, baseLocation, pluginChain, addedPlugins);
}
private boolean matchFilter(BundleDescription target) {
Filter filter = BundleHelper.getDefault().getFilter(target);
if (filter == null) //Target is platform independent, add it
return true;
FeatureEntry associatedEntry = generator.getAssociatedEntry();
if (associatedEntry == null)
return true;
String os = associatedEntry.getOS();
String ws = associatedEntry.getWS();
String arch = associatedEntry.getArch();
String nl = associatedEntry.getNL();
if (os == null && ws == null && arch == null && nl == null) //I'm a platform independent plugin
return true;
//The plugin for which we are generating the classpath and target are not platform independent
Dictionary<String, Object> properties = new Hashtable<>(3);
if (os != null) {
Object value = os.indexOf(',') > -1 ? (Object) Utils.getArrayFromString(os, ",") : os; //$NON-NLS-1$
properties.put(OSGI_OS, value);
} else {
properties.put(OSGI_OS, CatchAllValue.singleton);
}
if (ws != null) {
Object value = ws.indexOf(',') > -1 ? (Object) Utils.getArrayFromString(ws, ",") : ws; //$NON-NLS-1$
properties.put(OSGI_WS, value);
} else
properties.put(OSGI_WS, CatchAllValue.singleton);
if (arch != null) {
Object value = arch.indexOf(',') > -1 ? (Object) Utils.getArrayFromString(arch, ",") : arch; //$NON-NLS-1$
properties.put(OSGI_ARCH, value);
} else
properties.put(OSGI_ARCH, CatchAllValue.singleton);
if (nl != null) {
Object value = nl.indexOf(',') > -1 ? (Object) Utils.getArrayFromString(nl, ",") : nl; //$NON-NLS-1$
properties.put(OSGI_NL, value);
} else
properties.put(OSGI_NL, CatchAllValue.singleton);
return filter.match(properties);
}
/**
*
* @param model
* @param baseLocation
* @param classpath
*/
private void addDevEntries(BundleDescription model, String baseLocation, List<Object> classpath, String[] jarSpecificEntries, Properties modelProperties) {
if (generator.devEntries == null && (jarSpecificEntries == null || jarSpecificEntries.length == 0))
return;
String[] entries;
// if jarSpecificEntries is given, then it overrides devEntries
if (jarSpecificEntries != null && jarSpecificEntries.length > 0)
entries = jarSpecificEntries;
else
entries = generator.devEntries.getDevClassPath(model.getSymbolicName());
IPath root = Utils.makeRelative(new Path(generator.getLocation(model)), new Path(baseLocation));
for (int i = 0; i < entries.length; i++) {
addPathAndCheck(model, root, entries[i], modelProperties, classpath);
}
}
//Return the jar name from the classpath
private String[] getClasspathEntries(BundleDescription bundle) throws CoreException {
return generator.getClasspathEntries(bundle);
}
}