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 public static long getLineCount(File file) {
159 return getLineCount(getCanonicalPath(file));
160 }
161
162 public static long getLineCount(String location) {
163 long count = 0;
164 BufferedReader in = null;
165 try {
166 in = getBufferedReader(location);
167 while (in.readLine() != null) {
168 count++;
169 }
170 return count;
171 } catch (IOException e) {
172 throw new IllegalStateException(e);
173 } finally {
174 IOUtils.closeQuietly(in);
175 }
176 }
177
178 public static final void copyLocationsToFiles(List<String> locations, List<File> files) {
179 Assert.isTrue(locations.size() == files.size());
180 for (int i = 0; i < locations.size(); i++) {
181 String location = locations.get(i);
182 File destination = files.get(i);
183 copyLocationToFile(location, destination);
184 }
185 }
186
187
188
189
190 public static final String getClasspathFilename(String location) {
191 return getClasspathFilenames(Arrays.asList(location)).get(0);
192 }
193
194
195
196
197 public static final List<String> getClasspathFilenames(List<String> locations) {
198 List<String> classpathFilenames = new ArrayList<String>();
199 for (String location : locations) {
200 if (!isClasspathLocation(location)) {
201 throw new IllegalArgumentException(location + " must start with " + CLASSPATH);
202 } else {
203 classpathFilenames.add(StringUtils.substring(location, CLASSPATH.length()));
204 }
205 }
206 return classpathFilenames;
207 }
208
209
210
211
212 public static final boolean isClasspathLocation(String location) {
213 return StringUtils.startsWith(location, CLASSPATH);
214 }
215
216 public static final List<String> getNormalizedPathFragments(String absolutePath, boolean directory) {
217 String normalized = getNormalizedAbsolutePath(absolutePath);
218 String[] tokens = StringUtils.split(normalized, FORWARD_SLASH);
219 List<String> fragments = new ArrayList<String>();
220 StringBuilder sb = new StringBuilder();
221 sb.append(FORWARD_SLASH);
222 int length = directory ? tokens.length : tokens.length - 1;
223 for (int i = 0; i < length; i++) {
224 if (i != 0) {
225 sb.append(FORWARD_SLASH);
226 }
227 sb.append(tokens[i]);
228 fragments.add(sb.toString());
229 }
230 return fragments;
231 }
232
233 public static final List<String> getCanonicalPaths(List<File> files) {
234 List<String> paths = new ArrayList<String>();
235 for (File file : files) {
236 String path = getCanonicalPath(file);
237 paths.add(path);
238 }
239 return paths;
240 }
241
242 public static final List<String> getLocations(String location, LocationType type, String encoding) {
243 switch (type) {
244 case LOCATION:
245 return Collections.singletonList(location);
246 case LOCATIONLIST:
247 return getLocations(location, encoding);
248 default:
249 throw new IllegalArgumentException("Location type '" + type + "' is unknown");
250 }
251 }
252
253 public static final List<String> getLocations(String location, LocationType type) {
254 return getLocations(location, type, null);
255 }
256
257 public static final List<String> getLocations(String locationListing) {
258 return getLocations(Collections.singletonList(locationListing), null);
259 }
260
261 public static final List<String> getLocations(String locationListing, String encoding) {
262 return getLocations(Collections.singletonList(locationListing), encoding);
263 }
264
265 public static final List<String> getLocations(List<String> locationListings) {
266 return getLocations(locationListings, null);
267 }
268
269 public static final void copyLocationToFile(String location, File destination) {
270 Assert.notNull(location);
271 Assert.notNull(destination);
272 logger.debug("Copying [{}]->[{}]", location, destination);
273 InputStream in = null;
274 try {
275 in = getInputStream(location);
276 FileUtils.copyInputStreamToFile(in, destination);
277 } catch (IOException e) {
278 throw new IllegalStateException(e);
279 } finally {
280 IOUtils.closeQuietly(in);
281 }
282 }
283
284 public static final List<File> getFiles(File dir, List<String> filenames) {
285 List<File> files = new ArrayList<File>();
286 for (String filename : filenames) {
287 File file = new File(dir, filename);
288 files.add(file);
289 }
290 return files;
291 }
292
293 public static final List<String> getFilenames(List<String> locations) {
294 Assert.notNull(locations);
295 List<String> filenames = new ArrayList<String>();
296 for (String location : locations) {
297 filenames.add(getFilename(location));
298 }
299 return filenames;
300 }
301
302
303
304
305 public static final void validateLocationListing(String locationListing) {
306 validateLocationListings(Collections.singletonList(locationListing));
307 }
308
309
310
311
312 public static final void validateLocationListings(List<String> locationListings) {
313 for (String locationListing : locationListings) {
314 validateLocation(locationListing);
315 List<String> locations = getLocations(locationListing);
316 validateLocations(locations);
317 }
318 }
319
320 public static final void validateLocations(List<String> locations) {
321 for (String location : locations) {
322 validateLocation(location);
323 }
324 }
325
326
327
328
329 public static final void validateLocation(String location) {
330 Assert.isTrue(exists(location), "[" + location + "] does not exist");
331 }
332
333 public static final List<String> getLocations(List<String> locationListings, String encoding) {
334 List<String> locations = new ArrayList<String>();
335 for (String locationListing : locationListings) {
336 List<String> lines = readLines(locationListing, encoding);
337 locations.addAll(lines);
338 }
339 return locations;
340 }
341
342 public static final String getCanonicalURLString(File file) {
343 if (file == null) {
344 return null;
345 }
346 String path = getCanonicalPath(file);
347 File canonical = new File(path);
348 return getURLString(canonical);
349 }
350
351 public static final void validateNormalizedPath(String originalPath, String normalizedPath) {
352 if (CollectionUtils.containsAny(normalizedPath, Arrays.asList(SLASH_DOT_DOT, SLASH_DOT_SLASH, DOT_DOT_SLASH))) {
353 throw new IllegalArgumentException("[" + originalPath + "] could not be normalized. Normalized path [" + normalizedPath + "]");
354 }
355 }
356
357
358
359
360 public static final String getNormalizedAbsolutePath(String absolutePath) {
361 if (absolutePath == null) {
362 return null;
363 }
364 String replaced = StringUtils.replace(absolutePath, BACK_SLASH, FORWARD_SLASH);
365 boolean absolute = StringUtils.startsWith(replaced, FORWARD_SLASH);
366 if (!absolute) {
367 throw new IllegalArgumentException("[" + absolutePath + "] is not an absolute path.");
368 }
369 String prefixed = FILE_PREFIX + replaced;
370 try {
371 URI rawURI = new URI(prefixed);
372 URI normalizedURI = rawURI.normalize();
373 URL normalizedURL = normalizedURI.toURL();
374 String externalForm = normalizedURL.toExternalForm();
375 String trimmed = StringUtils.substring(externalForm, FILE_PREFIX.length());
376 validateNormalizedPath(absolutePath, trimmed);
377 return trimmed;
378 } catch (MalformedURLException e) {
379 throw new IllegalArgumentException(e);
380 } catch (URISyntaxException e) {
381 throw new IllegalArgumentException(e);
382 }
383 }
384
385 public static final String getURLString(File file) {
386 if (file == null) {
387 return null;
388 }
389 try {
390 URI uri = file.toURI();
391 URL url = uri.toURL();
392 return url.toExternalForm();
393 } catch (MalformedURLException e) {
394 throw new IllegalArgumentException(e);
395 }
396 }
397
398 public static final void forceMkdir(File file) {
399 try {
400 FileUtils.forceMkdir(file);
401 } catch (IOException e) {
402 throw new IllegalArgumentException("Unexpected IO error", e);
403 }
404 }
405
406 public static final void touch(File file) {
407 try {
408 FileUtils.touch(file);
409 } catch (IOException e) {
410 throw new IllegalArgumentException("Unexpected IO error", e);
411 }
412 }
413
414 public static final String getCanonicalPath(File file) {
415 try {
416 return file.getCanonicalPath();
417 } catch (IOException e) {
418 throw new IllegalArgumentException("Unexpected IO error", e);
419 }
420 }
421
422
423
424
425
426 public static final boolean deleteFileQuietly(String filename) {
427 File file = getFileQuietly(filename);
428 return FileUtils.deleteQuietly(file);
429 }
430
431
432
433
434 public static final File getFileQuietly(String filename) {
435 if (filename == null) {
436 return null;
437 } else {
438 return new File(filename);
439 }
440 }
441
442
443
444
445 public static final String toString(File file) {
446 return toString(file, null);
447 }
448
449
450
451
452 public static final String toString(File file, String encoding) {
453 return toString(getCanonicalPath(file), encoding);
454 }
455
456
457
458
459 public static final String toString(String location) {
460 return toString(location, null);
461 }
462
463
464
465
466 public static final String toString(String location, String encoding) {
467 InputStream in = null;
468 try {
469 in = getInputStream(location);
470 if (encoding == null) {
471 return IOUtils.toString(in);
472 } else {
473 return IOUtils.toString(in, encoding);
474 }
475 } catch (IOException e) {
476 throw new IllegalStateException("Unexpected IO error", e);
477 } finally {
478 IOUtils.closeQuietly(in);
479 }
480 }
481
482
483
484
485 public static final List<String> readLinesFromString(String s) {
486 Reader reader = getBufferedReaderFromString(s);
487 return readLinesAndClose(reader);
488 }
489
490 public static final List<String> readLinesAndClose(InputStream in) {
491 return readLinesAndClose(in, null);
492 }
493
494 public static final List<String> readLinesAndClose(InputStream in, String encoding) {
495 Reader reader = null;
496 try {
497 reader = getBufferedReader(in, encoding);
498 return readLinesAndClose(reader);
499 } catch (IOException e) {
500 throw new IllegalStateException("Unexpected IO error", e);
501 } finally {
502 IOUtils.closeQuietly(reader);
503 }
504 }
505
506 public static final List<String> readLinesAndClose(Reader reader) {
507 try {
508 return IOUtils.readLines(reader);
509 } catch (IOException e) {
510 throw new IllegalStateException("Unexpected IO error", e);
511 } finally {
512 IOUtils.closeQuietly(reader);
513 }
514 }
515
516
517
518
519 public static final List<String> readLines(File file) {
520 return readLines(getCanonicalPath(file));
521 }
522
523
524
525
526 public static final List<String> readLines(String location) {
527 return readLines(location, null);
528 }
529
530
531
532
533 public static final List<String> readLines(String location, String encoding) {
534 Reader reader = null;
535 try {
536 reader = getBufferedReader(location, encoding);
537 return readLinesAndClose(reader);
538 } catch (IOException e) {
539 throw new IllegalStateException("Unexpected IO error", e);
540 } finally {
541 IOUtils.closeQuietly(reader);
542 }
543 }
544
545
546
547
548 public static final BufferedReader getBufferedReader(String location) throws IOException {
549 return getBufferedReader(location, null);
550 }
551
552
553
554
555 public static final BufferedReader getBufferedReader(String location, String encoding) throws IOException {
556 try {
557 InputStream in = getInputStream(location);
558 return getBufferedReader(in, encoding);
559 } catch (IOException e) {
560 throw new IOException("Unexpected IO error", e);
561 }
562 }
563
564
565
566
567 public static final BufferedReader getBufferedReaderFromString(String s) {
568 return new BufferedReader(new StringReader(s));
569 }
570
571
572
573
574 public static final Writer getWriter(OutputStream out, String encoding) throws IOException {
575 if (encoding == null) {
576 return new BufferedWriter(new OutputStreamWriter(out));
577 } else {
578 return new BufferedWriter(new OutputStreamWriter(out, encoding));
579 }
580 }
581
582
583
584
585 public static final BufferedReader getBufferedReader(File file, String encoding) throws IOException {
586 return getBufferedReader(FileUtils.openInputStream(file), encoding);
587 }
588
589
590
591
592 public static final BufferedReader getBufferedReader(InputStream in, String encoding) throws IOException {
593 if (encoding == null) {
594 return new BufferedReader(new InputStreamReader(in));
595 } else {
596 return new BufferedReader(new InputStreamReader(in, encoding));
597 }
598 }
599
600
601
602
603 public static final boolean isExistingFile(String location) {
604 if (location == null) {
605 return false;
606 }
607 File file = new File(location);
608 return file.exists();
609 }
610
611
612
613
614 public static final boolean exists(File file) {
615 if (file == null) {
616 return false;
617 }
618 String location = getCanonicalPath(file);
619 if (isExistingFile(location)) {
620 return true;
621 } else {
622 Resource resource = getResource(location);
623 return resource.exists();
624 }
625 }
626
627
628
629
630 public static final boolean exists(String location) {
631 if (location == null) {
632 return false;
633 }
634 if (isExistingFile(location)) {
635 return true;
636 } else {
637 Resource resource = getResource(location);
638 return resource.exists();
639 }
640 }
641
642
643
644
645
646 public static final InputStream getInputStream(String location) throws IOException {
647 if (isExistingFile(location)) {
648 return FileUtils.openInputStream(new File(location));
649 }
650 Resource resource = getResource(location);
651 return resource.getInputStream();
652 }
653
654 public static final Resource getResource(String location) {
655 if (location == null) {
656 return null;
657 }
658 ResourceLoader loader = new DefaultResourceLoader();
659 return loader.getResource(location);
660 }
661
662 public static final String getFilename(String location) {
663 if (location == null) {
664 return null;
665 }
666 if (isExistingFile(location)) {
667 return getFileQuietly(location).getName();
668 } else {
669 Resource resource = getResource(location);
670 return resource.getFilename();
671 }
672 }
673
674 public static final List<String> getAbsolutePaths(List<File> files) {
675 List<String> results = new ArrayList<String>(files.size());
676
677 for (File f : files) {
678 results.add(f.getAbsolutePath());
679 }
680
681 return results;
682 }
683
684 public static final ComparisonResults getLocationListComparison(List<String> newLocations, List<String> originalLocations) {
685 ComparisonResults result = new ComparisonResults();
686
687 result.setAdded(new ArrayList<String>());
688 result.setSame(new ArrayList<String>());
689 result.setDeleted(new ArrayList<String>());
690
691 for (String newLocation : newLocations) {
692 if (originalLocations.contains(newLocation)) {
693
694 result.getSame().add(newLocation);
695 } else {
696
697 result.getAdded().add(newLocation);
698 }
699 }
700
701
702 result.getDeleted().addAll(originalLocations);
703 result.getDeleted().removeAll(newLocations);
704
705 return result;
706 }
707
708 public static String getChecksum(String location, String algorithm) {
709 byte[] b = createChecksum(location, algorithm);
710 StringBuilder sb = new StringBuilder();
711 for (int i = 0; i < b.length; i++) {
712 sb.append(Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1));
713 }
714 return sb.toString();
715 }
716
717 public static byte[] createChecksum(String location, String algorithm) {
718
719 InputStream in = null;
720 try {
721
722
723 in = LocationUtils.getInputStream(location);
724
725 byte[] buffer = new byte[1024];
726 MessageDigest complete = MessageDigest.getInstance(algorithm);
727 int numRead;
728 do {
729 numRead = in.read(buffer);
730 if (numRead > 0) {
731 complete.update(buffer, 0, numRead);
732 }
733 } while (numRead != -1);
734 IOUtils.closeQuietly(in);
735 return complete.digest();
736 } catch (NoSuchAlgorithmException e) {
737 throw new IllegalStateException("Unexpected message digest error", e);
738 } catch (IOException e) {
739 throw new IllegalStateException("Unexpected IO error", e);
740 } finally {
741 IOUtils.closeQuietly(in);
742 }
743 }
744
745 }