blob: 5d095d87b7686689408ed8b7a686bb33e28e5531 [file] [log] [blame]
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Richard S. Hall01a56ce2007-05-20 22:31:11 +000019package org.apache.felix.bundleplugin;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000020
Stuart McCulloch5ae59142008-01-29 06:21:05 +000021
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000022import java.io.File;
23import java.io.FilenameFilter;
24import java.util.Arrays;
25import java.util.Collection;
Stuart McCulloche0245812007-09-25 14:54:09 +000026import java.util.HashSet;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000027import java.util.Iterator;
Stuart McCullochd00f9712009-07-13 10:06:47 +000028import java.util.LinkedHashMap;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000029import java.util.List;
30import java.util.Map;
Stuart McCulloch2cb9a562008-04-23 11:00:42 +000031import java.util.Properties;
Stuart McCulloche0245812007-09-25 14:54:09 +000032import java.util.Set;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000033import java.util.jar.Manifest;
34import java.util.regex.Matcher;
35import java.util.regex.Pattern;
36
37import org.apache.maven.artifact.Artifact;
38import org.apache.maven.artifact.factory.ArtifactFactory;
39import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
40import org.apache.maven.artifact.repository.ArtifactRepository;
41import org.apache.maven.artifact.resolver.ArtifactCollector;
42import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
43import org.apache.maven.artifact.resolver.ArtifactResolutionException;
44import org.apache.maven.artifact.resolver.ArtifactResolver;
Stuart McCulloche0245812007-09-25 14:54:09 +000045import org.apache.maven.artifact.versioning.VersionRange;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000046import org.apache.maven.plugin.MojoExecutionException;
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +000047import org.apache.maven.plugins.annotations.Component;
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +000048import org.apache.maven.plugins.annotations.LifecyclePhase;
49import org.apache.maven.plugins.annotations.Mojo;
50import org.apache.maven.plugins.annotations.Parameter;
51import org.apache.maven.plugins.annotations.ResolutionScope;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000052import org.apache.maven.project.MavenProject;
53import org.apache.maven.project.MavenProjectBuilder;
54import org.apache.maven.project.ProjectBuildingException;
Stuart McCulloche0245812007-09-25 14:54:09 +000055import org.apache.maven.project.artifact.InvalidDependencyVersionException;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000056import org.apache.maven.shared.dependency.tree.DependencyNode;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000057import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder;
58import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException;
Stuart McCullochd6e642f2008-03-03 02:19:21 +000059import org.codehaus.plexus.util.FileUtils;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000060
Stuart McCulloch42151ee2012-07-16 13:43:38 +000061import aQute.bnd.osgi.Analyzer;
62import aQute.bnd.osgi.Jar;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000063
Stuart McCulloch5ae59142008-01-29 06:21:05 +000064
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000065/**
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +000066 * Build an OSGi bundle jar for all transitive dependencies.
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +000067 *
Stuart McCulloch034e7b82011-06-16 17:41:18 +000068 * @deprecated The bundleall goal is no longer supported and may be removed in a future release
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000069 */
Stuart McCulloch034e7b82011-06-16 17:41:18 +000070@Deprecated
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +000071@Mojo( name = "bundleall", requiresDependencyResolution = ResolutionScope.TEST, defaultPhase = LifecyclePhase.PACKAGE )
Stuart McCulloch5ae59142008-01-29 06:21:05 +000072public class BundleAllPlugin extends ManifestPlugin
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000073{
Stuart McCulloche0245812007-09-25 14:54:09 +000074 private static final String LS = System.getProperty( "line.separator" );
75
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000076 private static final Pattern SNAPSHOT_VERSION_PATTERN = Pattern.compile( "[0-9]{8}_[0-9]{6}_[0-9]+" );
77
78 /**
Stuart McCulloch9366a822008-01-29 07:45:57 +000079 * Local repository.
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000080 */
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +000081 @Parameter( defaultValue = "${localRepository}", readonly = true, required = true )
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000082 private ArtifactRepository localRepository;
83
84 /**
Stuart McCulloch9366a822008-01-29 07:45:57 +000085 * Remote repositories.
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000086 */
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +000087 @Parameter( defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true )
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000088 private List remoteRepositories;
89
90 /**
Stuart McCulloch2cb9a562008-04-23 11:00:42 +000091 * Import-Package to be used when wrapping dependencies.
Stuart McCulloch2cb9a562008-04-23 11:00:42 +000092 */
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +000093 @Parameter( property = "wrapImportPackage", defaultValue = "*" )
Stuart McCulloch2cb9a562008-04-23 11:00:42 +000094 private String wrapImportPackage;
95
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +000096 @Component
Stuart McCulloch9366a822008-01-29 07:45:57 +000097 private ArtifactFactory m_factory;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +000098
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +000099 @Component
Stuart McCulloch9366a822008-01-29 07:45:57 +0000100 private ArtifactMetadataSource m_artifactMetadataSource;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000101
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +0000102 @Component
Stuart McCulloch9366a822008-01-29 07:45:57 +0000103 private ArtifactCollector m_collector;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000104
105 /**
106 * Artifact resolver, needed to download jars.
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000107 */
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +0000108 @Component
Stuart McCulloch9366a822008-01-29 07:45:57 +0000109 private ArtifactResolver m_artifactResolver;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000110
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +0000111 @Component
Stuart McCulloch9366a822008-01-29 07:45:57 +0000112 private DependencyTreeBuilder m_dependencyTreeBuilder;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000113
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +0000114 @Component
Stuart McCulloch9366a822008-01-29 07:45:57 +0000115 private MavenProjectBuilder m_mavenProjectBuilder;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000116
Stuart McCulloche0245812007-09-25 14:54:09 +0000117 /**
118 * Ignore missing artifacts that are not required by current project but are required by the
119 * transitive dependencies.
Stuart McCulloche0245812007-09-25 14:54:09 +0000120 */
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +0000121 @Parameter
Stuart McCulloche0245812007-09-25 14:54:09 +0000122 private boolean ignoreMissingArtifacts;
123
Stuart McCulloch9366a822008-01-29 07:45:57 +0000124 private Set m_artifactsBeingProcessed = new HashSet();
Stuart McCulloche0245812007-09-25 14:54:09 +0000125
Stuart McCullochd6e642f2008-03-03 02:19:21 +0000126 /**
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000127 * Process up to some depth
Stuart McCullochd6e642f2008-03-03 02:19:21 +0000128 */
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +0000129 @Parameter
Stuart McCullochd6e642f2008-03-03 02:19:21 +0000130 private int depth = Integer.MAX_VALUE;
131
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000132
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000133 @Override
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000134 public void execute() throws MojoExecutionException
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000135 {
Stuart McCullochb45e1812011-06-27 17:38:53 +0000136 getLog().warn( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
137 getLog().warn( "! The bundleall goal is no longer supported and may be removed in a future release !" );
138 getLog().warn( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
139
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000140 BundleInfo bundleInfo = bundleAll( getProject() );
141 logDuplicatedPackages( bundleInfo );
142 }
143
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000144
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000145 /**
146 * Bundle a project and all its dependencies
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000147 *
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000148 * @param project
149 * @throws MojoExecutionException
150 */
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000151 private BundleInfo bundleAll( MavenProject project ) throws MojoExecutionException
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000152 {
Stuart McCullochd6e642f2008-03-03 02:19:21 +0000153 return bundleAll( project, depth );
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000154 }
155
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000156
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000157 /**
158 * Bundle a project and its transitive dependencies up to some depth level
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000159 *
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000160 * @param project
Stuart McCullochd6e642f2008-03-03 02:19:21 +0000161 * @param maxDepth how deep to process the dependency tree
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000162 * @throws MojoExecutionException
163 */
Stuart McCullochd6e642f2008-03-03 02:19:21 +0000164 protected BundleInfo bundleAll( MavenProject project, int maxDepth ) throws MojoExecutionException
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000165 {
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000166 if ( alreadyBundled( project.getArtifact() ) )
167 {
168 getLog().debug( "Ignoring project already processed " + project.getArtifact() );
169 return null;
170 }
171
Stuart McCulloch9366a822008-01-29 07:45:57 +0000172 if ( m_artifactsBeingProcessed.contains( project.getArtifact() ) )
Stuart McCulloche0245812007-09-25 14:54:09 +0000173 {
174 getLog().warn( "Ignoring artifact due to dependency cycle " + project.getArtifact() );
175 return null;
176 }
Stuart McCulloch9366a822008-01-29 07:45:57 +0000177 m_artifactsBeingProcessed.add( project.getArtifact() );
Stuart McCulloche0245812007-09-25 14:54:09 +0000178
Stuart McCullochde88f0c2007-10-04 13:12:06 +0000179 DependencyNode dependencyTree;
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000180
181 try
182 {
Stuart McCulloch9366a822008-01-29 07:45:57 +0000183 dependencyTree = m_dependencyTreeBuilder.buildDependencyTree( project, localRepository, m_factory,
184 m_artifactMetadataSource, null, m_collector );
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000185 }
186 catch ( DependencyTreeBuilderException e )
187 {
188 throw new MojoExecutionException( "Unable to build dependency tree", e );
189 }
190
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000191 BundleInfo bundleInfo = new BundleInfo();
192
Stuart McCullochde88f0c2007-10-04 13:12:06 +0000193 if ( !dependencyTree.hasChildren() )
194 {
195 /* no need to traverse the tree */
196 return bundleRoot( project, bundleInfo );
197 }
198
Stuart McCulloche0245812007-09-25 14:54:09 +0000199 getLog().debug( "Will bundle the following dependency tree" + LS + dependencyTree );
200
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000201 for ( Iterator it = dependencyTree.inverseIterator(); it.hasNext(); )
202 {
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000203 DependencyNode node = ( DependencyNode ) it.next();
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000204 if ( !it.hasNext() )
205 {
206 /* this is the root, current project */
207 break;
208 }
209
Stuart McCullochde88f0c2007-10-04 13:12:06 +0000210 if ( node.getState() != DependencyNode.INCLUDED )
211 {
212 continue;
213 }
214
Stuart McCulloche0245812007-09-25 14:54:09 +0000215 if ( Artifact.SCOPE_SYSTEM.equals( node.getArtifact().getScope() ) )
216 {
217 getLog().debug( "Ignoring system scoped artifact " + node.getArtifact() );
218 continue;
219 }
220
221 Artifact artifact;
222 try
223 {
224 artifact = resolveArtifact( node.getArtifact() );
225 }
226 catch ( ArtifactNotFoundException e )
227 {
228 if ( ignoreMissingArtifacts )
229 {
230 continue;
231 }
Stuart McCullochf806f862008-02-04 07:57:09 +0000232
233 throw new MojoExecutionException( "Artifact was not found in the repo" + node.getArtifact(), e );
Stuart McCulloche0245812007-09-25 14:54:09 +0000234 }
235
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000236 node.getArtifact().setFile( artifact.getFile() );
237
Stuart McCulloche0245812007-09-25 14:54:09 +0000238 int nodeDepth = node.getDepth();
Stuart McCullochd6e642f2008-03-03 02:19:21 +0000239 if ( nodeDepth > maxDepth )
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000240 {
241 /* node is deeper than we want */
Stuart McCullochd6e642f2008-03-03 02:19:21 +0000242 getLog().debug(
243 "Ignoring " + node.getArtifact() + ", depth is " + nodeDepth + ", bigger than " + maxDepth );
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000244 continue;
245 }
246
247 MavenProject childProject;
248 try
249 {
Stuart McCulloch9366a822008-01-29 07:45:57 +0000250 childProject = m_mavenProjectBuilder.buildFromRepository( artifact, remoteRepositories,
251 localRepository, true );
Stuart McCulloche0245812007-09-25 14:54:09 +0000252 if ( childProject.getDependencyArtifacts() == null )
253 {
Stuart McCulloch9366a822008-01-29 07:45:57 +0000254 childProject.setDependencyArtifacts( childProject.createArtifacts( m_factory, null, null ) );
Stuart McCulloche0245812007-09-25 14:54:09 +0000255 }
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000256 }
Stuart McCulloche0245812007-09-25 14:54:09 +0000257 catch ( InvalidDependencyVersionException e )
258 {
259 throw new MojoExecutionException( "Invalid dependency version for artifact " + artifact );
260 }
Stuart McCullochd3003ed2011-10-26 12:24:15 +0000261 catch ( ProjectBuildingException e )
262 {
263 throw new MojoExecutionException( "Unable to build project object for artifact " + artifact, e );
264 }
Stuart McCulloche0245812007-09-25 14:54:09 +0000265
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000266 childProject.setArtifact( artifact );
267 getLog().debug( "Child project artifact location: " + childProject.getArtifact().getFile() );
268
Stuart McCulloche0245812007-09-25 14:54:09 +0000269 if ( ( Artifact.SCOPE_COMPILE.equals( artifact.getScope() ) )
270 || ( Artifact.SCOPE_RUNTIME.equals( artifact.getScope() ) ) )
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000271 {
Stuart McCullochd6e642f2008-03-03 02:19:21 +0000272 BundleInfo subBundleInfo = bundleAll( childProject, maxDepth - 1 );
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000273 if ( subBundleInfo != null )
274 {
275 bundleInfo.merge( subBundleInfo );
276 }
277 }
278 else
279 {
280 getLog().debug(
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000281 "Not processing due to scope (" + childProject.getArtifact().getScope() + "): "
282 + childProject.getArtifact() );
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000283 }
284 }
285
Stuart McCulloche0245812007-09-25 14:54:09 +0000286 return bundleRoot( project, bundleInfo );
287 }
288
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000289
Stuart McCulloche0245812007-09-25 14:54:09 +0000290 /**
291 * Bundle the root of a dependency tree after all its children have been bundled
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000292 *
Stuart McCulloche0245812007-09-25 14:54:09 +0000293 * @param project
294 * @param bundleInfo
295 * @return
296 * @throws MojoExecutionException
297 */
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000298 private BundleInfo bundleRoot( MavenProject project, BundleInfo bundleInfo ) throws MojoExecutionException
Stuart McCulloche0245812007-09-25 14:54:09 +0000299 {
300 /* do not bundle the project the mojo was called on */
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000301 if ( getProject() != project )
302 {
303 getLog().debug( "Project artifact location: " + project.getArtifact().getFile() );
304
305 BundleInfo subBundleInfo = bundle( project );
306 if ( subBundleInfo != null )
307 {
308 bundleInfo.merge( subBundleInfo );
309 }
310 }
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000311 return bundleInfo;
312 }
313
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000314
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000315 /**
316 * Bundle one project only without building its childre
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000317 *
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000318 * @param project
319 * @throws MojoExecutionException
320 */
Stuart McCulloch9366a822008-01-29 07:45:57 +0000321 protected BundleInfo bundle( MavenProject project ) throws MojoExecutionException
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000322 {
323 Artifact artifact = project.getArtifact();
324 getLog().info( "Bundling " + artifact );
325
326 try
327 {
Stuart McCullochd00f9712009-07-13 10:06:47 +0000328 Map instructions = new LinkedHashMap();
Stuart McCulloch2cb9a562008-04-23 11:00:42 +0000329 instructions.put( Analyzer.IMPORT_PACKAGE, wrapImportPackage );
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000330
331 project.getArtifact().setFile( getFile( artifact ) );
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000332 File outputFile = getOutputFile(artifact);
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000333
334 if ( project.getArtifact().getFile().equals( outputFile ) )
335 {
336 /* TODO find the cause why it's getting here */
337 return null;
338 // getLog().error(
339 // "Trying to read and write " + artifact + " to the same file, try cleaning: "
340 // + outputFile );
341 // throw new IllegalStateException( "Trying to read and write " + artifact
342 // + " to the same file, try cleaning: " + outputFile );
343 }
344
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000345 org.apache.maven.shared.dependency.graph.DependencyNode dependencyGraph = buildDependencyGraph( project );
346 Analyzer analyzer = getAnalyzer( project, dependencyGraph, instructions, new Properties(), getClasspath( project, dependencyGraph ) );
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000347
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000348 Jar osgiJar = new Jar( project.getArtifactId(), project.getArtifact().getFile() );
Richard S. Hallea2e9e02007-05-17 13:05:50 +0000349
Stuart McCullochd6e642f2008-03-03 02:19:21 +0000350 outputFile.getAbsoluteFile().getParentFile().mkdirs();
351
Richard S. Hallea2e9e02007-05-17 13:05:50 +0000352 Collection exportedPackages;
353 if ( isOsgi( osgiJar ) )
354 {
355 /* if it is already an OSGi jar copy it as is */
356 getLog().info(
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000357 "Using existing OSGi bundle for " + project.getGroupId() + ":" + project.getArtifactId() + ":"
358 + project.getVersion() );
Richard S. Hallea2e9e02007-05-17 13:05:50 +0000359 String exportHeader = osgiJar.getManifest().getMainAttributes().getValue( Analyzer.EXPORT_PACKAGE );
360 exportedPackages = analyzer.parseHeader( exportHeader ).keySet();
Stuart McCullochd6e642f2008-03-03 02:19:21 +0000361 FileUtils.copyFile( project.getArtifact().getFile(), outputFile );
Richard S. Hallea2e9e02007-05-17 13:05:50 +0000362 }
363 else
364 {
Stuart McCullochd6e642f2008-03-03 02:19:21 +0000365 /* else generate the manifest from the packages */
Richard S. Hallea2e9e02007-05-17 13:05:50 +0000366 exportedPackages = analyzer.getExports().keySet();
367 Manifest manifest = analyzer.getJar().getManifest();
368 osgiJar.setManifest( manifest );
Stuart McCullochd6e642f2008-03-03 02:19:21 +0000369 osgiJar.write( outputFile );
Richard S. Hallea2e9e02007-05-17 13:05:50 +0000370 }
371
Richard S. Hallea2e9e02007-05-17 13:05:50 +0000372 BundleInfo bundleInfo = addExportedPackages( project, exportedPackages );
373
Stuart McCullochd8a04c52008-08-06 16:05:23 +0000374 // cleanup...
375 analyzer.close();
376 osgiJar.close();
377
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000378 return bundleInfo;
379 }
380 /* too bad Jar.write throws Exception */
381 catch ( Exception e )
382 {
383 throw new MojoExecutionException( "Error generating OSGi bundle for project "
384 + getArtifactKey( project.getArtifact() ), e );
385 }
386 }
387
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000388
Stuart McCulloch35c25c32011-04-02 10:24:03 +0000389 private boolean isOsgi( Jar jar ) throws Exception
Richard S. Hallea2e9e02007-05-17 13:05:50 +0000390 {
Stuart McCulloche0245812007-09-25 14:54:09 +0000391 if ( jar.getManifest() != null )
392 {
393 return jar.getManifest().getMainAttributes().getValue( Analyzer.BUNDLE_NAME ) != null;
394 }
395 return false;
Richard S. Hallea2e9e02007-05-17 13:05:50 +0000396 }
397
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000398
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000399 private BundleInfo addExportedPackages( MavenProject project, Collection packages )
400 {
401 BundleInfo bundleInfo = new BundleInfo();
402 for ( Iterator it = packages.iterator(); it.hasNext(); )
403 {
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000404 String packageName = ( String ) it.next();
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000405 bundleInfo.addExportedPackage( packageName, project.getArtifact() );
406 }
407 return bundleInfo;
408 }
409
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000410
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000411 private String getArtifactKey( Artifact artifact )
412 {
413 return artifact.getGroupId() + ":" + artifact.getArtifactId();
414 }
415
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000416
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000417 private String getBundleName( Artifact artifact )
418 {
Richard S. Hall17b8e3d2007-06-13 16:20:40 +0000419 return getMaven2OsgiConverter().getBundleFileName( artifact );
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000420 }
421
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000422
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000423 private boolean alreadyBundled( Artifact artifact )
424 {
425 return getBuiltFile( artifact ) != null;
426 }
427
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000428
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000429 /**
430 * Use previously built bundles when available.
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000431 *
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000432 * @param artifact
433 */
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000434 @Override
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000435 protected File getFile( final Artifact artifact )
436 {
437 File bundle = getBuiltFile( artifact );
438
439 if ( bundle != null )
440 {
441 getLog().debug( "Using previously built OSGi bundle for " + artifact + " in " + bundle );
442 return bundle;
443 }
444 return super.getFile( artifact );
445 }
446
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000447
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000448 private File getBuiltFile( final Artifact artifact )
449 {
450 File bundle = null;
451
452 /* if bundle was already built use it instead of jar from repo */
453 File outputFile = getOutputFile( artifact );
454 if ( outputFile.exists() )
455 {
456 bundle = outputFile;
457 }
458
459 /*
460 * Find snapshots in output folder, eg. 2.1-SNAPSHOT will match 2.1.0.20070207_193904_2
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000461 * TODO there has to be another way to do this using Maven libs
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000462 */
463 if ( ( bundle == null ) && artifact.isSnapshot() )
464 {
465 final File buildDirectory = new File( getBuildDirectory() );
466 if ( !buildDirectory.exists() )
467 {
468 buildDirectory.mkdirs();
469 }
470 File[] files = buildDirectory.listFiles( new FilenameFilter()
471 {
472 public boolean accept( File dir, String name )
473 {
474 if ( dir.equals( buildDirectory ) && snapshotMatch( artifact, name ) )
475 {
476 return true;
477 }
478 return false;
479 }
480 } );
481 if ( files.length > 1 )
482 {
483 throw new RuntimeException( "More than one previously built bundle matches for artifact " + artifact
484 + " : " + Arrays.asList( files ) );
485 }
486 if ( files.length == 1 )
487 {
488 bundle = files[0];
489 }
490 }
491
492 return bundle;
493 }
494
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000495
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000496 /**
497 * Check that the bundleName provided correspond to the artifact provided.
498 * Used to determine when the bundle name is a timestamped snapshot and the artifact is a snapshot not timestamped.
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000499 *
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000500 * @param artifact artifact with snapshot version
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000501 * @param bundleName bundle file name
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000502 * @return if both represent the same artifact and version, forgetting about the snapshot timestamp
503 */
Stuart McCulloch9366a822008-01-29 07:45:57 +0000504 protected boolean snapshotMatch( Artifact artifact, String bundleName )
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000505 {
506 String artifactBundleName = getBundleName( artifact );
507 int i = artifactBundleName.indexOf( "SNAPSHOT" );
508 if ( i < 0 )
509 {
510 return false;
511 }
512 artifactBundleName = artifactBundleName.substring( 0, i );
513
514 if ( bundleName.startsWith( artifactBundleName ) )
515 {
516 /* it's the same artifact groupId and artifactId */
517 String timestamp = bundleName.substring( artifactBundleName.length(), bundleName.lastIndexOf( ".jar" ) );
518 Matcher m = SNAPSHOT_VERSION_PATTERN.matcher( timestamp );
519 return m.matches();
520 }
521 return false;
522 }
523
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000524
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000525 protected File getOutputFile( Artifact artifact )
526 {
Richard S. Hall420d2782007-06-14 12:31:48 +0000527 return new File( getOutputDirectory(), getBundleName( artifact ) );
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000528 }
529
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000530
531 private Artifact resolveArtifact( Artifact artifact ) throws MojoExecutionException, ArtifactNotFoundException
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000532 {
Stuart McCulloche0245812007-09-25 14:54:09 +0000533 VersionRange versionRange;
534 if ( artifact.getVersion() != null )
535 {
536 versionRange = VersionRange.createFromVersion( artifact.getVersion() );
537 }
538 else
539 {
540 versionRange = artifact.getVersionRange();
541 }
542
543 /*
544 * there's a bug with ArtifactFactory#createDependencyArtifact(String, String, VersionRange,
545 * String, String, String) that ignores the scope parameter, that's why we use the one with
546 * the extra null parameter
547 */
Stuart McCulloch9366a822008-01-29 07:45:57 +0000548 Artifact resolvedArtifact = m_factory.createDependencyArtifact( artifact.getGroupId(),
549 artifact.getArtifactId(), versionRange, artifact.getType(), artifact.getClassifier(), artifact.getScope(),
550 null );
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000551
552 try
553 {
Stuart McCulloch9366a822008-01-29 07:45:57 +0000554 m_artifactResolver.resolve( resolvedArtifact, remoteRepositories, localRepository );
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000555 }
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000556 catch ( ArtifactResolutionException e )
557 {
558 throw new MojoExecutionException( "Error resolving artifact " + resolvedArtifact, e );
559 }
560
561 return resolvedArtifact;
562 }
563
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000564
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000565 /**
566 * Log what packages are exported in more than one bundle
567 */
568 protected void logDuplicatedPackages( BundleInfo bundleInfo )
569 {
570 Map duplicatedExports = bundleInfo.getDuplicatedExports();
571
572 for ( Iterator it = duplicatedExports.entrySet().iterator(); it.hasNext(); )
573 {
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000574 Map.Entry entry = ( Map.Entry ) it.next();
575 String packageName = ( String ) entry.getKey();
576 Collection artifacts = ( Collection ) entry.getValue();
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000577
578 getLog().warn( "Package " + packageName + " is exported in more than a bundle: " );
579 for ( Iterator it2 = artifacts.iterator(); it2.hasNext(); )
580 {
Stuart McCulloch5ae59142008-01-29 06:21:05 +0000581 Artifact artifact = ( Artifact ) it2.next();
Richard S. Hall6cf6f0b2007-04-10 16:50:31 +0000582 getLog().warn( " " + artifact );
583 }
584
585 }
586 }
587}