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 }