Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2004-2008 the original author or authors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 package org.springframework.js.resource;
 
 import java.net.URL;
 import java.util.Map;
 import java.util.Set;
 
 
Special resource servlet for efficiently resolving and rendering static resources from within a JAR file.

Author(s):
Jeremy Grelle
Scott Andrews
 
 public class ResourceServlet extends HttpServletBean {
 
 	private static final String HTTP_CONTENT_LENGTH_HEADER = "Content-Length";
 
 	private static final String HTTP_LAST_MODIFIED_HEADER = "Last-Modified";
 
 	private static final String HTTP_EXPIRES_HEADER = "Expires";
 
 	private static final String HTTP_CACHE_CONTROL_HEADER = "Cache-Control";
 
 	private static final Log log = LogFactory.getLog(ResourceServlet.class);
 
 	private final String protectedPath = "/?WEB-INF/.*";
 
 	private String jarPathPrefix = "META-INF";
 
 	private boolean gzipEnabled = true;
 
 	private Set allowedResourcePaths = new HashSet();
 	{
 		.add("/**/*.css");
 		.add("/**/*.gif");
 		.add("/**/*.ico");
 		.add("/**/*.jpeg");
 		.add("/**/*.jpg");
 		.add("/**/*.js");
 		.add("/**/*.png");
 		.add("META-INF/**/*.css");
 		.add("META-INF/**/*.gif");
 		.add("META-INF/**/*.ico");
 		.add("META-INF/**/*.jpeg");
 		.add("META-INF/**/*.jpg");
 		.add("META-INF/**/*.js");
 		.add("META-INF/**/*.png");
 	};
 
 	private Map defaultMimeTypes = new HashMap();
 	{
 		.put(".css""text/css");
 		.put(".gif""image/gif");
 		.put(".ico""image/vnd.microsoft.icon");
 		.put(".jpeg""image/jpeg");
 		.put(".jpg""image/jpeg");
 		.put(".js""text/javascript");
 		.put(".png""image/png");
 	}
 
 	private Set compressedMimeTypes = new HashSet();
	{
	}
	private int cacheTimeout = 31556926;
	protected void doGet(HttpServletRequest requestHttpServletResponse responsethrows ServletExceptionIOException {
		String rawResourcePath = request.getPathInfo();
			.debug("Attempting to GET resource: " + rawResourcePath);
		}
		URL[] resources = getRequestResourceURLs(request);
		if (resources == null || resources.length == 0) {
				.debug("Resource not found: " + rawResourcePath);
			}
			return;
		}
		prepareResponse(responseresourcesrawResourcePath);
		OutputStream out = selectOutputStream(requestresponse);
		try {
			for (int i = 0; i < resources.lengthi++) {
				URLConnection resourceConn = resources[i].openConnection();
				InputStream in = resourceConn.getInputStream();
				try {
					byte[] buffer = new byte[1024];
					int bytesRead = -1;
					while ((bytesRead = in.read(buffer)) != -1) {
						out.write(buffer, 0, bytesRead);
					}
finally {
					in.close();
				}
			}
finally {
			out.close();
		}
	}
			throws IOException {
		String acceptEncoding = request.getHeader("Accept-Encoding");
		String mimeType = response.getContentType();
		if ( && StringUtils.hasText(acceptEncoding) && acceptEncoding.indexOf("gzip") > -1
			.debug("Enabling GZIP compression for the current response.");
			return new GZIPResponseStream(response);
else {
			return response.getOutputStream();
		}
	}
	private boolean matchesCompressedMimeTypes(String mimeType) {
		PathMatcher pathMatcher = new AntPathMatcher();
		Iterator compressedMimeTypesIt = .iterator();
		while (compressedMimeTypesIt.hasNext()) {
			String compressedMimeType = (StringcompressedMimeTypesIt.next();
			if (pathMatcher.match(compressedMimeTypemimeType)) {
				return true;
			}
		}
		return false;
	}
	private void prepareResponse(HttpServletResponse responseURL[] resourcesString rawResourcePath)
			throws IOException {
		long lastModified = -1;
		int contentLength = 0;
		String mimeType = null;
		for (int i = 0; i < resources.lengthi++) {
			URLConnection resourceConn = resources[i].openConnection();
			if (resourceConn.getLastModified() > lastModified) {
				lastModified = resourceConn.getLastModified();
			}
			String currentMimeType = getServletContext().getMimeType(resources[i].getPath());
			if (currentMimeType == null) {
				String extension = resources[i].getPath().substring(resources[i].getPath().lastIndexOf('.'));
				currentMimeType = (String.get(extension);
			}
			if (mimeType == null) {
				mimeType = currentMimeType;
else if (!mimeType.equals(currentMimeType)) {
				throw new MalformedURLException("Combined resource path: " + rawResourcePath
" is invalid. All resources in a combined resource path must be of the same mime type.");
			}
			contentLength += resourceConn.getContentLength();
		}
		response.setContentType(mimeType);
		response.setHeader(, Long.toString(contentLength));
		response.setDateHeader(lastModified);
		if ( > 0) {
		}
	}
	protected long getLastModified(HttpServletRequest request) {
			.debug("Checking last modified of resource: " + request.getPathInfo());
		}
		URL[] resources;
		try {
			resources = getRequestResourceURLs(request);
catch (MalformedURLException e) {
			return -1;
		}
		if (resources == null || resources.length == 0) {
			return -1;
		}
		long lastModified = -1;
		for (int i = 0; i < resources.lengthi++) {
			URLConnection resourceConn;
			try {
				resourceConn = resources[i].openConnection();
catch (IOException e) {
				return -1;
			}
			if (resourceConn.getLastModified() > lastModified) {
				lastModified = resourceConn.getLastModified();
			}
		}
		return lastModified;
	}
		String rawResourcePath = request.getPathInfo();
		String appendedPaths = request.getParameter("appended");
		if (StringUtils.hasText(appendedPaths)) {
			rawResourcePath = rawResourcePath + "," + appendedPaths;
		}
		String[] localResourcePaths = StringUtils.delimitedListToStringArray(rawResourcePath",");
		URL[] resources = new URL[localResourcePaths.length];
		for (int i = 0; i < localResourcePaths.lengthi++) {
			String localResourcePath = localResourcePaths[i];
			if (!isAllowed(localResourcePath)) {
				if (.isWarnEnabled()) {
					.warn("An attempt to access a protected resource at " + localResourcePath + " was disallowed.");
				}
				return null;
			}
			URL resource = getServletContext().getResource(localResourcePath);
			if (resource == null) {
				String jarResourcePath =  + localResourcePath;
				if (!isAllowed(jarResourcePath)) {
					if (.isWarnEnabled()) {
								.warn("An attempt to access a protected resource at " + jarResourcePath
" was disallowed.");
					}
					return null;
				}
				if (jarResourcePath.startsWith("/")) {
					jarResourcePath = jarResourcePath.substring(1);
				}
					.debug("Searching classpath for resource: " + jarResourcePath);
				}
				resource = ClassUtils.getDefaultClassLoader().getResource(jarResourcePath);
			}
			if (resource == null) {
				if (resources.length > 1) {
					.debug("Combined resource not found: " + localResourcePath);
				}
				return null;
else {
				resources[i] = resource;
			}
		}
		return resources;
	}
	private boolean isAllowed(String resourcePath) {
		if (resourcePath.matches()) {
			return false;
		}
		PathMatcher pathMatcher = new AntPathMatcher();
		Iterator allowedResourcePathsIt = .iterator();
		while (allowedResourcePathsIt.hasNext()) {
			String pattern = (StringallowedResourcePathsIt.next();
			if (pathMatcher.match(patternresourcePath)) {
				return true;
			}
		}
		return false;
	}

Set HTTP headers to allow caching for the given number of seconds.

Parameters:
seconds number of seconds into the future that the response should be cacheable for
	private void configureCaching(HttpServletResponse responseint seconds) {
		// HTTP 1.0 header
		response.setDateHeader(, System.currentTimeMillis() + seconds * 1000L);
		// HTTP 1.1 header
		response.setHeader("max-age=" + seconds);
	}
	private class GZIPResponseStream extends ServletOutputStream {
		private GZIPOutputStream gzipStream = null;
		private boolean closed = false;
		private HttpServletResponse response = null;
		public GZIPResponseStream(HttpServletResponse responsethrows IOException {
			super();
			 = false;
			this. = response;
			this. = response.getOutputStream();
		}
		public void close() throws IOException {
			if () {
				throw new IOException("This output stream has already been closed");
			}
			byte[] bytes = .toByteArray();
			.addHeader("Content-Encoding""gzip");
			 = true;
		}
		public void flush() throws IOException {
			if () {
				throw new IOException("Cannot flush a closed output stream");
			}
		}
		public void write(int bthrows IOException {
			if () {
				throw new IOException("Cannot write to a closed output stream");
			}
			.write((byteb);
		}
		public void write(byte b[]) throws IOException {
			write(b, 0, b.length);
		}
		public void write(byte b[], int offint lenthrows IOException {
			if () {
				throw new IOException("Cannot write to a closed output stream");
			}
			.write(bofflen);
		}
		public boolean closed() {
			return (this.);
		}
		public void reset() {
			// noop
		}
	}

Set whether to apply gzip compression to resources if the requesting client supports it.
	public void setGzipEnabled(boolean gzipEnabled) {
		this. = gzipEnabled;
	}

Set allowed resources as an comma separated String of URL patterns, e.g. "META-INF/** /*.js", The paths may be any Ant-style pattern parsable by AntPathMatcher.

	public void setAllowedResourcePaths(String allowedResourcePaths) {
		this. = new HashSet(Arrays.asList(StringUtils.tokenizeToStringArray(allowedResourcePaths,
				","truetrue)));
	}

Set comma separated MIME types that should have gzip compression applied. Typically, gzip compression is only useful for text based content. Ant-style patterns are supported, e.g. "text/*".

	public void setCompressedMimeTypes(String compressedMimeTypes) {
		this. = new HashSet(Arrays.asList(StringUtils.tokenizeToStringArray(compressedMimeTypes,
				","truetrue)));
	}

Set the default path prefix to apply to resources being served from jar files. Default is "META-INF".
	public void setJarPathPrefix(String jarPathPrefix) {
		this. = jarPathPrefix;
	}

Set the number of seconds resources should be cached by the client. Zero disables caching. Default is one year.
	public void setCacheTimeout(int cacheTimeout) {
		this. = cacheTimeout;
	}
New to GrepCode? Check out our FAQ X