1 package org.andromda.core.common;
2
3 import java.io.File;
4 import java.io.FileNotFoundException;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.Reader;
8 import java.net.MalformedURLException;
9 import java.net.URL;
10 import java.net.URLConnection;
11 import java.net.URLDecoder;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.Enumeration;
16 import java.util.List;
17 import java.util.ListIterator;
18 import java.util.zip.ZipEntry;
19 import java.util.zip.ZipFile;
20
21 import org.apache.commons.io.FileUtils;
22 import org.apache.commons.io.IOUtils;
23 import org.apache.commons.io.filefilter.TrueFileFilter;
24 import org.apache.commons.lang.StringUtils;
25 import org.apache.log4j.Logger;
26
27
28
29
30
31
32
33
34 public class ResourceUtils
35 {
36 private static final Logger logger = Logger.getLogger(ResourceUtils.class);
37
38
39
40
41 private static final String ARCHIVE_PREFIX = "jar:";
42
43
44
45
46 private static final String FILE_PREFIX = "file:";
47
48
49
50
51 private static final String CLASSPATH_PREFIX = "classpath:";
52
53
54
55
56
57
58
59 public static URL getResource(final String resourceName)
60 {
61 ExceptionUtils.checkEmpty(
62 "resourceName",
63 resourceName);
64 final ClassLoader loader = ClassUtils.getClassLoader();
65 URL resource = loader != null ? loader.getResource(resourceName) : null;
66
67 return resource;
68 }
69
70
71
72
73
74
75
76 public static String getContents(final URL resource)
77 {
78 String result = null;
79
80 InputStream in = null;
81 try
82 {
83 if(null!=resource)
84 {
85 in = resource.openStream();
86 result = IOUtils.toString(in);
87 }
88 }
89 catch (final IOException ex) {
90 throw new RuntimeException(ex);
91 }finally {
92 IOUtils.closeQuietly(in);
93 }
94 return result;
95 }
96
97
98
99
100
101
102
103 public static String getContents(final Reader resource)
104 {
105 String result;
106 try {
107 result = IOUtils.toString(resource);
108 }catch (IOException ex) {
109 throw new RuntimeException(ex);
110 }finally {
111 IOUtils.closeQuietly(resource);
112 }
113 return StringUtils.trimToEmpty(result);
114 }
115
116
117
118
119
120
121
122
123
124 public static List<String> getClassPathArchiveContents(final URL resource)
125 {
126 final List<String> contents = new ArrayList<String>();
127 if (isArchive(resource))
128 {
129 final ZipFile archive = getArchive(resource);
130 if (archive != null)
131 {
132 for (final Enumeration<? extends ZipEntry> entries = archive.entries(); entries.hasMoreElements();)
133 {
134 final ZipEntry entry = entries.nextElement();
135 contents.add(entry.getName());
136 }
137 try
138 {
139 archive.close();
140 }
141 catch (IOException ex)
142 {
143
144 }
145 }
146 }
147 return contents;
148 }
149
150
151
152
153
154
155
156
157
158
159
160 public static List<String> getDirectoryContents(
161 final URL resource,
162 final int levels)
163 {
164 return getDirectoryContents(resource, levels, true);
165 }
166
167
168
169
170 private static final String PATH_WHITESPACE_CHARACTER = "%20";
171
172
173
174
175
176
177
178
179 public static String unescapeFilePath(String filePath)
180 {
181 if (StringUtils.isNotBlank(filePath))
182 {
183 filePath = filePath.replaceAll(PATH_WHITESPACE_CHARACTER, " ");
184 }
185 return filePath;
186 }
187
188
189
190
191
192
193
194
195
196
197
198
199 public static List<String> getDirectoryContents(
200 final URL resource,
201 final int levels,
202 boolean includeSubdirectories)
203 {
204 final List<String> contents = new ArrayList<String>();
205 if (resource != null)
206 {
207
208 final File fileResource = new File(unescapeFilePath(resource.getFile()));
209 if (fileResource.isDirectory())
210 {
211 File rootDirectory = fileResource;
212 for (int ctr = 0; ctr < levels; ctr++)
213 {
214 rootDirectory = rootDirectory.getParentFile();
215 }
216 final File pluginDirectory = rootDirectory;
217 loadFiles(
218 pluginDirectory,
219 contents,
220 includeSubdirectories);
221
222
223 for (final ListIterator<String> iterator = contents.listIterator(); iterator.hasNext();)
224 {
225 final String filePath = iterator.next();
226 iterator.set(
227 StringUtils.replace(
228 filePath.replace(
229 '\\',
230 '/'),
231 pluginDirectory.getPath().replace(
232 '\\',
233 '/') + '/',
234 ""));
235 }
236 }
237 }
238 return contents;
239 }
240
241
242
243
244
245
246
247
248 private static void loadFiles(
249 final File directory,
250 final Collection<String> fileList,
251 boolean includeSubdirectories)
252 {
253 final Collection<File> lAllFiles = loadFiles(directory, includeSubdirectories);
254 for (File file : lAllFiles)
255 {
256 fileList.add(file.getPath());
257 }
258 }
259
260
261
262
263
264
265
266
267 private static Collection<File> loadFiles(
268 final File directory,
269 boolean includeSubdirectories)
270 {
271 Collection<File> result = Collections.emptyList();
272 if(null!=directory && directory.exists())
273 {
274 result = FileUtils.listFiles(
275 directory.isDirectory()? directory : directory.getParentFile(),
276 TrueFileFilter.INSTANCE,
277 includeSubdirectories ? TrueFileFilter.INSTANCE : null);
278 }
279 return result;
280 }
281
282
283
284
285
286
287
288
289 public static boolean isArchive(final URL resource)
290 {
291 return resource != null && resource.toString().startsWith(ARCHIVE_PREFIX);
292 }
293
294 private static final String URL_DECODE_ENCODING = "UTF-8";
295
296
297
298
299
300
301
302 public static ZipFile getArchive(final URL resource)
303 {
304 try
305 {
306 ZipFile archive = null;
307 if (resource != null)
308 {
309 String resourceUrl = resource.toString();
310 resourceUrl = resourceUrl.replaceFirst(
311 ARCHIVE_PREFIX,
312 "");
313 final int entryPrefixIndex = resourceUrl.indexOf('!');
314 if (entryPrefixIndex != -1)
315 {
316 resourceUrl = resourceUrl.substring(
317 0,
318 entryPrefixIndex);
319 }
320 resourceUrl = URLDecoder.decode(new URL(resourceUrl).getFile(), URL_DECODE_ENCODING);
321 File zipFile = new File(resourceUrl);
322 if (zipFile.exists())
323 {
324 archive = new ZipFile(resourceUrl);
325 }
326 else
327 {
328
329 throw new FileNotFoundException("ResourceUtils.getArchive " + resourceUrl + " NOT FOUND.");
330 }
331 }
332 return archive;
333 }
334
335 catch (final RuntimeException ex)
336 {
337 throw ex;
338 }
339
340 catch (final Throwable throwable)
341 {
342 throw new RuntimeException(throwable);
343 }
344 }
345
346
347
348
349
350
351
352 public static String getContents(final String resourceName)
353 {
354 return getContents(getResource(resourceName));
355 }
356
357
358
359
360
361
362
363 public static URL getClassResource(final String className)
364 {
365 ExceptionUtils.checkEmpty(
366 "className",
367 className);
368 return getResource(getClassNameAsResource(className));
369 }
370
371
372
373
374
375
376
377 private static String getClassNameAsResource(final String className)
378 {
379 return className.replace('.','/') + ".class";
380 }
381
382
383
384
385
386
387
388
389
390
391
392
393
394 public static URL getResource(
395 final String resourceName,
396 final String directory)
397 {
398 ExceptionUtils.checkEmpty(
399 "resourceName",
400 resourceName);
401
402 if (directory != null)
403 {
404 final File file = new File(directory, resourceName);
405 if (file.exists())
406 {
407 try
408 {
409 return file.toURI().toURL();
410 }
411 catch (final MalformedURLException exception)
412 {
413
414 }
415 }
416 }
417 return getResource(resourceName);
418 }
419
420
421
422
423
424
425 public static void makeDirectories(final String location)
426 {
427 final File file = new File(location);
428 makeDirectories(file);
429 }
430
431
432
433
434
435
436 public static void makeDirectories(final File location)
437 {
438 final File parent = location.getParentFile();
439 if (parent != null)
440 {
441 parent.mkdirs();
442 }
443 }
444
445
446
447
448
449
450
451
452
453 public static long getLastModifiedTime(final URL resource)
454 {
455 long lastModified;
456 try
457 {
458 final File file = new File(resource.getFile());
459 if (file.exists())
460 {
461 lastModified = file.lastModified();
462 }
463 else
464 {
465 URLConnection uriConnection = resource.openConnection();
466 lastModified = uriConnection.getLastModified();
467
468
469
470
471
472
473 IOUtils.closeQuietly(uriConnection.getInputStream());
474 }
475 }
476 catch (final Exception exception)
477 {
478 lastModified = 0;
479 }
480 return lastModified;
481 }
482
483
484
485
486
487
488
489
490
491
492
493
494
495 public static URL getResource(
496 final String resourceName,
497 final URL directory)
498 {
499 String directoryLocation = null;
500 if (directory != null)
501 {
502 directoryLocation = directory.getFile();
503 }
504 return getResource(
505 resourceName,
506 directoryLocation);
507 }
508
509
510
511
512
513
514
515
516
517
518 public static URL toURL(String path)
519 {
520 URL url = null;
521 if (path != null)
522 {
523 path = ResourceUtils.normalizePath(path);
524
525 try
526 {
527 if (path.startsWith(CLASSPATH_PREFIX))
528 {
529 url = ResourceUtils.resolveClasspathResource(path);
530 }
531 else
532 {
533 final File file = new File(path);
534 url = file.exists() ? file.toURI().toURL() : new URL(path);
535 }
536 }
537 catch (MalformedURLException exception)
538 {
539
540 }
541 }
542 return url;
543 }
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563 public static URL resolveClasspathResource(String path)
564 {
565 URL urlResource = null;
566 if (path.startsWith(CLASSPATH_PREFIX))
567 {
568 path = path.substring(CLASSPATH_PREFIX.length(), path.length());
569
570
571
572 final int nestedPathOffset = path.indexOf("!/");
573
574
575 final String resourcePath = nestedPathOffset == -1 ? path : path.substring(0, nestedPathOffset);
576 final String nestingPath = nestedPathOffset == -1 ? "" : path.substring(nestedPathOffset);
577
578
579 urlResource = Thread.currentThread().getContextClassLoader().getResource(resourcePath);
580
581
582 if (urlResource == null)
583 {
584 if (logger.isDebugEnabled())
585 {
586 logger.debug("Resource could not be located on the classpath: " + resourcePath);
587 }
588 }
589 else
590 {
591 try
592 {
593
594 final int fileNameOffset = resourcePath.lastIndexOf('/');
595 final String resourceFileName =
596 fileNameOffset == -1 ? resourcePath : resourcePath.substring(fileNameOffset + 1);
597
598 if (logger.isDebugEnabled())
599 {
600 logger.debug("Creating temporary copy on the file system of the classpath resource");
601 }
602 final File fileSystemResource = File.createTempFile(resourceFileName, null);
603 if (logger.isDebugEnabled())
604 {
605 logger.debug("Temporary file will be deleted on VM exit: " + fileSystemResource.getAbsolutePath());
606 }
607 fileSystemResource.deleteOnExit();
608 if (logger.isDebugEnabled())
609 {
610 logger.debug("Copying classpath resource contents into temporary file");
611 }
612 writeUrlToFile(urlResource, fileSystemResource.toString());
613
614
615 final int nestingCount = StringUtils.countMatches(path, "!/");
616
617 final StringBuilder buffer = new StringBuilder();
618 for (int ctr = 0; ctr < nestingCount; ctr++)
619 {
620 buffer.append(ARCHIVE_PREFIX);
621 }
622 buffer.append(FILE_PREFIX).append(fileSystemResource.getAbsolutePath()).append(nestingPath);
623 if (logger.isDebugEnabled())
624 {
625 logger.debug("Constructing URL to " +
626 (nestingCount > 0 ? "nested" : "") + " resource in temporary file");
627 }
628
629 urlResource = new URL(buffer.toString());
630 }
631 catch (final IOException exception)
632 {
633 logger.warn("Unable to resolve classpath resource", exception);
634
635 urlResource = null;
636 }
637 }
638 }
639 return urlResource;
640 }
641
642
643
644
645
646
647
648
649 public static void writeUrlToFile(final URL url, final String fileLocation)
650 throws IOException
651 {
652 ExceptionUtils.checkNull(
653 "url",
654 url);
655 ExceptionUtils.checkEmpty(
656 "fileLocation",
657 fileLocation);
658
659 final File lOutputFile = new File(fileLocation);
660 makeDirectories(lOutputFile);
661 FileUtils.copyURLToFile(url, lOutputFile);
662 }
663
664
665
666
667
668
669
670 public static boolean isFile(final URL url)
671 {
672 return url != null && new File(url.getFile()).isFile();
673 }
674
675
676
677
678 private static final String FORWARD_SLASH = "/";
679
680
681
682
683
684
685
686
687
688
689
690 public static List<String> getDirectoryContents(
691 final URL url,
692 boolean absolute,
693 final String[] patterns)
694 {
695 List<String> contents = ResourceUtils.getDirectoryContents(
696 url,
697 0,
698 true);
699
700
701 if (!contents.isEmpty())
702 {
703 for (final ListIterator<String> iterator = contents.listIterator(); iterator.hasNext();)
704 {
705 String path = iterator.next();
706 if (!matchesAtLeastOnePattern(
707 path,
708 patterns))
709 {
710 iterator.remove();
711 }
712 else if (absolute)
713 {
714 path = url.toString().endsWith(FORWARD_SLASH) ? path : FORWARD_SLASH + path;
715 final URL resource = ResourceUtils.toURL(url + path);
716 if (resource != null)
717 {
718 iterator.set(resource.toString());
719 }
720 }
721 }
722 }
723 else
724 {
725 final String urlAsString = url.toString();
726 final String delimiter = "!/";
727 final String archivePath = urlAsString.replaceAll(
728 delimiter + ".*",
729 delimiter);
730 contents = ResourceUtils.getClassPathArchiveContents(url);
731 for (final ListIterator<String> iterator = contents.listIterator(); iterator.hasNext();)
732 {
733 final String relativePath = iterator.next();
734 final String fullPath = archivePath + relativePath;
735 if (!fullPath.startsWith(urlAsString) || fullPath.equals(urlAsString + FORWARD_SLASH))
736 {
737 iterator.remove();
738 }
739 else if (!matchesAtLeastOnePattern(
740 relativePath,
741 patterns))
742 {
743 iterator.remove();
744 }
745 else if (absolute)
746 {
747 iterator.set(fullPath);
748 }
749 }
750 }
751 return contents;
752 }
753
754
755
756
757
758
759
760
761
762
763 public static boolean matchesAtLeastOnePattern(
764 final String path,
765 final String[] patterns)
766 {
767 boolean matches = (patterns == null || patterns.length == 0);
768 if (!matches && patterns != null && patterns.length > 0)
769 {
770 final int patternNumber = patterns.length;
771 for (int ctr = 0; ctr < patternNumber; ctr++)
772 {
773 final String pattern = patterns[ctr];
774 if (PathMatcher.wildcardMatch(
775 path,
776 pattern))
777 {
778 matches = true;
779 break;
780 }
781 }
782 }
783 return matches;
784 }
785
786
787
788
789
790
791
792
793
794 public static boolean modifiedAfter(
795 long time,
796 final File directory)
797 {
798 final Collection<File> files = ResourceUtils.loadFiles(directory, true);
799 boolean changed = files.isEmpty();
800 for (File file : files)
801 {
802 changed = file.lastModified() < time;
803 if (changed)
804 {
805 break;
806 }
807 }
808 return changed;
809 }
810
811
812
813
814 private static final String BACK_SLASH_NORMALIZATION_PATTERN = "\\\\+";
815
816
817
818
819 private static final String FORWARD_SLASH_NORMALIZATION_PATTERN = FORWARD_SLASH + '+';
820
821
822
823
824
825
826
827
828 public static String normalizePath(final String path)
829 {
830 return path != null
831 ? path.replaceAll(
832 BACK_SLASH_NORMALIZATION_PATTERN,
833 FORWARD_SLASH).replaceAll(
834 FORWARD_SLASH_NORMALIZATION_PATTERN,
835 FORWARD_SLASH) : null;
836 }
837
838
839
840
841
842
843
844
845
846 public static String renameExtension(
847 final String path,
848 final String oldExtension,
849 final String newExtension)
850 {
851 ExceptionUtils.checkEmpty(
852 "path",
853 path);
854 ExceptionUtils.checkNull(
855 "oldExtension",
856 oldExtension);
857 ExceptionUtils.checkNull(
858 "newExtension",
859 newExtension);
860 String newPath = path;
861 final int oldExtensionIndex = path.lastIndexOf(oldExtension);
862 if (oldExtensionIndex != -1)
863 {
864 newPath = path.substring(
865 0,
866 oldExtensionIndex) + newExtension;
867 }
868 return newPath;
869 }
870 }