001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.util;
018:
019: import java.io.File;
020: import java.io.FileNotFoundException;
021: import java.net.MalformedURLException;
022: import java.net.URI;
023: import java.net.URISyntaxException;
024: import java.net.URL;
025:
026: /**
027: * Utility methods for resolving resource locations to files in the
028: * file system. Mainly for internal use within the framework.
029: *
030: * <p>Consider using Spring's Resource abstraction in the core package
031: * for handling all kinds of file resources in a uniform manner.
032: * {@link org.springframework.core.io.ResourceLoader}'s <code>getResource</code>
033: * method can resolve any location to a {@link org.springframework.core.io.Resource}
034: * object, which in turn allows to obtain a <code>java.io.File</code> in the
035: * file system through its <code>getFile()</code> method.
036: *
037: * <p>The main reason for these utility methods for resource location handling
038: * is to support {@link Log4jConfigurer}, which must be able to resolve
039: * resource locations <i>before the logging system has been initialized</i>.
040: * Spring' Resource abstraction in the core package, on the other hand,
041: * already expects the logging system to be available.
042: *
043: * @author Juergen Hoeller
044: * @since 1.1.5
045: * @see org.springframework.core.io.Resource
046: * @see org.springframework.core.io.ClassPathResource
047: * @see org.springframework.core.io.FileSystemResource
048: * @see org.springframework.core.io.UrlResource
049: * @see org.springframework.core.io.ResourceLoader
050: */
051: public abstract class ResourceUtils {
052:
053: /** Pseudo URL prefix for loading from the class path: "classpath:" */
054: public static final String CLASSPATH_URL_PREFIX = "classpath:";
055:
056: /** URL prefix for loading from the file system: "file:" */
057: public static final String FILE_URL_PREFIX = "file:";
058:
059: /** URL protocol for a file in the file system: "file" */
060: public static final String URL_PROTOCOL_FILE = "file";
061:
062: /** URL protocol for an entry from a jar file: "jar" */
063: public static final String URL_PROTOCOL_JAR = "jar";
064:
065: /** URL protocol for an entry from a zip file: "zip" */
066: public static final String URL_PROTOCOL_ZIP = "zip";
067:
068: /** URL protocol for an entry from a WebSphere jar file: "wsjar" */
069: public static final String URL_PROTOCOL_WSJAR = "wsjar";
070:
071: /** URL protocol for an entry from an OC4J jar file: "code-source" */
072: public static final String URL_PROTOCOL_CODE_SOURCE = "code-source";
073:
074: /** Separator between JAR URL and file path within the JAR */
075: public static final String JAR_URL_SEPARATOR = "!/";
076:
077: /**
078: * Return whether the given resource location is a URL:
079: * either a special "classpath" pseudo URL or a standard URL.
080: * @param resourceLocation the location String to check
081: * @return whether the location qualifies as a URL
082: * @see #CLASSPATH_URL_PREFIX
083: * @see java.net.URL
084: */
085: public static boolean isUrl(String resourceLocation) {
086: if (resourceLocation == null) {
087: return false;
088: }
089: if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
090: return true;
091: }
092: try {
093: new URL(resourceLocation);
094: return true;
095: } catch (MalformedURLException ex) {
096: return false;
097: }
098: }
099:
100: /**
101: * Resolve the given resource location to a <code>java.net.URL</code>.
102: * <p>Does not check whether the URL actually exists; simply returns
103: * the URL that the given location would correspond to.
104: * @param resourceLocation the resource location to resolve: either a
105: * "classpath:" pseudo URL, a "file:" URL, or a plain file path
106: * @return a corresponding URL object
107: * @throws FileNotFoundException if the resource cannot be resolved to a URL
108: */
109: public static URL getURL(String resourceLocation)
110: throws FileNotFoundException {
111: Assert.notNull(resourceLocation,
112: "Resource location must not be null");
113: if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
114: String path = resourceLocation
115: .substring(CLASSPATH_URL_PREFIX.length());
116: URL url = ClassUtils.getDefaultClassLoader().getResource(
117: path);
118: if (url == null) {
119: String description = "class path resource [" + path
120: + "]";
121: throw new FileNotFoundException(
122: description
123: + " cannot be resolved to URL because it does not exist");
124: }
125: return url;
126: }
127: try {
128: // try URL
129: return new URL(resourceLocation);
130: } catch (MalformedURLException ex) {
131: // no URL -> treat as file path
132: try {
133: return new File(resourceLocation).toURI().toURL();
134: } catch (MalformedURLException ex2) {
135: throw new FileNotFoundException(
136: "Resource location ["
137: + resourceLocation
138: + "] is neither a URL not a well-formed file path");
139: }
140: }
141: }
142:
143: /**
144: * Resolve the given resource location to a <code>java.io.File</code>,
145: * i.e. to a file in the file system.
146: * <p>Does not check whether the fil actually exists; simply returns
147: * the File that the given location would correspond to.
148: * @param resourceLocation the resource location to resolve: either a
149: * "classpath:" pseudo URL, a "file:" URL, or a plain file path
150: * @return a corresponding File object
151: * @throws FileNotFoundException if the resource cannot be resolved to
152: * a file in the file system
153: */
154: public static File getFile(String resourceLocation)
155: throws FileNotFoundException {
156: Assert.notNull(resourceLocation,
157: "Resource location must not be null");
158: if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
159: String path = resourceLocation
160: .substring(CLASSPATH_URL_PREFIX.length());
161: String description = "class path resource [" + path + "]";
162: URL url = ClassUtils.getDefaultClassLoader().getResource(
163: path);
164: if (url == null) {
165: throw new FileNotFoundException(
166: description
167: + " cannot be resolved to absolute file path "
168: + "because it does not reside in the file system");
169: }
170: return getFile(url, description);
171: }
172: try {
173: // try URL
174: return getFile(new URL(resourceLocation));
175: } catch (MalformedURLException ex) {
176: // no URL -> treat as file path
177: return new File(resourceLocation);
178: }
179: }
180:
181: /**
182: * Resolve the given resource URL to a <code>java.io.File</code>,
183: * i.e. to a file in the file system.
184: * @param resourceUrl the resource URL to resolve
185: * @return a corresponding File object
186: * @throws FileNotFoundException if the URL cannot be resolved to
187: * a file in the file system
188: */
189: public static File getFile(URL resourceUrl)
190: throws FileNotFoundException {
191: return getFile(resourceUrl, "URL");
192: }
193:
194: /**
195: * Resolve the given resource URL to a <code>java.io.File</code>,
196: * i.e. to a file in the file system.
197: * @param resourceUrl the resource URL to resolve
198: * @param description a description of the original resource that
199: * the URL was created for (for example, a class path location)
200: * @return a corresponding File object
201: * @throws FileNotFoundException if the URL cannot be resolved to
202: * a file in the file system
203: */
204: public static File getFile(URL resourceUrl, String description)
205: throws FileNotFoundException {
206: Assert.notNull(resourceUrl, "Resource URL must not be null");
207: if (!URL_PROTOCOL_FILE.equals(resourceUrl.getProtocol())) {
208: throw new FileNotFoundException(description
209: + " cannot be resolved to absolute file path "
210: + "because it does not reside in the file system: "
211: + resourceUrl);
212: }
213: try {
214: return new File(toURI(resourceUrl).getSchemeSpecificPart());
215: } catch (URISyntaxException ex) {
216: // Fallback for URLs that are not valid URIs (should hardly ever happen).
217: return new File(resourceUrl.getFile());
218: }
219: }
220:
221: /**
222: * Resolve the given resource URI to a <code>java.io.File</code>,
223: * i.e. to a file in the file system.
224: * @param resourceUri the resource URI to resolve
225: * @return a corresponding File object
226: * @throws FileNotFoundException if the URL cannot be resolved to
227: * a file in the file system
228: */
229: public static File getFile(URI resourceUri)
230: throws FileNotFoundException {
231: return getFile(resourceUri, "URI");
232: }
233:
234: /**
235: * Resolve the given resource URI to a <code>java.io.File</code>,
236: * i.e. to a file in the file system.
237: * @param resourceUri the resource URI to resolve
238: * @param description a description of the original resource that
239: * the URI was created for (for example, a class path location)
240: * @return a corresponding File object
241: * @throws FileNotFoundException if the URL cannot be resolved to
242: * a file in the file system
243: */
244: public static File getFile(URI resourceUri, String description)
245: throws FileNotFoundException {
246: Assert.notNull(resourceUri, "Resource URI must not be null");
247: if (!URL_PROTOCOL_FILE.equals(resourceUri.getScheme())) {
248: throw new FileNotFoundException(description
249: + " cannot be resolved to absolute file path "
250: + "because it does not reside in the file system: "
251: + resourceUri);
252: }
253: return new File(resourceUri.getSchemeSpecificPart());
254: }
255:
256: /**
257: * Determine whether the given URL points to a resource in a jar file,
258: * that is, has protocol "jar", "zip", "wsjar" or "code-source".
259: * <p>"zip" and "wsjar" are used by BEA WebLogic Server and IBM WebSphere, respectively,
260: * but can be treated like jar files. The same applies to "code-source" URLs on Oracle
261: * OC4J, provided that the path contains a jar separator.
262: * @param url the URL to check
263: * @return whether the URL has been identified as a JAR URL
264: */
265: public static boolean isJarURL(URL url) {
266: String protocol = url.getProtocol();
267: return (URL_PROTOCOL_JAR.equals(protocol)
268: || URL_PROTOCOL_ZIP.equals(protocol)
269: || URL_PROTOCOL_WSJAR.equals(protocol) || (URL_PROTOCOL_CODE_SOURCE
270: .equals(protocol) && url.getPath().indexOf(
271: JAR_URL_SEPARATOR) != -1));
272: }
273:
274: /**
275: * Extract the URL for the actual jar file from the given URL
276: * (which may point to a resource in a jar file or to a jar file itself).
277: * @param jarUrl the original URL
278: * @return the URL for the actual jar file
279: * @throws MalformedURLException if no valid jar file URL could be extracted
280: */
281: public static URL extractJarFileURL(URL jarUrl)
282: throws MalformedURLException {
283: String urlFile = jarUrl.getFile();
284: int separatorIndex = urlFile.indexOf(JAR_URL_SEPARATOR);
285: if (separatorIndex != -1) {
286: String jarFile = urlFile.substring(0, separatorIndex);
287: try {
288: return new URL(jarFile);
289: } catch (MalformedURLException ex) {
290: // Probably no protocol in original jar URL, like "jar:C:/mypath/myjar.jar".
291: // This usually indicates that the jar file resides in the file system.
292: if (!jarFile.startsWith("/")) {
293: jarFile = "/" + jarFile;
294: }
295: return new URL(FILE_URL_PREFIX + jarFile);
296: }
297: } else {
298: return jarUrl;
299: }
300: }
301:
302: /**
303: * Create a URI instance for the given URL, replacing spaces with
304: * "%20" quotes first.
305: * <p>Furthermore, this method works on JDK 1.4 as well,
306: * in contrast to the <code>URL.toURI()</code> method.
307: * @param url the URL to convert into a URI instance
308: * @return the URI instance
309: * @throws URISyntaxException if the URL wasn't a valid URI
310: * @see java.net.URL#toURI()
311: */
312: public static URI toURI(URL url) throws URISyntaxException {
313: return new URI(StringUtils.replace(url.toString(), " ", "%20"));
314: }
315:
316: }
|