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