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