From e5b3d42a7aeb65c1f8885f8241a8ad482d8dc54d Mon Sep 17 00:00:00 2001 From: rfeng Date: Thu, 2 Apr 2009 19:21:11 +0000 Subject: [maven-release-plugin] copy for tag maven-eclipse-compiler-1.0.1 git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@761386 13f79535-47bb-0310-9956-ffa450edef68 --- .../maven/compiler/osgi/BundleResolver.java | 490 +++++++++++++++++++++ 1 file changed, 490 insertions(+) create mode 100644 maven-plugins/tags/maven-eclipse-compiler-1.0.1/src/main/java/org/apache/tuscany/maven/compiler/osgi/BundleResolver.java (limited to 'maven-plugins/tags/maven-eclipse-compiler-1.0.1/src/main/java/org/apache/tuscany/maven/compiler/osgi/BundleResolver.java') diff --git a/maven-plugins/tags/maven-eclipse-compiler-1.0.1/src/main/java/org/apache/tuscany/maven/compiler/osgi/BundleResolver.java b/maven-plugins/tags/maven-eclipse-compiler-1.0.1/src/main/java/org/apache/tuscany/maven/compiler/osgi/BundleResolver.java new file mode 100644 index 0000000000..e31c29ead4 --- /dev/null +++ b/maven-plugins/tags/maven-eclipse-compiler-1.0.1/src/main/java/org/apache/tuscany/maven/compiler/osgi/BundleResolver.java @@ -0,0 +1,490 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.maven.compiler.osgi; + +import static org.eclipse.osgi.service.resolver.ResolverError.IMPORT_PACKAGE_USES_CONFLICT; +import static org.eclipse.osgi.service.resolver.ResolverError.MISSING_FRAGMENT_HOST; +import static org.eclipse.osgi.service.resolver.ResolverError.MISSING_IMPORT_PACKAGE; +import static org.eclipse.osgi.service.resolver.ResolverError.MISSING_REQUIRE_BUNDLE; +import static org.eclipse.osgi.service.resolver.ResolverError.REQUIRE_BUNDLE_USES_CONFLICT; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.logging.Logger; +import org.eclipse.osgi.service.resolver.BundleDescription; +import org.eclipse.osgi.service.resolver.BundleSpecification; +import org.eclipse.osgi.service.resolver.ExportPackageDescription; +import org.eclipse.osgi.service.resolver.HostSpecification; +import org.eclipse.osgi.service.resolver.ImportPackageSpecification; +import org.eclipse.osgi.service.resolver.ResolverError; +import org.eclipse.osgi.service.resolver.State; +import org.eclipse.osgi.service.resolver.StateObjectFactory; +import org.eclipse.osgi.service.resolver.VersionConstraint; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; + +public class BundleResolver { + private static final String PROP_MAVEN_PROJECT = "MavenProject"; + private static final String PROP_MANIFEST = "BundleManifest"; + + private StateObjectFactory factory = StateObjectFactory.defaultFactory; + private State state; + private long id = 0; + private Logger logger; + + public static BundleDescription[] getDependentBundles(BundleDescription root) { + if (root == null) + return new BundleDescription[0]; + BundleDescription[] imported = getImportedBundles(root); + BundleDescription[] required = getRequiredBundles(root); + BundleDescription[] dependents = new BundleDescription[imported.length + required.length]; + System.arraycopy(imported, 0, dependents, 0, imported.length); + System.arraycopy(required, 0, dependents, imported.length, required.length); + return dependents; + } + + public static BundleDescription[] getImportedBundles(BundleDescription root) { + if (root == null) + return new BundleDescription[0]; + ExportPackageDescription[] packages = root.getResolvedImports(); + List resolvedImports = new ArrayList(packages.length); + for (int i = 0; i < packages.length; i++) + if (!root.getLocation().equals(packages[i].getExporter().getLocation()) && !resolvedImports + .contains(packages[i].getExporter())) + resolvedImports.add(packages[i].getExporter()); + return (BundleDescription[])resolvedImports.toArray(new BundleDescription[resolvedImports.size()]); + } + + public static BundleDescription[] getRequiredBundles(BundleDescription root) { + if (root == null) + return new BundleDescription[0]; + return root.getResolvedRequires(); + } + + public BundleResolver(Logger logger) { + this.logger = logger; + this.state = factory.createState(true); + Properties props = new Properties(); + props.putAll(System.getProperties()); + BundleUtil.loadVMProfile(props); + state.setPlatformProperties(props); + URL url = Bundle.class.getProtectionDomain().getCodeSource().getLocation(); + + File osgi = toFile(url); + try { + addBundle(osgi); + } catch (BundleException e) { + throw new IllegalArgumentException(e); + } + } + + private long getNextId() { + return ++id; + } + + public BundleDescription addBundle(File bundleLocation) throws BundleException { + return addBundle(bundleLocation, false); + } + + public BundleDescription addBundle(File bundleLocation, boolean override) throws BundleException { + if (bundleLocation == null || !bundleLocation.exists()) + throw new IllegalArgumentException("bundleLocation not found: " + bundleLocation); + Dictionary manifest = loadManifestAttributes(bundleLocation); + if (manifest == null) { + // throw new BundleException("manifest not found in " + bundleLocation); + return null; + } + return addBundle(manifest, bundleLocation, override); + } + + public BundleDescription addBundle(File manifestLocation, File bundleLocation, boolean override) + throws BundleException { + if (bundleLocation == null || !bundleLocation.exists()) + throw new IllegalArgumentException("bundleLocation not found: " + bundleLocation); + Dictionary manifest = loadManifestAttributes(manifestLocation); + if (manifest == null) + throw new IllegalArgumentException("manifest not found in " + manifestLocation); + return addBundle(manifest, bundleLocation, override); + } + + private Dictionary loadManifestAttributes(File bundleLocation) { + Manifest m = loadManifest(bundleLocation); + if (m == null) { + return null; + } + + return manifestToProperties(m.getMainAttributes()); + } + + public Manifest loadManifest(File bundleLocation) { + try { + return BundleUtil.getManifest(bundleLocation); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + private Properties manifestToProperties(Attributes d) { + Iterator iter = d.keySet().iterator(); + Properties result = new Properties(); + while (iter.hasNext()) { + Attributes.Name key = (Attributes.Name)iter.next(); + result.put(key.toString(), d.get(key)); + } + return result; + } + + private BundleDescription addBundle(Dictionary enhancedManifest, File bundleLocation, boolean override) + throws BundleException { + + BundleDescription descriptor = + factory.createBundleDescription(state, enhancedManifest, bundleLocation.getAbsolutePath(), getNextId()); + + setUserProperty(descriptor, PROP_MANIFEST, enhancedManifest); + if (override) { + BundleDescription[] conflicts = state.getBundles(descriptor.getSymbolicName()); + if (conflicts != null) { + for (BundleDescription conflict : conflicts) { + state.removeBundle(conflict); + logger + .warn(conflict.toString() + " has been replaced by another bundle with the same symbolic name " + + descriptor.toString()); + } + } + } + + state.addBundle(descriptor); + return descriptor; + } + + public BundleDescription getResolvedBundle(String bundleId) { + BundleDescription[] description = state.getBundles(bundleId); + if (description == null) + return null; + for (int i = 0; i < description.length; i++) { + if (description[i].isResolved()) + return description[i]; + } + return null; + } + + public void resolveState() { + state.resolve(false); + + if (logger.isDebugEnabled()) { + StringBuilder sb = new StringBuilder("Resolved OSGi state\n"); + for (BundleDescription bundle : state.getBundles()) { + if (!bundle.isResolved()) { + sb.append("[X] "); + } else { + sb.append("[V] "); + } + sb.append(bundle).append(": (").append(bundle.getLocation()); + sb.append(")\n"); + for (ResolverError error : state.getResolverErrors(bundle)) { + sb.append(" ").append(error.toString()).append('\n'); + } + } + logger.debug(sb.toString()); + } + } + + public State getState() { + return state; + } + + public BundleDescription[] getBundles() { + return state.getBundles(); + } + + public ResolverError[] getResolverErrors(BundleDescription bundle) { + Set errors = new LinkedHashSet(); + getRelevantErrors(errors, bundle); + return (ResolverError[])errors.toArray(new ResolverError[errors.size()]); + } + + private void getRelevantErrors(Set errors, BundleDescription bundle) { + ResolverError[] bundleErrors = state.getResolverErrors(bundle); + for (int j = 0; j < bundleErrors.length; j++) { + ResolverError error = bundleErrors[j]; + errors.add(error); + + VersionConstraint constraint = error.getUnsatisfiedConstraint(); + if (constraint instanceof BundleSpecification || constraint instanceof HostSpecification) { + BundleDescription[] requiredBundles = state.getBundles(constraint.getName()); + for (int i = 0; i < requiredBundles.length; i++) { + getRelevantErrors(errors, requiredBundles[i]); + } + } + } + } + + private void logError(BundleDescription bundle, int level, Object object) { + StringBuffer msg = new StringBuffer(); + for (int i = 0; i < level; i++) { + msg.append("--"); + } + msg.append("> [").append(bundle.getSymbolicName()).append("] "); + msg.append(object); + logger.error(msg.toString()); + } + + public void analyzeErrors(BundleDescription bundle) { + analyzeErrors(bundle, new HashSet(), 1); + } + + private void analyzeErrors(BundleDescription bundle, Set bundles, int level) { + if (bundles.contains(bundle)) { + return; + } + bundles.add(bundle); + ResolverError[] errors = state.getResolverErrors(bundle); + for (ResolverError error : errors) { + logError(bundle, level, error); + VersionConstraint constraint = error.getUnsatisfiedConstraint(); + switch (error.getType()) { + case MISSING_IMPORT_PACKAGE: + ImportPackageSpecification pkgSpec = (ImportPackageSpecification)constraint; + for (BundleDescription b : getBundles()) { + for (ExportPackageDescription pkg : b.getExportPackages()) { + if (pkg.getName().equals(pkgSpec.getName())) { + if (pkgSpec.getVersionRange().isIncluded(pkg.getVersion())) { + if (!pkg.getExporter().isResolved()) { + logError(b, level, "Bundle unresolved: " + pkg); + analyzeErrors(pkg.getExporter(), bundles, level + 1); + } + } else { + logError(b, level, "Version mismatch: " + pkgSpec + " " + pkg); + } + } + } + } + break; + case MISSING_REQUIRE_BUNDLE: + case MISSING_FRAGMENT_HOST: + // BundleSpecification bundleSpec = (BundleSpecification)constraint; + for (BundleDescription b : getBundles()) { + if (b == bundle) { + continue; + } + if (b.getSymbolicName().equals(constraint.getName())) { + if (constraint.getVersionRange().isIncluded(b.getVersion())) { + // There must be something wrong in the bundle + analyzeErrors(b, bundles, level); + } else { + logError(bundle, level, "Version mismatch: " + constraint + " " + b); + } + } + } + break; + case IMPORT_PACKAGE_USES_CONFLICT: + case REQUIRE_BUNDLE_USES_CONFLICT: + default: + logger.error(reportErrors(bundle)); + break; + } + } + + } + + public Set getAllErrors() { + BundleDescription[] bundles = state.getBundles(); + Set errors = new LinkedHashSet(); + for (int i = 0; i < bundles.length; i++) { + BundleDescription bundle = bundles[i]; + ResolverError[] bundleErrors = state.getResolverErrors(bundle); + if (bundleErrors != null) { + errors.addAll(Arrays.asList(bundleErrors)); + } + } + return errors; + } + + public List getDependencies(BundleDescription desc) { + Set bundleIds = new LinkedHashSet(); + addBundleAndDependencies(desc, bundleIds, true); + List dependencies = new ArrayList(); + for (long bundleId : bundleIds) { + if (desc.getBundleId() != bundleId) { + BundleDescription dependency = state.getBundle(bundleId); + BundleDescription supplier = dependency.getSupplier().getSupplier(); + HostSpecification host = supplier.getHost(); + if (host == null || !desc.equals(host.getSupplier())) { + dependencies.add(dependency); + } + } + } + return dependencies; + } + + /** + * Code below is copy&paste from org.eclipse.pde.internal.core.DependencyManager + * which seems to calculate runtime dependencies. In particular, it adds + * fragments' dependencies to the host bundle (see TychoTest#testFragment unit test). + * This may or may not cause problems... + * + * RequiredPluginsClasspathContainer#computePluginEntries has the logic to + * calculate compile-time dependencies in IDE. + * + * TODO find the code used by PDE/Build + */ + private static void addBundleAndDependencies(BundleDescription desc, Set bundleIds, boolean includeOptional) { + if (desc != null && bundleIds.add(new Long(desc.getBundleId()))) { + BundleSpecification[] required = desc.getRequiredBundles(); + for (int i = 0; i < required.length; i++) { + if (includeOptional || !required[i].isOptional()) + addBundleAndDependencies((BundleDescription)required[i].getSupplier(), bundleIds, includeOptional); + } + ImportPackageSpecification[] importedPkgs = desc.getImportPackages(); + for (int i = 0; i < importedPkgs.length; i++) { + ExportPackageDescription exporter = (ExportPackageDescription)importedPkgs[i].getSupplier(); + // Continue if the Imported Package is unresolved of the package is optional and don't want optional packages + if (exporter == null || (!includeOptional && Constants.RESOLUTION_OPTIONAL.equals(importedPkgs[i] + .getDirective(Constants.RESOLUTION_DIRECTIVE)))) + continue; + addBundleAndDependencies(exporter.getExporter(), bundleIds, includeOptional); + } + BundleDescription[] fragments = desc.getFragments(); + for (int i = 0; i < fragments.length; i++) { + if (!fragments[i].isResolved()) + continue; + String id = fragments[i].getSymbolicName(); + if (!"org.eclipse.ui.workbench.compatibility".equals(id)) //$NON-NLS-1$ + addBundleAndDependencies(fragments[i], bundleIds, includeOptional); + } + HostSpecification host = desc.getHost(); + if (host != null) + addBundleAndDependencies((BundleDescription)host.getSupplier(), bundleIds, includeOptional); + } + } + + public BundleDescription getBundleDescription(MavenProject project) { + String location = project.getFile().getParentFile().getAbsolutePath(); + return state.getBundleByLocation(location); + } + + public BundleDescription getBundleDescription(File location) { + String absolutePath = location.getAbsolutePath(); + return state.getBundleByLocation(absolutePath); + } + + private static void setUserProperty(BundleDescription desc, String name, Object value) { + Object userObject = desc.getUserObject(); + + if (userObject != null && !(userObject instanceof Map)) { + throw new IllegalStateException("Unexpected user object " + desc.toString()); + } + + Map props = (Map)userObject; + if (props == null) { + props = new HashMap(); + desc.setUserObject(props); + } + + props.put(name, value); + } + + private static Object getUserProperty(BundleDescription desc, String name) { + Object userObject = desc.getUserObject(); + if (userObject instanceof Map) { + return ((Map)userObject).get(name); + } + return null; + } + + public MavenProject getMavenProject(BundleDescription desc) { + return (MavenProject)getUserProperty(desc, PROP_MAVEN_PROJECT); + } + + public void assertResolved(BundleDescription desc) throws BundleException { + if (!desc.isResolved()) { + throw new BundleException("Bundle cannot be resolved: " + desc); + } + } + + public String reportErrors(BundleDescription desc) { + StringBuffer msg = new StringBuffer(); + msg.append("Bundle ").append(desc.getSymbolicName()).append(" cannot be resolved: \n"); + BundleDescription[] bundles = state.getBundles(); + int index = 0; + for (BundleDescription b : bundles) { + if (b.isResolved()) { + continue; + } + ResolverError[] errors = state.getResolverErrors(b); + if (errors.length > 0) { + msg.append(" ").append("[").append(index++).append("] ").append(b.getSymbolicName()).append("\n"); + } + for (int i = 0; i < errors.length; i++) { + ResolverError error = errors[i]; + msg.append(" -->").append(error).append("\n"); + } + } + return msg.toString(); + } + + public String getManifestAttribute(BundleDescription desc, String attr) { + Dictionary mf = (Dictionary)getUserProperty(desc, PROP_MANIFEST); + if (mf != null) { + return (String)mf.get(attr); + } + return null; + } + + private static File toFile(URL url) { + if (url.getProtocol().equals("file") == false) { + return null; + } else { + String filename = url.getFile().replace('/', File.separatorChar).replace("%20", " "); + return new File(filename); + } + } + + /* + public static void main(String[] args) throws Exception { + BundleResolver resolver = new BundleResolver(new ConsoleLogger(Logger.LEVEL_INFO, "tuscany")); + + String home = System.getProperty("user.home"); + File jar = + new File(new File(home), + ".m2/repository/org/apache/tuscany/sca/tuscany-sca-api/1.4-EQUINOX-SNAPSHOT/tuscany-sca-api-1.4-EQUINOX-SNAPSHOT.jar"); + BundleDescription bundle = resolver.addBundle(jar); + resolver.resolveState(); + resolver.assertResolved(bundle); + } + */ +} -- cgit v1.2.3