View Javadoc

1   /*
2    * Copyright 2002-2012 the original author or authors.
3    *
4    * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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  
17  package org.springframework.core.io;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.net.HttpURLConnection;
23  import java.net.MalformedURLException;
24  import java.net.URI;
25  import java.net.URL;
26  import java.net.URLConnection;
27  
28  import org.springframework.util.Assert;
29  import org.springframework.util.ResourceUtils;
30  import org.springframework.util.StringUtils;
31  
32  /**
33   * {@link Resource} implementation for <code>java.net.URL</code> locators.
34   * Obviously supports resolution as URL, and also as File in case of
35   * the "file:" protocol.
36   *
37   * @author Juergen Hoeller
38   * @since 28.12.2003
39   * @see java.net.URL
40   */
41  public class UrlResource extends AbstractFileResolvingResource {
42  
43  	/**
44  	 * Original URL, used for actual access.
45  	 */
46  	private final URL url;
47  
48  	/**
49  	 * Cleaned URL (with normalized path), used for comparisons.
50  	 */
51  	private final URL cleanedUrl;
52  
53  	/**
54  	 * Original URI, if available; used for URI and File access.
55  	 */
56  	private final URI uri;
57  
58  
59  	/**
60  	 * Create a new UrlResource.
61  	 * @param url a URL
62  	 */
63  	public UrlResource(URL url) {
64  		Assert.notNull(url, "URL must not be null");
65  		this.url = url;
66  		this.cleanedUrl = getCleanedUrl(this.url, url.toString());
67  		this.uri = null;
68  	}
69  
70  	/**
71  	 * Create a new UrlResource.
72  	 * @param uri a URI
73  	 * @throws MalformedURLException if the given URL path is not valid
74  	 */
75  	public UrlResource(URI uri) throws MalformedURLException {
76  		Assert.notNull(uri, "URI must not be null");
77  		this.url = uri.toURL();
78  		this.cleanedUrl = getCleanedUrl(this.url, uri.toString());
79  		this.uri = uri;
80  	}
81  
82  	/**
83  	 * Create a new UrlResource.
84  	 * @param path a URL path
85  	 * @throws MalformedURLException if the given URL path is not valid
86  	 */
87  	public UrlResource(String path) throws MalformedURLException {
88  		Assert.notNull(path, "Path must not be null");
89  		this.url = new URL(path);
90  		this.cleanedUrl = getCleanedUrl(this.url, path);
91  		this.uri = null;
92  	}
93  
94  	/**
95  	 * Determine a cleaned URL for the given original URL.
96  	 * @param originalUrl the original URL
97  	 * @param originalPath the original URL path
98  	 * @return the cleaned URL
99  	 * @see org.springframework.util.StringUtils#cleanPath
100 	 */
101 	private URL getCleanedUrl(URL originalUrl, String originalPath) {
102 		try {
103 			return new URL(StringUtils.cleanPath(originalPath));
104 		}
105 		catch (MalformedURLException ex) {
106 			// Cleaned URL path cannot be converted to URL
107 			// -> take original URL.
108 			return originalUrl;
109 		}
110 	}
111 
112 
113 	/**
114 	 * This implementation opens an InputStream for the given URL.
115 	 * It sets the "UseCaches" flag to <code>false</code>,
116 	 * mainly to avoid jar file locking on Windows.
117 	 * @see java.net.URL#openConnection()
118 	 * @see java.net.URLConnection#setUseCaches(boolean)
119 	 * @see java.net.URLConnection#getInputStream()
120 	 */
121 	public InputStream getInputStream() throws IOException {
122 		URLConnection con = this.url.openConnection();
123 		ResourceUtils.useCachesIfNecessary(con);
124 		try {
125 			return con.getInputStream();
126 		}
127 		catch (IOException ex) {
128 			// Close the HTTP connection (if applicable).
129 			if (con instanceof HttpURLConnection) {
130 				((HttpURLConnection) con).disconnect();
131 			}
132 			throw ex;
133 		}
134 	}
135 
136 	/**
137 	 * This implementation returns the underlying URL reference.
138 	 */
139 	@Override
140 	public URL getURL() throws IOException {
141 		return this.url;
142 	}
143 
144 	/**
145 	 * This implementation returns the underlying URI directly,
146 	 * if possible.
147 	 */
148 	@Override
149 	public URI getURI() throws IOException {
150 		if (this.uri != null) {
151 			return this.uri;
152 		}
153 		else {
154 			return super.getURI();
155 		}
156 	}
157 
158 	/**
159 	 * This implementation returns a File reference for the underlying URL/URI,
160 	 * provided that it refers to a file in the file system.
161 	 * @see org.springframework.util.ResourceUtils#getFile(java.net.URL, String)
162 	 */
163 	@Override
164 	public File getFile() throws IOException {
165 		if (this.uri != null) {
166 			return super.getFile(this.uri);
167 		}
168 		else {
169 			return super.getFile();
170 		}
171 	}
172 
173 	/**
174 	 * This implementation creates a UrlResource, applying the given path
175 	 * relative to the path of the underlying URL of this resource descriptor.
176 	 * @see java.net.URL#URL(java.net.URL, String)
177 	 */
178 	@Override
179 	public Resource createRelative(String relativePath) throws MalformedURLException {
180 		if (relativePath.startsWith("/")) {
181 			relativePath = relativePath.substring(1);
182 		}
183 		return new UrlResource(new URL(this.url, relativePath));
184 	}
185 
186 	/**
187 	 * This implementation returns the name of the file that this URL refers to.
188 	 * @see java.net.URL#getFile()
189 	 * @see java.io.File#getName()
190 	 */
191 	@Override
192 	public String getFilename() {
193 		return new File(this.url.getFile()).getName();
194 	}
195 
196 	/**
197 	 * This implementation returns a description that includes the URL.
198 	 */
199 	public String getDescription() {
200 		return "URL [" + this.url + "]";
201 	}
202 
203 
204 	/**
205 	 * This implementation compares the underlying URL references.
206 	 */
207 	@Override
208 	public boolean equals(Object obj) {
209 		return (obj == this ||
210 		    (obj instanceof UrlResource && this.cleanedUrl.equals(((UrlResource) obj).cleanedUrl)));
211 	}
212 
213 	/**
214 	 * This implementation returns the hash code of the underlying URL reference.
215 	 */
216 	@Override
217 	public int hashCode() {
218 		return this.cleanedUrl.hashCode();
219 	}
220 
221 }