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