1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.felix.bundleplugin;
20
21
22 import java.io.File;
23 import java.io.FilenameFilter;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.LinkedHashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Properties;
32 import java.util.Set;
33 import java.util.jar.Manifest;
34 import java.util.regex.Matcher;
35 import java.util.regex.Pattern;
36
37 import org.apache.maven.artifact.Artifact;
38 import org.apache.maven.artifact.factory.ArtifactFactory;
39 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
40 import org.apache.maven.artifact.repository.ArtifactRepository;
41 import org.apache.maven.artifact.resolver.ArtifactCollector;
42 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
43 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
44 import org.apache.maven.artifact.resolver.ArtifactResolver;
45 import org.apache.maven.artifact.versioning.VersionRange;
46 import org.apache.maven.plugin.MojoExecutionException;
47 import org.apache.maven.plugins.annotations.Component;
48 import org.apache.maven.plugins.annotations.LifecyclePhase;
49 import org.apache.maven.plugins.annotations.Mojo;
50 import org.apache.maven.plugins.annotations.Parameter;
51 import org.apache.maven.plugins.annotations.ResolutionScope;
52 import org.apache.maven.project.MavenProject;
53 import org.apache.maven.project.MavenProjectBuilder;
54 import org.apache.maven.project.ProjectBuildingException;
55 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
56 import org.apache.maven.shared.dependency.tree.DependencyNode;
57 import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder;
58 import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException;
59 import org.codehaus.plexus.util.FileUtils;
60
61 import aQute.bnd.osgi.Analyzer;
62 import aQute.bnd.osgi.Jar;
63
64
65
66
67
68
69
70 @Deprecated
71 @Mojo( name = "bundleall", requiresDependencyResolution = ResolutionScope.TEST, defaultPhase = LifecyclePhase.PACKAGE )
72 public class BundleAllPlugin extends ManifestPlugin
73 {
74 private static final String LS = System.getProperty( "line.separator" );
75
76 private static final Pattern SNAPSHOT_VERSION_PATTERN = Pattern.compile( "[0-9]{8}_[0-9]{6}_[0-9]+" );
77
78
79
80
81 @Parameter( defaultValue = "${localRepository}", readonly = true, required = true )
82 private ArtifactRepository localRepository;
83
84
85
86
87 @Parameter( defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true )
88 private List remoteRepositories;
89
90
91
92
93 @Parameter( property = "wrapImportPackage", defaultValue = "*" )
94 private String wrapImportPackage;
95
96 @Component
97 private ArtifactFactory m_factory;
98
99 @Component
100 private ArtifactMetadataSource m_artifactMetadataSource;
101
102 @Component
103 private ArtifactCollector m_collector;
104
105
106
107
108 @Component
109 private ArtifactResolver m_artifactResolver;
110
111 @Component
112 private DependencyTreeBuilder m_dependencyTreeBuilder;
113
114 @Component
115 private MavenProjectBuilder m_mavenProjectBuilder;
116
117
118
119
120
121 @Parameter
122 private boolean ignoreMissingArtifacts;
123
124 private Set m_artifactsBeingProcessed = new HashSet();
125
126
127
128
129 @Parameter
130 private int depth = Integer.MAX_VALUE;
131
132
133 @Override
134 public void execute() throws MojoExecutionException
135 {
136 getLog().warn( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
137 getLog().warn( "! The bundleall goal is no longer supported and may be removed in a future release !" );
138 getLog().warn( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
139
140 BundleInfo bundleInfo = bundleAll( getProject() );
141 logDuplicatedPackages( bundleInfo );
142 }
143
144
145
146
147
148
149
150
151 private BundleInfo bundleAll( MavenProject project ) throws MojoExecutionException
152 {
153 return bundleAll( project, depth );
154 }
155
156
157
158
159
160
161
162
163
164 protected BundleInfo bundleAll( MavenProject project, int maxDepth ) throws MojoExecutionException
165 {
166 if ( alreadyBundled( project.getArtifact() ) )
167 {
168 getLog().debug( "Ignoring project already processed " + project.getArtifact() );
169 return null;
170 }
171
172 if ( m_artifactsBeingProcessed.contains( project.getArtifact() ) )
173 {
174 getLog().warn( "Ignoring artifact due to dependency cycle " + project.getArtifact() );
175 return null;
176 }
177 m_artifactsBeingProcessed.add( project.getArtifact() );
178
179 DependencyNode dependencyTree;
180
181 try
182 {
183 dependencyTree = m_dependencyTreeBuilder.buildDependencyTree( project, localRepository, m_factory,
184 m_artifactMetadataSource, null, m_collector );
185 }
186 catch ( DependencyTreeBuilderException e )
187 {
188 throw new MojoExecutionException( "Unable to build dependency tree", e );
189 }
190
191 BundleInfo bundleInfo = new BundleInfo();
192
193 if ( !dependencyTree.hasChildren() )
194 {
195
196 return bundleRoot( project, bundleInfo );
197 }
198
199 getLog().debug( "Will bundle the following dependency tree" + LS + dependencyTree );
200
201 for ( Iterator it = dependencyTree.inverseIterator(); it.hasNext(); )
202 {
203 DependencyNode node = ( DependencyNode ) it.next();
204 if ( !it.hasNext() )
205 {
206
207 break;
208 }
209
210 if ( node.getState() != DependencyNode.INCLUDED )
211 {
212 continue;
213 }
214
215 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 }
232
233 throw new MojoExecutionException( "Artifact was not found in the repo" + node.getArtifact(), e );
234 }
235
236 node.getArtifact().setFile( artifact.getFile() );
237
238 int nodeDepth = node.getDepth();
239 if ( nodeDepth > maxDepth )
240 {
241
242 getLog().debug(
243 "Ignoring " + node.getArtifact() + ", depth is " + nodeDepth + ", bigger than " + maxDepth );
244 continue;
245 }
246
247 MavenProject childProject;
248 try
249 {
250 childProject = m_mavenProjectBuilder.buildFromRepository( artifact, remoteRepositories,
251 localRepository, true );
252 if ( childProject.getDependencyArtifacts() == null )
253 {
254 childProject.setDependencyArtifacts( childProject.createArtifacts( m_factory, null, null ) );
255 }
256 }
257 catch ( InvalidDependencyVersionException e )
258 {
259 throw new MojoExecutionException( "Invalid dependency version for artifact " + artifact );
260 }
261 catch ( ProjectBuildingException e )
262 {
263 throw new MojoExecutionException( "Unable to build project object for artifact " + artifact, e );
264 }
265
266 childProject.setArtifact( artifact );
267 getLog().debug( "Child project artifact location: " + childProject.getArtifact().getFile() );
268
269 if ( ( Artifact.SCOPE_COMPILE.equals( artifact.getScope() ) )
270 || ( Artifact.SCOPE_RUNTIME.equals( artifact.getScope() ) ) )
271 {
272 BundleInfo subBundleInfo = bundleAll( childProject, maxDepth - 1 );
273 if ( subBundleInfo != null )
274 {
275 bundleInfo.merge( subBundleInfo );
276 }
277 }
278 else
279 {
280 getLog().debug(
281 "Not processing due to scope (" + childProject.getArtifact().getScope() + "): "
282 + childProject.getArtifact() );
283 }
284 }
285
286 return bundleRoot( project, bundleInfo );
287 }
288
289
290
291
292
293
294
295
296
297
298 private BundleInfo bundleRoot( MavenProject project, BundleInfo bundleInfo ) throws MojoExecutionException
299 {
300
301 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 }
311 return bundleInfo;
312 }
313
314
315
316
317
318
319
320
321 protected BundleInfo bundle( MavenProject project ) throws MojoExecutionException
322 {
323 Artifact artifact = project.getArtifact();
324 getLog().info( "Bundling " + artifact );
325
326 try
327 {
328 Map instructions = new LinkedHashMap();
329 instructions.put( Analyzer.IMPORT_PACKAGE, wrapImportPackage );
330
331 project.getArtifact().setFile( getFile( artifact ) );
332 File outputFile = getOutputFile(artifact);
333
334 if ( project.getArtifact().getFile().equals( outputFile ) )
335 {
336
337 return null;
338
339
340
341
342
343 }
344
345 org.apache.maven.shared.dependency.graph.DependencyNode dependencyGraph = buildDependencyGraph( project );
346 Analyzer analyzer = getAnalyzer( project, dependencyGraph, instructions, new Properties(), getClasspath( project, dependencyGraph ) );
347
348 Jar osgiJar = new Jar( project.getArtifactId(), project.getArtifact().getFile() );
349
350 outputFile.getAbsoluteFile().getParentFile().mkdirs();
351
352 Collection exportedPackages;
353 if ( isOsgi( osgiJar ) )
354 {
355
356 getLog().info(
357 "Using existing OSGi bundle for " + project.getGroupId() + ":" + project.getArtifactId() + ":"
358 + project.getVersion() );
359 String exportHeader = osgiJar.getManifest().getMainAttributes().getValue( Analyzer.EXPORT_PACKAGE );
360 exportedPackages = analyzer.parseHeader( exportHeader ).keySet();
361 FileUtils.copyFile( project.getArtifact().getFile(), outputFile );
362 }
363 else
364 {
365
366 exportedPackages = analyzer.getExports().keySet();
367 Manifest manifest = analyzer.getJar().getManifest();
368 osgiJar.setManifest( manifest );
369 osgiJar.write( outputFile );
370 }
371
372 BundleInfo bundleInfo = addExportedPackages( project, exportedPackages );
373
374
375 analyzer.close();
376 osgiJar.close();
377
378 return bundleInfo;
379 }
380
381 catch ( Exception e )
382 {
383 throw new MojoExecutionException( "Error generating OSGi bundle for project "
384 + getArtifactKey( project.getArtifact() ), e );
385 }
386 }
387
388
389 private boolean isOsgi( Jar jar ) throws Exception
390 {
391 if ( jar.getManifest() != null )
392 {
393 return jar.getManifest().getMainAttributes().getValue( Analyzer.BUNDLE_NAME ) != null;
394 }
395 return false;
396 }
397
398
399 private BundleInfo addExportedPackages( MavenProject project, Collection packages )
400 {
401 BundleInfo bundleInfo = new BundleInfo();
402 for ( Iterator it = packages.iterator(); it.hasNext(); )
403 {
404 String packageName = ( String ) it.next();
405 bundleInfo.addExportedPackage( packageName, project.getArtifact() );
406 }
407 return bundleInfo;
408 }
409
410
411 private String getArtifactKey( Artifact artifact )
412 {
413 return artifact.getGroupId() + ":" + artifact.getArtifactId();
414 }
415
416
417 private String getBundleName( Artifact artifact )
418 {
419 return getMaven2OsgiConverter().getBundleFileName( artifact );
420 }
421
422
423 private boolean alreadyBundled( Artifact artifact )
424 {
425 return getBuiltFile( artifact ) != null;
426 }
427
428
429
430
431
432
433
434 @Override
435 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
447
448 private File getBuiltFile( final Artifact artifact )
449 {
450 File bundle = null;
451
452
453 File outputFile = getOutputFile( artifact );
454 if ( outputFile.exists() )
455 {
456 bundle = outputFile;
457 }
458
459
460
461
462
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
495
496
497
498
499
500
501
502
503
504 protected boolean snapshotMatch( Artifact artifact, String bundleName )
505 {
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
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
524
525 protected File getOutputFile( Artifact artifact )
526 {
527 return new File( getOutputDirectory(), getBundleName( artifact ) );
528 }
529
530
531 private Artifact resolveArtifact( Artifact artifact ) throws MojoExecutionException, ArtifactNotFoundException
532 {
533 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
545
546
547
548 Artifact resolvedArtifact = m_factory.createDependencyArtifact( artifact.getGroupId(),
549 artifact.getArtifactId(), versionRange, artifact.getType(), artifact.getClassifier(), artifact.getScope(),
550 null );
551
552 try
553 {
554 m_artifactResolver.resolve( resolvedArtifact, remoteRepositories, localRepository );
555 }
556 catch ( ArtifactResolutionException e )
557 {
558 throw new MojoExecutionException( "Error resolving artifact " + resolvedArtifact, e );
559 }
560
561 return resolvedArtifact;
562 }
563
564
565
566
567
568 protected void logDuplicatedPackages( BundleInfo bundleInfo )
569 {
570 Map duplicatedExports = bundleInfo.getDuplicatedExports();
571
572 for ( Iterator it = duplicatedExports.entrySet().iterator(); it.hasNext(); )
573 {
574 Map.Entry entry = ( Map.Entry ) it.next();
575 String packageName = ( String ) entry.getKey();
576 Collection artifacts = ( Collection ) entry.getValue();
577
578 getLog().warn( "Package " + packageName + " is exported in more than a bundle: " );
579 for ( Iterator it2 = artifacts.iterator(); it2.hasNext(); )
580 {
581 Artifact artifact = ( Artifact ) it2.next();
582 getLog().warn( " " + artifact );
583 }
584
585 }
586 }
587 }