1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.ear;
20
21 import javax.inject.Inject;
22
23 import java.io.BufferedWriter;
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.nio.charset.StandardCharsets;
28 import java.nio.file.FileSystem;
29 import java.nio.file.FileSystems;
30 import java.nio.file.FileVisitResult;
31 import java.nio.file.Files;
32 import java.nio.file.LinkOption;
33 import java.nio.file.Path;
34 import java.nio.file.Paths;
35 import java.nio.file.ProviderMismatchException;
36 import java.nio.file.SimpleFileVisitor;
37 import java.nio.file.StandardCopyOption;
38 import java.nio.file.StandardOpenOption;
39 import java.nio.file.attribute.BasicFileAttributes;
40 import java.nio.file.attribute.FileTime;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Collection;
44 import java.util.List;
45 import java.util.Objects;
46
47 import org.apache.maven.archiver.MavenArchiveConfiguration;
48 import org.apache.maven.archiver.MavenArchiver;
49 import org.apache.maven.artifact.Artifact;
50 import org.apache.maven.artifact.DependencyResolutionRequiredException;
51 import org.apache.maven.execution.MavenSession;
52 import org.apache.maven.plugin.MojoExecutionException;
53 import org.apache.maven.plugin.MojoFailureException;
54 import org.apache.maven.plugins.annotations.LifecyclePhase;
55 import org.apache.maven.plugins.annotations.Mojo;
56 import org.apache.maven.plugins.annotations.Parameter;
57 import org.apache.maven.plugins.annotations.ResolutionScope;
58 import org.apache.maven.plugins.ear.util.EarMavenArchiver;
59 import org.apache.maven.plugins.ear.util.JavaEEVersion;
60 import org.apache.maven.project.MavenProjectHelper;
61 import org.apache.maven.shared.filtering.FilterWrapper;
62 import org.apache.maven.shared.filtering.MavenFileFilter;
63 import org.apache.maven.shared.filtering.MavenFilteringException;
64 import org.apache.maven.shared.filtering.MavenResourcesExecution;
65 import org.apache.maven.shared.filtering.MavenResourcesFiltering;
66 import org.apache.maven.shared.mapping.MappingUtils;
67 import org.apache.maven.shared.utils.io.FileUtils;
68 import org.codehaus.plexus.archiver.ArchiverException;
69 import org.codehaus.plexus.archiver.UnArchiver;
70 import org.codehaus.plexus.archiver.ear.EarArchiver;
71 import org.codehaus.plexus.archiver.jar.JarArchiver;
72 import org.codehaus.plexus.archiver.jar.Manifest;
73 import org.codehaus.plexus.archiver.jar.Manifest.Attribute;
74 import org.codehaus.plexus.archiver.jar.ManifestException;
75 import org.codehaus.plexus.archiver.manager.ArchiverManager;
76 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
77 import org.codehaus.plexus.components.io.filemappers.FileMapper;
78 import org.codehaus.plexus.interpolation.InterpolationException;
79 import org.codehaus.plexus.util.DirectoryScanner;
80 import org.codehaus.plexus.util.StringUtils;
81
82
83
84
85
86
87 @Mojo(
88 name = "ear",
89 defaultPhase = LifecyclePhase.PACKAGE,
90 threadSafe = true,
91 requiresDependencyResolution = ResolutionScope.TEST)
92 public class EarMojo extends AbstractEarMojo {
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 File 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 private EarArchiver earArchiver;
242
243
244
245
246 private JarArchiver jarArchiver;
247
248
249
250
251
252 @Parameter
253 private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
254
255
256
257
258
259
260
261
262 @Parameter(defaultValue = "${project.build.outputTimestamp}")
263 private String outputTimestamp;
264
265 private MavenProjectHelper projectHelper;
266
267
268
269
270 private ArchiverManager archiverManager;
271
272 private MavenFileFilter mavenFileFilter;
273
274 private MavenResourcesFiltering mavenResourcesFiltering;
275
276
277
278
279 @Parameter(defaultValue = "${session}", readonly = true, required = true)
280 private MavenSession session;
281
282 private List<FilterWrapper> filterWrappers;
283
284 @Inject
285 public EarMojo(
286 EarArchiver earArchiver,
287 JarArchiver jarArchiver,
288 MavenProjectHelper projectHelper,
289 ArchiverManager archiverManager,
290 MavenFileFilter mavenFileFilter,
291 MavenResourcesFiltering mavenResourcesFiltering) {
292 this.earArchiver = earArchiver;
293 this.jarArchiver = jarArchiver;
294 this.projectHelper = projectHelper;
295 this.archiverManager = archiverManager;
296 this.mavenFileFilter = mavenFileFilter;
297 this.mavenResourcesFiltering = mavenResourcesFiltering;
298 }
299
300
301 @Override
302 public void execute() throws MojoExecutionException, MojoFailureException {
303
304 super.execute();
305
306 File earFile = getEarFile(outputDirectory, finalName, classifier);
307 MavenArchiver archiver = new EarMavenArchiver(getModules());
308 File ddFile = new File(getWorkDirectory(), APPLICATION_XML_URI);
309
310 JarArchiver theArchiver;
311 if (ddFile.exists()) {
312 earArchiver.setAppxml(ddFile);
313 theArchiver = earArchiver;
314 } else {
315
316
317 theArchiver = jarArchiver;
318 }
319 getLog().debug("Ear archiver implementation [" + theArchiver.getClass().getName() + "]");
320 archiver.setArchiver(theArchiver);
321 archiver.setOutputFile(earFile);
322 archiver.setCreatedBy("Maven EAR Plugin", "org.apache.maven.plugins", "maven-ear-plugin");
323
324
325 archiver.configureReproducibleBuild(outputTimestamp);
326
327 final JavaEEVersion javaEEVersion = JavaEEVersion.getJavaEEVersion(version);
328
329 final Collection<String> outdatedResources = initOutdatedResources();
330
331
332 List<String> unpackTypesList = createUnpackList();
333
334
335 copyModules(javaEEVersion, unpackTypesList, outdatedResources);
336
337
338 try {
339 File earSourceDir = earSourceDirectory;
340
341 if (earSourceDir.exists()) {
342 getLog().info("Copy ear sources to " + getWorkDirectory().getAbsolutePath());
343 String[] fileNames = getEarFiles(earSourceDir);
344 for (String fileName : fileNames) {
345 copyFile(new File(earSourceDir, fileName), new File(getWorkDirectory(), fileName));
346 outdatedResources.remove(Paths.get(fileName).toString());
347 }
348 }
349
350 if (applicationXml != null) {
351
352 getLog().info("Including custom application.xml[" + applicationXml + "]");
353 File metaInfDir = new File(getWorkDirectory(), META_INF);
354 copyFile(applicationXml, new File(metaInfDir, "/application.xml"));
355 outdatedResources.remove(Paths.get("META-INF/application.xml").toString());
356 }
357 } catch (IOException e) {
358 throw new MojoExecutionException("Error copying EAR sources", e);
359 } catch (MavenFilteringException e) {
360 throw new MojoExecutionException("Error filtering EAR sources", e);
361 }
362
363
364 if (!ddFile.exists() && (javaEEVersion.lt(JavaEEVersion.FIVE))) {
365 throw new MojoExecutionException("Deployment descriptor: " + ddFile.getAbsolutePath() + " does not exist.");
366 }
367
368 outdatedResources.remove(Paths.get(APPLICATION_XML_URI).toString());
369 if (getJbossConfiguration() != null) {
370 outdatedResources.remove(Paths.get("META-INF/jboss-app.xml").toString());
371 }
372
373 deleteOutdatedResources(outdatedResources);
374
375 try {
376 getLog().debug("Excluding " + Arrays.asList(getPackagingExcludes()) + " from the generated EAR.");
377 getLog().debug("Including " + Arrays.asList(getPackagingIncludes()) + " in the generated EAR.");
378
379 archiver.getArchiver().addDirectory(getWorkDirectory(), getPackagingIncludes(), getPackagingExcludes());
380
381 archiver.createArchive(session, getProject(), archive);
382 } catch (ManifestException | IOException | DependencyResolutionRequiredException e) {
383 throw new MojoExecutionException("Error assembling EAR", e);
384 }
385
386 if (classifier != null) {
387 projectHelper.attachArtifact(getProject(), "ear", classifier, earFile);
388 } else {
389 getProject().getArtifact().setFile(earFile);
390 }
391 }
392
393 private void copyModules(
394 final JavaEEVersion javaEEVersion, List<String> unpackTypesList, Collection<String> outdatedResources)
395 throws MojoExecutionException, MojoFailureException {
396 try {
397 for (EarModule module : getModules()) {
398 final File sourceFile = module.getArtifact().getFile();
399 final File destinationFile = buildDestinationFile(getWorkDirectory(), module.getUri());
400 if (!sourceFile.isFile()) {
401 throw new MojoExecutionException("Cannot copy a directory: " + sourceFile.getAbsolutePath()
402 + "; Did you package/install " + module.getArtifact() + "?");
403 }
404
405 if (destinationFile.getCanonicalPath().equals(sourceFile.getCanonicalPath())) {
406 getLog().info("Skipping artifact [" + module + "], as it already exists at [" + module.getUri()
407 + "]");
408
409 continue;
410 }
411
412
413
414 if ((unpackTypesList.contains(module.getType())
415 && (module.shouldUnpack() == null || module.shouldUnpack()))
416 || (module.shouldUnpack() != null && module.shouldUnpack())) {
417 getLog().info("Copying artifact [" + module + "] to [" + module.getUri() + "] (unpacked)");
418
419 if (!destinationFile.isDirectory() && !destinationFile.mkdirs()) {
420 throw new MojoExecutionException("Error creating " + destinationFile);
421 }
422 unpack(sourceFile, destinationFile, outdatedResources);
423
424 if (module.changeManifestClasspath()) {
425 changeManifestClasspath(module, destinationFile, javaEEVersion, outdatedResources);
426 }
427 } else {
428 if (sourceFile.lastModified() > destinationFile.lastModified()) {
429 getLog().info("Copying artifact [" + module + "] to [" + module.getUri() + "]");
430 createParentIfNecessary(destinationFile);
431 Files.copy(
432 sourceFile.toPath(),
433 destinationFile.toPath(),
434 LinkOption.NOFOLLOW_LINKS,
435 StandardCopyOption.REPLACE_EXISTING);
436 if (module.changeManifestClasspath()) {
437 changeManifestClasspath(module, destinationFile, javaEEVersion, outdatedResources);
438 }
439 } else {
440 getLog().debug("Skipping artifact [" + module + "], as it is already up to date at ["
441 + module.getUri() + "]");
442 }
443 removeFromOutdatedResources(destinationFile.toPath(), outdatedResources);
444 }
445 }
446 } catch (IOException e) {
447 throw new MojoExecutionException("Error copying EAR modules", e);
448 } catch (ArchiverException e) {
449 throw new MojoExecutionException("Error unpacking EAR modules", e);
450 } catch (NoSuchArchiverException e) {
451 throw new MojoExecutionException("No Archiver found for EAR modules", e);
452 }
453 }
454
455 private List<String> createUnpackList() throws MojoExecutionException {
456 List<String> unpackTypesList = new ArrayList<>();
457 if (unpackTypes != null) {
458 unpackTypesList = Arrays.asList(unpackTypes.split(","));
459 for (String type : unpackTypesList) {
460 if (!EarModuleFactory.isStandardArtifactType(type)) {
461 throw new MojoExecutionException("Invalid type [" + type + "] supported types are "
462 + EarModuleFactory.getStandardArtifactTypes());
463 }
464 }
465 getLog().debug("Initialized unpack types " + unpackTypesList);
466 }
467 return unpackTypesList;
468 }
469
470
471
472
473 public File getApplicationXml() {
474 return applicationXml;
475 }
476
477
478
479
480 public void setApplicationXml(File applicationXml) {
481 this.applicationXml = applicationXml;
482 }
483
484
485
486
487
488
489 protected String[] getExcludes() {
490 List<String> excludeList = new ArrayList<>(FileUtils.getDefaultExcludesAsList());
491 if (earSourceExcludes != null && !"".equals(earSourceExcludes)) {
492 excludeList.addAll(Arrays.asList(StringUtils.split(earSourceExcludes, ",")));
493 }
494
495
496 if (getApplicationXml() != null && !"".equals(getApplicationXml())) {
497 excludeList.add("**/" + META_INF + "/application.xml");
498 }
499
500 return excludeList.toArray(new String[excludeList.size()]);
501 }
502
503
504
505
506
507
508 protected String[] getIncludes() {
509 return StringUtils.split(Objects.toString(earSourceIncludes, ""), ",");
510 }
511
512
513
514
515 public String[] getPackagingExcludes() {
516 if (packagingExcludes == null || packagingExcludes.isEmpty()) {
517 return new String[0];
518 } else {
519 return StringUtils.split(packagingExcludes, ",");
520 }
521 }
522
523
524
525
526 public void setPackagingExcludes(String packagingExcludes) {
527 this.packagingExcludes = packagingExcludes;
528 }
529
530
531
532
533 public String[] getPackagingIncludes() {
534 if (packagingIncludes == null || packagingIncludes.isEmpty()) {
535 return new String[] {"**"};
536 } else {
537 return StringUtils.split(packagingIncludes, ",");
538 }
539 }
540
541
542
543
544 public void setPackagingIncludes(String packagingIncludes) {
545 this.packagingIncludes = packagingIncludes;
546 }
547
548 private static File buildDestinationFile(File buildDir, String uri) {
549 return new File(buildDir, uri);
550 }
551
552
553
554
555
556
557
558
559
560 private static File getEarFile(String basedir, String finalName, String classifier) {
561 if (classifier == null) {
562 classifier = "";
563 } else if (classifier.trim().length() > 0 && !classifier.startsWith("-")) {
564 classifier = "-" + classifier;
565 }
566
567 return new File(basedir, finalName + classifier + ".ear");
568 }
569
570
571
572
573
574
575
576 private String[] getEarFiles(File sourceDir) {
577 DirectoryScanner scanner = new DirectoryScanner();
578 scanner.setBasedir(sourceDir);
579 scanner.setExcludes(getExcludes());
580 scanner.addDefaultExcludes();
581
582 scanner.setIncludes(getIncludes());
583
584 scanner.scan();
585
586 return scanner.getIncludedFiles();
587 }
588
589
590
591
592
593
594
595
596
597
598
599 public void unpack(File source, final File destDir, final Collection<String> outdatedResources)
600 throws ArchiverException, NoSuchArchiverException, IOException {
601 Path destPath = destDir.toPath();
602
603 UnArchiver unArchiver = archiverManager.getUnArchiver("zip");
604 unArchiver.setSourceFile(source);
605 unArchiver.setDestDirectory(destDir);
606 unArchiver.setFileMappers(new FileMapper[] {
607 pName -> {
608 removeFromOutdatedResources(destPath.resolve(pName), outdatedResources);
609 return pName;
610 }
611 });
612
613
614 unArchiver.extract();
615 }
616
617 private void copyFile(File source, File target)
618 throws MavenFilteringException, IOException, MojoExecutionException {
619 createParentIfNecessary(target);
620 if (filtering && !isNonFilteredExtension(source.getName())) {
621 mavenFileFilter.copyFile(source, target, true, getFilterWrappers(), encoding);
622 } else {
623 Files.copy(
624 source.toPath(), target.toPath(), LinkOption.NOFOLLOW_LINKS, StandardCopyOption.REPLACE_EXISTING);
625 }
626 }
627
628 private void createParentIfNecessary(File target) throws IOException {
629
630 File parentDirectory = target.getParentFile();
631 if (parentDirectory != null && !parentDirectory.exists()) {
632 Files.createDirectories(parentDirectory.toPath());
633 }
634 }
635
636
637
638
639
640 public boolean isNonFilteredExtension(String fileName) {
641 return !mavenResourcesFiltering.filteredFileExtension(fileName, nonFilteredFileExtensions);
642 }
643
644 private List<FilterWrapper> getFilterWrappers() throws MojoExecutionException {
645 if (filterWrappers == null) {
646 try {
647 MavenResourcesExecution mavenResourcesExecution = new MavenResourcesExecution();
648 mavenResourcesExecution.setMavenProject(getProject());
649 mavenResourcesExecution.setEscapedBackslashesInFilePath(escapedBackslashesInFilePath);
650 mavenResourcesExecution.setFilters(filters);
651 mavenResourcesExecution.setEscapeString(escapeString);
652
653 filterWrappers = mavenFileFilter.getDefaultFilterWrappers(mavenResourcesExecution);
654 } catch (MavenFilteringException e) {
655 getLog().error("Fail to build filtering wrappers " + e.getMessage());
656 throw new MojoExecutionException(e.getMessage(), e);
657 }
658 }
659 return filterWrappers;
660 }
661
662 private void changeManifestClasspath(
663 EarModule module, File original, JavaEEVersion javaEEVersion, Collection<String> outdatedResources)
664 throws MojoFailureException {
665 final String moduleLibDir = module.getLibDir();
666 if (!((moduleLibDir == null) || skinnyModules || (skinnyWars && module instanceof WebModule))) {
667 return;
668 }
669
670
671 FileTime outputFileTime = MavenArchiver.parseBuildOutputTimestamp(outputTimestamp)
672 .map(FileTime::from)
673 .orElse(null);
674
675 FileSystem fileSystem = null;
676
677 try {
678 Path workDirectory;
679
680
681
682 if (original.isFile()) {
683 fileSystem = FileSystems.newFileSystem(
684 original.toPath(), Thread.currentThread().getContextClassLoader());
685 workDirectory = fileSystem.getRootDirectories().iterator().next();
686 } else {
687 workDirectory = original.toPath();
688 }
689
690
691 Path metaInfDirectory = workDirectory.resolve("META-INF");
692 if (!Files.exists(metaInfDirectory)) {
693 Files.createDirectory(metaInfDirectory);
694 if (outputFileTime != null) {
695 Files.setLastModifiedTime(metaInfDirectory, outputFileTime);
696 }
697 getLog().debug(
698 "This project did not have a META-INF directory before, so a new directory was created.");
699 }
700 Path manifestFile = metaInfDirectory.resolve("MANIFEST.MF");
701 if (!Files.exists(manifestFile)) {
702 Files.createFile(manifestFile);
703 if (outputFileTime != null) {
704 Files.setLastModifiedTime(manifestFile, outputFileTime);
705 }
706 getLog().debug(
707 "This project did not have a META-INF/MANIFEST.MF file before, so a new file was created.");
708 }
709
710 Manifest mf = readManifest(manifestFile);
711 Attribute classPath = mf.getMainSection().getAttribute("Class-Path");
712 List<String> classPathElements = new ArrayList<>();
713
714 boolean classPathExists;
715 if (classPath != null) {
716 classPathExists = true;
717 classPathElements.addAll(Arrays.asList(classPath.getValue().split(" ")));
718 } else {
719 classPathExists = false;
720 classPath = new Attribute("Class-Path", "");
721 }
722
723 if ((moduleLibDir != null) && (skinnyModules || (skinnyWars && module instanceof WebModule))) {
724
725 for (EarModule otherModule : getAllEarModules()) {
726 if (module.equals(otherModule)) {
727 continue;
728 }
729
730
731
732
733 final Path workLibDir = workDirectory.resolve(moduleLibDir);
734 Path artifact =
735 workLibDir.resolve(module.getArtifact().getFile().getName());
736
737
738
739
740
741 if (!Files.exists(artifact)) {
742 getLog().debug("module does not exist with original file name.");
743 artifact = workLibDir.resolve(otherModule.getBundleFileName());
744 getLog().debug("Artifact with mapping: " + artifact.toAbsolutePath());
745 }
746
747 if (!Files.exists(artifact)) {
748 getLog().debug("Artifact with mapping does not exist.");
749 artifact = workLibDir.resolve(
750 otherModule.getArtifact().getFile().getName());
751 getLog().debug("Artifact with original file name: " + artifact.toAbsolutePath());
752 }
753
754 if (!Files.exists(artifact)) {
755 getLog().debug("Artifact with original file name does not exist.");
756 final Artifact otherModuleArtifact = otherModule.getArtifact();
757 if (otherModuleArtifact.isSnapshot()) {
758 try {
759 artifact = workLibDir.resolve(MappingUtils.evaluateFileNameMapping(
760 ARTIFACT_DEFAULT_FILE_NAME_MAPPING, otherModuleArtifact));
761 getLog().debug("Artifact with default mapping file name: " + artifact.toAbsolutePath());
762 } catch (InterpolationException e) {
763 getLog().warn("Failed to evaluate file name for [" + otherModule
764 + "] module using mapping: " + ARTIFACT_DEFAULT_FILE_NAME_MAPPING);
765 }
766 }
767 }
768
769 if (Files.exists(artifact)) {
770 getLog().debug(" -> Artifact to delete: " + artifact);
771 Files.delete(artifact);
772 }
773 }
774 }
775
776
777 final boolean forceClassPathModification =
778 javaEEVersion.lt(JavaEEVersion.FIVE) || defaultLibBundleDir == null;
779 final boolean classPathExtension = !skipClassPathModification || forceClassPathModification;
780 for (EarModule otherModule : getModules()) {
781 if (module.equals(otherModule)) {
782 continue;
783 }
784 final int moduleClassPathIndex = findModuleInClassPathElements(classPathElements, otherModule);
785 if (moduleClassPathIndex != -1) {
786 if (otherModule.isClassPathItem()) {
787 classPathElements.set(moduleClassPathIndex, otherModule.getUri());
788 } else {
789 classPathElements.remove(moduleClassPathIndex);
790 }
791 } else if (otherModule.isClassPathItem() && classPathExtension) {
792 classPathElements.add(otherModule.getUri());
793 }
794 }
795
796
797 for (EarModule otherModule : getProvidedEarModules()) {
798 final int moduleClassPathIndex = findModuleInClassPathElements(classPathElements, otherModule);
799 if (moduleClassPathIndex != -1) {
800 classPathElements.remove(moduleClassPathIndex);
801 }
802 }
803
804 if (!skipClassPathModification || !classPathElements.isEmpty() || classPathExists) {
805 classPath.setValue(StringUtils.join(classPathElements.iterator(), " "));
806 mf.getMainSection().addConfiguredAttribute(classPath);
807
808
809 FileTime lastModifiedTime = Files.getLastModifiedTime(manifestFile);
810 try (BufferedWriter writer = Files.newBufferedWriter(
811 manifestFile,
812 StandardCharsets.UTF_8,
813 StandardOpenOption.WRITE,
814 StandardOpenOption.CREATE,
815 StandardOpenOption.TRUNCATE_EXISTING)) {
816 mf.write(writer);
817 }
818 Files.setLastModifiedTime(manifestFile, lastModifiedTime);
819 removeFromOutdatedResources(manifestFile, outdatedResources);
820 }
821
822 if (fileSystem != null) {
823 fileSystem.close();
824 fileSystem = null;
825 }
826 } catch (ManifestException | IOException | ArchiverException e) {
827 throw new MojoFailureException(e.getMessage(), e);
828 } finally {
829 if (fileSystem != null) {
830 try {
831 fileSystem.close();
832 } catch (IOException e) {
833
834 }
835 }
836 }
837 }
838
839 private static Manifest readManifest(Path manifestFile) throws IOException {
840
841 try (InputStream in = Files.newInputStream(manifestFile)) {
842 return new Manifest(in);
843 }
844 }
845
846 private Collection<String> initOutdatedResources() {
847 final Collection<String> outdatedResources = new ArrayList<>();
848
849 if (getWorkDirectory().exists()) {
850 try {
851 Files.walkFileTree(getWorkDirectory().toPath(), new SimpleFileVisitor<Path>() {
852 @Override
853 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
854 outdatedResources.add(
855 getWorkDirectory().toPath().relativize(file).toString());
856 return super.visitFile(file, attrs);
857 }
858 });
859 } catch (IOException e) {
860 getLog().warn("Can't detect outdated resources", e);
861 }
862 }
863
864 getLog().debug("initOutdatedResources: " + outdatedResources);
865 return outdatedResources;
866 }
867
868 private void deleteOutdatedResources(final Collection<String> outdatedResources) {
869 getLog().debug("deleteOutdatedResources: " + outdatedResources);
870 final long startTime = session.getStartTime().getTime();
871
872 getLog().debug("deleteOutdatedResources session startTime: " + startTime);
873
874 for (String outdatedResource : outdatedResources) {
875 File resourceFile = new File(getWorkDirectory(), outdatedResource);
876 if (resourceFile.lastModified() < startTime) {
877 getLog().info("deleting outdated resource " + outdatedResource);
878 getLog().debug(outdatedResource + " last modified: " + resourceFile.lastModified());
879 resourceFile.delete();
880 }
881 }
882 }
883
884 private void removeFromOutdatedResources(Path destination, Collection<String> outdatedResources) {
885 Path relativeDestFile;
886 try {
887 relativeDestFile = getWorkDirectory().toPath().relativize(destination.normalize());
888 } catch (ProviderMismatchException e) {
889 relativeDestFile = destination.normalize();
890 }
891
892 if (outdatedResources.remove(relativeDestFile.toString())) {
893 getLog().debug("Remove from outdatedResources: " + relativeDestFile);
894 }
895 }
896
897
898
899
900
901
902
903
904
905
906 private int findModuleInClassPathElements(final List<String> classPathElements, final EarModule module) {
907 if (classPathElements.isEmpty()) {
908 return -1;
909 }
910 int moduleClassPathIndex = classPathElements.indexOf(module.getBundleFileName());
911 if (moduleClassPathIndex != -1) {
912 return moduleClassPathIndex;
913 }
914 final Artifact artifact = module.getArtifact();
915 moduleClassPathIndex = classPathElements.indexOf(artifact.getFile().getName());
916 if (moduleClassPathIndex != -1) {
917 return moduleClassPathIndex;
918 }
919 if (artifact.isSnapshot()) {
920 try {
921 moduleClassPathIndex = classPathElements.indexOf(
922 MappingUtils.evaluateFileNameMapping(ARTIFACT_DEFAULT_FILE_NAME_MAPPING, artifact));
923 if (moduleClassPathIndex != -1) {
924 return moduleClassPathIndex;
925 }
926 } catch (InterpolationException e) {
927 getLog().warn("Failed to evaluate file name for [" + module + "] module using mapping: "
928 + ARTIFACT_DEFAULT_FILE_NAME_MAPPING);
929 }
930 }
931 return classPathElements.indexOf(module.getUri());
932 }
933 }