1 package org.codehaus.mojo.jaxb2.shared;
2
3 import org.apache.maven.plugin.MojoExecutionException;
4 import org.apache.maven.plugin.logging.Log;
5 import org.codehaus.mojo.jaxb2.AbstractJaxbMojo;
6 import org.codehaus.mojo.jaxb2.shared.filters.Filter;
7 import org.codehaus.mojo.jaxb2.shared.filters.Filters;
8 import org.codehaus.plexus.util.FileUtils;
9 import org.codehaus.plexus.util.Os;
10 import org.codehaus.plexus.util.StringUtils;
11
12 import java.io.File;
13 import java.io.FileFilter;
14 import java.io.IOException;
15 import java.net.MalformedURLException;
16 import java.net.URL;
17 import java.net.URLDecoder;
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.SortedMap;
22 import java.util.TreeMap;
23
24
25
26
27
28
29
30
31
32 public final class FileSystemUtilities {
33
34
35
36
37 private FileSystemUtilities() {
38
39 }
40
41
42
43
44 public static final FileFilter EXISTING_FILE = new FileFilter() {
45 @Override
46 public boolean accept(final File candidate) {
47 return candidate != null && candidate.exists() && candidate.isFile();
48 }
49 };
50
51
52
53
54 public static final FileFilter EXISTING_DIRECTORY = new FileFilter() {
55 @Override
56 public boolean accept(final File candidate) {
57 return candidate != null && candidate.exists() && candidate.isDirectory();
58 }
59 };
60
61
62
63
64
65
66
67 public static String getCanonicalPath(final File file) {
68 return getCanonicalFile(file).getPath();
69 }
70
71
72
73
74
75
76
77
78 private static final String[] INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME = {":", "*", "?", "\"", "<", ">", "|"};
79
80
81
82
83
84
85
86 public static File getCanonicalFile(final File file) {
87
88
89 Validate.notNull(file, "file");
90
91
92 try {
93 return file.getCanonicalFile();
94 } catch (IOException e) {
95 throw new IllegalArgumentException("Could not acquire the canonical file for ["
96 + file.getAbsolutePath() + "]", e);
97 }
98 }
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 public static File getExistingFile(final String path, final File baseDir) {
118
119
120 Validate.notEmpty(path, "path");
121 final File theFile = new File(path);
122 File toReturn = null;
123
124
125 if (theFile.isAbsolute() && (EXISTING_FILE.accept(theFile) || EXISTING_DIRECTORY.accept(theFile))) {
126 toReturn = getCanonicalFile(theFile);
127 }
128
129
130 if (!theFile.isAbsolute()) {
131
132
133 Validate.notNull(baseDir, "baseDir");
134 final File relativeFile = new File(baseDir, path);
135
136 if (EXISTING_FILE.accept(relativeFile) || EXISTING_DIRECTORY.accept(relativeFile)) {
137 toReturn = getCanonicalFile(relativeFile);
138 }
139 }
140
141
142 return toReturn;
143 }
144
145
146
147
148
149
150
151
152
153 public static URL getUrlFor(final File aFile) throws IllegalArgumentException {
154
155
156 Validate.notNull(aFile, "aFile");
157
158 try {
159 return aFile.toURI().normalize().toURL();
160 } catch (MalformedURLException e) {
161 throw new IllegalArgumentException("Could not retrieve the URL from file ["
162 + getCanonicalPath(aFile) + "]", e);
163 }
164 }
165
166
167
168
169
170
171
172
173 public static File getFileFor(final URL anURL, final String encoding) {
174
175
176 Validate.notNull(anURL, "anURL");
177 Validate.notNull(encoding, "encoding");
178
179 final String protocol = anURL.getProtocol();
180 File toReturn = null;
181 if ("file".equalsIgnoreCase(protocol)) {
182 try {
183 final String decodedPath = URLDecoder.decode(anURL.getPath(), encoding);
184 toReturn = new File(decodedPath);
185 } catch (Exception e) {
186 throw new IllegalArgumentException("Could not get the File for [" + anURL + "]", e);
187 }
188 } else if ("jar".equalsIgnoreCase(protocol)) {
189
190 try {
191
192
193 final String tmp = URLDecoder.decode(anURL.getFile(), encoding);
194
195
196
197 final URL innerURL = new URL(tmp);
198
199
200 if ("file".equalsIgnoreCase(innerURL.getProtocol())) {
201
202
203 final String innerUrlPath = innerURL.getPath();
204 final String filePath = innerUrlPath.contains("!")
205 ? innerUrlPath.substring(0, innerUrlPath.indexOf("!"))
206 : innerUrlPath;
207 toReturn = new File(filePath);
208 }
209 } catch (Exception e) {
210 throw new IllegalArgumentException("Could not get the File for [" + anURL + "]", e);
211 }
212 }
213
214
215 return toReturn;
216 }
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 public static List<URL> filterFiles(final File baseDir,
239 final List<String> sources,
240 final List<String> standardDirectories,
241 final Log log,
242 final String fileTypeDescription,
243 final List<Filter<File>> excludePatterns) {
244
245 final SortedMap<String, File> pathToResolvedSourceMap = new TreeMap<String, File>();
246
247 for (String current : standardDirectories) {
248 for (File currentResolvedSource : FileSystemUtilities.filterFiles(
249 baseDir,
250 sources,
251 FileSystemUtilities.relativize(current, baseDir),
252 log,
253 fileTypeDescription,
254 excludePatterns)) {
255
256
257 pathToResolvedSourceMap.put(
258 FileSystemUtilities.getCanonicalPath(currentResolvedSource),
259 currentResolvedSource);
260 }
261 }
262
263 final List<URL> toReturn = new ArrayList<URL>();
264
265
266 for (Map.Entry<String, File> current : pathToResolvedSourceMap.entrySet()) {
267 toReturn.add(FileSystemUtilities.getUrlFor(current.getValue()));
268 }
269
270 if (log.isDebugEnabled()) {
271
272 final StringBuilder builder = new StringBuilder();
273 builder.append("\n+=================== [Filtered " + fileTypeDescription + "]\n");
274
275 builder.append("|\n");
276 builder.append("| " + excludePatterns.size() + " Exclude patterns:\n");
277 for (int i = 0; i < excludePatterns.size(); i++) {
278 builder.append("| [" + (i + 1) + "/" + excludePatterns.size() + "]: " + excludePatterns.get(i) + "\n");
279 }
280
281 builder.append("|\n");
282 builder.append("| " + standardDirectories.size() + " Standard Directories:\n");
283 for (int i = 0; i < standardDirectories.size(); i++) {
284 builder.append("| [" + (i + 1) + "/" + standardDirectories.size() + "]: "
285 + standardDirectories.get(i) + "\n");
286 }
287
288 builder.append("|\n");
289 builder.append("| " + toReturn.size() + " Results:\n");
290 for (int i = 0; i < toReturn.size(); i++) {
291 builder.append("| [" + (i + 1) + "/" + toReturn.size() + "]: " + toReturn.get(i) + "\n");
292 }
293 builder.append("|\n");
294 builder.append("+=================== [End Filtered " + fileTypeDescription + "]\n\n");
295
296
297 log.debug(builder.toString().replace("\n", AbstractJaxbMojo.NEWLINE));
298 }
299
300
301 return toReturn;
302 }
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322 public static List<File> filterFiles(final File baseDir,
323 final List<String> sources,
324 final String standardDirectory,
325 final Log log,
326 final String fileTypeDescription,
327 final List<Filter<File>> excludeFilters) {
328
329
330 Validate.notNull(baseDir, "baseDir");
331 Validate.notNull(log, "log");
332 Validate.notEmpty(standardDirectory, "standardDirectory");
333 Validate.notEmpty(fileTypeDescription, "fileTypeDescription");
334
335
336 List<String> effectiveSources = sources;
337 if (sources == null || sources.isEmpty()) {
338 effectiveSources = new ArrayList<String>();
339
340 final File tmp = new File(standardDirectory);
341 final File rootDirectory = tmp.isAbsolute() ? tmp : new File(baseDir, standardDirectory);
342 effectiveSources.add(FileSystemUtilities.getCanonicalPath(rootDirectory));
343 }
344
345
346 List<File> existingSources = new ArrayList<File>();
347 for (String current : effectiveSources) {
348
349 final File existingFile = FileSystemUtilities.getExistingFile(current, baseDir);
350 if (existingFile != null) {
351 existingSources.add(existingFile);
352
353 if (log.isDebugEnabled()) {
354 log.debug("Accepted configured " + fileTypeDescription + " ["
355 + FileSystemUtilities.getCanonicalFile(existingFile) + "]");
356 }
357 } else {
358 if (log.isInfoEnabled()) {
359 log.info("Ignored given or default " + fileTypeDescription + " [" + current
360 + "], since it is not an existent file or directory.");
361 }
362 }
363 }
364
365 if (log.isDebugEnabled() && existingSources.size() > 0) {
366
367 final int size = existingSources.size();
368
369 log.debug(" [" + size + " existing " + fileTypeDescription + "] ...");
370 for (int i = 0; i < size; i++) {
371 log.debug(" " + (i + 1) + "/" + size + ": " + existingSources.get(i));
372 }
373 log.debug(" ... End [" + size + " existing " + fileTypeDescription + "]");
374 }
375
376
377 return FileSystemUtilities.resolveRecursively(existingSources, excludeFilters, log);
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395 public static List<File> resolveRecursively(final List<File> files,
396 final List<Filter<File>> exclusionFilters,
397 final Log log) {
398
399
400 Validate.notNull(files, "files");
401
402 final List<Filter<File>> effectiveExclusions = exclusionFilters == null
403 ? new ArrayList<Filter<File>>()
404 : exclusionFilters;
405
406 final List<File> toReturn = new ArrayList<File>();
407
408 if (files.size() > 0) {
409 for (File current : files) {
410
411 final boolean isAcceptedFile = EXISTING_FILE.accept(current)
412 && Filters.noFilterMatches(current, effectiveExclusions);
413 final boolean isAcceptedDirectory = EXISTING_DIRECTORY.accept(current)
414 && Filters.noFilterMatches(current, effectiveExclusions);
415
416 if (isAcceptedFile) {
417 toReturn.add(current);
418 } else if (isAcceptedDirectory) {
419 recurseAndPopulate(toReturn, effectiveExclusions, current, true, log);
420 }
421 }
422 }
423
424
425 return toReturn;
426 }
427
428
429
430
431
432
433
434
435
436 public static void createDirectory(final File aDirectory, final boolean cleanBeforeCreate)
437 throws MojoExecutionException {
438
439
440 Validate.notNull(aDirectory, "aDirectory");
441 validateFileOrDirectoryName(aDirectory);
442
443
444 if (cleanBeforeCreate) {
445 try {
446 FileUtils.deleteDirectory(aDirectory);
447 } catch (IOException e) {
448 throw new MojoExecutionException("Could not clean directory [" + getCanonicalPath(aDirectory) + "]", e);
449 }
450 }
451
452
453 final boolean existsAsFile = aDirectory.exists() && aDirectory.isFile();
454 if (existsAsFile) {
455 throw new MojoExecutionException("[" + getCanonicalPath(aDirectory) + "] exists and is a file. "
456 + "Cannot make directory");
457 } else if (!aDirectory.exists() && !aDirectory.mkdirs()) {
458 throw new MojoExecutionException("Could not create directory [" + getCanonicalPath(aDirectory) + "]");
459 }
460 }
461
462
463
464
465
466
467
468
469
470 public static String relativize(final String path, final File parentDir) {
471
472
473 Validate.notNull(path, "path");
474 Validate.notNull(parentDir, "parentDir");
475
476 final String basedirPath = FileSystemUtilities.getCanonicalPath(parentDir);
477 String toReturn = path;
478
479
480 if (path.toLowerCase().startsWith(basedirPath.toLowerCase())) {
481 toReturn = path.substring(basedirPath.length() + 1);
482 }
483
484
485 return toReturn;
486 }
487
488
489
490
491
492
493
494
495
496
497
498
499
500 public static List<File> listFiles(final File fileOrDir,
501 final List<Filter<File>> fileFilters,
502 final Log log) {
503 return listFiles(fileOrDir, fileFilters, false, log);
504 }
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521 public static List<File> listFiles(final File fileOrDir,
522 final List<Filter<File>> fileFilters,
523 final boolean excludeFilterOperation,
524 final Log log) {
525
526
527 Validate.notNull(log, "log");
528 Validate.notNull(fileFilters, "fileFilters");
529 final List<File> toReturn = new ArrayList<File>();
530
531 if (EXISTING_FILE.accept(fileOrDir)) {
532 checkAndAdd(toReturn, fileOrDir, fileFilters, excludeFilterOperation, log);
533 } else if (EXISTING_DIRECTORY.accept(fileOrDir)) {
534
535 final File[] listedFiles = fileOrDir.listFiles();
536 if (listedFiles != null) {
537 for (File current : listedFiles) {
538 checkAndAdd(toReturn, current, fileFilters, excludeFilterOperation, log);
539 }
540 }
541 }
542
543
544 return toReturn;
545 }
546
547
548
549
550
551 private static void checkAndAdd(final List<File> toPopulate,
552 final File current,
553 final List<Filter<File>> fileFilters,
554 final boolean excludeFilterOperation,
555 final Log log) {
556
557
558
559
560
561
562 final boolean noFilters = fileFilters == null || fileFilters.isEmpty();
563 final boolean addFile = excludeFilterOperation
564 ? noFilters || Filters.rejectAtLeastOnce(current, fileFilters)
565 : noFilters || Filters.matchAtLeastOnce(current, fileFilters);
566 final String logPrefix = (addFile ? "Accepted " : "Rejected ")
567 + (current.isDirectory() ? "directory" : "file") + " [";
568
569 if (addFile) {
570 toPopulate.add(current);
571 }
572
573 if (log.isDebugEnabled()) {
574 log.debug(logPrefix + getCanonicalPath(current) + "]");
575 }
576 }
577
578 private static void validateFileOrDirectoryName(final File fileOrDir) {
579
580 if (Os.isFamily(Os.FAMILY_WINDOWS) && !FileUtils.isValidWindowsFileName(fileOrDir)) {
581 throw new IllegalArgumentException(
582 "The file (" + fileOrDir + ") cannot contain any of the following characters: \n"
583 + StringUtils.join(INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME, " "));
584 }
585 }
586
587 private static void recurseAndPopulate(final List<File> toPopulate,
588 final List<Filter<File>> fileFilters,
589 final File aDirectory,
590 final boolean excludeOperation,
591 final Log log) {
592
593 final List<File> files = listFiles(aDirectory, fileFilters, excludeOperation, log);
594 for (File current : files) {
595 if (EXISTING_FILE.accept(current)) {
596 toPopulate.add(current);
597 }
598
599 if (EXISTING_DIRECTORY.accept(current)) {
600 recurseAndPopulate(toPopulate, fileFilters, current, excludeOperation, log);
601 }
602 }
603 }
604 }