View Javadoc
1   /**
2    * Copyright 2010-2012 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.IOException;
22  import java.io.InputStream;
23  import java.io.InputStreamReader;
24  import java.io.OutputStream;
25  import java.io.OutputStreamWriter;
26  import java.io.Reader;
27  import java.io.StringReader;
28  import java.io.Writer;
29  import java.net.MalformedURLException;
30  import java.net.URI;
31  import java.net.URISyntaxException;
32  import java.net.URL;
33  import java.util.ArrayList;
34  import java.util.Collections;
35  import java.util.List;
36  
37  import org.apache.commons.io.FileUtils;
38  import org.apache.commons.io.IOUtils;
39  import org.apache.commons.lang3.StringUtils;
40  import org.springframework.core.io.DefaultResourceLoader;
41  import org.springframework.core.io.Resource;
42  import org.springframework.core.io.ResourceLoader;
43  
44  public class LocationUtils {
45  
46  	private static final String FILE_PREFIX = "file:";
47  	private static final String BACK_SLASH = "\\";
48  	private static final String FORWARD_SLASH = "/";
49  	private static final String SLASH_DOT = "/.";
50  	private static final String DOT_SLASH = "./";
51  
52  	public static final List<String> getNormalizedPathFragments(String absolutePath, boolean directory) {
53  		String normalized = getNormalizedAbsolutePath(absolutePath);
54  		String[] tokens = StringUtils.split(normalized, FORWARD_SLASH);
55  		List<String> fragments = new ArrayList<String>();
56  		StringBuilder sb = new StringBuilder();
57  		sb.append(FORWARD_SLASH);
58  		int length = directory ? tokens.length : tokens.length - 1;
59  		for (int i = 0; i < length; i++) {
60  			if (i != 0) {
61  				sb.append(FORWARD_SLASH);
62  			}
63  			sb.append(tokens[i]);
64  			fragments.add(sb.toString());
65  		}
66  		return fragments;
67  	}
68  
69  	public static final List<String> getLocations(String location, LocationType type, String encoding) {
70  		switch (type) {
71  		case LOCATION:
72  			return Collections.singletonList(location);
73  		case LOCATIONLIST:
74  			return getLocations(location, encoding);
75  		default:
76  			throw new IllegalArgumentException("Location type '" + type + "' is unknown");
77  		}
78  	}
79  
80  	public static final List<String> getLocations(String location, LocationType type) {
81  		return getLocations(location, type, null);
82  	}
83  
84  	public static final List<String> getLocations(String locationListing) {
85  		return getLocations(Collections.singletonList(locationListing), null);
86  	}
87  
88  	public static final List<String> getLocations(String locationListing, String encoding) {
89  		return getLocations(Collections.singletonList(locationListing), encoding);
90  	}
91  
92  	public static final List<String> getLocations(List<String> locationListings) {
93  		return getLocations(locationListings, null);
94  	}
95  
96  	public static final List<String> getLocations(List<String> locationListings, String encoding) {
97  		List<String> locations = new ArrayList<String>();
98  		for (String locationListing : locationListings) {
99  			List<String> lines = readLines(locationListing, encoding);
100 			locations.addAll(lines);
101 		}
102 		return locations;
103 	}
104 
105 	public static final String getCanonicalURLString(File file) {
106 		if (file == null) {
107 			return null;
108 		}
109 		String path = getCanonicalPath(file);
110 		File canonical = new File(path);
111 		return getURLString(canonical);
112 	}
113 
114 	public static final void validateNormalizedPath(String originalPath, String normalizedPath) {
115 		if (StringUtils.contains(normalizedPath, SLASH_DOT)) {
116 			throw new IllegalArgumentException("[" + originalPath + "] could not be normalized. Normalized path [" + normalizedPath + "]");
117 		}
118 		if (StringUtils.contains(normalizedPath, DOT_SLASH)) {
119 			throw new IllegalArgumentException("[" + originalPath + "] could not be normalized. Normalized path [" + normalizedPath + "]");
120 		}
121 	}
122 
123 	/**
124 	 * Resolve and remove <code>..</code> and <code>.</code> from <code>absolutePath</code> after converting any back slashes to forward
125 	 * slashes
126 	 */
127 	public static final String getNormalizedAbsolutePath(String absolutePath) {
128 		if (absolutePath == null) {
129 			return null;
130 		}
131 		String replaced = StringUtils.replace(absolutePath, BACK_SLASH, FORWARD_SLASH);
132 		boolean absolute = StringUtils.startsWith(replaced, FORWARD_SLASH);
133 		if (!absolute) {
134 			throw new IllegalArgumentException("[" + absolutePath + "] is not an absolute path.");
135 		}
136 		String prefixed = FILE_PREFIX + replaced;
137 		try {
138 			URI rawURI = new URI(prefixed);
139 			URI normalizedURI = rawURI.normalize();
140 			URL normalizedURL = normalizedURI.toURL();
141 			String externalForm = normalizedURL.toExternalForm();
142 			String trimmed = StringUtils.substring(externalForm, FILE_PREFIX.length());
143 			validateNormalizedPath(absolutePath, trimmed);
144 			return trimmed;
145 		} catch (MalformedURLException e) {
146 			throw new IllegalArgumentException(e);
147 		} catch (URISyntaxException e) {
148 			throw new IllegalArgumentException(e);
149 		}
150 	}
151 
152 	public static final String getURLString(File file) {
153 		if (file == null) {
154 			return null;
155 		}
156 		try {
157 			URI uri = file.toURI();
158 			URL url = uri.toURL();
159 			return url.toExternalForm();
160 		} catch (MalformedURLException e) {
161 			throw new IllegalArgumentException(e);
162 		}
163 	}
164 
165 	public static final void forceMkdir(File file) {
166 		try {
167 			FileUtils.forceMkdir(file);
168 		} catch (IOException e) {
169 			throw new IllegalArgumentException("Unexpected IO error", e);
170 		}
171 	}
172 
173 	public static final void touch(File file) {
174 		try {
175 			FileUtils.touch(file);
176 		} catch (IOException e) {
177 			throw new IllegalArgumentException("Unexpected IO error", e);
178 		}
179 	}
180 
181 	public static final String getCanonicalPath(File file) {
182 		try {
183 			return file.getCanonicalPath();
184 		} catch (IOException e) {
185 			throw new IllegalArgumentException("Unexpected IO error", e);
186 		}
187 	}
188 
189 	/**
190 	 * Null safe method to unconditionally attempt to delete <code>filename</code> without throwing an exception. If <code>filename</code>
191 	 * is a directory, delete it and all sub-directories.
192 	 */
193 	public static final boolean deleteFileQuietly(String filename) {
194 		File file = getFileQuietly(filename);
195 		return FileUtils.deleteQuietly(file);
196 	}
197 
198 	/**
199 	 * Null safe method for getting a <code>File</code> handle from <code>filename</code>. If <code>filename</code> is null, null is
200 	 * returned.
201 	 */
202 	public static final File getFileQuietly(String filename) {
203 		if (filename == null) {
204 			return null;
205 		} else {
206 			return new File(filename);
207 		}
208 	}
209 
210 	/**
211 	 * Get the contents of <code>location</code> as a <code>String</code> using the platform's default character encoding.
212 	 */
213 	public static final String toString(String location) {
214 		return toString(location, null);
215 	}
216 
217 	/**
218 	 * Get the contents of <code>location</code> as a <code>String</code> using the specified character encoding.
219 	 */
220 	public static final String toString(String location, String encoding) {
221 		InputStream in = null;
222 		try {
223 			in = getInputStream(location);
224 			if (encoding == null) {
225 				return IOUtils.toString(in);
226 			} else {
227 				return IOUtils.toString(in, encoding);
228 			}
229 		} catch (IOException e) {
230 			throw new IllegalStateException("Unexpected IO error", e);
231 		} finally {
232 			IOUtils.closeQuietly(in);
233 		}
234 	}
235 
236 	/**
237 	 * Get the contents of <code>s</code> as a list of <code>String's</code> one entry per line
238 	 */
239 	public static final List<String> readLinesFromString(String s) {
240 		Reader reader = getBufferedReaderFromString(s);
241 		return readLinesAndClose(reader);
242 	}
243 
244 	public static final List<String> readLinesAndClose(InputStream in) {
245 		return readLinesAndClose(in, null);
246 	}
247 
248 	public static final List<String> readLinesAndClose(InputStream in, String encoding) {
249 		Reader reader = null;
250 		try {
251 			reader = getBufferedReader(in, encoding);
252 			return readLinesAndClose(reader);
253 		} catch (IOException e) {
254 			throw new IllegalStateException("Unexpected IO error", e);
255 		} finally {
256 			IOUtils.closeQuietly(reader);
257 		}
258 	}
259 
260 	public static final List<String> readLinesAndClose(Reader reader) {
261 		try {
262 			return IOUtils.readLines(reader);
263 		} catch (IOException e) {
264 			throw new IllegalStateException("Unexpected IO error", e);
265 		} finally {
266 			IOUtils.closeQuietly(reader);
267 		}
268 	}
269 
270 	/**
271 	 * Get the contents of <code>file</code> as a list of <code>String's</code> one entry per line using the platform default encoding
272 	 */
273 	public static final List<String> readLines(File file) {
274 		return readLines(getCanonicalPath(file));
275 	}
276 
277 	/**
278 	 * Get the contents of <code>location</code> as a list of <code>String's</code> one entry per line using the platform default encoding
279 	 */
280 	public static final List<String> readLines(String location) {
281 		return readLines(location, null);
282 	}
283 
284 	/**
285 	 * Get the contents of <code>location</code> as a list of <code>String's</code> one entry per line using the encoding indicated.
286 	 */
287 	public static final List<String> readLines(String location, String encoding) {
288 		Reader reader = null;
289 		try {
290 			reader = getBufferedReader(location, encoding);
291 			return readLinesAndClose(reader);
292 		} catch (IOException e) {
293 			throw new IllegalStateException("Unexpected IO error", e);
294 		} finally {
295 			IOUtils.closeQuietly(reader);
296 		}
297 	}
298 
299 	/**
300 	 * Return a <code>BufferedReader</code> for the location indicated using the platform default encoding.
301 	 */
302 	public static final BufferedReader getBufferedReader(String location) throws IOException {
303 		return getBufferedReader(location, null);
304 	}
305 
306 	/**
307 	 * Return a <code>BufferedReader</code> for the location indicated using the encoding indicated.
308 	 */
309 	public static final BufferedReader getBufferedReader(String location, String encoding) throws IOException {
310 		try {
311 			InputStream in = getInputStream(location);
312 			return getBufferedReader(in, encoding);
313 		} catch (IOException e) {
314 			throw new IOException("Unexpected IO error", e);
315 		}
316 	}
317 
318 	/**
319 	 * Return a <code>BufferedReader</code> that reads from <code>s</code>
320 	 */
321 	public static final BufferedReader getBufferedReaderFromString(String s) {
322 		return new BufferedReader(new StringReader(s));
323 	}
324 
325 	/**
326 	 * Return a <code>Writer</code> that writes to <code>out</code> using the indicated encoding. <code>null</code> means use the platform's
327 	 * default encoding.
328 	 */
329 	public static final Writer getWriter(OutputStream out, String encoding) throws IOException {
330 		if (encoding == null) {
331 			return new BufferedWriter(new OutputStreamWriter(out));
332 		} else {
333 			return new BufferedWriter(new OutputStreamWriter(out, encoding));
334 		}
335 	}
336 
337 	/**
338 	 * Return a <code>BufferedReader</code> that reads from <code>file</code> using the indicated encoding. <code>null</code> means use the
339 	 * platform's default encoding.
340 	 */
341 	public static final BufferedReader getBufferedReader(File file, String encoding) throws IOException {
342 		return getBufferedReader(FileUtils.openInputStream(file), encoding);
343 	}
344 
345 	/**
346 	 * Return a <code>BufferedReader</code> that reads from <code>in</code> using the indicated encoding. <code>null</code> means use the
347 	 * platform's default encoding.
348 	 */
349 	public static final BufferedReader getBufferedReader(InputStream in, String encoding) throws IOException {
350 		if (encoding == null) {
351 			return new BufferedReader(new InputStreamReader(in));
352 		} else {
353 			return new BufferedReader(new InputStreamReader(in, encoding));
354 		}
355 	}
356 
357 	/**
358 	 * Null safe method for determining if <code>location</code> is an existing file.
359 	 */
360 	public static final boolean isExistingFile(String location) {
361 		if (location == null) {
362 			return false;
363 		}
364 		File file = new File(location);
365 		return file.exists();
366 	}
367 
368 	/**
369 	 * Null safe method for determining if <code>location</code> exists.
370 	 */
371 	public static final boolean exists(String location) {
372 		if (location == null) {
373 			return false;
374 		}
375 		if (isExistingFile(location)) {
376 			return true;
377 		} else {
378 			Resource resource = getResource(location);
379 			return resource.exists();
380 		}
381 	}
382 
383 	/**
384 	 * Open an <code>InputStream</code> to <code>location</code>. If <code>location</code> is the path to an existing <code>File</code> on
385 	 * the local file system, a <code>FileInputStream</code> is returned. Otherwise Spring's resource loading framework is used to open an
386 	 * <code>InputStream</code> to <code>location</code>.
387 	 */
388 	public static final InputStream getInputStream(String location) throws IOException {
389 		if (isExistingFile(location)) {
390 			return FileUtils.openInputStream(new File(location));
391 		}
392 		Resource resource = getResource(location);
393 		return resource.getInputStream();
394 	}
395 
396 	public static final Resource getResource(String location) {
397 		if (location == null) {
398 			return null;
399 		}
400 		ResourceLoader loader = new DefaultResourceLoader();
401 		return loader.getResource(location);
402 	}
403 
404 	public static final String getFilename(String location) {
405 		if (location == null) {
406 			return null;
407 		}
408 		if (isExistingFile(location)) {
409 			return getFileQuietly(location).getName();
410 		} else {
411 			Resource resource = getResource(location);
412 			return resource.getFilename();
413 		}
414 	}
415 
416 }