You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicemix.apache.org by ge...@apache.org on 2008/09/29 14:19:53 UTC
svn commit: r700088 - in
/servicemix/maven-plugins/features-maven-plugin/trunk: pom.xml
src/main/java/org/apache/servicemix/tooling/features/GenerateFeaturesXmlMojo.java
Author: gertv
Date: Mon Sep 29 05:19:52 2008
New Revision: 700088
URL: http://svn.apache.org/viewvc?rev=700088&view=rev
Log:
SMX4-49: Looking at the OSGi imports for determining the bundles to use
Added:
servicemix/maven-plugins/features-maven-plugin/trunk/src/main/java/org/apache/servicemix/tooling/features/GenerateFeaturesXmlMojo.java
Modified:
servicemix/maven-plugins/features-maven-plugin/trunk/pom.xml
Modified: servicemix/maven-plugins/features-maven-plugin/trunk/pom.xml
URL: http://svn.apache.org/viewvc/servicemix/maven-plugins/features-maven-plugin/trunk/pom.xml?rev=700088&r1=700087&r2=700088&view=diff
==============================================================================
--- servicemix/maven-plugins/features-maven-plugin/trunk/pom.xml (original)
+++ servicemix/maven-plugins/features-maven-plugin/trunk/pom.xml Mon Sep 29 05:19:52 2008
@@ -49,7 +49,7 @@
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <version>1.4.1</version>
+ <version>1.4.3</version>
</dependency>
<dependency>
<groupId>org.jmock</groupId>
Added: servicemix/maven-plugins/features-maven-plugin/trunk/src/main/java/org/apache/servicemix/tooling/features/GenerateFeaturesXmlMojo.java
URL: http://svn.apache.org/viewvc/servicemix/maven-plugins/features-maven-plugin/trunk/src/main/java/org/apache/servicemix/tooling/features/GenerateFeaturesXmlMojo.java?rev=700088&view=auto
==============================================================================
--- servicemix/maven-plugins/features-maven-plugin/trunk/src/main/java/org/apache/servicemix/tooling/features/GenerateFeaturesXmlMojo.java (added)
+++ servicemix/maven-plugins/features-maven-plugin/trunk/src/main/java/org/apache/servicemix/tooling/features/GenerateFeaturesXmlMojo.java Mon Sep 29 05:19:52 2008
@@ -0,0 +1,401 @@
+/**
+ *
+ * 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.servicemix.tooling.features;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.InvalidArtifactRTException;
+import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
+import org.apache.maven.artifact.metadata.ResolutionGroup;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.osgi.impl.bundle.obr.resource.Manifest;
+import org.osgi.impl.bundle.obr.resource.ManifestEntry;
+import org.osgi.impl.bundle.obr.resource.VersionRange;
+
+/**
+ * Generates the features XML file
+ *
+ * @version $Revision: 1.1 $
+ * @goal generate-features-xml
+ * @phase compile
+ * @execute phase="compile"
+ * @requiresDependencyResolution runtime
+ * @inheritByDefault true
+ * @description Generates the features XML file
+ */
+@SuppressWarnings("unchecked")
+public class GenerateFeaturesXmlMojo extends MojoSupport {
+ protected static final String SEPARATOR = "/";
+
+ /**
+ * The file to generate
+ *
+ * @parameter default-value="${project.build.directory}/classes/feature.xml"
+ */
+ private File outputFile;
+
+ /**
+ * The artifact type for attaching the generated file to the project
+ *
+ * @parameter default-value="xml"
+ */
+ private String attachmentArtifactType = "xml";
+
+ /**
+ * The artifact classifier for attaching the generated file to the project
+ *
+ * @parameter default-value="features"
+ */
+ private String attachmentArtifactClassifier = "features";
+
+ /**
+ * The kernel version for which to generate the bundle
+ *
+ * @parameter
+ */
+ private String kernelVersion;
+
+ /*
+ * A list of packages exported by the kernel
+ */
+ private Map<String, VersionRange> kernelExports = new HashMap<String, VersionRange>();
+
+ /**
+ * A file containing the list of bundles
+ *
+ * @parameter
+ */
+ private File bundles;
+
+ /*
+ * A list of exports by the bundles
+ */
+ private Map<String, Map<VersionRange, Artifact>> bundleExports = new HashMap<String, Map<VersionRange, Artifact>>();
+
+ private String[] systemExports = {"javax.crypto", "javax.crypto.spec", "javax.management", "javax.management.loading",
+ "javax.management.modelmbean", "javax.management.monitor", "javax.management.remote",
+ "javax.net", "javax.net.ssl", "javax.security.cert", "javax.sql", "javax.naming",
+ "javax.naming.spi", "javax.xml.bind.annotation", "javax.xml.namespace", "javax.xml.parsers",
+ "javax.xml.stream", "javax.xml.transform", "javax.xml.transform.dom",
+ "javax.xml.transform.sax", "javax.xml.transform.stream", "javax.xml.validation",
+ "javax.xml.xpath", "org.osgi.framework", "org.w3c.dom", "org.xml.sax", "org.xml.sax.ext",
+ "org.xml.sax.helpers"};
+
+ /*
+ * These bundles are the features that will be built
+ */
+ private Set<Artifact> features = new HashSet<Artifact>();
+
+ public void execute() throws MojoExecutionException, MojoFailureException {
+ PrintStream out = null;
+ try {
+ out = new PrintStream(new FileOutputStream(outputFile));
+ readKernelBundles();
+ readBundles();
+ writeFeatures(out);
+ // now lets attach it
+ projectHelper.attachArtifact(project, attachmentArtifactType, attachmentArtifactClassifier, outputFile);
+ } catch (Exception e) {
+ getLog().error(e);
+ throw new MojoExecutionException("Unable to create features.xml file: " + e, e);
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ }
+ }
+
+ /*
+ * Download a Kernel distro and check the list of bundles provided by the Kernel
+ */
+ private void readKernelBundles() throws ArtifactResolutionException, ArtifactNotFoundException, MojoExecutionException,
+ ZipException, IOException {
+ getLog().info("Step 1 : building list of kernel exports");
+ Artifact kernel = factory.createArtifact("org.apache.servicemix.kernel", "apache-servicemix-kernel", kernelVersion,
+ Artifact.SCOPE_PROVIDED, "pom");
+ resolver.resolve(kernel, remoteRepos, localRepo);
+ for (Artifact artifact : getDependencies(kernel)) {
+ Manifest manifest = getManifest(artifact);
+ if (manifest.getExports() != null) {
+ for (ManifestEntry entry : (List<ManifestEntry>)manifest.getExports()) {
+ kernelExports.put(entry.getName(), entry.getVersion());
+ getLog().debug(" adding kernel export " + entry.getName() + " (" + entry.getVersion() + ")");
+ }
+ }
+ }
+ getLog().info("...done!");
+ }
+
+ /*
+ * Read the list of bundles we can use to satisfy links
+ */
+ private void readBundles() throws IOException, ArtifactResolutionException, ArtifactNotFoundException {
+ getLog().info("Step 2 : Building a list of exports for bundles in " + bundles.getAbsolutePath());
+ BufferedReader reader = null;
+ try {
+ if (bundles != null) {
+ reader = new BufferedReader(new FileReader(bundles));
+ String line = reader.readLine();
+ while (line != null) {
+ if (line.contains("/") && !line.startsWith("#")) {
+ String[] elements = line.split("/");
+ Artifact artifact = factory.createArtifact(elements[0], elements[1], elements[2], Artifact.SCOPE_PROVIDED,
+ elements[3]);
+ registerBundle(artifact);
+ }
+ line = reader.readLine();
+ }
+ }
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+ getLog().info("...done!");
+ }
+
+ /*
+ * Write all project dependencies as feature
+ */
+ private void writeFeatures(PrintStream out) throws ArtifactResolutionException, ArtifactNotFoundException,
+ ZipException, IOException {
+ getLog().info("Step 3 : Generating " + outputFile.getAbsolutePath());
+ out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ out.println("<features>");
+ Set<Artifact> dependencies = (Set<Artifact>)project.getDependencyArtifacts();
+ for (Artifact artifact : dependencies) {
+ getLog().info(" Generating feature " + artifact.getArtifactId() + " from " + artifact);
+ getFeature(artifact).write(out);
+ registerFeature(artifact);
+ }
+ out.println("</features>");
+ getLog().info("...done!");
+ }
+
+ /*
+ * Get the feature for an artifact
+ */
+ private Feature getFeature(Artifact artifact) throws ArtifactResolutionException, ArtifactNotFoundException, ZipException, IOException {
+ Feature feature = new Feature(artifact);
+ addRequirements(artifact, feature);
+ return feature;
+ }
+
+ /*
+ * Add requirements for an artifact to a feature
+ */
+ private void addRequirements(Artifact artifact, Feature feature) throws ArtifactResolutionException, ArtifactNotFoundException, ZipException, IOException {
+ Manifest manifest = getManifest(artifact);
+ Collection<ManifestEntry> remaining = getRemainingImports(manifest);
+ for (ManifestEntry entry : remaining) {
+ Artifact add = null;
+ Map<VersionRange, Artifact> versions = bundleExports.get(entry.getName());
+ if (versions != null) {
+ for (VersionRange range : versions.keySet()) {
+ add = versions.get(range);
+ if (range.compareTo(entry.getVersion()) == 0) {
+ add = versions.get(range);
+ }
+ }
+ }
+ if (add == null) {
+ if (isOptional(entry)) {
+ // debug logging for optional dependency...
+ getLog().debug(String.format(" Unable to find suitable bundle for optional dependency %s (%s)",
+ entry.getName(), entry.getVersion()));
+ } else {
+ // ...but a warning for a mandatory dependency
+ getLog().warn(
+ String.format(" Unable to find suitable bundle for dependency %s (%s)",
+ entry.getName(), entry.getVersion()));
+ }
+ } else {
+ if (feature.push(add) && !isFeature(add)) {
+ //and get requirements for the bundle we just added
+ getLog().debug(" Getting requirements for " + add);
+ addRequirements(add, feature);
+ }
+ }
+ }
+ }
+
+ /*
+ * Check if a given bundle is itself being generated as a feature
+ */
+ private boolean isFeature(Artifact artifact) {
+ return features.contains(artifact);
+ }
+
+ /*
+ * Check a manifest entry and check if the resolution for the import has been marked as optional
+ */
+ private boolean isOptional(ManifestEntry entry) {
+ return entry.getAttributes() != null && entry.getAttributes().get("resolution:") != null
+ && entry.getAttributes().get("resolution:").equals("optional");
+ }
+
+ /*
+ * Register a bundle, enlisting all packages it provides
+ */
+ private void registerBundle(Artifact artifact) throws ArtifactResolutionException, ArtifactNotFoundException, ZipException,
+ IOException {
+ getLog().debug("Registering bundle " + artifact);
+ Manifest manifest = getManifest(artifact);
+ for (ManifestEntry entry : getManifestEntries(manifest.getExports())) {
+ Map<VersionRange, Artifact> versions = bundleExports.get(entry.getName());
+ if (versions == null) {
+ versions = new HashMap<VersionRange, Artifact>();
+ }
+ versions.put(entry.getVersion(), artifact);
+ getLog().debug(String.format(" %s exported by bundle %s", entry.getName(), artifact));
+ bundleExports.put(entry.getName(), versions);
+ }
+ }
+
+ /*
+ * Register a feature and also register the bundle for the feature
+ */
+ private void registerFeature(Artifact artifact) throws ArtifactResolutionException, ArtifactNotFoundException, ZipException,
+ IOException {
+ features.add(artifact);
+ registerBundle(artifact);
+ }
+
+ /*
+ * Determine the list of imports to be resolved
+ */
+ private Collection<ManifestEntry> getRemainingImports(Manifest manifest) {
+ // take all imports
+ Collection<ManifestEntry> input = getManifestEntries(manifest.getImports());
+ Collection<ManifestEntry> output = new LinkedList<ManifestEntry>(input);
+ // remove imports satisfied by exports in the same bundle
+ for (ManifestEntry entry : input) {
+ for (ManifestEntry export : getManifestEntries(manifest.getExports())) {
+ if (entry.getName().equals(export.getName())) {
+ output.remove(entry);
+ }
+ }
+ }
+ // remove imports for packages exported by the kernel
+ for (ManifestEntry entry : input) {
+ for (String export : kernelExports.keySet()) {
+ if (entry.getName().equals(export)) {
+ output.remove(entry);
+ }
+ }
+ }
+ // remove imports for packages exported by the system bundle
+ for (ManifestEntry entry : input) {
+ for (String export : systemExports) {
+ if (entry.getName().equals(export)) {
+ output.remove(entry);
+ }
+ }
+ }
+ return output;
+ }
+
+ private Collection<ManifestEntry> getManifestEntries(List imports) {
+ if (imports == null) {
+ return new LinkedList<ManifestEntry>();
+ } else {
+ return (Collection<ManifestEntry>)imports;
+ }
+ }
+
+ private Manifest getManifest(Artifact artifact) throws ArtifactResolutionException, ArtifactNotFoundException, ZipException,
+ IOException {
+ resolver.resolve(artifact, remoteRepos, localRepo);
+ ZipFile file = new ZipFile(artifact.getFile());
+ ZipEntry entry = file.getEntry("META-INF/MANIFEST.MF");
+ Manifest manifest = new Manifest(file.getInputStream(entry));
+ return manifest;
+ }
+
+ private List<Artifact> getDependencies(Artifact artifact) {
+ List<Artifact> list = new ArrayList<Artifact>();
+ try {
+ ResolutionGroup pom = artifactMetadataSource.retrieve(artifact, localRepo, remoteRepos);
+ if (pom != null) {
+ list.addAll(pom.getArtifacts());
+ }
+ } catch (ArtifactMetadataRetrievalException e) {
+ getLog().warn("Unable to retrieve metadata for " + artifact + ", not including dependencies for it");
+ } catch (InvalidArtifactRTException e) {
+ getLog().warn("Unable to retrieve metadata for " + artifact + ", not including dependencies for it");
+ }
+ return list;
+ }
+
+
+ private class Feature {
+
+ private Stack<Artifact> artifacts = new Stack<Artifact>();
+ private final Artifact artifact;
+
+ private Feature(Artifact artifact) {
+ super();
+ this.artifact = artifact;
+ artifacts.push(artifact);
+ }
+
+ public boolean push(Artifact item) {
+ if (!artifacts.contains(item)) {
+ artifacts.push(item);
+ return true;
+ }
+ return false;
+ }
+
+ public void write(PrintStream out) {
+ out.println(" <feature name='" + artifact.getArtifactId() + "'>");
+ while (!artifacts.isEmpty()) {
+ Artifact next = artifacts.pop();
+ if (isFeature(next)) {
+ out.println(String.format(" <feature>%s</feature>", artifact.getArtifactId()));
+ } else {
+ out.println(String.format(" <bundle>mvn:%s/%s/%s</feature>",
+ artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()));
+ }
+ }
+ out.println(" </feature>");
+ }
+
+ }
+}