blob: b29e50926d5d7ee4295d469b03e0528584e1bc1f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014 Igor Fedorenko
* All rights reserved. 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:
* Igor Fedorenko - initial API and implementation
*******************************************************************************/
package org.eclipse.m2e.core.internal;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.framework.namespace.BundleNamespace;
import org.osgi.framework.namespace.PackageNamespace;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleWire;
import org.osgi.framework.wiring.BundleWiring;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.m2e.core.internal.equinox.DevClassPathHelper;
/**
* @since 1.5
*/
public class Bundles {
private static final Logger log = LoggerFactory.getLogger(Bundles.class);
private static Bundle findDependencyBundle(Bundle bundle, String dependencyName, Set<Bundle> visited) {
BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
if(bundleWiring == null) {
return null;
}
ArrayList<BundleWire> dependencies = new ArrayList<BundleWire>();
dependencies.addAll(bundleWiring.getRequiredWires(BundleNamespace.BUNDLE_NAMESPACE));
dependencies.addAll(bundleWiring.getRequiredWires(PackageNamespace.PACKAGE_NAMESPACE));
for(BundleWire wire : dependencies) {
Bundle requiredBundle = wire.getProviderWiring().getBundle();
if(requiredBundle != null && visited.add(requiredBundle)) {
if(dependencyName.equals(requiredBundle.getSymbolicName())) {
return requiredBundle;
}
Bundle required = findDependencyBundle(requiredBundle, dependencyName, visited);
if(required != null) {
return required;
}
}
}
return null;
}
public static Bundle findDependencyBundle(Bundle bundle, String dependencyId) {
return findDependencyBundle(bundle, dependencyId, new HashSet<Bundle>());
}
public static ClassLoader getBundleClassloader(Bundle bundle) {
BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
if(bundleWiring == null) {
return null;
}
return bundleWiring.getClassLoader();
}
public static List<String> getClasspathEntries(Bundle bundle) {
log.debug("getClasspathEntries(Bundle={})", bundle.toString());
Set<String> cp = new LinkedHashSet<String>();
if(DevClassPathHelper.inDevelopmentMode()) {
cp.addAll(Arrays.asList(DevClassPathHelper.getDevClassPath(bundle.getSymbolicName())));
}
cp.addAll(Arrays.asList(parseBundleClasspath(bundle)));
List<String> entries = new ArrayList<>();
for(String cpe : cp) {
String entry;
if(".".equals(cpe)) {
entry = getNestedJarOrDir(bundle, "/");
} else {
entry = getNestedJarOrDir(bundle, cpe);
}
if(entry != null) {
entry = new Path(entry).toOSString();
log.debug("\tEntry:{}", entry);
entries.add(entry);
}
}
return entries;
}
private static String[] parseBundleClasspath(Bundle bundle) {
String[] result = new String[] {"."};
String header = bundle.getHeaders().get(Constants.BUNDLE_CLASSPATH);
ManifestElement[] classpathEntries = null;
try {
classpathEntries = ManifestElement.parseHeader(Constants.BUNDLE_CLASSPATH, header);
} catch(BundleException ex) {
log.warn("Could not parse bundle classpath of {}", bundle.toString(), ex);
}
if(classpathEntries != null) {
result = new String[classpathEntries.length];
for(int i = 0; i < classpathEntries.length; i++ ) {
result[i] = classpathEntries[i].getValue();
}
}
return result;
}
private static String getNestedJarOrDir(Bundle bundle, String cp) {
// try embeded entries first
URL url = bundle.getEntry(cp);
if(url != null) {
try {
return FileLocator.toFileURL(url).getFile();
} catch(IOException ex) {
log.warn("Could not get entry {} for bundle {}", new Object[] {cp, bundle.toString(), ex});
}
}
// in development mode entries can be absolute paths outside of bundle basedir
if(DevClassPathHelper.inDevelopmentMode()) {
File file = new File(cp);
if(file.exists() && file.isAbsolute()) {
return file.getAbsolutePath();
}
}
log.debug("Bundle {} does not have entry {}", bundle.toString(), cp);
return null;
}
private static Bundle findDependencyBundleByPackage(Bundle bundle, String packageName, Set<Bundle> visited) {
BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
if(bundleWiring == null) {
return null;
}
ArrayList<BundleWire> dependencies = new ArrayList<BundleWire>();
dependencies.addAll(bundleWiring.getRequiredWires(BundleNamespace.BUNDLE_NAMESPACE));
dependencies.addAll(bundleWiring.getRequiredWires(PackageNamespace.PACKAGE_NAMESPACE));
for(BundleWire wire : dependencies) {
BundleCapability cap = wire.getCapability();
String pkg = (String) cap.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE);
Bundle requiredBundle = wire.getProviderWiring().getBundle();
if(requiredBundle != null) {
if(packageName.equals(pkg)) {
return requiredBundle;
}
if(visited.add(requiredBundle)) {
Bundle required = findDependencyBundleByPackage(requiredBundle, packageName, visited);
if(required != null) {
return required;
}
}
}
}
return null;
}
public static Bundle findDependencyBundleByPackage(Bundle bundle, String packageName) {
return findDependencyBundleByPackage(bundle, packageName, new HashSet<Bundle>());
}
}