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
496 public static URL getResource(
497 final String resourceName,
498 final URL directory)
499 {
500 String directoryLocation = null;
501 if (directory != null)
502 {
503 directoryLocation = directory.getFile();
504 }
505 return getResource(
506 resourceName,
507 directoryLocation);
508 }
509
510
511
512
513
514
515
516
517
518
519 public static URL toURL(String path)
520 {
521 URL url = null;
522 if (path != null)
523 {
524 path = ResourceUtils.normalizePath(path);
525
526 try
527 {
528 if (path.startsWith(CLASSPATH_PREFIX))
529 {
530 url = ResourceUtils.resolveClasspathResource(path);
531 }
532 else
533 {
534 final File file = new File(path);
535 url = file.exists() ? file.toURI().toURL() : new URL(path);
536 }
537 }
538 catch (MalformedURLException exception)
539 {
540
541 }
542 }
543 return url;
544 }
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564 public static URL resolveClasspathResource(String path)
565 {
566 URL urlResource = null;
567 if (path.startsWith(CLASSPATH_PREFIX))
568 {
569 path = path.substring(CLASSPATH_PREFIX.length(), path.length());
570
571
572
573 final int nestedPathOffset = path.indexOf("!/");
574
575
576 final String resourcePath = nestedPathOffset == -1 ? path : path.substring(0, nestedPathOffset);
577 final String nestingPath = nestedPathOffset == -1 ? "" : path.substring(nestedPathOffset);
578
579
580 urlResource = Thread.currentThread().getContextClassLoader().getResource(resourcePath);
581
582
583 if (urlResource == null)
584 {
585 if (logger.isDebugEnabled())
586 {
587 logger.debug("Resource could not be located on the classpath: " + resourcePath);
588 }
589 }
590 else
591 {
592 try
593 {
594
595 final int fileNameOffset = resourcePath.lastIndexOf('/');
596 final String resourceFileName =
597 fileNameOffset == -1 ? resourcePath : resourcePath.substring(fileNameOffset + 1);
598
599 if (logger.isDebugEnabled())
600 {
601 logger.debug("Creating temporary copy on the file system of the classpath resource");
602 }
603 final File fileSystemResource = File.createTempFile(resourceFileName, null);
604 if (logger.isDebugEnabled())
605 {
606 logger.debug("Temporary file will be deleted on VM exit: " + fileSystemResource.getAbsolutePath());
607 }
608 fileSystemResource.deleteOnExit();
609 if (logger.isDebugEnabled())
610 {
611 logger.debug("Copying classpath resource contents into temporary file");
612 }
613 writeUrlToFile(urlResource, fileSystemResource.toString());
614
615
616 final int nestingCount = StringUtils.countMatches(path, "!/");
617
618 final StringBuilder buffer = new StringBuilder();
619 for (int ctr = 0; ctr < nestingCount; ctr++)
620 {
621 buffer.append(ARCHIVE_PREFIX);
622 }
623 buffer.append(FILE_PREFIX).append(fileSystemResource.getAbsolutePath()).append(nestingPath);
624 if (logger.isDebugEnabled())
625 {
626 logger.debug("Constructing URL to " +
627 (nestingCount > 0 ? "nested" : "") + " resource in temporary file");
628 }
629
630 urlResource = new URL(buffer.toString());
631 }
632 catch (final IOException exception)
633 {
634 logger.warn("Unable to resolve classpath resource", exception);
635
636 urlResource = null;
637 }
638 }
639 }
640 return urlResource;
641 }
642
643
644
645
646
647
648
649
650 public static void writeUrlToFile(final URL url, final String fileLocation)
651 throws IOException
652 {
653 ExceptionUtils.checkNull(
654 "url",
655 url);
656 ExceptionUtils.checkEmpty(
657 "fileLocation",
658 fileLocation);
659
660 final File lOutputFile = new File(fileLocation);
661 makeDirectories(lOutputFile);
662 FileUtils.copyURLToFile(url, lOutputFile);
663 }
664
665
666
667
668
669
670
671 public static boolean isFile(final URL url)
672 {
673 return url != null && new File(url.getFile()).isFile();
674 }
675
676
677
678
679 private static final String FORWARD_SLASH = "/";
680
681
682
683
684
685
686
687
688
689
690
691 public static List<String> getDirectoryContents(
692 final URL url,
693 boolean absolute,
694 final String[] patterns)
695 {
696 List<String> contents = ResourceUtils.getDirectoryContents(
697 url,
698 0,
699 true);
700
701
702 if (!contents.isEmpty())
703 {
704 for (final ListIterator<String> iterator = contents.listIterator(); iterator.hasNext();)
705 {
706 String path = iterator.next();
707 if (!matchesAtLeastOnePattern(
708 path,
709 patterns))
710 {
711 iterator.remove();
712 }
713 else if (absolute)
714 {
715 path = url.toString().endsWith(FORWARD_SLASH) ? path : FORWARD_SLASH + path;
716 final URL resource = ResourceUtils.toURL(url + path);
717 if (resource != null)
718 {
719 iterator.set(resource.toString());
720 }
721 }
722 }
723 }
724 else
725 {
726 final String urlAsString = url.toString();
727 final String delimiter = "!/";
728 final String archivePath = urlAsString.replaceAll(
729 delimiter + ".*",
730 delimiter);
731 contents = ResourceUtils.getClassPathArchiveContents(url);
732 for (final ListIterator<String> iterator = contents.listIterator(); iterator.hasNext();)
733 {
734 final String relativePath = iterator.next();
735 final String fullPath = archivePath + relativePath;
736 if (!fullPath.startsWith(urlAsString) || fullPath.equals(urlAsString + FORWARD_SLASH))
737 {
738 iterator.remove();
739 }
740 else if (!matchesAtLeastOnePattern(
741 relativePath,
742 patterns))
743 {
744 iterator.remove();
745 }
746 else if (absolute)
747 {
748 iterator.set(fullPath);
749 }
750 }
751 }
752 return contents;
753 }
754
755
756
757
758
759
760
761
762
763
764 public static boolean matchesAtLeastOnePattern(
765 final String path,
766 final String[] patterns)
767 {
768 boolean matches = (patterns == null || patterns.length == 0);
769 if (!matches && patterns != null && patterns.length > 0)
770 {
771 final int patternNumber = patterns.length;
772 for (int ctr = 0; ctr < patternNumber; ctr++)
773 {
774 final String pattern = patterns[ctr];
775 if (PathMatcher.wildcardMatch(
776 path,
777 pattern))
778 {
779 matches = true;
780 break;
781 }
782 }
783 }
784 return matches;
785 }
786
787
788
789
790
791
792
793
794
795 public static boolean modifiedAfter(
796 long time,
797 final File directory)
798 {
799 final Collection<File> files = ResourceUtils.loadFiles(directory, true);
800 boolean changed = files.isEmpty();
801 for (File file : files)
802 {
803 changed = file.lastModified() < time;
804 if (changed)
805 {
806 break;
807 }
808 }
809 return changed;
810 }
811
812
813
814
815 private static final String BACK_SLASH_NORMALIZATION_PATTERN = "\\\\+";
816
817
818
819
820 private static final String FORWARD_SLASH_NORMALIZATION_PATTERN = FORWARD_SLASH + '+';
821
822
823
824
825
826
827
828
829 public static String normalizePath(final String path)
830 {
831 return path != null
832 ? path.replaceAll(
833 BACK_SLASH_NORMALIZATION_PATTERN,
834 FORWARD_SLASH).replaceAll(
835 FORWARD_SLASH_NORMALIZATION_PATTERN,
836 FORWARD_SLASH) : null;
837 }
838
839
840
841
842
843
844
845
846
847 public static String renameExtension(
848 final String path,
849 final String oldExtension,
850 final String newExtension)
851 {
852 ExceptionUtils.checkEmpty(
853 "path",
854 path);
855 ExceptionUtils.checkNull(
856 "oldExtension",
857 oldExtension);
858 ExceptionUtils.checkNull(
859 "newExtension",
860 newExtension);
861 String newPath = path;
862 final int oldExtensionIndex = path.lastIndexOf(oldExtension);
863 if (oldExtensionIndex != -1)
864 {
865 newPath = path.substring(
866 0,
867 oldExtensionIndex) + newExtension;
868 }
869 return newPath;
870 }
871 }