package com.delcyon.capo.webapp.servlets.resource;
/*
* Derived from ResourceServlet.java:
* Copyright (c) 2012. betterFORM Project - http://www.betterform.de
* Licensed under the terms of BSD License
*/
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.delcyon.capo.CapoApplication;
public abstract class AbstractResourceServlet extends HttpServlet
{
private static AbstractResourceServlet resourceServlet = null;
private boolean caching; // allow the client to cache resources sent by this servlet? defaults to true but can be overridden by setting a 'caching' init-param with value 'false' in web.xml
private long oneYear = 31363200000L;
@Override
public void init(ServletConfig config) throws ServletException
{
super.init(config);
if ("false".equals(config.getInitParameter("caching")))
{
caching = false;
Logger.getGlobal().log(Level.FINEST, "Caching of Resources is disabled");
}
else
{
caching = true;
Logger.getGlobal().log(Level.FINEST, "Caching of Resources is enabled - resources are loaded from classpath");
}
initMimeTypes();
initResourceStreamers();
if(AbstractResourceServlet.resourceServlet == null)
{
AbstractResourceServlet.resourceServlet = this;
}
}
public static AbstractResourceServlet getResourceServletInstance()
{
return AbstractResourceServlet.resourceServlet;
}
/**
* define the collection of MimeTypes the servlet will serve up
*/
protected abstract void initMimeTypes();
/**
* define any ResourceStreamers the servlet will use to stream content
*/
protected abstract void initResourceStreamers();
/**
* return a date (as long) to be used for the Last-Modified response header when caching is enabled
*/
protected abstract long getLastModifiedValue();
/**
* return a MimeType string associated with the given fileExtension if the servlet is set up to stream files of that type
* @param fileExtension
* @return a MimeType string for the given extension if one can be found, otherwise null
*/
protected abstract String getMimeType(String fileExtension);
/**
* return the resource path for a given resource request
* @param requestURI
* @return a String representing the absolute path for the requested resource, validity of path may or may not be checked
*/
public abstract String getResourcePath(String requestURI);
/**
* Stream the resource with the appropriate ResourceStreamer for mimeType
* @param request
* @param response
* @param mimeType
* @param inputStream
*/
protected abstract void streamResource(HttpServletRequest request, HttpServletResponse response, String mimeType, InputStream inputStream) throws IOException;
public boolean exists(String requestURI)
{
return (AbstractResourceServlet.class.getResource(getResourcePath(requestURI)) != null);
}
/**
* Takes a request, attempts to locate the resource requested and stream it to the response
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String requestUri = request.getRequestURI();
Logger.getGlobal().log(Level.FINEST, "Request URI: " + requestUri);
String resourcePath = getResourcePath(requestUri);
Logger.getGlobal().log(Level.FINEST, "Resource path: " + resourcePath);
if (resourcePath == null)
{
Logger.getGlobal().log(Level.INFO, "resourcePath '" + resourcePath + "' does not map to a valid resource. Sending 'not found' response - ");
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
InputStream inputStream = null;
inputStream = AbstractResourceServlet.class.getResourceAsStream(resourcePath);
if (inputStream == null)
{
Logger.getGlobal().log(Level.INFO, "Resource not found at '" + resourcePath + "'. Sending 'not found' response - ");
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
String mimeType = getResourceContentType(resourcePath);
if (mimeType == null)
{
Logger.getGlobal().log(Level.INFO, "MimeType for '" + resourcePath + "' not found. Sending 'not found' response - ");
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
response.setContentType(mimeType);
response.setStatus(HttpServletResponse.SC_OK);
setCaching(request, response);
try
{
streamResource(request, response, mimeType, inputStream);
Logger.getGlobal().log(Level.FINEST, "Resource '" + resourcePath + "' streamed succesfully");
}
catch (IOException e)
{
Logger.getGlobal().log(Level.SEVERE, "Read exception occurred while streaming resource; path: " + resourcePath, e);
}
if (inputStream != null)
{
inputStream.close();
}
response.getOutputStream().flush();
response.getOutputStream().close();
}
/**
* set the caching headers for the resource response. Caching can be disabled by adding an init-param of 'caching' with value 'false' to web.xml
*
* @param request the http servlet request
* @param response the http servlet response
*/
protected void setCaching(HttpServletRequest request, HttpServletResponse response)
{
long now = System.currentTimeMillis();
if (caching == true)
{
response.setHeader("Cache-Control", "max-age=3600, public");
response.setDateHeader("Date", now);
response.setDateHeader("Expires", now + this.oneYear);
response.setDateHeader("Last-Modified", getLastModifiedValue());
}
else
{
// Set to expire far in the past.
response.setHeader("Expires", "Sat, 6 May 1995 12:00:00 GMT");
// Set standard HTTP/1.1 no-cache headers.
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
// Set IE extended HTTP/1.1 no-cache headers (use addHeader).
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
// Set standard HTTP/1.0 no-cache header.
response.setHeader("Pragma", "no-cache");
}
}
/**
* get Content-Type string (mime type) for the requested file's extension
* @param resourcePath
* @return
*/
protected String getResourceContentType(String resourcePath)
{
String resourceFileExtension = getResourceFileExtension(resourcePath);
return getMimeType(resourceFileExtension);
}
/**
* get the file extension for file at resourcePath
* @param resourcePath
* @return
*/
protected String getResourceFileExtension(String resourcePath)
{
String parsed[] = resourcePath.split("\\.");
return parsed[parsed.length - 1];
}
}