1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.war.packaging;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.nio.file.Files;
24 import java.nio.file.attribute.BasicFileAttributes;
25
26 import org.apache.commons.io.input.XmlStreamReader;
27 import org.apache.maven.artifact.Artifact;
28 import org.apache.maven.plugin.MojoExecutionException;
29 import org.apache.maven.plugins.war.util.PathSet;
30 import org.apache.maven.plugins.war.util.WebappStructure;
31 import org.apache.maven.shared.filtering.MavenFilteringException;
32 import org.apache.maven.shared.mapping.MappingUtils;
33 import org.apache.maven.shared.utils.StringUtils;
34 import org.codehaus.plexus.archiver.ArchiverException;
35 import org.codehaus.plexus.archiver.UnArchiver;
36 import org.codehaus.plexus.archiver.jar.JarArchiver;
37 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
38 import org.codehaus.plexus.interpolation.InterpolationException;
39 import org.codehaus.plexus.util.DirectoryScanner;
40 import org.codehaus.plexus.util.FileUtils;
41
42
43
44
45 public abstract class AbstractWarPackagingTask implements WarPackagingTask {
46
47
48
49 public static final String[] DEFAULT_INCLUDES = {"**/**"};
50
51
52
53
54 public static final String WEB_INF_PATH = "WEB-INF";
55
56
57
58
59 public static final String META_INF_PATH = "META-INF";
60
61
62
63
64 public static final String CLASSES_PATH = "WEB-INF/classes/";
65
66
67
68
69 public static final String LIB_PATH = "WEB-INF/lib/";
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 protected void copyFiles(
91 String sourceId,
92 WarPackagingContext context,
93 File sourceBaseDir,
94 PathSet sourceFilesSet,
95 String targetPrefix,
96 boolean filtered)
97 throws IOException, MojoExecutionException {
98 for (String fileToCopyName : sourceFilesSet.paths()) {
99 final File sourceFile = new File(sourceBaseDir, fileToCopyName);
100
101 String destinationFileName;
102 if (targetPrefix == null) {
103 destinationFileName = fileToCopyName;
104 } else {
105 destinationFileName = targetPrefix + fileToCopyName;
106 }
107
108 if (filtered && !context.isNonFilteredExtension(sourceFile.getName())) {
109 copyFilteredFile(sourceId, context, sourceFile, destinationFileName);
110 } else {
111 copyFile(sourceId, context, sourceFile, destinationFileName);
112 }
113 }
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 protected void copyFiles(
131 String sourceId, WarPackagingContext context, File sourceBaseDir, PathSet sourceFilesSet, boolean filtered)
132 throws IOException, MojoExecutionException {
133 copyFiles(sourceId, context, sourceBaseDir, sourceFilesSet, null, filtered);
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147
148 protected void copyFile(String sourceId, final WarPackagingContext context, final File file, String targetFilename)
149 throws IOException
150
151 {
152 final File targetFile = new File(context.getWebappDirectory(), targetFilename);
153
154 if (file.isFile()) {
155 context.getWebappStructure()
156 .registerFile(sourceId, targetFilename, new WebappStructure.RegistrationCallback() {
157 public void registered(String ownerId, String targetFilename) throws IOException {
158 copyFile(context, file, targetFile, targetFilename, false);
159 }
160
161 public void alreadyRegistered(String ownerId, String targetFilename) throws IOException {
162 copyFile(context, file, targetFile, targetFilename, true);
163 }
164
165 public void refused(String ownerId, String targetFilename, String actualOwnerId)
166 throws IOException {
167 context.getLog()
168 .debug(" - "
169 + targetFilename
170 + " wasn't copied because it has "
171 + "already been packaged for overlay ["
172 + actualOwnerId + "].");
173 }
174
175 public void superseded(String ownerId, String targetFilename, String deprecatedOwnerId)
176 throws IOException {
177 context.getLog()
178 .info("File ["
179 + targetFilename
180 + "] belonged to overlay ["
181 + deprecatedOwnerId
182 + "] so it will be overwritten.");
183 copyFile(context, file, targetFile, targetFilename, false);
184 }
185
186 public void supersededUnknownOwner(String ownerId, String targetFilename, String unknownOwnerId)
187 throws IOException {
188
189 context.getLog()
190 .warn("File ["
191 + targetFilename
192 + "] belonged to overlay ["
193 + unknownOwnerId
194 + "] which does not exist anymore in the current project. It is recommended to invoke "
195 + "clean if the dependencies of the project changed.");
196
197 copyFile(context, file, targetFile, targetFilename, false);
198 }
199 });
200 } else if (!targetFile.exists() && !targetFile.mkdirs()) {
201 context.getLog().info("Failed to create directory " + targetFile.getAbsolutePath());
202 }
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219 protected boolean copyFilteredFile(
220 String sourceId, final WarPackagingContext context, File file, String targetFilename)
221 throws IOException, MojoExecutionException {
222 context.addResource(targetFilename);
223
224 if (context.getWebappStructure().registerFile(sourceId, targetFilename)) {
225 final File targetFile = new File(context.getWebappDirectory(), targetFilename);
226 final String encoding;
227 try {
228 if (isXmlFile(file)) {
229
230 encoding = getEncoding(file);
231 } else if (isPropertiesFile(file) && StringUtils.isNotEmpty(context.getPropertiesEncoding())) {
232 encoding = context.getPropertiesEncoding();
233 } else {
234
235 encoding = context.getResourceEncoding();
236 }
237
238 targetFile.getParentFile().mkdirs();
239
240 context.getMavenFileFilter().copyFile(file, targetFile, true, context.getFilterWrappers(), encoding);
241 } catch (MavenFilteringException e) {
242 throw new MojoExecutionException(e.getMessage(), e);
243 }
244
245
246 context.getLog().debug(" + " + targetFilename + " has been copied (filtered encoding='" + encoding + "').");
247
248 return true;
249 } else {
250 context.getLog()
251 .debug(" - " + targetFilename + " wasn't copied because it has already been packaged (filtered).");
252 return false;
253 }
254 }
255
256
257
258
259
260
261
262
263
264 protected void doUnpack(WarPackagingContext context, File file, File unpackDirectory)
265 throws MojoExecutionException {
266 String archiveExt = FileUtils.getExtension(file.getAbsolutePath()).toLowerCase();
267
268 try {
269 UnArchiver unArchiver = context.getArchiverManager().getUnArchiver(archiveExt);
270 unArchiver.setSourceFile(file);
271 unArchiver.setDestDirectory(unpackDirectory);
272 unArchiver.setOverwrite(true);
273 unArchiver.extract();
274 } catch (ArchiverException e) {
275 throw new MojoExecutionException(
276 "Error unpacking file [" + file.getAbsolutePath() + "]" + " to ["
277 + unpackDirectory.getAbsolutePath() + "]",
278 e);
279 } catch (NoSuchArchiverException e) {
280 context.getLog()
281 .warn("Skip unpacking dependency file [" + file.getAbsolutePath() + " with unknown extension ["
282 + archiveExt + "]");
283 }
284 }
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301 protected boolean copyFile(
302 WarPackagingContext context, File source, File destination, String targetFilename, boolean onlyIfModified)
303 throws IOException {
304 context.addResource(targetFilename);
305
306 BasicFileAttributes readAttributes = Files.readAttributes(source.toPath(), BasicFileAttributes.class);
307 if (onlyIfModified
308 && destination.lastModified()
309 >= readAttributes.lastModifiedTime().toMillis()) {
310 context.getLog().debug(" * " + targetFilename + " is up to date.");
311 return false;
312 } else {
313 if (readAttributes.isDirectory()) {
314 context.getLog().warn(" + " + targetFilename + " is packaged from the source folder");
315
316 try {
317 JarArchiver archiver = context.getJarArchiver();
318 archiver.addDirectory(source);
319 archiver.setDestFile(destination);
320 archiver.createArchive();
321 } catch (ArchiverException e) {
322 String msg = "Failed to create " + targetFilename;
323 context.getLog().error(msg, e);
324 throw new IOException(msg, e);
325 }
326 } else {
327 FileUtils.copyFile(source.getCanonicalFile(), destination);
328
329 destination.setLastModified(readAttributes.lastModifiedTime().toMillis());
330 context.getLog().debug(" + " + targetFilename + " has been copied.");
331 }
332 return true;
333 }
334 }
335
336
337
338
339
340
341
342
343 protected String getEncoding(File webXml) throws IOException {
344 try (XmlStreamReader xmlReader = new XmlStreamReader(webXml)) {
345 return xmlReader.getEncoding();
346 }
347 }
348
349
350
351
352
353
354
355
356
357 protected PathSet getFilesToIncludes(File baseDir, String[] includes, String[] excludes) {
358 return getFilesToIncludes(baseDir, includes, excludes, false);
359 }
360
361
362
363
364
365
366
367
368
369
370
371 protected PathSet getFilesToIncludes(
372 File baseDir, String[] includes, String[] excludes, boolean includeDirectories)
373
374 {
375 final DirectoryScanner scanner = new DirectoryScanner();
376 scanner.setBasedir(baseDir);
377
378 if (excludes != null) {
379 scanner.setExcludes(excludes);
380 }
381 scanner.addDefaultExcludes();
382
383 if (includes != null && includes.length > 0) {
384 scanner.setIncludes(includes);
385 } else {
386 scanner.setIncludes(DEFAULT_INCLUDES);
387 }
388
389 scanner.scan();
390
391 PathSet pathSet = new PathSet(scanner.getIncludedFiles());
392
393 if (includeDirectories) {
394 pathSet.addAll(scanner.getIncludedDirectories());
395 }
396
397 return pathSet;
398 }
399
400
401
402
403
404
405
406
407
408
409
410 protected String getArtifactFinalName(WarPackagingContext context, Artifact artifact)
411 throws InterpolationException {
412 if (context.getOutputFileNameMapping() != null) {
413 return MappingUtils.evaluateFileNameMapping(context.getOutputFileNameMapping(), artifact);
414 }
415
416 String classifier = artifact.getClassifier();
417 if ((classifier != null) && !("".equals(classifier.trim()))) {
418 return MappingUtils.evaluateFileNameMapping(MappingUtils.DEFAULT_FILE_NAME_MAPPING_CLASSIFIER, artifact);
419 } else {
420 return MappingUtils.evaluateFileNameMapping(MappingUtils.DEFAULT_FILE_NAME_MAPPING, artifact);
421 }
422 }
423
424
425
426
427
428
429
430
431
432 private boolean isFileOfType(File file, String extension) {
433 return file != null && file.isFile() && file.getName().endsWith(extension);
434 }
435
436
437
438
439
440
441
442
443 private boolean isPropertiesFile(File file) {
444 return isFileOfType(file, ".properties");
445 }
446
447
448
449
450
451
452
453
454
455 private boolean isXmlFile(File file) {
456 return isFileOfType(file, ".xml");
457 }
458 }