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