Code clean-up.

This commit is contained in:
Harald Kuhr
2011-12-19 14:30:40 +01:00
parent 0c4fc454b9
commit 49f5ab8e64
64 changed files with 309 additions and 242 deletions
@@ -9,7 +9,7 @@ import java.util.*;
* *
* @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/AbstractServletMapAdapter.java#1 $ * @version $Id: AbstractServletMapAdapter.java#1 $
*/ */
abstract class AbstractServletMapAdapter extends AbstractMap<String, List<String>> { abstract class AbstractServletMapAdapter extends AbstractMap<String, List<String>> {
// TODO: This map is now a little too lazy.. Should cache entries too (instead?) ! // TODO: This map is now a little too lazy.. Should cache entries too (instead?) !
@@ -30,16 +30,16 @@ package com.twelvemonkeys.servlet;
import com.twelvemonkeys.lang.StringUtil; import com.twelvemonkeys.lang.StringUtil;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException; import java.io.IOException;
import java.util.Properties;
import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException; import java.util.regex.PatternSyntaxException;
@@ -47,12 +47,13 @@ import java.util.regex.PatternSyntaxException;
* BrowserHelperFilter * BrowserHelperFilter
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/BrowserHelperFilter.java#1 $ * @version $Id: BrowserHelperFilter.java#1 $
*/ */
public class BrowserHelperFilter extends GenericFilter { 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";
// TODO: Consider using unmodifiable LinkedHashMap<Pattern, String> instead
private Pattern[] knownAgentPatterns; private Pattern[] knownAgentPatterns;
private String[] knownAgentAccepts; private String[] knownAgentAccepts;
@@ -68,45 +69,52 @@ public class BrowserHelperFilter extends GenericFilter {
// <agent-name>.accept=<http-accept-header> // <agent-name>.accept=<http-accept-header>
Properties mappings = new Properties(); Properties mappings = new Properties();
try { try {
log("Reading Accept-mappings properties file: " + pPropertiesFile); log("Reading Accept-mappings properties file: " + pPropertiesFile);
mappings.load(getServletContext().getResourceAsStream(pPropertiesFile)); mappings.load(getServletContext().getResourceAsStream(pPropertiesFile));
List<Pattern> patterns = new ArrayList<Pattern>();
List<String> accepts = new ArrayList<String>();
//System.out.println("--> Loaded file: " + pPropertiesFile); //System.out.println("--> Loaded file: " + pPropertiesFile);
for (Object key : mappings.keySet()) {
String agent = (String) key;
if (agent.endsWith(".accept")) {
continue;
}
//System.out.println("--> Adding accept-mapping for User-Agent: " + agent);
try {
String accept = (String) mappings.get(agent + ".accept");
if (!StringUtil.isEmpty(accept)) {
patterns.add(Pattern.compile((String) mappings.get(agent)));
accepts.add(accept);
//System.out.println("--> " + agent + " accepts: " + accept);
}
else {
log("Missing Accept mapping for User-Agent: " + agent);
}
}
catch (PatternSyntaxException e) {
log("Could not parse User-Agent identification for " + agent, e);
}
knownAgentPatterns = patterns.toArray(new Pattern[patterns.size()]);
knownAgentAccepts = accepts.toArray(new String[accepts.size()]);
}
} }
catch (IOException e) { catch (IOException e) {
throw new ServletConfigException("Could not read Accept-mappings properties file: " + pPropertiesFile, e); throw new ServletConfigException("Could not read Accept-mappings properties file: " + pPropertiesFile, e);
} }
parseMappings(mappings);
}
private void parseMappings(Properties mappings) {
List<Pattern> patterns = new ArrayList<Pattern>();
List<String> accepts = new ArrayList<String>();
for (Object key : mappings.keySet()) {
String agent = (String) key;
if (agent.endsWith(".accept")) {
continue;
}
//System.out.println("--> Adding accept-mapping for User-Agent: " + agent);
try {
String accept = (String) mappings.get(agent + ".accept");
if (!StringUtil.isEmpty(accept)) {
patterns.add(Pattern.compile((String) mappings.get(agent)));
accepts.add(accept);
//System.out.println("--> " + agent + " accepts: " + accept);
}
else {
log("Missing Accept mapping for User-Agent: " + agent);
}
}
catch (PatternSyntaxException e) {
log("Could not parse User-Agent identification for " + agent, e);
}
knownAgentPatterns = patterns.toArray(new Pattern[patterns.size()]);
knownAgentAccepts = accepts.toArray(new String[accepts.size()]);
}
} }
public void init() throws ServletException { public void init() throws ServletException {
@@ -119,6 +127,7 @@ public class BrowserHelperFilter extends GenericFilter {
if (pRequest instanceof HttpServletRequest) { if (pRequest instanceof HttpServletRequest) {
//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 (knownAgentPatterns != null && knownAgentPatterns.length > 0) { if (knownAgentPatterns != null && knownAgentPatterns.length > 0) {
String agent = request.getHeader(HTTP_HEADER_USER_AGENT); String agent = request.getHeader(HTTP_HEADER_USER_AGENT);
@@ -127,10 +136,10 @@ public class BrowserHelperFilter extends GenericFilter {
for (int i = 0; i < knownAgentPatterns.length; i++) { for (int i = 0; i < knownAgentPatterns.length; i++) {
Pattern pattern = knownAgentPatterns[i]; Pattern pattern = knownAgentPatterns[i];
//System.out.println("--> Pattern: " + pattern); //System.out.println("--> Pattern: " + pattern);
if (pattern.matcher(agent).matches()) {
// TODO: Consider merge known with real accpet, in case plugins add extra capabilities?
final String fakeAccept = knownAgentAccepts[i];
if (pattern.matcher(agent).matches()) {
// TODO: Consider merge known with real accept, in case plugins add extra capabilities?
final String fakeAccept = knownAgentAccepts[i];
//System.out.println("--> User-Agent: " + agent + " accepts: " + fakeAccept); //System.out.println("--> User-Agent: " + agent + " accepts: " + fakeAccept);
pRequest = new HttpServletRequestWrapper(request) { pRequest = new HttpServletRequestWrapper(request) {
@@ -138,9 +147,11 @@ public class BrowserHelperFilter extends GenericFilter {
if (HTTP_HEADER_ACCEPT.equals(pName)) { if (HTTP_HEADER_ACCEPT.equals(pName)) {
return fakeAccept; return fakeAccept;
} }
return super.getHeader(pName); return super.getHeader(pName);
} }
}; };
break; break;
} }
} }
@@ -42,7 +42,7 @@ import java.util.Enumeration;
* *
* @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/DebugServlet.java#1 $ * @version $Id: DebugServlet.java#1 $
*/ */
public class DebugServlet extends GenericServlet { public class DebugServlet extends GenericServlet {
private long dateModified; private long dateModified;
@@ -61,7 +61,7 @@ import java.util.Enumeration;
* @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/GenericFilter.java#1 $ * @version $Id: GenericFilter.java#1 $
* *
* @see Filter * @see Filter
* @see FilterConfig * @see FilterConfig
@@ -47,7 +47,7 @@ import java.lang.reflect.InvocationTargetException;
* @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/GenericServlet.java#1 $ * @version $Id: GenericServlet.java#1 $
*/ */
public abstract class GenericServlet extends javax.servlet.GenericServlet { public abstract class GenericServlet extends javax.servlet.GenericServlet {
@@ -72,7 +72,7 @@ public abstract class GenericServlet extends javax.servlet.GenericServlet {
@Override @Override
public void init(final 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("servlet config == null");
} }
try { try {
@@ -41,13 +41,13 @@ 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 $
* *
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/HttpServlet.java#1 $ * @version $Id: HttpServlet.java#1 $
*/ */
public abstract class HttpServlet extends javax.servlet.http.HttpServlet { public abstract class HttpServlet extends javax.servlet.http.HttpServlet {
@@ -63,7 +63,7 @@ public abstract class HttpServlet extends javax.servlet.http.HttpServlet {
* have a matching setter method annotated with {@link InitParam}. * have a matching setter method annotated with {@link InitParam}.
* *
* @param pConfig the servlet config * @param pConfig the servlet config
* @throws ServletException if an error ouccured during init * @throws ServletException if an error occurred during init
* *
* @see javax.servlet.GenericServlet#init * @see javax.servlet.GenericServlet#init
* @see #init() init * @see #init() init
@@ -72,7 +72,7 @@ public abstract class HttpServlet extends javax.servlet.http.HttpServlet {
@Override @Override
public void init(ServletConfig pConfig) throws ServletException { public void init(ServletConfig pConfig) throws ServletException {
if (pConfig == null) { if (pConfig == null) {
throw new ServletConfigException("servletconfig == null"); throw new ServletConfigException("servlet config == null");
} }
try { try {
@@ -36,7 +36,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: InitParam.java#1 $
* @see com.twelvemonkeys.servlet.ServletConfigurator * @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)
@@ -63,7 +63,7 @@ import java.io.OutputStream;
* </pre> * </pre>
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author $Author: haku $ * @author $Author: haku $
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/OutputStreamAdapter.java#1 $ * @version $Id: OutputStreamAdapter.java#1 $
* *
*/ */
public class OutputStreamAdapter extends ServletOutputStream { public class OutputStreamAdapter extends ServletOutputStream {
@@ -66,7 +66,7 @@ import java.util.Enumeration;
* @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/ProxyServlet.java#1 $ * @version $Id: ProxyServlet.java#1 $
*/ */
public class ProxyServlet extends GenericServlet { public class ProxyServlet extends GenericServlet {
@@ -34,10 +34,12 @@ import javax.servlet.ServletException;
* ServletConfigException. * ServletConfigException.
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigException.java#2 $ * @version $Id: ServletConfigException.java#2 $
*/ */
public class ServletConfigException extends ServletException { public class ServletConfigException extends ServletException {
// TODO: Parameters for init-param at fault, and possibly servlet name?
/** /**
* Creates a {@code ServletConfigException} with the given message. * Creates a {@code ServletConfigException} with the given message.
* *
@@ -55,9 +57,8 @@ public class ServletConfigException extends ServletException {
*/ */
public ServletConfigException(final String pMessage, final Throwable pCause) { public ServletConfigException(final String pMessage, final Throwable pCause) {
super(pMessage, pCause); super(pMessage, pCause);
if (getCause() == null) {
initCause(pCause); maybeInitCause(pCause);
}
} }
/** /**
@@ -66,7 +67,13 @@ public class ServletConfigException extends ServletException {
* @param pCause the exception cause * @param pCause the exception cause
*/ */
public ServletConfigException(final Throwable pCause) { public ServletConfigException(final Throwable pCause) {
super("Error in Servlet configuration: " + pCause.getMessage(), pCause); super(String.format("Error in Servlet configuration: %s", pCause.getMessage()), pCause);
maybeInitCause(pCause);
}
private void maybeInitCause(Throwable pCause) {
// Workaround for ServletExceptions that does not do proper exception chaining
if (getCause() == null) { if (getCause() == null) {
initCause(pCause); initCause(pCause);
} }
@@ -45,7 +45,7 @@ import java.util.*;
* <p/> * <p/>
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigMapAdapter.java#2 $ * @version $Id: ServletConfigMapAdapter.java#2 $
*/ */
class ServletConfigMapAdapter extends AbstractMap<String, String> implements Map<String, String>, Serializable, Cloneable { class ServletConfigMapAdapter extends AbstractMap<String, String> implements Map<String, String>, Serializable, Cloneable {
@@ -12,7 +12,7 @@ import java.util.Iterator;
* *
* @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/ServletHeadersMapAdapter.java#1 $ * @version $Id: ServletHeadersMapAdapter.java#1 $
*/ */
class ServletHeadersMapAdapter extends AbstractServletMapAdapter { class ServletHeadersMapAdapter extends AbstractServletMapAdapter {
@@ -12,7 +12,7 @@ import java.util.Iterator;
* *
* @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/ServletParametersMapAdapter.java#1 $ * @version $Id: ServletParametersMapAdapter.java#1 $
*/ */
class ServletParametersMapAdapter extends AbstractServletMapAdapter { class ServletParametersMapAdapter extends AbstractServletMapAdapter {
@@ -42,7 +42,7 @@ import java.io.OutputStream;
* *
* @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/ServletResponseStreamDelegate.java#2 $ * @version $Id: ServletResponseStreamDelegate.java#2 $
*/ */
public class ServletResponseStreamDelegate { public class ServletResponseStreamDelegate {
private Object out = null; private Object out = null;
@@ -53,7 +53,7 @@ import java.util.Map;
* @author Harald Kuhr * @author Harald Kuhr
* @author Eirik Torske * @author Eirik Torske
* @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/ServletUtil.java#3 $ * @version $Id: ServletUtil.java#3 $
*/ */
public final class ServletUtil { public final class ServletUtil {
@@ -46,19 +46,16 @@ import java.util.Map;
/** /**
* ThrottleFilter, a filter for easing server during heavy load. * ThrottleFilter, a filter for easing server during heavy load.
* <!-- * <p/>
* Renamed from LoadShutoffFilter... * Intercepts requests, and returns HTTP response code {@code 503 (Service Unavailable)},
* Happened to be listening to Xploding Plastix' Shakedown Shutoff at the time.. * if there are more than a given number of concurrent
* -->
* Intercepts requests, and returns HTTP response code 503
* (Service Unavailable), if there are more than a given number of concurrent
* requests, to avoid large backlogs. The number of concurrent requests and the * requests, to avoid large backlogs. The number of concurrent requests and the
* response messages sent to the user agent, is configurable from the web * response messages sent to the user agent, is configurable from the web
* descriptor. * descriptor.
* *
* @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/ThrottleFilter.java#1 $ * @version $Id: ThrottleFilter.java#1 $
* @see #setMaxConcurrentThreadCount * @see #setMaxConcurrentThreadCount
* @see #setResponseMessages * @see #setResponseMessages
*/ */
@@ -195,7 +192,7 @@ public class ThrottleFilter extends GenericFilter {
/** /**
* Marks the beginning of a request * Marks the beginning of a request
* *
* @return <CODE>true<CODE> if the request should be handled. * @return {@code true} if the request should be handled.
*/ */
private boolean beginRequest() { private boolean beginRequest() {
synchronized (runningThreadsLock) { synchronized (runningThreadsLock) {
@@ -40,7 +40,7 @@ import java.io.IOException;
* *
* @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/TimingFilter.java#1 $ * @version $Id: TimingFilter.java#1 $
*/ */
public class TimingFilter extends GenericFilter { public class TimingFilter extends GenericFilter {
@@ -102,8 +102,7 @@ public class TimingFilter extends GenericFilter {
} }
long delta = end - start; long delta = end - start;
log("Request processing time for resource \"" + resourceURI + "\": " + log(String.format("Request processing time for resource \"%s\": %d ms (accumulated: %d ms).", resourceURI, (delta - usage), delta));
(delta - usage) + " ms (accumulated: " + delta + " ms).");
// Store total usage // Store total usage
total += delta; total += delta;
@@ -109,7 +109,7 @@ import java.io.FilterOutputStream;
* *
* @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/TrimWhiteSpaceFilter.java#2 $ * @version $Id: TrimWhiteSpaceFilter.java#2 $
*/ */
public class TrimWhiteSpaceFilter extends GenericFilter { public class TrimWhiteSpaceFilter extends GenericFilter {
@@ -9,7 +9,7 @@ import java.net.URI;
* *
* @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/cache/AbstractCacheRequest.java#1 $ * @version $Id: AbstractCacheRequest.java#1 $
*/ */
public abstract class AbstractCacheRequest implements CacheRequest { public abstract class AbstractCacheRequest implements CacheRequest {
private final URI requestURI; private final URI requestURI;
@@ -7,7 +7,7 @@ import java.util.*;
* *
* @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/cache/AbstractCacheResponse.java#1 $ * @version $Id: AbstractCacheResponse.java#1 $
*/ */
public abstract class AbstractCacheResponse implements CacheResponse { public abstract class AbstractCacheResponse implements CacheResponse {
private int status; private int status;
@@ -32,10 +32,12 @@ 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 ? headers.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>();
headers.put(pHeaderName, values); headers.put(pHeaderName, values);
} }
values.add(pHeaderValue); values.add(pHeaderValue);
} }
@@ -5,7 +5,7 @@ package com.twelvemonkeys.servlet.cache;
* *
* @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/cache/CacheException.java#1 $ * @version $Id: CacheException.java#1 $
*/ */
public class CacheException extends Exception { public class CacheException extends Exception {
public CacheException(Throwable pCause) { public CacheException(Throwable pCause) {
@@ -52,7 +52,7 @@ import java.util.logging.Logger;
* @author Jayson Falkner * @author Jayson Falkner
* @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/cache/CacheFilter.java#4 $ * @version $Id: CacheFilter.java#4 $
* *
*/ */
public class CacheFilter extends GenericFilter { public class CacheFilter extends GenericFilter {
@@ -9,7 +9,7 @@ import java.util.Map;
* *
* @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/cache/CacheRequest.java#1 $ * @version $Id: CacheRequest.java#1 $
*/ */
public interface CacheRequest { public interface CacheRequest {
URI getRequestURI(); URI getRequestURI();
@@ -10,7 +10,7 @@ import java.util.Map;
* *
* @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/cache/CacheResponse.java#1 $ * @version $Id: CacheResponse.java#1 $
*/ */
public interface CacheResponse { public interface CacheResponse {
OutputStream getOutputStream() throws IOException; OutputStream getOutputStream() throws IOException;
@@ -49,7 +49,7 @@ import java.io.PrintWriter;
* @author Jayson Falkner * @author Jayson Falkner
* @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/cache/CacheResponseWrapper.java#3 $ * @version $Id: CacheResponseWrapper.java#3 $
*/ */
class CacheResponseWrapper extends HttpServletResponseWrapper { class CacheResponseWrapper extends HttpServletResponseWrapper {
private ServletResponseStreamDelegate streamDelegate; private ServletResponseStreamDelegate streamDelegate;
@@ -58,7 +58,7 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
private CachedEntity cached; private CachedEntity cached;
private WritableCachedResponse cachedResponse; private WritableCachedResponse cachedResponse;
private Boolean cachable; private Boolean cacheable;
private int status; private int status;
public CacheResponseWrapper(final ServletCacheResponse pResponse, final CachedEntity pCached) { public CacheResponseWrapper(final ServletCacheResponse pResponse, final CachedEntity pCached) {
@@ -75,14 +75,14 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
methods below. methods below.
*/ */
private void init() { private void init() {
cachable = null; cacheable = null;
status = SC_OK; status = SC_OK;
cachedResponse = cached.createCachedResponse(); cachedResponse = cached.createCachedResponse();
streamDelegate = new ServletResponseStreamDelegate(this) { streamDelegate = new ServletResponseStreamDelegate(this) {
protected OutputStream createOutputStream() throws IOException { protected OutputStream createOutputStream() throws IOException {
// Test if this request is really cacheable, otherwise, // Test if this request is really cacheable, otherwise,
// just write through to underlying response, and don't cache // just write through to underlying response, and don't cache
if (isCachable()) { if (isCacheable()) {
return cachedResponse.getOutputStream(); return cachedResponse.getOutputStream();
} }
else { else {
@@ -98,16 +98,16 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
return cachedResponse.getCachedResponse(); return cachedResponse.getCachedResponse();
} }
public boolean isCachable() { public boolean isCacheable() {
// NOTE: Intentionally not synchronized // NOTE: Intentionally not synchronized
if (cachable == null) { if (cacheable == null) {
cachable = isCachableImpl(); cacheable = isCacheableImpl();
} }
return cachable; return cacheable;
} }
private boolean isCachableImpl() { private boolean isCacheableImpl() {
if (status != SC_OK) { if (status != SC_OK) {
return false; return false;
} }
@@ -157,10 +157,10 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
} }
public void reset() { public void reset() {
if (Boolean.FALSE.equals(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.reset(); super.reset();
} }
// No else, might be cachable after all.. // No else, might be cacheable after all..
init(); init();
} }
@@ -177,13 +177,13 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
} }
public void sendError(int pStatusCode, String msg) throws IOException { public void sendError(int pStatusCode, String msg) throws IOException {
// NOT cachable // NOT cacheable
status = 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 cacheable
status = pStatusCode; status = pStatusCode;
super.sendError(pStatusCode); super.sendError(pStatusCode);
} }
@@ -194,7 +194,7 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
} }
public void setStatus(int pStatusCode) { public void setStatus(int pStatusCode) {
// NOT cachable unless pStatusCode == 200 (or a FEW others?) // NOT cacheable unless pStatusCode == 200 (or a FEW others?)
if (pStatusCode != SC_OK) { if (pStatusCode != SC_OK) {
status = pStatusCode; status = pStatusCode;
super.setStatus(pStatusCode); super.setStatus(pStatusCode);
@@ -202,14 +202,14 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
} }
public void sendRedirect(String pLocation) throws IOException { public void sendRedirect(String pLocation) throws IOException {
// NOT cachable // NOT cacheable
status = 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(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.setDateHeader(pName, pValue); super.setDateHeader(pName, pValue);
} }
cachedResponse.setHeader(pName, NetUtil.formatHTTPDate(pValue)); cachedResponse.setHeader(pName, NetUtil.formatHTTPDate(pValue));
@@ -217,7 +217,7 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
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(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.addDateHeader(pName, pValue); super.addDateHeader(pName, pValue);
} }
cachedResponse.addHeader(pName, NetUtil.formatHTTPDate(pValue)); cachedResponse.addHeader(pName, NetUtil.formatHTTPDate(pValue));
@@ -225,7 +225,7 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
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(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.setHeader(pName, pValue); super.setHeader(pName, pValue);
} }
cachedResponse.setHeader(pName, pValue); cachedResponse.setHeader(pName, pValue);
@@ -233,7 +233,7 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
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(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.addHeader(pName, pValue); super.addHeader(pName, pValue);
} }
cachedResponse.addHeader(pName, pValue); cachedResponse.addHeader(pName, pValue);
@@ -241,7 +241,7 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
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(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.setIntHeader(pName, pValue); super.setIntHeader(pName, pValue);
} }
cachedResponse.setHeader(pName, String.valueOf(pValue)); cachedResponse.setHeader(pName, String.valueOf(pValue));
@@ -249,7 +249,7 @@ class CacheResponseWrapper extends HttpServletResponseWrapper {
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(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.addIntHeader(pName, pValue); super.addIntHeader(pName, pValue);
} }
cachedResponse.addHeader(pName, String.valueOf(pValue)); cachedResponse.addHeader(pName, String.valueOf(pValue));
@@ -34,7 +34,7 @@ import java.io.IOException;
* CachedEntity * CachedEntity
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedEntity.java#3 $ * @version $Id: CachedEntity.java#3 $
*/ */
interface CachedEntity { interface CachedEntity {
@@ -38,7 +38,7 @@ import java.util.List;
* CachedEntity * CachedEntity
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedEntityImpl.java#3 $ * @version $Id: CachedEntityImpl.java#3 $
*/ */
class CachedEntityImpl implements CachedEntity { class CachedEntityImpl implements CachedEntity {
private String cacheURI; private String cacheURI;
@@ -131,7 +131,7 @@ class CachedEntityImpl implements CachedEntity {
// //
// CacheResponseWrapper response = (CacheResponseWrapper) pResponse; // CacheResponseWrapper response = (CacheResponseWrapper) pResponse;
// if (response.isCachable()) { // if (response.isCacheable()) {
cache.registerContent( cache.registerContent(
cacheURI, cacheURI,
pRequest, pRequest,
@@ -35,7 +35,7 @@ import java.io.OutputStream;
* CachedResponse * CachedResponse
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedResponse.java#3 $ * @version $Id: CachedResponse.java#3 $
*/ */
interface CachedResponse { interface CachedResponse {
/** /**
@@ -30,7 +30,6 @@ package com.twelvemonkeys.servlet.cache;
import com.twelvemonkeys.io.FastByteArrayOutputStream; import com.twelvemonkeys.io.FastByteArrayOutputStream;
import com.twelvemonkeys.lang.Validate; import com.twelvemonkeys.lang.Validate;
import com.twelvemonkeys.util.LinkedMap;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
@@ -41,7 +40,7 @@ import java.util.*;
* CachedResponseImpl * CachedResponseImpl
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedResponseImpl.java#4 $ * @version $Id: CachedResponseImpl.java#4 $
*/ */
class CachedResponseImpl implements CachedResponse { class CachedResponseImpl implements CachedResponse {
final protected Map<String, List<String>> headers; final protected Map<String, List<String>> headers;
@@ -54,7 +53,7 @@ class CachedResponseImpl implements CachedResponse {
} }
// 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 LinkedHashMap<String, List<String>> pHeaders, final int pHeaderSize, final byte[] pContent) {
status = pStatus; status = pStatus;
headers = Validate.notNull(pHeaders, "headers"); headers = Validate.notNull(pHeaders, "headers");
headersSize = pHeaderSize; headersSize = pHeaderSize;
@@ -85,6 +84,7 @@ class CachedResponseImpl implements CachedResponse {
for (int i = 0; i < headerValues.length; i++) { for (int i = 0; i < headerValues.length; i++) {
String headerValue = headerValues[i]; String headerValue = headerValues[i];
if (i == 0) { if (i == 0) {
pResponse.setHeader(header, headerValue); pResponse.setHeader(header, headerValue);
} }
@@ -116,6 +116,7 @@ class CachedResponseImpl implements CachedResponse {
*/ */
public String[] getHeaderNames() { public String[] getHeaderNames() {
Set<String> headers = this.headers.keySet(); Set<String> headers = this.headers.keySet();
return headers.toArray(new String[headers.size()]); return headers.toArray(new String[headers.size()]);
} }
@@ -130,12 +131,7 @@ class CachedResponseImpl implements CachedResponse {
public String[] getHeaderValues(final String pHeaderName) { public String[] getHeaderValues(final String pHeaderName) {
List<String> values = headers.get(pHeaderName); List<String> values = headers.get(pHeaderName);
if (values == null) { return values == null ? null : values.toArray(new String[values.size()]);
return null;
}
else {
return values.toArray(new String[values.size()]);
}
} }
/** /**
@@ -10,7 +10,7 @@ import java.util.Map;
* *
* @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/cache/ClientCacheRequest.java#1 $ * @version $Id: ClientCacheRequest.java#1 $
*/ */
public final class ClientCacheRequest extends AbstractCacheRequest { public final class ClientCacheRequest extends AbstractCacheRequest {
private Map<String, List<String>> parameters; private Map<String, List<String>> parameters;
@@ -9,7 +9,7 @@ import java.io.OutputStream;
* *
* @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/cache/ClientCacheResponse.java#2 $ * @version $Id: ClientCacheResponse.java#2 $
*/ */
public final class ClientCacheResponse extends AbstractCacheResponse { public final class ClientCacheResponse extends AbstractCacheResponse {
// It's quite useless to cache the data either on disk or in memory, as it already is cached in the client's cache... // It's quite useless to cache the data either on disk or in memory, as it already is cached in the client's cache...
@@ -34,10 +34,10 @@ 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;
import com.twelvemonkeys.util.LinkedMap;
import com.twelvemonkeys.util.NullMap; import com.twelvemonkeys.util.NullMap;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import java.util.logging.Level; import java.util.logging.Level;
@@ -48,7 +48,7 @@ import java.util.logging.Logger;
* <p/> * <p/>
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/HTTPCache.java#4 $ * @version $Id: HTTPCache.java#4 $
* @todo OMPTIMIZE: Cache parsed vary-info objects, not the properties-files * @todo OMPTIMIZE: Cache parsed vary-info objects, not the properties-files
* @todo BUG: Better filename handling, as some filenames become too long.. * @todo BUG: Better filename handling, as some filenames become too long..
* - Use a mix of parameters and hashcode + lenght with fixed (max) lenght? * - Use a mix of parameters and hashcode + lenght with fixed (max) lenght?
@@ -149,8 +149,6 @@ public class HTTPCache {
*/ */
protected static final String FILE_EXT_VARY = ".vary"; protected static final String FILE_EXT_VARY = ".vary";
protected static final int STATUS_OK = 200;
/** /**
* The directory used for the disk-based cache * The directory used for the disk-based cache
*/ */
@@ -446,7 +444,7 @@ public class HTTPCache {
} }
private boolean isCachable(final CacheResponse pResponse) { private boolean isCachable(final CacheResponse pResponse) {
if (pResponse.getStatus() != STATUS_OK) { if (pResponse.getStatus() != HttpServletResponse.SC_OK) {
return false; return false;
} }
@@ -898,7 +896,7 @@ public class HTTPCache {
int headerSize = (int) headers.length(); int headerSize = (int) headers.length();
BufferedReader reader = new BufferedReader(new FileReader(headers)); BufferedReader reader = new BufferedReader(new FileReader(headers));
LinkedMap<String, List<String>> headerMap = new LinkedMap<String, List<String>>(); LinkedHashMap<String, List<String>> headerMap = new LinkedHashMap<String, List<String>>();
String line; String line;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
int colIdx = line.indexOf(':'); int colIdx = line.indexOf(':');
@@ -916,7 +914,7 @@ public class HTTPCache {
headerMap.put(name, Arrays.asList(StringUtil.toStringArray(value, "\\"))); headerMap.put(name, Arrays.asList(StringUtil.toStringArray(value, "\\")));
} }
response = new CachedResponseImpl(STATUS_OK, headerMap, headerSize, contents); response = new CachedResponseImpl(HttpServletResponse.SC_OK, headerMap, headerSize, contents);
contentCache.put(pCacheURI + '.' + FileUtil.getExtension(content), response); contentCache.put(pCacheURI + '.' + FileUtil.getExtension(content), response);
} }
} }
@@ -7,7 +7,7 @@ import java.io.IOException;
* *
* @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/cache/ResponseResolver.java#2 $ * @version $Id: ResponseResolver.java#2 $
*/ */
public interface ResponseResolver { public interface ResponseResolver {
void resolve(CacheRequest pRequest, CacheResponse pResponse) throws IOException, CacheException; void resolve(CacheRequest pRequest, CacheResponse pResponse) throws IOException, CacheException;
@@ -52,14 +52,14 @@ import java.util.Map;
* @author Jayson Falkner * @author Jayson Falkner
* @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/cache/SerlvetCacheResponseWrapper.java#2 $ * @version $Id: SerlvetCacheResponseWrapper.java#2 $
*/ */
class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper { class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
private ServletResponseStreamDelegate streamDelegate; private ServletResponseStreamDelegate streamDelegate;
private CacheResponse cacheResponse; private CacheResponse cacheResponse;
private Boolean cachable; private Boolean cacheable;
private int status; private int status;
public SerlvetCacheResponseWrapper(final HttpServletResponse pServletResponse, final CacheResponse pResponse) { public SerlvetCacheResponseWrapper(final HttpServletResponse pServletResponse, final CacheResponse pResponse) {
@@ -70,19 +70,19 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
/* /*
NOTE: This class defers determining if a response is cachable until the NOTE: This class defers determining if a response is cacheable until the
output stream is needed. output stream is needed.
This it the reason for the somewhat complicated logic in the add/setHeader This it the reason for the somewhat complicated logic in the add/setHeader
methods below. methods below.
*/ */
private void init() { private void init() {
cachable = null; cacheable = null;
status = SC_OK; status = SC_OK;
streamDelegate = 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 cacheable, otherwise,
// just write through to underlying response, and don't cache // just write through to underlying response, and don't cache
if (isCachable()) { if (isCacheable()) {
return cacheResponse.getOutputStream(); return cacheResponse.getOutputStream();
} }
else { else {
@@ -109,16 +109,16 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
} }
} }
public boolean isCachable() { public boolean isCacheable() {
// NOTE: Intentionally not synchronized // NOTE: Intentionally not synchronized
if (cachable == null) { if (cacheable == null) {
cachable = isCachableImpl(); cacheable = isCacheableImpl();
} }
return cachable; return cacheable;
} }
private boolean isCachableImpl() { private boolean isCacheableImpl() {
// TODO: This code is duped in the cache... // TODO: This code is duped in the cache...
if (status != SC_OK) { if (status != SC_OK) {
return false; return false;
@@ -169,10 +169,10 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
} }
public void reset() { public void reset() {
if (Boolean.FALSE.equals(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.reset(); super.reset();
} }
// No else, might be cachable after all.. // No else, might be cacheable after all..
init(); init();
} }
@@ -189,13 +189,13 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
} }
public void sendError(int pStatusCode, String msg) throws IOException { public void sendError(int pStatusCode, String msg) throws IOException {
// NOT cachable // NOT cacheable
status = 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 cacheable
status = pStatusCode; status = pStatusCode;
super.sendError(pStatusCode); super.sendError(pStatusCode);
} }
@@ -206,7 +206,7 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
} }
public void setStatus(int pStatusCode) { public void setStatus(int pStatusCode) {
// NOT cachable unless pStatusCode == 200 (or a FEW others?) // NOT cacheable unless pStatusCode == 200 (or a FEW others?)
if (pStatusCode != SC_OK) { if (pStatusCode != SC_OK) {
status = pStatusCode; status = pStatusCode;
super.setStatus(pStatusCode); super.setStatus(pStatusCode);
@@ -214,14 +214,14 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
} }
public void sendRedirect(String pLocation) throws IOException { public void sendRedirect(String pLocation) throws IOException {
// NOT cachable // NOT cacheable
status = 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(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.setDateHeader(pName, pValue); super.setDateHeader(pName, pValue);
} }
cacheResponse.setHeader(pName, NetUtil.formatHTTPDate(pValue)); cacheResponse.setHeader(pName, NetUtil.formatHTTPDate(pValue));
@@ -229,7 +229,7 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
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(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.addDateHeader(pName, pValue); super.addDateHeader(pName, pValue);
} }
cacheResponse.addHeader(pName, NetUtil.formatHTTPDate(pValue)); cacheResponse.addHeader(pName, NetUtil.formatHTTPDate(pValue));
@@ -237,7 +237,7 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
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(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.setHeader(pName, pValue); super.setHeader(pName, pValue);
} }
cacheResponse.setHeader(pName, pValue); cacheResponse.setHeader(pName, pValue);
@@ -245,7 +245,7 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
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(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.addHeader(pName, pValue); super.addHeader(pName, pValue);
} }
cacheResponse.addHeader(pName, pValue); cacheResponse.addHeader(pName, pValue);
@@ -253,7 +253,7 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
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(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.setIntHeader(pName, pValue); super.setIntHeader(pName, pValue);
} }
cacheResponse.setHeader(pName, String.valueOf(pValue)); cacheResponse.setHeader(pName, String.valueOf(pValue));
@@ -261,7 +261,7 @@ class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
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(cachable)) { if (Boolean.FALSE.equals(cacheable)) {
super.addIntHeader(pName, pValue); super.addIntHeader(pName, pValue);
} }
cacheResponse.addHeader(pName, String.valueOf(pValue)); cacheResponse.addHeader(pName, String.valueOf(pValue));
@@ -12,7 +12,7 @@ import java.util.Map;
* *
* @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/cache/ServletCacheRequest.java#1 $ * @version $Id: ServletCacheRequest.java#1 $
*/ */
public final class ServletCacheRequest extends AbstractCacheRequest { public final class ServletCacheRequest extends AbstractCacheRequest {
private final HttpServletRequest request; private final HttpServletRequest request;
@@ -9,38 +9,38 @@ import java.io.OutputStream;
* *
* @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/cache/ServletCacheResponse.java#2 $ * @version $Id: ServletCacheResponse.java#2 $
*/ */
public final class ServletCacheResponse extends AbstractCacheResponse { public final class ServletCacheResponse extends AbstractCacheResponse {
private HttpServletResponse mResponse; private HttpServletResponse response;
public ServletCacheResponse(HttpServletResponse pResponse) { public ServletCacheResponse(HttpServletResponse pResponse) {
mResponse = pResponse; response = pResponse;
} }
public OutputStream getOutputStream() throws IOException { public OutputStream getOutputStream() throws IOException {
return mResponse.getOutputStream(); return response.getOutputStream();
} }
@Override @Override
public void setStatus(int pStatusCode) { public void setStatus(int pStatusCode) {
mResponse.setStatus(pStatusCode); response.setStatus(pStatusCode);
super.setStatus(pStatusCode); super.setStatus(pStatusCode);
} }
@Override @Override
public void addHeader(String pHeaderName, String pHeaderValue) { public void addHeader(String pHeaderName, String pHeaderValue) {
mResponse.addHeader(pHeaderName, pHeaderValue); response.addHeader(pHeaderName, pHeaderValue);
super.addHeader(pHeaderName, pHeaderValue); super.addHeader(pHeaderName, pHeaderValue);
} }
@Override @Override
public void setHeader(String pHeaderName, String pHeaderValue) { public void setHeader(String pHeaderName, String pHeaderValue) {
mResponse.setHeader(pHeaderName, pHeaderValue); response.setHeader(pHeaderName, pHeaderValue);
super.setHeader(pHeaderName, pHeaderValue); super.setHeader(pHeaderName, pHeaderValue);
} }
HttpServletResponse getResponse() { HttpServletResponse getResponse() {
return mResponse; return response;
} }
} }
@@ -10,7 +10,7 @@ import java.io.IOException;
* *
* @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/cache/ServletResponseResolver.java#2 $ * @version $Id: ServletResponseResolver.java#2 $
*/ */
final class ServletResponseResolver implements ResponseResolver { final class ServletResponseResolver implements ResponseResolver {
final private ServletCacheRequest request; final private ServletCacheRequest request;
@@ -34,7 +34,7 @@ import java.io.OutputStream;
* WritableCachedResponse * WritableCachedResponse
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/WritableCachedResponse.java#2 $ * @version $Id: WritableCachedResponse.java#2 $
*/ */
public interface WritableCachedResponse extends CachedResponse, CacheResponse { public interface WritableCachedResponse extends CachedResponse, CacheResponse {
/** /**
@@ -42,7 +42,7 @@ import java.util.Map;
* WritableCachedResponseImpl * WritableCachedResponseImpl
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/cache/WritableCachedResponseImpl.java#3 $ * @version $Id: WritableCachedResponseImpl.java#3 $
*/ */
class WritableCachedResponseImpl implements WritableCachedResponse { class WritableCachedResponseImpl implements WritableCachedResponse {
private final CachedResponseImpl cachedResponse; private final CachedResponseImpl cachedResponse;
@@ -81,10 +81,7 @@ class WritableCachedResponseImpl implements WritableCachedResponse {
private void setHeader(String pName, String pValue, boolean pAdd) { private void setHeader(String pName, String pValue, boolean pAdd) {
// System.out.println(" ++ CachedResponse ++ " + (pAdd ? "addHeader(" : "setHeader(") + pName + ", " + pValue + ")"); // System.out.println(" ++ CachedResponse ++ " + (pAdd ? "addHeader(" : "setHeader(") + pName + ", " + pValue + ")");
// 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 = pAdd ? cachedResponse.headers.get(pName) : null;
if (pAdd) {
values = cachedResponse.headers.get(pName);
}
if (values == null) { if (values == null) {
values = new ArrayList<String>(); values = new ArrayList<String>();
@@ -96,6 +93,7 @@ class WritableCachedResponseImpl implements WritableCachedResponse {
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) {
cachedResponse.headersSize -= oldValue.length(); cachedResponse.headersSize -= oldValue.length();
@@ -33,7 +33,7 @@ package com.twelvemonkeys.servlet.fileupload;
* <p/> * <p/>
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/FileSizeExceededException.java#1 $ * @version $Id: FileSizeExceededException.java#1 $
*/ */
public class FileSizeExceededException extends FileUploadException { public class FileSizeExceededException extends FileUploadException {
public FileSizeExceededException(Throwable pCause) { public FileSizeExceededException(Throwable pCause) {
@@ -35,7 +35,7 @@ import javax.servlet.ServletException;
* <p/> * <p/>
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/FileUploadException.java#1 $ * @version $Id: FileUploadException.java#1 $
*/ */
public class FileUploadException extends ServletException { public class FileUploadException extends ServletException {
public FileUploadException(String pMessage) { public FileUploadException(String pMessage) {
@@ -51,7 +51,7 @@ import java.net.MalformedURLException;
* @see HttpFileUploadRequest * @see HttpFileUploadRequest
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/FileUploadFilter.java#1 $ * @version $Id: FileUploadFilter.java#1 $
*/ */
public class FileUploadFilter extends GenericFilter { public class FileUploadFilter extends GenericFilter {
private File uploadDir; private File uploadDir;
@@ -35,7 +35,7 @@ import javax.servlet.http.HttpServletRequest;
* <a href="http://www.ietf.org/rfc/rfc1867.txt">Form-based File Upload in HTML (RFC1867)</a>. * <a href="http://www.ietf.org/rfc/rfc1867.txt">Form-based File Upload in HTML (RFC1867)</a>.
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/HttpFileUploadRequest.java#1 $ * @version $Id: HttpFileUploadRequest.java#1 $
*/ */
public interface HttpFileUploadRequest extends HttpServletRequest { public interface HttpFileUploadRequest extends HttpServletRequest {
/** /**
@@ -43,7 +43,7 @@ import java.util.*;
* <a href="http://jakarta.apache.org/commons/fileupload/">Jakarta Commons FileUpload</a>. * <a href="http://jakarta.apache.org/commons/fileupload/">Jakarta Commons FileUpload</a>.
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/HttpFileUploadRequestWrapper.java#1 $ * @version $Id: HttpFileUploadRequestWrapper.java#1 $
*/ */
class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements HttpFileUploadRequest { class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements HttpFileUploadRequest {
@@ -36,7 +36,7 @@ import java.io.IOException;
* This class represents an uploaded file. * This class represents an uploaded file.
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/UploadedFile.java#1 $ * @version $Id: UploadedFile.java#1 $
*/ */
public interface UploadedFile { public interface UploadedFile {
/** /**
@@ -40,7 +40,7 @@ import java.io.File;
* <a href="http://jakarta.apache.org/commons/fileupload/">Jakarta Commons FileUpload</a>. * <a href="http://jakarta.apache.org/commons/fileupload/">Jakarta Commons FileUpload</a>.
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/UploadedFileImpl.java#1 $ * @version $Id: UploadedFileImpl.java#1 $
*/ */
class UploadedFileImpl implements UploadedFile { class UploadedFileImpl implements UploadedFile {
private final FileItem item; private final FileItem item;
@@ -104,7 +104,7 @@ import java.io.IOException;
* @author Jayson Falkner * @author Jayson Falkner
* @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/gzip/GZIPFilter.java#1 $ * @version $Id: GZIPFilter.java#1 $
*/ */
public class GZIPFilter extends GenericFilter { public class GZIPFilter extends GenericFilter {
@@ -120,22 +120,23 @@ public class GZIPFilter extends GenericFilter {
// If GZIP is supported, use compression // If GZIP is supported, use compression
String accept = request.getHeader("Accept-Encoding"); String accept = request.getHeader("Accept-Encoding");
if (accept != null && accept.indexOf("gzip") != -1) { if (accept != null && accept.contains("gzip")) {
//System.out.println("GZIP supported, compressing."); //System.out.println("GZIP supported, compressing.");
// TODO: Set Vary: Accept-Encoding ?! // TODO: Set Vary: Accept-Encoding ?!
GZIPResponseWrapper wrapped = new GZIPResponseWrapper(response); GZIPResponseWrapper wrapped = new GZIPResponseWrapper(response);
try { try {
pChain.doFilter(pRequest, wrapped); pChain.doFilter(pRequest, wrapped);
} }
finally { finally {
wrapped.flushResponse(); wrapped.flushResponse();
} }
return; return;
} }
} }
// Else, contiue chain // Else, continue chain
pChain.doFilter(pRequest, pResponse); pChain.doFilter(pRequest, pResponse);
} }
} }
@@ -48,7 +48,7 @@ import java.util.zip.GZIPOutputStream;
* @author Jayson Falkner * @author Jayson Falkner
* @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/gzip/GZIPResponseWrapper.java#1 $ * @version $Id: GZIPResponseWrapper.java#1 $
*/ */
public class GZIPResponseWrapper extends HttpServletResponseWrapper { public class GZIPResponseWrapper extends HttpServletResponseWrapper {
protected ServletOutputStream out; protected ServletOutputStream out;
@@ -121,7 +121,8 @@ public class GZIPResponseWrapper extends HttpServletResponseWrapper {
if (out == null) { if (out == null) {
out = createOutputStream(); out = createOutputStream();
} }
return (out);
return out;
} }
public PrintWriter getWriter() throws IOException { public PrintWriter getWriter() throws IOException {
@@ -134,9 +135,11 @@ public class GZIPResponseWrapper extends HttpServletResponseWrapper {
} }
out = 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 getCE returns null.
writer = new PrintWriter(new OutputStreamWriter(out, "UTF-8")); writer = new PrintWriter(new OutputStreamWriter(out, "UTF-8"));
return (writer);
return writer;
} }
public void setContentLength(int pLength) { public void setContentLength(int pLength) {
@@ -38,8 +38,8 @@ import java.awt.image.RenderedImage;
/** /**
* AWTImageFilterAdapter * AWTImageFilterAdapter
* *
* @author $Author: haku $ * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/AWTImageFilterAdapter.java#1 $ * @version $Id: AWTImageFilterAdapter.java#1 $
* *
*/ */
public class AWTImageFilterAdapter extends ImageFilter { public class AWTImageFilterAdapter extends ImageFilter {
@@ -67,6 +67,6 @@ public class AWTImageFilterAdapter extends ImageFilter {
Image img = ImageUtil.filter(pImage, imageFilter); 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 ok for JPEG only...
} }
} }
@@ -36,8 +36,8 @@ import java.awt.image.RenderedImage;
/** /**
* BufferedImageOpAdapter * BufferedImageOpAdapter
* *
* @author $Author: haku $ * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/BufferedImageOpAdapter.java#1 $ * @version $Id: BufferedImageOpAdapter.java#1 $
* *
*/ */
public class BufferedImageOpAdapter extends ImageFilter { public class BufferedImageOpAdapter extends ImageFilter {
@@ -47,7 +47,7 @@ import java.util.zip.CRC32;
* *
* @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/image/ColorServlet.java#2 $ * @version $Id: ColorServlet.java#2 $
*/ */
public class ColorServlet extends GenericServlet { public class ColorServlet extends GenericServlet {
private final static String RGB_PARAME = "color"; private final static String RGB_PARAME = "color";
@@ -38,7 +38,7 @@ import java.io.IOException;
* <p/> * <p/>
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/ComposeFilter.java#1 $ * @version $Id: ComposeFilter.java#1 $
*/ */
public class ComposeFilter extends ImageFilter { public class ComposeFilter extends ImageFilter {
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) throws IOException { protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) throws IOException {
@@ -54,6 +54,9 @@ import java.util.*;
* unneccessary conversion (as IE supports PNG, the latests FireFox supports * unneccessary conversion (as IE supports PNG, the latests FireFox supports
* JPEG and GIF, etc. even though they both don't explicitly list these formats * JPEG and GIF, etc. even though they both don't explicitly list these formats
* in their Accept headers). * in their Accept headers).
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: ContentNegotiationFilter.java#1 $
*/ */
public class ContentNegotiationFilter extends ImageFilter { public class ContentNegotiationFilter extends ImageFilter {
@@ -91,7 +91,7 @@ import java.awt.image.RenderedImage;
* *
* @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/image/CropFilter.java#1 $ * @version $Id: CropFilter.java#1 $
*/ */
public class CropFilter extends ScaleFilter { public class CropFilter extends ScaleFilter {
/** {@code cropX}*/ /** {@code cropX}*/
@@ -45,7 +45,7 @@ import java.io.IOException;
* @see #doFilter(java.awt.image.BufferedImage,javax.servlet.ServletRequest,ImageServletResponse) * @see #doFilter(java.awt.image.BufferedImage,javax.servlet.ServletRequest,ImageServletResponse)
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageFilter.java#2 $ * @version $Id: ImageFilter.java#2 $
* *
*/ */
public abstract class ImageFilter extends GenericFilter { public abstract class ImageFilter extends GenericFilter {
@@ -31,13 +31,13 @@ package com.twelvemonkeys.servlet.image;
import javax.servlet.*; import javax.servlet.*;
/** /**
* This excpetion is a subclass of ServletException, and acts just as a marker * This exception is a subclass of ServletException, and acts just as a marker
* for excpetions thrown by the ImageServlet API. * for exceptions thrown by the ImageServlet API.
* *
* @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/image/ImageServletException.java#2 $ * @version $Id: ImageServletException.java#2 $
*/ */
public class ImageServletException extends ServletException { public class ImageServletException extends ServletException {
@@ -41,7 +41,7 @@ import java.awt.image.BufferedImage;
* {@link #getImage()} to have any effect. * {@link #getImage()} to have any effect.
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponse.java#4 $ * @version $Id: ImageServletResponse.java#4 $
*/ */
public interface ImageServletResponse extends ServletResponse { public interface ImageServletResponse extends ServletResponse {
/** /**
@@ -65,7 +65,7 @@ import java.util.Iterator;
* <p> * <p>
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java#10 $ * @version $Id: ImageServletResponseImpl.java#10 $
* *
*/ */
// TODO: Refactor out HTTP specifics (if possible). // TODO: Refactor out HTTP specifics (if possible).
@@ -178,6 +178,20 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
originalContentLength = pLength; originalContentLength = pLength;
} }
@Override
public void setHeader(String name, String value) {
// NOTE: Clients could also specify content type/content length using the setHeader method, special handling
if (name != null && name.equals("Content-Length")) {
setContentLength(Integer.valueOf(value)); // Value might be too large, but we don't support that anyway
}
else if (name != null && name.equals("Content-Type")) {
setContentType(value);
}
else {
super.setHeader(name, value);
}
}
/** /**
* Writes the image to the original {@code ServletOutputStream}. * Writes the image to the original {@code ServletOutputStream}.
* If no format is set in this response, the image is encoded in the same * If no format is set in this response, the image is encoded in the same
@@ -211,14 +225,56 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima
Float requestQuality = (Float) originalRequest.getAttribute(ImageServletResponse.ATTRIB_OUTPUT_QUALITY); Float requestQuality = (Float) originalRequest.getAttribute(ImageServletResponse.ATTRIB_OUTPUT_QUALITY);
// The default JPEG quality is not good enough, so always apply compression // The default JPEG quality is not good enough, so always adjust compression/quality
if ((requestQuality != null || "jpeg".equalsIgnoreCase(getFormatNameSafe(writer))) && param.canWriteCompressed()) { if ((requestQuality != null || "jpeg".equalsIgnoreCase(getFormatNameSafe(writer))) && param.canWriteCompressed()) {
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
// WORKAROUND: Known bug in GIFImageWriter in certain JDK versions, compression type is not set
if (param.getCompressionTypes() != null && param.getCompressionType() == null) {
param.setCompressionType(param.getCompressionTypes()[0]); // Just choose any, to keep param happy
}
param.setCompressionQuality(requestQuality != null ? requestQuality : 0.8f); param.setCompressionQuality(requestQuality != null ? requestQuality : 0.8f);
} }
if ("gif".equalsIgnoreCase(getFormatNameSafe(writer)) && !(image.getColorModel() instanceof IndexColorModel)
&& image.getColorModel().getTransparency() != Transparency.OPAQUE) {
// WORKAROUND: Bug in GIFImageWriter may throw NPE if transparent pixels
// http://bugs.sun.com/view_bug.do?bug_id=6287936
image = ImageUtil.createIndexed(ImageUtil.toBuffered(image), 256, null, ImageUtil.TRANSPARENCY_BITMASK);
}
////////////////// //////////////////
ImageOutputStream stream = ImageIO.createImageOutputStream(out); ImageOutputStream stream = ImageIO.createImageOutputStream(out);
/*
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
JScrollPane scroll = new JScrollPane(new JLabel(new BufferedImageIcon(ImageUtil.toBuffered(image))) {
{
setOpaque(true);
setBackground(Color.ORANGE);
}
});
scroll.setBorder(BorderFactory.createEmptyBorder());
JOptionPane.showMessageDialog(null, scroll);
}
});
}
catch (InterruptedException ignore) {
}
catch (InvocationTargetException ignore) {
}
image = ImageUtil.createIndexed(ImageUtil.toBuffered(image));
// */
// Bug in GIF writer, if pixel at 0,0 is transparent.. :-P
// BufferedImage bufferedImage = ImageUtil.toBuffered(image);
// bufferedImage.setRGB(0, 0, bufferedImage.getRGB(0, 0) | 0xFF000000);
// image = bufferedImage;
writer.setOutput(stream); writer.setOutput(stream);
try { try {
writer.write(null, new IIOImage(image, null, null), param); writer.write(null, new IIOImage(image, null, null), param);
@@ -35,8 +35,8 @@ import java.awt.image.RenderedImage;
/** /**
* An {@code ImageFilter} that does nothing. Useful for debugging purposes. * An {@code ImageFilter} that does nothing. Useful for debugging purposes.
* *
* @author $Author: haku $ * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/NullImageFilter.java#2 $ * @version $Id: NullImageFilter.java $
* *
*/ */
public final class NullImageFilter extends ImageFilter { public final class NullImageFilter extends ImageFilter {
@@ -78,7 +78,7 @@ import java.awt.image.RenderedImage;
* *
* @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/image/RotateFilter.java#1 $ * @version $Id: RotateFilter.java#1 $
*/ */
public class RotateFilter extends ImageFilter { public class RotateFilter extends ImageFilter {
@@ -69,7 +69,7 @@ import java.lang.reflect.Field;
* *
* @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/image/ScaleFilter.java#1 $ * @version $Id: ScaleFilter.java#1 $
* *
* @example &lt;IMG src="/scale/test.jpg?scaleX=500&scaleUniform=false"&gt; * @example &lt;IMG src="/scale/test.jpg?scaleX=500&scaleUniform=false"&gt;
* @example &lt;IMG src="/scale/test.png?scaleY=50&scaleUnits=PERCENT"&gt; * @example &lt;IMG src="/scale/test.png?scaleY=50&scaleUnits=PERCENT"&gt;
@@ -21,69 +21,69 @@ import java.io.IOException;
* @see ImageServletResponse#ATTRIB_AOI * @see ImageServletResponse#ATTRIB_AOI
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/image/SourceRenderFilter.java#1 $ * @version $Id: SourceRenderFilter.java#1 $
*/ */
public class SourceRenderFilter extends ImageFilter { public class SourceRenderFilter extends ImageFilter {
private String mSizeWidthParam = "size.w"; private String sizeWidthParam = "size.w";
private String mSizeHeightParam = "size.h"; private String sizeHeightParam = "size.h";
private String mSizePercentParam = "size.percent"; private String sizePercentParam = "size.percent";
private String mSizeUniformParam = "size.uniform"; private String sizeUniformParam = "size.uniform";
private String mRegionWidthParam = "aoi.w"; private String regionWidthParam = "aoi.w";
private String mRegionHeightParam = "aoi.h"; private String regionHeightParam = "aoi.h";
private String mRegionLeftParam = "aoi.x"; private String regionLeftParam = "aoi.x";
private String mRegionTopParam = "aoi.y"; private String regionTopParam = "aoi.y";
private String mRegionPercentParam = "aoi.percent"; private String regionPercentParam = "aoi.percent";
private String mRegionUniformParam = "aoi.uniform"; private String regionUniformParam = "aoi.uniform";
public void setRegionHeightParam(String pRegionHeightParam) { public void setRegionHeightParam(String pRegionHeightParam) {
mRegionHeightParam = pRegionHeightParam; regionHeightParam = pRegionHeightParam;
} }
public void setRegionWidthParam(String pRegionWidthParam) { public void setRegionWidthParam(String pRegionWidthParam) {
mRegionWidthParam = pRegionWidthParam; regionWidthParam = pRegionWidthParam;
} }
public void setRegionLeftParam(String pRegionLeftParam) { public void setRegionLeftParam(String pRegionLeftParam) {
mRegionLeftParam = pRegionLeftParam; regionLeftParam = pRegionLeftParam;
} }
public void setRegionTopParam(String pRegionTopParam) { public void setRegionTopParam(String pRegionTopParam) {
mRegionTopParam = pRegionTopParam; regionTopParam = pRegionTopParam;
} }
public void setSizeHeightParam(String pSizeHeightParam) { public void setSizeHeightParam(String pSizeHeightParam) {
mSizeHeightParam = pSizeHeightParam; sizeHeightParam = pSizeHeightParam;
} }
public void setSizeWidthParam(String pSizeWidthParam) { public void setSizeWidthParam(String pSizeWidthParam) {
mSizeWidthParam = pSizeWidthParam; sizeWidthParam = pSizeWidthParam;
} }
public void setRegionPercentParam(String pRegionPercentParam) { public void setRegionPercentParam(String pRegionPercentParam) {
mRegionPercentParam = pRegionPercentParam; regionPercentParam = pRegionPercentParam;
} }
public void setRegionUniformParam(String pRegionUniformParam) { public void setRegionUniformParam(String pRegionUniformParam) {
mRegionUniformParam = pRegionUniformParam; regionUniformParam = pRegionUniformParam;
} }
public void setSizePercentParam(String pSizePercentParam) { public void setSizePercentParam(String pSizePercentParam) {
mSizePercentParam = pSizePercentParam; sizePercentParam = pSizePercentParam;
} }
public void setSizeUniformParam(String pSizeUniformParam) { public void setSizeUniformParam(String pSizeUniformParam) {
mSizeUniformParam = pSizeUniformParam; sizeUniformParam = pSizeUniformParam;
} }
public void init() throws ServletException { public void init() throws ServletException {
if (triggerParams == null) { if (triggerParams == null) {
// Add all params as triggers // Add all params as triggers
triggerParams = new String[]{mSizeWidthParam, mSizeHeightParam, triggerParams = new String[]{sizeWidthParam, sizeHeightParam,
mSizeUniformParam, mSizePercentParam, sizeUniformParam, sizePercentParam,
mRegionLeftParam, mRegionTopParam, regionLeftParam, regionTopParam,
mRegionWidthParam, mRegionHeightParam, regionWidthParam, regionHeightParam,
mRegionUniformParam, mRegionPercentParam}; regionUniformParam, regionPercentParam};
} }
} }
@@ -101,37 +101,37 @@ public class SourceRenderFilter extends ImageFilter {
// TODO: Max size configuration, to avoid DOS attacks? OutOfMemory // TODO: Max size configuration, to avoid DOS attacks? OutOfMemory
// Size parameters // Size parameters
int width = ServletUtil.getIntParameter(pRequest, mSizeWidthParam, -1); int width = ServletUtil.getIntParameter(pRequest, sizeWidthParam, -1);
int height = ServletUtil.getIntParameter(pRequest, mSizeHeightParam, -1); int height = ServletUtil.getIntParameter(pRequest, sizeHeightParam, -1);
if (width > 0 || height > 0) { if (width > 0 || height > 0) {
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE, new Dimension(width, height)); pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE, new Dimension(width, height));
} }
// Size uniform/percent // Size uniform/percent
boolean uniform = ServletUtil.getBooleanParameter(pRequest, mSizeUniformParam, true); boolean uniform = ServletUtil.getBooleanParameter(pRequest, sizeUniformParam, true);
if (!uniform) { if (!uniform) {
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_UNIFORM, Boolean.FALSE); pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_UNIFORM, Boolean.FALSE);
} }
boolean percent = ServletUtil.getBooleanParameter(pRequest, mSizePercentParam, false); boolean percent = ServletUtil.getBooleanParameter(pRequest, sizePercentParam, false);
if (percent) { if (percent) {
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_PERCENT, Boolean.TRUE); pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_PERCENT, Boolean.TRUE);
} }
// Area of interest parameters // Area of interest parameters
int x = ServletUtil.getIntParameter(pRequest, mRegionLeftParam, -1); // Default is center int x = ServletUtil.getIntParameter(pRequest, regionLeftParam, -1); // Default is center
int y = ServletUtil.getIntParameter(pRequest, mRegionTopParam, -1); // Default is center int y = ServletUtil.getIntParameter(pRequest, regionTopParam, -1); // Default is center
width = ServletUtil.getIntParameter(pRequest, mRegionWidthParam, -1); width = ServletUtil.getIntParameter(pRequest, regionWidthParam, -1);
height = ServletUtil.getIntParameter(pRequest, mRegionHeightParam, -1); height = ServletUtil.getIntParameter(pRequest, regionHeightParam, -1);
if (width > 0 || height > 0) { if (width > 0 || height > 0) {
pRequest.setAttribute(ImageServletResponse.ATTRIB_AOI, new Rectangle(x, y, width, height)); pRequest.setAttribute(ImageServletResponse.ATTRIB_AOI, new Rectangle(x, y, width, height));
} }
// AOI uniform/percent // AOI uniform/percent
uniform = ServletUtil.getBooleanParameter(pRequest, mRegionUniformParam, false); uniform = ServletUtil.getBooleanParameter(pRequest, regionUniformParam, false);
if (uniform) { if (uniform) {
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_UNIFORM, Boolean.TRUE); pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_UNIFORM, Boolean.TRUE);
} }
percent = ServletUtil.getBooleanParameter(pRequest, mRegionPercentParam, false); percent = ServletUtil.getBooleanParameter(pRequest, regionPercentParam, false);
if (percent) { if (percent) {
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_PERCENT, Boolean.TRUE); pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_PERCENT, Boolean.TRUE);
} }
@@ -144,7 +144,7 @@ import java.awt.geom.Rectangle2D;
* *
* @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/image/TextRenderer.java#2 $ * @version $Id: TextRenderer.java#2 $
*/ */
class TextRenderer /*extends ImageServlet implements ImagePainterServlet*/ { class TextRenderer /*extends ImageServlet implements ImagePainterServlet*/ {
@@ -342,7 +342,4 @@ class TextRenderer /*extends ImageServlet implements ImagePainterServlet*/ {
return angle; return angle;
} }
}
}
@@ -1,7 +1,6 @@
/** /**
* Contains various image-outputting servlets, that should run under any servlet engine. To create your own image servlet, simply subclass the servlet * Contains various image-outputting filters, that should run under any
* {@code ImageServlet}. Optionally implement the interface * servlet engine.
* {@code ImagePainterServlet}, if you want to do painting.
* <P> * <P>
* Some of these methods may require use of the native graphics libraries * Some of these methods may require use of the native graphics libraries
* supported by the JVM, like the X libraries on Unix systems, and should be * supported by the JVM, like the X libraries on Unix systems, and should be
@@ -13,8 +12,8 @@
* <A href="http://java.sun.com/j2se/1.4/docs/guide/awt/AWTChanges.html#headless">AWT Enhancements</A> and bugtraq report * <A href="http://java.sun.com/j2se/1.4/docs/guide/awt/AWTChanges.html#headless">AWT Enhancements</A> and bugtraq report
* <A href="http://developer.java.sun.com/developer/bugParade/bugs/4281163.html">4281163</A> for more information on this issue. * <A href="http://developer.java.sun.com/developer/bugParade/bugs/4281163.html">4281163</A> for more information on this issue.
* <P> * <P>
* If you cannot use JRE 1.4 for any reason, or do not want to use the X * If you cannot use JRE 1.4 or later, or do not want to use the X
* libraries, a possibilty is to use the * libraries, one possibility is to use the
* <A href="http://www.eteks.com/pja/en/">PJA package</A> (com.eteks.pja), * <A href="http://www.eteks.com/pja/en/">PJA package</A> (com.eteks.pja),
* and start the JVM with the following options: * and start the JVM with the following options:
* <DL> * <DL>