View Javadoc

1   /**
2    * Copyright 2010-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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  	 * Get the MD5 checksum of the location
68  	 */
69  	public static String getMD5Checksum(String location) {
70  		return getChecksum(location, MD5);
71  	}
72  
73  	/**
74  	 * Get the MD5 checksum of the file
75  	 */
76  	public static String getMD5Checksum(File file) {
77  		return getChecksum(getCanonicalPath(file), MD5);
78  	}
79  
80  	/**
81  	 * Open a <code>PrintStream</code> to the indicated file. Parent directories are created if necessary.
82  	 */
83  	public static final PrintStream openPrintStream(File file) throws IOException {
84  		return new PrintStream(FileUtils.openOutputStream(file));
85  	}
86  
87  	/**
88  	 * Open a <code>Writer</code> to the indicated file. Parent directories are created if necessary.
89  	 */
90  	public static final Writer openWriter(File file) throws IOException {
91  		touch(file);
92  		return new FileWriter(file);
93  	}
94  
95  	/**
96  	 * Open a <code>Writer</code> to the <code>location</code> (It must be a writable file on the local file system). Parent directories are created if necessary.
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 	 * Return the text that appears after <code>classpath:</code>. Throws <code>IllegalArgumentException</code> if location does not start with <code>classpath:</code>
189 	 */
190 	public static final String getClasspathFilename(String location) {
191 		return getClasspathFilenames(Arrays.asList(location)).get(0);
192 	}
193 
194 	/**
195 	 * Return the text that appears after <code>classpath:</code>. Throws <code>IllegalArgumentException</code> if any locations do not start with <code>classpath:</code>
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 	 * Return <code>true</code> if location starts with <code>classpath:</code>
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 	 * Throw IllegalArgumentException if the locationListing does not exist, or if any of the locations inside the locationListing do not exist
304 	 */
305 	public static final void validateLocationListing(String locationListing) {
306 		validateLocationListings(Collections.singletonList(locationListing));
307 	}
308 
309 	/**
310 	 * Throw IllegalArgumentException if any of the locationListings do not exist, or if any of the locations inside any of the locationListings do not exist
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 	 * Throw IllegalArgumentException if the location does not exist
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 	 * Resolve and remove <code>..</code> and <code>.</code> from <code>absolutePath</code> after converting any back slashes to forward slashes
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 	 * Null safe method to unconditionally attempt to delete <code>filename</code> without throwing an exception. If <code>filename</code> is a directory, delete it and all
424 	 * sub-directories.
425 	 */
426 	public static final boolean deleteFileQuietly(String filename) {
427 		File file = getFileQuietly(filename);
428 		return FileUtils.deleteQuietly(file);
429 	}
430 
431 	/**
432 	 * Null safe method for getting a <code>File</code> handle from <code>filename</code>. If <code>filename</code> is null, null is returned.
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 	 * Get the contents of <code>file</code> as a <code>String</code> using the platform's default character encoding.
444 	 */
445 	public static final String toString(File file) {
446 		return toString(file, null);
447 	}
448 
449 	/**
450 	 * Get the contents of <code>file</code> as a <code>String</code> using the specified character encoding.
451 	 */
452 	public static final String toString(File file, String encoding) {
453 		return toString(getCanonicalPath(file), encoding);
454 	}
455 
456 	/**
457 	 * Get the contents of <code>location</code> as a <code>String</code> using the platform's default character encoding.
458 	 */
459 	public static final String toString(String location) {
460 		return toString(location, null);
461 	}
462 
463 	/**
464 	 * Get the contents of <code>location</code> as a <code>String</code> using the specified character encoding.
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 	 * Get the contents of <code>s</code> as a list of <code>String's</code> one entry per line
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 	 * Get the contents of <code>file</code> as a list of <code>String's</code> one entry per line using the platform default encoding
518 	 */
519 	public static final List<String> readLines(File file) {
520 		return readLines(getCanonicalPath(file));
521 	}
522 
523 	/**
524 	 * Get the contents of <code>location</code> as a list of <code>String's</code> one entry per line using the platform default encoding
525 	 */
526 	public static final List<String> readLines(String location) {
527 		return readLines(location, null);
528 	}
529 
530 	/**
531 	 * Get the contents of <code>location</code> as a list of <code>String's</code> one entry per line using the encoding indicated.
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 	 * Return a <code>BufferedReader</code> for the location indicated using the platform default encoding.
547 	 */
548 	public static final BufferedReader getBufferedReader(String location) throws IOException {
549 		return getBufferedReader(location, null);
550 	}
551 
552 	/**
553 	 * Return a <code>BufferedReader</code> for the location indicated using the encoding indicated.
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 	 * Return a <code>BufferedReader</code> that reads from <code>s</code>
566 	 */
567 	public static final BufferedReader getBufferedReaderFromString(String s) {
568 		return new BufferedReader(new StringReader(s));
569 	}
570 
571 	/**
572 	 * Return a <code>Writer</code> that writes to <code>out</code> using the indicated encoding. <code>null</code> means use the platform's default encoding.
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 	 * Return a <code>BufferedReader</code> that reads from <code>file</code> using the indicated encoding. <code>null</code> means use the platform's default encoding.
584 	 */
585 	public static final BufferedReader getBufferedReader(File file, String encoding) throws IOException {
586 		return getBufferedReader(FileUtils.openInputStream(file), encoding);
587 	}
588 
589 	/**
590 	 * Return a <code>BufferedReader</code> that reads from <code>in</code> using the indicated encoding. <code>null</code> means use the platform's default encoding.
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 	 * Null safe method for determining if <code>location</code> is an existing file.
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 	 * Null safe method for determining if <code>location</code> exists.
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 	 * Null safe method for determining if <code>location</code> exists.
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 	 * Open an <code>InputStream</code> to <code>location</code>. If <code>location</code> is the path to an existing <code>File</code> on the local file system, a
644 	 * <code>FileInputStream</code> is returned. Otherwise Spring's resource loading framework is used to open an <code>InputStream</code> to <code>location</code>.
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 				// if a location is in both lists, add it to the "same" list
694 				result.getSame().add(newLocation);
695 			} else {
696 				// if a location is only in the new list, add it to the "added" list
697 				result.getAdded().add(newLocation);
698 			}
699 		}
700 
701 		// the "deleted" list will contain all locations from the original list that are NOT in the new list
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 			// Open an input stream
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 }