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.web.context.support; 18 19 import java.io.File; 20 import java.io.FileNotFoundException; 21 import java.io.IOException; 22 import java.io.InputStream; 23 import java.net.MalformedURLException; 24 import java.net.URL; 25 import javax.servlet.ServletContext; 26 27 import org.springframework.core.io.AbstractFileResolvingResource; 28 import org.springframework.core.io.ContextResource; 29 import org.springframework.core.io.Resource; 30 import org.springframework.util.Assert; 31 import org.springframework.util.ResourceUtils; 32 import org.springframework.util.StringUtils; 33 import org.springframework.web.util.WebUtils; 34 35 /** 36 * {@link org.springframework.core.io.Resource} implementation for 37 * {@link javax.servlet.ServletContext} resources, interpreting 38 * relative paths within the web application root directory. 39 * 40 * <p>Always supports stream access and URL access, but only allows 41 * <code>java.io.File</code> access when the web application archive 42 * is expanded. 43 * 44 * @author Juergen Hoeller 45 * @since 28.12.2003 46 * @see javax.servlet.ServletContext#getResourceAsStream 47 * @see javax.servlet.ServletContext#getResource 48 * @see javax.servlet.ServletContext#getRealPath 49 */ 50 public class ServletContextResource extends AbstractFileResolvingResource implements ContextResource { 51 52 private final ServletContext servletContext; 53 54 private final String path; 55 56 57 /** 58 * Create a new ServletContextResource. 59 * <p>The Servlet spec requires that resource paths start with a slash, 60 * even if many containers accept paths without leading slash too. 61 * Consequently, the given path will be prepended with a slash if it 62 * doesn't already start with one. 63 * @param servletContext the ServletContext to load from 64 * @param path the path of the resource 65 */ ServletContextResource(ServletContext servletContext, String path)66 public ServletContextResource(ServletContext servletContext, String path) { 67 // check ServletContext 68 Assert.notNull(servletContext, "Cannot resolve ServletContextResource without ServletContext"); 69 this.servletContext = servletContext; 70 71 // check path 72 Assert.notNull(path, "Path is required"); 73 String pathToUse = StringUtils.cleanPath(path); 74 if (!pathToUse.startsWith("/")) { 75 pathToUse = "/" + pathToUse; 76 } 77 this.path = pathToUse; 78 } 79 80 /** 81 * Return the ServletContext for this resource. 82 */ getServletContext()83 public final ServletContext getServletContext() { 84 return this.servletContext; 85 } 86 87 /** 88 * Return the path for this resource. 89 */ getPath()90 public final String getPath() { 91 return this.path; 92 } 93 94 95 /** 96 * This implementation checks <code>ServletContext.getResource</code>. 97 * @see javax.servlet.ServletContext#getResource(String) 98 */ 99 @Override exists()100 public boolean exists() { 101 try { 102 URL url = this.servletContext.getResource(this.path); 103 return (url != null); 104 } 105 catch (MalformedURLException ex) { 106 return false; 107 } 108 } 109 110 /** 111 * This implementation delegates to <code>ServletContext.getResourceAsStream</code>, 112 * which returns <code>null</code> in case of a non-readable resource (e.g. a directory). 113 * @see javax.servlet.ServletContext#getResourceAsStream(String) 114 */ 115 @Override isReadable()116 public boolean isReadable() { 117 InputStream is = this.servletContext.getResourceAsStream(this.path); 118 if (is != null) { 119 try { 120 is.close(); 121 } 122 catch (IOException ex) { 123 // ignore 124 } 125 return true; 126 } 127 else { 128 return false; 129 } 130 } 131 132 /** 133 * This implementation delegates to <code>ServletContext.getResourceAsStream</code>, 134 * but throws a FileNotFoundException if no resource found. 135 * @see javax.servlet.ServletContext#getResourceAsStream(String) 136 */ getInputStream()137 public InputStream getInputStream() throws IOException { 138 InputStream is = this.servletContext.getResourceAsStream(this.path); 139 if (is == null) { 140 throw new FileNotFoundException("Could not open " + getDescription()); 141 } 142 return is; 143 } 144 145 /** 146 * This implementation delegates to <code>ServletContext.getResource</code>, 147 * but throws a FileNotFoundException if no resource found. 148 * @see javax.servlet.ServletContext#getResource(String) 149 */ 150 @Override getURL()151 public URL getURL() throws IOException { 152 URL url = this.servletContext.getResource(this.path); 153 if (url == null) { 154 throw new FileNotFoundException( 155 getDescription() + " cannot be resolved to URL because it does not exist"); 156 } 157 return url; 158 } 159 160 /** 161 * This implementation resolves "file:" URLs or alternatively delegates to 162 * <code>ServletContext.getRealPath</code>, throwing a FileNotFoundException 163 * if not found or not resolvable. 164 * @see javax.servlet.ServletContext#getResource(String) 165 * @see javax.servlet.ServletContext#getRealPath(String) 166 */ 167 @Override getFile()168 public File getFile() throws IOException { 169 URL url = this.servletContext.getResource(this.path); 170 if (url != null && ResourceUtils.isFileURL(url)) { 171 // Proceed with file system resolution... 172 return super.getFile(); 173 } 174 else { 175 String realPath = WebUtils.getRealPath(this.servletContext, this.path); 176 return new File(realPath); 177 } 178 } 179 180 /** 181 * This implementation creates a ServletContextResource, applying the given path 182 * relative to the path of the underlying file of this resource descriptor. 183 * @see org.springframework.util.StringUtils#applyRelativePath(String, String) 184 */ 185 @Override createRelative(String relativePath)186 public Resource createRelative(String relativePath) { 187 String pathToUse = StringUtils.applyRelativePath(this.path, relativePath); 188 return new ServletContextResource(this.servletContext, pathToUse); 189 } 190 191 /** 192 * This implementation returns the name of the file that this ServletContext 193 * resource refers to. 194 * @see org.springframework.util.StringUtils#getFilename(String) 195 */ 196 @Override getFilename()197 public String getFilename() { 198 return StringUtils.getFilename(this.path); 199 } 200 201 /** 202 * This implementation returns a description that includes the ServletContext 203 * resource location. 204 */ getDescription()205 public String getDescription() { 206 return "ServletContext resource [" + this.path + "]"; 207 } 208 getPathWithinContext()209 public String getPathWithinContext() { 210 return this.path; 211 } 212 213 214 /** 215 * This implementation compares the underlying ServletContext resource locations. 216 */ 217 @Override equals(Object obj)218 public boolean equals(Object obj) { 219 if (obj == this) { 220 return true; 221 } 222 if (obj instanceof ServletContextResource) { 223 ServletContextResource otherRes = (ServletContextResource) obj; 224 return (this.servletContext.equals(otherRes.servletContext) && this.path.equals(otherRes.path)); 225 } 226 return false; 227 } 228 229 /** 230 * This implementation returns the hash code of the underlying 231 * ServletContext resource location. 232 */ 233 @Override hashCode()234 public int hashCode() { 235 return this.path.hashCode(); 236 } 237 238 } 239