1 package org.apache.maven.plugin.resources.remote;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.ProjectDependenciesResolver;
23 import org.apache.maven.artifact.Artifact;
24 import org.apache.maven.artifact.factory.ArtifactFactory;
25 import org.apache.maven.artifact.repository.ArtifactRepository;
26 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
27 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
28 import org.apache.maven.artifact.resolver.ArtifactResolver;
29 import org.apache.maven.artifact.versioning.VersionRange;
30 import org.apache.maven.execution.MavenSession;
31 import org.apache.maven.model.Model;
32 import org.apache.maven.model.Organization;
33 import org.apache.maven.model.Resource;
34 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
35 import org.apache.maven.plugin.AbstractMojo;
36 import org.apache.maven.plugin.MojoExecutionException;
37 import org.apache.maven.plugin.logging.Log;
38 import org.apache.maven.plugin.resources.remote.io.xpp3.RemoteResourcesBundleXpp3Reader;
39 import org.apache.maven.plugin.resources.remote.io.xpp3.SupplementalDataModelXpp3Reader;
40 import org.apache.maven.plugins.annotations.Component;
41 import org.apache.maven.plugins.annotations.LifecyclePhase;
42 import org.apache.maven.plugins.annotations.Mojo;
43 import org.apache.maven.plugins.annotations.Parameter;
44 import org.apache.maven.project.InvalidProjectModelException;
45 import org.apache.maven.project.MavenProject;
46 import org.apache.maven.project.MavenProjectBuilder;
47 import org.apache.maven.project.ProjectBuildingException;
48 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
49 import org.apache.maven.project.inheritance.ModelInheritanceAssembler;
50 import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
51 import org.apache.maven.shared.artifact.filter.collection.ArtifactIdFilter;
52 import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
53 import org.apache.maven.shared.artifact.filter.collection.GroupIdFilter;
54 import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
55 import org.apache.maven.shared.artifact.filter.collection.TransitivityFilter;
56 import org.apache.maven.shared.filtering.MavenFileFilter;
57 import org.apache.maven.shared.filtering.MavenFileFilterRequest;
58 import org.apache.maven.shared.filtering.MavenFilteringException;
59 import org.apache.velocity.VelocityContext;
60 import org.apache.velocity.app.Velocity;
61 import org.apache.velocity.exception.MethodInvocationException;
62 import org.apache.velocity.exception.ParseErrorException;
63 import org.apache.velocity.exception.ResourceNotFoundException;
64 import org.codehaus.plexus.resource.ResourceManager;
65 import org.codehaus.plexus.resource.loader.FileResourceLoader;
66 import org.codehaus.plexus.util.FileUtils;
67 import org.codehaus.plexus.util.IOUtil;
68 import org.codehaus.plexus.util.ReaderFactory;
69 import org.codehaus.plexus.util.StringUtils;
70 import org.codehaus.plexus.util.WriterFactory;
71 import org.codehaus.plexus.util.xml.Xpp3Dom;
72 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
73 import org.codehaus.plexus.velocity.VelocityComponent;
74
75 import java.io.File;
76 import java.io.FileInputStream;
77 import java.io.FileOutputStream;
78 import java.io.FileReader;
79 import java.io.FileWriter;
80 import java.io.IOException;
81 import java.io.InputStream;
82 import java.io.InputStreamReader;
83 import java.io.OutputStream;
84 import java.io.OutputStreamWriter;
85 import java.io.PrintWriter;
86 import java.io.Reader;
87 import java.io.StringReader;
88 import java.io.Writer;
89 import java.net.MalformedURLException;
90 import java.net.URL;
91 import java.text.SimpleDateFormat;
92 import java.util.ArrayList;
93 import java.util.Collections;
94 import java.util.Comparator;
95 import java.util.Date;
96 import java.util.Enumeration;
97 import java.util.HashMap;
98 import java.util.LinkedHashSet;
99 import java.util.List;
100 import java.util.Map;
101 import java.util.Properties;
102 import java.util.Set;
103 import java.util.TreeMap;
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 @Mojo( name = "process", defaultPhase = LifecyclePhase.GENERATE_RESOURCES, threadSafe = true )
126 public class ProcessRemoteResourcesMojo
127 extends AbstractMojo
128 {
129
130 private static final String TEMPLATE_SUFFIX = ".vm";
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 @Parameter
154 protected List<String> filterDelimiters;
155
156
157
158
159 @Parameter( defaultValue = "true" )
160 protected boolean useDefaultFilterDelimiters;
161
162
163
164
165
166
167
168 @Parameter( defaultValue = "false" )
169 protected boolean runOnlyAtExecutionRoot;
170
171
172
173
174 @Parameter( defaultValue = "${basedir}", readonly = true, required = true )
175 protected File basedir;
176
177
178
179
180 @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
181 protected String encoding;
182
183
184
185
186 @Parameter( defaultValue = "${localRepository}", readonly = true, required = true )
187 private ArtifactRepository localRepository;
188
189
190
191
192 @Parameter( defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true )
193 private List<ArtifactRepository> remoteArtifactRepositories;
194
195
196
197
198 @Component
199 private MavenProject project;
200
201
202
203
204 @Parameter( defaultValue = "${project.build.directory}/maven-shared-archive-resources" )
205 private File outputDirectory;
206
207
208
209
210 @Parameter( defaultValue = "${basedir}/src/main/appended-resources" )
211 private File appendedResourcesDirectory;
212
213
214
215
216
217
218
219
220
221
222 @Parameter
223 private String[] supplementalModels;
224
225
226
227
228
229
230
231
232 @Parameter
233 private List<String> supplementalModelArtifacts;
234
235
236
237
238 private Map<String, Model> supplementModels;
239
240
241
242
243
244
245 @Component
246 private ModelInheritanceAssembler inheritanceAssembler;
247
248
249
250
251
252 @Parameter( required = true )
253 private List<String> resourceBundles;
254
255
256
257
258
259
260 @Parameter( property = "remoteresources.skip", defaultValue = "false" )
261 private boolean skip;
262
263
264
265
266
267
268 @Parameter( defaultValue = "true" )
269 private boolean attached = true;
270
271
272
273
274
275
276
277
278
279
280
281
282 @Parameter
283 private Map<String, String> properties = new HashMap<String, String>();
284
285
286
287
288
289
290 @Parameter( defaultValue = "false" )
291 protected boolean includeProjectProperties = false;
292
293
294
295
296 @Parameter( defaultValue = "${project.resources}", readonly = true, required = true )
297 private List<Resource> resources;
298
299
300
301
302 @Component
303 private ArtifactResolver artifactResolver;
304
305
306
307
308 @Component
309 private VelocityComponent velocity;
310
311
312
313
314 @Component
315 private MavenFileFilter fileFilter;
316
317
318
319
320 @Component
321 private ArtifactFactory artifactFactory;
322
323
324
325
326 @Component
327 private MavenSession mavenSession;
328
329
330
331
332 @Component( role = MavenProjectBuilder.class )
333 private MavenProjectBuilder mavenProjectBuilder;
334
335
336
337 @Component
338 private ResourceManager locator;
339
340
341
342
343
344
345
346 @Parameter( property = "includeScope", defaultValue = "runtime" )
347 protected String includeScope;
348
349
350
351
352
353
354 @Parameter( property = "excludeScope", defaultValue = "" )
355 protected String excludeScope;
356
357
358
359
360
361
362 @Parameter( property = "excludeArtifactIds", defaultValue = "" )
363 protected String excludeArtifactIds;
364
365
366
367
368
369
370 @Parameter( property = "includeArtifactIds", defaultValue = "" )
371 protected String includeArtifactIds;
372
373
374
375
376
377
378 @Parameter( property = "excludeGroupIds", defaultValue = "" )
379 protected String excludeGroupIds;
380
381
382
383
384
385
386 @Parameter( property = "includeGroupIds", defaultValue = "" )
387 protected String includeGroupIds;
388
389
390
391
392
393
394 @Parameter( property = "excludeTransitive", defaultValue = "false" )
395 protected boolean excludeTransitive;
396
397
398
399 @Component( hint = "default" )
400 protected ProjectDependenciesResolver dependencyResolver;
401
402 @SuppressWarnings( "unchecked" )
403 public void execute()
404 throws MojoExecutionException
405 {
406 if ( skip )
407 {
408 return;
409 }
410
411 if ( runOnlyAtExecutionRoot && !isExecutionRoot() )
412 {
413 getLog().info( "Skipping remote-resource generation in this project because it's not the Execution Root" );
414 return;
415 }
416
417 if ( supplementalModels == null )
418 {
419 File sups = new File( appendedResourcesDirectory, "supplemental-models.xml" );
420 if ( sups.exists() )
421 {
422 try
423 {
424 supplementalModels = new String[]{ sups.toURL().toString() };
425 }
426 catch ( MalformedURLException e )
427 {
428
429 getLog().debug( "URL issue with supplemental-models.xml: " + e.toString() );
430 }
431 }
432 }
433
434 addSupplementalModelArtifacts();
435 locator.addSearchPath( FileResourceLoader.ID, project.getFile().getParentFile().getAbsolutePath() );
436 if ( appendedResourcesDirectory != null )
437 {
438 locator.addSearchPath( FileResourceLoader.ID, appendedResourcesDirectory.getAbsolutePath() );
439 }
440 locator.addSearchPath( "url", "" );
441 locator.setOutputDirectory( new File( project.getBuild().getDirectory() ) );
442
443 if ( includeProjectProperties )
444 {
445 final Properties projectProperties = project.getProperties();
446 for ( Object key : projectProperties.keySet() )
447 {
448 properties.put( key.toString(), projectProperties.get( key ).toString() );
449 }
450 }
451
452 ClassLoader origLoader = Thread.currentThread().getContextClassLoader();
453 try
454 {
455 Thread.currentThread().setContextClassLoader( this.getClass().getClassLoader() );
456
457 validate();
458
459 List<File> resourceBundleArtifacts = downloadBundles( resourceBundles );
460 supplementModels = loadSupplements( supplementalModels );
461
462 VelocityContext context = new VelocityContext( properties );
463 configureVelocityContext( context );
464
465 RemoteResourcesClassLoader classLoader = new RemoteResourcesClassLoader( null );
466
467 initalizeClassloader( classLoader, resourceBundleArtifacts );
468 Thread.currentThread().setContextClassLoader( classLoader );
469
470 processResourceBundles( classLoader, context );
471
472 try
473 {
474 if ( outputDirectory.exists() )
475 {
476
477
478
479
480 if ( attached )
481 {
482 Resource resource = new Resource();
483 resource.setDirectory( outputDirectory.getAbsolutePath() );
484
485 project.getResources().add( resource );
486 project.getTestResources().add( resource );
487 }
488
489
490
491
492 File dotFile = new File( project.getBuild().getDirectory(), ".plxarc" );
493 FileUtils.mkdir( dotFile.getParentFile().getAbsolutePath() );
494 FileUtils.fileWrite( dotFile.getAbsolutePath(), outputDirectory.getName() );
495 }
496 }
497 catch ( IOException e )
498 {
499 throw new MojoExecutionException( "Error creating dot file for archiving instructions.", e );
500 }
501 }
502 finally
503 {
504 Thread.currentThread().setContextClassLoader( origLoader );
505 }
506 }
507
508 private boolean isExecutionRoot()
509 {
510 Log log = this.getLog();
511
512 boolean result = mavenSession.getExecutionRootDirectory().equalsIgnoreCase( basedir.toString() );
513
514 if ( log.isDebugEnabled() )
515 {
516 log.debug( "Root Folder:" + mavenSession.getExecutionRootDirectory() );
517 log.debug( "Current Folder:" + basedir );
518
519 if ( result )
520 {
521 log.debug( "This is the execution root." );
522 }
523 else
524 {
525 log.debug( "This is NOT the execution root." );
526 }
527 }
528
529 return result;
530 }
531
532 private void addSupplementalModelArtifacts()
533 throws MojoExecutionException
534 {
535 if ( supplementalModelArtifacts != null && !supplementalModelArtifacts.isEmpty() )
536 {
537 List<File> artifacts = downloadBundles( supplementalModelArtifacts );
538
539 for ( File artifact : artifacts )
540 {
541 if ( artifact.isDirectory() )
542 {
543 locator.addSearchPath( FileResourceLoader.ID, artifact.getAbsolutePath() );
544 }
545 else
546 {
547 try
548 {
549 locator.addSearchPath( "jar", "jar:" + artifact.toURL().toExternalForm() );
550 }
551 catch ( MalformedURLException e )
552 {
553 throw new MojoExecutionException( "Could not use jar " + artifact.getAbsolutePath(), e );
554 }
555 }
556 }
557
558
559 }
560 }
561
562 @SuppressWarnings( "unchecked" )
563 protected List<MavenProject> getProjects()
564 throws MojoExecutionException
565 {
566 List<MavenProject> projects = new ArrayList<MavenProject>();
567
568
569 FilterArtifacts filter = new FilterArtifacts();
570
571 Set<Artifact> depArtifacts;
572 Set<Artifact> artifacts = resolveProjectArtifacts();
573 if ( runOnlyAtExecutionRoot )
574 {
575 depArtifacts = aggregateProjectDependencyArtifacts();
576 }
577 else
578 {
579 depArtifacts = project.getDependencyArtifacts();
580 }
581
582 filter.addFilter( new TransitivityFilter( depArtifacts, this.excludeTransitive ) );
583 filter.addFilter( new ScopeFilter( this.includeScope, this.excludeScope ) );
584 filter.addFilter( new GroupIdFilter( this.includeGroupIds, this.excludeGroupIds ) );
585 filter.addFilter( new ArtifactIdFilter( this.includeArtifactIds, this.excludeArtifactIds ) );
586
587
588 try
589 {
590 artifacts = filter.filter( artifacts );
591 }
592 catch ( ArtifactFilterException e )
593 {
594 throw new MojoExecutionException( e.getMessage(), e );
595 }
596
597 for ( Artifact artifact : artifacts )
598 {
599 try
600 {
601 List<ArtifactRepository> remoteRepo = remoteArtifactRepositories;
602 if ( artifact.isSnapshot() )
603 {
604 VersionRange rng = VersionRange.createFromVersion( artifact.getBaseVersion() );
605 artifact =
606 artifactFactory.createDependencyArtifact( artifact.getGroupId(), artifact.getArtifactId(), rng,
607 artifact.getType(), artifact.getClassifier(),
608 artifact.getScope(), null, artifact.isOptional() );
609 }
610
611 getLog().debug( "Building project for " + artifact );
612 MavenProject p = null;
613 try
614 {
615 p = mavenProjectBuilder.buildFromRepository( artifact, remoteRepo, localRepository );
616 }
617 catch ( InvalidProjectModelException e )
618 {
619 getLog().warn( "Invalid project model for artifact [" + artifact.getArtifactId() + ":" +
620 artifact.getGroupId() + ":" + artifact.getVersion() + "]. " +
621 "It will be ignored by the remote resources Mojo." );
622 continue;
623 }
624
625 String supplementKey =
626 generateSupplementMapKey( p.getModel().getGroupId(), p.getModel().getArtifactId() );
627
628 if ( supplementModels.containsKey( supplementKey ) )
629 {
630 Model mergedModel = mergeModels( p.getModel(), (Model) supplementModels.get( supplementKey ) );
631 MavenProject mergedProject = new MavenProject( mergedModel );
632 projects.add( mergedProject );
633 mergedProject.setArtifact( artifact );
634 mergedProject.setVersion( artifact.getVersion() );
635 getLog().debug( "Adding project with groupId [" + mergedProject.getGroupId() + "] (supplemented)" );
636 }
637 else
638 {
639 projects.add( p );
640 getLog().debug( "Adding project with groupId [" + p.getGroupId() + "]" );
641 }
642 }
643 catch ( ProjectBuildingException e )
644 {
645 throw new MojoExecutionException( e.getMessage(), e );
646 }
647 }
648 Collections.sort( projects, new ProjectComparator() );
649 return projects;
650 }
651
652 @SuppressWarnings( "unchecked" )
653 private Set<Artifact> resolveProjectArtifacts()
654 throws MojoExecutionException
655 {
656 try
657 {
658 if ( runOnlyAtExecutionRoot )
659 {
660 List<MavenProject> projects = mavenSession.getSortedProjects();
661 return dependencyResolver.resolve( projects, Collections.singleton( Artifact.SCOPE_TEST ),
662 mavenSession );
663 }
664 else
665 {
666 return dependencyResolver.resolve( project, Collections.singleton( Artifact.SCOPE_TEST ),
667 mavenSession );
668 }
669 }
670 catch ( ArtifactResolutionException e )
671 {
672 throw new MojoExecutionException(
673 "Failed to resolve dependencies for one or more projects in the reactor. Reason: " + e.getMessage(),
674 e );
675 }
676 catch ( ArtifactNotFoundException e )
677 {
678 throw new MojoExecutionException(
679 "Failed to resolve dependencies for one or more projects in the reactor. Reason: " + e.getMessage(),
680 e );
681 }
682 }
683
684 @SuppressWarnings( "unchecked" )
685 private Set<Artifact> aggregateProjectDependencyArtifacts()
686 throws MojoExecutionException
687 {
688 Set<Artifact> artifacts = new LinkedHashSet<Artifact>();
689
690 List<MavenProject> projects = mavenSession.getSortedProjects();
691 for ( MavenProject p : projects )
692 {
693 if ( p.getDependencyArtifacts() == null )
694 {
695 try
696 {
697 Set<Artifact> depArtifacts = p.createArtifacts( artifactFactory, null, null );
698 p.setDependencyArtifacts( depArtifacts );
699
700 if ( depArtifacts != null && !depArtifacts.isEmpty() )
701 {
702 artifacts.addAll( depArtifacts );
703 }
704 }
705 catch ( InvalidDependencyVersionException e )
706 {
707 throw new MojoExecutionException(
708 "Failed to create dependency artifacts for: " + p.getId() + ". Reason: " + e.getMessage(), e );
709 }
710 }
711 }
712
713 return artifacts;
714 }
715
716 protected Map<Organization, List<MavenProject>> getProjectsSortedByOrganization( List<MavenProject> projects )
717 throws MojoExecutionException
718 {
719 Map<Organization, List<MavenProject>> organizations =
720 new TreeMap<Organization, List<MavenProject>>( new OrganizationComparator() );
721 List<MavenProject> unknownOrganization = new ArrayList<MavenProject>();
722
723 for ( MavenProject p : projects )
724 {
725 if ( p.getOrganization() != null && StringUtils.isNotEmpty( p.getOrganization().getName() ) )
726 {
727 List<MavenProject> sortedProjects = (List<MavenProject>) organizations.get( p.getOrganization() );
728 if ( sortedProjects == null )
729 {
730 sortedProjects = new ArrayList<MavenProject>();
731 }
732 sortedProjects.add( p );
733
734 organizations.put( p.getOrganization(), sortedProjects );
735 }
736 else
737 {
738 unknownOrganization.add( p );
739 }
740 }
741 if ( !unknownOrganization.isEmpty() )
742 {
743 Organization unknownOrg = new Organization();
744 unknownOrg.setName( "an unknown organization" );
745 organizations.put( unknownOrg, unknownOrganization );
746 }
747
748 return organizations;
749 }
750
751 protected boolean copyResourceIfExists( File file, String relFileName, VelocityContext context )
752 throws IOException, MojoExecutionException
753 {
754 for ( Resource resource : resources )
755 {
756 File resourceDirectory = new File( resource.getDirectory() );
757
758 if ( !resourceDirectory.exists() )
759 {
760 continue;
761 }
762
763
764 File source = new File( resourceDirectory, relFileName );
765 File templateSource = new File( resourceDirectory, relFileName + TEMPLATE_SUFFIX );
766
767 if ( !source.exists() && templateSource.exists() )
768 {
769 source = templateSource;
770 }
771
772 if ( source.exists() && !source.equals( file ) )
773 {
774 if ( source == templateSource )
775 {
776 Reader reader = null;
777 Writer writer = null;
778 try
779 {
780 if ( encoding != null )
781 {
782 reader = new InputStreamReader( new FileInputStream( source ), encoding );
783 writer = new OutputStreamWriter( new FileOutputStream( file ), encoding );
784 }
785 else
786 {
787 reader = ReaderFactory.newPlatformReader( source );
788 writer = WriterFactory.newPlatformWriter( file );
789 }
790
791 velocity.getEngine().evaluate( context, writer, "", reader );
792 velocity.getEngine().evaluate( context, writer, "", reader );
793 }
794 catch ( ParseErrorException e )
795 {
796 throw new MojoExecutionException( "Error rendering velocity resource.", e );
797 }
798 catch ( MethodInvocationException e )
799 {
800 throw new MojoExecutionException( "Error rendering velocity resource.", e );
801 }
802 catch ( ResourceNotFoundException e )
803 {
804 throw new MojoExecutionException( "Error rendering velocity resource.", e );
805 }
806 finally
807 {
808 IOUtil.close( writer );
809 IOUtil.close( reader );
810 }
811 }
812 else if ( resource.isFiltering() )
813 {
814
815 MavenFileFilterRequest req = setupRequest( resource, source, file );
816
817 try
818 {
819 fileFilter.copyFile( req );
820 }
821 catch ( MavenFilteringException e )
822 {
823 throw new MojoExecutionException( "Error filtering resource: " + source, e );
824 }
825 }
826 else
827 {
828 FileUtils.copyFile( source, file );
829 }
830
831
832 resource.addExclude( relFileName );
833
834 return true;
835 }
836
837 }
838 return false;
839 }
840
841 @SuppressWarnings( "unchecked" )
842 private MavenFileFilterRequest setupRequest( Resource resource, File source, File file )
843 {
844 MavenFileFilterRequest req = new MavenFileFilterRequest();
845 req.setFrom( source );
846 req.setTo( file );
847 req.setFiltering( resource.isFiltering() );
848
849 req.setMavenProject( project );
850 req.setMavenSession( mavenSession );
851 req.setInjectProjectBuildFilters( true );
852
853 if ( encoding != null )
854 {
855 req.setEncoding( encoding );
856 }
857
858 if ( filterDelimiters != null && !filterDelimiters.isEmpty() )
859 {
860 LinkedHashSet<String> delims = new LinkedHashSet<String>();
861 if ( useDefaultFilterDelimiters )
862 {
863 delims.addAll( req.getDelimiters() );
864 }
865
866 for ( String delim : filterDelimiters )
867 {
868 if ( delim == null )
869 {
870 delims.add( "${*}" );
871 }
872 else
873 {
874 delims.add( delim );
875 }
876 }
877
878 req.setDelimiters( delims );
879 }
880
881 return req;
882 }
883
884 protected void validate()
885 throws MojoExecutionException
886 {
887 int bundleCount = 1;
888
889 for ( String artifactDescriptor : resourceBundles )
890 {
891
892
893 String[] s = StringUtils.split( artifactDescriptor, ":" );
894
895 if ( s.length < 3 || s.length > 5 )
896 {
897 String position;
898
899 if ( bundleCount == 1 )
900 {
901 position = "1st";
902 }
903 else if ( bundleCount == 2 )
904 {
905 position = "2nd";
906 }
907 else if ( bundleCount == 3 )
908 {
909 position = "3rd";
910 }
911 else
912 {
913 position = bundleCount + "th";
914 }
915
916 throw new MojoExecutionException( "The " + position +
917 " resource bundle configured must specify a groupId, artifactId, " +
918 " version and, optionally, type and classifier for a remote resource bundle. " +
919 "Must be of the form <resourceBundle>groupId:artifactId:version</resourceBundle>, " +
920 "<resourceBundle>groupId:artifactId:version:type</resourceBundle> or " +
921 "<resourceBundle>groupId:artifactId:version:type:classifier</resourceBundle>" );
922 }
923
924 bundleCount++;
925 }
926
927 }
928
929 protected void configureVelocityContext( VelocityContext context )
930 throws MojoExecutionException
931 {
932 String inceptionYear = project.getInceptionYear();
933 String year = new SimpleDateFormat( "yyyy" ).format( new Date() );
934
935 if ( StringUtils.isEmpty( inceptionYear ) )
936 {
937 if ( getLog().isDebugEnabled() )
938 {
939 getLog().debug( "inceptionYear not specified, defaulting to " + year );
940 }
941
942 inceptionYear = year;
943 }
944 context.put( "project", project );
945 List<MavenProject> projects = getProjects();
946 context.put( "projects", projects );
947 context.put( "projectsSortedByOrganization", getProjectsSortedByOrganization( projects ) );
948
949 context.put( "presentYear", year );
950
951 if ( inceptionYear.equals( year ) )
952 {
953 context.put( "projectTimespan", year );
954 }
955 else
956 {
957 context.put( "projectTimespan", inceptionYear + "-" + year );
958 }
959 }
960
961 @SuppressWarnings( "unchecked" )
962 private List<File> downloadBundles( List<String> bundles )
963 throws MojoExecutionException
964 {
965 List<File> bundleArtifacts = new ArrayList<File>();
966
967 try
968 {
969 for ( String artifactDescriptor : bundles )
970 {
971
972 String[] s = artifactDescriptor.split( ":" );
973
974 File artifactFile = null;
975
976 if ( mavenSession != null )
977 {
978 List<MavenProject> list = mavenSession.getSortedProjects();
979 for ( MavenProject p : list )
980 {
981 if ( s[0].equals( p.getGroupId() ) && s[1].equals( p.getArtifactId() ) &&
982 s[2].equals( p.getVersion() ) )
983 {
984 artifactFile = new File( p.getBuild().getOutputDirectory() );
985 }
986 }
987 }
988 if ( artifactFile == null || !artifactFile.exists() )
989 {
990 String type = ( s.length >= 4 ? s[3] : "jar" );
991 String classifier = ( s.length == 5 ? s[4] : null );
992 Artifact artifact =
993 artifactFactory.createDependencyArtifact( s[0], s[1], VersionRange.createFromVersion( s[2] ),
994 type, classifier, Artifact.SCOPE_RUNTIME );
995
996 artifactResolver.resolve( artifact, remoteArtifactRepositories, localRepository );
997
998 artifactFile = artifact.getFile();
999 }
1000 bundleArtifacts.add( artifactFile );
1001 }
1002 }
1003 catch ( ArtifactResolutionException e )
1004 {
1005 throw new MojoExecutionException( "Error downloading resources archive.", e );
1006 }
1007 catch ( ArtifactNotFoundException e )
1008 {
1009 throw new MojoExecutionException( "Resources archive cannot be found.", e );
1010 }
1011
1012 return bundleArtifacts;
1013 }
1014
1015 private void initalizeClassloader( RemoteResourcesClassLoader cl, List<File> artifacts )
1016 throws MojoExecutionException
1017 {
1018 try
1019 {
1020 for ( File artifact : artifacts )
1021 {
1022 cl.addURL( artifact.toURI().toURL() );
1023 }
1024 }
1025 catch ( MalformedURLException e )
1026 {
1027 throw new MojoExecutionException( "Unable to configure resources classloader: " + e.getMessage(), e );
1028 }
1029 }
1030
1031 protected void processResourceBundles( RemoteResourcesClassLoader classLoader, VelocityContext context )
1032 throws MojoExecutionException
1033 {
1034 InputStreamReader reader = null;
1035
1036 try
1037 {
1038
1039 for ( Enumeration<URL> e = classLoader.getResources( BundleRemoteResourcesMojo.RESOURCES_MANIFEST );
1040 e.hasMoreElements(); )
1041 {
1042 URL url = (URL) e.nextElement();
1043
1044 try
1045 {
1046 reader = new InputStreamReader( url.openStream() );
1047
1048 RemoteResourcesBundleXpp3Reader bundleReader = new RemoteResourcesBundleXpp3Reader();
1049
1050 RemoteResourcesBundle bundle = bundleReader.read( reader );
1051
1052 for ( String bundleResource : (List<String>) bundle.getRemoteResources() )
1053 {
1054 String projectResource = bundleResource;
1055
1056 boolean doVelocity = false;
1057 if ( projectResource.endsWith( TEMPLATE_SUFFIX ) )
1058 {
1059 projectResource = projectResource.substring( 0, projectResource.length() - 3 );
1060 doVelocity = true;
1061 }
1062
1063
1064
1065 File f = new File( outputDirectory, projectResource );
1066
1067 FileUtils.mkdir( f.getParentFile().getAbsolutePath() );
1068
1069 if ( !copyResourceIfExists( f, projectResource, context ) )
1070 {
1071 if ( doVelocity )
1072 {
1073 PrintWriter writer;
1074 if ( bundle.getSourceEncoding() == null )
1075 {
1076 writer = new PrintWriter( new FileWriter( f ) );
1077 }
1078 else
1079 {
1080 writer = new PrintWriter( new OutputStreamWriter( new FileOutputStream( f ),
1081 bundle.getSourceEncoding() ) );
1082
1083 }
1084
1085 try
1086 {
1087 if ( bundle.getSourceEncoding() == null )
1088 {
1089 velocity.getEngine().mergeTemplate( bundleResource, context, writer );
1090 }
1091 else
1092 {
1093 velocity.getEngine().mergeTemplate( bundleResource, bundle.getSourceEncoding(),
1094 context, writer );
1095
1096 }
1097 }
1098 finally
1099 {
1100 IOUtil.close( writer );
1101 }
1102 }
1103 else
1104 {
1105 URL resUrl = classLoader.getResource( bundleResource );
1106 if ( resUrl != null )
1107 {
1108 FileUtils.copyURLToFile( resUrl, f );
1109 }
1110 }
1111 File appendedResourceFile = new File( appendedResourcesDirectory, projectResource );
1112 File appendedVmResourceFile =
1113 new File( appendedResourcesDirectory, projectResource + ".vm" );
1114 if ( appendedResourceFile.exists() )
1115 {
1116 final InputStream in = new FileInputStream( appendedResourceFile );
1117 final OutputStream append = new FileOutputStream( f, true );
1118
1119 try
1120 {
1121 IOUtil.copy( in, append );
1122 }
1123 finally
1124 {
1125 IOUtil.close( in );
1126 IOUtil.close( append );
1127 }
1128 }
1129 else if ( appendedVmResourceFile.exists() )
1130 {
1131 PrintWriter writer;
1132 FileReader freader = new FileReader( appendedVmResourceFile );
1133
1134 if ( bundle.getSourceEncoding() == null )
1135 {
1136 writer = new PrintWriter( new FileWriter( f, true ) );
1137 }
1138 else
1139 {
1140 writer = new PrintWriter( new OutputStreamWriter( new FileOutputStream( f, true ),
1141 bundle.getSourceEncoding() ) );
1142
1143 }
1144
1145 try
1146 {
1147 Velocity.init();
1148 Velocity.evaluate( context, writer, "remote-resources", freader );
1149 }
1150 finally
1151 {
1152 IOUtil.close( writer );
1153 IOUtil.close( freader );
1154 }
1155 }
1156
1157 }
1158 }
1159 }
1160 finally
1161 {
1162 reader.close();
1163 }
1164 }
1165 }
1166 catch ( IOException e )
1167 {
1168 throw new MojoExecutionException( "Error finding remote resources manifests", e );
1169 }
1170 catch ( XmlPullParserException e )
1171 {
1172 throw new MojoExecutionException( "Error parsing remote resource bundle descriptor.", e );
1173 }
1174 catch ( Exception e )
1175 {
1176 throw new MojoExecutionException( "Error rendering velocity resource.", e );
1177 }
1178 }
1179
1180 protected Model getSupplement( Xpp3Dom supplementModelXml )
1181 throws MojoExecutionException
1182 {
1183 MavenXpp3Reader modelReader = new MavenXpp3Reader();
1184 Model model = null;
1185
1186 try
1187 {
1188 model = modelReader.read( new StringReader( supplementModelXml.toString() ) );
1189 String groupId = model.getGroupId();
1190 String artifactId = model.getArtifactId();
1191
1192 if ( groupId == null || groupId.trim().equals( "" ) )
1193 {
1194 throw new MojoExecutionException(
1195 "Supplemental project XML " + "requires that a <groupId> element be present." );
1196 }
1197
1198 if ( artifactId == null || artifactId.trim().equals( "" ) )
1199 {
1200 throw new MojoExecutionException(
1201 "Supplemental project XML " + "requires that a <artifactId> element be present." );
1202 }
1203 }
1204 catch ( IOException e )
1205 {
1206 getLog().warn( "Unable to read supplemental XML: " + e.getMessage(), e );
1207 }
1208 catch ( XmlPullParserException e )
1209 {
1210 getLog().warn( "Unable to parse supplemental XML: " + e.getMessage(), e );
1211 }
1212
1213 return model;
1214 }
1215
1216 protected Model mergeModels( Model parent, Model child )
1217 {
1218 inheritanceAssembler.assembleModelInheritance( child, parent );
1219 return child;
1220 }
1221
1222 private static String generateSupplementMapKey( String groupId, String artifactId )
1223 {
1224 return groupId.trim() + ":" + artifactId.trim();
1225 }
1226
1227 private Map<String, Model> loadSupplements( String models[] )
1228 throws MojoExecutionException
1229 {
1230 if ( models == null )
1231 {
1232 getLog().debug( "Supplemental data models won't be loaded. " + "No models specified." );
1233 return Collections.emptyMap();
1234 }
1235
1236 List<Supplement> supplements = new ArrayList<Supplement>();
1237 for ( int idx = 0; idx < models.length; idx++ )
1238 {
1239 String set = models[idx];
1240 getLog().debug( "Preparing ruleset: " + set );
1241 try
1242 {
1243 File f = locator.getResourceAsFile( set, getLocationTemp( set ) );
1244
1245 if ( null == f || !f.exists() )
1246 {
1247 throw new MojoExecutionException( "Cold not resolve " + set );
1248 }
1249 if ( !f.canRead() )
1250 {
1251 throw new MojoExecutionException( "Supplemental data models won't be loaded. " + "File " +
1252 f.getAbsolutePath() +
1253 " cannot be read, check permissions on the file." );
1254 }
1255
1256 getLog().debug( "Loading supplemental models from " + f.getAbsolutePath() );
1257
1258 SupplementalDataModelXpp3Reader reader = new SupplementalDataModelXpp3Reader();
1259 SupplementalDataModel supplementalModel = reader.read( new FileReader( f ) );
1260 supplements.addAll( supplementalModel.getSupplement() );
1261 }
1262 catch ( Exception e )
1263 {
1264 String msg = "Error loading supplemental data models: " + e.getMessage();
1265 getLog().error( msg, e );
1266 throw new MojoExecutionException( msg, e );
1267 }
1268 }
1269
1270 getLog().debug( "Loading supplements complete." );
1271
1272 Map<String, Model> supplementMap = new HashMap<String, Model>();
1273 for ( Supplement sd : supplements )
1274 {
1275 Xpp3Dom dom = (Xpp3Dom) sd.getProject();
1276
1277 Model m = getSupplement( dom );
1278 supplementMap.put( generateSupplementMapKey( m.getGroupId(), m.getArtifactId() ), m );
1279 }
1280
1281 return supplementMap;
1282 }
1283
1284
1285
1286
1287
1288
1289
1290 private String getLocationTemp( String name )
1291 {
1292 String loc = name;
1293 if ( loc.indexOf( '/' ) != -1 )
1294 {
1295 loc = loc.substring( loc.lastIndexOf( '/' ) + 1 );
1296 }
1297 if ( loc.indexOf( '\\' ) != -1 )
1298 {
1299 loc = loc.substring( loc.lastIndexOf( '\\' ) + 1 );
1300 }
1301 getLog().debug( "Before: " + name + " After: " + loc );
1302 return loc;
1303 }
1304
1305 class OrganizationComparator
1306 implements Comparator<Organization>
1307 {
1308 public int compare( Organization org1, Organization org2 )
1309 {
1310 int i = compareStrings( org1.getName(), org2.getName() );
1311 if ( i == 0 )
1312 {
1313 i = compareStrings( org1.getUrl(), org2.getUrl() );
1314 }
1315 return i;
1316 }
1317
1318 public boolean equals( Organization o1, Organization o2 )
1319 {
1320 return compare( o1, o2 ) == 0;
1321 }
1322
1323 private int compareStrings( String s1, String s2 )
1324 {
1325 if ( s1 == null && s2 == null )
1326 {
1327 return 0;
1328 }
1329 else if ( s1 == null && s2 != null )
1330 {
1331 return 1;
1332 }
1333 else if ( s1 != null && s2 == null )
1334 {
1335 return -1;
1336 }
1337
1338 return s1.compareToIgnoreCase( s2 );
1339 }
1340 }
1341
1342 class ProjectComparator
1343 implements Comparator<MavenProject>
1344 {
1345 @SuppressWarnings( "unchecked" )
1346 public int compare( MavenProject p1, MavenProject p2 )
1347 {
1348 return p1.getArtifact().compareTo( p2.getArtifact() );
1349 }
1350
1351 public boolean equals( MavenProject p1, MavenProject p2 )
1352 {
1353 return p1.getArtifact().equals( p2.getArtifact() );
1354 }
1355 }
1356
1357 }