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.FileNotFoundException;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.net.URL;
23  
24  import org.springframework.util.Assert;
25  import org.springframework.util.ClassUtils;
26  import org.springframework.util.ObjectUtils;
27  import org.springframework.util.StringUtils;
28  
29  /**
30   * {@link Resource} implementation for class path resources.
31   * Uses either a given ClassLoader or a given Class for loading resources.
32   *
33   * <p>Supports resolution as <code>java.io.File</code> if the class path
34   * resource resides in the file system, but not for resources in a JAR.
35   * Always supports resolution as URL.
36   *
37   * @author Juergen Hoeller
38   * @author Sam Brannen
39   * @since 28.12.2003
40   * @see java.lang.ClassLoader#getResourceAsStream(String)
41   * @see java.lang.Class#getResourceAsStream(String)
42   */
43  public class ClassPathResource extends AbstractFileResolvingResource {
44  
45  	private final String path;
46  
47  	private ClassLoader classLoader;
48  
49  	private Class<?> clazz;
50  
51  
52  	/**
53  	 * Create a new ClassPathResource for ClassLoader usage.
54  	 * A leading slash will be removed, as the ClassLoader
55  	 * resource access methods will not accept it.
56  	 * <p>The thread context class loader will be used for
57  	 * loading the resource.
58  	 * @param path the absolute path within the class path
59  	 * @see java.lang.ClassLoader#getResourceAsStream(String)
60  	 * @see org.springframework.util.ClassUtils#getDefaultClassLoader()
61  	 */
62  	public ClassPathResource(String path) {
63  		this(path, (ClassLoader) null);
64  	}
65  
66  	/**
67  	 * Create a new ClassPathResource for ClassLoader usage.
68  	 * A leading slash will be removed, as the ClassLoader
69  	 * resource access methods will not accept it.
70  	 * @param path the absolute path within the classpath
71  	 * @param classLoader the class loader to load the resource with,
72  	 * or <code>null</code> for the thread context class loader
73  	 * @see java.lang.ClassLoader#getResourceAsStream(String)
74  	 */
75  	public ClassPathResource(String path, ClassLoader classLoader) {
76  		Assert.notNull(path, "Path must not be null");
77  		String pathToUse = StringUtils.cleanPath(path);
78  		if (pathToUse.startsWith("/")) {
79  			pathToUse = pathToUse.substring(1);
80  		}
81  		this.path = pathToUse;
82  		this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
83  	}
84  
85  	/**
86  	 * Create a new ClassPathResource for Class usage.
87  	 * The path can be relative to the given class,
88  	 * or absolute within the classpath via a leading slash.
89  	 * @param path relative or absolute path within the class path
90  	 * @param clazz the class to load resources with
91  	 * @see java.lang.Class#getResourceAsStream
92  	 */
93  	public ClassPathResource(String path, Class<?> clazz) {
94  		Assert.notNull(path, "Path must not be null");
95  		this.path = StringUtils.cleanPath(path);
96  		this.clazz = clazz;
97  	}
98  
99  	/**
100 	 * Create a new ClassPathResource with optional ClassLoader and Class.
101 	 * Only for internal usage.
102 	 * @param path relative or absolute path within the classpath
103 	 * @param classLoader the class loader to load the resource with, if any
104 	 * @param clazz the class to load resources with, if any
105 	 */
106 	protected ClassPathResource(String path, ClassLoader classLoader, Class<?> clazz) {
107 		this.path = StringUtils.cleanPath(path);
108 		this.classLoader = classLoader;
109 		this.clazz = clazz;
110 	}
111 
112 	/**
113 	 * Return the path for this resource (as resource path within the class path).
114 	 */
115 	public final String getPath() {
116 		return this.path;
117 	}
118 
119 	/**
120 	 * Return the ClassLoader that this resource will be obtained from.
121 	 */
122 	public final ClassLoader getClassLoader() {
123 		return (this.classLoader != null ? this.classLoader : this.clazz.getClassLoader());
124 	}
125 
126 	/**
127 	 * This implementation checks for the resolution of a resource URL.
128 	 * @see java.lang.ClassLoader#getResource(String)
129 	 * @see java.lang.Class#getResource(String)
130 	 */
131 	@Override
132 	public boolean exists() {
133 		URL url;
134 		if (this.clazz != null) {
135 			url = this.clazz.getResource(this.path);
136 		}
137 		else {
138 			url = this.classLoader.getResource(this.path);
139 		}
140 		return (url != null);
141 	}
142 
143 	/**
144 	 * This implementation opens an InputStream for the given class path resource.
145 	 * @see java.lang.ClassLoader#getResourceAsStream(String)
146 	 * @see java.lang.Class#getResourceAsStream(String)
147 	 */
148 	public InputStream getInputStream() throws IOException {
149 		InputStream is;
150 		if (this.clazz != null) {
151 			is = this.clazz.getResourceAsStream(this.path);
152 		}
153 		else {
154 			is = this.classLoader.getResourceAsStream(this.path);
155 		}
156 		if (is == null) {
157 			throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
158 		}
159 		return is;
160 	}
161 
162 	/**
163 	 * This implementation returns a URL for the underlying class path resource.
164 	 * @see java.lang.ClassLoader#getResource(String)
165 	 * @see java.lang.Class#getResource(String)
166 	 */
167 	@Override
168 	public URL getURL() throws IOException {
169 		URL url;
170 		if (this.clazz != null) {
171 			url = this.clazz.getResource(this.path);
172 		}
173 		else {
174 			url = this.classLoader.getResource(this.path);
175 		}
176 		if (url == null) {
177 			throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist");
178 		}
179 		return url;
180 	}
181 
182 	/**
183 	 * This implementation creates a ClassPathResource, applying the given path
184 	 * relative to the path of the underlying resource of this descriptor.
185 	 * @see org.springframework.util.StringUtils#applyRelativePath(String, String)
186 	 */
187 	@Override
188 	public Resource createRelative(String relativePath) {
189 		String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);
190 		return new ClassPathResource(pathToUse, this.classLoader, this.clazz);
191 	}
192 
193 	/**
194 	 * This implementation returns the name of the file that this class path
195 	 * resource refers to.
196 	 * @see org.springframework.util.StringUtils#getFilename(String)
197 	 */
198 	@Override
199 	public String getFilename() {
200 		return StringUtils.getFilename(this.path);
201 	}
202 
203 	/**
204 	 * This implementation returns a description that includes the class path location.
205 	 */
206 	public String getDescription() {
207 		StringBuilder builder = new StringBuilder("class path resource [");
208 
209 		String pathToUse = path;
210 
211 		if (this.clazz != null && !pathToUse.startsWith("/")) {
212 			builder.append(ClassUtils.classPackageAsResourcePath(this.clazz));
213 			builder.append('/');
214 		}
215 
216 		if (pathToUse.startsWith("/")) {
217 			pathToUse = pathToUse.substring(1);
218 		}
219 
220 		builder.append(pathToUse);
221 		builder.append(']');
222 		return builder.toString();
223 	}
224 
225 	/**
226 	 * This implementation compares the underlying class path locations.
227 	 */
228 	@Override
229 	public boolean equals(Object obj) {
230 		if (obj == this) {
231 			return true;
232 		}
233 		if (obj instanceof ClassPathResource) {
234 			ClassPathResource otherRes = (ClassPathResource) obj;
235 			return (this.path.equals(otherRes.path)
236 					&& ObjectUtils.nullSafeEquals(this.classLoader, otherRes.classLoader) && ObjectUtils.nullSafeEquals(
237 				this.clazz, otherRes.clazz));
238 		}
239 		return false;
240 	}
241 
242 	/**
243 	 * This implementation returns the hash code of the underlying
244 	 * class path location.
245 	 */
246 	@Override
247 	public int hashCode() {
248 		return this.path.hashCode();
249 	}
250 
251 }