1 package org.apache.maven.plugins.ear;
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.FileInputStream;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.OutputStreamWriter;
27 import java.nio.charset.StandardCharsets;
28 import java.nio.file.FileVisitResult;
29 import java.nio.file.Files;
30 import java.nio.file.LinkOption;
31 import java.nio.file.Path;
32 import java.nio.file.Paths;
33 import java.nio.file.SimpleFileVisitor;
34 import java.nio.file.StandardCopyOption;
35 import java.nio.file.attribute.BasicFileAttributes;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.Date;
40 import java.util.List;
41 import java.util.Objects;
42
43 import org.apache.maven.archiver.MavenArchiveConfiguration;
44 import org.apache.maven.archiver.MavenArchiver;
45 import org.apache.maven.artifact.Artifact;
46 import org.apache.maven.artifact.DependencyResolutionRequiredException;
47 import org.apache.maven.execution.MavenSession;
48 import org.apache.maven.plugin.MojoExecutionException;
49 import org.apache.maven.plugin.MojoFailureException;
50 import org.apache.maven.plugins.annotations.Component;
51 import org.apache.maven.plugins.annotations.LifecyclePhase;
52 import org.apache.maven.plugins.annotations.Mojo;
53 import org.apache.maven.plugins.annotations.Parameter;
54 import org.apache.maven.plugins.annotations.ResolutionScope;
55 import org.apache.maven.plugins.ear.util.EarMavenArchiver;
56 import org.apache.maven.plugins.ear.util.JavaEEVersion;
57 import org.apache.maven.project.MavenProjectHelper;
58 import org.apache.maven.shared.filtering.MavenFileFilter;
59 import org.apache.maven.shared.filtering.MavenFilteringException;
60 import org.apache.maven.shared.filtering.MavenResourcesExecution;
61 import org.apache.maven.shared.filtering.MavenResourcesFiltering;
62 import org.apache.maven.shared.mapping.MappingUtils;
63 import org.apache.maven.shared.utils.io.FileUtils;
64 import org.codehaus.plexus.archiver.Archiver;
65 import org.codehaus.plexus.archiver.ArchiverException;
66 import org.codehaus.plexus.archiver.UnArchiver;
67 import org.codehaus.plexus.archiver.ear.EarArchiver;
68 import org.codehaus.plexus.archiver.jar.JarArchiver;
69 import org.codehaus.plexus.archiver.jar.Manifest;
70 import org.codehaus.plexus.archiver.jar.Manifest.Attribute;
71 import org.codehaus.plexus.archiver.jar.ManifestException;
72 import org.codehaus.plexus.archiver.manager.ArchiverManager;
73 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
74 import org.codehaus.plexus.archiver.zip.ZipArchiver;
75 import org.codehaus.plexus.archiver.zip.ZipUnArchiver;
76 import org.codehaus.plexus.components.io.filemappers.FileMapper;
77 import org.codehaus.plexus.interpolation.InterpolationException;
78 import org.codehaus.plexus.util.DirectoryScanner;
79 import org.codehaus.plexus.util.StringUtils;
80
81
82
83
84
85
86 @Mojo( name = "ear",
87 defaultPhase = LifecyclePhase.PACKAGE,
88 threadSafe = true,
89 requiresDependencyResolution = ResolutionScope.TEST )
90 public class EarMojo
91 extends AbstractEarMojo
92 {
93
94
95
96 private static final String ARTIFACT_DEFAULT_FILE_NAME_MAPPING =
97 "@{artifactId}@-@{version}@@{dashClassifier?}@.@{extension}@";
98
99
100
101
102 @Parameter( defaultValue = "${basedir}/src/main/application", required = true )
103 private File earSourceDirectory;
104
105
106
107
108 @Parameter( alias = "includes", defaultValue = "**" )
109 private String earSourceIncludes;
110
111
112
113
114 @Parameter( alias = "excludes" )
115 private String earSourceExcludes;
116
117
118
119
120
121
122 @Parameter( defaultValue = "false" )
123 private boolean filtering;
124
125
126
127
128
129
130 @Parameter
131 private List<String> filters;
132
133
134
135
136
137
138 @Parameter
139 private List<String> nonFilteredFileExtensions;
140
141
142
143
144
145
146 @Parameter( defaultValue = "false" )
147 private boolean escapedBackslashesInFilePath;
148
149
150
151
152
153
154 @Parameter
155 protected String escapeString;
156
157
158
159
160
161
162
163
164 @Parameter( defaultValue = "false" )
165 private boolean skipClassPathModification;
166
167
168
169
170 @Parameter
171 private String applicationXml;
172
173
174
175
176 @Parameter( defaultValue = "${project.build.directory}", required = true )
177 private String outputDirectory;
178
179
180
181
182 @Parameter( defaultValue = "${project.build.finalName}", required = true, readonly = true )
183 private String finalName;
184
185
186
187
188 @Parameter
189 private String unpackTypes;
190
191
192
193
194 @Parameter
195 private String classifier;
196
197
198
199
200
201
202
203
204 @Parameter
205 private String packagingExcludes;
206
207
208
209
210
211
212
213
214 @Parameter
215 private String packagingIncludes;
216
217
218
219
220
221
222
223 @Parameter( defaultValue = "false" )
224 private boolean skinnyWars;
225
226
227
228
229
230
231
232
233
234
235 @Parameter( defaultValue = "false" )
236 private boolean skinnyModules;
237
238
239
240
241 @Component( role = Archiver.class, hint = "ear" )
242 private EarArchiver earArchiver;
243
244
245
246
247 @Component( role = Archiver.class, hint = "jar" )
248 private JarArchiver jarArchiver;
249
250
251
252
253 @Component( role = Archiver.class, hint = "zip" )
254 private ZipArchiver zipArchiver;
255
256
257
258
259 @Component( role = UnArchiver.class, hint = "zip" )
260 private ZipUnArchiver zipUnArchiver;
261
262
263
264
265
266 @Parameter
267 private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
268
269
270
271
272
273
274
275
276 @Parameter( defaultValue = "${project.build.outputTimestamp}" )
277 private String outputTimestamp;
278
279
280
281 @Component
282 private MavenProjectHelper projectHelper;
283
284
285
286
287 @Component
288 private ArchiverManager archiverManager;
289
290
291
292 @Component( role = MavenFileFilter.class, hint = "default" )
293 private MavenFileFilter mavenFileFilter;
294
295
296
297 @Component( role = MavenResourcesFiltering.class, hint = "default" )
298 private MavenResourcesFiltering mavenResourcesFiltering;
299
300
301
302
303 @Parameter( defaultValue = "${session}", readonly = true, required = true )
304 private MavenSession session;
305
306 private List<FileUtils.FilterWrapper> filterWrappers;
307
308
309
310
311 @Parameter( defaultValue = "true" )
312 private boolean useJvmChmod = true;
313
314
315 public void execute()
316 throws MojoExecutionException, MojoFailureException
317 {
318
319 super.execute();
320
321 File earFile = getEarFile( outputDirectory, finalName, classifier );
322 MavenArchiver archiver = new EarMavenArchiver( getModules() );
323 File ddFile = new File( getWorkDirectory(), APPLICATION_XML_URI );
324
325 JarArchiver theArchiver;
326 if ( ddFile.exists() )
327 {
328 earArchiver.setAppxml( ddFile );
329 theArchiver = earArchiver;
330 }
331 else
332 {
333
334
335 theArchiver = jarArchiver;
336 }
337 getLog().debug( "Ear archiver implementation [" + theArchiver.getClass().getName() + "]" );
338 archiver.setArchiver( theArchiver );
339 archiver.setOutputFile( earFile );
340 archiver.setCreatedBy( "Maven EAR Plugin", "org.apache.maven.plugins", "maven-ear-plugin" );
341
342
343 Date reproducibleLastModifiedDate = archiver.configureReproducible( outputTimestamp );
344
345 zipArchiver.setUseJvmChmod( useJvmChmod );
346 if ( reproducibleLastModifiedDate != null )
347 {
348 zipArchiver.configureReproducible( reproducibleLastModifiedDate );
349 }
350 zipUnArchiver.setUseJvmChmod( useJvmChmod );
351
352 final JavaEEVersion javaEEVersion = JavaEEVersion.getJavaEEVersion( version );
353
354 final Collection<String> outdatedResources = initOutdatedResources();
355
356
357 List<String> unpackTypesList = createUnpackList();
358
359
360 copyModules( javaEEVersion, unpackTypesList, outdatedResources );
361
362
363 try
364 {
365 File earSourceDir = earSourceDirectory;
366
367 if ( earSourceDir.exists() )
368 {
369 getLog().info( "Copy ear sources to " + getWorkDirectory().getAbsolutePath() );
370 String[] fileNames = getEarFiles( earSourceDir );
371 for ( String fileName : fileNames )
372 {
373 copyFile( new File( earSourceDir, fileName ), new File( getWorkDirectory(), fileName ) );
374 outdatedResources.remove( Paths.get( fileName ).toString() );
375 }
376 }
377
378 if ( applicationXml != null && !"".equals( applicationXml ) )
379 {
380
381 getLog().info( "Including custom application.xml[" + applicationXml + "]" );
382 File metaInfDir = new File( getWorkDirectory(), META_INF );
383 copyFile( new File( applicationXml ), new File( metaInfDir, "/application.xml" ) );
384 outdatedResources.remove( Paths.get( "META-INF/application.xml" ).toString() );
385 }
386 }
387 catch ( IOException e )
388 {
389 throw new MojoExecutionException( "Error copying EAR sources", e );
390 }
391 catch ( MavenFilteringException e )
392 {
393 throw new MojoExecutionException( "Error filtering EAR sources", e );
394 }
395
396
397 if ( !ddFile.exists() && ( javaEEVersion.lt( JavaEEVersion.FIVE ) ) )
398 {
399 throw new MojoExecutionException( "Deployment descriptor: " + ddFile.getAbsolutePath()
400 + " does not exist." );
401 }
402
403 outdatedResources.remove( Paths.get( APPLICATION_XML_URI ).toString() );
404 if ( getJbossConfiguration() != null )
405 {
406 outdatedResources.remove( Paths.get( "META-INF/jboss-app.xml" ).toString() );
407 }
408
409 deleteOutdatedResources( outdatedResources );
410
411 try
412 {
413 getLog().debug( "Excluding " + Arrays.asList( getPackagingExcludes() ) + " from the generated EAR." );
414 getLog().debug( "Including " + Arrays.asList( getPackagingIncludes() ) + " in the generated EAR." );
415
416 archiver.getArchiver().addDirectory( getWorkDirectory(), getPackagingIncludes(), getPackagingExcludes() );
417
418 archiver.createArchive( session, getProject(), archive );
419 }
420 catch ( ManifestException | IOException | DependencyResolutionRequiredException e )
421 {
422 throw new MojoExecutionException( "Error assembling EAR", e );
423 }
424
425 if ( classifier != null )
426 {
427 projectHelper.attachArtifact( getProject(), "ear", classifier, earFile );
428 }
429 else
430 {
431 getProject().getArtifact().setFile( earFile );
432 }
433 }
434
435 private void copyModules( final JavaEEVersion javaEEVersion,
436 List<String> unpackTypesList,
437 Collection<String> outdatedResources )
438 throws MojoExecutionException, MojoFailureException
439 {
440 final Path workingDir = getWorkDirectory().toPath();
441
442 try
443 {
444 for ( EarModule module : getModules() )
445 {
446 final File sourceFile = module.getArtifact().getFile();
447 final File destinationFile = buildDestinationFile( getWorkDirectory(), module.getUri() );
448 if ( !sourceFile.isFile() )
449 {
450 throw new MojoExecutionException( "Cannot copy a directory: " + sourceFile.getAbsolutePath()
451 + "; Did you package/install " + module.getArtifact() + "?" );
452 }
453
454 if ( destinationFile.getCanonicalPath().equals( sourceFile.getCanonicalPath() ) )
455 {
456 getLog().info( "Skipping artifact [" + module + "], as it already exists at [" + module.getUri()
457 + "]" );
458
459 continue;
460 }
461
462
463
464 if ( ( unpackTypesList.contains( module.getType() )
465 && ( module.shouldUnpack() == null || module.shouldUnpack() ) )
466 || ( module.shouldUnpack() != null && module.shouldUnpack() ) )
467 {
468 getLog().info( "Copying artifact [" + module + "] to [" + module.getUri() + "] (unpacked)" );
469
470 if ( !destinationFile.isDirectory() && !destinationFile.mkdirs() )
471 {
472 throw new MojoExecutionException( "Error creating " + destinationFile );
473 }
474 unpack( sourceFile, destinationFile, outdatedResources );
475
476 if ( module.changeManifestClasspath() )
477 {
478 changeManifestClasspath( module, destinationFile, javaEEVersion );
479 }
480 }
481 else
482 {
483 if ( sourceFile.lastModified() > destinationFile.lastModified() )
484 {
485 getLog().info( "Copying artifact [" + module + "] to [" + module.getUri() + "]" );
486 createParentIfNecessary( destinationFile );
487 Files.copy( sourceFile.toPath(), destinationFile.toPath(),
488 LinkOption.NOFOLLOW_LINKS, StandardCopyOption.REPLACE_EXISTING );
489 if ( module.changeManifestClasspath() )
490 {
491 changeManifestClasspath( module, destinationFile, javaEEVersion );
492 }
493 }
494 else
495 {
496 getLog().debug( "Skipping artifact [" + module + "], as it is already up to date at ["
497 + module.getUri() + "]" );
498 }
499 outdatedResources.remove( workingDir.relativize( destinationFile.toPath() ).toString() );
500 }
501 }
502 }
503 catch ( IOException e )
504 {
505 throw new MojoExecutionException( "Error copying EAR modules", e );
506 }
507 catch ( ArchiverException e )
508 {
509 throw new MojoExecutionException( "Error unpacking EAR modules", e );
510 }
511 catch ( NoSuchArchiverException e )
512 {
513 throw new MojoExecutionException( "No Archiver found for EAR modules", e );
514 }
515 }
516
517 private List<String> createUnpackList()
518 throws MojoExecutionException
519 {
520 List<String> unpackTypesList = new ArrayList<String>();
521 if ( unpackTypes != null )
522 {
523 unpackTypesList = Arrays.asList( unpackTypes.split( "," ) );
524 for ( String type : unpackTypesList )
525 {
526 if ( !EarModuleFactory.isStandardArtifactType( type ) )
527 {
528 throw new MojoExecutionException( "Invalid type [" + type + "] supported types are "
529 + EarModuleFactory.getStandardArtifactTypes() );
530 }
531 }
532 getLog().debug( "Initialized unpack types " + unpackTypesList );
533 }
534 return unpackTypesList;
535 }
536
537
538
539
540 public String getApplicationXml()
541 {
542 return applicationXml;
543 }
544
545
546
547
548 public void setApplicationXml( String applicationXml )
549 {
550 this.applicationXml = applicationXml;
551 }
552
553
554
555
556
557
558 protected String[] getExcludes()
559 {
560 List<String> excludeList = new ArrayList<String>( FileUtils.getDefaultExcludesAsList() );
561 if ( earSourceExcludes != null && !"".equals( earSourceExcludes ) )
562 {
563 excludeList.addAll( Arrays.asList( StringUtils.split( earSourceExcludes, "," ) ) );
564 }
565
566
567 if ( getApplicationXml() != null && !"".equals( getApplicationXml() ) )
568 {
569 excludeList.add( "**/" + META_INF + "/application.xml" );
570 }
571
572 return excludeList.toArray( new String[excludeList.size()] );
573 }
574
575
576
577
578
579
580 protected String[] getIncludes()
581 {
582 return StringUtils.split( Objects.toString( earSourceIncludes, "" ), "," );
583 }
584
585
586
587
588 public String[] getPackagingExcludes()
589 {
590 if ( StringUtils.isEmpty( packagingExcludes ) )
591 {
592 return new String[0];
593 }
594 else
595 {
596 return StringUtils.split( packagingExcludes, "," );
597 }
598 }
599
600
601
602
603 public void setPackagingExcludes( String packagingExcludes )
604 {
605 this.packagingExcludes = packagingExcludes;
606 }
607
608
609
610
611 public String[] getPackagingIncludes()
612 {
613 if ( StringUtils.isEmpty( packagingIncludes ) )
614 {
615 return new String[] { "**" };
616 }
617 else
618 {
619 return StringUtils.split( packagingIncludes, "," );
620 }
621 }
622
623
624
625
626 public void setPackagingIncludes( String packagingIncludes )
627 {
628 this.packagingIncludes = packagingIncludes;
629 }
630
631 private static File buildDestinationFile( File buildDir, String uri )
632 {
633 return new File( buildDir, uri );
634 }
635
636
637
638
639
640
641
642
643
644 private static File getEarFile( String basedir, String finalName, String classifier )
645 {
646 if ( classifier == null )
647 {
648 classifier = "";
649 }
650 else if ( classifier.trim().length() > 0 && !classifier.startsWith( "-" ) )
651 {
652 classifier = "-" + classifier;
653 }
654
655 return new File( basedir, finalName + classifier + ".ear" );
656 }
657
658
659
660
661
662
663
664 private String[] getEarFiles( File sourceDir )
665 {
666 DirectoryScanner scanner = new DirectoryScanner();
667 scanner.setBasedir( sourceDir );
668 scanner.setExcludes( getExcludes() );
669 scanner.addDefaultExcludes();
670
671 scanner.setIncludes( getIncludes() );
672
673 scanner.scan();
674
675 return scanner.getIncludedFiles();
676 }
677
678
679
680
681
682
683
684
685
686
687
688 public void unpack( File source, final File destDir, final Collection<String> outdatedResources )
689 throws ArchiverException, NoSuchArchiverException, IOException
690 {
691 UnArchiver unArchiver = archiverManager.getUnArchiver( "zip" );
692 unArchiver.setSourceFile( source );
693 unArchiver.setDestDirectory( destDir );
694 unArchiver.setFileMappers( new FileMapper[] {
695 new FileMapper()
696 {
697 @Override
698 public String getMappedFileName( String pName )
699 {
700 Path destFile = destDir.toPath().resolve( pName );
701 outdatedResources.remove( getWorkDirectory().toPath().relativize( destFile ).toString() );
702 return pName;
703 }
704 }
705 } );
706
707
708 unArchiver.extract();
709 }
710
711 private void copyFile( File source, File target )
712 throws MavenFilteringException, IOException, MojoExecutionException
713 {
714 createParentIfNecessary( target );
715 if ( filtering && !isNonFilteredExtension( source.getName() ) )
716 {
717 mavenFileFilter.copyFile( source, target, true, getFilterWrappers(), encoding );
718 }
719 else
720 {
721 Files.copy( source.toPath(), target.toPath(), LinkOption.NOFOLLOW_LINKS,
722 StandardCopyOption.REPLACE_EXISTING );
723 }
724 }
725
726 private void createParentIfNecessary( File target )
727 throws IOException
728 {
729
730 File parentDirectory = target.getParentFile();
731 if ( parentDirectory != null && !parentDirectory.exists() )
732 {
733 Files.createDirectories( parentDirectory.toPath() );
734 }
735 }
736
737
738
739
740
741 public boolean isNonFilteredExtension( String fileName )
742 {
743 return !mavenResourcesFiltering.filteredFileExtension( fileName, nonFilteredFileExtensions );
744 }
745
746 private List<FileUtils.FilterWrapper> getFilterWrappers()
747 throws MojoExecutionException
748 {
749 if ( filterWrappers == null )
750 {
751 try
752 {
753 MavenResourcesExecution mavenResourcesExecution = new MavenResourcesExecution();
754 mavenResourcesExecution.setMavenProject( getProject() );
755 mavenResourcesExecution.setEscapedBackslashesInFilePath( escapedBackslashesInFilePath );
756 mavenResourcesExecution.setFilters( filters );
757 mavenResourcesExecution.setEscapeString( escapeString );
758
759 filterWrappers = mavenFileFilter.getDefaultFilterWrappers( mavenResourcesExecution );
760 }
761 catch ( MavenFilteringException e )
762 {
763 getLog().error( "Fail to build filtering wrappers " + e.getMessage() );
764 throw new MojoExecutionException( e.getMessage(), e );
765 }
766 }
767 return filterWrappers;
768 }
769
770 private void changeManifestClasspath( EarModule module, File original, JavaEEVersion javaEEVersion )
771 throws MojoFailureException
772 {
773 final String moduleLibDir = module.getLibDir();
774 if ( !( ( moduleLibDir == null ) || skinnyModules || ( skinnyWars && module instanceof WebModule ) ) )
775 {
776 return;
777 }
778 try
779 {
780 File workDirectory;
781
782
783 if ( original.isFile() )
784 {
785
786
787 workDirectory = new File( new File( getTempFolder(), "temp" ), module.getUri() );
788 if ( !workDirectory.isDirectory() )
789 {
790 if ( workDirectory.mkdirs() )
791 {
792 getLog().debug( "Created a temporary work directory: " + workDirectory.getAbsolutePath() );
793 }
794 else
795 {
796 throw new MojoFailureException( "Failed to create directory " + workDirectory );
797 }
798 }
799
800 zipUnArchiver.setSourceFile( original );
801 zipUnArchiver.setDestDirectory( workDirectory );
802 zipUnArchiver.extract();
803 }
804 else
805 {
806 workDirectory = original;
807 }
808
809
810 File metaInfDirectory = new File( workDirectory, "META-INF" );
811 boolean newMetaInfCreated = metaInfDirectory.mkdirs();
812 if ( newMetaInfCreated )
813 {
814 getLog().debug(
815 "This project did not have a META-INF directory before, so a new directory was created." );
816 }
817 File manifestFile = new File( metaInfDirectory, "MANIFEST.MF" );
818 boolean newManifestCreated = manifestFile.createNewFile();
819 if ( newManifestCreated )
820 {
821 getLog().debug(
822 "This project did not have a META-INF/MANIFEST.MF file before, so a new file was created." );
823 }
824
825 Manifest mf = readManifest( manifestFile );
826 Attribute classPath = mf.getMainSection().getAttribute( "Class-Path" );
827 List<String> classPathElements = new ArrayList<String>();
828
829 boolean classPathExists;
830 if ( classPath != null )
831 {
832 classPathExists = true;
833 classPathElements.addAll( Arrays.asList( classPath.getValue().split( " " ) ) );
834 }
835 else
836 {
837 classPathExists = false;
838 classPath = new Attribute( "Class-Path", "" );
839 }
840
841 if ( ( moduleLibDir != null ) && ( skinnyModules || ( skinnyWars && module instanceof WebModule ) ) )
842 {
843
844 for ( EarModule otherModule : getAllEarModules() )
845 {
846 if ( module.equals( otherModule ) )
847 {
848 continue;
849 }
850
851
852
853
854 final File workLibDir = new File( workDirectory, moduleLibDir );
855 File artifact = new File( workLibDir, module.getArtifact().getFile().getName() );
856
857
858
859
860
861 if ( !artifact.exists() )
862 {
863 getLog().debug( "module does not exist with original file name." );
864 artifact = new File( workLibDir, otherModule.getBundleFileName() );
865 getLog().debug( "Artifact with mapping: " + artifact.getAbsolutePath() );
866 }
867
868 if ( !artifact.exists() )
869 {
870 getLog().debug( "Artifact with mapping does not exist." );
871 artifact = new File( workLibDir, otherModule.getArtifact().getFile().getName() );
872 getLog().debug( "Artifact with original file name: " + artifact.getAbsolutePath() );
873 }
874
875 if ( !artifact.exists() )
876 {
877 getLog().debug( "Artifact with original file name does not exist." );
878 final Artifact otherModuleArtifact = otherModule.getArtifact();
879 if ( otherModuleArtifact.isSnapshot() )
880 {
881 try
882 {
883 artifact = new File( workLibDir, MappingUtils.evaluateFileNameMapping(
884 ARTIFACT_DEFAULT_FILE_NAME_MAPPING, otherModuleArtifact ) );
885 getLog()
886 .debug( "Artifact with default mapping file name: " + artifact.getAbsolutePath() );
887 }
888 catch ( InterpolationException e )
889 {
890 getLog().warn(
891 "Failed to evaluate file name for [" + otherModule + "] module using mapping: "
892 + ARTIFACT_DEFAULT_FILE_NAME_MAPPING );
893 }
894 }
895 }
896
897 if ( artifact.exists() )
898 {
899 getLog().debug( " -> Artifact to delete: " + artifact );
900 if ( !artifact.delete() )
901 {
902 getLog().error( "Could not delete '" + artifact + "'" );
903 }
904 }
905 }
906 }
907
908
909 final boolean forceClassPathModification =
910 javaEEVersion.lt( JavaEEVersion.FIVE ) || defaultLibBundleDir == null;
911 final boolean classPathExtension = !skipClassPathModification || forceClassPathModification;
912 for ( EarModule otherModule : getModules() )
913 {
914 if ( module.equals( otherModule ) )
915 {
916 continue;
917 }
918 final int moduleClassPathIndex = findModuleInClassPathElements( classPathElements, otherModule );
919 if ( moduleClassPathIndex != -1 )
920 {
921 if ( otherModule.isClassPathItem() )
922 {
923 classPathElements.set( moduleClassPathIndex, otherModule.getUri() );
924 }
925 else
926 {
927 classPathElements.remove( moduleClassPathIndex );
928 }
929 }
930 else if ( otherModule.isClassPathItem() && classPathExtension )
931 {
932 classPathElements.add( otherModule.getUri() );
933 }
934 }
935
936
937 for ( EarModule otherModule : getProvidedEarModules() )
938 {
939 final int moduleClassPathIndex = findModuleInClassPathElements( classPathElements, otherModule );
940 if ( moduleClassPathIndex != -1 )
941 {
942 classPathElements.remove( moduleClassPathIndex );
943 }
944 }
945
946 if ( !skipClassPathModification || !classPathElements.isEmpty() || classPathExists )
947 {
948 classPath.setValue( StringUtils.join( classPathElements.iterator(), " " ) );
949 mf.getMainSection().addConfiguredAttribute( classPath );
950
951
952 try ( FileOutputStream out = new FileOutputStream( manifestFile );
953 OutputStreamWriter writer = new OutputStreamWriter( out, StandardCharsets.UTF_8 ) )
954 {
955 mf.write( writer );
956 }
957 }
958
959 if ( original.isFile() )
960 {
961
962 if ( !original.delete() )
963 {
964 getLog().error( "Could not delete original artifact file " + original );
965 }
966
967 getLog().debug( "Zipping module" );
968 zipArchiver.setDestFile( original );
969 zipArchiver.addDirectory( workDirectory );
970 zipArchiver.createArchive();
971 }
972 }
973 catch ( ManifestException | IOException | ArchiverException e )
974 {
975 throw new MojoFailureException( e.getMessage(), e );
976 }
977 }
978
979 private static Manifest readManifest( File manifestFile )
980 throws IOException
981 {
982
983 try ( FileInputStream in = new FileInputStream( manifestFile ) )
984 {
985 Manifest manifest = new Manifest( in );
986 return manifest;
987 }
988 }
989
990 private Collection<String> initOutdatedResources()
991 {
992 final Collection<String> outdatedResources = new ArrayList<>();
993
994 if ( getWorkDirectory().exists() )
995 {
996 try
997 {
998 Files.walkFileTree( getWorkDirectory().toPath(), new SimpleFileVisitor<Path>()
999 {
1000 @Override
1001 public FileVisitResult visitFile( Path file, BasicFileAttributes attrs )
1002 throws IOException
1003 {
1004 outdatedResources.add( getWorkDirectory().toPath().relativize( file ).toString() );
1005 return super.visitFile( file, attrs );
1006 }
1007 } );
1008 }
1009 catch ( IOException e )
1010 {
1011 getLog().warn( "Can't detect outdated resources", e );
1012 }
1013 }
1014 return outdatedResources;
1015 }
1016
1017 private void deleteOutdatedResources( final Collection<String> outdatedResources )
1018 {
1019 final long startTime = session.getStartTime().getTime();
1020
1021 for ( String outdatedResource : outdatedResources )
1022 {
1023 if ( new File( getWorkDirectory(), outdatedResource ).lastModified() < startTime )
1024 {
1025 getLog().info( "deleting outdated resource " + outdatedResource );
1026 new File( getWorkDirectory(), outdatedResource ).delete();
1027 }
1028 }
1029 }
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040 private int findModuleInClassPathElements( final List<String> classPathElements, final EarModule module )
1041 {
1042 if ( classPathElements.isEmpty() )
1043 {
1044 return -1;
1045 }
1046 int moduleClassPathIndex = classPathElements.indexOf( module.getBundleFileName() );
1047 if ( moduleClassPathIndex != -1 )
1048 {
1049 return moduleClassPathIndex;
1050 }
1051 final Artifact artifact = module.getArtifact();
1052 moduleClassPathIndex = classPathElements.indexOf( artifact.getFile().getName() );
1053 if ( moduleClassPathIndex != -1 )
1054 {
1055 return moduleClassPathIndex;
1056 }
1057 if ( artifact.isSnapshot() )
1058 {
1059 try
1060 {
1061 moduleClassPathIndex = classPathElements
1062 .indexOf( MappingUtils.evaluateFileNameMapping( ARTIFACT_DEFAULT_FILE_NAME_MAPPING, artifact ) );
1063 if ( moduleClassPathIndex != -1 )
1064 {
1065 return moduleClassPathIndex;
1066 }
1067 }
1068 catch ( InterpolationException e )
1069 {
1070 getLog().warn( "Failed to evaluate file name for [" + module + "] module using mapping: "
1071 + ARTIFACT_DEFAULT_FILE_NAME_MAPPING );
1072 }
1073 }
1074 return classPathElements.indexOf( module.getUri() );
1075 }
1076 }