1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.codehaus.mojo.nbm;
18
19 import java.io.File;
20 import java.io.FileInputStream;
21 import java.io.IOException;
22 import java.io.InputStreamReader;
23 import java.io.PrintWriter;
24 import java.io.Reader;
25 import java.net.URL;
26 import java.text.BreakIterator;
27 import java.text.SimpleDateFormat;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collections;
31 import java.util.Date;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.TimeZone;
38 import java.util.regex.Pattern;
39 import org.apache.maven.artifact.Artifact;
40 import org.apache.maven.artifact.factory.ArtifactFactory;
41 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
42 import org.apache.maven.artifact.repository.ArtifactRepository;
43 import org.apache.maven.artifact.resolver.ArtifactCollector;
44 import org.apache.maven.plugin.MojoExecutionException;
45 import org.apache.maven.plugin.MojoFailureException;
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.codehaus.mojo.nbm.model.Dependency;
52 import org.codehaus.mojo.nbm.model.NetBeansModule;
53 import org.apache.maven.project.MavenProject;
54 import org.apache.maven.shared.dependency.analyzer.DefaultClassAnalyzer;
55 import org.apache.maven.shared.dependency.analyzer.asm.ASMDependencyAnalyzer;
56 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
57 import org.apache.maven.shared.dependency.graph.DependencyNode;
58 import org.apache.tools.ant.taskdefs.Manifest;
59 import org.apache.tools.ant.taskdefs.ManifestException;
60 import org.codehaus.mojo.nbm.utils.ExamineManifest;
61 import org.codehaus.plexus.util.IOUtil;
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 @Mojo(name="manifest",
83 defaultPhase= LifecyclePhase.PROCESS_CLASSES,
84 requiresProject=true,
85 threadSafe = true,
86 requiresDependencyResolution= ResolutionScope.RUNTIME )
87 public class NetBeansManifestUpdateMojo
88 extends AbstractNbmMojo
89 {
90
91
92
93
94
95 @Parameter(defaultValue="${project.build.directory}/nbm", property="maven.nbm.buildDir")
96 protected File nbmBuildDir;
97
98
99
100
101
102 @Parameter(defaultValue="${basedir}/src/main/nbm/module.xml")
103 protected File descriptor;
104
105
106
107
108 @Parameter(required=true, readonly=true, property="project")
109 private MavenProject project;
110
111
112
113
114
115
116
117
118
119 @Parameter(defaultValue="${basedir}/src/main/javahelp")
120 protected File nbmJavahelpSource;
121
122
123
124
125
126
127 @Parameter(required=true, defaultValue="${basedir}/src/main/nbm/manifest.mf")
128 private File sourceManifestFile;
129
130
131
132
133
134 @Parameter(required=true, readonly=true, defaultValue="${project.build.outputDirectory}/META-INF/MANIFEST.MF")
135 private File targetManifestFile;
136
137
138
139
140
141
142
143
144
145
146 @Parameter(property="maven.nbm.verify", defaultValue="fail")
147 private String verifyRuntime;
148
149 private static final String FAIL = "fail";
150 private static final String WARN = "warn";
151 private static final String SKIP = "skip";
152
153
154
155
156
157
158
159
160
161
162 @Parameter
163 private List<String> publicPackages;
164
165
166
167
168
169
170
171
172
173
174
175
176 @Parameter(defaultValue="false")
177 private boolean useOSGiDependencies;
178
179
180
181
182
183
184
185 @Parameter(defaultValue="${project.groupId}.${project.artifactId}")
186 private String codeNameBase;
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211 @Parameter
212 private Dependency[] moduleDependencies;
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237 @Parameter(defaultValue="normal")
238 protected String moduleType;
239
240
241
242
243
244
245
246 @Parameter(required=true, readonly=true, defaultValue="${localRepository}")
247 private ArtifactRepository localRepository;
248
249
250
251
252 @Component
253 private ArtifactFactory artifactFactory;
254
255
256
257
258 @Component
259 private ArtifactMetadataSource artifactMetadataSource;
260
261
262
263
264 @Component
265 private ArtifactCollector artifactCollector;
266
267
268
269
270 @Component( hint = "default" )
271 private DependencyGraphBuilder dependencyGraphBuilder;
272
273
274
275
276
277
278
279
280
281 public void execute()
282 throws MojoExecutionException, MojoFailureException
283
284 {
285
286 super.registerNbmAntTasks();
287 NetBeansModule module;
288 if ( descriptor != null && descriptor.exists() )
289 {
290 module = readModuleDescriptor( descriptor );
291 getLog().warn( "descriptor parameter is deprecated, use equivalent mojo parameters instead.");
292 }
293 else
294 {
295 module = createDefaultDescriptor( project, false );
296 }
297
298 String mtype = moduleType;
299
300 if ("normal".equals(mtype) && module.getModuleType() != null) {
301 mtype = module.getModuleType();
302 getLog().warn( "moduleType in module descriptor is deprecated, use the plugin's parameter moduleType");
303 }
304 if (!"normal".equals(mtype) && !"autoload".equals(mtype) && !"eager".equals(mtype) && !"disabled".equals(mtype)) {
305 getLog().error( "Only 'normal,autoload,eager,disabled' are allowed values in the moduleType parameter");
306 }
307 boolean autoload = "autoload".equals( mtype );
308 boolean eager = "eager".equals( mtype );
309
310
311 String moduleName = codeNameBase;
312 if (module.getCodeNameBase() != null) {
313 moduleName = module.getCodeNameBase();
314 getLog().warn( "codeNameBase in module descriptor is deprecated, use the plugin's parameter codeNameBase");
315 }
316 moduleName = moduleName.replaceAll( "-", "." );
317
318
319 File specialManifest = sourceManifestFile;
320 File nbmManifest = ( module.getManifest() != null ? new File(
321 project.getBasedir(), module.getManifest() ) : null );
322 if ( nbmManifest != null && nbmManifest.exists() )
323 {
324
325 specialManifest = nbmManifest;
326 }
327 ExamineManifest examinator = new ExamineManifest( getLog() );
328 if ( specialManifest != null && specialManifest.exists() )
329 {
330 examinator.setManifestFile( specialManifest );
331 examinator.checkFile();
332 }
333 else
334 {
335
336 }
337
338 getLog().info( "NBM Plugin generates manifest" );
339
340 Manifest manifest = null;
341 if ( specialManifest != null && specialManifest.exists() )
342 {
343 Reader reader = null;
344 try
345 {
346 reader = new InputStreamReader( new FileInputStream( specialManifest ) );
347 manifest = new Manifest( reader );
348 }
349 catch ( IOException exc )
350 {
351 manifest = new Manifest();
352 getLog().warn( "Error reading manifest at " + specialManifest, exc );
353 }
354 catch ( ManifestException ex )
355 {
356 getLog().warn( "Error reading manifest at " + specialManifest, ex );
357 manifest = new Manifest();
358 }
359 finally
360 {
361 IOUtil.close( reader );
362 }
363 }
364 else
365 {
366 manifest = new Manifest();
367 }
368 Date date = new Date();
369 String specVersion = AdaptNbVersion.adaptVersion( project.getVersion(),
370 AdaptNbVersion.TYPE_SPECIFICATION, date );
371 String implVersion = AdaptNbVersion.adaptVersion( project.getVersion(),
372 AdaptNbVersion.TYPE_IMPLEMENTATION, date );
373 Manifest.Section mainSection = manifest.getMainSection();
374 conditionallyAddAttribute( mainSection,
375 "OpenIDE-Module-Specification-Version", specVersion );
376 conditionallyAddAttribute( mainSection,
377 "OpenIDE-Module-Implementation-Version", implVersion );
378 if (autoload || eager) {
379 conditionallyAddAttribute( mainSection, "AutoUpdate-Show-In-Client", "false");
380 }
381 final String timestamp = createTimestamp( date );
382 conditionallyAddAttribute( mainSection, "OpenIDE-Module-Build-Version",
383 timestamp );
384 String projectCNB = conditionallyAddAttribute( mainSection, "OpenIDE-Module", moduleName );
385 String packagesValue;
386 if ( publicPackages != null && publicPackages.size() > 0 )
387 {
388 StringBuilder sb = new StringBuilder();
389 for ( String pub : publicPackages )
390 {
391 if (pub == null) {
392 continue;
393 }
394 if ( pub.endsWith( ".**" ) )
395 {
396
397 sb.append( pub );
398 }
399 else if ( pub.endsWith( ".*" ) )
400 {
401
402 sb.append( pub ).append( "*" );
403 }
404 else
405 {
406 sb.append( pub ).append( ".*" );
407 }
408 sb.append( ", " );
409 }
410 if (sb.length() > 1) {
411 sb.setLength( sb.length() - 2 );
412 packagesValue = sb.toString();
413 } else {
414
415 packagesValue = "-";
416 }
417 }
418 else
419 {
420
421 packagesValue = "-";
422 }
423 conditionallyAddAttribute( mainSection, "OpenIDE-Module-Public-Packages", packagesValue );
424
425
426 conditionallyAddAttribute( mainSection, "OpenIDE-Module-Requires",
427 "org.openide.modules.ModuleFormat1" );
428
429
430 if ( !examinator.isLocalized() )
431 {
432 conditionallyAddAttribute( mainSection,
433 "OpenIDE-Module-Display-Category", project.getGroupId() );
434 conditionallyAddAttribute( mainSection, "OpenIDE-Module-Name",
435 project.getName() );
436 conditionallyAddAttribute( mainSection,
437 "OpenIDE-Module-Short-Description", shorten( project.getDescription() ) );
438 conditionallyAddAttribute( mainSection,
439 "OpenIDE-Module-Long-Description", project.getDescription() );
440 }
441 getLog().debug( "module =" + module );
442
443 DependencyNode treeroot = createDependencyTree( project, dependencyGraphBuilder, "compile" );
444 Map<Artifact, ExamineManifest> examinerCache = new HashMap<Artifact, ExamineManifest>();
445 @SuppressWarnings( "unchecked" )
446 List<Artifact> libArtifacts = getLibraryArtifacts( treeroot, module, project.getRuntimeArtifacts(),
447 examinerCache, getLog(), useOSGiDependencies );
448 List<ModuleWrapper> moduleArtifacts = getModuleDependencyArtifacts( treeroot, module, moduleDependencies, project, examinerCache,
449 libArtifacts, getLog(), useOSGiDependencies );
450 StringBuilder classPath = new StringBuilder();
451 StringBuilder mavenClassPath = new StringBuilder();
452 String dependencies = "";
453 String depSeparator = " ";
454
455 for ( Artifact a : libArtifacts )
456 {
457 if (classPath.length() > 0)
458 {
459 classPath.append(' ');
460 }
461 classPath.append(artifactToClassPathEntry( a, codeNameBase ));
462 if ( mavenClassPath.length() > 0 )
463 {
464 mavenClassPath.append( ' ' );
465 }
466 mavenClassPath.append( a.getGroupId() ).append( ':' ).append( a.getArtifactId() ).append( ':' ).append( a.getBaseVersion() );
467 if (a.getClassifier() != null)
468 {
469 mavenClassPath.append(":").append(a.getClassifier());
470 }
471 }
472
473 for ( ModuleWrapper wr : moduleArtifacts )
474 {
475 if ( wr.transitive )
476 {
477 continue;
478 }
479 Dependency dep = wr.dependency;
480 Artifact artifact = wr.artifact;
481 ExamineManifest depExaminator = examinerCache.get( artifact );
482 String type = dep.getType();
483 String depToken = dep.getExplicitValue();
484 if ( depToken == null )
485 {
486 if ( "loose".equals( type ) )
487 {
488 depToken = depExaminator.getModuleWithRelease();
489 }
490 else if ( "spec".equals( type ) )
491 {
492 depToken =
493 depExaminator.getModuleWithRelease()
494 + " > "
495 + ( depExaminator.isNetBeansModule() ? depExaminator.getSpecVersion()
496 : AdaptNbVersion.adaptVersion( depExaminator.getSpecVersion(),
497 AdaptNbVersion.TYPE_SPECIFICATION, date ) );
498 }
499 else if ( "impl".equals( type ) )
500 {
501 depToken =
502 depExaminator.getModuleWithRelease()
503 + " = "
504 + ( depExaminator.isNetBeansModule() ? depExaminator.getImplVersion()
505 : AdaptNbVersion.adaptVersion( depExaminator.getImplVersion(),
506 AdaptNbVersion.TYPE_IMPLEMENTATION, date ) );
507 }
508 else
509 {
510 throw new MojoExecutionException(
511 "Wrong type of NetBeans dependency: " + type + " Allowed values are: loose, spec, impl." );
512 }
513 }
514 if ( depToken == null )
515 {
516
517 getLog().error(
518 "Cannot properly resolve the NetBeans dependency for " + dep.getId() );
519 }
520 else
521 {
522 dependencies = dependencies + depSeparator + depToken;
523 depSeparator = ", ";
524 }
525 }
526 if ( !verifyRuntime.equalsIgnoreCase( SKIP ) )
527 {
528 try
529 {
530 checkModuleClassPath( treeroot, libArtifacts, examinerCache, moduleArtifacts, projectCNB );
531 }
532 catch ( IOException ex )
533 {
534 throw new MojoExecutionException( "Error while checking runtime dependencies", ex );
535 }
536 }
537
538 if ( nbmJavahelpSource.exists() )
539 {
540 String moduleJarName = stripVersionFromCodebaseName( moduleName ).replace( ".", "-" );
541 classPath.append( " docs/").append( moduleJarName ).append( ".jar" );
542 }
543
544 if ( classPath.length() > 0 )
545 {
546 conditionallyAddAttribute( mainSection, "X-Class-Path", classPath.toString().trim() );
547 }
548 if ( mavenClassPath.length() > 0)
549 {
550 conditionallyAddAttribute( mainSection, "Maven-Class-Path", mavenClassPath.toString() );
551 }
552 if ( dependencies.length() > 0 )
553 {
554 conditionallyAddAttribute( mainSection, "OpenIDE-Module-Module-Dependencies", dependencies );
555 }
556
557
558
559
560
561
562
563
564
565
566 PrintWriter writer = null;
567 try
568 {
569 if ( !targetManifestFile.exists() )
570 {
571 targetManifestFile.getParentFile().mkdirs();
572 targetManifestFile.createNewFile();
573 }
574 writer = new PrintWriter( targetManifestFile, "UTF-8" );
575 manifest.write( writer );
576 }
577 catch ( IOException ex )
578 {
579 throw new MojoExecutionException( ex.getMessage(), ex );
580 }
581 finally
582 {
583 IOUtil.close( writer );
584 }
585 }
586
587
588 static String artifactToClassPathEntry( Artifact a, String codenamebase )
589 {
590 return "ext/" + codenamebase + "/" + a.getGroupId().replace( '.', '-') + "/" + a.getArtifactId() + ( a.getClassifier() != null ? "-" + a.getClassifier() : "" ) + "." + a.getArtifactHandler().getExtension();
591 }
592
593
594
595
596
597
598
599
600
601
602 private static String createTimestamp( Date date )
603 {
604 final SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyyMMddHHmm" );
605 dateFormat.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
606 final String timestamp = dateFormat.format( date );
607 return timestamp;
608 }
609
610 static String stripVersionFromCodebaseName( String cnb )
611 {
612
613 String base = cnb;
614 int index = base.indexOf( '/' );
615 if ( index > -1 )
616 {
617 base = base.substring( 0, index ).trim();
618 }
619 return base;
620 }
621
622 String conditionallyAddAttribute( Manifest.Section section, String key, String value )
623 {
624 Manifest.Attribute attr = section.getAttribute( key );
625 if ( attr == null )
626 {
627 attr = new Manifest.Attribute();
628 attr.setName( key );
629 attr.setValue( value != null ? value.replaceAll("\\s+", " ").trim() : "<undefined>" );
630 try
631 {
632 section.addConfiguredAttribute( attr );
633 }
634 catch ( ManifestException ex )
635 {
636 getLog().error( "Cannot update manifest (key=" + key + ")" );
637 ex.printStackTrace();
638 }
639 }
640 return attr.getValue();
641 }
642
643
644
645
646
647
648 static String shorten( String paragraph )
649 {
650 if ( paragraph == null || paragraph.length() == 0 )
651 {
652 return null;
653 }
654 BreakIterator breaker = BreakIterator.getSentenceInstance();
655 breaker.setText( paragraph );
656 return paragraph.substring( 0, breaker.following( 0 ) ).trim();
657 }
658
659
660
661
662 private void checkModuleClassPath( DependencyNode treeroot,
663 List<Artifact> libArtifacts,
664 Map<Artifact, ExamineManifest> examinerCache, List<ModuleWrapper> moduleArtifacts, String projectCodeNameBase )
665 throws IOException, MojoExecutionException, MojoFailureException
666 {
667 Set<String> deps = buildProjectDependencyClasses( project, libArtifacts );
668 deps.retainAll( allProjectClasses( project ) );
669
670 Set<String> own = projectModuleOwnClasses( project, libArtifacts );
671 deps.removeAll( own );
672 CollectModuleLibrariesNodeVisitor visitor = new CollectModuleLibrariesNodeVisitor(
673 project.getRuntimeArtifacts(), examinerCache, getLog(), treeroot, useOSGiDependencies );
674 treeroot.accept( visitor );
675 Map<String, List<Artifact>> modules = visitor.getDeclaredArtifacts();
676 Map<Artifact, Set<String>> moduleAllClasses = new HashMap<Artifact, Set<String>>();
677
678 for ( ModuleWrapper wr : moduleArtifacts )
679 {
680 if ( modules.containsKey( wr.artifact.getDependencyConflictId() ) )
681 {
682 ExamineManifest man = examinerCache.get( wr.artifact );
683 List<Artifact> arts = modules.get( wr.artifact.getDependencyConflictId() );
684 Set<String>[] classes = visibleModuleClasses( arts, man, wr.dependency, projectCodeNameBase );
685 deps.removeAll( classes[0] );
686 moduleAllClasses.put( wr.artifact, classes[1] );
687 }
688 }
689
690
691
692 if ( !deps.isEmpty() )
693 {
694 Map<String, List<Artifact>> transmodules = visitor.getTransitiveArtifacts();
695 for ( ModuleWrapper wr : moduleArtifacts )
696 {
697 if ( transmodules.containsKey( wr.artifact.getDependencyConflictId() ) )
698 {
699 ExamineManifest man = examinerCache.get( wr.artifact );
700 List<Artifact> arts = transmodules.get( wr.artifact.getDependencyConflictId() );
701 Set<String>[] classes = visibleModuleClasses( arts, man, wr.dependency, projectCodeNameBase );
702 classes[0].retainAll( deps );
703 if ( classes[0].size() > 0 )
704 {
705 String module = wr.osgi ? "OSGi bundle" : "module";
706 getLog().error(
707 "Project uses classes from transitive " + module + " " + wr.artifact.getId() + " which will not be accessible at runtime." );
708 getLog().info( " To fix the problem, add this module as direct dependency. For OSGi bundles that are supposed to be wrapped in NetBeans modules, use the useOSGiDependencies=false parameter");
709 deps.removeAll( classes[0] );
710 }
711 classes[1].retainAll( deps );
712 if ( classes[1].size() > 0 )
713 {
714 getLog().info( "Private classes referenced in transitive module: " + Arrays.toString( classes[1].toArray() ) );
715 getLog().error(
716 "Project depends on packages not accessible at runtime in transitive module " + wr.artifact.getId() + " which will not be accessible at runtime." );
717 deps.removeAll( classes[1] );
718 }
719 }
720 }
721 for ( Map.Entry<Artifact, Set<String>> e : moduleAllClasses.entrySet() )
722 {
723 List<String> strs = new ArrayList<String>( deps );
724 if ( deps.removeAll( e.getValue() ) )
725 {
726 strs.retainAll( e.getValue() );
727 getLog().info( "Private classes referenced in module: " + Arrays.toString( strs.toArray() ) );
728 getLog().error( "Project depends on packages not accessible at runtime in module " + e.getKey().getId() );
729 }
730 }
731 if ( verifyRuntime.equalsIgnoreCase( FAIL ) )
732 {
733 if ( !deps.isEmpty() )
734 {
735 throw new MojoFailureException( "Uncategorized problems with NetBeans dependency verification (maybe MNBMODULE-102 or wrong maven dependency metadata). Supposedly external classes are used in the project's binaries but the classes are not found on classpath. Class usages: " + deps );
736 }
737 else
738 {
739 throw new MojoFailureException( "See above for failures in runtime NetBeans dependencies verification." );
740 }
741 }
742 }
743 }
744
745
746
747
748
749
750
751
752
753 private Set<String> buildProjectDependencyClasses( MavenProject project, List<Artifact> libraries )
754 throws IOException
755 {
756 Set<String> dependencyClasses = new HashSet<String>();
757
758 String outputDirectory = project.getBuild().getOutputDirectory();
759 dependencyClasses.addAll( buildDependencyClasses( outputDirectory ) );
760
761 for ( Artifact lib : libraries )
762 {
763 dependencyClasses.addAll( buildDependencyClasses( lib.getFile().getAbsolutePath() ) );
764 }
765 return dependencyClasses;
766 }
767
768 @SuppressWarnings( "unchecked" )
769 private Set<String> projectModuleOwnClasses( MavenProject project, List<Artifact> libraries )
770 throws IOException
771 {
772 Set<String> projectClasses = new HashSet<String>();
773 DefaultClassAnalyzer analyzer = new DefaultClassAnalyzer();
774
775 String outputDirectory = project.getBuild().getOutputDirectory();
776 URL fl = new File( outputDirectory ).toURI().toURL();
777 projectClasses.addAll( analyzer.analyze( fl ) );
778
779 for ( Artifact lib : libraries )
780 {
781 URL url = lib.getFile().toURI().toURL();
782 projectClasses.addAll( analyzer.analyze( url ) );
783 }
784
785 return projectClasses;
786 }
787
788
789
790
791
792
793
794
795 @SuppressWarnings( "unchecked" )
796 private Set<String> allProjectClasses( MavenProject project )
797 throws IOException
798 {
799 Set<String> projectClasses = new HashSet<String>();
800 DefaultClassAnalyzer analyzer = new DefaultClassAnalyzer();
801
802 String outputDirectory = project.getBuild().getOutputDirectory();
803 URL fl = new File( outputDirectory ).toURI().toURL();
804 projectClasses.addAll( analyzer.analyze( fl ) );
805
806 List<Artifact> libs = project.getRuntimeArtifacts();
807
808 for ( Artifact lib : libs )
809 {
810 URL url = lib.getFile().toURI().toURL();
811 projectClasses.addAll( analyzer.analyze( url ) );
812 }
813
814 return projectClasses;
815 }
816
817 private Set<String>[] visibleModuleClasses( List<Artifact> moduleLibraries,
818 ExamineManifest manifest, Dependency dep, String projectCodeNameBase )
819 throws IOException, MojoFailureException
820 {
821 Set<String> moduleClasses = new HashSet<String>();
822 Set<String> visibleModuleClasses = new HashSet<String>();
823 DefaultClassAnalyzer analyzer = new DefaultClassAnalyzer();
824 String type = dep.getType();
825 if ( dep.getExplicitValue() != null )
826 {
827 if ( dep.getExplicitValue().contains( "=" ) )
828 {
829 type = "impl";
830 }
831 }
832 if ( type == null || "loose".equals( type ) )
833 {
834 type = "spec";
835 }
836
837 for ( Artifact lib : moduleLibraries )
838 {
839 URL url = lib.getFile().toURI().toURL();
840 moduleClasses.addAll( analyzer.analyze( url ) );
841 }
842
843 if ( "spec".equals( type ) )
844 {
845 String cnb = stripVersionFromCodebaseName( projectCodeNameBase );
846 if ( manifest.hasFriendPackages() && !manifest.getFriends().contains( cnb ) )
847 {
848 String message = "Module has friend dependency on " + manifest.getModule() + " but is not listed as a friend.";
849 if ( verifyRuntime.equalsIgnoreCase( FAIL ) )
850 {
851 throw new MojoFailureException( message );
852 }
853 else
854 {
855 getLog().warn( message );
856 }
857 }
858 List<Pattern> compiled = createCompiledPatternList( manifest.getPackages() );
859 if ( useOSGiDependencies && manifest.isOsgiBundle() )
860 {
861
862 compiled = Collections.singletonList( Pattern.compile( "(.+)" ) );
863 }
864 for ( String clazz : moduleClasses )
865 {
866 for ( Pattern patt : compiled )
867 {
868 if ( patt.matcher( clazz ).matches() )
869 {
870 visibleModuleClasses.add( clazz );
871 break;
872 }
873 }
874 }
875
876 }
877 else if ( "impl".equals( type ) )
878 {
879 visibleModuleClasses.addAll( moduleClasses );
880 }
881 else
882 {
883
884 throw new MojoFailureException( "Wrong type of module dependency " + type );
885 }
886
887 return new Set[]
888 {
889 visibleModuleClasses,
890 moduleClasses
891 };
892 }
893
894 static List<Pattern> createCompiledPatternList( List<String> packages )
895 {
896 List<Pattern> toRet = new ArrayList<Pattern>();
897 for ( String token : packages )
898 {
899 if ( token.endsWith( ".**" ) )
900 {
901 String patt = "^" + Pattern.quote( token.substring( 0, token.length() - 2 ) ) + "(.+)";
902 toRet.add( 0, Pattern.compile( patt ) );
903 }
904 else
905 {
906 String patt = "^" + Pattern.quote( token.substring( 0, token.length() - 1 ) ) + "([^\\.]+)";
907 toRet.add( Pattern.compile( patt ) );
908 }
909 }
910 return toRet;
911 }
912
913 @SuppressWarnings( "unchecked" )
914 private Set<String> buildDependencyClasses( String path )
915 throws IOException
916 {
917 URL url = new File( path ).toURI().toURL();
918 ASMDependencyAnalyzer dependencyAnalyzer = new ASMDependencyAnalyzer();
919 return dependencyAnalyzer.analyze( url );
920 }
921 }