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