1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.common.util;
17
18 import java.io.BufferedReader;
19 import java.io.BufferedWriter;
20 import java.io.File;
21 import java.io.FileWriter;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.io.OutputStream;
26 import java.io.OutputStreamWriter;
27 import java.io.PrintStream;
28 import java.io.Reader;
29 import java.io.StringReader;
30 import java.io.Writer;
31 import java.net.MalformedURLException;
32 import java.net.URI;
33 import java.net.URISyntaxException;
34 import java.net.URL;
35 import java.security.MessageDigest;
36 import java.security.NoSuchAlgorithmException;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.Collections;
40 import java.util.List;
41 import java.util.Properties;
42
43 import org.apache.commons.io.FileUtils;
44 import org.apache.commons.io.IOUtils;
45 import org.apache.commons.lang3.StringUtils;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.springframework.core.io.DefaultResourceLoader;
49 import org.springframework.core.io.Resource;
50 import org.springframework.core.io.ResourceLoader;
51 import org.springframework.util.Assert;
52
53 public class LocationUtils {
54
55 private static final Logger logger = LoggerFactory.getLogger(LocationUtils.class);
56
57 private static final String FILE_PREFIX = "file:";
58 private static final String BACK_SLASH = "\\";
59 private static final String FORWARD_SLASH = "/";
60 private static final String SLASH_DOT_SLASH = "/./";
61 private static final String DOT_DOT_SLASH = "../";
62 private static final String SLASH_DOT_DOT = "/..";
63 private static final String CLASSPATH = "classpath:";
64 private static final String MD5 = "MD5";
65
66
67
68
69 public static String getMD5Checksum(String location) {
70 return getChecksum(location, MD5);
71 }
72
73
74
75
76 public static String getMD5Checksum(File file) {
77 return getChecksum(getCanonicalPath(file), MD5);
78 }
79
80
81
82
83 public static final PrintStream openPrintStream(File file) throws IOException {
84 return new PrintStream(FileUtils.openOutputStream(file));
85 }
86
87
88
89
90 public static final Writer openWriter(File file) throws IOException {
91 touch(file);
92 return new FileWriter(file);
93 }
94
95
96
97
98 public static final Writer openWriter(String location) throws IOException {
99 return openWriter(new File(location));
100 }
101
102 public static Properties getLocationProperties(LocationPropertiesContext context) {
103
104 Assert.notNull(context, "context is null");
105
106 Properties properties = context.getProperties();
107 String keySuffix = context.getKeySuffix();
108 String locationPropertiesSuffix = context.getLocationPropertiesSuffix();
109 String encoding = context.getEncoding();
110
111 Assert.notNull(properties, "properties is null");
112 Assert.notNull(keySuffix, "keySuffix is null");
113 Assert.notNull(locationPropertiesSuffix, "locationPropertiesSuffix is null");
114
115 List<String> keys = PropertyUtils.getEndsWithKeys(properties, keySuffix);
116
117 Properties locationProperties = new Properties();
118 for (String key : keys) {
119 String location = properties.getProperty(key);
120 if (!exists(location)) {
121 continue;
122 }
123 String propertiesLocation = location + locationPropertiesSuffix;
124 if (!exists(propertiesLocation)) {
125 continue;
126 }
127 Properties p = PropertyUtils.load(propertiesLocation, encoding);
128 locationProperties.putAll(p);
129 }
130 logger.info("Located {} properties for {} location listings", locationProperties.size(), keys.size());
131 return locationProperties;
132 }
133
134 public static TextMetaData getTextMetaData(File file) {
135 return getTextMetaData(getCanonicalPath(file));
136 }
137
138 public static TextMetaData getTextMetaData(String location) {
139 long lines = 0;
140 long size = 0;
141 BufferedReader in = null;
142 try {
143 in = getBufferedReader(location);
144 String s = in.readLine();
145 while (s != null) {
146 lines++;
147 size += s.length();
148 s = in.readLine();
149 }
150 return new TextMetaData(lines, size);
151 } catch (IOException e) {
152 throw new IllegalStateException(e);
153 } finally {
154 IOUtils.closeQuietly(in);
155 }
156 }
157
158
159
160
161
162
163
164
165
166
167
168 public static long getLineCount(File file) {
169 return getLineCount(file, null);
170 }
171
172 public static long getLineCount(File file, String encoding) {
173 return getLineCount(getCanonicalPath(file));
174 }
175
176
177
178
179
180
181
182
183
184
185
186
187 @Deprecated
188 public static long getLineCount(String location) {
189 return getLineCount(location, null);
190 }
191
192
193
194
195
196
197
198
199
200
201
202 public static long getLineCount(String location, String encoding) {
203 long count = 0;
204 BufferedReader in = null;
205 try {
206 in = getBufferedReader(location, encoding);
207 while (in.readLine() != null) {
208 count++;
209 }
210 return count;
211 } catch (IOException e) {
212 throw new IllegalStateException("Unexpected IO error", e);
213 } finally {
214 IOUtils.closeQuietly(in);
215 }
216 }
217
218 public static final void copyLocationsToFiles(List<String> locations, List<File> files) {
219 Assert.isTrue(locations.size() == files.size());
220 for (int i = 0; i < locations.size(); i++) {
221 String location = locations.get(i);
222 File destination = files.get(i);
223 copyLocationToFile(location, destination);
224 }
225 }
226
227
228
229
230 public static final String getClasspathFilename(String location) {
231 return getClasspathFilenames(Arrays.asList(location)).get(0);
232 }
233
234
235
236
237 public static final List<String> getClasspathFilenames(List<String> locations) {
238 List<String> classpathFilenames = new ArrayList<String>();
239 for (String location : locations) {
240 if (!isClasspathLocation(location)) {
241 throw new IllegalArgumentException(location + " must start with " + CLASSPATH);
242 } else {
243 classpathFilenames.add(StringUtils.substring(location, CLASSPATH.length()));
244 }
245 }
246 return classpathFilenames;
247 }
248
249
250
251
252 public static final boolean isClasspathLocation(String location) {
253 return StringUtils.startsWith(location, CLASSPATH);
254 }
255
256 public static final List<String> getNormalizedPathFragments(String absolutePath, boolean directory) {
257 String normalized = getNormalizedAbsolutePath(absolutePath);
258 String[] tokens = StringUtils.split(normalized, FORWARD_SLASH);
259 List<String> fragments = new ArrayList<String>();
260 StringBuilder sb = new StringBuilder();
261 sb.append(FORWARD_SLASH);
262 int length = directory ? tokens.length : tokens.length - 1;
263 for (int i = 0; i < length; i++) {
264 if (i != 0) {
265 sb.append(FORWARD_SLASH);
266 }
267 sb.append(tokens[i]);
268 fragments.add(sb.toString());
269 }
270 return fragments;
271 }
272
273 public static final List<String> getCanonicalPaths(List<File> files) {
274 List<String> paths = new ArrayList<String>();
275 for (File file : files) {
276 String path = getCanonicalPath(file);
277 paths.add(path);
278 }
279 return paths;
280 }
281
282 public static final List<String> getLocations(String location, LocationType type, String encoding) {
283 switch (type) {
284 case LOCATION:
285 return Collections.singletonList(location);
286 case LOCATIONLIST:
287 return getLocations(location, encoding);
288 default:
289 throw new IllegalArgumentException("Location type '" + type + "' is unknown");
290 }
291 }
292
293 public static final List<String> getLocations(String location, LocationType type) {
294 return getLocations(location, type, null);
295 }
296
297 public static final List<String> getLocations(String locationListing) {
298 return getLocations(Collections.singletonList(locationListing), null);
299 }
300
301 public static final List<String> getLocations(String locationListing, String encoding) {
302 return getLocations(Collections.singletonList(locationListing), encoding);
303 }
304
305 public static final List<String> getLocations(List<String> locationListings) {
306 return getLocations(locationListings, null);
307 }
308
309 public static final void copyLocationToFile(String location, File destination) {
310 Assert.notNull(location);
311 Assert.notNull(destination);
312 logger.debug("Copying [{}]->[{}]", location, destination);
313 InputStream in = null;
314 try {
315 in = getInputStream(location);
316 FileUtils.copyInputStreamToFile(in, destination);
317 } catch (IOException e) {
318 throw new IllegalStateException(e);
319 } finally {
320 IOUtils.closeQuietly(in);
321 }
322 }
323
324 public static final List<File> getFiles(File dir, List<String> filenames) {
325 List<File> files = new ArrayList<File>();
326 for (String filename : filenames) {
327 File file = new File(dir, filename);
328 files.add(file);
329 }
330 return files;
331 }
332
333 public static final List<String> getFilenames(List<String> locations) {
334 Assert.notNull(locations);
335 List<String> filenames = new ArrayList<String>();
336 for (String location : locations) {
337 filenames.add(getFilename(location));
338 }
339 return filenames;
340 }
341
342
343
344
345 public static final void validateLocationListing(String locationListing) {
346 validateLocationListings(Collections.singletonList(locationListing));
347 }
348
349
350
351
352 public static final void validateLocationListings(List<String> locationListings) {
353 for (String locationListing : locationListings) {
354 validateLocation(locationListing);
355 List<String> locations = getLocations(locationListing);
356 validateLocations(locations);
357 }
358 }
359
360 public static final void validateLocations(List<String> locations) {
361 for (String location : locations) {
362 validateLocation(location);
363 }
364 }
365
366
367
368
369 public static final void validateLocation(String location) {
370 validateLocation(location, "[" + location + "] does not exist");
371 }
372
373
374
375
376 public static final void validateLocation(String location, String message) {
377 Assert.isTrue(exists(location), message);
378 }
379
380 public static final List<String> getLocations(List<String> locationListings, String encoding) {
381 List<String> locations = new ArrayList<String>();
382 for (String locationListing : locationListings) {
383 List<String> lines = readLines(locationListing, encoding);
384 locations.addAll(lines);
385 }
386 return locations;
387 }
388
389 public static final String getCanonicalURLString(File file) {
390 if (file == null) {
391 return null;
392 }
393 String path = getCanonicalPath(file);
394 File canonical = new File(path);
395 return getURLString(canonical);
396 }
397
398 public static final void validateNormalizedPath(String originalPath, String normalizedPath) {
399 if (CollectionUtils.containsAny(normalizedPath, Arrays.asList(SLASH_DOT_DOT, SLASH_DOT_SLASH, DOT_DOT_SLASH))) {
400 throw new IllegalArgumentException("[" + originalPath + "] could not be normalized. Normalized path [" + normalizedPath + "]");
401 }
402 }
403
404
405
406
407 public static final String getNormalizedAbsolutePath(String absolutePath) {
408 if (absolutePath == null) {
409 return null;
410 }
411 String replaced = StringUtils.replace(absolutePath, BACK_SLASH, FORWARD_SLASH);
412 boolean absolute = StringUtils.startsWith(replaced, FORWARD_SLASH);
413 if (!absolute) {
414 throw new IllegalArgumentException("[" + absolutePath + "] is not an absolute path.");
415 }
416 String prefixed = FILE_PREFIX + replaced;
417 try {
418 URI rawURI = new URI(prefixed);
419 URI normalizedURI = rawURI.normalize();
420 URL normalizedURL = normalizedURI.toURL();
421 String externalForm = normalizedURL.toExternalForm();
422 String trimmed = StringUtils.substring(externalForm, FILE_PREFIX.length());
423 validateNormalizedPath(absolutePath, trimmed);
424 return trimmed;
425 } catch (MalformedURLException e) {
426 throw new IllegalArgumentException(e);
427 } catch (URISyntaxException e) {
428 throw new IllegalArgumentException(e);
429 }
430 }
431
432 public static final String getURLString(File file) {
433 if (file == null) {
434 return null;
435 }
436 try {
437 URI uri = file.toURI();
438 URL url = uri.toURL();
439 return url.toExternalForm();
440 } catch (MalformedURLException e) {
441 throw new IllegalArgumentException(e);
442 }
443 }
444
445 public static final void forceMkdir(File file) {
446 try {
447 FileUtils.forceMkdir(file);
448 } catch (IOException e) {
449 throw new IllegalArgumentException("Unexpected IO error", e);
450 }
451 }
452
453 public static final void touch(File file) {
454 try {
455 FileUtils.touch(file);
456 } catch (IOException e) {
457 throw new IllegalArgumentException("Unexpected IO error", e);
458 }
459 }
460
461 public static final String getCanonicalPath(File file) {
462 try {
463 return file.getCanonicalPath();
464 } catch (IOException e) {
465 throw new IllegalArgumentException("Unexpected IO error", e);
466 }
467 }
468
469
470
471
472
473 public static final boolean deleteFileQuietly(String filename) {
474 File file = getFileQuietly(filename);
475 return FileUtils.deleteQuietly(file);
476 }
477
478
479
480
481 public static final File getFileQuietly(String filename) {
482 if (filename == null) {
483 return null;
484 } else {
485 return new File(filename);
486 }
487 }
488
489
490
491
492 public static final String toString(File file) {
493 return toString(file, null);
494 }
495
496
497
498
499 public static final String toString(File file, String encoding) {
500 return toString(getCanonicalPath(file), encoding);
501 }
502
503
504
505
506 public static final String toString(String location) {
507 return toString(location, null);
508 }
509
510
511
512
513 public static final String toString(String location, String encoding) {
514 InputStream in = null;
515 try {
516 in = getInputStream(location);
517 if (encoding == null) {
518 return IOUtils.toString(in);
519 } else {
520 return IOUtils.toString(in, encoding);
521 }
522 } catch (IOException e) {
523 throw new IllegalStateException("Unexpected IO error", e);
524 } finally {
525 IOUtils.closeQuietly(in);
526 }
527 }
528
529
530
531
532 public static final List<String> readLinesFromString(String s) {
533 Reader reader = getBufferedReaderFromString(s);
534 return readLinesAndClose(reader);
535 }
536
537 public static final List<String> readLinesAndClose(InputStream in) {
538 return readLinesAndClose(in, null);
539 }
540
541 public static final List<String> readLinesAndClose(InputStream in, String encoding) {
542 Reader reader = null;
543 try {
544 reader = getBufferedReader(in, encoding);
545 return readLinesAndClose(reader);
546 } catch (IOException e) {
547 throw new IllegalStateException("Unexpected IO error", e);
548 } finally {
549 IOUtils.closeQuietly(reader);
550 }
551 }
552
553 public static final List<String> readLinesAndClose(Reader reader) {
554 try {
555 return IOUtils.readLines(reader);
556 } catch (IOException e) {
557 throw new IllegalStateException("Unexpected IO error", e);
558 } finally {
559 IOUtils.closeQuietly(reader);
560 }
561 }
562
563
564
565
566 public static final List<String> readLines(File file) {
567 return readLines(getCanonicalPath(file));
568 }
569
570
571
572
573 public static final List<String> readLines(String location) {
574 return readLines(location, null);
575 }
576
577
578
579
580 public static final List<String> readLines(String location, String encoding) {
581 Reader reader = null;
582 try {
583 reader = getBufferedReader(location, encoding);
584 return readLinesAndClose(reader);
585 } catch (IOException e) {
586 throw new IllegalStateException("Unexpected IO error", e);
587 } finally {
588 IOUtils.closeQuietly(reader);
589 }
590 }
591
592
593
594
595 public static final BufferedReader getBufferedReader(String location) throws IOException {
596 return getBufferedReader(location, null);
597 }
598
599
600
601
602 public static final BufferedReader getBufferedReader(String location, String encoding) throws IOException {
603 try {
604 InputStream in = getInputStream(location);
605 return getBufferedReader(in, encoding);
606 } catch (IOException e) {
607 throw new IOException("Unexpected IO error", e);
608 }
609 }
610
611
612
613
614 public static final BufferedReader getBufferedReaderFromString(String s) {
615 return new BufferedReader(new StringReader(s));
616 }
617
618
619
620
621 public static final Writer getWriter(OutputStream out, String encoding) throws IOException {
622 if (encoding == null) {
623 return new BufferedWriter(new OutputStreamWriter(out));
624 } else {
625 return new BufferedWriter(new OutputStreamWriter(out, encoding));
626 }
627 }
628
629
630
631
632 public static final BufferedReader getBufferedReader(File file, String encoding) throws IOException {
633 return getBufferedReader(FileUtils.openInputStream(file), encoding);
634 }
635
636
637
638
639 public static final BufferedReader getBufferedReader(InputStream in, String encoding) throws IOException {
640 if (encoding == null) {
641 return new BufferedReader(new InputStreamReader(in));
642 } else {
643 return new BufferedReader(new InputStreamReader(in, encoding));
644 }
645 }
646
647
648
649
650 public static final boolean isExistingFile(String location) {
651 if (location == null) {
652 return false;
653 }
654 File file = new File(location);
655 return file.exists();
656 }
657
658
659
660
661 public static final boolean exists(File file) {
662 if (file == null) {
663 return false;
664 }
665 String location = getCanonicalPath(file);
666 if (isExistingFile(location)) {
667 return true;
668 } else {
669 Resource resource = getResource(location);
670 return resource.exists();
671 }
672 }
673
674 public static void validateExists(List<String> locations) {
675 StringBuilder sb = new StringBuilder();
676 for (String location : locations) {
677 if (!LocationUtils.exists(location)) {
678 sb.append("Location [" + location + "] does not exist\n");
679 }
680 }
681 if (sb.length() > 0) {
682 throw new IllegalArgumentException(sb.toString());
683 }
684 }
685
686
687
688
689 public static final boolean exists(String location) {
690 if (location == null) {
691 return false;
692 }
693 if (isExistingFile(location)) {
694 return true;
695 } else {
696 Resource resource = getResource(location);
697 return resource.exists();
698 }
699 }
700
701
702
703
704
705 public static final InputStream getInputStream(String location) throws IOException {
706 if (isExistingFile(location)) {
707 return FileUtils.openInputStream(new File(location));
708 }
709 Resource resource = getResource(location);
710 return resource.getInputStream();
711 }
712
713 public static final Resource getResource(String location) {
714 if (location == null) {
715 return null;
716 }
717 ResourceLoader loader = new DefaultResourceLoader();
718 return loader.getResource(location);
719 }
720
721 public static final String getFilename(String location) {
722 if (location == null) {
723 return null;
724 }
725 if (isExistingFile(location)) {
726 return getFileQuietly(location).getName();
727 } else {
728 Resource resource = getResource(location);
729 return resource.getFilename();
730 }
731 }
732
733 public static final List<String> getAbsolutePaths(List<File> files) {
734 List<String> results = new ArrayList<String>(files.size());
735
736 for (File f : files) {
737 results.add(f.getAbsolutePath());
738 }
739
740 return results;
741 }
742
743 public static final ComparisonResults getLocationListComparison(List<String> newLocations, List<String> originalLocations) {
744 ComparisonResults result = new ComparisonResults();
745
746 result.setAdded(new ArrayList<String>());
747 result.setSame(new ArrayList<String>());
748 result.setDeleted(new ArrayList<String>());
749
750 for (String newLocation : newLocations) {
751 if (originalLocations.contains(newLocation)) {
752
753 result.getSame().add(newLocation);
754 } else {
755
756 result.getAdded().add(newLocation);
757 }
758 }
759
760
761 result.getDeleted().addAll(originalLocations);
762 result.getDeleted().removeAll(newLocations);
763
764 return result;
765 }
766
767 public static String getChecksum(String location, String algorithm) {
768 byte[] b = createChecksum(location, algorithm);
769 StringBuilder sb = new StringBuilder();
770 for (int i = 0; i < b.length; i++) {
771 sb.append(Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1));
772 }
773 return sb.toString();
774 }
775
776 public static byte[] createChecksum(String location, String algorithm) {
777
778 InputStream in = null;
779 try {
780
781
782 in = LocationUtils.getInputStream(location);
783
784 byte[] buffer = new byte[1024];
785 MessageDigest complete = MessageDigest.getInstance(algorithm);
786 int numRead;
787 do {
788 numRead = in.read(buffer);
789 if (numRead > 0) {
790 complete.update(buffer, 0, numRead);
791 }
792 } while (numRead != -1);
793 IOUtils.closeQuietly(in);
794 return complete.digest();
795 } catch (NoSuchAlgorithmException e) {
796 throw new IllegalStateException("Unexpected message digest error", e);
797 } catch (IOException e) {
798 throw new IllegalStateException("Unexpected IO error", e);
799 } finally {
800 IOUtils.closeQuietly(in);
801 }
802 }
803
804 }