1 package org.apache.maven.plugin.war;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collections;
27 import java.util.List;
28
29 import org.apache.maven.archiver.MavenArchiveConfiguration;
30 import org.apache.maven.artifact.factory.ArtifactFactory;
31 import org.apache.maven.execution.MavenSession;
32 import org.apache.maven.model.Resource;
33 import org.apache.maven.plugin.AbstractMojo;
34 import org.apache.maven.plugin.MojoExecutionException;
35 import org.apache.maven.plugin.MojoFailureException;
36 import org.apache.maven.plugin.logging.Log;
37 import org.apache.maven.plugin.war.overlay.OverlayManager;
38 import org.apache.maven.plugin.war.packaging.CopyUserManifestTask;
39 import org.apache.maven.plugin.war.packaging.DependenciesAnalysisPackagingTask;
40 import org.apache.maven.plugin.war.packaging.OverlayPackagingTask;
41 import org.apache.maven.plugin.war.packaging.SaveWebappStructurePostPackagingTask;
42 import org.apache.maven.plugin.war.packaging.WarPackagingContext;
43 import org.apache.maven.plugin.war.packaging.WarPackagingTask;
44 import org.apache.maven.plugin.war.packaging.WarPostPackagingTask;
45 import org.apache.maven.plugin.war.packaging.WarProjectPackagingTask;
46 import org.apache.maven.plugin.war.util.WebappStructure;
47 import org.apache.maven.plugin.war.util.WebappStructureSerializer;
48 import org.apache.maven.plugins.annotations.Component;
49 import org.apache.maven.plugins.annotations.Parameter;
50 import org.apache.maven.project.MavenProject;
51 import org.apache.maven.shared.filtering.MavenFileFilter;
52 import org.apache.maven.shared.filtering.MavenFilteringException;
53 import org.apache.maven.shared.filtering.MavenResourcesExecution;
54 import org.apache.maven.shared.filtering.MavenResourcesFiltering;
55 import org.apache.maven.shared.utils.StringUtils;
56 import org.apache.maven.shared.utils.io.FileUtils;
57 import org.codehaus.plexus.archiver.Archiver;
58 import org.codehaus.plexus.archiver.jar.JarArchiver;
59 import org.codehaus.plexus.archiver.manager.ArchiverManager;
60
61
62
63
64
65
66 public abstract class AbstractWarMojo
67 extends AbstractMojo
68 {
69 private static final String[] EMPTY_STRING_ARRAY = {};
70
71 private static final String META_INF = "META-INF";
72
73 private static final String WEB_INF = "WEB-INF";
74
75
76
77
78 @Parameter( defaultValue = "${project}", readonly = true, required = true )
79 private MavenProject project;
80
81
82
83
84 @Parameter( defaultValue = "${project.build.outputDirectory}", required = true, readonly = true )
85 private File classesDirectory;
86
87
88
89
90
91
92
93
94 @Parameter( property = "archiveClasses", defaultValue = "false" )
95 private boolean archiveClasses;
96
97
98
99
100
101
102 @Parameter( property = "resourceEncoding", defaultValue = "${project.build.sourceEncoding}" )
103 private String resourceEncoding;
104
105
106
107
108 @Component( role = Archiver.class, hint = "jar" )
109 private JarArchiver jarArchiver;
110
111
112
113
114 @Parameter( defaultValue = "${project.build.directory}/${project.build.finalName}", required = true )
115 private File webappDirectory;
116
117
118
119
120 @Parameter( defaultValue = "${basedir}/src/main/webapp", required = true )
121 private File warSourceDirectory;
122
123
124
125
126 @Parameter
127 private Resource[] webResources;
128
129
130
131
132 @Parameter
133 private List<String> filters;
134
135
136
137
138 @Parameter( property = "maven.war.webxml" )
139 private File webXml;
140
141
142
143
144
145
146 @Parameter( property = "maven.war.containerConfigXML" )
147 private File containerConfigXML;
148
149
150
151
152 @Parameter( defaultValue = "${project.build.directory}/war/work", required = true )
153 private File workDirectory;
154
155
156
157
158
159
160
161 @Parameter
162 private String outputFileNameMapping;
163
164
165
166
167
168
169 @Parameter( defaultValue = "${project.build.directory}/war/work/webapp-cache.xml", required = true )
170 private File cacheFile;
171
172
173
174
175
176
177
178 @Parameter( property = "useCache", defaultValue = "false" )
179 private boolean useCache = false;
180
181
182
183 @Component( role = ArtifactFactory.class )
184 private ArtifactFactory artifactFactory;
185
186
187
188
189 @Component( role = ArchiverManager.class )
190 private ArchiverManager archiverManager;
191
192
193
194 @Component( role = MavenFileFilter.class, hint = "default" )
195 private MavenFileFilter mavenFileFilter;
196
197
198
199 @Component( role = MavenResourcesFiltering.class, hint = "default" )
200 private MavenResourcesFiltering mavenResourcesFiltering;
201
202
203
204
205 @Parameter( alias = "includes", defaultValue = "**" )
206 private String warSourceIncludes;
207
208
209
210
211 @Parameter( alias = "excludes" )
212 private String warSourceExcludes;
213
214
215
216
217
218
219 @Parameter
220 private String dependentWarIncludes = "**/**";
221
222
223
224
225
226
227 @Parameter
228 private String dependentWarExcludes = "META-INF/**";
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247 @Parameter
248 private List<Overlay> overlays = new ArrayList<Overlay>();
249
250
251
252
253
254
255
256 @Parameter
257 private List<String> nonFilteredFileExtensions;
258
259
260
261
262 @Parameter( defaultValue = "${session}", readonly = true, required = true )
263 private MavenSession session;
264
265
266
267
268
269
270 @Parameter( property = "maven.war.filteringDeploymentDescriptors", defaultValue = "false" )
271 private boolean filteringDeploymentDescriptors = false;
272
273
274
275
276
277
278
279 @Parameter( property = "maven.war.escapedBackslashesInFilePath", defaultValue = "false" )
280 private boolean escapedBackslashesInFilePath = false;
281
282
283
284
285
286
287
288 @Parameter( property = "maven.war.escapeString" )
289 protected String escapeString;
290
291
292
293
294
295
296
297 @Parameter( defaultValue = "true" )
298 private boolean recompressZippedFiles;
299
300
301
302
303 @Parameter( defaultValue = "false" )
304 private boolean includeEmptyDirectories;
305
306
307
308
309
310
311 @Parameter( property = "maven.war.supportMultiLineFiltering", defaultValue = "false" )
312 private boolean supportMultiLineFiltering = false;
313
314
315
316
317
318
319 @Parameter( property = "maven.war.useJvmChmod", defaultValue = "true" )
320 private boolean useJvmChmod;
321
322
323
324
325
326 @Parameter
327 private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
328
329 private final WebappStructureSerializer webappStructureSerialier = new WebappStructureSerializer();
330
331 private final Overlay currentProjectOverlay = Overlay.createInstance();
332
333
334
335
336 public Overlay getCurrentProjectOverlay()
337 {
338 return currentProjectOverlay;
339 }
340
341
342
343
344
345
346 protected String[] getExcludes()
347 {
348 List<String> excludeList = new ArrayList<String>();
349 if ( StringUtils.isNotEmpty( warSourceExcludes ) )
350 {
351 excludeList.addAll( Arrays.asList( StringUtils.split( warSourceExcludes, "," ) ) );
352 }
353
354
355 if ( webXml != null && StringUtils.isNotEmpty( webXml.getName() ) )
356 {
357 excludeList.add( "**/" + WEB_INF + "/web.xml" );
358 }
359
360
361 if ( containerConfigXML != null && StringUtils.isNotEmpty( containerConfigXML.getName() ) )
362 {
363 excludeList.add( "**/" + META_INF + "/" + containerConfigXML.getName() );
364 }
365
366 return excludeList.toArray( new String[excludeList.size()] );
367 }
368
369
370
371
372
373
374 protected String[] getIncludes()
375 {
376 return StringUtils.split( StringUtils.defaultString( warSourceIncludes ), "," );
377 }
378
379
380
381
382
383
384 protected String[] getDependentWarExcludes()
385 {
386 String[] excludes;
387 if ( StringUtils.isNotEmpty( dependentWarExcludes ) )
388 {
389 excludes = StringUtils.split( dependentWarExcludes, "," );
390 }
391 else
392 {
393 excludes = EMPTY_STRING_ARRAY;
394 }
395 return excludes;
396 }
397
398
399
400
401
402
403 protected String[] getDependentWarIncludes()
404 {
405 return StringUtils.split( StringUtils.defaultString( dependentWarIncludes ), "," );
406 }
407
408
409
410
411
412
413 public void buildExplodedWebapp( File webapplicationDirectory )
414 throws MojoExecutionException, MojoFailureException
415 {
416 webapplicationDirectory.mkdirs();
417
418 try
419 {
420 buildWebapp( project, webapplicationDirectory );
421 }
422 catch ( IOException e )
423 {
424 throw new MojoExecutionException( "Could not build webapp", e );
425 }
426 }
427
428
429
430
431
432
433
434
435
436
437
438
439 @SuppressWarnings( "unchecked" )
440 public void buildWebapp( MavenProject mavenProject, File webapplicationDirectory )
441 throws MojoExecutionException, MojoFailureException, IOException
442 {
443
444 WebappStructure cache;
445 if ( useCache && cacheFile.exists() )
446 {
447
448 cache = new WebappStructure( mavenProject.getDependencies(), webappStructureSerialier.fromXml( cacheFile ) );
449
450 }
451 else
452 {
453 cache = new WebappStructure( mavenProject.getDependencies(), null );
454 }
455
456
457 final long startTime = System.currentTimeMillis();
458 getLog().info( "Assembling webapp [" + mavenProject.getArtifactId() + "] in [" + webapplicationDirectory + "]" );
459
460 final OverlayManager overlayManager =
461 new OverlayManager( overlays, mavenProject, dependentWarIncludes, dependentWarExcludes,
462 currentProjectOverlay );
463 final List<WarPackagingTask> packagingTasks = getPackagingTasks( overlayManager );
464
465 List<FileUtils.FilterWrapper> defaultFilterWrappers;
466 try
467 {
468 MavenResourcesExecution mavenResourcesExecution = new MavenResourcesExecution();
469 mavenResourcesExecution.setEscapeString( escapeString );
470 mavenResourcesExecution.setSupportMultiLineFiltering( supportMultiLineFiltering );
471 mavenResourcesExecution.setMavenProject( mavenProject );
472 if ( filters == null )
473 {
474 filters = getProject().getBuild().getFilters();
475 }
476 mavenResourcesExecution.setFilters( filters );
477 mavenResourcesExecution.setEscapedBackslashesInFilePath( escapedBackslashesInFilePath );
478 mavenResourcesExecution.setMavenSession( this.session );
479 mavenResourcesExecution.setEscapeString( this.escapeString );
480 mavenResourcesExecution.setSupportMultiLineFiltering( supportMultiLineFiltering );
481
482 defaultFilterWrappers = mavenFileFilter.getDefaultFilterWrappers( mavenResourcesExecution );
483
484 }
485 catch ( MavenFilteringException e )
486 {
487 getLog().error( "fail to build filering wrappers " + e.getMessage() );
488 throw new MojoExecutionException( e.getMessage(), e );
489 }
490
491 final WarPackagingContext context =
492 new DefaultWarPackagingContext( webapplicationDirectory, cache, overlayManager, defaultFilterWrappers,
493 getNonFilteredFileExtensions(), filteringDeploymentDescriptors,
494 this.artifactFactory, resourceEncoding, useJvmChmod );
495 for ( WarPackagingTask warPackagingTask : packagingTasks )
496 {
497 warPackagingTask.performPackaging( context );
498 }
499
500
501 final List<WarPostPackagingTask> postPackagingTasks = getPostPackagingTasks();
502 for ( WarPostPackagingTask task : postPackagingTasks )
503 {
504 task.performPostPackaging( context );
505 }
506 getLog().info( "Webapp assembled in [" + ( System.currentTimeMillis() - startTime ) + " msecs]" );
507
508 }
509
510
511
512
513
514
515
516
517
518 private List<WarPackagingTask> getPackagingTasks( OverlayManager overlayManager )
519 throws MojoExecutionException
520 {
521 final List<WarPackagingTask> packagingTasks = new ArrayList<WarPackagingTask>();
522
523 packagingTasks.add( new CopyUserManifestTask() );
524
525 if ( useCache )
526 {
527 packagingTasks.add( new DependenciesAnalysisPackagingTask() );
528
529 }
530
531 final List<Overlay> resolvedOverlays = overlayManager.getOverlays();
532 for ( Overlay overlay : resolvedOverlays )
533 {
534 if ( overlay.isCurrentProject() )
535 {
536 packagingTasks.add( new WarProjectPackagingTask( webResources, webXml, containerConfigXML,
537 currentProjectOverlay ) );
538 }
539 else
540 {
541 packagingTasks.add( new OverlayPackagingTask( overlay, currentProjectOverlay ) );
542 }
543 }
544 return packagingTasks;
545 }
546
547
548
549
550
551
552
553 private List<WarPostPackagingTask> getPostPackagingTasks()
554 {
555 final List<WarPostPackagingTask> postPackagingTasks = new ArrayList<WarPostPackagingTask>();
556 if ( useCache )
557 {
558 postPackagingTasks.add( new SaveWebappStructurePostPackagingTask( cacheFile ) );
559 }
560
561 return postPackagingTasks;
562 }
563
564
565
566
567 private class DefaultWarPackagingContext
568 implements WarPackagingContext
569 {
570
571 private final ArtifactFactory artifactFactory;
572
573 private final String resourceEncoding;
574
575 private final WebappStructure webappStructure;
576
577 private final File webappDirectory;
578
579 private final OverlayManager overlayManager;
580
581 private final List<FileUtils.FilterWrapper> filterWrappers;
582
583 private List<String> nonFilteredFileExtensions;
584
585 private boolean filteringDeploymentDescriptors;
586
587 private boolean useJvmChmod = true;
588
589
590
591
592
593
594
595
596
597
598
599
600 public DefaultWarPackagingContext( File webappDirectory, final WebappStructure webappStructure,
601 final OverlayManager overlayManager,
602 List<FileUtils.FilterWrapper> filterWrappers,
603 List<String> nonFilteredFileExtensions,
604 boolean filteringDeploymentDescriptors, ArtifactFactory artifactFactory,
605 String resourceEncoding, boolean useJvmChmod )
606 {
607 this.webappDirectory = webappDirectory;
608 this.webappStructure = webappStructure;
609 this.overlayManager = overlayManager;
610 this.filterWrappers = filterWrappers;
611 this.artifactFactory = artifactFactory;
612 this.filteringDeploymentDescriptors = filteringDeploymentDescriptors;
613 this.nonFilteredFileExtensions =
614 nonFilteredFileExtensions == null ? Collections.<String>emptyList() : nonFilteredFileExtensions;
615 this.resourceEncoding = resourceEncoding;
616
617
618 for ( String overlayId : overlayManager.getOverlayIds() )
619 {
620 webappStructure.getStructure( overlayId );
621 }
622 this.useJvmChmod = useJvmChmod;
623 }
624
625
626
627
628 public MavenProject getProject()
629 {
630 return project;
631 }
632
633
634
635
636 public File getWebappDirectory()
637 {
638 return webappDirectory;
639 }
640
641
642
643
644 public File getClassesDirectory()
645 {
646 return classesDirectory;
647 }
648
649
650
651
652 public Log getLog()
653 {
654 return AbstractWarMojo.this.getLog();
655 }
656
657
658
659
660 public String getOutputFileNameMapping()
661 {
662 return outputFileNameMapping;
663 }
664
665
666
667
668 public File getWebappSourceDirectory()
669 {
670 return warSourceDirectory;
671 }
672
673
674
675
676 public String[] getWebappSourceIncludes()
677 {
678 return getIncludes();
679 }
680
681
682
683
684 public String[] getWebappSourceExcludes()
685 {
686 return getExcludes();
687 }
688
689
690
691
692 public boolean isWebappSourceIncludeEmptyDirectories()
693 {
694 return includeEmptyDirectories;
695 }
696
697
698
699
700 public boolean archiveClasses()
701 {
702 return archiveClasses;
703 }
704
705
706
707
708 public File getOverlaysWorkDirectory()
709 {
710 return workDirectory;
711 }
712
713
714
715
716 public ArchiverManager getArchiverManager()
717 {
718 return archiverManager;
719 }
720
721
722
723
724 public MavenArchiveConfiguration getArchive()
725 {
726 return archive;
727 }
728
729
730
731
732 public JarArchiver getJarArchiver()
733 {
734 return jarArchiver;
735 }
736
737
738
739
740 public List<String> getFilters()
741 {
742 return filters;
743 }
744
745
746
747
748 public WebappStructure getWebappStructure()
749 {
750 return webappStructure;
751 }
752
753
754
755
756 public List<String> getOwnerIds()
757 {
758 return overlayManager.getOverlayIds();
759 }
760
761
762
763
764 public MavenFileFilter getMavenFileFilter()
765 {
766 return mavenFileFilter;
767 }
768
769
770
771
772 public List<FileUtils.FilterWrapper> getFilterWrappers()
773 {
774 return filterWrappers;
775 }
776
777
778
779
780 public boolean isNonFilteredExtension( String fileName )
781 {
782 return !mavenResourcesFiltering.filteredFileExtension( fileName, nonFilteredFileExtensions );
783 }
784
785
786
787
788 public boolean isFilteringDeploymentDescriptors()
789 {
790 return filteringDeploymentDescriptors;
791 }
792
793
794
795
796 public ArtifactFactory getArtifactFactory()
797 {
798 return this.artifactFactory;
799 }
800
801
802
803
804 public MavenSession getSession()
805 {
806 return session;
807 }
808
809
810
811
812 public String getResourceEncoding()
813 {
814 return resourceEncoding;
815 }
816
817
818
819
820 public boolean isUseJvmChmod()
821 {
822 return useJvmChmod;
823 }
824 }
825
826
827
828
829 public MavenProject getProject()
830 {
831 return project;
832 }
833
834
835
836
837 public void setProject( MavenProject project )
838 {
839 this.project = project;
840 }
841
842
843
844
845 public File getClassesDirectory()
846 {
847 return classesDirectory;
848 }
849
850
851
852
853 public void setClassesDirectory( File classesDirectory )
854 {
855 this.classesDirectory = classesDirectory;
856 }
857
858
859
860
861 public File getWebappDirectory()
862 {
863 return webappDirectory;
864 }
865
866
867
868
869 public void setWebappDirectory( File webappDirectory )
870 {
871 this.webappDirectory = webappDirectory;
872 }
873
874
875
876
877 public File getWarSourceDirectory()
878 {
879 return warSourceDirectory;
880 }
881
882
883
884
885 public void setWarSourceDirectory( File warSourceDirectory )
886 {
887 this.warSourceDirectory = warSourceDirectory;
888 }
889
890
891
892
893 public File getWebXml()
894 {
895 return webXml;
896 }
897
898
899
900
901 public void setWebXml( File webXml )
902 {
903 this.webXml = webXml;
904 }
905
906
907
908
909 public File getContainerConfigXML()
910 {
911 return containerConfigXML;
912 }
913
914
915
916
917 public void setContainerConfigXML( File containerConfigXML )
918 {
919 this.containerConfigXML = containerConfigXML;
920 }
921
922
923
924
925 public String getOutputFileNameMapping()
926 {
927 return outputFileNameMapping;
928 }
929
930
931
932
933 public void setOutputFileNameMapping( String outputFileNameMapping )
934 {
935 this.outputFileNameMapping = outputFileNameMapping;
936 }
937
938
939
940
941 public List<Overlay> getOverlays()
942 {
943 return overlays;
944 }
945
946
947
948
949 public void setOverlays( List<Overlay> overlays )
950 {
951 this.overlays = overlays;
952 }
953
954
955
956
957 public void addOverlay( Overlay overlay )
958 {
959 overlays.add( overlay );
960 }
961
962
963
964
965 public boolean isArchiveClasses()
966 {
967 return archiveClasses;
968 }
969
970
971
972
973 public void setArchiveClasses( boolean archiveClasses )
974 {
975 this.archiveClasses = archiveClasses;
976 }
977
978
979
980
981 public JarArchiver getJarArchiver()
982 {
983 return jarArchiver;
984 }
985
986
987
988
989 public void setJarArchiver( JarArchiver jarArchiver )
990 {
991 this.jarArchiver = jarArchiver;
992 }
993
994
995
996
997 public Resource[] getWebResources()
998 {
999 return webResources;
1000 }
1001
1002
1003
1004
1005 public void setWebResources( Resource[] webResources )
1006 {
1007 this.webResources = webResources;
1008 }
1009
1010
1011
1012
1013 public List<String> getFilters()
1014 {
1015 return filters;
1016 }
1017
1018
1019
1020
1021 public void setFilters( List<String> filters )
1022 {
1023 this.filters = filters;
1024 }
1025
1026
1027
1028
1029 public File getWorkDirectory()
1030 {
1031 return workDirectory;
1032 }
1033
1034
1035
1036
1037 public void setWorkDirectory( File workDirectory )
1038 {
1039 this.workDirectory = workDirectory;
1040 }
1041
1042
1043
1044
1045 public File getCacheFile()
1046 {
1047 return cacheFile;
1048 }
1049
1050
1051
1052
1053 public void setCacheFile( File cacheFile )
1054 {
1055 this.cacheFile = cacheFile;
1056 }
1057
1058
1059
1060
1061 public String getWarSourceIncludes()
1062 {
1063 return warSourceIncludes;
1064 }
1065
1066
1067
1068
1069 public void setWarSourceIncludes( String warSourceIncludes )
1070 {
1071 this.warSourceIncludes = warSourceIncludes;
1072 }
1073
1074
1075
1076
1077 public String getWarSourceExcludes()
1078 {
1079 return warSourceExcludes;
1080 }
1081
1082
1083
1084
1085 public void setWarSourceExcludes( String warSourceExcludes )
1086 {
1087 this.warSourceExcludes = warSourceExcludes;
1088 }
1089
1090
1091
1092
1093 public boolean isUseCache()
1094 {
1095 return useCache;
1096 }
1097
1098
1099
1100
1101 public void setUseCache( boolean useCache )
1102 {
1103 this.useCache = useCache;
1104 }
1105
1106
1107
1108
1109 public MavenArchiveConfiguration getArchive()
1110 {
1111 return archive;
1112 }
1113
1114
1115
1116
1117 public List<String> getNonFilteredFileExtensions()
1118 {
1119 return nonFilteredFileExtensions;
1120 }
1121
1122
1123
1124
1125 public void setNonFilteredFileExtensions( List<String> nonFilteredFileExtensions )
1126 {
1127 this.nonFilteredFileExtensions = nonFilteredFileExtensions;
1128 }
1129
1130
1131
1132
1133 public ArtifactFactory getArtifactFactory()
1134 {
1135 return this.artifactFactory;
1136 }
1137
1138
1139
1140
1141 public void setArtifactFactory( ArtifactFactory artifactFactory )
1142 {
1143 this.artifactFactory = artifactFactory;
1144 }
1145
1146
1147
1148
1149 protected MavenSession getSession()
1150 {
1151 return this.session;
1152 }
1153
1154
1155
1156
1157 protected boolean isRecompressZippedFiles()
1158 {
1159 return recompressZippedFiles;
1160 }
1161
1162
1163
1164
1165 protected boolean isIncludeEmptyDirectories()
1166 {
1167 return includeEmptyDirectories;
1168 }
1169 }