Applied patch (FELIX-199) to add a recursive goal to generate OSGi
bundles for all dependencies.
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@527194 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/tools/maven2/maven-bundle-plugin/pom.xml b/tools/maven2/maven-bundle-plugin/pom.xml
index 425a8f3..b4f6f7b 100644
--- a/tools/maven2/maven-bundle-plugin/pom.xml
+++ b/tools/maven2/maven-bundle-plugin/pom.xml
@@ -30,13 +30,6 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <repositories>
- <repository>
- <id>aQute</id>
- <url>http://www.aQute.biz/repo</url>
- </repository>
- </repositories>
-
<packaging>maven-plugin</packaging>
<name>Maven Bundle Plugin</name>
<description> provides a maven plugin that allows that builds the jar by
@@ -48,7 +41,7 @@
<dependencies>
<dependency>
<groupId>biz.aQute</groupId>
- <artifactId>bnd</artifactId>
+ <artifactId>bndlib</artifactId>
<version>0.0.116</version>
</dependency>
<dependency>
@@ -59,17 +52,28 @@
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
- <version>2.0</version>
+ <version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-archiver</artifactId>
- <version>2.0</version>
+ <version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
- <version>2.0</version>
+ <version>2.0.6</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.maven.shared</groupId>
+ <artifactId>maven-dependency-tree</artifactId>
+ <version>1.0-alpha-3-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.shared</groupId>
+ <artifactId>maven-plugin-testing-harness</artifactId>
+ <version>1.0-beta-2-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/BundleAllPlugin.java b/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/BundleAllPlugin.java
new file mode 100644
index 0000000..bec3498
--- /dev/null
+++ b/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/BundleAllPlugin.java
@@ -0,0 +1,459 @@
+/*
+ * 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.felix.tools.maven2.bundleplugin;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.ArtifactCollector;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.MavenProjectBuilder;
+import org.apache.maven.project.ProjectBuildingException;
+import org.apache.maven.shared.dependency.tree.DependencyNode;
+import org.apache.maven.shared.dependency.tree.DependencyTree;
+import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder;
+import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException;
+
+import aQute.lib.osgi.Analyzer;
+import aQute.lib.osgi.Jar;
+
+/**
+ *
+ * @goal bundleall
+ * @phase package
+ * @requiresDependencyResolution runtime
+ * @description build an OSGi bundle jar for all transitive dependencies
+ */
+public class BundleAllPlugin
+ extends ManifestPlugin
+{
+
+ private static final Pattern SNAPSHOT_VERSION_PATTERN = Pattern.compile( "[0-9]{8}_[0-9]{6}_[0-9]+" );
+
+ /**
+ * Local Repository.
+ *
+ * @parameter expression="${localRepository}"
+ * @required
+ * @readonly
+ */
+ private ArtifactRepository localRepository;
+
+ /**
+ * Remote repositories
+ *
+ * @parameter expression="${project.remoteArtifactRepositories}"
+ * @required
+ * @readonly
+ */
+ private List remoteRepositories;
+
+ /**
+ * @component
+ */
+ private ArtifactFactory factory;
+
+ /**
+ * @component
+ */
+ private ArtifactMetadataSource artifactMetadataSource;
+
+ /**
+ * @component
+ */
+ private ArtifactCollector collector;
+
+ /**
+ * Artifact resolver, needed to download jars.
+ *
+ * @component
+ */
+ private ArtifactResolver artifactResolver;
+
+ /**
+ * @component
+ */
+ private DependencyTreeBuilder dependencyTreeBuilder;
+
+ /**
+ * @component
+ */
+ private MavenProjectBuilder mavenProjectBuilder;
+
+ public void execute()
+ throws MojoExecutionException
+ {
+ BundleInfo bundleInfo = bundleAll( getProject() );
+ logDuplicatedPackages( bundleInfo );
+ }
+
+ /**
+ * Bundle a project and all its dependencies
+ *
+ * @param project
+ * @throws MojoExecutionException
+ */
+ private BundleInfo bundleAll( MavenProject project )
+ throws MojoExecutionException
+ {
+ return bundleAll( project, Integer.MAX_VALUE );
+ }
+
+ /**
+ * Bundle a project and its transitive dependencies up to some depth level
+ *
+ * @param project
+ * @param depth how deep to process the dependency tree
+ * @throws MojoExecutionException
+ */
+ protected BundleInfo bundleAll( MavenProject project, int depth )
+ throws MojoExecutionException
+ {
+
+ if ( alreadyBundled( project.getArtifact() ) )
+ {
+ getLog().debug( "Ignoring project already processed " + project.getArtifact() );
+ return null;
+ }
+
+ DependencyTree dependencyTree;
+
+ try
+ {
+ dependencyTree = dependencyTreeBuilder.buildDependencyTree( project, localRepository, factory,
+ artifactMetadataSource, collector );
+ }
+ catch ( DependencyTreeBuilderException e )
+ {
+ throw new MojoExecutionException( "Unable to build dependency tree", e );
+ }
+
+ getLog().debug( "Will bundle the following dependency tree\n" + dependencyTree );
+
+ BundleInfo bundleInfo = new BundleInfo();
+
+ for ( Iterator it = dependencyTree.inverseIterator(); it.hasNext(); )
+ {
+ DependencyNode node = (DependencyNode) it.next();
+ if ( !it.hasNext() )
+ {
+ /* this is the root, current project */
+ break;
+ }
+
+ Artifact artifact = resolveArtifact( node.getArtifact() );
+ node.getArtifact().setFile( artifact.getFile() );
+
+ if ( node.getDepth() > depth )
+ {
+ /* node is deeper than we want */
+ getLog().debug( "Ignoring " + node.getArtifact() + ", depth is " + node.getDepth() + ", bigger than " + depth );
+ continue;
+ }
+
+ MavenProject childProject;
+ try
+ {
+ childProject = mavenProjectBuilder.buildFromRepository( artifact, remoteRepositories, localRepository,
+ true );
+ }
+ catch ( ProjectBuildingException e )
+ {
+ throw new MojoExecutionException( "Unable to build project object for artifact " + artifact, e );
+ }
+ childProject.setArtifact( artifact );
+ getLog().debug( "Child project artifact location: " + childProject.getArtifact().getFile() );
+
+ if ( ( artifact.getScope().equals( Artifact.SCOPE_COMPILE ) )
+ || ( artifact.getScope().equals( Artifact.SCOPE_RUNTIME ) ) )
+ {
+ BundleInfo subBundleInfo = bundleAll( childProject, depth - 1 );
+ if ( subBundleInfo != null )
+ {
+ bundleInfo.merge( subBundleInfo );
+ }
+ }
+ else
+ {
+ getLog().debug(
+ "Not processing due to scope (" + childProject.getArtifact().getScope() + "): "
+ + childProject.getArtifact() );
+ }
+ }
+
+ if ( getProject() != project )
+ {
+ getLog().debug( "Project artifact location: " + project.getArtifact().getFile() );
+
+ BundleInfo subBundleInfo = bundle( project );
+ if ( subBundleInfo != null )
+ {
+ bundleInfo.merge( subBundleInfo );
+ }
+ }
+
+ return bundleInfo;
+ }
+
+ /**
+ * Bundle one project only without building its childre
+ *
+ * @param project
+ * @throws MojoExecutionException
+ */
+ BundleInfo bundle( MavenProject project )
+ throws MojoExecutionException
+ {
+ Artifact artifact = project.getArtifact();
+ getLog().info( "Bundling " + artifact );
+
+ try
+ {
+ Map instructions = new HashMap();
+ instructions.put( Analyzer.EXPORT_PACKAGE, "*" );
+
+ project.getArtifact().setFile( getFile( artifact ) );
+ File outputFile = getOutputFile( artifact );
+
+ if ( project.getArtifact().getFile().equals( outputFile ) )
+ {
+ /* TODO find the cause why it's getting here */
+ return null;
+ // getLog().error(
+ // "Trying to read and write " + artifact + " to the same file, try cleaning: "
+ // + outputFile );
+ // throw new IllegalStateException( "Trying to read and write " + artifact
+ // + " to the same file, try cleaning: " + outputFile );
+ }
+
+ Analyzer analyzer = getAnalyzer( project, getClasspath( project ) );
+
+ BundleInfo bundleInfo = addExportedPackages( project, analyzer.getExports().keySet() );
+
+ Jar osgiJar = new Jar( project.getArtifactId(), project.getArtifact().getFile() );
+ Manifest manifest = analyzer.getJar().getManifest();
+ osgiJar.setManifest( manifest );
+ outputFile.getParentFile().mkdirs();
+ osgiJar.write( outputFile );
+
+ return bundleInfo;
+ }
+ /* too bad Jar.write throws Exception */
+ catch ( Exception e )
+ {
+ throw new MojoExecutionException( "Error generating OSGi bundle for project "
+ + getArtifactKey( project.getArtifact() ), e );
+ }
+ }
+
+ private BundleInfo addExportedPackages( MavenProject project, Collection packages )
+ {
+ BundleInfo bundleInfo = new BundleInfo();
+ for ( Iterator it = packages.iterator(); it.hasNext(); )
+ {
+ String packageName = (String) it.next();
+ bundleInfo.addExportedPackage( packageName, project.getArtifact() );
+ }
+ return bundleInfo;
+ }
+
+ private String getArtifactKey( Artifact artifact )
+ {
+ return artifact.getGroupId() + ":" + artifact.getArtifactId();
+ }
+
+ protected String getBundleName( MavenProject project )
+ {
+ return getBundleName( project.getArtifact() );
+ }
+
+ private String getBundleNameFirstPart( Artifact artifact )
+ {
+ return artifact.getGroupId() + "." + artifact.getArtifactId();
+ }
+
+ private String getBundleName( Artifact artifact )
+ {
+ return getBundleNameFirstPart( artifact ) + "_" + convertVersionToOsgi( artifact.getVersion() ) + ".jar";
+ }
+
+ private boolean alreadyBundled( Artifact artifact )
+ {
+ return getBuiltFile( artifact ) != null;
+ }
+
+ /**
+ * Use previously built bundles when available.
+ *
+ * @param artifact
+ */
+ protected File getFile( final Artifact artifact )
+ {
+ File bundle = getBuiltFile( artifact );
+
+ if ( bundle != null )
+ {
+ getLog().debug( "Using previously built OSGi bundle for " + artifact + " in " + bundle );
+ return bundle;
+ }
+ return super.getFile( artifact );
+ }
+
+ private File getBuiltFile( final Artifact artifact )
+ {
+ File bundle = null;
+
+ /* if bundle was already built use it instead of jar from repo */
+ File outputFile = getOutputFile( artifact );
+ if ( outputFile.exists() )
+ {
+ bundle = outputFile;
+ }
+
+ /*
+ * Find snapshots in output folder, eg. 2.1-SNAPSHOT will match 2.1.0.20070207_193904_2
+ * TODO there has to be another way to do this using Maven libs
+ */
+ if ( ( bundle == null ) && artifact.isSnapshot() )
+ {
+ final File buildDirectory = new File( getBuildDirectory() );
+ if ( !buildDirectory.exists() )
+ {
+ buildDirectory.mkdirs();
+ }
+ File[] files = buildDirectory.listFiles( new FilenameFilter()
+ {
+ public boolean accept( File dir, String name )
+ {
+ if ( dir.equals( buildDirectory ) && snapshotMatch( artifact, name ) )
+ {
+ return true;
+ }
+ return false;
+ }
+ } );
+ if ( files.length > 1 )
+ {
+ throw new RuntimeException( "More than one previously built bundle matches for artifact " + artifact
+ + " : " + Arrays.asList( files ) );
+ }
+ if ( files.length == 1 )
+ {
+ bundle = files[0];
+ }
+ }
+
+ return bundle;
+ }
+
+ /**
+ * Check that the bundleName provided correspond to the artifact provided.
+ * Used to determine when the bundle name is a timestamped snapshot and the artifact is a snapshot not timestamped.
+ *
+ * @param artifact artifact with snapshot version
+ * @param bundleName bundle file name
+ * @return if both represent the same artifact and version, forgetting about the snapshot timestamp
+ */
+ boolean snapshotMatch( Artifact artifact, String bundleName )
+ {
+ String artifactBundleName = getBundleName( artifact );
+ int i = artifactBundleName.indexOf( "SNAPSHOT" );
+ if ( i < 0 )
+ {
+ return false;
+ }
+ artifactBundleName = artifactBundleName.substring( 0, i );
+
+ if ( bundleName.startsWith( artifactBundleName ) )
+ {
+ /* it's the same artifact groupId and artifactId */
+ String timestamp = bundleName.substring( artifactBundleName.length(), bundleName.lastIndexOf( ".jar" ) );
+ Matcher m = SNAPSHOT_VERSION_PATTERN.matcher( timestamp );
+ return m.matches();
+ }
+ return false;
+ }
+
+ protected File getOutputFile( Artifact artifact )
+ {
+ return new File( getBuildDirectory(), getBundleName( artifact ) );
+ }
+
+ private Artifact resolveArtifact( Artifact artifact )
+ throws MojoExecutionException
+ {
+ Artifact resolvedArtifact = factory.createArtifact( artifact.getGroupId(), artifact.getArtifactId(), artifact
+ .getVersion(), artifact.getScope(), artifact.getType() );
+
+ try
+ {
+ artifactResolver.resolve( resolvedArtifact, remoteRepositories, localRepository );
+ }
+ catch ( ArtifactNotFoundException e )
+ {
+ throw new MojoExecutionException( "Artifact was not found in the repo" + resolvedArtifact, e );
+ }
+ catch ( ArtifactResolutionException e )
+ {
+ throw new MojoExecutionException( "Error resolving artifact " + resolvedArtifact, e );
+ }
+
+ return resolvedArtifact;
+ }
+
+ /**
+ * Log what packages are exported in more than one bundle
+ */
+ protected void logDuplicatedPackages( BundleInfo bundleInfo )
+ {
+ Map duplicatedExports = bundleInfo.getDuplicatedExports();
+
+ for ( Iterator it = duplicatedExports.entrySet().iterator(); it.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) it.next();
+ String packageName = (String) entry.getKey();
+ Collection artifacts = (Collection) entry.getValue();
+
+ getLog().warn( "Package " + packageName + " is exported in more than a bundle: " );
+ for ( Iterator it2 = artifacts.iterator(); it2.hasNext(); )
+ {
+ Artifact artifact = (Artifact) it2.next();
+ getLog().warn( " " + artifact );
+ }
+
+ }
+ }
+}
diff --git a/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/BundleInfo.java b/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/BundleInfo.java
new file mode 100644
index 0000000..351c702
--- /dev/null
+++ b/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/BundleInfo.java
@@ -0,0 +1,109 @@
+/*
+ * 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.felix.tools.maven2.bundleplugin;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+
+/**
+ * Information result of the bundling process
+ *
+ * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
+ * @version $Id$
+ */
+public class BundleInfo
+{
+
+ /**
+ * {@link Map} < {@link String}, {@link Set} < {@link Artifact} > >
+ * Used to check for duplicated exports. Key is package name and value list of artifacts where it's exported.
+ */
+ private Map exportedPackages = new HashMap();
+
+ public void addExportedPackage( String packageName, Artifact artifact )
+ {
+ Set artifacts = (Set) getExportedPackages().get( packageName );
+ if ( artifacts == null )
+ {
+ artifacts = new HashSet();
+ exportedPackages.put( packageName, artifacts );
+ }
+ artifacts.add( artifact );
+ }
+
+ private Map getExportedPackages()
+ {
+ return exportedPackages;
+ }
+
+ /**
+ * Get a list of packages that are exported in more than one bundle.
+ * Key is package name and value list of artifacts where it's exported.
+ * @return {@link Map} < {@link String}, {@link Set} < {@link Artifact} > >
+ */
+ public Map getDuplicatedExports()
+ {
+ Map duplicatedExports = new HashMap();
+
+ for ( Iterator it = getExportedPackages().entrySet().iterator(); it.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) it.next();
+ Set artifacts = (Set) entry.getValue();
+ if ( artifacts.size() > 1 )
+ {
+ /* remove warnings caused by different versions of same artifact */
+ Set artifactKeys = new HashSet();
+
+ String packageName = (String) entry.getKey();
+ for ( Iterator it2 = artifacts.iterator(); it2.hasNext(); )
+ {
+ Artifact artifact = (Artifact) it2.next();
+ artifactKeys.add( artifact.getGroupId() + "." + artifact.getArtifactId() );
+ }
+
+ if ( artifactKeys.size() > 1 )
+ {
+ duplicatedExports.put( packageName, artifacts );
+ }
+ }
+ }
+
+ return duplicatedExports;
+ }
+
+ public void merge( BundleInfo bundleInfo )
+ {
+ for ( Iterator it = bundleInfo.getExportedPackages().entrySet().iterator(); it.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) it.next();
+ String packageName = (String) entry.getKey();
+ Collection artifacts = (Collection) entry.getValue();
+
+ Collection artifactsWithPackage = (Collection) getExportedPackages().get( packageName );
+ if ( artifactsWithPackage == null )
+ {
+ artifactsWithPackage = new HashSet();
+ getExportedPackages().put( packageName, artifactsWithPackage );
+ }
+ artifactsWithPackage.addAll( artifacts );
+ }
+ }
+}
diff --git a/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/BundlePlugin.java b/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/BundlePlugin.java
index b6bacfe..982fe58 100644
--- a/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/BundlePlugin.java
+++ b/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/BundlePlugin.java
@@ -40,6 +40,15 @@
*/
public class BundlePlugin extends AbstractMojo {
+ /** Bundle-Version must match this pattern */
+ private static final Pattern OSGI_VERSION_PATTERN = Pattern.compile("[0-9]+(\\.[0-9]+(\\.[0-9]+(\\.[0-9A-Za-z_-]+)?)?)?");
+
+ /** pattern used to change - to . */
+ //private static final Pattern P_VERSION = Pattern.compile("([0-9]+(\\.[0-9])*)-(.*)");
+
+ /** pattern that matches strings that contain only numbers */
+ private static final Pattern ONLY_NUMBERS = Pattern.compile("[0-9]+");
+
/**
* @parameter expression="${project.build.outputDirectory}"
* @required
@@ -79,74 +88,50 @@
*/
private Map instructions = new HashMap();
+ protected MavenProject getProject() {
+ return project;
+ }
+
public void execute() throws MojoExecutionException {
+ Properties properties = new Properties();
+
+ if (new File(baseDir, "src/main/resources").exists()) {
+ header(properties, Analyzer.INCLUDE_RESOURCE, "src/main/resources/");
+ }
+
+ execute(project, instructions, properties);
+ }
+
+ protected void execute(MavenProject project, Map instructions, Properties properties) throws MojoExecutionException {
try {
- File jarFile = new File(buildDirectory, project.getBuild()
- .getFinalName()
- + ".jar");
-
- // Setup defaults
+ execute(project, instructions, properties, getClasspath(project));
+ }
+ catch ( IOException e ) {
+ throw new MojoExecutionException("Error calculating classpath for project " + project, e);
+ }
+ }
+
+ protected void execute(MavenProject project, Map instructions, Properties properties, Jar[] classpath) throws MojoExecutionException {
+ try {
+ File jarFile = new File(getBuildDirectory(), getBundleName(project));
+
+ properties.putAll(getDefaultProperties(project));
+
String bsn = project.getGroupId() + "." + project.getArtifactId();
- Properties properties = new Properties();
- properties.put(Analyzer.BUNDLE_SYMBOLICNAME, bsn);
- properties.put(Analyzer.IMPORT_PACKAGE, "*");
if (!instructions.containsKey(Analyzer.PRIVATE_PACKAGE)) {
properties.put(Analyzer.EXPORT_PACKAGE, bsn + ".*");
}
- String version = project.getVersion();
- Pattern P_VERSION = Pattern.compile("([0-9]+(\\.[0-9]+)*)-(.*)");
- Matcher m = P_VERSION.matcher(version);
- if (m.matches()) {
- version = m.group(1) + "." + m.group(3);
- }
- properties.put(Analyzer.BUNDLE_VERSION, version);
- header(properties, Analyzer.BUNDLE_DESCRIPTION, project
- .getDescription());
- header(properties, Analyzer.BUNDLE_LICENSE, printLicenses(project
- .getLicenses()));
- header(properties, Analyzer.BUNDLE_NAME, project.getName());
-
- if (project.getOrganization() != null) {
- header(properties, Analyzer.BUNDLE_VENDOR, project
- .getOrganization().getName());
- if (project.getOrganization().getUrl() != null) {
- header(properties, Analyzer.BUNDLE_DOCURL, project
- .getOrganization().getUrl());
- }
- }
- if (new File(baseDir, "src/main/resources").exists()) {
- header(properties, Analyzer.INCLUDE_RESOURCE, "src/main/resources/");
- }
+ properties.putAll(instructions);
- properties.putAll(project.getProperties());
- properties.putAll(project.getModel().getProperties());
- properties.putAll( getProperies("project.build.", project.getBuild()));
- properties.putAll( getProperies("pom.", project.getModel()));
- properties.putAll( getProperies("project.", project));
- properties.put("project.baseDir", baseDir );
- properties.put("project.build.directory", buildDirectory );
- properties.put("project.build.outputdirectory", outputDirectory );
-
- Iterator i = instructions.entrySet().iterator();
- while (i.hasNext()) {
- Map.Entry e = (Map.Entry)i.next();
- String key = (String)e.getKey();
- if (key.startsWith("_")) {
- key = "-"+key.substring(1);
- }
- properties.put(key, e.getValue());
- }
-
Builder builder = new Builder();
builder.setBase(baseDir);
- Jar[] cp = getClasspath();
builder.setProperties(properties);
- builder.setClasspath(cp);
+ builder.setClasspath(classpath);
builder.build();
Jar jar = builder.getJar();
- doMavenMetadata(jar);
+ doMavenMetadata(project, jar);
builder.setJar(jar);
List errors = builder.getErrors();
@@ -156,7 +141,7 @@
jarFile.delete();
for (Iterator e = errors.iterator(); e.hasNext();) {
String msg = (String) e.next();
- getLog().error(msg);
+ getLog().error("Error building bundle " + project.getArtifact() + " : " + msg);
}
throw new MojoFailureException("Found errors, see log");
}
@@ -167,7 +152,7 @@
}
for (Iterator w = warnings.iterator(); w.hasNext();) {
String msg = (String) w.next();
- getLog().warn(msg);
+ getLog().warn("Warning building bundle " + project.getArtifact() + " : " + msg);
}
}
@@ -177,14 +162,14 @@
}
}
- private Map getProperies(String prefix, Object model) {
+ private Map getProperies(Model projectModel, String prefix, Object model) {
Map properties = new HashMap();
Method methods[] = Model.class.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
String name = methods[i].getName();
if ( name.startsWith("get") ) {
try {
- Object v = methods[i].invoke(project.getModel(), null );
+ Object v = methods[i].invoke(projectModel, null );
if ( v != null ) {
name = prefix + Character.toLowerCase(name.charAt(3)) + name.substring(4);
if ( v.getClass().isArray() )
@@ -221,7 +206,7 @@
* @param jar
* @throws IOException
*/
- private void doMavenMetadata(Jar jar) throws IOException {
+ private void doMavenMetadata(MavenProject project, Jar jar) throws IOException {
String path = "META-INF/maven/" + project.getGroupId() + "/"
+ project.getArtifactId();
File pomFile = new File(baseDir, "pom.xml");
@@ -242,20 +227,24 @@
* @throws ZipException
* @throws IOException
*/
- private Jar[] getClasspath() throws ZipException, IOException {
+ protected Jar[] getClasspath(MavenProject project) throws ZipException, IOException {
List list = new ArrayList();
if (outputDirectory != null && outputDirectory.exists()) {
list.add(new Jar(".", outputDirectory));
}
- Set artifacts = project.getArtifacts();
+ Set artifacts = project.getDependencyArtifacts();
for (Iterator it = artifacts.iterator(); it.hasNext();) {
Artifact artifact = (Artifact) it.next();
if (Artifact.SCOPE_COMPILE.equals(artifact.getScope())
|| Artifact.SCOPE_SYSTEM.equals(artifact.getScope())
|| Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) {
- Jar jar = new Jar(artifact.getArtifactId(), artifact.getFile());
+ File file = getFile(artifact);
+ if (file == null) {
+ throw new RuntimeException("File is not available for artifact " + artifact + " in project " + project.getArtifact());
+ }
+ Jar jar = new Jar(artifact.getArtifactId(), file);
list.add(jar);
}
}
@@ -264,6 +253,15 @@
return cp;
}
+ /**
+ * Get the file for an Artifact
+ *
+ * @param artifact
+ */
+ protected File getFile(Artifact artifact) {
+ return artifact.getFile();
+ }
+
private void header(Properties properties, String key, Object value) {
if (value == null)
return;
@@ -273,4 +271,170 @@
properties.put(key, value.toString());
}
+
+ /**
+ * Convert a Maven version into an OSGi compliant version
+ *
+ * @param version Maven version
+ * @return the OSGi version
+ */
+ protected String convertVersionToOsgi(String version)
+ {
+ String osgiVersion;
+
+// Matcher m = P_VERSION.matcher(version);
+// if (m.matches()) {
+// osgiVersion = m.group(1) + "." + m.group(3);
+// }
+
+ /* TODO need a regexp guru here */
+
+ Matcher m;
+
+ /* if it's already OSGi compliant don't touch it */
+ m = OSGI_VERSION_PATTERN.matcher(version);
+ if (m.matches()) {
+ return version;
+ }
+
+ osgiVersion = version;
+
+ /* check for dated snapshot versions with only major or major and minor */
+ Pattern DATED_SNAPSHOT = Pattern.compile("([0-9])(\\.([0-9]))?(\\.([0-9]))?\\-([0-9]{8}\\.[0-9]{6}\\-[0-9]*)");
+ m = DATED_SNAPSHOT.matcher(osgiVersion);
+ if (m.matches()) {
+ String major = m.group(1);
+ String minor = (m.group(3) != null) ? m.group(3) : "0";
+ String service = (m.group(5) != null) ? m.group(5) : "0";
+ String qualifier = m.group(6).replaceAll( "-", "_" ).replaceAll( "\\.", "_" );
+ osgiVersion = major + "." + minor + "." + service + "." + qualifier;
+ }
+
+ /* else transform first - to . and others to _ */
+ osgiVersion = osgiVersion.replaceFirst( "-", "\\." );
+ osgiVersion = osgiVersion.replaceAll( "-", "_" );
+ m = OSGI_VERSION_PATTERN.matcher(osgiVersion);
+ if (m.matches()) {
+ return osgiVersion;
+ }
+
+ /* remove dots in the middle of the qualifier */
+ Pattern DOTS_IN_QUALIFIER = Pattern.compile("([0-9])(\\.[0-9])?\\.([0-9A-Za-z_-]+)\\.([0-9A-Za-z_-]+)");
+ m = DOTS_IN_QUALIFIER.matcher(osgiVersion);
+ if (m.matches()) {
+ String s1 = m.group(1);
+ String s2 = m.group(2);
+ String s3 = m.group(3);
+ String s4 = m.group(4);
+
+ Matcher qualifierMatcher = ONLY_NUMBERS.matcher( s3 );
+ /* if last portion before dot is only numbers then it's not in the middle of the qualifier */
+ if (!qualifierMatcher.matches()) {
+ osgiVersion = s1 + s2 + "." + s3 + "_" + s4;
+ }
+ }
+
+ /* convert 1.string into 1.0.0.string and 1.2.string into 1.2.0.string */
+ Pattern NEED_TO_FILL_ZEROS = Pattern.compile("([0-9])(\\.([0-9]))?\\.([0-9A-Za-z_-]+)");
+ m = NEED_TO_FILL_ZEROS.matcher(osgiVersion);
+ if (m.matches()) {
+ String major = m.group(1);
+ String minor = ( m.group( 3 ) != null ) ? m.group( 3 ) : "0";
+ String service = "0";
+ String qualifier = m.group(4);
+
+ Matcher qualifierMatcher = ONLY_NUMBERS.matcher( qualifier );
+ /* if last portion is only numbers then it's not a qualifier */
+ if (!qualifierMatcher.matches()) {
+ osgiVersion = major + "." + minor + "." + service + "." + qualifier;
+ }
+ }
+
+ m = OSGI_VERSION_PATTERN.matcher(osgiVersion);
+ /* if still its not OSGi version then add everything as qualifier */
+ if (!m.matches()) {
+ String major = "0";
+ String minor = "0";
+ String service = "0";
+ String qualifier = osgiVersion.replaceAll( "\\.", "_" );
+ osgiVersion = major + "." + minor + "." + service + "." + qualifier;
+ }
+
+ return osgiVersion;
+ }
+
+ protected String getBundleName(MavenProject project) {
+ return project.getBuild().getFinalName() + ".jar";
+ }
+
+ public String getBuildDirectory() {
+ return buildDirectory;
+ }
+
+ void setBuildDirectory(String buildirectory) {
+ this.buildDirectory = buildirectory;
+ }
+
+ /**
+ * Get a list of packages inside a Jar
+ *
+ * @param jar
+ * @return list of package names
+ */
+ public List getPackages(Jar jar) {
+ List packages = new ArrayList();
+ for (Iterator p = jar.getDirectories().entrySet().iterator(); p.hasNext();) {
+ Map.Entry directory = (Map.Entry) p.next();
+ String path = (String) directory.getKey();
+
+ String pack = path.replace('/', '.');
+ packages.add(pack);
+ }
+ return packages;
+ }
+
+ protected Properties getDefaultProperties(MavenProject project) {
+ Properties properties = new Properties();
+ // Setup defaults
+ String bsn = project.getGroupId() + "." + project.getArtifactId();
+ properties.put(Analyzer.BUNDLE_SYMBOLICNAME, bsn);
+ properties.put(Analyzer.IMPORT_PACKAGE, "*");
+
+ String version = convertVersionToOsgi(project.getVersion());
+
+ properties.put(Analyzer.BUNDLE_VERSION, version);
+ header(properties, Analyzer.BUNDLE_DESCRIPTION, project
+ .getDescription());
+ header(properties, Analyzer.BUNDLE_LICENSE, printLicenses(project
+ .getLicenses()));
+ header(properties, Analyzer.BUNDLE_NAME, project.getName());
+
+ if (project.getOrganization() != null) {
+ header(properties, Analyzer.BUNDLE_VENDOR, project
+ .getOrganization().getName());
+ if (project.getOrganization().getUrl() != null) {
+ header(properties, Analyzer.BUNDLE_DOCURL, project
+ .getOrganization().getUrl());
+ }
+ }
+
+ properties.putAll(project.getProperties());
+ properties.putAll(project.getModel().getProperties());
+ properties.putAll( getProperies(project.getModel(), "project.build.", project.getBuild()));
+ properties.putAll( getProperies(project.getModel(), "pom.", project.getModel()));
+ properties.putAll( getProperies(project.getModel(), "project.", project));
+ properties.put("project.baseDir", baseDir );
+ properties.put("project.build.directory", getBuildDirectory() );
+ properties.put("project.build.outputdirectory", outputDirectory );
+
+ return properties;
+ }
+
+ void setBasedir(File basedir){
+ this.baseDir = basedir;
+ }
+
+ void setOutputDirectory(File outputDirectory){
+ this.outputDirectory = outputDirectory;
+ }
}
diff --git a/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/ManifestPlugin.java b/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/ManifestPlugin.java
new file mode 100644
index 0000000..25f7304
--- /dev/null
+++ b/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/ManifestPlugin.java
@@ -0,0 +1,157 @@
+/*
+ * 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.felix.tools.maven2.bundleplugin;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.jar.Manifest;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+
+import aQute.lib.osgi.Analyzer;
+import aQute.lib.osgi.Jar;
+
+/**
+ * Generate an OSGi manifest for this project
+ *
+ * @goal manifest
+ * @phase process-classes
+ * @requiresDependencyResolution runtime
+ */
+public class ManifestPlugin
+ extends BundlePlugin
+{
+
+ /**
+ * Directory where the manifest will be written
+ * @parameter expression="${project.build.outputDirectory}/META-INF"
+ */
+ private String manifestLocation;
+
+ protected void execute( MavenProject project, Map instructions, Properties properties, Jar[] classpath )
+ throws MojoExecutionException
+ {
+ Manifest manifest;
+ try
+ {
+ manifest = getManifest( project, instructions, properties, classpath );
+ }
+ catch ( IOException e )
+ {
+ throw new MojoExecutionException( "Error trying to generate Manifest", e );
+ }
+
+ File outputFile = new File( manifestLocation + "/MANIFEST.MF" );
+
+ try
+ {
+ writeManifest( manifest, outputFile );
+ }
+ catch ( IOException e )
+ {
+ throw new MojoExecutionException( "Error trying to write Manifest to file " + outputFile, e );
+ }
+ }
+
+ public Manifest getManifest( MavenProject project, Jar[] classpath )
+ throws IOException
+ {
+ return getManifest( project, null, null, classpath );
+ }
+
+ public Manifest getManifest( MavenProject project, Map instructions, Properties properties, Jar[] classpath )
+ throws IOException
+ {
+ return getAnalyzer( project, instructions, properties, classpath ).getJar().getManifest();
+ }
+
+ protected Analyzer getAnalyzer( MavenProject project, Jar[] classpath )
+ throws IOException
+ {
+ return getAnalyzer( project, new HashMap(), new Properties(), classpath );
+ }
+
+ protected Analyzer getAnalyzer( MavenProject project, Map instructions, Properties properties, Jar[] classpath )
+ throws IOException
+ {
+ PackageVersionAnalyzer analyzer = new PackageVersionAnalyzer();
+
+ Properties props = getDefaultProperties( project );
+ props.putAll( properties );
+
+ if ( !instructions.containsKey( Analyzer.IMPORT_PACKAGE ) )
+ {
+ props.put( Analyzer.IMPORT_PACKAGE, "*" );
+ }
+
+ props.putAll( instructions );
+
+ analyzer.setProperties( props );
+
+ analyzer.setJar( project.getArtifact().getFile() );
+
+ if ( classpath != null )
+ analyzer.setClasspath( classpath );
+
+ if ( !instructions.containsKey( Analyzer.PRIVATE_PACKAGE )
+ && !instructions.containsKey( Analyzer.EXPORT_PACKAGE ) )
+ {
+ String export = analyzer.calculateExportsFromContents( analyzer.getJar() );
+ analyzer.setProperty( Analyzer.EXPORT_PACKAGE, export );
+ }
+
+ analyzer.mergeManifest( analyzer.getJar().getManifest() );
+
+ analyzer.calcManifest();
+
+ return analyzer;
+ }
+
+ public void writeManifest( Manifest manifest, File outputFile )
+ throws IOException
+ {
+ outputFile.getParentFile().mkdirs();
+
+ FileOutputStream os;
+ os = new FileOutputStream( outputFile );
+ try
+ {
+ manifest.write( os );
+ }
+ finally
+ {
+ if ( os != null )
+ {
+ try
+ {
+ os.close();
+ }
+ catch ( IOException e )
+ {
+ //nothing we can do here
+ }
+ }
+ }
+ }
+}
diff --git a/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/PackageVersionAnalyzer.java b/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/PackageVersionAnalyzer.java
new file mode 100644
index 0000000..ae91a53
--- /dev/null
+++ b/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/PackageVersionAnalyzer.java
@@ -0,0 +1,79 @@
+/*
+ * 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.felix.tools.maven2.bundleplugin;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+
+import aQute.lib.osgi.Analyzer;
+import aQute.lib.osgi.Jar;
+
+/**
+ * Extension of {@link aQute.lib.osgi.Analyzer} to handle package versions
+ *
+ * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
+ * @version $Id$
+ */
+public class PackageVersionAnalyzer
+ extends Analyzer
+{
+
+ /**
+ * Remove META-INF subfolders from exports and set package versions to bundle version.
+ *
+ * @param dot
+ * @param bundleClasspath
+ * @param contained
+ * @param referred
+ * @param uses
+ * @return
+ * @throws IOException
+ */
+ public Map analyzeBundleClasspath( Jar dot, Map bundleClasspath, Map contained, Map referred, Map uses )
+ throws IOException
+ {
+ Map classSpace = super.analyzeBundleClasspath( dot, bundleClasspath, contained, referred, uses );
+ String bundleVersion = getProperties().getProperty( BUNDLE_VERSION );
+ for ( Iterator it = contained.entrySet().iterator(); it.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) it.next();
+
+ /* remove packages under META-INF */
+ String packageName = (String) entry.getKey();
+ if ( packageName.startsWith( "META-INF." ) )
+ {
+ it.remove();
+ }
+
+ /* set package versions to bundle version values */
+ if ( bundleVersion != null )
+ {
+ Map values = (Map) entry.getValue();
+ if ( values.get( "version" ) == null )
+ {
+ values.put( "version", bundleVersion );
+ }
+ }
+
+ }
+ return classSpace;
+ }
+
+}
diff --git a/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/WrapPlugin.java b/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/WrapPlugin.java
new file mode 100644
index 0000000..d0a83be
--- /dev/null
+++ b/tools/maven2/maven-bundle-plugin/src/main/java/org/apache/felix/tools/maven2/bundleplugin/WrapPlugin.java
@@ -0,0 +1,41 @@
+/*
+ * 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.felix.tools.maven2.bundleplugin;
+
+import org.apache.maven.plugin.MojoExecutionException;
+
+/**
+ *
+ * @goal wrap
+ * @phase package
+ * @requiresDependencyResolution runtime
+ * @description build an OSGi bundle jar for direct dependencies
+ */
+public class WrapPlugin
+ extends BundleAllPlugin
+{
+
+ public void execute()
+ throws MojoExecutionException
+ {
+ BundleInfo bundleInfo = bundleAll( getProject(), 1 );
+ logDuplicatedPackages( bundleInfo );
+ }
+
+}
diff --git a/tools/maven2/maven-bundle-plugin/src/test/java/org/apache/felix/tools/maven2/bundleplugin/AbstractBundlePluginTest.java b/tools/maven2/maven-bundle-plugin/src/test/java/org/apache/felix/tools/maven2/bundleplugin/AbstractBundlePluginTest.java
new file mode 100644
index 0000000..1641878
--- /dev/null
+++ b/tools/maven2/maven-bundle-plugin/src/test/java/org/apache/felix/tools/maven2/bundleplugin/AbstractBundlePluginTest.java
@@ -0,0 +1,52 @@
+package org.apache.felix.tools.maven2.bundleplugin;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+
+import org.apache.maven.plugin.testing.stubs.ArtifactStub;
+import org.codehaus.plexus.PlexusTestCase;
+
+/**
+ * Common methods for bundle plugin testing
+ *
+ * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
+ * @version $Id$
+ */
+public abstract class AbstractBundlePluginTest
+ extends PlexusTestCase
+{
+
+ protected ArtifactStub getArtifactStub()
+ {
+ ArtifactStub artifact = new ArtifactStub();
+ artifact.setGroupId( "group" );
+ artifact.setArtifactId( "artifact" );
+ artifact.setVersion( "1.0" );
+ return artifact;
+ }
+
+ protected File getTestBundle()
+ {
+ String osgiBundleFileName = "org.apache.maven.maven-model_2.1.0.SNAPSHOT.jar";
+ return getTestFile( getBasedir(), "src/test/resources/" + osgiBundleFileName );
+ }
+
+}
\ No newline at end of file
diff --git a/tools/maven2/maven-bundle-plugin/src/test/java/org/apache/felix/tools/maven2/bundleplugin/BundleAllPluginTest.java b/tools/maven2/maven-bundle-plugin/src/test/java/org/apache/felix/tools/maven2/bundleplugin/BundleAllPluginTest.java
new file mode 100644
index 0000000..81d122b
--- /dev/null
+++ b/tools/maven2/maven-bundle-plugin/src/test/java/org/apache/felix/tools/maven2/bundleplugin/BundleAllPluginTest.java
@@ -0,0 +1,102 @@
+package org.apache.felix.tools.maven2.bundleplugin;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.util.Collections;
+
+import org.apache.maven.plugin.testing.stubs.ArtifactStub;
+import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
+
+/**
+ * Test for {@link BundleAllPlugin}
+ *
+ * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
+ * @version $Id$
+ */
+public class BundleAllPluginTest
+ extends AbstractBundlePluginTest
+{
+
+ private BundleAllPlugin plugin;
+
+ protected void setUp()
+ throws Exception
+ {
+ super.setUp();
+ init();
+ }
+
+ private void init()
+ {
+ plugin = new BundleAllPlugin();
+ File basedir = new File( getBasedir() );
+ plugin.setBasedir( basedir );
+ File buildDirectory = new File( basedir, "target" );
+ plugin.setBuildDirectory( buildDirectory.getPath() );
+ File outputDirectory = new File( buildDirectory, "classes" );
+ plugin.setOutputDirectory( outputDirectory );
+ }
+
+ public void testSnapshotMatch()
+ {
+ ArtifactStub artifact = getArtifactStub();
+ String bundleName;
+
+ artifact.setVersion( "2.1-SNAPSHOT" );
+ bundleName = "group.artifact_2.1.0.20070207_193904_2.jar";
+
+ assertTrue( plugin.snapshotMatch( artifact, bundleName ) );
+
+ artifact.setVersion( "2-SNAPSHOT" );
+ assertFalse( plugin.snapshotMatch( artifact, bundleName ) );
+
+ artifact.setArtifactId( "artifactx" );
+ artifact.setVersion( "2.1-SNAPSHOT" );
+ assertFalse( plugin.snapshotMatch( artifact, bundleName ) );
+ }
+
+// public void testRewriting()
+// throws Exception
+// {
+//
+// MavenProjectStub project = new MavenProjectStub();
+// project.setArtifact( getArtifactStub() );
+// project.getArtifact().setFile( getTestBundle() );
+// project.setDependencyArtifacts( Collections.EMPTY_SET );
+// project.setVersion( project.getArtifact().getVersion() );
+//
+// File output = new File( plugin.getBuildDirectory(), plugin.getBundleName( project ) );
+// boolean delete = output.delete();
+//
+// plugin.bundle( project );
+//
+// init();
+// try
+// {
+// plugin.bundle( project );
+// fail();
+// }
+// catch ( RuntimeException e )
+// {
+// // expected
+// }
+// }
+}
diff --git a/tools/maven2/maven-bundle-plugin/src/test/java/org/apache/felix/tools/maven2/bundleplugin/BundlePluginTest.java b/tools/maven2/maven-bundle-plugin/src/test/java/org/apache/felix/tools/maven2/bundleplugin/BundlePluginTest.java
new file mode 100644
index 0000000..e024b62
--- /dev/null
+++ b/tools/maven2/maven-bundle-plugin/src/test/java/org/apache/felix/tools/maven2/bundleplugin/BundlePluginTest.java
@@ -0,0 +1,151 @@
+package org.apache.felix.tools.maven2.bundleplugin;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.archiver.ArchiverException;
+import org.codehaus.plexus.archiver.jar.JarArchiver;
+
+import aQute.lib.osgi.Analyzer;
+import aQute.lib.osgi.Jar;
+
+/**
+ * Test for {@link BundlePlugin}.
+ *
+ * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
+ * @version $Id$
+ */
+public class BundlePluginTest
+ extends AbstractBundlePluginTest
+{
+
+ private BundlePlugin plugin;
+
+ protected void setUp()
+ throws Exception
+ {
+ super.setUp();
+ plugin = new BundlePlugin();
+ }
+
+ public void testConvertVersionToOsgi()
+ {
+ String osgiVersion;
+
+ osgiVersion = plugin.convertVersionToOsgi( "2.1.0-SNAPSHOT" );
+ assertEquals( "2.1.0.SNAPSHOT", osgiVersion );
+
+ osgiVersion = plugin.convertVersionToOsgi( "2.1-SNAPSHOT" );
+ assertEquals( "2.1.0.SNAPSHOT", osgiVersion );
+
+ osgiVersion = plugin.convertVersionToOsgi( "2-SNAPSHOT" );
+ assertEquals( "2.0.0.SNAPSHOT", osgiVersion );
+
+ osgiVersion = plugin.convertVersionToOsgi( "2" );
+ assertEquals( "2", osgiVersion );
+
+ osgiVersion = plugin.convertVersionToOsgi( "2.1" );
+ assertEquals( "2.1", osgiVersion );
+
+ osgiVersion = plugin.convertVersionToOsgi( "2.1.3" );
+ assertEquals( "2.1.3", osgiVersion );
+
+ osgiVersion = plugin.convertVersionToOsgi( "2.1.3.4" );
+ assertEquals( "2.1.3.4", osgiVersion );
+
+ osgiVersion = plugin.convertVersionToOsgi( "4aug2000r7-dev" );
+ assertEquals( "0.0.0.4aug2000r7_dev", osgiVersion );
+
+ osgiVersion = plugin.convertVersionToOsgi( "1.1-alpha-2" );
+ assertEquals( "1.1.0.alpha_2", osgiVersion );
+
+ osgiVersion = plugin.convertVersionToOsgi( "1.0-alpha-16-20070122.203121-13" );
+ assertEquals( "1.0.0.alpha_16_20070122_203121_13", osgiVersion );
+
+ osgiVersion = plugin.convertVersionToOsgi( "1.0-20070119.021432-1" );
+ assertEquals( "1.0.0.20070119_021432_1", osgiVersion );
+
+ osgiVersion = plugin.convertVersionToOsgi( "1-20070119.021432-1" );
+ assertEquals( "1.0.0.20070119_021432_1", osgiVersion );
+
+ osgiVersion = plugin.convertVersionToOsgi( "1.4.1-20070217.082013-7" );
+ assertEquals( "1.4.1.20070217_082013_7", osgiVersion );
+ }
+
+ public void testReadExportedModules()
+ throws Exception
+ {
+ File osgiBundleFile = getTestBundle();
+
+ assertTrue( osgiBundleFile.exists() );
+
+ MavenProject project = new MavenProjectStub();
+ project.setGroupId( "group" );
+ project.setArtifactId( "artifact" );
+ project.setVersion( "1.1.0.0" );
+
+ PackageVersionAnalyzer analyzer = new PackageVersionAnalyzer();
+ Jar jar = new Jar( "name", osgiBundleFile );
+ analyzer.setJar( jar );
+ analyzer.setClasspath( new Jar[] { jar } );
+
+ analyzer.setProperty( Analyzer.EXPORT_PACKAGE, "*" );
+ analyzer.calcManifest();
+
+ assertEquals( 3, analyzer.getExports().size() );
+ }
+
+ public void testGetPackages()
+ throws Exception
+ {
+ File jarFile = getTestFile( "target/test-jar.jar" );
+
+ createTestJar( jarFile );
+
+ Jar jar = new Jar( "testJar", jarFile );
+ List packages = plugin.getPackages( jar );
+
+ assertEquals( 4, packages.size() );
+ int i = 0;
+ assertEquals( "META-INF", packages.get( i++ ) );
+ assertEquals( "META-INF.maven.org.apache.maven.plugins.maven-bundle-plugin", packages.get( i++ ) );
+ assertEquals( "org.apache.maven.test", packages.get( i++ ) );
+ assertEquals( "org.apache.maven.test.resources", packages.get( i++ ) );
+ }
+
+ private void createTestJar( File jarFile )
+ throws ArchiverException, IOException
+ {
+ JarArchiver archiver = new JarArchiver();
+ archiver
+ .addFile( getTestFile( "target/classes/" + BundlePlugin.class.getName().replace( '.', '/' ) + ".class" ),
+ "org/apache/maven/test/BundlePlugin.class" );
+ archiver.addFile( getTestFile( "pom.xml" ),
+ "META-INF/maven/org.apache.maven.plugins/maven-bundle-plugin/pom.xml" );
+ archiver.addFile( getTestFile( "pom.xml" ), "org/apache/maven/test/resources/someresource" );
+ archiver.setDestFile( jarFile );
+ archiver.createArchive();
+ }
+}
diff --git a/tools/maven2/maven-bundle-plugin/src/test/resources/org.apache.maven.maven-model_2.1.0.SNAPSHOT.jar b/tools/maven2/maven-bundle-plugin/src/test/resources/org.apache.maven.maven-model_2.1.0.SNAPSHOT.jar
new file mode 100644
index 0000000..a619981
--- /dev/null
+++ b/tools/maven2/maven-bundle-plugin/src/test/resources/org.apache.maven.maven-model_2.1.0.SNAPSHOT.jar
Binary files differ