New code style. No functional changes.

This commit is contained in:
Harald Kuhr
2011-02-17 16:53:08 +01:00
parent 1433a24052
commit 5bd896f80f
65 changed files with 1028 additions and 1048 deletions
@@ -63,7 +63,7 @@ public class MappedBufferImage {
File file = args.length > 0 ? new File(args[0]) : null; File file = args.length > 0 ? new File(args[0]) : null;
if (file != null && file.exists()) { if (file != null && file.exists()) {
// Load image using ImageIO // Load image using ImageIO
ImageInputStream input = ImageIO.createImageInputStream(file); ImageInputStream input = ImageIO.createImageInputStream(file);
Iterator<ImageReader> readers = ImageIO.getImageReaders(input); Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
@@ -90,6 +90,7 @@ public class MappedBufferImage {
// image = MappedImageFactory.createCompatibleMappedImage(w, h, cm2); // image = MappedImageFactory.createCompatibleMappedImage(w, h, cm2);
// image = MappedImageFactory.createCompatibleMappedImage(w, h, cm); // image = MappedImageFactory.createCompatibleMappedImage(w, h, cm);
// image = MappedImageFactory.createCompatibleMappedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR); // image = MappedImageFactory.createCompatibleMappedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
// image = MappedImageFactory.createCompatibleMappedImage(w, h, BufferedImage.TYPE_INT_BGR);
image = MappedImageFactory.createCompatibleMappedImage(w, h, type); image = MappedImageFactory.createCompatibleMappedImage(w, h, type);
// image = type.createBufferedImage(w, h); // image = type.createBufferedImage(w, h);
@@ -121,8 +122,18 @@ public class MappedBufferImage {
paintDots(w, h, image); paintDots(w, h, image);
} }
// TODO: Make re-sampling optional
if (true) {
image = resampleImage(image, 800);
}
int bytesPerPixel = image.getColorModel().getPixelSize() / 8; // Calculate first to avoid overflow int bytesPerPixel = image.getColorModel().getPixelSize() / 8; // Calculate first to avoid overflow
JFrame frame = new JFrame(String.format("Test [%s x %s] (%s)", w, h, toHumanReadableSize(w * h * bytesPerPixel))) { String size = toHumanReadableSize(w * h * bytesPerPixel);
showIt(w, h, image, size);
}
private static void showIt(final int w, final int h, BufferedImage image, final String size) {
JFrame frame = new JFrame(String.format("Test [%s x %s] (%s)", w, h, size)) {
@Override @Override
public Dimension getPreferredSize() { public Dimension getPreferredSize() {
// TODO: This looks like a useful util method... // TODO: This looks like a useful util method...
@@ -144,26 +155,83 @@ public class MappedBufferImage {
frame.setVisible(true); frame.setVisible(true);
} }
private static void paintDots(int w, int h, BufferedImage image) { private static BufferedImage resampleImage(final BufferedImage image, final int width) {
long start = System.currentTimeMillis();
float aspect = image.getHeight() / (float) image.getWidth();
int height = Math.round(width * aspect);
ExecutorService executorService = Executors.newFixedThreadPool(threads);
// NOTE: The createCompatibleDestImage takes the byte order/layout into account, unlike the cm.createCompatibleWritableRaster
final BufferedImage output = new ResampleOp(width, height).createCompatibleDestImage(image, null);
final int inStep = (int) Math.ceil(image.getHeight() / (double) threads);
final int outStep = (int) Math.ceil(height / (double) threads);
// Resample image in slices
for (int i = 0; i < threads; i++) {
final int inY = i * inStep;
final int outY = i * outStep;
final int inHeight = Math.min(inStep, image.getHeight() - inY);
final int outHeight = Math.min(outStep, output.getHeight() - outY);
executorService.submit(new Runnable() {
public void run() {
try {
BufferedImage in = image.getSubimage(0, inY, image.getWidth(), inHeight);
BufferedImage out = output.getSubimage(0, outY, width, outHeight);
new ResampleOp(width, outHeight, ResampleOp.FILTER_LANCZOS).filter(in, out);
// BufferedImage out = new ResampleOp(width, outHeight, ResampleOp.FILTER_LANCZOS).filter(in, null);
// ImageUtil.drawOnto(output.getSubimage(0, outY, width, outHeight), out);
// showIt(width, outHeight, out, "foo");
}
catch (RuntimeException e) {
e.printStackTrace();
throw e;
}
}
});
}
// System.out.println("Starting image scale on single thread, waiting for execution to complete...");
// BufferedImage output = new ResampleOp(width, height, ResampleOp.FILTER_LANCZOS).filter(image, null);
System.out.printf("Started image scale on %d threads, waiting for execution to complete...%n", threads);
Boolean done = null;
try {
executorService.shutdown();
done = executorService.awaitTermination(5L, TimeUnit.MINUTES);
}
catch (InterruptedException ignore) {
}
System.out.printf("%s scaling image in %d ms%n", (done == null ? "Interrupted" : !done ? "Timed out" : "Done"), System.currentTimeMillis() - start);
System.out.println("image = " + output);
return output;
}
private static void paintDots(int width, int height, final BufferedImage image) {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
int s = 300; int s = 300;
int ws = w / s; int ws = width / s;
int hs = h / s; int hs = height / s;
Color[] colors = new Color[] { Color[] colors = new Color[] {
Color.WHITE, Color.ORANGE, Color.BLUE, Color.MAGENTA, Color.BLACK, Color.RED, Color.CYAN, Color.WHITE, Color.ORANGE, Color.BLUE, Color.MAGENTA, Color.BLACK, Color.RED, Color.CYAN,
Color.GRAY, Color.GREEN, Color.YELLOW, Color.PINK, Color.LIGHT_GRAY, Color.DARK_GRAY Color.GRAY, Color.GREEN, Color.YELLOW, Color.PINK, Color.LIGHT_GRAY, Color.DARK_GRAY
}; };
Random r = new Random();
ExecutorService executorService = Executors.newFixedThreadPool(threads); ExecutorService executorService = Executors.newFixedThreadPool(threads);
int step = (int) Math.ceil(hs / (double) threads); int step = (int) Math.ceil(hs / (double) threads);
Random r = new Random();
for (int i = 0; i < threads; i++) { for (int i = 0; i < threads; i++) {
executorService.submit(new PaintDotsTask(image, s, ws, colors, r, i * step, i * step + step)); executorService.submit(new PaintDotsTask(image, s, ws, colors, r, i * step, i * step + step));
} }
System.err.printf("Started painting in %d threads, waiting for execution to complete...%n", threads); System.err.printf("Started painting in %d threads, waiting for execution to complete...%n", threads);
Boolean done = null; Boolean done = null;
@@ -52,7 +52,7 @@ public abstract class MappedFileBuffer extends DataBuffer {
private final Buffer buffer; private final Buffer buffer;
private MappedFileBuffer(final int type, final int size, final int numBanks) throws IOException { private MappedFileBuffer(final int type, final int size, final int numBanks) throws IOException {
super(type, Validate.isTrue(size < 0, size, "Integer overflow for size: %d"), numBanks); super(type, Validate.isTrue(size >= 0, size, "Integer overflow for size: %d"), numBanks);
int componentSize = DataBuffer.getDataTypeSize(type) / 8; int componentSize = DataBuffer.getDataTypeSize(type) / 8;
@@ -45,7 +45,9 @@ import java.io.IOException;
* @author last modified by $Author: haraldk$ * @author last modified by $Author: haraldk$
* @version $Id: MappedImageFactory.java,v 1.0 May 26, 2010 5:07:01 PM haraldk Exp$ * @version $Id: MappedImageFactory.java,v 1.0 May 26, 2010 5:07:01 PM haraldk Exp$
*/ */
public class MappedImageFactory { public final class MappedImageFactory {
private MappedImageFactory() {}
public static BufferedImage createCompatibleMappedImage(int width, int height, int type) throws IOException { public static BufferedImage createCompatibleMappedImage(int width, int height, int type) throws IOException {
BufferedImage temp = new BufferedImage(1, 1, type); BufferedImage temp = new BufferedImage(1, 1, type);
return createCompatibleMappedImage(width, height, temp.getSampleModel().createCompatibleSampleModel(width, height), temp.getColorModel()); return createCompatibleMappedImage(width, height, temp.getSampleModel().createCompatibleSampleModel(width, height), temp.getColorModel());
@@ -16,9 +16,9 @@ abstract class AbstractServletMapAdapter extends AbstractMap<String, List<String
private final static List<String> NULL_LIST = new ArrayList<String>(); private final static List<String> NULL_LIST = new ArrayList<String>();
private transient Map<String, List<String>> mCache = new HashMap<String, List<String>>(); private transient Map<String, List<String>> cache = new HashMap<String, List<String>>();
private transient int mSize = -1; private transient int size = -1;
private transient AbstractSet<Entry<String, List<String>>> mEntries; private transient AbstractSet<Entry<String, List<String>>> entries;
protected abstract Iterator<String> keysImpl(); protected abstract Iterator<String> keysImpl();
@@ -34,17 +34,18 @@ abstract class AbstractServletMapAdapter extends AbstractMap<String, List<String
} }
private List<String> getValues(final String pName) { private List<String> getValues(final String pName) {
List<String> values = mCache.get(pName); List<String> values = cache.get(pName);
if (values == null) { if (values == null) {
//noinspection unchecked //noinspection unchecked
Iterator<String> headers = valuesImpl(pName); Iterator<String> headers = valuesImpl(pName);
if (headers == null) { if (headers == null) {
mCache.put(pName, NULL_LIST); cache.put(pName, NULL_LIST);
} }
else { else {
values = toList(headers); values = toList(headers);
mCache.put(pName, values); cache.put(pName, values);
} }
} }
@@ -59,24 +60,24 @@ abstract class AbstractServletMapAdapter extends AbstractMap<String, List<String
@Override @Override
public int size() { public int size() {
if (mSize == -1) { if (size == -1) {
computeSize(); computeSize();
} }
return mSize; return size;
} }
private void computeSize() { private void computeSize() {
mSize = 0; size = 0;
for (Iterator<String> names = keysImpl(); names.hasNext(); names.next()) { for (Iterator<String> names = keysImpl(); names.hasNext(); names.next()) {
mSize++; size++;
} }
} }
public Set<Entry<String, List<String>>> entrySet() { public Set<Entry<String, List<String>>> entrySet() {
if (mEntries == null) { if (entries == null) {
mEntries = new AbstractSet<Entry<String, List<String>>>() { entries = new AbstractSet<Entry<String, List<String>>>() {
public Iterator<Entry<String, List<String>>> iterator() { public Iterator<Entry<String, List<String>>> iterator() {
return new Iterator<Entry<String, List<String>>>() { return new Iterator<Entry<String, List<String>>>() {
Iterator<String> mHeaderNames = keysImpl(); Iterator<String> mHeaderNames = keysImpl();
@@ -102,7 +103,7 @@ abstract class AbstractServletMapAdapter extends AbstractMap<String, List<String
}; };
} }
return mEntries; return entries;
} }
private class HeaderEntry implements Entry<String, List<String>> { private class HeaderEntry implements Entry<String, List<String>> {
@@ -53,8 +53,8 @@ public class BrowserHelperFilter extends GenericFilter {
private static final String HTTP_HEADER_ACCEPT = "Accept"; private static final String HTTP_HEADER_ACCEPT = "Accept";
protected static final String HTTP_HEADER_USER_AGENT = "User-Agent"; protected static final String HTTP_HEADER_USER_AGENT = "User-Agent";
private Pattern[] mKnownAgentPatterns; private Pattern[] knownAgentPatterns;
private String[] mKnownAgentAccpets; private String[] knownAgentAccepts;
/** /**
* Sets the accept-mappings for this filter * Sets the accept-mappings for this filter
@@ -100,8 +100,8 @@ public class BrowserHelperFilter extends GenericFilter {
log("Could not parse User-Agent identification for " + agent, e); log("Could not parse User-Agent identification for " + agent, e);
} }
mKnownAgentPatterns = patterns.toArray(new Pattern[patterns.size()]); knownAgentPatterns = patterns.toArray(new Pattern[patterns.size()]);
mKnownAgentAccpets = accepts.toArray(new String[accepts.size()]); knownAgentAccepts = accepts.toArray(new String[accepts.size()]);
} }
} }
catch (IOException e) { catch (IOException e) {
@@ -110,7 +110,7 @@ public class BrowserHelperFilter extends GenericFilter {
} }
public void init() throws ServletException { public void init() throws ServletException {
if (mKnownAgentAccpets == null || mKnownAgentAccpets.length == 0) { if (knownAgentAccepts == null || knownAgentAccepts.length == 0) {
throw new ServletConfigException("No User-Agent/Accept mappings for filter: " + getFilterName()); throw new ServletConfigException("No User-Agent/Accept mappings for filter: " + getFilterName());
} }
} }
@@ -120,16 +120,16 @@ public class BrowserHelperFilter extends GenericFilter {
//System.out.println("--> Trying to find User-Agent/Accept headers..."); //System.out.println("--> Trying to find User-Agent/Accept headers...");
HttpServletRequest request = (HttpServletRequest) pRequest; HttpServletRequest request = (HttpServletRequest) pRequest;
// Check if User-Agent is in list of known agents // Check if User-Agent is in list of known agents
if (mKnownAgentPatterns != null && mKnownAgentPatterns.length > 0) { if (knownAgentPatterns != null && knownAgentPatterns.length > 0) {
String agent = request.getHeader(HTTP_HEADER_USER_AGENT); String agent = request.getHeader(HTTP_HEADER_USER_AGENT);
//System.out.println("--> User-Agent: " + agent); //System.out.println("--> User-Agent: " + agent);
for (int i = 0; i < mKnownAgentPatterns.length; i++) { for (int i = 0; i < knownAgentPatterns.length; i++) {
Pattern pattern = mKnownAgentPatterns[i]; Pattern pattern = knownAgentPatterns[i];
//System.out.println("--> Pattern: " + pattern); //System.out.println("--> Pattern: " + pattern);
if (pattern.matcher(agent).matches()) { if (pattern.matcher(agent).matches()) {
// TODO: Consider merge known with real accpet, in case plugins add extra capabilities? // TODO: Consider merge known with real accpet, in case plugins add extra capabilities?
final String fakeAccept = mKnownAgentAccpets[i]; final String fakeAccept = knownAgentAccepts[i];
//System.out.println("--> User-Agent: " + agent + " accepts: " + fakeAccept); //System.out.println("--> User-Agent: " + agent + " accepts: " + fakeAccept);
@@ -45,7 +45,7 @@ import java.util.Enumeration;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/DebugServlet.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/DebugServlet.java#1 $
*/ */
public class DebugServlet extends GenericServlet { public class DebugServlet extends GenericServlet {
private long mDateModified; private long dateModified;
public final void service(ServletRequest pRequest, ServletResponse pResponse) throws ServletException, IOException { public final void service(ServletRequest pRequest, ServletResponse pResponse) throws ServletException, IOException {
service((HttpServletRequest) pRequest, (HttpServletResponse) pResponse); service((HttpServletRequest) pRequest, (HttpServletResponse) pResponse);
@@ -53,13 +53,13 @@ public class DebugServlet extends GenericServlet {
public void init() throws ServletException { public void init() throws ServletException {
super.init(); super.init();
mDateModified = System.currentTimeMillis(); dateModified = System.currentTimeMillis();
} }
public void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException { public void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
pResponse.setContentType("text/plain"); pResponse.setContentType("text/plain");
// Include these to allow browser caching // Include these to allow browser caching
pResponse.setDateHeader("Last-Modified", mDateModified); pResponse.setDateHeader("Last-Modified", dateModified);
pResponse.setHeader("ETag", getServletName()); pResponse.setHeader("ETag", getServletName());
ServletOutputStream out = pResponse.getOutputStream(); ServletOutputStream out = pResponse.getOutputStream();
@@ -71,14 +71,14 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
/** /**
* The filter config. * The filter config.
*/ */
private transient FilterConfig mFilterConfig = null; private transient FilterConfig filterConfig = null;
/** /**
* Makes sure the filter runs once per request * Makes sure the filter runs once per request
* <p/> * <p/>
* see #isRunOnce * see #isRunOnce
* *
* @see #mOncePerRequest * @see #oncePerRequest
* see #ATTRIB_RUN_ONCE_VALUE * see #ATTRIB_RUN_ONCE_VALUE
*/ */
private final static String ATTRIB_RUN_ONCE_EXT = ".REQUEST_HANDLED"; private final static String ATTRIB_RUN_ONCE_EXT = ".REQUEST_HANDLED";
@@ -90,17 +90,17 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
* <p/> * <p/>
* see #isRunOnce * see #isRunOnce
* *
* @see #mOncePerRequest * @see #oncePerRequest
* see #ATTRIB_RUN_ONCE_VALUE * see #ATTRIB_RUN_ONCE_VALUE
*/ */
private String mAttribRunOnce = null; private String attribRunOnce = null;
/** /**
* Makes sure the filter runs once per request * Makes sure the filter runs once per request
* <p/> * <p/>
* see #isRunOnce * see #isRunOnce
* *
* @see #mOncePerRequest * @see #oncePerRequest
* see #ATTRIB_RUN_ONCE_EXT * see #ATTRIB_RUN_ONCE_EXT
*/ */
private static final Object ATTRIB_RUN_ONCE_VALUE = new Object(); private static final Object ATTRIB_RUN_ONCE_VALUE = new Object();
@@ -119,7 +119,7 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
* <pre>&lt;dispatcher&gt;REQUEST&lt;/dispatcher&gt;</pre> * <pre>&lt;dispatcher&gt;REQUEST&lt;/dispatcher&gt;</pre>
* </em> * </em>
*/ */
protected boolean mOncePerRequest = false; protected boolean oncePerRequest = false;
/** /**
* Does nothing. * Does nothing.
@@ -153,7 +153,7 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
} }
// Store filter config // Store filter config
mFilterConfig = pConfig; filterConfig = pConfig;
// Configure this // Configure this
try { try {
@@ -164,8 +164,8 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
} }
// Create run-once attribute name // Create run-once attribute name
mAttribRunOnce = pConfig.getFilterName() + ATTRIB_RUN_ONCE_EXT; attribRunOnce = pConfig.getFilterName() + ATTRIB_RUN_ONCE_EXT;
log("init (oncePerRequest=" + mOncePerRequest + ", attribRunOnce=" + mAttribRunOnce + ")"); log("init (oncePerRequest=" + oncePerRequest + ", attribRunOnce=" + attribRunOnce + ")");
init(); init();
} }
@@ -199,7 +199,7 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
*/ */
public final void doFilter(final ServletRequest pRequest, final ServletResponse pResponse, final FilterChain pFilterChain) throws IOException, ServletException { public final void doFilter(final ServletRequest pRequest, final ServletResponse pResponse, final FilterChain pFilterChain) throws IOException, ServletException {
// If request filter and already run, continue chain and return fast // If request filter and already run, continue chain and return fast
if (mOncePerRequest && isRunOnce(pRequest)) { if (oncePerRequest && isRunOnce(pRequest)) {
pFilterChain.doFilter(pRequest, pResponse); pFilterChain.doFilter(pRequest, pResponse);
return; return;
} }
@@ -227,18 +227,18 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
*/ */
private boolean isRunOnce(final ServletRequest pRequest) { private boolean isRunOnce(final ServletRequest pRequest) {
// If request already filtered, return true (skip) // If request already filtered, return true (skip)
if (pRequest.getAttribute(mAttribRunOnce) == ATTRIB_RUN_ONCE_VALUE) { if (pRequest.getAttribute(attribRunOnce) == ATTRIB_RUN_ONCE_VALUE) {
return true; return true;
} }
// Set attribute and return false (continue) // Set attribute and return false (continue)
pRequest.setAttribute(mAttribRunOnce, ATTRIB_RUN_ONCE_VALUE); pRequest.setAttribute(attribRunOnce, ATTRIB_RUN_ONCE_VALUE);
return false; return false;
} }
/** /**
* Invoked once, or each time a request/response pair is passed through the * Invoked once, or each time a request/response pair is passed through the
* chain, depending on the {@link #mOncePerRequest} member variable. * chain, depending on the {@link #oncePerRequest} member variable.
* *
* @param pRequest the servlet request * @param pRequest the servlet request
* @param pResponse the servlet response * @param pResponse the servlet response
@@ -247,7 +247,7 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
* @throws IOException if an I/O error occurs * @throws IOException if an I/O error occurs
* @throws ServletException if an exception occurs during the filter process * @throws ServletException if an exception occurs during the filter process
* *
* @see #mOncePerRequest * @see #oncePerRequest
* @see #doFilter doFilter * @see #doFilter doFilter
* @see Filter#doFilter Filter.doFilter * @see Filter#doFilter Filter.doFilter
*/ */
@@ -262,7 +262,7 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
*/ */
public void destroy() { public void destroy() {
log("destroy"); log("destroy");
mFilterConfig = null; filterConfig = null;
} }
/** /**
@@ -273,7 +273,7 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
* @see FilterConfig#getFilterName * @see FilterConfig#getFilterName
*/ */
public String getFilterName() { public String getFilterName() {
return mFilterConfig.getFilterName(); return filterConfig.getFilterName();
} }
/** /**
@@ -287,7 +287,7 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
*/ */
public ServletContext getServletContext() { public ServletContext getServletContext() {
// TODO: Create a servlet context wrapper that lets you log to a log4j appender? // TODO: Create a servlet context wrapper that lets you log to a log4j appender?
return mFilterConfig.getServletContext(); return filterConfig.getServletContext();
} }
/** /**
@@ -300,7 +300,7 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
* parameter * parameter
*/ */
public String getInitParameter(final String pKey) { public String getInitParameter(final String pKey) {
return mFilterConfig.getInitParameter(pKey); return filterConfig.getInitParameter(pKey);
} }
/** /**
@@ -312,7 +312,7 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
* containing the mNames of the servlet's initialization parameters * containing the mNames of the servlet's initialization parameters
*/ */
public Enumeration getInitParameterNames() { public Enumeration getInitParameterNames() {
return mFilterConfig.getInitParameterNames(); return filterConfig.getInitParameterNames();
} }
/** /**
@@ -363,7 +363,7 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
* @see FilterConfig * @see FilterConfig
*/ */
public FilterConfig getFilterConfig() { public FilterConfig getFilterConfig() {
return mFilterConfig; return filterConfig;
} }
/** /**
@@ -374,10 +374,10 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl
* *
* @param pOncePerRequest {@code true} if the filter should run only * @param pOncePerRequest {@code true} if the filter should run only
* once per request * once per request
* @see #mOncePerRequest * @see #oncePerRequest
*/ */
@InitParam(name = "once-per-request") @InitParam(name = "once-per-request")
public void setOncePerRequest(final boolean pOncePerRequest) { public void setOncePerRequest(final boolean pOncePerRequest) {
mOncePerRequest = pOncePerRequest; oncePerRequest = pOncePerRequest;
} }
} }
@@ -41,8 +41,8 @@ import java.lang.reflect.InvocationTargetException;
* the method matching the signature {@code void setX(&lt;Type&gt;)}, * the method matching the signature {@code void setX(&lt;Type&gt;)},
* for every init-parameter {@code x}. Both camelCase and lisp-style paramter * for every init-parameter {@code x}. Both camelCase and lisp-style paramter
* naming is supported, lisp-style names will be converted to camelCase. * naming is supported, lisp-style names will be converted to camelCase.
* Parameter values are automatically converted from string represenation to * Parameter values are automatically converted from string representation to
* most basic types, if neccessary. * most basic types, if necessary.
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haku $ * @author last modified by $Author: haku $
@@ -70,7 +70,7 @@ public abstract class GenericServlet extends javax.servlet.GenericServlet {
* @see BeanUtil#configure(Object, java.util.Map, boolean) * @see BeanUtil#configure(Object, java.util.Map, boolean)
*/ */
@Override @Override
public void init(ServletConfig pConfig) throws ServletException { public void init(final ServletConfig pConfig) throws ServletException {
if (pConfig == null) { if (pConfig == null) {
throw new ServletConfigException("servletconfig == null"); throw new ServletConfigException("servletconfig == null");
} }
@@ -37,6 +37,7 @@ import java.lang.annotation.*;
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haku $ * @author last modified by $Author: haku $
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/InitParam.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/InitParam.java#1 $
* @see com.twelvemonkeys.servlet.ServletConfigurator
* @see com.twelvemonkeys.servlet.GenericFilter#init(javax.servlet.FilterConfig) * @see com.twelvemonkeys.servlet.GenericFilter#init(javax.servlet.FilterConfig)
* @see com.twelvemonkeys.servlet.GenericServlet#init(javax.servlet.ServletConfig) * @see com.twelvemonkeys.servlet.GenericServlet#init(javax.servlet.ServletConfig)
* @see com.twelvemonkeys.servlet.HttpServlet#init(javax.servlet.ServletConfig) * @see com.twelvemonkeys.servlet.HttpServlet#init(javax.servlet.ServletConfig)
@@ -45,8 +46,10 @@ import java.lang.annotation.*;
@Documented @Documented
@Inherited @Inherited
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target({ElementType.METHOD/*, TODO: ElementType.FIELD*/})
public @interface InitParam { public @interface InitParam {
// TODO: Rename to value, to allow skipping name = "..." static final String UNDEFINED = "";
String name() default ""; String name() default UNDEFINED;
String defaultValue() default UNDEFINED; // TODO: Consider separate annotation?
boolean required() default false; // TODO: Consider separate annotation?
} }
@@ -28,6 +28,8 @@
package com.twelvemonkeys.servlet; package com.twelvemonkeys.servlet;
import com.twelvemonkeys.lang.Validate;
import javax.servlet.ServletOutputStream; import javax.servlet.ServletOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
@@ -67,7 +69,7 @@ import java.io.OutputStream;
public class OutputStreamAdapter extends ServletOutputStream { public class OutputStreamAdapter extends ServletOutputStream {
/** The wrapped {@code OutputStream}. */ /** The wrapped {@code OutputStream}. */
protected final OutputStream mOut; protected final OutputStream out;
/** /**
* Creates an {@code OutputStreamAdapter}. * Creates an {@code OutputStreamAdapter}.
@@ -76,11 +78,9 @@ public class OutputStreamAdapter extends ServletOutputStream {
* *
* @throws IllegalArgumentException if {@code pOut} is {@code null}. * @throws IllegalArgumentException if {@code pOut} is {@code null}.
*/ */
public OutputStreamAdapter(OutputStream pOut) { public OutputStreamAdapter(final OutputStream pOut) {
if (pOut == null) { Validate.notNull(pOut, "out");
throw new IllegalArgumentException("out == null"); out = pOut;
}
mOut = pOut;
} }
/** /**
@@ -89,11 +89,12 @@ public class OutputStreamAdapter extends ServletOutputStream {
* @return the wrapped {@code OutputStream}. * @return the wrapped {@code OutputStream}.
*/ */
public OutputStream getOutputStream() { public OutputStream getOutputStream() {
return mOut; return out;
} }
@Override
public String toString() { public String toString() {
return "ServletOutputStream adapted from " + mOut.toString(); return "ServletOutputStream adapted from " + out.toString();
} }
/** /**
@@ -103,20 +104,17 @@ public class OutputStreamAdapter extends ServletOutputStream {
* *
* @throws IOException if an error occurs during writing * @throws IOException if an error occurs during writing
*/ */
public void write(int pByte) public void write(final int pByte) throws IOException {
throws IOException { out.write(pByte);
mOut.write(pByte);
} }
// Overide for efficiency // Overide for efficiency
public void write(byte pBytes[]) public void write(final byte pBytes[]) throws IOException {
throws IOException { out.write(pBytes);
mOut.write(pBytes);
} }
// Overide for efficiency // Overide for efficiency
public void write(byte pBytes[], int pOff, int pLen) public void write(final byte pBytes[], final int pOff, final int pLen) throws IOException {
throws IOException { out.write(pBytes, pOff, pLen);
mOut.write(pBytes, pOff, pLen);
} }
} }
@@ -71,11 +71,11 @@ import java.util.Enumeration;
public class ProxyServlet extends GenericServlet { public class ProxyServlet extends GenericServlet {
/** Remote server host name or IP address */ /** Remote server host name or IP address */
protected String mRemoteServer = null; protected String remoteServer = null;
/** Remote server port */ /** Remote server port */
protected int mRemotePort = 80; protected int remotePort = 80;
/** Remote server "mount" path */ /** Remote server "mount" path */
protected String mRemotePath = ""; protected String remotePath = "";
private static final String HTTP_REQUEST_HEADER_HOST = "host"; private static final String HTTP_REQUEST_HEADER_HOST = "host";
private static final String HTTP_RESPONSE_HEADER_SERVER = "server"; private static final String HTTP_RESPONSE_HEADER_SERVER = "server";
@@ -88,7 +88,7 @@ public class ProxyServlet extends GenericServlet {
* @param pRemoteServer * @param pRemoteServer
*/ */
public void setRemoteServer(String pRemoteServer) { public void setRemoteServer(String pRemoteServer) {
mRemoteServer = pRemoteServer; remoteServer = pRemoteServer;
} }
/** /**
@@ -99,7 +99,7 @@ public class ProxyServlet extends GenericServlet {
*/ */
public void setRemotePort(String pRemotePort) { public void setRemotePort(String pRemotePort) {
try { try {
mRemotePort = Integer.parseInt(pRemotePort); remotePort = Integer.parseInt(pRemotePort);
} }
catch (NumberFormatException e) { catch (NumberFormatException e) {
log("RemotePort must be a number!", e); log("RemotePort must be a number!", e);
@@ -121,7 +121,7 @@ public class ProxyServlet extends GenericServlet {
pRemotePath = "/" + pRemotePath; pRemotePath = "/" + pRemotePath;
} }
mRemotePath = pRemotePath; remotePath = pRemotePath;
} }
/** /**
@@ -153,7 +153,7 @@ public class ProxyServlet extends GenericServlet {
*/ */
protected void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException { protected void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
// Sanity check configuration // Sanity check configuration
if (mRemoteServer == null) { if (remoteServer == null) {
log(MESSAGE_REMOTE_SERVER_NOT_CONFIGURED); log(MESSAGE_REMOTE_SERVER_NOT_CONFIGURED);
pResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, pResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
MESSAGE_REMOTE_SERVER_NOT_CONFIGURED); MESSAGE_REMOTE_SERVER_NOT_CONFIGURED);
@@ -164,7 +164,7 @@ public class ProxyServlet extends GenericServlet {
try { try {
// Recreate request URI for remote request // Recreate request URI for remote request
String requestURI = createRemoteRequestURI(pRequest); String requestURI = createRemoteRequestURI(pRequest);
URL remoteURL = new URL(pRequest.getScheme(), mRemoteServer, mRemotePort, requestURI); URL remoteURL = new URL(pRequest.getScheme(), remoteServer, remotePort, requestURI);
// Get connection, with method from original request // Get connection, with method from original request
// NOTE: The actual connection is not done before we ask for streams... // NOTE: The actual connection is not done before we ask for streams...
@@ -319,7 +319,7 @@ public class ProxyServlet extends GenericServlet {
* @return a {@code String} representing the remote request URI * @return a {@code String} representing the remote request URI
*/ */
private String createRemoteRequestURI(HttpServletRequest pRequest) { private String createRemoteRequestURI(HttpServletRequest pRequest) {
StringBuilder requestURI = new StringBuilder(mRemotePath); StringBuilder requestURI = new StringBuilder(remotePath);
requestURI.append(pRequest.getPathInfo()); requestURI.append(pRequest.getPathInfo());
if (!StringUtil.isEmpty(pRequest.getQueryString())) { if (!StringUtil.isEmpty(pRequest.getQueryString())) {
@@ -53,14 +53,14 @@ class ServletConfigMapAdapter extends AbstractMap<String, String> implements Map
ServletConfig, FilterConfig, ServletContext ServletConfig, FilterConfig, ServletContext
} }
private final ConfigType mType; private final ConfigType type;
private final ServletConfig mServletConfig; private final ServletConfig servletConfig;
private final FilterConfig mFilterConfig; private final FilterConfig filterConfig;
private final ServletContext mServletContext; private final ServletContext servletContext;
// Cache the entry set // Cache the entry set
private transient Set<Entry<String, String>> mEntrySet; private transient Set<Entry<String, String>> entrySet;
public ServletConfigMapAdapter(final ServletConfig pConfig) { public ServletConfigMapAdapter(final ServletConfig pConfig) {
this(pConfig, ConfigType.ServletConfig); this(pConfig, ConfigType.ServletConfig);
@@ -78,23 +78,23 @@ class ServletConfigMapAdapter extends AbstractMap<String, String> implements Map
// Could happen if client code invokes with null reference // Could happen if client code invokes with null reference
Validate.notNull(pConfig, "config"); Validate.notNull(pConfig, "config");
mType = pType; type = pType;
switch (mType) { switch (type) {
case ServletConfig: case ServletConfig:
mServletConfig = (ServletConfig) pConfig; servletConfig = (ServletConfig) pConfig;
mFilterConfig = null; filterConfig = null;
mServletContext = null; servletContext = null;
break; break;
case FilterConfig: case FilterConfig:
mServletConfig = null; servletConfig = null;
mFilterConfig = (FilterConfig) pConfig; filterConfig = (FilterConfig) pConfig;
mServletContext = null; servletContext = null;
break; break;
case ServletContext: case ServletContext:
mServletConfig = null; servletConfig = null;
mFilterConfig = null; filterConfig = null;
mServletContext = (ServletContext) pConfig; servletContext = (ServletContext) pConfig;
break; break;
default: default:
throw new IllegalArgumentException("Wrong type: " + pType); throw new IllegalArgumentException("Wrong type: " + pType);
@@ -107,13 +107,13 @@ class ServletConfigMapAdapter extends AbstractMap<String, String> implements Map
* @return the servlet or filter name * @return the servlet or filter name
*/ */
public final String getName() { public final String getName() {
switch (mType) { switch (type) {
case ServletConfig: case ServletConfig:
return mServletConfig.getServletName(); return servletConfig.getServletName();
case FilterConfig: case FilterConfig:
return mFilterConfig.getFilterName(); return filterConfig.getFilterName();
case ServletContext: case ServletContext:
return mServletContext.getServletContextName(); return servletContext.getServletContextName();
default: default:
throw new IllegalStateException(); throw new IllegalStateException();
} }
@@ -125,49 +125,49 @@ class ServletConfigMapAdapter extends AbstractMap<String, String> implements Map
* @return the servlet context * @return the servlet context
*/ */
public final ServletContext getServletContext() { public final ServletContext getServletContext() {
switch (mType) { switch (type) {
case ServletConfig: case ServletConfig:
return mServletConfig.getServletContext(); return servletConfig.getServletContext();
case FilterConfig: case FilterConfig:
return mFilterConfig.getServletContext(); return filterConfig.getServletContext();
case ServletContext: case ServletContext:
return mServletContext; return servletContext;
default: default:
throw new IllegalStateException(); throw new IllegalStateException();
} }
} }
public final Enumeration getInitParameterNames() { public final Enumeration getInitParameterNames() {
switch (mType) { switch (type) {
case ServletConfig: case ServletConfig:
return mServletConfig.getInitParameterNames(); return servletConfig.getInitParameterNames();
case FilterConfig: case FilterConfig:
return mFilterConfig.getInitParameterNames(); return filterConfig.getInitParameterNames();
case ServletContext: case ServletContext:
return mServletContext.getInitParameterNames(); return servletContext.getInitParameterNames();
default: default:
throw new IllegalStateException(); throw new IllegalStateException();
} }
} }
public final String getInitParameter(final String pName) { public final String getInitParameter(final String pName) {
switch (mType) { switch (type) {
case ServletConfig: case ServletConfig:
return mServletConfig.getInitParameter(pName); return servletConfig.getInitParameter(pName);
case FilterConfig: case FilterConfig:
return mFilterConfig.getInitParameter(pName); return filterConfig.getInitParameter(pName);
case ServletContext: case ServletContext:
return mServletContext.getInitParameter(pName); return servletContext.getInitParameter(pName);
default: default:
throw new IllegalStateException(); throw new IllegalStateException();
} }
} }
public Set<Entry<String, String>> entrySet() { public Set<Entry<String, String>> entrySet() {
if (mEntrySet == null) { if (entrySet == null) {
mEntrySet = createEntrySet(); entrySet = createEntrySet();
} }
return mEntrySet; return entrySet;
} }
private Set<Entry<String, String>> createEntrySet() { private Set<Entry<String, String>> createEntrySet() {
@@ -1,5 +1,6 @@
package com.twelvemonkeys.servlet; package com.twelvemonkeys.servlet;
import com.twelvemonkeys.lang.Validate;
import com.twelvemonkeys.util.CollectionUtil; import com.twelvemonkeys.util.CollectionUtil;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@@ -15,25 +16,21 @@ import java.util.Iterator;
*/ */
class ServletHeadersMapAdapter extends AbstractServletMapAdapter { class ServletHeadersMapAdapter extends AbstractServletMapAdapter {
protected final HttpServletRequest mRequest; protected final HttpServletRequest request;
public ServletHeadersMapAdapter(HttpServletRequest pRequest) { public ServletHeadersMapAdapter(HttpServletRequest pRequest) {
if (pRequest == null) { request = Validate.notNull(pRequest, "request");
throw new IllegalArgumentException("request == null");
}
mRequest = pRequest;
} }
protected Iterator<String> valuesImpl(String pName) { protected Iterator<String> valuesImpl(String pName) {
//noinspection unchecked //noinspection unchecked
Enumeration<String> headers = mRequest.getHeaders(pName); Enumeration<String> headers = request.getHeaders(pName);
return headers == null ? null : CollectionUtil.iterator(headers); return headers == null ? null : CollectionUtil.iterator(headers);
} }
protected Iterator<String> keysImpl() { protected Iterator<String> keysImpl() {
//noinspection unchecked //noinspection unchecked
Enumeration<String> headerNames = mRequest.getHeaderNames(); Enumeration<String> headerNames = request.getHeaderNames();
return headerNames == null ? null : CollectionUtil.iterator(headerNames); return headerNames == null ? null : CollectionUtil.iterator(headerNames);
} }
@@ -1,10 +1,11 @@
package com.twelvemonkeys.servlet; package com.twelvemonkeys.servlet;
import com.twelvemonkeys.lang.Validate;
import com.twelvemonkeys.util.CollectionUtil; import com.twelvemonkeys.util.CollectionUtil;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.Iterator;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Iterator;
/** /**
* ServletParametersMapAdapter * ServletParametersMapAdapter
@@ -15,23 +16,20 @@ import java.util.Enumeration;
*/ */
class ServletParametersMapAdapter extends AbstractServletMapAdapter { class ServletParametersMapAdapter extends AbstractServletMapAdapter {
protected final HttpServletRequest mRequest; protected final HttpServletRequest request;
public ServletParametersMapAdapter(HttpServletRequest pRequest) { public ServletParametersMapAdapter(HttpServletRequest pRequest) {
if (pRequest == null) { request = Validate.notNull(pRequest, "request");
throw new IllegalArgumentException("request == null");
}
mRequest = pRequest;
} }
protected Iterator<String> valuesImpl(String pName) { protected Iterator<String> valuesImpl(String pName) {
String[] values = mRequest.getParameterValues(pName); String[] values = request.getParameterValues(pName);
return values == null ? null : CollectionUtil.iterator(values); return values == null ? null : CollectionUtil.iterator(values);
} }
protected Iterator<String> keysImpl() { protected Iterator<String> keysImpl() {
//noinspection unchecked //noinspection unchecked
Enumeration<String> names = mRequest.getParameterNames(); Enumeration<String> names = request.getParameterNames();
return names == null ? null : CollectionUtil.iterator(names); return names == null ? null : CollectionUtil.iterator(names);
} }
@@ -28,6 +28,8 @@
package com.twelvemonkeys.servlet; package com.twelvemonkeys.servlet;
import com.twelvemonkeys.lang.Validate;
import javax.servlet.ServletOutputStream; import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import java.io.IOException; import java.io.IOException;
@@ -43,44 +45,41 @@ import java.io.OutputStream;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/ServletResponseStreamDelegate.java#2 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/ServletResponseStreamDelegate.java#2 $
*/ */
public class ServletResponseStreamDelegate { public class ServletResponseStreamDelegate {
private Object mOut = null; private Object out = null;
protected final ServletResponse mResponse; protected final ServletResponse response;
public ServletResponseStreamDelegate(ServletResponse pResponse) { public ServletResponseStreamDelegate(ServletResponse pResponse) {
if (pResponse == null) { response = Validate.notNull(pResponse, "response");
throw new IllegalArgumentException("response == null");
}
mResponse = pResponse;
} }
// NOTE: Intentionally NOT threadsafe, as one request/response should be // NOTE: Intentionally NOT threadsafe, as one request/response should be
// handled by one thread ONLY. // handled by one thread ONLY.
public final ServletOutputStream getOutputStream() throws IOException { public final ServletOutputStream getOutputStream() throws IOException {
if (mOut == null) { if (out == null) {
OutputStream out = createOutputStream(); OutputStream out = createOutputStream();
mOut = out instanceof ServletOutputStream ? out : new OutputStreamAdapter(out); this.out = out instanceof ServletOutputStream ? out : new OutputStreamAdapter(out);
} }
else if (mOut instanceof PrintWriter) { else if (out instanceof PrintWriter) {
throw new IllegalStateException("getWriter() allready called."); throw new IllegalStateException("getWriter() allready called.");
} }
return (ServletOutputStream) mOut; return (ServletOutputStream) out;
} }
// NOTE: Intentionally NOT threadsafe, as one request/response should be // NOTE: Intentionally NOT threadsafe, as one request/response should be
// handled by one thread ONLY. // handled by one thread ONLY.
public final PrintWriter getWriter() throws IOException { public final PrintWriter getWriter() throws IOException {
if (mOut == null) { if (out == null) {
// NOTE: getCharacterEncoding may should not return null // NOTE: getCharacterEncoding may should not return null
OutputStream out = createOutputStream(); OutputStream out = createOutputStream();
String charEncoding = mResponse.getCharacterEncoding(); String charEncoding = response.getCharacterEncoding();
mOut = new PrintWriter(charEncoding != null ? new OutputStreamWriter(out, charEncoding) : new OutputStreamWriter(out)); this.out = new PrintWriter(charEncoding != null ? new OutputStreamWriter(out, charEncoding) : new OutputStreamWriter(out));
} }
else if (mOut instanceof ServletOutputStream) { else if (out instanceof ServletOutputStream) {
throw new IllegalStateException("getOutputStream() allready called."); throw new IllegalStateException("getOutputStream() allready called.");
} }
return (PrintWriter) mOut; return (PrintWriter) out;
} }
/** /**
@@ -95,20 +94,20 @@ public class ServletResponseStreamDelegate {
* @throws IOException if an I/O exception occurs * @throws IOException if an I/O exception occurs
*/ */
protected OutputStream createOutputStream() throws IOException { protected OutputStream createOutputStream() throws IOException {
return mResponse.getOutputStream(); return response.getOutputStream();
} }
public void flushBuffer() throws IOException { public void flushBuffer() throws IOException {
if (mOut instanceof ServletOutputStream) { if (out instanceof ServletOutputStream) {
((ServletOutputStream) mOut).flush(); ((ServletOutputStream) out).flush();
} }
else if (mOut != null) { else if (out != null) {
((PrintWriter) mOut).flush(); ((PrintWriter) out).flush();
} }
} }
public void resetBuffer() { public void resetBuffer() {
// TODO: Is this okay? Probably not... :-) // TODO: Is this okay? Probably not... :-)
mOut = null; out = null;
} }
} }
@@ -706,21 +706,21 @@ public final class ServletUtil {
} }
private static class HttpServletResponseHandler implements InvocationHandler { private static class HttpServletResponseHandler implements InvocationHandler {
private final ServletResponseWrapper mResponse; private final ServletResponseWrapper response;
HttpServletResponseHandler(final ServletResponseWrapper pResponse) { HttpServletResponseHandler(final ServletResponseWrapper pResponse) {
mResponse = pResponse; response = pResponse;
} }
public Object invoke(final Object pProxy, final Method pMethod, final Object[] pArgs) throws Throwable { public Object invoke(final Object pProxy, final Method pMethod, final Object[] pArgs) throws Throwable {
try { try {
// TODO: Allow partial implementing? // TODO: Allow partial implementing?
if (pMethod.getDeclaringClass().isInstance(mResponse)) { if (pMethod.getDeclaringClass().isInstance(response)) {
return pMethod.invoke(mResponse, pArgs); return pMethod.invoke(response, pArgs);
} }
// Method is not implemented in wrapper // Method is not implemented in wrapper
return pMethod.invoke(mResponse.getResponse(), pArgs); return pMethod.invoke(response.getResponse(), pArgs);
} }
catch (InvocationTargetException e) { catch (InvocationTargetException e) {
// Unwrap, to avoid UndeclaredThrowableException... // Unwrap, to avoid UndeclaredThrowableException...
@@ -730,21 +730,21 @@ public final class ServletUtil {
} }
private static class HttpServletRequestHandler implements InvocationHandler { private static class HttpServletRequestHandler implements InvocationHandler {
private final ServletRequestWrapper mRequest; private final ServletRequestWrapper request;
HttpServletRequestHandler(final ServletRequestWrapper pRequest) { HttpServletRequestHandler(final ServletRequestWrapper pRequest) {
mRequest = pRequest; request = pRequest;
} }
public Object invoke(final Object pProxy, final Method pMethod, final Object[] pArgs) throws Throwable { public Object invoke(final Object pProxy, final Method pMethod, final Object[] pArgs) throws Throwable {
try { try {
// TODO: Allow partial implementing? // TODO: Allow partial implementing?
if (pMethod.getDeclaringClass().isInstance(mRequest)) { if (pMethod.getDeclaringClass().isInstance(request)) {
return pMethod.invoke(mRequest, pArgs); return pMethod.invoke(request, pArgs);
} }
// Method is not implemented in wrapper // Method is not implemented in wrapper
return pMethod.invoke(mRequest.getRequest(), pArgs); return pMethod.invoke(request.getRequest(), pArgs);
} }
catch (InvocationTargetException e) { catch (InvocationTargetException e) {
// Unwrap, to avoid UndeclaredThrowableException... // Unwrap, to avoid UndeclaredThrowableException...
@@ -67,13 +67,13 @@ public class ThrottleFilter extends GenericFilter {
/** /**
* Minimum free thread count, defaults to {@code 10} * Minimum free thread count, defaults to {@code 10}
*/ */
protected int mMaxConcurrentThreadCount = 10; protected int maxConcurrentThreadCount = 10;
/** /**
* The number of running request threads * The number of running request threads
*/ */
private int mRunningThreads = 0; private int runningThreads = 0;
private final Object mRunningThreadsLock = new Object(); private final Object runningThreadsLock = new Object();
/** /**
* Default response message sent to user agents, if the request is rejected * Default response message sent to user agents, if the request is rejected
@@ -89,17 +89,17 @@ public class ThrottleFilter extends GenericFilter {
/** /**
* The reposne message sent to user agenta, if the request is rejected * The reposne message sent to user agenta, if the request is rejected
*/ */
private Map mResponseMessageNames = new HashMap(10); private Map<String, String> responseMessageNames = new HashMap<String, String>(10);
/** /**
* The reposne message sent to user agents, if the request is rejected * The reposne message sent to user agents, if the request is rejected
*/ */
private String[] mResponseMessageTypes = null; private String[] responseMessageTypes = null;
/** /**
* Cache for response messages * Cache for response messages
*/ */
private Map mResponseCache = new HashMap(10); private Map<String, CacheEntry> responseCache = new HashMap<String, CacheEntry>(10);
/** /**
@@ -110,7 +110,7 @@ public class ThrottleFilter extends GenericFilter {
public void setMaxConcurrentThreadCount(String pMaxConcurrentThreadCount) { public void setMaxConcurrentThreadCount(String pMaxConcurrentThreadCount) {
if (!StringUtil.isEmpty(pMaxConcurrentThreadCount)) { if (!StringUtil.isEmpty(pMaxConcurrentThreadCount)) {
try { try {
mMaxConcurrentThreadCount = Integer.parseInt(pMaxConcurrentThreadCount); maxConcurrentThreadCount = Integer.parseInt(pMaxConcurrentThreadCount);
} }
catch (NumberFormatException nfe) { catch (NumberFormatException nfe) {
// Use default // Use default
@@ -133,23 +133,24 @@ public class ThrottleFilter extends GenericFilter {
public void setResponseMessages(String pResponseMessages) { public void setResponseMessages(String pResponseMessages) {
// Split string in type=filename pairs // Split string in type=filename pairs
String[] mappings = StringUtil.toStringArray(pResponseMessages, ", \r\n\t"); String[] mappings = StringUtil.toStringArray(pResponseMessages, ", \r\n\t");
List types = new ArrayList(); List<String> types = new ArrayList<String>();
for (int i = 0; i < mappings.length; i++) { for (String pair : mappings) {
// Split pairs on '=' // Split pairs on '='
String[] mapping = StringUtil.toStringArray(mappings[i], "= "); String[] mapping = StringUtil.toStringArray(pair, "= ");
// Test for wrong mapping // Test for wrong mapping
if ((mapping == null) || (mapping.length < 2)) { if ((mapping == null) || (mapping.length < 2)) {
log("Error in init param \"responseMessages\": " + pResponseMessages); log("Error in init param \"responseMessages\": " + pResponseMessages);
continue; continue;
} }
types.add(mapping[0]); types.add(mapping[0]);
mResponseMessageNames.put(mapping[0], mapping[1]); responseMessageNames.put(mapping[0], mapping[1]);
} }
// Create arrays // Create arrays
mResponseMessageTypes = (String[]) types.toArray(new String[types.size()]); responseMessageTypes = types.toArray(new String[types.size()]);
} }
/** /**
@@ -159,8 +160,7 @@ public class ThrottleFilter extends GenericFilter {
* @throws IOException * @throws IOException
* @throws ServletException * @throws ServletException
*/ */
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
throws IOException, ServletException {
try { try {
if (beginRequest()) { if (beginRequest()) {
// Continue request // Continue request
@@ -198,18 +198,19 @@ public class ThrottleFilter extends GenericFilter {
* @return <CODE>true<CODE> if the request should be handled. * @return <CODE>true<CODE> if the request should be handled.
*/ */
private boolean beginRequest() { private boolean beginRequest() {
synchronized (mRunningThreadsLock) { synchronized (runningThreadsLock) {
mRunningThreads++; runningThreads++;
} }
return (mRunningThreads <= mMaxConcurrentThreadCount);
return (runningThreads <= maxConcurrentThreadCount);
} }
/** /**
* Marks the end of the request * Marks the end of the request
*/ */
private void doneRequest() { private void doneRequest() {
synchronized (mRunningThreadsLock) { synchronized (runningThreadsLock) {
mRunningThreads--; runningThreads--;
} }
} }
@@ -220,12 +221,10 @@ public class ThrottleFilter extends GenericFilter {
* @return the content type * @return the content type
*/ */
private String getContentType(HttpServletRequest pRequest) { private String getContentType(HttpServletRequest pRequest) {
if (mResponseMessageTypes != null) { if (responseMessageTypes != null) {
String accept = pRequest.getHeader("Accept"); String accept = pRequest.getHeader("Accept");
for (int i = 0; i < mResponseMessageTypes.length; i++) { for (String type : responseMessageTypes) {
String type = mResponseMessageTypes[i];
// Note: This is not 100% correct way of doing content negotiation // Note: This is not 100% correct way of doing content negotiation
// But we just want a compatible result, quick, so this is okay // But we just want a compatible result, quick, so this is okay
if (StringUtil.contains(accept, type)) { if (StringUtil.contains(accept, type)) {
@@ -245,17 +244,16 @@ public class ThrottleFilter extends GenericFilter {
* @return the message * @return the message
*/ */
private String getMessage(String pContentType) { private String getMessage(String pContentType) {
String fileName = responseMessageNames.get(pContentType);
String fileName = (String) mResponseMessageNames.get(pContentType);
// Get cached value // Get cached value
CacheEntry entry = (CacheEntry) mResponseCache.get(fileName); CacheEntry entry = responseCache.get(fileName);
if ((entry == null) || entry.isExpired()) { if ((entry == null) || entry.isExpired()) {
// Create and add or replace cached value // Create and add or replace cached value
entry = new CacheEntry(readMessage(fileName)); entry = new CacheEntry(readMessage(fileName));
mResponseCache.put(fileName, entry); responseCache.put(fileName, entry);
} }
// Return value // Return value
@@ -292,20 +290,20 @@ public class ThrottleFilter extends GenericFilter {
* Keeps track of Cached objects * Keeps track of Cached objects
*/ */
private static class CacheEntry { private static class CacheEntry {
private Object mValue; private Object value;
private long mTimestamp = -1; private long timestamp = -1;
CacheEntry(Object pValue) { CacheEntry(Object pValue) {
mValue = pValue; value = pValue;
mTimestamp = System.currentTimeMillis(); timestamp = System.currentTimeMillis();
} }
Object getValue() { Object getValue() {
return mValue; return value;
} }
boolean isExpired() { boolean isExpired() {
return (System.currentTimeMillis() - mTimestamp) > 60000; // Cache 1 minute return (System.currentTimeMillis() - timestamp) > 60000; // Cache 1 minute
} }
} }
} }
@@ -44,7 +44,7 @@ import java.io.IOException;
*/ */
public class TimingFilter extends GenericFilter { public class TimingFilter extends GenericFilter {
private String mAttribUsage = null; private String attribUsage = null;
/** /**
* Method init * Method init
@@ -52,7 +52,7 @@ public class TimingFilter extends GenericFilter {
* @throws ServletException * @throws ServletException
*/ */
public void init() throws ServletException { public void init() throws ServletException {
mAttribUsage = getFilterName() + ".timerDelta"; attribUsage = getFilterName() + ".timerDelta";
} }
/** /**
@@ -66,13 +66,13 @@ public class TimingFilter extends GenericFilter {
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain)
throws IOException, ServletException { throws IOException, ServletException {
// Get total usage of earlier filters on same level // Get total usage of earlier filters on same level
Object usageAttrib = pRequest.getAttribute(mAttribUsage); Object usageAttrib = pRequest.getAttribute(attribUsage);
long total = 0; long total = 0;
if (usageAttrib instanceof Long) { if (usageAttrib instanceof Long) {
// If set, get value, and remove attribute for nested resources // If set, get value, and remove attribute for nested resources
total = ((Long) usageAttrib).longValue(); total = (Long) usageAttrib;
pRequest.removeAttribute(mAttribUsage); pRequest.removeAttribute(attribUsage);
} }
// Start timing // Start timing
@@ -87,10 +87,10 @@ public class TimingFilter extends GenericFilter {
long end = System.currentTimeMillis(); long end = System.currentTimeMillis();
// Get time usage of included resources, add to total usage // Get time usage of included resources, add to total usage
usageAttrib = pRequest.getAttribute(mAttribUsage); usageAttrib = pRequest.getAttribute(attribUsage);
long usage = 0; long usage = 0;
if (usageAttrib instanceof Long) { if (usageAttrib instanceof Long) {
usage = ((Long) usageAttrib).longValue(); usage = (Long) usageAttrib;
} }
// Get the name of the included resource // Get the name of the included resource
@@ -107,7 +107,7 @@ public class TimingFilter extends GenericFilter {
// Store total usage // Store total usage
total += delta; total += delta;
pRequest.setAttribute(mAttribUsage, new Long(total)); pRequest.setAttribute(attribUsage, total);
} }
} }
} }
@@ -113,28 +113,28 @@ import java.io.FilterOutputStream;
*/ */
public class TrimWhiteSpaceFilter extends GenericFilter { public class TrimWhiteSpaceFilter extends GenericFilter {
private boolean mAutoFlush = true; private boolean autoFlush = true;
@InitParam @InitParam
public void setAutoFlush(final boolean pAutoFlush) { public void setAutoFlush(final boolean pAutoFlush) {
mAutoFlush = pAutoFlush; autoFlush = pAutoFlush;
} }
public void init() throws ServletException { public void init() throws ServletException {
super.init(); super.init();
log("Automatic flushing is " + (mAutoFlush ? "enabled" : "disabled")); log("Automatic flushing is " + (autoFlush ? "enabled" : "disabled"));
} }
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException { protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
ServletResponseWrapper wrapped = new TrimWSServletResponseWrapper(pResponse); ServletResponseWrapper wrapped = new TrimWSServletResponseWrapper(pResponse);
pChain.doFilter(pRequest, ServletUtil.createWrapper(wrapped)); pChain.doFilter(pRequest, ServletUtil.createWrapper(wrapped));
if (mAutoFlush) { if (autoFlush) {
wrapped.flushBuffer(); wrapped.flushBuffer();
} }
} }
static final class TrimWSFilterOutputStream extends FilterOutputStream { static final class TrimWSFilterOutputStream extends FilterOutputStream {
boolean mLastWasWS = true; // Avoids leading WS by init to true boolean lastWasWS = true; // Avoids leading WS by init to true
public TrimWSFilterOutputStream(OutputStream pOut) { public TrimWSFilterOutputStream(OutputStream pOut) {
super(pOut); super(pOut);
@@ -175,12 +175,12 @@ public class TrimWhiteSpaceFilter extends GenericFilter {
if (!Character.isWhitespace((char) pByte)) { if (!Character.isWhitespace((char) pByte)) {
// If char is not WS, just store // If char is not WS, just store
super.write(pByte); super.write(pByte);
mLastWasWS = false; lastWasWS = false;
} }
else { else {
// TODO: Consider writing only 0x0a (LF) and 0x20 (space) // TODO: Consider writing only 0x0a (LF) and 0x20 (space)
// Else, if char is WS, store first, skip the rest // Else, if char is WS, store first, skip the rest
if (!mLastWasWS) { if (!lastWasWS) {
if (pByte == 0x0d) { // Convert all CR/LF's to 0x0a if (pByte == 0x0d) { // Convert all CR/LF's to 0x0a
super.write(0x0a); super.write(0x0a);
} }
@@ -188,7 +188,7 @@ public class TrimWhiteSpaceFilter extends GenericFilter {
super.write(pByte); super.write(pByte);
} }
} }
mLastWasWS = true; lastWasWS = true;
} }
} }
} }
@@ -199,23 +199,23 @@ public class TrimWhiteSpaceFilter extends GenericFilter {
} }
protected OutputStream createOutputStream() throws IOException { protected OutputStream createOutputStream() throws IOException {
return new TrimWSFilterOutputStream(mResponse.getOutputStream()); return new TrimWSFilterOutputStream(response.getOutputStream());
} }
} }
static class TrimWSServletResponseWrapper extends ServletResponseWrapper { static class TrimWSServletResponseWrapper extends ServletResponseWrapper {
private final ServletResponseStreamDelegate mStreamDelegate = new TrimWSStreamDelegate(getResponse()); private final ServletResponseStreamDelegate streamDelegate = new TrimWSStreamDelegate(getResponse());
public TrimWSServletResponseWrapper(ServletResponse pResponse) { public TrimWSServletResponseWrapper(ServletResponse pResponse) {
super(pResponse); super(pResponse);
} }
public ServletOutputStream getOutputStream() throws IOException { public ServletOutputStream getOutputStream() throws IOException {
return mStreamDelegate.getOutputStream(); return streamDelegate.getOutputStream();
} }
public PrintWriter getWriter() throws IOException { public PrintWriter getWriter() throws IOException {
return mStreamDelegate.getWriter(); return streamDelegate.getWriter();
} }
public void setContentLength(int pLength) { public void setContentLength(int pLength) {
@@ -224,12 +224,12 @@ public class TrimWhiteSpaceFilter extends GenericFilter {
@Override @Override
public void flushBuffer() throws IOException { public void flushBuffer() throws IOException {
mStreamDelegate.flushBuffer(); streamDelegate.flushBuffer();
} }
@Override @Override
public void resetBuffer() { public void resetBuffer() {
mStreamDelegate.resetBuffer(); streamDelegate.resetBuffer();
} }
// TODO: Consider picking up content-type/encoding, as we can only // TODO: Consider picking up content-type/encoding, as we can only
@@ -1,6 +1,7 @@
package com.twelvemonkeys.servlet.cache; package com.twelvemonkeys.servlet.cache;
import java.io.File; import com.twelvemonkeys.lang.Validate;
import java.net.URI; import java.net.URI;
/** /**
@@ -11,27 +12,20 @@ import java.net.URI;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/AbstractCacheRequest.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/AbstractCacheRequest.java#1 $
*/ */
public abstract class AbstractCacheRequest implements CacheRequest { public abstract class AbstractCacheRequest implements CacheRequest {
private final URI mRequestURI; private final URI requestURI;
private final String mMethod; private final String method;
protected AbstractCacheRequest(final URI pRequestURI, final String pMethod) { protected AbstractCacheRequest(final URI pRequestURI, final String pMethod) {
if (pRequestURI == null) { requestURI = Validate.notNull(pRequestURI, "requestURI");
throw new IllegalArgumentException("request URI == null"); method = Validate.notNull(pMethod, "method");
}
if (pMethod == null) {
throw new IllegalArgumentException("method == null");
}
mRequestURI = pRequestURI;
mMethod = pMethod;
} }
public URI getRequestURI() { public URI getRequestURI() {
return mRequestURI; return requestURI;
} }
public String getMethod() { public String getMethod() {
return mMethod; return method;
} }
// TODO: Consider overriding equals/hashcode // TODO: Consider overriding equals/hashcode
@@ -39,7 +33,7 @@ public abstract class AbstractCacheRequest implements CacheRequest {
@Override @Override
public String toString() { public String toString() {
return new StringBuilder(getClass().getSimpleName()) return new StringBuilder(getClass().getSimpleName())
.append("[URI=").append(mRequestURI) .append("[URI=").append(requestURI)
.append(", parameters=").append(getParameters()) .append(", parameters=").append(getParameters())
.append(", headers=").append(getHeaders()) .append(", headers=").append(getHeaders())
.append("]").toString(); .append("]").toString();
@@ -10,16 +10,16 @@ import java.util.*;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/AbstractCacheResponse.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/AbstractCacheResponse.java#1 $
*/ */
public abstract class AbstractCacheResponse implements CacheResponse { public abstract class AbstractCacheResponse implements CacheResponse {
private int mStatus; private int status;
private final Map<String, List<String>> mHeaders = new LinkedHashMap<String, List<String>>(); // Insertion order private final Map<String, List<String>> headers = new LinkedHashMap<String, List<String>>(); // Insertion order
private final Map<String, List<String>> mReadableHeaders = Collections.unmodifiableMap(mHeaders); private final Map<String, List<String>> readableHeaders = Collections.unmodifiableMap(headers);
public int getStatus() { public int getStatus() {
return mStatus; return status;
} }
public void setStatus(int pStatusCode) { public void setStatus(int pStatusCode) {
mStatus = pStatusCode; status = pStatusCode;
} }
public void addHeader(String pHeaderName, String pHeaderValue) { public void addHeader(String pHeaderName, String pHeaderValue) {
@@ -31,15 +31,15 @@ public abstract class AbstractCacheResponse implements CacheResponse {
} }
private void setHeader(String pHeaderName, String pHeaderValue, boolean pAdd) { private void setHeader(String pHeaderName, String pHeaderValue, boolean pAdd) {
List<String> values = pAdd ? mHeaders.get(pHeaderName) : null; List<String> values = pAdd ? headers.get(pHeaderName) : null;
if (values == null) { if (values == null) {
values = new ArrayList<String>(); values = new ArrayList<String>();
mHeaders.put(pHeaderName, values); headers.put(pHeaderName, values);
} }
values.add(pHeaderValue); values.add(pHeaderValue);
} }
public Map<String, List<String>> getHeaders() { public Map<String, List<String>> getHeaders() {
return mReadableHeaders; return readableHeaders;
} }
} }
@@ -57,7 +57,7 @@ import java.util.logging.Logger;
*/ */
public class CacheFilter extends GenericFilter { public class CacheFilter extends GenericFilter {
HTTPCache mCache; HTTPCache cache;
/** /**
* Initializes the filter * Initializes the filter
@@ -99,7 +99,7 @@ public class CacheFilter extends GenericFilter {
int maxCachedEntites = 10000; int maxCachedEntites = 10000;
try { try {
mCache = new HTTPCache( cache = new HTTPCache(
getTempFolder(), getTempFolder(),
expiryTime, expiryTime,
memCacheSize * 1024 * 1024, memCacheSize * 1024 * 1024,
@@ -120,7 +120,7 @@ public class CacheFilter extends GenericFilter {
return null; return null;
} }
}; };
log("Created cache: " + mCache); log("Created cache: " + cache);
} }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
throw new ServletConfigException("Could not create cache: " + e.toString(), e); throw new ServletConfigException("Could not create cache: " + e.toString(), e);
@@ -136,8 +136,8 @@ public class CacheFilter extends GenericFilter {
} }
public void destroy() { public void destroy() {
log("Destroying cache: " + mCache); log("Destroying cache: " + cache);
mCache = null; cache = null;
super.destroy(); super.destroy();
} }
@@ -155,7 +155,7 @@ public class CacheFilter extends GenericFilter {
// Render fast // Render fast
try { try {
mCache.doCached(cacheRequest, cacheResponse, resolver); cache.doCached(cacheRequest, cacheResponse, resolver);
} }
catch (CacheException e) { catch (CacheException e) {
if (e.getCause() instanceof ServletException) { if (e.getCause() instanceof ServletException) {
@@ -52,19 +52,19 @@ import java.io.PrintWriter;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheResponseWrapper.java#3 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheResponseWrapper.java#3 $
*/ */
class CacheResponseWrapper extends HttpServletResponseWrapper { class CacheResponseWrapper extends HttpServletResponseWrapper {
private ServletResponseStreamDelegate mStreamDelegate; private ServletResponseStreamDelegate streamDelegate;
private CacheResponse mResponse; private CacheResponse response;
private CachedEntity mCached; private CachedEntity cached;
private WritableCachedResponse mCachedResponse; private WritableCachedResponse cachedResponse;
private Boolean mCachable; private Boolean cachable;
private int mStatus; private int status;
public CacheResponseWrapper(final ServletCacheResponse pResponse, final CachedEntity pCached) { public CacheResponseWrapper(final ServletCacheResponse pResponse, final CachedEntity pCached) {
super(pResponse.getResponse()); super(pResponse.getResponse());
mResponse = pResponse; response = pResponse;
mCached = pCached; cached = pCached;
init(); init();
} }
@@ -75,19 +75,19 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
methods below. methods below.
*/ */
private void init() { private void init() {
mCachable = null; cachable = null;
mStatus = SC_OK; status = SC_OK;
mCachedResponse = mCached.createCachedResponse(); cachedResponse = cached.createCachedResponse();
mStreamDelegate = new ServletResponseStreamDelegate(this) { streamDelegate = new ServletResponseStreamDelegate(this) {
protected OutputStream createOutputStream() throws IOException { protected OutputStream createOutputStream() throws IOException {
// Test if this request is really cachable, otherwise, // Test if this request is really cachable, otherwise,
// just write through to underlying response, and don't cache // just write through to underlying response, and don't cache
if (isCachable()) { if (isCachable()) {
return mCachedResponse.getOutputStream(); return cachedResponse.getOutputStream();
} }
else { else {
mCachedResponse.setStatus(mStatus); cachedResponse.setStatus(status);
mCachedResponse.writeHeadersTo(CacheResponseWrapper.this.mResponse); cachedResponse.writeHeadersTo(CacheResponseWrapper.this.response);
return super.getOutputStream(); return super.getOutputStream();
} }
} }
@@ -95,25 +95,25 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
} }
CachedResponse getCachedResponse() { CachedResponse getCachedResponse() {
return mCachedResponse.getCachedResponse(); return cachedResponse.getCachedResponse();
} }
public boolean isCachable() { public boolean isCachable() {
// NOTE: Intentionally not synchronized // NOTE: Intentionally not synchronized
if (mCachable == null) { if (cachable == null) {
mCachable = isCachableImpl(); cachable = isCachableImpl();
} }
return mCachable; return cachable;
} }
private boolean isCachableImpl() { private boolean isCachableImpl() {
if (mStatus != SC_OK) { if (status != SC_OK) {
return false; return false;
} }
// Vary: * // Vary: *
String[] values = mCachedResponse.getHeaderValues(HTTPCache.HEADER_VARY); String[] values = cachedResponse.getHeaderValues(HTTPCache.HEADER_VARY);
if (values != null) { if (values != null) {
for (String value : values) { for (String value : values) {
if ("*".equals(value)) { if ("*".equals(value)) {
@@ -123,7 +123,7 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
} }
// Cache-Control: no-cache, no-store, must-revalidate // Cache-Control: no-cache, no-store, must-revalidate
values = mCachedResponse.getHeaderValues(HTTPCache.HEADER_CACHE_CONTROL); values = cachedResponse.getHeaderValues(HTTPCache.HEADER_CACHE_CONTROL);
if (values != null) { if (values != null) {
for (String value : values) { for (String value : values) {
if (StringUtil.contains(value, "no-cache") if (StringUtil.contains(value, "no-cache")
@@ -135,7 +135,7 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
} }
// Pragma: no-cache // Pragma: no-cache
values = mCachedResponse.getHeaderValues(HTTPCache.HEADER_PRAGMA); values = cachedResponse.getHeaderValues(HTTPCache.HEADER_PRAGMA);
if (values != null) { if (values != null) {
for (String value : values) { for (String value : values) {
if (StringUtil.contains(value, "no-cache")) { if (StringUtil.contains(value, "no-cache")) {
@@ -148,16 +148,16 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
} }
public void flushBuffer() throws IOException { public void flushBuffer() throws IOException {
mStreamDelegate.flushBuffer(); streamDelegate.flushBuffer();
} }
public void resetBuffer() { public void resetBuffer() {
// Servlet 2.3 // Servlet 2.3
mStreamDelegate.resetBuffer(); streamDelegate.resetBuffer();
} }
public void reset() { public void reset() {
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.reset(); super.reset();
} }
// No else, might be cachable after all.. // No else, might be cachable after all..
@@ -165,26 +165,26 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
} }
public ServletOutputStream getOutputStream() throws IOException { public ServletOutputStream getOutputStream() throws IOException {
return mStreamDelegate.getOutputStream(); return streamDelegate.getOutputStream();
} }
public PrintWriter getWriter() throws IOException { public PrintWriter getWriter() throws IOException {
return mStreamDelegate.getWriter(); return streamDelegate.getWriter();
} }
public boolean containsHeader(String name) { public boolean containsHeader(String name) {
return mCachedResponse.getHeaderValues(name) != null; return cachedResponse.getHeaderValues(name) != null;
} }
public void sendError(int pStatusCode, String msg) throws IOException { public void sendError(int pStatusCode, String msg) throws IOException {
// NOT cachable // NOT cachable
mStatus = pStatusCode; status = pStatusCode;
super.sendError(pStatusCode, msg); super.sendError(pStatusCode, msg);
} }
public void sendError(int pStatusCode) throws IOException { public void sendError(int pStatusCode) throws IOException {
// NOT cachable // NOT cachable
mStatus = pStatusCode; status = pStatusCode;
super.sendError(pStatusCode); super.sendError(pStatusCode);
} }
@@ -196,63 +196,63 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
public void setStatus(int pStatusCode) { public void setStatus(int pStatusCode) {
// NOT cachable unless pStatusCode == 200 (or a FEW others?) // NOT cachable unless pStatusCode == 200 (or a FEW others?)
if (pStatusCode != SC_OK) { if (pStatusCode != SC_OK) {
mStatus = pStatusCode; status = pStatusCode;
super.setStatus(pStatusCode); super.setStatus(pStatusCode);
} }
} }
public void sendRedirect(String pLocation) throws IOException { public void sendRedirect(String pLocation) throws IOException {
// NOT cachable // NOT cachable
mStatus = SC_MOVED_TEMPORARILY; status = SC_MOVED_TEMPORARILY;
super.sendRedirect(pLocation); super.sendRedirect(pLocation);
} }
public void setDateHeader(String pName, long pValue) { public void setDateHeader(String pName, long pValue) {
// If in write-trough-mode, set headers directly // If in write-trough-mode, set headers directly
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.setDateHeader(pName, pValue); super.setDateHeader(pName, pValue);
} }
mCachedResponse.setHeader(pName, NetUtil.formatHTTPDate(pValue)); cachedResponse.setHeader(pName, NetUtil.formatHTTPDate(pValue));
} }
public void addDateHeader(String pName, long pValue) { public void addDateHeader(String pName, long pValue) {
// If in write-trough-mode, set headers directly // If in write-trough-mode, set headers directly
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.addDateHeader(pName, pValue); super.addDateHeader(pName, pValue);
} }
mCachedResponse.addHeader(pName, NetUtil.formatHTTPDate(pValue)); cachedResponse.addHeader(pName, NetUtil.formatHTTPDate(pValue));
} }
public void setHeader(String pName, String pValue) { public void setHeader(String pName, String pValue) {
// If in write-trough-mode, set headers directly // If in write-trough-mode, set headers directly
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.setHeader(pName, pValue); super.setHeader(pName, pValue);
} }
mCachedResponse.setHeader(pName, pValue); cachedResponse.setHeader(pName, pValue);
} }
public void addHeader(String pName, String pValue) { public void addHeader(String pName, String pValue) {
// If in write-trough-mode, set headers directly // If in write-trough-mode, set headers directly
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.addHeader(pName, pValue); super.addHeader(pName, pValue);
} }
mCachedResponse.addHeader(pName, pValue); cachedResponse.addHeader(pName, pValue);
} }
public void setIntHeader(String pName, int pValue) { public void setIntHeader(String pName, int pValue) {
// If in write-trough-mode, set headers directly // If in write-trough-mode, set headers directly
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.setIntHeader(pName, pValue); super.setIntHeader(pName, pValue);
} }
mCachedResponse.setHeader(pName, String.valueOf(pValue)); cachedResponse.setHeader(pName, String.valueOf(pValue));
} }
public void addIntHeader(String pName, int pValue) { public void addIntHeader(String pName, int pValue) {
// If in write-trough-mode, set headers directly // If in write-trough-mode, set headers directly
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.addIntHeader(pName, pValue); super.addIntHeader(pName, pValue);
} }
mCachedResponse.addHeader(pName, String.valueOf(pValue)); cachedResponse.addHeader(pName, String.valueOf(pValue));
} }
public final void setContentType(String type) { public final void setContentType(String type) {
@@ -28,6 +28,8 @@
package com.twelvemonkeys.servlet.cache; package com.twelvemonkeys.servlet.cache;
import com.twelvemonkeys.lang.Validate;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@@ -39,21 +41,17 @@ import java.util.List;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedEntityImpl.java#3 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedEntityImpl.java#3 $
*/ */
class CachedEntityImpl implements CachedEntity { class CachedEntityImpl implements CachedEntity {
private String mCacheURI; private String cacheURI;
private HTTPCache mCache; private HTTPCache cache;
CachedEntityImpl(String pCacheURI, HTTPCache pCache) { CachedEntityImpl(String pCacheURI, HTTPCache pCache) {
if (pCacheURI == null) { cacheURI = Validate.notNull(pCacheURI, "cacheURI");
throw new IllegalArgumentException("cacheURI == null"); cache = pCache;
}
mCacheURI = pCacheURI;
mCache = pCache;
} }
public void render(CacheRequest pRequest, CacheResponse pResponse) throws IOException { public void render(CacheRequest pRequest, CacheResponse pResponse) throws IOException {
// Get cached content // Get cached content
CachedResponse cached = mCache.getContent(mCacheURI, pRequest); CachedResponse cached = cache.getContent(cacheURI, pRequest);
// Sanity check // Sanity check
if (cached == null) { if (cached == null) {
@@ -93,7 +91,7 @@ class CachedEntityImpl implements CachedEntity {
} }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
// Seems to be a bug in FireFox 1.0.2..?! // Seems to be a bug in FireFox 1.0.2..?!
mCache.log("Error in date header from user-agent. User-Agent: " + pRequest.getHeaders().get("User-Agent"), e); cache.log("Error in date header from user-agent. User-Agent: " + pRequest.getHeaders().get("User-Agent"), e);
} }
if (lastModified == -1L || (ifModifiedSince < (lastModified / 1000L) * 1000L)) { if (lastModified == -1L || (ifModifiedSince < (lastModified / 1000L) * 1000L)) {
@@ -134,8 +132,8 @@ class CachedEntityImpl implements CachedEntity {
// CacheResponseWrapper response = (CacheResponseWrapper) pResponse; // CacheResponseWrapper response = (CacheResponseWrapper) pResponse;
// if (response.isCachable()) { // if (response.isCachable()) {
mCache.registerContent( cache.registerContent(
mCacheURI, cacheURI,
pRequest, pRequest,
pResponse instanceof WritableCachedResponse ? ((WritableCachedResponse) pResponse).getCachedResponse() : pResponse pResponse instanceof WritableCachedResponse ? ((WritableCachedResponse) pResponse).getCachedResponse() : pResponse
); );
@@ -149,7 +147,7 @@ class CachedEntityImpl implements CachedEntity {
} }
public boolean isStale(CacheRequest pRequest) { public boolean isStale(CacheRequest pRequest) {
return mCache.isContentStale(mCacheURI, pRequest); return cache.isContentStale(cacheURI, pRequest);
} }
public WritableCachedResponse createCachedResponse() { public WritableCachedResponse createCachedResponse() {
@@ -157,16 +155,16 @@ class CachedEntityImpl implements CachedEntity {
} }
public int hashCode() { public int hashCode() {
return (mCacheURI != null ? mCacheURI.hashCode() : 0) + 1397; return (cacheURI != null ? cacheURI.hashCode() : 0) + 1397;
} }
public boolean equals(Object pOther) { public boolean equals(Object pOther) {
return pOther instanceof CachedEntityImpl && return pOther instanceof CachedEntityImpl &&
((mCacheURI == null && ((CachedEntityImpl) pOther).mCacheURI == null) || ((cacheURI == null && ((CachedEntityImpl) pOther).cacheURI == null) ||
mCacheURI != null && mCacheURI.equals(((CachedEntityImpl) pOther).mCacheURI)); cacheURI != null && cacheURI.equals(((CachedEntityImpl) pOther).cacheURI));
} }
public String toString() { public String toString() {
return "CachedEntity[URI=" + mCacheURI + "]"; return "CachedEntity[URI=" + cacheURI + "]";
} }
} }
@@ -29,6 +29,7 @@
package com.twelvemonkeys.servlet.cache; package com.twelvemonkeys.servlet.cache;
import com.twelvemonkeys.io.FastByteArrayOutputStream; import com.twelvemonkeys.io.FastByteArrayOutputStream;
import com.twelvemonkeys.lang.Validate;
import com.twelvemonkeys.util.LinkedMap; import com.twelvemonkeys.util.LinkedMap;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@@ -46,28 +47,25 @@ import java.util.Set;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedResponseImpl.java#4 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedResponseImpl.java#4 $
*/ */
class CachedResponseImpl implements CachedResponse { class CachedResponseImpl implements CachedResponse {
final protected Map<String, List<String>> mHeaders; final protected Map<String, List<String>> headers;
protected int mHeadersSize; protected int headersSize;
protected ByteArrayOutputStream mContent = null; protected ByteArrayOutputStream content = null;
int mStatus; int status;
protected CachedResponseImpl() { protected CachedResponseImpl() {
mHeaders = new LinkedMap<String, List<String>>(); // Keep headers in insertion order headers = new LinkedMap<String, List<String>>(); // Keep headers in insertion order
} }
// For use by HTTPCache, when recreating CachedResponses from disk cache // For use by HTTPCache, when recreating CachedResponses from disk cache
CachedResponseImpl(final int pStatus, final LinkedMap<String, List<String>> pHeaders, final int pHeaderSize, final byte[] pContent) { CachedResponseImpl(final int pStatus, final LinkedMap<String, List<String>> pHeaders, final int pHeaderSize, final byte[] pContent) {
if (pHeaders == null) { status = pStatus;
throw new IllegalArgumentException("headers == null"); headers = Validate.notNull(pHeaders, "headers");
} headersSize = pHeaderSize;
mStatus = pStatus; content = new FastByteArrayOutputStream(pContent);
mHeaders = pHeaders;
mHeadersSize = pHeaderSize;
mContent = new FastByteArrayOutputStream(pContent);
} }
public int getStatus() { public int getStatus() {
return mStatus; return status;
} }
/** /**
@@ -107,11 +105,11 @@ class CachedResponseImpl implements CachedResponse {
* @throws java.io.IOException * @throws java.io.IOException
*/ */
public void writeContentsTo(final OutputStream pStream) throws IOException { public void writeContentsTo(final OutputStream pStream) throws IOException {
if (mContent == null) { if (content == null) {
throw new IOException("Cache is null, no content to write."); throw new IOException("Cache is null, no content to write.");
} }
mContent.writeTo(pStream); content.writeTo(pStream);
} }
/** /**
@@ -120,7 +118,7 @@ class CachedResponseImpl implements CachedResponse {
* @return an array of {@code String}s * @return an array of {@code String}s
*/ */
public String[] getHeaderNames() { public String[] getHeaderNames() {
Set<String> headers = mHeaders.keySet(); Set<String> headers = this.headers.keySet();
return headers.toArray(new String[headers.size()]); return headers.toArray(new String[headers.size()]);
} }
@@ -133,7 +131,7 @@ class CachedResponseImpl implements CachedResponse {
* such header in this response. * such header in this response.
*/ */
public String[] getHeaderValues(final String pHeaderName) { public String[] getHeaderValues(final String pHeaderName) {
List<String> values = mHeaders.get(pHeaderName); List<String> values = headers.get(pHeaderName);
if (values == null) { if (values == null) {
return null; return null;
} }
@@ -153,13 +151,13 @@ class CachedResponseImpl implements CachedResponse {
* such header in this response. * such header in this response.
*/ */
public String getHeaderValue(final String pHeaderName) { public String getHeaderValue(final String pHeaderName) {
List<String> values = mHeaders.get(pHeaderName); List<String> values = headers.get(pHeaderName);
return (values != null && values.size() > 0) ? values.get(0) : null; return (values != null && values.size() > 0) ? values.get(0) : null;
} }
public int size() { public int size() {
// mContent.size() is exact size in bytes, mHeadersSize is an estimate // content.size() is exact size in bytes, headersSize is an estimate
return (mContent != null ? mContent.size() : 0) + mHeadersSize; return (content != null ? content.size() : 0) + headersSize;
} }
public boolean equals(final Object pOther) { public boolean equals(final Object pOther) {
@@ -180,9 +178,9 @@ class CachedResponseImpl implements CachedResponse {
} }
private boolean equalsImpl(final CachedResponseImpl pOther) { private boolean equalsImpl(final CachedResponseImpl pOther) {
return mHeadersSize == pOther.mHeadersSize && return headersSize == pOther.headersSize &&
(mContent == null ? pOther.mContent == null : mContent.equals(pOther.mContent)) && (content == null ? pOther.content == null : content.equals(pOther.content)) &&
mHeaders.equals(pOther.mHeaders); headers.equals(pOther.headers);
} }
private boolean equalsGeneric(final CachedResponse pOther) { private boolean equalsGeneric(final CachedResponse pOther) {
@@ -212,9 +210,9 @@ class CachedResponseImpl implements CachedResponse {
public int hashCode() { public int hashCode() {
int result; int result;
result = mHeaders.hashCode(); result = headers.hashCode();
result = 29 * result + mHeadersSize; result = 29 * result + headersSize;
result = 37 * result + (mContent != null ? mContent.hashCode() : 0); result = 37 * result + (content != null ? content.hashCode() : 0);
return result; return result;
} }
} }
@@ -13,13 +13,13 @@ import java.util.Map;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/ClientCacheRequest.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/ClientCacheRequest.java#1 $
*/ */
public final class ClientCacheRequest extends AbstractCacheRequest { public final class ClientCacheRequest extends AbstractCacheRequest {
private Map<String, List<String>> mParameters; private Map<String, List<String>> parameters;
private Map<String, List<String>> mHeaders; private Map<String, List<String>> headers;
public ClientCacheRequest(final URI pRequestURI,final Map<String, List<String>> pParameters, final Map<String, List<String>> pHeaders) { public ClientCacheRequest(final URI pRequestURI,final Map<String, List<String>> pParameters, final Map<String, List<String>> pHeaders) {
super(pRequestURI, "GET"); // TODO: Consider supporting more than get? At least HEAD and OPTIONS... super(pRequestURI, "GET"); // TODO: Consider supporting more than get? At least HEAD and OPTIONS...
mParameters = normalizeMap(pParameters); parameters = normalizeMap(pParameters);
mHeaders = normalizeMap(pHeaders); headers = normalizeMap(pHeaders);
} }
private <K, V> Map<K, V> normalizeMap(Map<K, V> pMap) { private <K, V> Map<K, V> normalizeMap(Map<K, V> pMap) {
@@ -27,11 +27,11 @@ public final class ClientCacheRequest extends AbstractCacheRequest {
} }
public Map<String, List<String>> getParameters() { public Map<String, List<String>> getParameters() {
return mParameters; return parameters;
} }
public Map<String, List<String>> getHeaders() { public Map<String, List<String>> getHeaders() {
return mHeaders; return headers;
} }
public String getServerName() { public String getServerName() {
@@ -30,6 +30,7 @@ package com.twelvemonkeys.servlet.cache;
import com.twelvemonkeys.io.FileUtil; import com.twelvemonkeys.io.FileUtil;
import com.twelvemonkeys.lang.StringUtil; import com.twelvemonkeys.lang.StringUtil;
import com.twelvemonkeys.lang.Validate;
import com.twelvemonkeys.net.MIMEUtil; import com.twelvemonkeys.net.MIMEUtil;
import com.twelvemonkeys.net.NetUtil; import com.twelvemonkeys.net.NetUtil;
import com.twelvemonkeys.util.LRUHashMap; import com.twelvemonkeys.util.LRUHashMap;
@@ -153,30 +154,30 @@ public class HTTPCache {
/** /**
* The directory used for the disk-based cache * The directory used for the disk-based cache
*/ */
private File mTempDir; private File tempDir;
/** /**
* Indicates wether the disk-based cache should be deleted when the * Indicates wether the disk-based cache should be deleted when the
* container shuts down/VM exits * container shuts down/VM exits
*/ */
private boolean mDeleteCacheOnExit; private boolean deleteCacheOnExit;
/** /**
* In-memory content cache * In-memory content cache
*/ */
private final Map<String, CachedResponse> mContentCache; private final Map<String, CachedResponse> contentCache;
/** /**
* In-memory enity cache * In-memory enity cache
*/ */
private final Map<String, CachedEntity> mEntityCache; private final Map<String, CachedEntity> entityCache;
/** /**
* In-memory varyiation-info cache * In-memory varyiation-info cache
*/ */
private final Map<String, Properties> mVaryCache; private final Map<String, Properties> varyCache;
private long mDefaultExpiryTime = -1; private long defaultExpiryTime = -1;
private final Logger mLogger; private final Logger logger;
// Internal constructor for sublcasses only // Internal constructor for sublcasses only
protected HTTPCache( protected HTTPCache(
@@ -187,44 +188,33 @@ public class HTTPCache {
final boolean pDeleteCacheOnExit, final boolean pDeleteCacheOnExit,
final Logger pLogger final Logger pLogger
) { ) {
if (pTempFolder == null) { Validate.notNull(pTempFolder, "temp folder");
throw new IllegalArgumentException("temp folder == null"); Validate.isTrue(pTempFolder.exists() || pTempFolder.mkdirs(), pTempFolder.getAbsolutePath(), "Could not create required temp directory: %s");
} Validate.isTrue(pTempFolder.canRead() && pTempFolder.canWrite(), pTempFolder.getAbsolutePath(), "Must have read/write access to temp folder: %s");
if (!pTempFolder.exists() && !pTempFolder.mkdirs()) {
throw new IllegalArgumentException("Could not create required temp directory: " + mTempDir.getAbsolutePath());
}
if (!(pTempFolder.canRead() && pTempFolder.canWrite())) {
throw new IllegalArgumentException("Must have read/write access to temp folder: " + mTempDir.getAbsolutePath());
}
if (pDefaultCacheExpiryTime < 0) {
throw new IllegalArgumentException("Negative expiry time");
}
if (pMaxMemCacheSize < 0) {
throw new IllegalArgumentException("Negative maximum memory cache size");
}
if (pMaxCachedEntites < 0) {
throw new IllegalArgumentException("Negative maximum number of cached entries");
}
mDefaultExpiryTime = pDefaultCacheExpiryTime; Validate.isTrue(pDefaultCacheExpiryTime >= 0, pDefaultCacheExpiryTime, "Negative expiry time: %d");
Validate.isTrue(pMaxMemCacheSize >= 0, pDefaultCacheExpiryTime, "Negative maximum memory cache size: %d");
Validate.isTrue(pMaxCachedEntites >= 0, pDefaultCacheExpiryTime, "Negative maximum number of cached entries: %d");
defaultExpiryTime = pDefaultCacheExpiryTime;
if (pMaxMemCacheSize > 0) { if (pMaxMemCacheSize > 0) {
// Map backing = new SizedLRUMap(pMaxMemCacheSize); // size in bytes // Map backing = new SizedLRUMap(pMaxMemCacheSize); // size in bytes
// mContentCache = new TimeoutMap(backing, null, pDefaultCacheExpiryTime); // contentCache = new TimeoutMap(backing, null, pDefaultCacheExpiryTime);
mContentCache = new SizedLRUMap<String, CachedResponse>(pMaxMemCacheSize); // size in bytes contentCache = new SizedLRUMap<String, CachedResponse>(pMaxMemCacheSize); // size in bytes
} }
else { else {
mContentCache = new NullMap<String, CachedResponse>(); contentCache = new NullMap<String, CachedResponse>();
} }
mEntityCache = new LRUHashMap<String, CachedEntity>(pMaxCachedEntites); entityCache = new LRUHashMap<String, CachedEntity>(pMaxCachedEntites);
mVaryCache = new LRUHashMap<String, Properties>(pMaxCachedEntites); varyCache = new LRUHashMap<String, Properties>(pMaxCachedEntites);
mDeleteCacheOnExit = pDeleteCacheOnExit; deleteCacheOnExit = pDeleteCacheOnExit;
mTempDir = pTempFolder; tempDir = pTempFolder;
mLogger = pLogger != null ? pLogger : Logger.getLogger(getClass().getName()); logger = pLogger != null ? pLogger : Logger.getLogger(getClass().getName());
} }
/** /**
@@ -289,19 +279,15 @@ public class HTTPCache {
} }
private static File getTempFolder(String pName, ServletContext pContext) { private static File getTempFolder(String pName, ServletContext pContext) {
if (pName == null) { Validate.notNull(pName, "name");
throw new IllegalArgumentException("name == null"); Validate.isTrue(!StringUtil.isEmpty(pName), pName, "empty name: '%s'");
} Validate.notNull(pContext, "context");
if (pName.trim().length() == 0) {
throw new IllegalArgumentException("Empty name");
}
if (pContext == null) {
throw new IllegalArgumentException("servlet context == null");
}
File tempRoot = (File) pContext.getAttribute("javax.servlet.context.tempdir"); File tempRoot = (File) pContext.getAttribute("javax.servlet.context.tempdir");
if (tempRoot == null) { if (tempRoot == null) {
throw new IllegalStateException("Missing context attribute \"javax.servlet.context.tempdir\""); throw new IllegalStateException("Missing context attribute \"javax.servlet.context.tempdir\"");
} }
return new File(tempRoot, pName); return new File(tempRoot, pName);
} }
@@ -309,36 +295,36 @@ public class HTTPCache {
StringBuilder buf = new StringBuilder(getClass().getSimpleName()); StringBuilder buf = new StringBuilder(getClass().getSimpleName());
buf.append("["); buf.append("[");
buf.append("Temp dir: "); buf.append("Temp dir: ");
buf.append(mTempDir.getAbsolutePath()); buf.append(tempDir.getAbsolutePath());
if (mDeleteCacheOnExit) { if (deleteCacheOnExit) {
buf.append(" (non-persistent)"); buf.append(" (non-persistent)");
} }
else { else {
buf.append(" (persistent)"); buf.append(" (persistent)");
} }
buf.append(", EntityCache: {"); buf.append(", EntityCache: {");
buf.append(mEntityCache.size()); buf.append(entityCache.size());
buf.append(" entries in a "); buf.append(" entries in a ");
buf.append(mEntityCache.getClass().getName()); buf.append(entityCache.getClass().getName());
buf.append("}, VaryCache: {"); buf.append("}, VaryCache: {");
buf.append(mVaryCache.size()); buf.append(varyCache.size());
buf.append(" entries in a "); buf.append(" entries in a ");
buf.append(mVaryCache.getClass().getName()); buf.append(varyCache.getClass().getName());
buf.append("}, ContentCache: {"); buf.append("}, ContentCache: {");
buf.append(mContentCache.size()); buf.append(contentCache.size());
buf.append(" entries in a "); buf.append(" entries in a ");
buf.append(mContentCache.getClass().getName()); buf.append(contentCache.getClass().getName());
buf.append("}]"); buf.append("}]");
return buf.toString(); return buf.toString();
} }
void log(final String pMessage) { void log(final String pMessage) {
mLogger.log(Level.INFO, pMessage); logger.log(Level.INFO, pMessage);
} }
void log(final String pMessage, Throwable pException) { void log(final String pMessage, Throwable pException) {
mLogger.log(Level.WARNING, pMessage, pException); logger.log(Level.WARNING, pMessage, pException);
} }
/** /**
@@ -363,16 +349,16 @@ public class HTTPCache {
// Get/create cached entity // Get/create cached entity
CachedEntity cached; CachedEntity cached;
synchronized (mEntityCache) { synchronized (entityCache) {
cached = mEntityCache.get(cacheURI); cached = entityCache.get(cacheURI);
if (cached == null) { if (cached == null) {
cached = new CachedEntityImpl(cacheURI, this); cached = new CachedEntityImpl(cacheURI, this);
mEntityCache.put(cacheURI, cached); entityCache.put(cacheURI, cached);
} }
} }
// else if (not cached || stale), resolve through wrapped (caching) response // else if (not cached ||stale), resolve through wrapped (caching) response
// else render to response // else render to response
// TODO: This is a bottleneck for uncachable resources. Should not // TODO: This is a bottleneck for uncachable resources. Should not
@@ -412,11 +398,11 @@ public class HTTPCache {
// Get/create cached entity // Get/create cached entity
CachedEntity cached; CachedEntity cached;
synchronized (mEntityCache) { synchronized (entityCache) {
cached = mEntityCache.get(cacheURI); cached = entityCache.get(cacheURI);
if (cached != null) { if (cached != null) {
// TODO; Remove all variants // TODO; Remove all variants
mEntityCache.remove(cacheURI); entityCache.remove(cacheURI);
} }
} }
@@ -531,7 +517,7 @@ public class HTTPCache {
File file = null; File file = null;
// Get base dir // Get base dir
File base = new File(mTempDir, "./" + pCacheURI); File base = new File(tempDir, "./" + pCacheURI);
final String basePath = base.getAbsolutePath(); final String basePath = base.getAbsolutePath();
File directory = base.getParentFile(); File directory = base.getParentFile();
@@ -603,7 +589,7 @@ public class HTTPCache {
synchronized (pVariations) { synchronized (pVariations) {
try { try {
File file = getVaryPropertiesFile(pCacheURI); File file = getVaryPropertiesFile(pCacheURI);
if (!file.exists() && mDeleteCacheOnExit) { if (!file.exists() && deleteCacheOnExit) {
file.deleteOnExit(); file.deleteOnExit();
} }
@@ -624,11 +610,11 @@ public class HTTPCache {
private Properties getVaryProperties(final String pCacheURI) { private Properties getVaryProperties(final String pCacheURI) {
Properties variations; Properties variations;
synchronized (mVaryCache) { synchronized (varyCache) {
variations = mVaryCache.get(pCacheURI); variations = varyCache.get(pCacheURI);
if (variations == null) { if (variations == null) {
variations = loadVaryProperties(pCacheURI); variations = loadVaryProperties(pCacheURI);
mVaryCache.put(pCacheURI, variations); varyCache.put(pCacheURI, variations);
} }
} }
@@ -657,7 +643,7 @@ public class HTTPCache {
} }
private File getVaryPropertiesFile(final String pCacheURI) { private File getVaryPropertiesFile(final String pCacheURI) {
return new File(mTempDir, "./" + pCacheURI + FILE_EXT_VARY); return new File(tempDir, "./" + pCacheURI + FILE_EXT_VARY);
} }
private static String generateCacheURI(final CacheRequest pRequest) { private static String generateCacheURI(final CacheRequest pRequest) {
@@ -769,18 +755,18 @@ public class HTTPCache {
extension = "[NULL]"; extension = "[NULL]";
} }
synchronized (mContentCache) { synchronized (contentCache) {
mContentCache.put(pCacheURI + '.' + extension, pCachedResponse); contentCache.put(pCacheURI + '.' + extension, pCachedResponse);
// This will be the default version // This will be the default version
if (!mContentCache.containsKey(pCacheURI)) { if (!contentCache.containsKey(pCacheURI)) {
mContentCache.put(pCacheURI, pCachedResponse); contentCache.put(pCacheURI, pCachedResponse);
} }
} }
// Write the cached content to disk // Write the cached content to disk
File content = new File(mTempDir, "./" + pCacheURI + '.' + extension); File content = new File(tempDir, "./" + pCacheURI + '.' + extension);
if (mDeleteCacheOnExit && !content.exists()) { if (deleteCacheOnExit && !content.exists()) {
content.deleteOnExit(); content.deleteOnExit();
} }
@@ -809,7 +795,7 @@ public class HTTPCache {
// Write the cached headers to disk (in pseudo-properties-format) // Write the cached headers to disk (in pseudo-properties-format)
File headers = new File(content.getAbsolutePath() + FILE_EXT_HEADERS); File headers = new File(content.getAbsolutePath() + FILE_EXT_HEADERS);
if (mDeleteCacheOnExit && !headers.exists()) { if (deleteCacheOnExit && !headers.exists()) {
headers.deleteOnExit(); headers.deleteOnExit();
} }
@@ -872,13 +858,13 @@ public class HTTPCache {
String extension = getVaryExtension(pCacheURI, pRequest); String extension = getVaryExtension(pCacheURI, pRequest);
CachedResponse response; CachedResponse response;
synchronized (mContentCache) { synchronized (contentCache) {
// System.out.println(" ## HTTPCache ## Looking up content with ext: \"" + extension + "\" from memory cache (" + mContentCache /*.size()*/ + " entries)..."); // System.out.println(" ## HTTPCache ## Looking up content with ext: \"" + extension + "\" from memory cache (" + contentCache /*.size()*/ + " entries)...");
if ("ANY".equals(extension)) { if ("ANY".equals(extension)) {
response = mContentCache.get(pCacheURI); response = contentCache.get(pCacheURI);
} }
else { else {
response = mContentCache.get(pCacheURI + '.' + extension); response = contentCache.get(pCacheURI + '.' + extension);
} }
if (response == null) { if (response == null) {
@@ -932,7 +918,7 @@ public class HTTPCache {
} }
response = new CachedResponseImpl(STATUS_OK, headerMap, headerSize, contents); response = new CachedResponseImpl(STATUS_OK, headerMap, headerSize, contents);
mContentCache.put(pCacheURI + '.' + FileUtil.getExtension(content), response); contentCache.put(pCacheURI + '.' + FileUtil.getExtension(content), response);
} }
} }
catch (IOException e) { catch (IOException e) {
@@ -997,7 +983,7 @@ public class HTTPCache {
// If Cache-Control: max-age is present, use it, otherwise default // If Cache-Control: max-age is present, use it, otherwise default
int maxAge = getIntHeader(response, HEADER_CACHE_CONTROL, "max-age"); int maxAge = getIntHeader(response, HEADER_CACHE_CONTROL, "max-age");
if (maxAge == -1) { if (maxAge == -1) {
expires = lastModified + mDefaultExpiryTime; expires = lastModified + defaultExpiryTime;
//// System.out.println(" ## HTTPCache ## Expires is " + NetUtil.formatHTTPDate(expires) + ", using lastModified + defaultExpiry"); //// System.out.println(" ## HTTPCache ## Expires is " + NetUtil.formatHTTPDate(expires) + ", using lastModified + defaultExpiry");
} }
else { else {
@@ -55,16 +55,16 @@ import java.util.Map;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/SerlvetCacheResponseWrapper.java#2 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/SerlvetCacheResponseWrapper.java#2 $
*/ */
class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper { class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
private ServletResponseStreamDelegate mStreamDelegate; private ServletResponseStreamDelegate streamDelegate;
private CacheResponse mCacheResponse; private CacheResponse cacheResponse;
private Boolean mCachable; private Boolean cachable;
private int mStatus; private int status;
public SerlvetCacheResponseWrapper(final HttpServletResponse pServletResponse, final CacheResponse pResponse) { public SerlvetCacheResponseWrapper(final HttpServletResponse pServletResponse, final CacheResponse pResponse) {
super(pServletResponse); super(pServletResponse);
mCacheResponse = pResponse; cacheResponse = pResponse;
init(); init();
} }
@@ -76,18 +76,18 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
methods below. methods below.
*/ */
private void init() { private void init() {
mCachable = null; cachable = null;
mStatus = SC_OK; status = SC_OK;
mStreamDelegate = new ServletResponseStreamDelegate(this) { streamDelegate = new ServletResponseStreamDelegate(this) {
protected OutputStream createOutputStream() throws IOException { protected OutputStream createOutputStream() throws IOException {
// Test if this request is really cachable, otherwise, // Test if this request is really cachable, otherwise,
// just write through to underlying response, and don't cache // just write through to underlying response, and don't cache
if (isCachable()) { if (isCachable()) {
return mCacheResponse.getOutputStream(); return cacheResponse.getOutputStream();
} }
else { else {
// TODO: We need to tell the cache about this, somehow... // TODO: We need to tell the cache about this, somehow...
writeHeaders(mCacheResponse, (HttpServletResponse) getResponse()); writeHeaders(cacheResponse, (HttpServletResponse) getResponse());
return super.getOutputStream(); return super.getOutputStream();
} }
} }
@@ -111,21 +111,21 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
public boolean isCachable() { public boolean isCachable() {
// NOTE: Intentionally not synchronized // NOTE: Intentionally not synchronized
if (mCachable == null) { if (cachable == null) {
mCachable = isCachableImpl(); cachable = isCachableImpl();
} }
return mCachable; return cachable;
} }
private boolean isCachableImpl() { private boolean isCachableImpl() {
// TODO: This code is duped in the cache... // TODO: This code is duped in the cache...
if (mStatus != SC_OK) { if (status != SC_OK) {
return false; return false;
} }
// Vary: * // Vary: *
List<String> values = mCacheResponse.getHeaders().get(HTTPCache.HEADER_VARY); List<String> values = cacheResponse.getHeaders().get(HTTPCache.HEADER_VARY);
if (values != null) { if (values != null) {
for (String value : values) { for (String value : values) {
if ("*".equals(value)) { if ("*".equals(value)) {
@@ -135,7 +135,7 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
} }
// Cache-Control: no-cache, no-store, must-revalidate // Cache-Control: no-cache, no-store, must-revalidate
values = mCacheResponse.getHeaders().get(HTTPCache.HEADER_CACHE_CONTROL); values = cacheResponse.getHeaders().get(HTTPCache.HEADER_CACHE_CONTROL);
if (values != null) { if (values != null) {
for (String value : values) { for (String value : values) {
if (StringUtil.contains(value, "no-cache") if (StringUtil.contains(value, "no-cache")
@@ -147,7 +147,7 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
} }
// Pragma: no-cache // Pragma: no-cache
values = mCacheResponse.getHeaders().get(HTTPCache.HEADER_PRAGMA); values = cacheResponse.getHeaders().get(HTTPCache.HEADER_PRAGMA);
if (values != null) { if (values != null) {
for (String value : values) { for (String value : values) {
if (StringUtil.contains(value, "no-cache")) { if (StringUtil.contains(value, "no-cache")) {
@@ -160,16 +160,16 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
} }
public void flushBuffer() throws IOException { public void flushBuffer() throws IOException {
mStreamDelegate.flushBuffer(); streamDelegate.flushBuffer();
} }
public void resetBuffer() { public void resetBuffer() {
// Servlet 2.3 // Servlet 2.3
mStreamDelegate.resetBuffer(); streamDelegate.resetBuffer();
} }
public void reset() { public void reset() {
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.reset(); super.reset();
} }
// No else, might be cachable after all.. // No else, might be cachable after all..
@@ -177,26 +177,26 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
} }
public ServletOutputStream getOutputStream() throws IOException { public ServletOutputStream getOutputStream() throws IOException {
return mStreamDelegate.getOutputStream(); return streamDelegate.getOutputStream();
} }
public PrintWriter getWriter() throws IOException { public PrintWriter getWriter() throws IOException {
return mStreamDelegate.getWriter(); return streamDelegate.getWriter();
} }
public boolean containsHeader(String name) { public boolean containsHeader(String name) {
return mCacheResponse.getHeaders().get(name) != null; return cacheResponse.getHeaders().get(name) != null;
} }
public void sendError(int pStatusCode, String msg) throws IOException { public void sendError(int pStatusCode, String msg) throws IOException {
// NOT cachable // NOT cachable
mStatus = pStatusCode; status = pStatusCode;
super.sendError(pStatusCode, msg); super.sendError(pStatusCode, msg);
} }
public void sendError(int pStatusCode) throws IOException { public void sendError(int pStatusCode) throws IOException {
// NOT cachable // NOT cachable
mStatus = pStatusCode; status = pStatusCode;
super.sendError(pStatusCode); super.sendError(pStatusCode);
} }
@@ -208,63 +208,63 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
public void setStatus(int pStatusCode) { public void setStatus(int pStatusCode) {
// NOT cachable unless pStatusCode == 200 (or a FEW others?) // NOT cachable unless pStatusCode == 200 (or a FEW others?)
if (pStatusCode != SC_OK) { if (pStatusCode != SC_OK) {
mStatus = pStatusCode; status = pStatusCode;
super.setStatus(pStatusCode); super.setStatus(pStatusCode);
} }
} }
public void sendRedirect(String pLocation) throws IOException { public void sendRedirect(String pLocation) throws IOException {
// NOT cachable // NOT cachable
mStatus = SC_MOVED_TEMPORARILY; status = SC_MOVED_TEMPORARILY;
super.sendRedirect(pLocation); super.sendRedirect(pLocation);
} }
public void setDateHeader(String pName, long pValue) { public void setDateHeader(String pName, long pValue) {
// If in write-trough-mode, set headers directly // If in write-trough-mode, set headers directly
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.setDateHeader(pName, pValue); super.setDateHeader(pName, pValue);
} }
mCacheResponse.setHeader(pName, NetUtil.formatHTTPDate(pValue)); cacheResponse.setHeader(pName, NetUtil.formatHTTPDate(pValue));
} }
public void addDateHeader(String pName, long pValue) { public void addDateHeader(String pName, long pValue) {
// If in write-trough-mode, set headers directly // If in write-trough-mode, set headers directly
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.addDateHeader(pName, pValue); super.addDateHeader(pName, pValue);
} }
mCacheResponse.addHeader(pName, NetUtil.formatHTTPDate(pValue)); cacheResponse.addHeader(pName, NetUtil.formatHTTPDate(pValue));
} }
public void setHeader(String pName, String pValue) { public void setHeader(String pName, String pValue) {
// If in write-trough-mode, set headers directly // If in write-trough-mode, set headers directly
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.setHeader(pName, pValue); super.setHeader(pName, pValue);
} }
mCacheResponse.setHeader(pName, pValue); cacheResponse.setHeader(pName, pValue);
} }
public void addHeader(String pName, String pValue) { public void addHeader(String pName, String pValue) {
// If in write-trough-mode, set headers directly // If in write-trough-mode, set headers directly
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.addHeader(pName, pValue); super.addHeader(pName, pValue);
} }
mCacheResponse.addHeader(pName, pValue); cacheResponse.addHeader(pName, pValue);
} }
public void setIntHeader(String pName, int pValue) { public void setIntHeader(String pName, int pValue) {
// If in write-trough-mode, set headers directly // If in write-trough-mode, set headers directly
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.setIntHeader(pName, pValue); super.setIntHeader(pName, pValue);
} }
mCacheResponse.setHeader(pName, String.valueOf(pValue)); cacheResponse.setHeader(pName, String.valueOf(pValue));
} }
public void addIntHeader(String pName, int pValue) { public void addIntHeader(String pName, int pValue) {
// If in write-trough-mode, set headers directly // If in write-trough-mode, set headers directly
if (Boolean.FALSE.equals(mCachable)) { if (Boolean.FALSE.equals(cachable)) {
super.addIntHeader(pName, pValue); super.addIntHeader(pName, pValue);
} }
mCacheResponse.addHeader(pName, String.valueOf(pValue)); cacheResponse.addHeader(pName, String.valueOf(pValue));
} }
public final void setContentType(String type) { public final void setContentType(String type) {
@@ -15,42 +15,42 @@ import java.util.Map;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/ServletCacheRequest.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/ServletCacheRequest.java#1 $
*/ */
public final class ServletCacheRequest extends AbstractCacheRequest { public final class ServletCacheRequest extends AbstractCacheRequest {
private final HttpServletRequest mRequest; private final HttpServletRequest request;
private Map<String, List<String>> mHeaders; private Map<String, List<String>> headers;
private Map<String, List<String>> mParameters; private Map<String, List<String>> parameters;
protected ServletCacheRequest(final HttpServletRequest pRequest) { protected ServletCacheRequest(final HttpServletRequest pRequest) {
super(URI.create(pRequest.getRequestURI()), pRequest.getMethod()); super(URI.create(pRequest.getRequestURI()), pRequest.getMethod());
mRequest = pRequest; request = pRequest;
} }
public Map<String, List<String>> getHeaders() { public Map<String, List<String>> getHeaders() {
if (mHeaders == null) { if (headers == null) {
mHeaders = ServletUtil.headersAsMap(mRequest); headers = ServletUtil.headersAsMap(request);
} }
return mHeaders; return headers;
} }
public Map<String, List<String>> getParameters() { public Map<String, List<String>> getParameters() {
if (mParameters == null) { if (parameters == null) {
mParameters = ServletUtil.parametersAsMap(mRequest); parameters = ServletUtil.parametersAsMap(request);
} }
return mParameters; return parameters;
} }
public String getServerName() { public String getServerName() {
return mRequest.getServerName(); return request.getServerName();
} }
public int getServerPort() { public int getServerPort() {
return mRequest.getServerPort(); return request.getServerPort();
} }
HttpServletRequest getRequest() { HttpServletRequest getRequest() {
return mRequest; return request;
} }
} }
@@ -13,22 +13,22 @@ import java.io.IOException;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/ServletResponseResolver.java#2 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/ServletResponseResolver.java#2 $
*/ */
final class ServletResponseResolver implements ResponseResolver { final class ServletResponseResolver implements ResponseResolver {
final private ServletCacheRequest mRequest; final private ServletCacheRequest request;
final private ServletCacheResponse mResponse; final private ServletCacheResponse response;
final private FilterChain mChain; final private FilterChain chain;
ServletResponseResolver(final ServletCacheRequest pRequest, final ServletCacheResponse pResponse, final FilterChain pChain) { ServletResponseResolver(final ServletCacheRequest pRequest, final ServletCacheResponse pResponse, final FilterChain pChain) {
mRequest = pRequest; request = pRequest;
mResponse = pResponse; response = pResponse;
mChain = pChain; chain = pChain;
} }
public void resolve(final CacheRequest pRequest, final CacheResponse pResponse) throws IOException, CacheException { public void resolve(final CacheRequest pRequest, final CacheResponse pResponse) throws IOException, CacheException {
// Need only wrap if pResponse is not mResponse... // Need only wrap if pResponse is not response...
HttpServletResponse response = pResponse == mResponse ? mResponse.getResponse() : new SerlvetCacheResponseWrapper(mResponse.getResponse(), pResponse); HttpServletResponse response = pResponse == this.response ? this.response.getResponse() : new SerlvetCacheResponseWrapper(this.response.getResponse(), pResponse);
try { try {
mChain.doFilter(mRequest.getRequest(), response); chain.doFilter(request.getRequest(), response);
} }
catch (ServletException e) { catch (ServletException e) {
throw new CacheException(e); throw new CacheException(e);
@@ -45,19 +45,19 @@ import java.util.Map;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/WritableCachedResponseImpl.java#3 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/WritableCachedResponseImpl.java#3 $
*/ */
class WritableCachedResponseImpl implements WritableCachedResponse { class WritableCachedResponseImpl implements WritableCachedResponse {
private final CachedResponseImpl mCachedResponse; private final CachedResponseImpl cachedResponse;
/** /**
* Creates a {@code WritableCachedResponseImpl}. * Creates a {@code WritableCachedResponseImpl}.
*/ */
protected WritableCachedResponseImpl() { protected WritableCachedResponseImpl() {
mCachedResponse = new CachedResponseImpl(); cachedResponse = new CachedResponseImpl();
// Hmmm.. // Hmmm..
setHeader(HTTPCache.HEADER_CACHED_TIME, NetUtil.formatHTTPDate(System.currentTimeMillis())); setHeader(HTTPCache.HEADER_CACHED_TIME, NetUtil.formatHTTPDate(System.currentTimeMillis()));
} }
public CachedResponse getCachedResponse() { public CachedResponse getCachedResponse() {
return mCachedResponse; return cachedResponse;
} }
public void setHeader(String pName, String pValue) { public void setHeader(String pName, String pValue) {
@@ -69,7 +69,7 @@ class WritableCachedResponseImpl implements WritableCachedResponse {
} }
public Map<String, List<String>> getHeaders() { public Map<String, List<String>> getHeaders() {
return mCachedResponse.mHeaders; return cachedResponse.headers;
} }
/** /**
@@ -83,7 +83,7 @@ class WritableCachedResponseImpl implements WritableCachedResponse {
// If adding, get list and append, otherwise replace list // If adding, get list and append, otherwise replace list
List<String> values = null; List<String> values = null;
if (pAdd) { if (pAdd) {
values = mCachedResponse.mHeaders.get(pName); values = cachedResponse.headers.get(pName);
} }
if (values == null) { if (values == null) {
@@ -91,18 +91,18 @@ class WritableCachedResponseImpl implements WritableCachedResponse {
if (pAdd) { if (pAdd) {
// Add length of pName // Add length of pName
mCachedResponse.mHeadersSize += (pName != null ? pName.length() : 0); cachedResponse.headersSize += (pName != null ? pName.length() : 0);
} }
else { else {
// Remove length of potential replaced old values + pName // Remove length of potential replaced old values + pName
String[] oldValues = getHeaderValues(pName); String[] oldValues = getHeaderValues(pName);
if (oldValues != null) { if (oldValues != null) {
for (String oldValue : oldValues) { for (String oldValue : oldValues) {
mCachedResponse.mHeadersSize -= oldValue.length(); cachedResponse.headersSize -= oldValue.length();
} }
} }
else { else {
mCachedResponse.mHeadersSize += (pName != null ? pName.length() : 0); cachedResponse.headersSize += (pName != null ? pName.length() : 0);
} }
} }
} }
@@ -112,31 +112,31 @@ class WritableCachedResponseImpl implements WritableCachedResponse {
values.add(pValue); values.add(pValue);
// Add length of pValue // Add length of pValue
mCachedResponse.mHeadersSize += pValue.length(); cachedResponse.headersSize += pValue.length();
} }
// Always add to headers // Always add to headers
mCachedResponse.mHeaders.put(pName, values); cachedResponse.headers.put(pName, values);
} }
public OutputStream getOutputStream() { public OutputStream getOutputStream() {
// TODO: Hmm.. Smells like DCL..? // TODO: Hmm.. Smells like DCL..?
if (mCachedResponse.mContent == null) { if (cachedResponse.content == null) {
createOutputStream(); createOutputStream();
} }
return mCachedResponse.mContent; return cachedResponse.content;
} }
public void setStatus(int pStatusCode) { public void setStatus(int pStatusCode) {
mCachedResponse.mStatus = pStatusCode; cachedResponse.status = pStatusCode;
} }
public int getStatus() { public int getStatus() {
return mCachedResponse.getStatus(); return cachedResponse.getStatus();
} }
private synchronized void createOutputStream() { private synchronized void createOutputStream() {
ByteArrayOutputStream cache = mCachedResponse.mContent; ByteArrayOutputStream cache = cachedResponse.content;
if (cache == null) { if (cache == null) {
String contentLengthStr = getHeaderValue("Content-Length"); String contentLengthStr = getHeaderValue("Content-Length");
if (contentLengthStr != null) { if (contentLengthStr != null) {
@@ -146,43 +146,43 @@ class WritableCachedResponseImpl implements WritableCachedResponse {
else { else {
cache = new FastByteArrayOutputStream(1024); cache = new FastByteArrayOutputStream(1024);
} }
mCachedResponse.mContent = cache; cachedResponse.content = cache;
} }
} }
public void writeHeadersTo(CacheResponse pResponse) { public void writeHeadersTo(CacheResponse pResponse) {
mCachedResponse.writeHeadersTo(pResponse); cachedResponse.writeHeadersTo(pResponse);
} }
public void writeContentsTo(OutputStream pStream) throws IOException { public void writeContentsTo(OutputStream pStream) throws IOException {
mCachedResponse.writeContentsTo(pStream); cachedResponse.writeContentsTo(pStream);
} }
public String[] getHeaderNames() { public String[] getHeaderNames() {
return mCachedResponse.getHeaderNames(); return cachedResponse.getHeaderNames();
} }
public String[] getHeaderValues(String pHeaderName) { public String[] getHeaderValues(String pHeaderName) {
return mCachedResponse.getHeaderValues(pHeaderName); return cachedResponse.getHeaderValues(pHeaderName);
} }
public String getHeaderValue(String pHeaderName) { public String getHeaderValue(String pHeaderName) {
return mCachedResponse.getHeaderValue(pHeaderName); return cachedResponse.getHeaderValue(pHeaderName);
} }
public int size() { public int size() {
return mCachedResponse.size(); return cachedResponse.size();
} }
public boolean equals(Object pOther) { public boolean equals(Object pOther) {
if (pOther instanceof WritableCachedResponse) { if (pOther instanceof WritableCachedResponse) {
// Take advantage of faster implementation // Take advantage of faster implementation
return mCachedResponse.equals(((WritableCachedResponse) pOther).getCachedResponse()); return cachedResponse.equals(((WritableCachedResponse) pOther).getCachedResponse());
} }
return mCachedResponse.equals(pOther); return cachedResponse.equals(pOther);
} }
public int hashCode() { public int hashCode() {
return mCachedResponse.hashCode(); return cachedResponse.hashCode();
} }
} }
@@ -54,8 +54,8 @@ import java.net.MalformedURLException;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/FileUploadFilter.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/FileUploadFilter.java#1 $
*/ */
public class FileUploadFilter extends GenericFilter { public class FileUploadFilter extends GenericFilter {
private File mUploadDir; private File uploadDir;
private long mMaxFileSize = 1024 * 1024; // 1 MByte private long maxFileSize = 1024 * 1024; // 1 MByte
/** /**
* This method is called by the server before the filter goes into service, * This method is called by the server before the filter goes into service,
@@ -66,17 +66,19 @@ public class FileUploadFilter extends GenericFilter {
public void init() throws ServletException { public void init() throws ServletException {
// Get the name of the upload directory. // Get the name of the upload directory.
String uploadDirParam = getInitParameter("uploadDir"); String uploadDirParam = getInitParameter("uploadDir");
if (!StringUtil.isEmpty(uploadDirParam)) { if (!StringUtil.isEmpty(uploadDirParam)) {
try { try {
URL uploadDirURL = getServletContext().getResource(uploadDirParam); URL uploadDirURL = getServletContext().getResource(uploadDirParam);
mUploadDir = FileUtil.toFile(uploadDirURL); uploadDir = FileUtil.toFile(uploadDirURL);
} }
catch (MalformedURLException e) { catch (MalformedURLException e) {
throw new ServletException(e.getMessage(), e); throw new ServletException(e.getMessage(), e);
} }
} }
if (mUploadDir == null) {
mUploadDir = ServletUtil.getTempDir(getServletContext()); if (uploadDir == null) {
uploadDir = ServletUtil.getTempDir(getServletContext());
} }
} }
@@ -86,23 +88,9 @@ public class FileUploadFilter extends GenericFilter {
* *
* @param pMaxSize * @param pMaxSize
*/ */
// public void setMaxFileSize(String pMaxSize) {
// try {
// setMaxFileSize(Long.parseLong(pMaxSize));
// }
// catch (NumberFormatException e) {
// log("Error setting maxFileSize, using default: " + mMaxFileSize, e);
// }
// }
/**
* Sets max filesize allowed for upload.
*
* @param pMaxSize
*/
public void setMaxFileSize(long pMaxSize) { public void setMaxFileSize(long pMaxSize) {
log("maxFileSize=" + pMaxSize); log("maxFileSize=" + pMaxSize);
mMaxFileSize = pMaxSize; maxFileSize = pMaxSize;
} }
/** /**
@@ -125,7 +113,7 @@ public class FileUploadFilter extends GenericFilter {
// If the content type is multipart, wrap // If the content type is multipart, wrap
if (isMultipartFileUpload(contentType)) { if (isMultipartFileUpload(contentType)) {
pRequest = new HttpFileUploadRequestWrapper(request, mUploadDir, mMaxFileSize); pRequest = new HttpFileUploadRequestWrapper(request, uploadDir, maxFileSize);
} }
pChain.doFilter(pRequest, pResponse); pChain.doFilter(pRequest, pResponse);
@@ -47,8 +47,8 @@ import java.util.*;
*/ */
class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements HttpFileUploadRequest { class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements HttpFileUploadRequest {
private final Map<String, String[]> mParameters = new HashMap<String, String[]>(); private final Map<String, String[]> parameters = new HashMap<String, String[]>();
private final Map<String, UploadedFile[]> mFiles = new HashMap<String, UploadedFile[]>(); private final Map<String, UploadedFile[]> files = new HashMap<String, UploadedFile[]>();
public HttpFileUploadRequestWrapper(HttpServletRequest pRequest, File pUploadDir, long pMaxSize) throws ServletException { public HttpFileUploadRequestWrapper(HttpServletRequest pRequest, File pUploadDir, long pMaxSize) throws ServletException {
super(pRequest); super(pRequest);
@@ -86,7 +86,7 @@ class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements
String name = pItem.getFieldName(); String name = pItem.getFieldName();
UploadedFile[] values; UploadedFile[] values;
UploadedFile[] oldValues = mFiles.get(name); UploadedFile[] oldValues = files.get(name);
if (oldValues != null) { if (oldValues != null) {
values = new UploadedFile[oldValues.length + 1]; values = new UploadedFile[oldValues.length + 1];
@@ -97,7 +97,7 @@ class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements
values = new UploadedFile[] {value}; values = new UploadedFile[] {value};
} }
mFiles.put(name, values); files.put(name, values);
// Also add to normal fields // Also add to normal fields
processFormField(name, value.getName()); processFormField(name, value.getName());
@@ -108,7 +108,7 @@ class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements
// probably faster to just use arrays... // probably faster to just use arrays...
// TODO: Research and document... // TODO: Research and document...
String[] values; String[] values;
String[] oldValues = mParameters.get(pName); String[] oldValues = parameters.get(pName);
if (oldValues != null) { if (oldValues != null) {
values = new String[oldValues.length + 1]; values = new String[oldValues.length + 1];
@@ -119,17 +119,17 @@ class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements
values = new String[] {pValue}; values = new String[] {pValue};
} }
mParameters.put(pName, values); parameters.put(pName, values);
} }
public Map getParameterMap() { public Map getParameterMap() {
// TODO: The spec dicates immutable map, but what about the value arrays?! // TODO: The spec dicates immutable map, but what about the value arrays?!
// Probably just leave as-is, for performance // Probably just leave as-is, for performance
return Collections.unmodifiableMap(mParameters); return Collections.unmodifiableMap(parameters);
} }
public Enumeration getParameterNames() { public Enumeration getParameterNames() {
return Collections.enumeration(mParameters.keySet()); return Collections.enumeration(parameters.keySet());
} }
public String getParameter(String pString) { public String getParameter(String pString) {
@@ -139,7 +139,7 @@ class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements
public String[] getParameterValues(String pString) { public String[] getParameterValues(String pString) {
// TODO: Optimize? // TODO: Optimize?
return mParameters.get(pString).clone(); return parameters.get(pString).clone();
} }
public UploadedFile getUploadedFile(String pName) { public UploadedFile getUploadedFile(String pName) {
@@ -149,6 +149,6 @@ class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements
public UploadedFile[] getUploadedFiles(String pName) { public UploadedFile[] getUploadedFiles(String pName) {
// TODO: Optimize? // TODO: Optimize?
return mFiles.get(pName).clone(); return files.get(pName).clone();
} }
} }
@@ -43,35 +43,35 @@ import java.io.File;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/UploadedFileImpl.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/UploadedFileImpl.java#1 $
*/ */
class UploadedFileImpl implements UploadedFile { class UploadedFileImpl implements UploadedFile {
private final FileItem mItem; private final FileItem item;
public UploadedFileImpl(FileItem pItem) { public UploadedFileImpl(FileItem pItem) {
if (pItem == null) { if (pItem == null) {
throw new IllegalArgumentException("fileitem == null"); throw new IllegalArgumentException("fileitem == null");
} }
mItem = pItem; item = pItem;
} }
public String getContentType() { public String getContentType() {
return mItem.getContentType(); return item.getContentType();
} }
public InputStream getInputStream() throws IOException { public InputStream getInputStream() throws IOException {
return mItem.getInputStream(); return item.getInputStream();
} }
public String getName() { public String getName() {
return mItem.getName(); return item.getName();
} }
public long length() { public long length() {
return mItem.getSize(); return item.getSize();
} }
public void writeTo(File pFile) throws IOException { public void writeTo(File pFile) throws IOException {
try { try {
mItem.write(pFile); item.write(pFile);
} }
catch(RuntimeException e) { catch(RuntimeException e) {
throw e; throw e;
@@ -109,7 +109,7 @@ import java.io.IOException;
public class GZIPFilter extends GenericFilter { public class GZIPFilter extends GenericFilter {
{ {
mOncePerRequest = true; oncePerRequest = true;
} }
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException { protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
@@ -51,12 +51,12 @@ import java.util.zip.GZIPOutputStream;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/gzip/GZIPResponseWrapper.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/gzip/GZIPResponseWrapper.java#1 $
*/ */
public class GZIPResponseWrapper extends HttpServletResponseWrapper { public class GZIPResponseWrapper extends HttpServletResponseWrapper {
protected ServletOutputStream mOut = null; protected ServletOutputStream out;
protected PrintWriter mWriter = null; protected PrintWriter writer;
protected GZIPOutputStream mGZIPOut = null; protected GZIPOutputStream gzipOut;
protected int mContentLength = -1; protected int contentLength = -1;
public GZIPResponseWrapper(HttpServletResponse response) { public GZIPResponseWrapper(final HttpServletResponse response) {
super(response); super(response);
response.addHeader("Content-Encoding", "gzip"); response.addHeader("Content-Encoding", "gzip");
} }
@@ -64,15 +64,15 @@ public class GZIPResponseWrapper extends HttpServletResponseWrapper {
public ServletOutputStream createOutputStream() throws IOException { public ServletOutputStream createOutputStream() throws IOException {
// FIX: Write directly to servlet output stream, for faster responses. // FIX: Write directly to servlet output stream, for faster responses.
// Relies on chunked streams, or buffering in the servlet engine. // Relies on chunked streams, or buffering in the servlet engine.
if (mContentLength >= 0) { if (contentLength >= 0) {
mGZIPOut = new GZIPOutputStream(getResponse().getOutputStream(), mContentLength); gzipOut = new GZIPOutputStream(getResponse().getOutputStream(), contentLength);
} }
else { else {
mGZIPOut = new GZIPOutputStream(getResponse().getOutputStream()); gzipOut = new GZIPOutputStream(getResponse().getOutputStream());
} }
// Wrap in ServletOutputStream and return // Wrap in ServletOutputStream and return
return new OutputStreamAdapter(mGZIPOut); return new OutputStreamAdapter(gzipOut);
} }
// TODO: Move this to flushbuffer or something? Hmmm.. // TODO: Move this to flushbuffer or something? Hmmm..
@@ -80,20 +80,20 @@ public class GZIPResponseWrapper extends HttpServletResponseWrapper {
try { try {
try { try {
// Finish GZIP encodig // Finish GZIP encodig
if (mGZIPOut != null) { if (gzipOut != null) {
mGZIPOut.finish(); gzipOut.finish();
} }
flushBuffer(); flushBuffer();
} }
finally { finally {
// Close stream // Close stream
if (mWriter != null) { if (writer != null) {
mWriter.close(); writer.close();
} }
else { else {
if (mOut != null) { if (out != null) {
mOut.close(); out.close();
} }
} }
} }
@@ -105,42 +105,42 @@ public class GZIPResponseWrapper extends HttpServletResponseWrapper {
} }
public void flushBuffer() throws IOException { public void flushBuffer() throws IOException {
if (mWriter != null) { if (writer != null) {
mWriter.flush(); writer.flush();
} }
else if (mOut != null) { else if (out != null) {
mOut.flush(); out.flush();
} }
} }
public ServletOutputStream getOutputStream() throws IOException { public ServletOutputStream getOutputStream() throws IOException {
if (mWriter != null) { if (writer != null) {
throw new IllegalStateException("getWriter() has already been called!"); throw new IllegalStateException("getWriter() has already been called!");
} }
if (mOut == null) { if (out == null) {
mOut = createOutputStream(); out = createOutputStream();
} }
return (mOut); return (out);
} }
public PrintWriter getWriter() throws IOException { public PrintWriter getWriter() throws IOException {
if (mWriter != null) { if (writer != null) {
return (mWriter); return (writer);
} }
if (mOut != null) { if (out != null) {
throw new IllegalStateException("getOutputStream() has already been called!"); throw new IllegalStateException("getOutputStream() has already been called!");
} }
mOut = createOutputStream(); out = createOutputStream();
// TODO: This is wrong. Should use getCharacterEncoding() or "ISO-8859-1" if gCE returns null. // TODO: This is wrong. Should use getCharacterEncoding() or "ISO-8859-1" if gCE returns null.
mWriter = new PrintWriter(new OutputStreamWriter(mOut, "UTF-8")); writer = new PrintWriter(new OutputStreamWriter(out, "UTF-8"));
return (mWriter); return (writer);
} }
public void setContentLength(int pLength) { public void setContentLength(int pLength) {
// NOTE: Do not call super, as we will shrink the size. // NOTE: Do not call super, as we will shrink the size.
mContentLength = pLength; contentLength = pLength;
} }
} }
@@ -44,12 +44,12 @@ import java.awt.image.RenderedImage;
*/ */
public class AWTImageFilterAdapter extends ImageFilter { public class AWTImageFilterAdapter extends ImageFilter {
private java.awt.image.ImageFilter mFilter = null; private java.awt.image.ImageFilter imageFilter = null;
public void setImageFilter(String pFilterClass) { public void setImageFilter(String pFilterClass) {
try { try {
Class filterClass = Class.forName(pFilterClass); Class filterClass = Class.forName(pFilterClass);
mFilter = (java.awt.image.ImageFilter) filterClass.newInstance(); imageFilter = (java.awt.image.ImageFilter) filterClass.newInstance();
} }
catch (ClassNotFoundException e) { catch (ClassNotFoundException e) {
log("Could not load filter class.", e); log("Could not load filter class.", e);
@@ -64,7 +64,7 @@ public class AWTImageFilterAdapter extends ImageFilter {
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) { protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
// Filter // Filter
Image img = ImageUtil.filter(pImage, mFilter); Image img = ImageUtil.filter(pImage, imageFilter);
// Create BufferedImage & return // Create BufferedImage & return
return ImageUtil.toBuffered(img, BufferedImage.TYPE_INT_RGB); // TODO: This is for JPEG only... return ImageUtil.toBuffered(img, BufferedImage.TYPE_INT_RGB); // TODO: This is for JPEG only...
@@ -42,12 +42,12 @@ import java.awt.image.RenderedImage;
*/ */
public class BufferedImageOpAdapter extends ImageFilter { public class BufferedImageOpAdapter extends ImageFilter {
private BufferedImageOp mFilter = null; private BufferedImageOp filter = null;
public void setImageFilter(String pFilterClass) { public void setImageFilter(String pFilterClass) {
try { try {
Class filterClass = Class.forName(pFilterClass); Class filterClass = Class.forName(pFilterClass);
mFilter = (BufferedImageOp) filterClass.newInstance(); filter = (BufferedImageOp) filterClass.newInstance();
} }
catch (ClassNotFoundException e) { catch (ClassNotFoundException e) {
log("Could not instantiate filter class.", e); log("Could not instantiate filter class.", e);
@@ -62,6 +62,6 @@ public class BufferedImageOpAdapter extends ImageFilter {
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) { protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
// Filter & return // Filter & return
return mFilter.filter(pImage, null); return filter.filter(pImage, null);
} }
} }
@@ -87,7 +87,7 @@ public class ColorServlet extends GenericServlet {
private final static int GREEN_IDX = RED_IDX + 1; private final static int GREEN_IDX = RED_IDX + 1;
private final static int BLUE_IDX = GREEN_IDX + 1; private final static int BLUE_IDX = GREEN_IDX + 1;
private final CRC32 mCRC = new CRC32(); private final CRC32 crc = new CRC32();
/** /**
* Creates a ColorDroplet. * Creates a ColorDroplet.
@@ -108,7 +108,6 @@ public class ColorServlet extends GenericServlet {
* @throws ServletException * @throws ServletException
*/ */
public void service(ServletRequest pRequest, ServletResponse pResponse) throws IOException, ServletException { public void service(ServletRequest pRequest, ServletResponse pResponse) throws IOException, ServletException {
int red = 0; int red = 0;
int green = 0; int green = 0;
int blue = 0; int blue = 0;
@@ -172,10 +171,10 @@ public class ColorServlet extends GenericServlet {
private void updateCRC(byte[] pBytes, int pOff, int pLen) { private void updateCRC(byte[] pBytes, int pOff, int pLen) {
int value; int value;
synchronized (mCRC) { synchronized (crc) {
mCRC.reset(); crc.reset();
mCRC.update(pBytes, pOff, pLen); crc.update(pBytes, pOff, pLen);
value = (int) mCRC.getValue(); value = (int) crc.getValue();
} }
pBytes[pOff + pLen ] = (byte) ((value >> 24) & 0xff); pBytes[pOff + pLen ] = (byte) ((value >> 24) & 0xff);
@@ -72,12 +72,12 @@ public class ContentNegotiationFilter extends ImageFilter {
private final static String[] sKnownFormats = new String[] { private final static String[] sKnownFormats = new String[] {
FORMAT_JPEG, FORMAT_PNG, FORMAT_GIF, FORMAT_WBMP FORMAT_JPEG, FORMAT_PNG, FORMAT_GIF, FORMAT_WBMP
}; };
private float[] mKnownFormatQuality = new float[] { private float[] knownFormatQuality = new float[] {
1f, 1f, 0.99f, 0.5f 1f, 1f, 0.99f, 0.5f
}; };
private HashMap<String, Float> mFormatQuality; // HashMap, as I need to clone this for each request private HashMap<String, Float> formatQuality; // HashMap, as I need to clone this for each request
private final Object mLock = new Object(); private final Object lock = new Object();
/* /*
private Pattern[] mKnownAgentPatterns; private Pattern[] mKnownAgentPatterns;
@@ -86,7 +86,7 @@ public class ContentNegotiationFilter extends ImageFilter {
{ {
// Hack: Make sure the filter don't trigger all the time // Hack: Make sure the filter don't trigger all the time
// See: super.trigger(ServletRequest) // See: super.trigger(ServletRequest)
mTriggerParams = new String[] {}; triggerParams = new String[] {};
} }
/* /*
@@ -242,9 +242,9 @@ public class ContentNegotiationFilter extends ImageFilter {
} }
private Map<String, Float> getFormatQualityMapping() { private Map<String, Float> getFormatQualityMapping() {
synchronized(mLock) { synchronized(lock) {
if (mFormatQuality == null) { if (formatQuality == null) {
mFormatQuality = new HashMap<String, Float>(); formatQuality = new HashMap<String, Float>();
// Use ImageIO to find formats we can actually write // Use ImageIO to find formats we can actually write
String[] formats = ImageIO.getWriterMIMETypes(); String[] formats = ImageIO.getWriterMIMETypes();
@@ -252,12 +252,12 @@ public class ContentNegotiationFilter extends ImageFilter {
// All known formats qs are initially 1.0 // All known formats qs are initially 1.0
// Others should be 0.1 or something like that... // Others should be 0.1 or something like that...
for (String format : formats) { for (String format : formats) {
mFormatQuality.put(format, getKnownFormatQuality(format)); formatQuality.put(format, getKnownFormatQuality(format));
} }
} }
} }
//noinspection unchecked //noinspection unchecked
return (Map<String, Float>) mFormatQuality.clone(); return (Map<String, Float>) formatQuality.clone();
} }
/** /**
@@ -428,7 +428,7 @@ public class ContentNegotiationFilter extends ImageFilter {
private float getKnownFormatQuality(String pFormat) { private float getKnownFormatQuality(String pFormat) {
for (int i = 0; i < sKnownFormats.length; i++) { for (int i = 0; i < sKnownFormats.length; i++) {
if (pFormat.equals(sKnownFormats[i])) { if (pFormat.equals(sKnownFormats[i])) {
return mKnownFormatQuality[i]; return knownFormatQuality[i];
} }
} }
return 0.1f; return 0.1f;
@@ -49,15 +49,19 @@ import java.io.IOException;
* *
*/ */
public abstract class ImageFilter extends GenericFilter { public abstract class ImageFilter extends GenericFilter {
// TODO: Take the design back to the drawing board (see ImageServletResponseImpl)
// - Allow multiple filters to set size attribute
// - Allow a later filter to reset, to get pass-through given certain criteria...
// - Or better yet, allow a filter to decide if it wants to decode, based on image metadata on the original image (ie: width/height)
protected String[] mTriggerParams = null; protected String[] triggerParams = null;
/** /**
* The {@code doFilterImpl} method is called once, or each time a * The {@code doFilterImpl} method is called once, or each time a
* request/response pair is passed through the chain, depending on the * request/response pair is passed through the chain, depending on the
* {@link #mOncePerRequest} member variable. * {@link #oncePerRequest} member variable.
* *
* @see #mOncePerRequest * @see #oncePerRequest
* @see com.twelvemonkeys.servlet.GenericFilter#doFilterImpl doFilter * @see com.twelvemonkeys.servlet.GenericFilter#doFilterImpl doFilter
* @see Filter#doFilter Filter.doFilter * @see Filter#doFilter Filter.doFilter
* *
@@ -107,8 +111,7 @@ public abstract class ImageFilter extends GenericFilter {
//System.out.println("Done filtering."); //System.out.println("Done filtering.");
//System.out.println("Making image available..."); //System.out.println("Making image available...");
// Make image available to other filters (avoid unnecessary // Make image available to other filters (avoid unnecessary serializing/deserializing)
// serializing/deserializing)
imageResponse.setImage(image); imageResponse.setImage(image);
//System.out.println("Done."); //System.out.println("Done.");
@@ -156,7 +159,7 @@ public abstract class ImageFilter extends GenericFilter {
/** /**
* Tests if the filter should do image filtering/processing. * Tests if the filter should do image filtering/processing.
* <P/> * <P/>
* This default implementation uses {@link #mTriggerParams} to test if: * This default implementation uses {@link #triggerParams} to test if:
* <dl> * <dl>
* <dt>{@code mTriggerParams == null}</dt> * <dt>{@code mTriggerParams == null}</dt>
* <dd>{@code return true}</dd> * <dd>{@code return true}</dd>
@@ -173,12 +176,12 @@ public abstract class ImageFilter extends GenericFilter {
*/ */
protected boolean trigger(final ServletRequest pRequest) { protected boolean trigger(final ServletRequest pRequest) {
// If triggerParams not set, assume always trigger // If triggerParams not set, assume always trigger
if (mTriggerParams == null) { if (triggerParams == null) {
return true; return true;
} }
// Trigger only for certain request parameters // Trigger only for certain request parameters
for (String triggerParam : mTriggerParams) { for (String triggerParam : triggerParams) {
if (pRequest.getParameter(triggerParam) != null) { if (pRequest.getParameter(triggerParam) != null) {
return true; return true;
} }
@@ -195,8 +198,9 @@ public abstract class ImageFilter extends GenericFilter {
* *
* @param pTriggerParams a comma-separated string of parameter names. * @param pTriggerParams a comma-separated string of parameter names.
*/ */
public void setTriggerParams(String pTriggerParams) { // TODO: Make it an @InitParam, and make sure we may set String[]/Collection<String> as parameter?
mTriggerParams = StringUtil.toStringArray(pTriggerParams); public void setTriggerParams(final String pTriggerParams) {
triggerParams = StringUtil.toStringArray(pTriggerParams);
} }
/** /**
@@ -60,7 +60,7 @@ import java.util.Iterator;
* This {@link ImageServletResponse} implementation can be used with image * This {@link ImageServletResponse} implementation can be used with image
* requests, to have the image immediately decoded to a {@code BufferedImage}. * requests, to have the image immediately decoded to a {@code BufferedImage}.
* The image may be optionally subsampled, scaled and/or cropped. * The image may be optionally subsampled, scaled and/or cropped.
* The response also automtically handles writing the image back to the underlying response stream * The response also automatically handles writing the image back to the underlying response stream
* in the preferred format, when the response is flushed. * in the preferred format, when the response is flushed.
* <p> * <p>
* *
@@ -68,22 +68,23 @@ import java.util.Iterator;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java#10 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java#10 $
* *
*/ */
// TODO: Refactor out HTTP specifcs (if possible). // TODO: Refactor out HTTP specifics (if possible).
// TODO: Is it a good ide to throw IIOException? // TODO: Is it a good ide to throw IIOException?
// TODO: This implementation has a problem if two filters does scaling, as the second will overwrite the SIZE attribute // TODO: This implementation has a problem if two filters does scaling, as the second will overwrite the SIZE attribute
// TODO: Allow different scaling algorithm based on input image (use case: IndexColorModel does not scale well using default, smooth may be slow for large images)
class ImageServletResponseImpl extends HttpServletResponseWrapper implements ImageServletResponse { class ImageServletResponseImpl extends HttpServletResponseWrapper implements ImageServletResponse {
private ServletRequest mOriginalRequest; private ServletRequest originalRequest;
private final ServletContext mContext; private final ServletContext context;
private final ServletResponseStreamDelegate mStreamDelegate; private final ServletResponseStreamDelegate streamDelegate;
private FastByteArrayOutputStream mBufferedOut; private FastByteArrayOutputStream bufferedOut;
private RenderedImage mImage; private RenderedImage image;
private String mOutputContentType; private String outputContentType;
private String mOriginalContentType; private String originalContentType;
private int mOriginalContentLength = -1; private int originalContentLength = -1;
/** /**
* Creates an {@code ImageServletResponseImpl}. * Creates an {@code ImageServletResponseImpl}.
@@ -94,21 +95,21 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
*/ */
public ImageServletResponseImpl(final HttpServletRequest pRequest, final HttpServletResponse pResponse, final ServletContext pContext) { public ImageServletResponseImpl(final HttpServletRequest pRequest, final HttpServletResponse pResponse, final ServletContext pContext) {
super(pResponse); super(pResponse);
mOriginalRequest = pRequest; originalRequest = pRequest;
mStreamDelegate = new ServletResponseStreamDelegate(pResponse) { streamDelegate = new ServletResponseStreamDelegate(pResponse) {
@Override @Override
protected OutputStream createOutputStream() throws IOException { protected OutputStream createOutputStream() throws IOException {
if (mOriginalContentLength >= 0) { if (originalContentLength >= 0) {
mBufferedOut = new FastByteArrayOutputStream(mOriginalContentLength); bufferedOut = new FastByteArrayOutputStream(originalContentLength);
} }
else { else {
mBufferedOut = new FastByteArrayOutputStream(0); bufferedOut = new FastByteArrayOutputStream(0);
} }
return mBufferedOut; return bufferedOut;
} }
}; };
mContext = pContext; context = pContext;
} }
/** /**
@@ -127,7 +128,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
} }
public void setRequest(ServletRequest pRequest) { public void setRequest(ServletRequest pRequest) {
mOriginalRequest = pRequest; originalRequest = pRequest;
} }
/** /**
@@ -137,11 +138,11 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
*/ */
public void setContentType(final String pMimeType) { public void setContentType(final String pMimeType) {
// Throw exception is already set // Throw exception is already set
if (mOriginalContentType != null) { if (originalContentType != null) {
throw new IllegalStateException("ContentType already set."); throw new IllegalStateException("ContentType already set.");
} }
mOriginalContentType = pMimeType; originalContentType = pMimeType;
} }
/** /**
@@ -151,7 +152,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
* @throws IOException * @throws IOException
*/ */
public ServletOutputStream getOutputStream() throws IOException { public ServletOutputStream getOutputStream() throws IOException {
return mStreamDelegate.getOutputStream(); return streamDelegate.getOutputStream();
} }
/** /**
@@ -161,7 +162,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
* @throws IOException * @throws IOException
*/ */
public PrintWriter getWriter() throws IOException { public PrintWriter getWriter() throws IOException {
return mStreamDelegate.getWriter(); return streamDelegate.getWriter();
} }
/** /**
@@ -170,11 +171,11 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
* @param pLength the content length * @param pLength the content length
*/ */
public void setContentLength(final int pLength) { public void setContentLength(final int pLength) {
if (mOriginalContentLength != -1) { if (originalContentLength != -1) {
throw new IllegalStateException("ContentLength already set."); throw new IllegalStateException("ContentLength already set.");
} }
mOriginalContentLength = pLength; originalContentLength = pLength;
} }
/** /**
@@ -188,59 +189,62 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
String outputType = getOutputContentType(); String outputType = getOutputContentType();
// Force transcoding, if no other filtering is done // Force transcoding, if no other filtering is done
if (!outputType.equals(mOriginalContentType)) { if (!outputType.equals(originalContentType)) {
getImage(); getImage();
} }
if (mImage != null) { if (image != null) {
Iterator writers = ImageIO.getImageWritersByMIMEType(outputType); Iterator writers = ImageIO.getImageWritersByMIMEType(outputType);
if (writers.hasNext()) { if (writers.hasNext()) {
super.setContentType(outputType); super.setContentType(outputType);
OutputStream out = super.getOutputStream(); OutputStream out = super.getOutputStream();
ImageWriter writer = (ImageWriter) writers.next();
try { try {
ImageWriteParam param = writer.getDefaultWriteParam(); ImageWriter writer = (ImageWriter) writers.next();
///////////////////
// POST-PROCESS
// For known formats that don't support transparency, convert to opaque
if (isNonAlphaFormat(outputType) && mImage.getColorModel().getTransparency() != Transparency.OPAQUE) {
mImage = ImageUtil.toBuffered(mImage, BufferedImage.TYPE_INT_RGB);
}
Float requestQuality = (Float) mOriginalRequest.getAttribute(ImageServletResponse.ATTRIB_OUTPUT_QUALITY);
// The default JPEG quality is not good enough, so always apply compression
if ((requestQuality != null || "jpeg".equalsIgnoreCase(getFormatNameSafe(writer))) && param.canWriteCompressed()) {
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(requestQuality != null ? requestQuality : 0.8f);
}
//////////////////
ImageOutputStream stream = ImageIO.createImageOutputStream(out);
writer.setOutput(stream);
try { try {
writer.write(null, new IIOImage(mImage, null, null), param); ImageWriteParam param = writer.getDefaultWriteParam();
///////////////////
// POST-PROCESS
// For known formats that don't support transparency, convert to opaque
if (isNonAlphaFormat(outputType) && image.getColorModel().getTransparency() != Transparency.OPAQUE) {
image = ImageUtil.toBuffered(image, BufferedImage.TYPE_INT_RGB);
}
Float requestQuality = (Float) originalRequest.getAttribute(ImageServletResponse.ATTRIB_OUTPUT_QUALITY);
// The default JPEG quality is not good enough, so always apply compression
if ((requestQuality != null || "jpeg".equalsIgnoreCase(getFormatNameSafe(writer))) && param.canWriteCompressed()) {
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(requestQuality != null ? requestQuality : 0.8f);
}
//////////////////
ImageOutputStream stream = ImageIO.createImageOutputStream(out);
writer.setOutput(stream);
try {
writer.write(null, new IIOImage(image, null, null), param);
}
finally {
stream.close();
}
} }
finally { finally {
stream.close(); writer.dispose();
} }
} }
finally { finally {
writer.dispose();
out.flush(); out.flush();
} }
} }
else { else {
mContext.log("ERROR: No writer for content-type: " + outputType); context.log("ERROR: No writer for content-type: " + outputType);
throw new IIOException("Unable to transcode image: No suitable image writer found (content-type: " + outputType + ")."); throw new IIOException("Unable to transcode image: No suitable image writer found (content-type: " + outputType + ").");
} }
} }
else { else {
super.setContentType(mOriginalContentType); super.setContentType(originalContentType);
ServletOutputStream out = super.getOutputStream(); ServletOutputStream out = super.getOutputStream();
try { try {
mBufferedOut.writeTo(out); bufferedOut.writeTo(out);
} }
finally { finally {
out.flush(); out.flush();
@@ -264,11 +268,11 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
} }
public String getOutputContentType() { public String getOutputContentType() {
return mOutputContentType != null ? mOutputContentType : mOriginalContentType; return outputContentType != null ? outputContentType : originalContentType;
} }
public void setOutputContentType(final String pImageFormat) { public void setOutputContentType(final String pImageFormat) {
mOutputContentType = pImageFormat; outputContentType = pImageFormat;
} }
/** /**
@@ -278,7 +282,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
* response stream * response stream
*/ */
public void setImage(final RenderedImage pImage) { public void setImage(final RenderedImage pImage) {
mImage = pImage; image = pImage;
} }
/** /**
@@ -290,14 +294,14 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
* @throws java.io.IOException if an I/O exception occurs during reading * @throws java.io.IOException if an I/O exception occurs during reading
*/ */
public BufferedImage getImage() throws IOException { public BufferedImage getImage() throws IOException {
if (mImage == null) { if (image == null) {
// No content, no image // No content, no image
if (mBufferedOut == null) { if (bufferedOut == null) {
return null; return null;
} }
// Read from the byte buffer // Read from the byte buffer
InputStream byteStream = mBufferedOut.createInputStream(); InputStream byteStream = bufferedOut.createInputStream();
ImageInputStream input = null; ImageInputStream input = null;
try { try {
input = ImageIO.createImageInputStream(byteStream); input = ImageIO.createImageInputStream(byteStream);
@@ -317,7 +321,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
// PRE-PROCESS (prepare): param, size, format?, request, response? // PRE-PROCESS (prepare): param, size, format?, request, response?
// TODO: AOI strategy? // TODO: AOI strategy?
// Extract AOI from request // Extract AOI from request
Rectangle aoi = extractAOIFromRequest(originalWidth, originalHeight, mOriginalRequest); Rectangle aoi = extractAOIFromRequest(originalWidth, originalHeight, originalRequest);
if (aoi != null) { if (aoi != null) {
param.setSourceRegion(aoi); param.setSourceRegion(aoi);
originalWidth = aoi.width; originalWidth = aoi.width;
@@ -326,8 +330,8 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
// TODO: Size and subsampling strategy? // TODO: Size and subsampling strategy?
// If possible, extract size from request // If possible, extract size from request
Dimension size = extractSizeFromRequest(originalWidth, originalHeight, mOriginalRequest); Dimension size = extractSizeFromRequest(originalWidth, originalHeight, originalRequest);
double readSubSamplingFactor = getReadSubsampleFactorFromRequest(mOriginalRequest); double readSubSamplingFactor = getReadSubsampleFactorFromRequest(originalRequest);
if (size != null) { if (size != null) {
//System.out.println("Size: " + size); //System.out.println("Size: " + size);
if (param.canSetSourceRenderSize()) { if (param.canSetSourceRenderSize()) {
@@ -358,21 +362,21 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
extractAndSetBackgroundColor(image); // TODO: Move to flush/POST-PROCESS extractAndSetBackgroundColor(image); // TODO: Move to flush/POST-PROCESS
// Set image // Set image
mImage = image; this.image = image;
} }
finally { finally {
reader.dispose(); reader.dispose();
} }
} }
else { else {
mContext.log("ERROR: No suitable image reader found (content-type: " + mOriginalContentType + ")."); context.log("ERROR: No suitable image reader found (content-type: " + originalContentType + ").");
mContext.log("ERROR: Available formats: " + getFormatsString()); context.log("ERROR: Available formats: " + getFormatsString());
throw new IIOException("Unable to transcode image: No suitable image reader found (content-type: " + mOriginalContentType + ")."); throw new IIOException("Unable to transcode image: No suitable image reader found (content-type: " + originalContentType + ").");
} }
// Free resources, as the image is now either read, or unreadable // Free resources, as the image is now either read, or unreadable
mBufferedOut = null; bufferedOut = null;
} }
finally { finally {
if (input != null) { if (input != null) {
@@ -382,7 +386,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
} }
// Image is usually a BufferedImage, but may also be a RenderedImage // Image is usually a BufferedImage, but may also be a RenderedImage
return mImage != null ? ImageUtil.toBuffered(mImage) : null; return image != null ? ImageUtil.toBuffered(image) : null;
} }
private BufferedImage resampleImage(final BufferedImage image, final Dimension size) { private BufferedImage resampleImage(final BufferedImage image, final Dimension size) {
@@ -401,13 +405,13 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
} }
private int getResampleAlgorithmFromRequest() { private int getResampleAlgorithmFromRequest() {
Object algorithm = mOriginalRequest.getAttribute(ATTRIB_IMAGE_RESAMPLE_ALGORITHM); Object algorithm = originalRequest.getAttribute(ATTRIB_IMAGE_RESAMPLE_ALGORITHM);
if (algorithm instanceof Integer && ((Integer) algorithm == Image.SCALE_SMOOTH || (Integer) algorithm == Image.SCALE_FAST || (Integer) algorithm == Image.SCALE_DEFAULT)) { if (algorithm instanceof Integer && ((Integer) algorithm == Image.SCALE_SMOOTH || (Integer) algorithm == Image.SCALE_FAST || (Integer) algorithm == Image.SCALE_DEFAULT)) {
return (Integer) algorithm; return (Integer) algorithm;
} }
else { else {
if (algorithm != null) { if (algorithm != null) {
mContext.log("WARN: Illegal image resampling algorithm: " + algorithm); context.log("WARN: Illegal image resampling algorithm: " + algorithm);
} }
return BufferedImage.SCALE_DEFAULT; return BufferedImage.SCALE_DEFAULT;
} }
@@ -422,7 +426,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
} }
else { else {
if (factor != null) { if (factor != null) {
mContext.log("WARN: Illegal read subsampling factor: " + factor); context.log("WARN: Illegal read subsampling factor: " + factor);
} }
subsampleFactor = 2.0; subsampleFactor = 2.0;
@@ -434,7 +438,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
private void extractAndSetBackgroundColor(final BufferedImage pImage) { private void extractAndSetBackgroundColor(final BufferedImage pImage) {
// TODO: bgColor request attribute instead of parameter? // TODO: bgColor request attribute instead of parameter?
if (pImage.getColorModel().hasAlpha()) { if (pImage.getColorModel().hasAlpha()) {
String bgColor = mOriginalRequest.getParameter("bg.color"); String bgColor = originalRequest.getParameter("bg.color");
if (bgColor != null) { if (bgColor != null) {
Color color = StringUtil.toColor(bgColor); Color color = StringUtil.toColor(bgColor);
@@ -465,7 +469,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
} }
private void maybeSetBaseURIFromRequest(final ImageReadParam pParam) { private void maybeSetBaseURIFromRequest(final ImageReadParam pParam) {
if (mOriginalRequest instanceof HttpServletRequest) { if (originalRequest instanceof HttpServletRequest) {
try { try {
// If there's a setBaseURI method, we'll try to use that (uses reflection, to avoid dependency on plugins) // If there's a setBaseURI method, we'll try to use that (uses reflection, to avoid dependency on plugins)
Method setBaseURI; Method setBaseURI;
@@ -477,22 +481,22 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
} }
// Get URL for resource and set as base // Get URL for resource and set as base
String baseURI = ServletUtil.getContextRelativeURI((HttpServletRequest) mOriginalRequest); String baseURI = ServletUtil.getContextRelativeURI((HttpServletRequest) originalRequest);
URL resourceURL = mContext.getResource(baseURI); URL resourceURL = context.getResource(baseURI);
if (resourceURL == null) { if (resourceURL == null) {
resourceURL = ServletUtil.getRealURL(mContext, baseURI); resourceURL = ServletUtil.getRealURL(context, baseURI);
} }
if (resourceURL != null) { if (resourceURL != null) {
setBaseURI.invoke(pParam, resourceURL.toExternalForm()); setBaseURI.invoke(pParam, resourceURL.toExternalForm());
} }
else { else {
mContext.log("WARN: Resource URL not found for URI: " + baseURI); context.log("WARN: Resource URL not found for URI: " + baseURI);
} }
} }
catch (Exception e) { catch (Exception e) {
mContext.log("WARN: Could not set base URI: ", e); context.log("WARN: Could not set base URI: ", e);
} }
} }
} }
@@ -500,10 +504,10 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
private Dimension extractSizeFromRequest(final int pDefaultWidth, final int pDefaultHeight, final ServletRequest pOriginalRequest) { private Dimension extractSizeFromRequest(final int pDefaultWidth, final int pDefaultHeight, final ServletRequest pOriginalRequest) {
// TODO: Allow extraction from request parameters // TODO: Allow extraction from request parameters
/* /*
int sizeW = ServletUtil.getIntParameter(mOriginalRequest, "size.w", -1); int sizeW = ServletUtil.getIntParameter(originalRequest, "size.w", -1);
int sizeH = ServletUtil.getIntParameter(mOriginalRequest, "size.h", -1); int sizeH = ServletUtil.getIntParameter(originalRequest, "size.h", -1);
boolean sizePercent = ServletUtil.getBooleanParameter(mOriginalRequest, "size.percent", false); boolean sizePercent = ServletUtil.getBooleanParameter(originalRequest, "size.percent", false);
boolean sizeUniform = ServletUtil.getBooleanParameter(mOriginalRequest, "size.uniform", true); boolean sizeUniform = ServletUtil.getBooleanParameter(originalRequest, "size.uniform", true);
*/ */
Dimension size = (Dimension) pOriginalRequest.getAttribute(ATTRIB_SIZE); Dimension size = (Dimension) pOriginalRequest.getAttribute(ATTRIB_SIZE);
int sizeW = size != null ? size.width : -1; int sizeW = size != null ? size.width : -1;
@@ -525,12 +529,12 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
private Rectangle extractAOIFromRequest(final int pDefaultWidth, final int pDefaultHeight, final ServletRequest pOriginalRequest) { private Rectangle extractAOIFromRequest(final int pDefaultWidth, final int pDefaultHeight, final ServletRequest pOriginalRequest) {
// TODO: Allow extraction from request parameters // TODO: Allow extraction from request parameters
/* /*
int aoiX = ServletUtil.getIntParameter(mOriginalRequest, "aoi.x", -1); int aoiX = ServletUtil.getIntParameter(originalRequest, "aoi.x", -1);
int aoiY = ServletUtil.getIntParameter(mOriginalRequest, "aoi.y", -1); int aoiY = ServletUtil.getIntParameter(originalRequest, "aoi.y", -1);
int aoiW = ServletUtil.getIntParameter(mOriginalRequest, "aoi.w", -1); int aoiW = ServletUtil.getIntParameter(originalRequest, "aoi.w", -1);
int aoiH = ServletUtil.getIntParameter(mOriginalRequest, "aoi.h", -1); int aoiH = ServletUtil.getIntParameter(originalRequest, "aoi.h", -1);
boolean aoiPercent = ServletUtil.getBooleanParameter(mOriginalRequest, "aoi.percent", false); boolean aoiPercent = ServletUtil.getBooleanParameter(originalRequest, "aoi.percent", false);
boolean aoiUniform = ServletUtil.getBooleanParameter(mOriginalRequest, "aoi.uniform", false); boolean aoiUniform = ServletUtil.getBooleanParameter(originalRequest, "aoi.uniform", false);
*/ */
Rectangle aoi = (Rectangle) pOriginalRequest.getAttribute(ATTRIB_AOI); Rectangle aoi = (Rectangle) pOriginalRequest.getAttribute(ATTRIB_AOI);
int aoiX = aoi != null ? aoi.x : -1; int aoiX = aoi != null ? aoi.x : -1;
@@ -123,7 +123,7 @@ public class ScaleFilter extends ImageFilter {
protected final static String PARAM_IMAGE = "image"; protected final static String PARAM_IMAGE = "image";
/** */ /** */
protected int mDefaultScaleQuality = Image.SCALE_DEFAULT; protected int defaultScaleQuality = Image.SCALE_DEFAULT;
/** /**
* Reads the image from the requested URL, scales it, and returns it in the * Reads the image from the requested URL, scales it, and returns it in the
@@ -188,11 +188,11 @@ public class ScaleFilter extends ImageFilter {
} }
} }
return mDefaultScaleQuality; return defaultScaleQuality;
} }
public void setDefaultScaleQuality(String pDefaultScaleQuality) { public void setDefaultScaleQuality(String pDefaultScaleQuality) {
mDefaultScaleQuality = getQuality(pDefaultScaleQuality); defaultScaleQuality = getQuality(pDefaultScaleQuality);
} }
/** /**
@@ -77,9 +77,9 @@ public class SourceRenderFilter extends ImageFilter {
} }
public void init() throws ServletException { public void init() throws ServletException {
if (mTriggerParams == null) { if (triggerParams == null) {
// Add all params as triggers // Add all params as triggers
mTriggerParams = new String[]{mSizeWidthParam, mSizeHeightParam, triggerParams = new String[]{mSizeWidthParam, mSizeHeightParam,
mSizeUniformParam, mSizePercentParam, mSizeUniformParam, mSizePercentParam,
mRegionLeftParam, mRegionTopParam, mRegionLeftParam, mRegionTopParam,
mRegionWidthParam, mRegionHeightParam, mRegionWidthParam, mRegionHeightParam,
@@ -17,13 +17,14 @@
package com.twelvemonkeys.servlet.jsp.droplet; package com.twelvemonkeys.servlet.jsp.droplet;
import java.io.*; import com.twelvemonkeys.servlet.jsp.droplet.taglib.IncludeTag;
import javax.servlet.*; import javax.servlet.ServletException;
import javax.servlet.http.*; import javax.servlet.http.HttpServlet;
import javax.servlet.jsp.*; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.twelvemonkeys.servlet.jsp.droplet.taglib.*; import javax.servlet.jsp.PageContext;
import java.io.IOException;
/** /**
* Dynamo Droplet like Servlet. * Dynamo Droplet like Servlet.
@@ -44,8 +45,7 @@ public abstract class Droplet extends HttpServlet implements JspFragment {
* Services a parameter. Programatically equivalent to the * Services a parameter. Programatically equivalent to the
* <d:valueof param="pParameter"/> JSP tag. * <d:valueof param="pParameter"/> JSP tag.
*/ */
public void serviceParameter(String pParameter, PageContext pPageContext) public void serviceParameter(String pParameter, PageContext pPageContext) throws ServletException, IOException {
throws ServletException, IOException {
Object param = pPageContext.getRequest().getAttribute(pParameter); Object param = pPageContext.getRequest().getAttribute(pParameter);
if (param != null) { if (param != null) {
@@ -68,11 +68,8 @@ public abstract class Droplet extends HttpServlet implements JspFragment {
/** /**
* "There's no need to override this method." :-) * "There's no need to override this method." :-)
*/ */
final public void service(HttpServletRequest pRequest, final public void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
HttpServletResponse pResponse) PageContext pageContext = (PageContext) pRequest.getAttribute(IncludeTag.PAGE_CONTEXT);
throws ServletException, IOException {
PageContext pageContext =
(PageContext) pRequest.getAttribute(IncludeTag.PAGE_CONTEXT);
// TODO: What if pageContext == null // TODO: What if pageContext == null
service(pageContext); service(pageContext);
@@ -14,10 +14,9 @@
package com.twelvemonkeys.servlet.jsp.droplet; package com.twelvemonkeys.servlet.jsp.droplet;
import java.io.*; import javax.servlet.ServletException;
import javax.servlet.jsp.PageContext;
import javax.servlet.*; import java.io.IOException;
import javax.servlet.jsp.*;
/** /**
* Interface for JSP sub pages or page fragments to implement. * Interface for JSP sub pages or page fragments to implement.
@@ -39,6 +38,5 @@ public interface JspFragment {
* subpage's normal operation * subpage's normal operation
* @throws IOException if an input or output exception occurs * @throws IOException if an input or output exception occurs
*/ */
public void service(PageContext pContext) public void service(PageContext pContext) throws ServletException, IOException;
throws ServletException, IOException;
} }
@@ -19,11 +19,10 @@ public class Oparam extends Param implements JspFragment {
super(pValue); super(pValue);
} }
public void service(PageContext pContext) public void service(PageContext pContext) throws ServletException, IOException {
throws ServletException, IOException { pContext.getServletContext().log("Service subpage " + pContext.getServletContext().getRealPath(value));
pContext.getServletContext().log("Service subpage " + pContext.getServletContext().getRealPath(mValue));
pContext.include(mValue); pContext.include(value);
} }
} }
@@ -1,10 +1,10 @@
package com.twelvemonkeys.servlet.jsp.droplet; package com.twelvemonkeys.servlet.jsp.droplet;
import java.io.*; import javax.servlet.ServletException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.*; import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.*; import java.io.IOException;
/** /**
* Param * Param
@@ -12,7 +12,7 @@ import javax.servlet.jsp.*;
public class Param implements JspFragment { public class Param implements JspFragment {
/** The value member field. */ /** The value member field. */
protected String mValue = null; protected String value = null;
/** /**
* Creates a Param. * Creates a Param.
@@ -20,14 +20,14 @@ public class Param implements JspFragment {
* @param pValue the value of the parameter * @param pValue the value of the parameter
*/ */
public Param(String pValue) { public Param(String pValue) {
mValue = pValue; value = pValue;
} }
/** /**
* Gets the value of the parameter. * Gets the value of the parameter.
*/ */
public String getValue() { public String getValue() {
return mValue; return value;
} }
/** /**
@@ -37,6 +37,6 @@ public class Param implements JspFragment {
public void service(PageContext pContext) public void service(PageContext pContext)
throws ServletException, IOException { throws ServletException, IOException {
JspWriter writer = pContext.getOut(); JspWriter writer = pContext.getOut();
writer.print(mValue); writer.print(value);
} }
} }
@@ -41,20 +41,20 @@ public class IncludeTag extends ExTagSupport {
* This will contain the names of all the parameters that have been * This will contain the names of all the parameters that have been
* added to the PageContext.REQUEST_SCOPE scope by this tag. * added to the PageContext.REQUEST_SCOPE scope by this tag.
*/ */
private ArrayList mParameterNames = null; private ArrayList<String> parameterNames = null;
/** /**
* If any of the parameters we insert for this tag already exist, then * If any of the parameters we insert for this tag already exist, then
* we back up the older parameter in this {@code HashMap} and * we back up the older parameter in this {@code HashMap} and
* restore them when the tag is finished. * restore them when the tag is finished.
*/ */
private HashMap mOldParameters = null; private HashMap<String, Object> oldParameters = null;
/** /**
* This is the URL for the JSP page that the parameters contained in this * This is the URL for the JSP page that the parameters contained in this
* tag are to be inserted into. * tag are to be inserted into.
*/ */
private String mPage; private String page;
/** /**
* The name of the PageContext attribute * The name of the PageContext attribute
@@ -68,7 +68,7 @@ public class IncludeTag extends ExTagSupport {
* @param pPage The URL for the JSP page to insert parameters into. * @param pPage The URL for the JSP page to insert parameters into.
*/ */
public void setPage(String pPage) { public void setPage(String pPage) {
mPage = pPage; page = pPage;
} }
/** /**
@@ -85,13 +85,13 @@ public class IncludeTag extends ExTagSupport {
*/ */
public void addParameter(String pName, Object pValue) { public void addParameter(String pName, Object pValue) {
// Check that we haven't already saved this parameter // Check that we haven't already saved this parameter
if (!mParameterNames.contains(pName)) { if (!parameterNames.contains(pName)) {
mParameterNames.add(pName); parameterNames.add(pName);
// Now check if this parameter already exists in the page. // Now check if this parameter already exists in the page.
Object obj = getRequest().getAttribute(pName); Object obj = getRequest().getAttribute(pName);
if (obj != null) { if (obj != null) {
mOldParameters.put(pName, obj); oldParameters.put(pName, obj);
} }
} }
@@ -110,8 +110,8 @@ public class IncludeTag extends ExTagSupport {
* @exception JspException * @exception JspException
*/ */
public int doStartTag() throws JspException { public int doStartTag() throws JspException {
mOldParameters = new HashMap(); oldParameters = new HashMap<String, Object>();
mParameterNames = new ArrayList(); parameterNames = new ArrayList<String>();
return EVAL_BODY_INCLUDE; return EVAL_BODY_INCLUDE;
} }
@@ -129,44 +129,44 @@ public class IncludeTag extends ExTagSupport {
String msg; String msg;
try { try {
Iterator iterator; Iterator<String> iterator;
String parameterName; String parameterName;
// -- Harald K 20020726 // -- Harald K 20020726
// Include the page, in place // Include the page, in place
//getDispatcher().include(getRequest(), getResponse()); //getDispatcher().include(getRequest(), getResponse());
addParameter(PAGE_CONTEXT, pageContext); // Will be cleared later addParameter(PAGE_CONTEXT, pageContext); // Will be cleared later
pageContext.include(mPage); pageContext.include(page);
// Remove all the parameters that were added to the request scope // Remove all the parameters that were added to the request scope
// for this insert tag. // for this insert tag.
iterator = mParameterNames.iterator(); iterator = parameterNames.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
parameterName = (String) iterator.next(); parameterName = iterator.next();
getRequest().removeAttribute(parameterName); getRequest().removeAttribute(parameterName);
} }
iterator = mOldParameters.keySet().iterator(); iterator = oldParameters.keySet().iterator();
// Restore the parameters we temporarily replaced (if any). // Restore the parameters we temporarily replaced (if any).
while (iterator.hasNext()) { while (iterator.hasNext()) {
parameterName = (String) iterator.next(); parameterName = iterator.next();
getRequest().setAttribute(parameterName, mOldParameters.get(parameterName)); getRequest().setAttribute(parameterName, oldParameters.get(parameterName));
} }
return super.doEndTag(); return super.doEndTag();
} }
catch (IOException ioe) { catch (IOException ioe) {
msg = "Caught an IOException while including " + mPage msg = "Caught an IOException while including " + page
+ "\n" + ioe.toString(); + "\n" + ioe.toString();
log(msg, ioe); log(msg, ioe);
throw new JspException(msg); throw new JspException(msg);
} }
catch (ServletException se) { catch (ServletException se) {
msg = "Caught a ServletException while including " + mPage msg = "Caught a ServletException while including " + page
+ "\n" + se.toString(); + "\n" + se.toString();
log(msg, se); log(msg, se);
throw new JspException(msg); throw new JspException(msg);
@@ -177,8 +177,8 @@ public class IncludeTag extends ExTagSupport {
* Free up the member variables that we've used throughout this tag. * Free up the member variables that we've used throughout this tag.
*/ */
protected void clearServiceState() { protected void clearServiceState() {
mOldParameters = null; oldParameters = null;
mParameterNames = null; parameterNames = null;
} }
/** /**
@@ -190,7 +190,7 @@ public class IncludeTag extends ExTagSupport {
*/ */
/* /*
private RequestDispatcher getDispatcher() { private RequestDispatcher getDispatcher() {
return getRequest().getRequestDispatcher(mPage); return getRequest().getRequestDispatcher(page);
} }
*/ */
@@ -41,27 +41,26 @@ import org.xml.sax.helpers.DefaultHandler;
* *
* @version $Revision: #1 $, ($Date: 2008/05/05 $) * @version $Revision: #1 $, ($Date: 2008/05/05 $)
*/ */
public class NestingHandler extends DefaultHandler { public class NestingHandler extends DefaultHandler {
private String mIncludeTagName = "include"; private String includeTagName = "include";
private String mParamTagName = "param"; private String paramTagName = "param";
private String mOpenParamTagName = "oparam"; private String openParamTagName = "oparam";
//private Stack mParents = new Stack(); //private Stack mParents = new Stack();
private boolean mInIncludeTag = false; private boolean inIncludeTag = false;
private String mNamespacePrefix = null; private String namespacePrefix = null;
private String mNamespaceURI = null; private String namespaceURI = null;
private NestingValidator mValidator = null; private NestingValidator validator = null;
public NestingHandler(String pNamespacePrefix, String pNameSpaceURI, public NestingHandler(String pNamespacePrefix, String pNameSpaceURI,
NestingValidator pValidator) { NestingValidator pValidator) {
mNamespacePrefix = pNamespacePrefix; namespacePrefix = pNamespacePrefix;
mNamespaceURI = pNameSpaceURI; namespaceURI = pNameSpaceURI;
mValidator = pValidator; validator = pValidator;
} }
public void startElement(String pNamespaceURI, String pLocalName, public void startElement(String pNamespaceURI, String pLocalName,
@@ -74,7 +73,7 @@ public class NestingHandler extends DefaultHandler {
String localName = !StringUtil.isEmpty(pLocalName) String localName = !StringUtil.isEmpty(pLocalName)
? pLocalName : getLocalName(pQualifiedName); ? pLocalName : getLocalName(pQualifiedName);
/* /*
if (namespacePrefix.equals(mNamespacePrefix)) { if (namespacePrefix.equals(namespacePrefix)) {
System.out.println("startElement:\nnamespaceURI=" + pNamespaceURI System.out.println("startElement:\nnamespaceURI=" + pNamespaceURI
+ " namespacePrefix=" + namespacePrefix + " namespacePrefix=" + namespacePrefix
+ " localName=" + localName + " localName=" + localName
@@ -82,48 +81,48 @@ public class NestingHandler extends DefaultHandler {
+ " attributes=" + pAttributes); + " attributes=" + pAttributes);
} }
*/ */
if (localName.equals(mIncludeTagName)) { if (localName.equals(includeTagName)) {
// include // include
//System.out.println("<" + mNamespacePrefix + ":" //System.out.println("<" + namespacePrefix + ":"
// + mIncludeTagName + ">"); // + includeTagName + ">");
if (mInIncludeTag) { if (inIncludeTag) {
mValidator.reportError("Cannot nest " + namespacePrefix + ":" validator.reportError("Cannot nest " + namespacePrefix + ":"
+ mIncludeTagName); + includeTagName);
} }
mInIncludeTag = true; inIncludeTag = true;
} }
else if (localName.equals(mParamTagName)) { else if (localName.equals(paramTagName)) {
// param // param
//System.out.println("<" + mNamespacePrefix + ":" //System.out.println("<" + namespacePrefix + ":"
// + mParamTagName + "/>"); // + paramTagName + "/>");
if (!mInIncludeTag) { if (!inIncludeTag) {
mValidator.reportError(mNamespacePrefix + ":" validator.reportError(this.namespacePrefix + ":"
+ mParamTagName + paramTagName
+ " can only appear within " + " can only appear within "
+ mNamespacePrefix + ":" + this.namespacePrefix + ":"
+ mIncludeTagName); + includeTagName);
} }
} }
else if (localName.equals(mOpenParamTagName)) { else if (localName.equals(openParamTagName)) {
// oparam // oparam
//System.out.println("<" + mNamespacePrefix + ":" //System.out.println("<" + namespacePrefix + ":"
// + mOpenParamTagName + ">"); // + openParamTagName + ">");
if (!mInIncludeTag) { if (!inIncludeTag) {
mValidator.reportError(mNamespacePrefix + ":" validator.reportError(this.namespacePrefix + ":"
+ mOpenParamTagName + openParamTagName
+ " can only appear within " + " can only appear within "
+ mNamespacePrefix + ":" + this.namespacePrefix + ":"
+ mIncludeTagName); + includeTagName);
} }
mInIncludeTag = false; inIncludeTag = false;
} }
else { else {
// Only jsp:text allowed inside include! // Only jsp:text allowed inside include!
if (mInIncludeTag && !localName.equals("text")) { if (inIncludeTag && !localName.equals("text")) {
mValidator.reportError(namespacePrefix + ":" + localName validator.reportError(namespacePrefix + ":" + localName
+ " can not appear within " + " can not appear within "
+ mNamespacePrefix + ":" + this.namespacePrefix + ":"
+ mIncludeTagName); + includeTagName);
} }
} }
} }
@@ -139,28 +138,28 @@ public class NestingHandler extends DefaultHandler {
String localName = !StringUtil.isEmpty(pLocalName) String localName = !StringUtil.isEmpty(pLocalName)
? pLocalName : getLocalName(pQualifiedName); ? pLocalName : getLocalName(pQualifiedName);
/* /*
if (namespacePrefix.equals(mNamespacePrefix)) { if (namespacePrefix.equals(namespacePrefix)) {
System.out.println("endElement:\nnamespaceURI=" + pNamespaceURI System.out.println("endElement:\nnamespaceURI=" + pNamespaceURI
+ " namespacePrefix=" + namespacePrefix + " namespacePrefix=" + namespacePrefix
+ " localName=" + localName + " localName=" + localName
+ " qName=" + pQualifiedName); + " qName=" + pQualifiedName);
} }
*/ */
if (namespacePrefix.equals(mNamespacePrefix) if (namespacePrefix.equals(this.namespacePrefix)
&& localName.equals(mIncludeTagName)) { && localName.equals(includeTagName)) {
//System.out.println("</" + mNamespacePrefix + ":" //System.out.println("</" + namespacePrefix + ":"
// + mIncludeTagName + ">"); // + includeTagName + ">");
mInIncludeTag = false; inIncludeTag = false;
} }
else if (namespacePrefix.equals(mNamespacePrefix) else if (namespacePrefix.equals(this.namespacePrefix)
&& localName.equals(mOpenParamTagName)) { && localName.equals(openParamTagName)) {
//System.out.println("</" + mNamespacePrefix + ":" //System.out.println("</" + namespacePrefix + ":"
// + mOpenParamTagName + ">"); // + openParamTagName + ">");
mInIncludeTag = true; // assuming no errors before this... inIncludeTag = true; // assuming no errors before this...
} }
} }
@@ -169,8 +168,8 @@ public class NestingHandler extends DefaultHandler {
*/ */
private String getNSPrefixFromURI(String pNamespaceURI) { private String getNSPrefixFromURI(String pNamespaceURI) {
return (pNamespaceURI.equals(mNamespaceURI) return (pNamespaceURI.equals(namespaceURI)
? mNamespacePrefix : ""); ? namespacePrefix : "");
} }
private String getNamespacePrefix(String pQualifiedName) { private String getNamespacePrefix(String pQualifiedName) {
@@ -20,16 +20,16 @@
package com.twelvemonkeys.servlet.jsp.droplet.taglib; package com.twelvemonkeys.servlet.jsp.droplet.taglib;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
import java.util.*; import javax.servlet.jsp.tagext.PageData;
import javax.servlet.jsp.tagext.TagLibraryValidator;
import javax.servlet.jsp.tagext.*; import javax.servlet.jsp.tagext.ValidationMessage;
import javax.xml.parsers.*; import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.*; import java.util.ArrayList;
import org.xml.sax.helpers.*; import java.util.List;
import com.twelvemonkeys.util.*;
/** /**
* A validator that verifies that tags follow * A validator that verifies that tags follow
@@ -47,18 +47,14 @@ import com.twelvemonkeys.util.*;
* @version $Revision: #1 $, ($Date: 2008/05/05 $) * @version $Revision: #1 $, ($Date: 2008/05/05 $)
* *
*/ */
public class NestingValidator extends TagLibraryValidator { public class NestingValidator extends TagLibraryValidator {
private Vector errors = new Vector(); private List<ValidationMessage> errors = new ArrayList<ValidationMessage>();
/** /**
* *
*/ */
public ValidationMessage[] validate(String pPrefix, String pURI, PageData pPage) {
public ValidationMessage[] validate(String pPrefix,
String pURI,
PageData pPage) {
//System.out.println("Validating " + pPrefix + " (" + pURI + ") for " //System.out.println("Validating " + pPrefix + " (" + pURI + ") for "
// + pPage + "."); // + pPage + ".");
@@ -88,14 +84,12 @@ public class NestingValidator extends TagLibraryValidator {
} }
// Return any errors and exceptions, empty array means okay // Return any errors and exceptions, empty array means okay
return (ValidationMessage[]) return errors.toArray(new ValidationMessage[errors.size()]);
errors.toArray(new ValidationMessage[errors.size()]);
} }
/** /**
* Callback method for the handler to report errors * Callback method for the handler to report errors
*/ */
public void reportError(String pMessage) { public void reportError(String pMessage) {
// The first argument to the ValidationMessage // The first argument to the ValidationMessage
// constructor can be a tag ID. Since tag IDs // constructor can be a tag ID. Since tag IDs
@@ -32,55 +32,49 @@ import javax.servlet.jsp.tagext.Tag;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
/** /**
* Open parameter tag that emulates ATG Dynamo JHTML behaviour for JSP. * Open parameter tag that emulates ATG Dynamo JHTML behaviour for JSP.
* *
* @author Thomas Purcell (CSC Australia) * @author Thomas Purcell (CSC Australia)
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haku $ * @author last modified by $Author: haku $
*
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/jsp/droplet/taglib/OparamTag.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/jsp/droplet/taglib/OparamTag.java#1 $
*/ */
public class OparamTag extends BodyReaderTag { public class OparamTag extends BodyReaderTag {
protected final static String COUNTER = "com.twelvemonkeys.servlet.jsp.taglib.OparamTag.counter"; protected final static String COUNTER = "com.twelvemonkeys.servlet.jsp.taglib.OparamTag.counter";
private File subpage = null;
private File mSubpage = null;
/** /**
* This is the name of the parameter to be inserted into the {@code * This is the name of the parameter to be inserted into the {@code
* PageContext.REQUEST_SCOPE} scope. * PageContext.REQUEST_SCOPE} scope.
*/ */
private String parameterName = null;
private String mParameterName = null; private String language = null;
private String mLanguage = null; private String prefix = null;
private String mPrefix = null;
/** /**
* This method allows the JSP page to set the name for the parameter by * This method allows the JSP page to set the name for the parameter by
* using the {@code name} tag attribute. * using the {@code name} tag attribute.
* *
* @param pName The name for the parameter to insert into the {@code * @param pName The name for the parameter to insert into the {@code
* PageContext.REQUEST_SCOPE} scope. * PageContext.REQUEST_SCOPE} scope.
*/ */
public void setName(String pName) { public void setName(String pName) {
mParameterName = pName; parameterName = pName;
} }
public void setLanguage(String pLanguage) { public void setLanguage(String pLanguage) {
//System.out.println("setLanguage:"+pLanguage); //System.out.println("setLanguage:"+pLanguage);
mLanguage = pLanguage; language = pLanguage;
} }
public void setPrefix(String pPrefix) { public void setPrefix(String pPrefix) {
//System.out.println("setPrefix:"+pPrefix); //System.out.println("setPrefix:"+pPrefix);
mPrefix = pPrefix; prefix = pPrefix;
} }
/** /**
@@ -89,11 +83,11 @@ public class OparamTag extends BodyReaderTag {
* {@code IncludeTag} then a {@code JspException} is thrown. * {@code IncludeTag} then a {@code JspException} is thrown.
* *
* @return If this tag is enclosed within an {@code IncludeTag}, then * @return If this tag is enclosed within an {@code IncludeTag}, then
* the default return value from this method is the {@code * the default return value from this method is the {@code
* TagSupport.EVAL_BODY_TAG} value. * TagSupport.EVAL_BODY_TAG} value.
* @exception JspException *
* @throws JspException
*/ */
public int doStartTag() throws JspException { public int doStartTag() throws JspException {
//checkEnclosedInIncludeTag(); // Moved to TagLibValidator //checkEnclosedInIncludeTag(); // Moved to TagLibValidator
@@ -101,17 +95,17 @@ public class OparamTag extends BodyReaderTag {
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
// Get filename // Get filename
mSubpage = createFileNameFromRequest(request); subpage = createFileNameFromRequest(request);
// Get include tag, and add to parameters // Get include tag, and add to parameters
IncludeTag includeTag = (IncludeTag) getParent(); IncludeTag includeTag = (IncludeTag) getParent();
includeTag.addParameter(mParameterName, new Oparam(mSubpage.getName())); includeTag.addParameter(parameterName, new Oparam(subpage.getName()));
// if ! subpage.exist || jsp newer than subpage, write new // if ! subpage.exist || jsp newer than subpage, write new
File jsp = new File(pageContext.getServletContext() File jsp = new File(pageContext.getServletContext()
.getRealPath(request.getServletPath())); .getRealPath(request.getServletPath()));
if (!mSubpage.exists() || jsp.lastModified() > mSubpage.lastModified()) { if (!subpage.exists() || jsp.lastModified() > subpage.lastModified()) {
return BodyTag.EVAL_BODY_BUFFERED; return BodyTag.EVAL_BODY_BUFFERED;
} }
@@ -148,9 +142,8 @@ public class OparamTag extends BodyReaderTag {
* life cycle just in case a JspException was thrown during the tag * life cycle just in case a JspException was thrown during the tag
* execution. * execution.
*/ */
protected void clearServiceState() { protected void clearServiceState() {
mParameterName = null; parameterName = null;
} }
/** /**
@@ -160,36 +153,31 @@ public class OparamTag extends BodyReaderTag {
* into the session scope then a {@code JspException} will be thrown. * into the session scope then a {@code JspException} will be thrown.
* *
* @param pContent The body of the tag as a String. * @param pContent The body of the tag as a String.
* * @throws JspException
* @exception JspException
*/ */
protected void processBody(String pContent) throws JspException { protected void processBody(String pContent) throws JspException {
// Okay, we have the content, we need to write it to disk somewhere // Okay, we have the content, we need to write it to disk somewhere
String content = pContent; String content = pContent;
if (!StringUtil.isEmpty(mLanguage)) { if (!StringUtil.isEmpty(language)) {
content = "<%@page language=\"" + mLanguage + "\" %>" + content; content = "<%@page language=\"" + language + "\" %>" + content;
} }
if (!StringUtil.isEmpty(mPrefix)) { if (!StringUtil.isEmpty(prefix)) {
content = "<%@taglib uri=\"/twelvemonkeys-common\" prefix=\"" + mPrefix + "\" %>" + content; content = "<%@taglib uri=\"/twelvemonkeys-common\" prefix=\"" + prefix + "\" %>" + content;
} }
// Write the content of the oparam to disk // Write the content of the oparam to disk
try { try {
log("Processing subpage " + mSubpage.getPath()); log("Processing subpage " + subpage.getPath());
FileUtil.write(mSubpage, content.getBytes()); FileUtil.write(subpage, content.getBytes());
} }
catch (IOException ioe) { catch (IOException ioe) {
throw new JspException(ioe); throw new JspException(ioe);
} }
} }
/** /** Creates a unique filename for each (nested) oparam */
* Creates a unique filename for each (nested) oparam
*/
private File createFileNameFromRequest(HttpServletRequest pRequest) { private File createFileNameFromRequest(HttpServletRequest pRequest) {
//System.out.println("ServletPath" + pRequest.getServletPath()); //System.out.println("ServletPath" + pRequest.getServletPath());
String path = pRequest.getServletPath(); String path = pRequest.getServletPath();
@@ -203,7 +191,7 @@ public class OparamTag extends BodyReaderTag {
// Replace special chars in name with '_' // Replace special chars in name with '_'
name = name.replace('.', '_'); name = name.replace('.', '_');
String param = mParameterName.replace('.', '_'); String param = parameterName.replace('.', '_');
param = param.replace('/', '_'); param = param.replace('/', '_');
param = param.replace('\\', '_'); param = param.replace('\\', '_');
param = param.replace(':', '_'); param = param.replace(':', '_');
@@ -218,21 +206,20 @@ public class OparamTag extends BodyReaderTag {
return new File(new File(pageContext.getServletContext().getRealPath(path)), name + "_oparam_" + count + "_" + param + ".jsp"); return new File(new File(pageContext.getServletContext().getRealPath(path)), name + "_oparam_" + count + "_" + param + ".jsp");
} }
/** /** Gets the current oparam count for this request */
* Gets the current oparam count for this request
*/
private int getOparamCountFromRequest(HttpServletRequest pRequest) { private int getOparamCountFromRequest(HttpServletRequest pRequest) {
// Use request.attribute for incrementing oparam counter // Use request.attribute for incrementing oparam counter
Integer count = (Integer) pRequest.getAttribute(COUNTER); Integer count = (Integer) pRequest.getAttribute(COUNTER);
if (count == null) if (count == null) {
count = new Integer(0); count = new Integer(0);
else }
else {
count = new Integer(count.intValue() + 1); count = new Integer(count.intValue() + 1);
}
// ... and set it back // ... and set it back
pRequest.setAttribute(COUNTER, count); pRequest.setAttribute(COUNTER, count);
return count.intValue(); return count.intValue();
} }
} }
@@ -14,14 +14,10 @@
package com.twelvemonkeys.servlet.jsp.droplet.taglib; package com.twelvemonkeys.servlet.jsp.droplet.taglib;
import java.io.IOException; import com.twelvemonkeys.servlet.jsp.droplet.Param;
import com.twelvemonkeys.servlet.jsp.taglib.ExTagSupport;
import javax.servlet.*; import javax.servlet.jsp.JspException;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import com.twelvemonkeys.servlet.jsp.droplet.*;
import com.twelvemonkeys.servlet.jsp.taglib.*;
/** /**
* Parameter tag that emulates ATG Dynamo JHTML behaviour for JSP. * Parameter tag that emulates ATG Dynamo JHTML behaviour for JSP.
@@ -33,22 +29,19 @@ import com.twelvemonkeys.servlet.jsp.taglib.*;
* @version $Revision: #1 $, ($Date: 2008/05/05 $) * @version $Revision: #1 $, ($Date: 2008/05/05 $)
* *
*/ */
public class ParamTag extends ExTagSupport { public class ParamTag extends ExTagSupport {
/** /**
* This is the name of the parameter to be inserted into the {@code * This is the name of the parameter to be inserted into the {@code
* PageContext.REQUEST_SCOPE} scope. * PageContext.REQUEST_SCOPE} scope.
*/ */
private String parameterName;
private String mParameterName;
/** /**
* This is the value for the parameter to be inserted into the {@code * This is the value for the parameter to be inserted into the {@code
* PageContext.REQUEST_SCOPE} scope. * PageContext.REQUEST_SCOPE} scope.
*/ */
private Object parameterValue;
private Object mParameterValue;
/** /**
* This method allows the JSP page to set the name for the parameter by * This method allows the JSP page to set the name for the parameter by
@@ -57,9 +50,8 @@ public class ParamTag extends ExTagSupport {
* @param pName The name for the parameter to insert into the {@code * @param pName The name for the parameter to insert into the {@code
* PageContext.REQUEST_SCOPE} scope. * PageContext.REQUEST_SCOPE} scope.
*/ */
public void setName(String pName) { public void setName(String pName) {
mParameterName = pName; parameterName = pName;
} }
/** /**
@@ -69,9 +61,8 @@ public class ParamTag extends ExTagSupport {
* @param pValue The value for the parameter to insert into the <code> * @param pValue The value for the parameter to insert into the <code>
* PageContext.REQUEST_SCOPE</page> scope. * PageContext.REQUEST_SCOPE</page> scope.
*/ */
public void setValue(String pValue) { public void setValue(String pValue) {
mParameterValue = new Param(pValue); parameterValue = new Param(pValue);
} }
/** /**
@@ -84,7 +75,6 @@ public class ParamTag extends ExTagSupport {
* TagSupport.SKIP_BODY} value. * TagSupport.SKIP_BODY} value.
* @exception JspException * @exception JspException
*/ */
public int doStartTag() throws JspException { public int doStartTag() throws JspException {
//checkEnclosedInIncludeTag(); //checkEnclosedInIncludeTag();
@@ -118,11 +108,10 @@ public class ParamTag extends ExTagSupport {
* This method adds the parameter whose name and value were passed to this * This method adds the parameter whose name and value were passed to this
* object via the tag attributes to the parent {@code Include} tag. * object via the tag attributes to the parent {@code Include} tag.
*/ */
private void addParameter() { private void addParameter() {
IncludeTag includeTag = (IncludeTag) getParent(); IncludeTag includeTag = (IncludeTag) getParent();
includeTag.addParameter(mParameterName, mParameterValue); includeTag.addParameter(parameterName, parameterValue);
} }
/** /**
@@ -133,9 +122,8 @@ public class ParamTag extends ExTagSupport {
* life cycle just in case a JspException was thrown during the tag * life cycle just in case a JspException was thrown during the tag
* execution. * execution.
*/ */
protected void clearServiceState() { protected void clearServiceState() {
mParameterName = null; parameterName = null;
mParameterValue = null; parameterValue = null;
} }
} }
@@ -39,8 +39,7 @@ public class ValueOfTEI extends TagExtraInfo {
Object nameAttr = pTagData.getAttribute("name"); Object nameAttr = pTagData.getAttribute("name");
Object paramAttr = pTagData.getAttribute("param"); Object paramAttr = pTagData.getAttribute("param");
if ((nameAttr != null && paramAttr == null) || if ((nameAttr != null && paramAttr == null) || (nameAttr == null && paramAttr != null)) {
(nameAttr == null && paramAttr != null)) {
return true; // Exactly one of name or param set return true; // Exactly one of name or param set
} }
@@ -14,13 +14,14 @@
package com.twelvemonkeys.servlet.jsp.droplet.taglib; package com.twelvemonkeys.servlet.jsp.droplet.taglib;
import java.io.*; import com.twelvemonkeys.servlet.jsp.droplet.JspFragment;
import com.twelvemonkeys.servlet.jsp.taglib.ExTagSupport;
import javax.servlet.*; import javax.servlet.ServletException;
import javax.servlet.jsp.*; import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import com.twelvemonkeys.servlet.jsp.droplet.*; import javax.servlet.jsp.PageContext;
import com.twelvemonkeys.servlet.jsp.taglib.*; import java.io.IOException;
/** /**
* ValueOf tag that emulates ATG Dynamo JHTML behaviour for JSP. * ValueOf tag that emulates ATG Dynamo JHTML behaviour for JSP.
@@ -38,14 +39,14 @@ public class ValueOfTag extends ExTagSupport {
* the current JSP page. This value will be set via the {@code name} * the current JSP page. This value will be set via the {@code name}
* attribute. * attribute.
*/ */
private String mParameterName; private String parameterName;
/** /**
* This is the value of the parameter read from the {@code * This is the value of the parameter read from the {@code
* PageContext.REQUEST_SCOPE} scope. If the parameter doesn't exist, * PageContext.REQUEST_SCOPE} scope. If the parameter doesn't exist,
* then this will be null. * then this will be null.
*/ */
private Object mParameterValue; private Object parameterValue;
/** /**
* This method is called as part of the initialisation phase of the tag * This method is called as part of the initialisation phase of the tag
@@ -56,7 +57,7 @@ public class ValueOfTag extends ExTagSupport {
* PageContext.REQUEST_SCOPE} scope. * PageContext.REQUEST_SCOPE} scope.
*/ */
public void setName(String pName) { public void setName(String pName) {
mParameterName = pName; parameterName = pName;
} }
/** /**
@@ -69,7 +70,7 @@ public class ValueOfTag extends ExTagSupport {
* PageContext.REQUEST_SCOPE} scope. * PageContext.REQUEST_SCOPE} scope.
*/ */
public void setParam(String pName) { public void setParam(String pName) {
mParameterName = pName; parameterName = pName;
} }
/** /**
@@ -88,19 +89,19 @@ public class ValueOfTag extends ExTagSupport {
public int doStartTag() throws JspException { public int doStartTag() throws JspException {
try { try {
if (parameterExists()) { if (parameterExists()) {
if (mParameterValue instanceof JspFragment) { if (parameterValue instanceof JspFragment) {
// OPARAM or PARAM // OPARAM or PARAM
((JspFragment) mParameterValue).service(pageContext); ((JspFragment) parameterValue).service(pageContext);
/* /*
log("Service subpage " + pageContext.getServletContext().getRealPath(((Oparam) mParameterValue).getName())); log("Service subpage " + pageContext.getServletContext().getRealPath(((Oparam) parameterValue).getName()));
pageContext.include(((Oparam) mParameterValue).getName()); pageContext.include(((Oparam) parameterValue).getName());
*/ */
} }
else { else {
// Normal JSP parameter value // Normal JSP parameter value
JspWriter writer = pageContext.getOut(); JspWriter writer = pageContext.getOut();
writer.print(mParameterValue); writer.print(parameterValue);
} }
return SKIP_BODY; return SKIP_BODY;
@@ -135,13 +136,13 @@ public class ValueOfTag extends ExTagSupport {
* } scope, {@code false} otherwise. * } scope, {@code false} otherwise.
*/ */
private boolean parameterExists() { private boolean parameterExists() {
mParameterValue = pageContext.getAttribute(mParameterName, PageContext.REQUEST_SCOPE); parameterValue = pageContext.getAttribute(parameterName, PageContext.REQUEST_SCOPE);
// -- Harald K 20020726 // -- Harald K 20020726
if (mParameterValue == null) { if (parameterValue == null) {
mParameterValue = pageContext.getRequest().getParameter(mParameterName); parameterValue = pageContext.getRequest().getParameter(parameterName);
} }
return (mParameterValue != null); return (parameterValue != null);
} }
} }
@@ -10,7 +10,6 @@ import javax.servlet.jsp.JspException;
* *
* @version 1.0 * @version 1.0
*/ */
public abstract class BodyReaderTag extends ExBodyTagSupport { public abstract class BodyReaderTag extends ExBodyTagSupport {
/** /**
* This is the method called by the JSP engine when the body for a tag * This is the method called by the JSP engine when the body for a tag
@@ -23,7 +22,6 @@ public abstract class BodyReaderTag extends ExBodyTagSupport {
* processed the one time. * processed the one time.
* @exception JspException * @exception JspException
*/ */
public int doAfterBody() throws JspException { public int doAfterBody() throws JspException {
processBody(bodyContent.getString()); processBody(bodyContent.getString());
return SKIP_BODY; return SKIP_BODY;
@@ -36,8 +34,7 @@ public abstract class BodyReaderTag extends ExBodyTagSupport {
* this method is called. * this method is called.
* *
* @param pContent The body for the custom tag converted to a String. * @param pContent The body for the custom tag converted to a String.
* @exception JscException * @exception JspException
*/ */
protected abstract void processBody(String pContent) throws JspException; protected abstract void processBody(String pContent) throws JspException;
} }
@@ -20,11 +20,16 @@
package com.twelvemonkeys.servlet.jsp.taglib; package com.twelvemonkeys.servlet.jsp.taglib;
import java.util.*; import javax.servlet.jsp.JspException;
import java.io.*; import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.*; import java.io.BufferedReader;
import javax.servlet.jsp.tagext.*; import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;
/** /**
* Creates a table from a string of "comma-separated values" (CSV). * Creates a table from a string of "comma-separated values" (CSV).
@@ -67,29 +72,27 @@ import javax.servlet.jsp.tagext.*;
* *
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/jsp/taglib/CSVToTableTag.java#1 $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/jsp/taglib/CSVToTableTag.java#1 $
*/ */
public class CSVToTableTag extends ExBodyTagSupport { public class CSVToTableTag extends ExBodyTagSupport {
public final static String TAB = "\t"; public final static String TAB = "\t";
protected String mDelimiter = null; protected String delimiter = null;
protected boolean mFirstRowIsHeader = false; protected boolean firstRowIsHeader = false;
protected boolean mFirstColIsHeader = false; protected boolean firstColIsHeader = false;
public void setDelimiter(String pDelimiter) { public void setDelimiter(String pDelimiter) {
mDelimiter = pDelimiter; delimiter = pDelimiter;
} }
public String getDelimiter() { public String getDelimiter() {
return mDelimiter != null ? mDelimiter : TAB; return delimiter != null ? delimiter : TAB;
} }
public void setFirstRowIsHeader(String pBoolean) { public void setFirstRowIsHeader(String pBoolean) {
mFirstRowIsHeader = Boolean.valueOf(pBoolean).booleanValue(); firstRowIsHeader = Boolean.valueOf(pBoolean);
} }
public void setFirstColIsHeader(String pBoolean) { public void setFirstColIsHeader(String pBoolean) {
mFirstColIsHeader = Boolean.valueOf(pBoolean).booleanValue(); firstColIsHeader = Boolean.valueOf(pBoolean);
} }
@@ -114,14 +117,11 @@ public class CSVToTableTag extends ExBodyTagSupport {
// Loop over cells in each row // Loop over cells in each row
for (int col = 0; col < table.getCols(); col++) { for (int col = 0; col < table.getCols(); col++) {
// Test if we are using headers, else normal cell // Test if we are using headers, else normal cell
if (mFirstRowIsHeader && row == 0 if (firstRowIsHeader && row == 0 || firstColIsHeader && col == 0) {
|| mFirstColIsHeader && col == 0) { out.println("<TH>" + table.get(row, col) + " </TH>");
out.println("<TH>" + table.get(row, col)
+ " </TH>");
} }
else { else {
out.println("<TD>" + table.get(row, col) out.println("<TD>" + table.get(row, col) + " </TD>");
+ " </TD>");
} }
} }
@@ -139,29 +139,29 @@ public class CSVToTableTag extends ExBodyTagSupport {
} }
static class Table { static class Table {
List mRows = null; List rows = null;
int mCols = 0; int cols = 0;
private Table(List pRows, int pCols) { private Table(List pRows, int pCols) {
mRows = pRows; rows = pRows;
mCols = pCols; cols = pCols;
} }
int getRows() { int getRows() {
return mRows != null ? mRows.size() : 0; return rows != null ? rows.size() : 0;
} }
int getCols() { int getCols() {
return mCols; return cols;
} }
List getTableRows() { List getTableRows() {
return mRows; return rows;
} }
List getTableRow(int pRow) { List getTableRow(int pRow) {
return mRows != null return rows != null
? (List) mRows.get(pRow) ? (List) rows.get(pRow)
: Collections.EMPTY_LIST; : Collections.EMPTY_LIST;
} }
@@ -175,25 +175,22 @@ public class CSVToTableTag extends ExBodyTagSupport {
* Parses a BodyContent to a table. * Parses a BodyContent to a table.
* *
*/ */
static Table parseContent(Reader pContent, String pDelim) throws IOException {
static Table parseContent(Reader pContent, String pDelim) List<List<String>> tableRows = new ArrayList<List<String>>();
throws IOException {
ArrayList tableRows = new ArrayList();
int tdsPerTR = 0; int tdsPerTR = 0;
// Loop through TRs // Loop through TRs
BufferedReader reader = new BufferedReader(pContent); BufferedReader reader = new BufferedReader(pContent);
String tr = null; String tr;
while ((tr = reader.readLine()) != null) { while ((tr = reader.readLine()) != null) {
// Discard blank lines // Discard blank lines
if (tr != null if (tr.trim().length() <= 0 && tr.indexOf(pDelim) < 0) {
&& tr.trim().length() <= 0 && tr.indexOf(pDelim) < 0) {
continue; continue;
} }
//System.out.println("CSVToTable: read LINE=\"" + tr + "\""); //System.out.println("CSVToTable: read LINE=\"" + tr + "\"");
ArrayList tableDatas = new ArrayList(); List<String> tableDatas = new ArrayList<String>();
StringTokenizer tableRow = new StringTokenizer(tr, pDelim, StringTokenizer tableRow = new StringTokenizer(tr, pDelim,
true); true);
@@ -235,6 +232,4 @@ public class CSVToTableTag extends ExBodyTagSupport {
return new Table(tableRows, tdsPerTR); return new Table(tableRows, tdsPerTR);
} }
} }
} }
@@ -1,53 +1,49 @@
package com.twelvemonkeys.servlet.jsp.taglib; package com.twelvemonkeys.servlet.jsp.taglib;
import com.twelvemonkeys.util.convert.Converter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
import java.io.File; import java.io.File;
import java.util.Date; import java.util.Date;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import com.twelvemonkeys.util.convert.*;
/** /**
* Prints the last modified * Prints the last modified
*/ */
public class LastModifiedTag extends TagSupport { public class LastModifiedTag extends TagSupport {
private String mFileName = null; private String fileName = null;
private String mFormat = null; private String format = null;
public void setFile(String pFileName) { public void setFile(String pFileName) {
mFileName = pFileName; fileName = pFileName;
} }
public void setFormat(String pFormat) { public void setFormat(String pFormat) {
mFormat = pFormat; format = pFormat;
} }
public int doStartTag() throws JspException { public int doStartTag() throws JspException {
File file = null; File file;
if (mFileName != null) { if (fileName != null) {
file = new File(pageContext.getServletContext() file = new File(pageContext.getServletContext().getRealPath(fileName));
.getRealPath(mFileName));
} }
else { else {
HttpServletRequest request = HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
(HttpServletRequest) pageContext.getRequest();
// Get the file containing the servlet // Get the file containing the servlet
file = new File(pageContext.getServletContext() file = new File(pageContext.getServletContext().getRealPath(request.getServletPath()));
.getRealPath(request.getServletPath()));
} }
Date lastModified = new Date(file.lastModified()); Date lastModified = new Date(file.lastModified());
Converter conv = Converter.getInstance(); Converter conv = Converter.getInstance();
// Set the last modified value back // Set the last modified value back
pageContext.setAttribute("lastModified", pageContext.setAttribute("lastModified", conv.toString(lastModified, format));
conv.toString(lastModified, mFormat));
return Tag.EVAL_BODY_INCLUDE; return Tag.EVAL_BODY_INCLUDE;
} }
@@ -23,8 +23,6 @@
package com.twelvemonkeys.servlet.jsp.taglib.logic; package com.twelvemonkeys.servlet.jsp.taglib.logic;
import java.lang.*;
import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport; import javax.servlet.jsp.tagext.TagSupport;
@@ -38,8 +36,8 @@ import javax.servlet.jsp.tagext.TagSupport;
public abstract class ConditionalTagBase extends TagSupport { public abstract class ConditionalTagBase extends TagSupport {
// Members // Members
protected String mObjectName; protected String objectName;
protected String mObjectValue; protected String objectValue;
// Properties // Properties
@@ -51,7 +49,7 @@ public abstract class ConditionalTagBase extends TagSupport {
* *
*/ */
public String getName() { public String getName() {
return mObjectName; return objectName;
} }
/** /**
@@ -62,7 +60,7 @@ public abstract class ConditionalTagBase extends TagSupport {
* *
*/ */
public void setName(String pObjectName) { public void setName(String pObjectName) {
this.mObjectName = pObjectName; this.objectName = pObjectName;
} }
/** /**
@@ -73,7 +71,7 @@ public abstract class ConditionalTagBase extends TagSupport {
* *
*/ */
public String getValue() { public String getValue() {
return mObjectValue; return objectValue;
} }
/** /**
@@ -84,7 +82,7 @@ public abstract class ConditionalTagBase extends TagSupport {
* *
*/ */
public void setValue(String pObjectValue) { public void setValue(String pObjectValue) {
this.mObjectValue = pObjectValue; this.objectValue = pObjectValue;
} }
/** /**
@@ -120,8 +118,8 @@ public abstract class ConditionalTagBase extends TagSupport {
public void release() { public void release() {
super.release(); super.release();
mObjectName = null; objectName = null;
mObjectValue = null; objectValue = null;
} }
/** /**
@@ -8,13 +8,11 @@
package com.twelvemonkeys.servlet.jsp.taglib.logic; package com.twelvemonkeys.servlet.jsp.taglib.logic;
import java.lang.*; import com.twelvemonkeys.lang.StringUtil;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspException;
import com.twelvemonkeys.lang.StringUtil;
/** /**
* <p> * <p>
@@ -134,15 +132,15 @@ public class EqualTag extends ConditionalTagBase {
*/ */
protected boolean condition() throws JspException { protected boolean condition() throws JspException {
if (StringUtil.isEmpty(mObjectName)) { if (StringUtil.isEmpty(objectName)) {
return false; return false;
} }
if (StringUtil.isEmpty(mObjectValue)) { if (StringUtil.isEmpty(objectValue)) {
return true; return true;
} }
Object pageScopedAttribute = pageContext.getAttribute(mObjectName); Object pageScopedAttribute = pageContext.getAttribute(objectName);
if (pageScopedAttribute == null) { if (pageScopedAttribute == null) {
return false; return false;
} }
@@ -164,7 +162,7 @@ public class EqualTag extends ConditionalTagBase {
return false; return false;
} }
return (pageScopedStringAttribute.equals(mObjectValue)); return (pageScopedStringAttribute.equals(objectValue));
} }
} }
@@ -1,10 +1,10 @@
package com.twelvemonkeys.servlet.jsp.taglib.logic; package com.twelvemonkeys.servlet.jsp.taglib.logic;
import java.util.Iterator;
import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.*; import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
import java.util.Iterator;
/** /**
* Abstract base class for adding iterators to a page. * Abstract base class for adding iterators to a page.
@@ -24,7 +24,7 @@ public abstract class IteratorProviderTag extends TagSupport {
public final static String ATTRIBUTE_TYPE = "type"; public final static String ATTRIBUTE_TYPE = "type";
/** */ /** */
private String mType = null; private String type = null;
/** /**
* Gets the type. * Gets the type.
@@ -32,7 +32,7 @@ public abstract class IteratorProviderTag extends TagSupport {
* @return the type (class name) * @return the type (class name)
*/ */
public String getType() { public String getType() {
return mType; return type;
} }
/** /**
@@ -42,7 +42,7 @@ public abstract class IteratorProviderTag extends TagSupport {
*/ */
public void setType(String pType) { public void setType(String pType) {
mType = pType; type = pType;
} }
/** /**
@@ -132,15 +132,15 @@ public class NotEqualTag extends ConditionalTagBase {
*/ */
protected boolean condition() throws JspException { protected boolean condition() throws JspException {
if (StringUtil.isEmpty(mObjectName)) { if (StringUtil.isEmpty(objectName)) {
return false; return false;
} }
if (StringUtil.isEmpty(mObjectValue)) { if (StringUtil.isEmpty(objectValue)) {
return true; return true;
} }
Object pageScopedAttribute = pageContext.getAttribute(mObjectName); Object pageScopedAttribute = pageContext.getAttribute(objectName);
if (pageScopedAttribute == null) { if (pageScopedAttribute == null) {
return false; return false;
} }
@@ -162,7 +162,7 @@ public class NotEqualTag extends ConditionalTagBase {
return false; return false;
} }
return (!(pageScopedStringAttribute.equals(mObjectValue))); return (!(pageScopedStringAttribute.equals(objectValue)));
} }
} }
@@ -57,15 +57,15 @@ final class Log4JContextWrapper implements ServletContext {
}); });
} }
private final ServletContext mContext; private final ServletContext context;
private final Logger mLogger; private final Logger logger;
Log4JContextWrapper(ServletContext pContext) { Log4JContextWrapper(ServletContext pContext) {
mContext = pContext; context = pContext;
// TODO: We want a logger per servlet, not per servlet context, right? // TODO: We want a logger per servlet, not per servlet context, right?
mLogger = Logger.getLogger(pContext.getServletContextName()); logger = Logger.getLogger(pContext.getServletContextName());
// TODO: Automatic init/config of Log4J using context parameter for log4j.xml? // TODO: Automatic init/config of Log4J using context parameter for log4j.xml?
// See Log4JInit.java // See Log4JInit.java
@@ -85,99 +85,99 @@ final class Log4JContextWrapper implements ServletContext {
// Should be possible using some stack peek hack, but that's slow... // Should be possible using some stack peek hack, but that's slow...
// Find a good way... // Find a good way...
// Maybe just pass it into the constuctor, and have one wrapper per servlet // Maybe just pass it into the constuctor, and have one wrapper per servlet
mLogger.info(pMessage); logger.info(pMessage);
} }
public void log(String pMessage, Throwable pCause) { public void log(String pMessage, Throwable pCause) {
// TODO: Get logger for caller.. // TODO: Get logger for caller..
mLogger.error(pMessage, pCause); logger.error(pMessage, pCause);
} }
public Object getAttribute(String pMessage) { public Object getAttribute(String pMessage) {
return mContext.getAttribute(pMessage); return context.getAttribute(pMessage);
} }
public Enumeration getAttributeNames() { public Enumeration getAttributeNames() {
return mContext.getAttributeNames(); return context.getAttributeNames();
} }
public ServletContext getContext(String pMessage) { public ServletContext getContext(String pMessage) {
return mContext.getContext(pMessage); return context.getContext(pMessage);
} }
public String getInitParameter(String pMessage) { public String getInitParameter(String pMessage) {
return mContext.getInitParameter(pMessage); return context.getInitParameter(pMessage);
} }
public Enumeration getInitParameterNames() { public Enumeration getInitParameterNames() {
return mContext.getInitParameterNames(); return context.getInitParameterNames();
} }
public int getMajorVersion() { public int getMajorVersion() {
return mContext.getMajorVersion(); return context.getMajorVersion();
} }
public String getMimeType(String pMessage) { public String getMimeType(String pMessage) {
return mContext.getMimeType(pMessage); return context.getMimeType(pMessage);
} }
public int getMinorVersion() { public int getMinorVersion() {
return mContext.getMinorVersion(); return context.getMinorVersion();
} }
public RequestDispatcher getNamedDispatcher(String pMessage) { public RequestDispatcher getNamedDispatcher(String pMessage) {
return mContext.getNamedDispatcher(pMessage); return context.getNamedDispatcher(pMessage);
} }
public String getRealPath(String pMessage) { public String getRealPath(String pMessage) {
return mContext.getRealPath(pMessage); return context.getRealPath(pMessage);
} }
public RequestDispatcher getRequestDispatcher(String pMessage) { public RequestDispatcher getRequestDispatcher(String pMessage) {
return mContext.getRequestDispatcher(pMessage); return context.getRequestDispatcher(pMessage);
} }
public URL getResource(String pMessage) throws MalformedURLException { public URL getResource(String pMessage) throws MalformedURLException {
return mContext.getResource(pMessage); return context.getResource(pMessage);
} }
public InputStream getResourceAsStream(String pMessage) { public InputStream getResourceAsStream(String pMessage) {
return mContext.getResourceAsStream(pMessage); return context.getResourceAsStream(pMessage);
} }
public Set getResourcePaths(String pMessage) { public Set getResourcePaths(String pMessage) {
return mContext.getResourcePaths(pMessage); return context.getResourcePaths(pMessage);
} }
public String getServerInfo() { public String getServerInfo() {
return mContext.getServerInfo(); return context.getServerInfo();
} }
public Servlet getServlet(String pMessage) throws ServletException { public Servlet getServlet(String pMessage) throws ServletException {
//noinspection deprecation //noinspection deprecation
return mContext.getServlet(pMessage); return context.getServlet(pMessage);
} }
public String getServletContextName() { public String getServletContextName() {
return mContext.getServletContextName(); return context.getServletContextName();
} }
public Enumeration getServletNames() { public Enumeration getServletNames() {
//noinspection deprecation //noinspection deprecation
return mContext.getServletNames(); return context.getServletNames();
} }
public Enumeration getServlets() { public Enumeration getServlets() {
//noinspection deprecation //noinspection deprecation
return mContext.getServlets(); return context.getServlets();
} }
public void removeAttribute(String pMessage) { public void removeAttribute(String pMessage) {
mContext.removeAttribute(pMessage); context.removeAttribute(pMessage);
} }
public void setAttribute(String pMessage, Object pExtension) { public void setAttribute(String pMessage, Object pExtension) {
mContext.setAttribute(pMessage, pExtension); context.setAttribute(pMessage, pExtension);
} }
} }
@@ -1,10 +1,9 @@
package com.twelvemonkeys.servlet; package com.twelvemonkeys.servlet;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
import javax.servlet.*; import javax.servlet.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/** /**
* GenericFilterTestCase * GenericFilterTestCase
@@ -30,12 +29,12 @@ public final class GenericFilterTestCase extends FilterAbstractTestCase {
fail(e.getMessage()); fail(e.getMessage());
} }
assertFalse("OncePerRequest should default to false", filter.mOncePerRequest); assertFalse("OncePerRequest should default to false", filter.oncePerRequest);
filter.destroy(); filter.destroy();
// TRUE // TRUE
filter = new GenericFilterImpl(); filter = new GenericFilterImpl();
Map params = new HashMap(); Map<String, String> params = new HashMap<String, String>();
params.put("once-per-request", "true"); params.put("once-per-request", "true");
try { try {
@@ -45,12 +44,12 @@ public final class GenericFilterTestCase extends FilterAbstractTestCase {
fail(e.getMessage()); fail(e.getMessage());
} }
assertTrue("oncePerRequest should be true", filter.mOncePerRequest); assertTrue("oncePerRequest should be true", filter.oncePerRequest);
filter.destroy(); filter.destroy();
// TRUE // TRUE
filter = new GenericFilterImpl(); filter = new GenericFilterImpl();
params = new HashMap(); params = new HashMap<String, String>();
params.put("oncePerRequest", "true"); params.put("oncePerRequest", "true");
try { try {
@@ -60,7 +59,7 @@ public final class GenericFilterTestCase extends FilterAbstractTestCase {
fail(e.getMessage()); fail(e.getMessage());
} }
assertTrue("oncePerRequest should be true", filter.mOncePerRequest); assertTrue("oncePerRequest should be true", filter.oncePerRequest);
filter.destroy(); filter.destroy();
} }
@@ -35,7 +35,7 @@ public abstract class ServletConfigMapAdapterTestCase extends MapAbstractTestCas
} }
private static class TestConfig implements ServletConfig, FilterConfig, ServletContext, Serializable, Cloneable { private static class TestConfig implements ServletConfig, FilterConfig, ServletContext, Serializable, Cloneable {
Map mMap = new HashMap(); Map map = new HashMap();
public String getServletName() { public String getServletName() {
return "dummy"; // Not needed for this test return "dummy"; // Not needed for this test
@@ -55,12 +55,12 @@ public abstract class ServletConfigMapAdapterTestCase extends MapAbstractTestCas
} }
public String getInitParameter(String s) { public String getInitParameter(String s) {
return (String) mMap.get(s); return (String) map.get(s);
} }
public Enumeration getInitParameterNames() { public Enumeration getInitParameterNames() {
//noinspection unchecked //noinspection unchecked
return Collections.enumeration(mMap.keySet()); return Collections.enumeration(map.keySet());
} }
public ServletContext getContext(String uripath) { public ServletContext getContext(String uripath) {
@@ -157,7 +157,7 @@ public abstract class ServletConfigMapAdapterTestCase extends MapAbstractTestCas
public Map makeFullMap() { public Map makeFullMap() {
ServletConfig config = new TestConfig(); ServletConfig config = new TestConfig();
addSampleMappings(((TestConfig) config).mMap); addSampleMappings(((TestConfig) config).map);
return new ServletConfigMapAdapter(config); return new ServletConfigMapAdapter(config);
} }
} }
@@ -171,7 +171,7 @@ public abstract class ServletConfigMapAdapterTestCase extends MapAbstractTestCas
public Map makeFullMap() { public Map makeFullMap() {
FilterConfig config = new TestConfig(); FilterConfig config = new TestConfig();
addSampleMappings(((TestConfig) config).mMap); addSampleMappings(((TestConfig) config).map);
return new ServletConfigMapAdapter(config); return new ServletConfigMapAdapter(config);
} }
} }
@@ -185,7 +185,7 @@ public abstract class ServletConfigMapAdapterTestCase extends MapAbstractTestCas
public Map makeFullMap() { public Map makeFullMap() {
FilterConfig config = new TestConfig(); FilterConfig config = new TestConfig();
addSampleMappings(((TestConfig) config).mMap); addSampleMappings(((TestConfig) config).map);
return new ServletConfigMapAdapter(config); return new ServletConfigMapAdapter(config);
} }
} }