diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/AbstractServletMapAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/AbstractServletMapAdapter.java index 1dcf01f1..fea4e607 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/AbstractServletMapAdapter.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/AbstractServletMapAdapter.java @@ -25,14 +25,15 @@ abstract class AbstractServletMapAdapter extends AbstractMap valuesImpl(String pName); @Override - public List get(Object pKey) { + public List get(final Object pKey) { if (pKey instanceof String) { return getValues((String) pKey); } + return null; } - private List getValues(String pName) { + private List getValues(final String pName) { List values = mCache.get(pName); if (values == null) { @@ -61,13 +62,14 @@ abstract class AbstractServletMapAdapter extends AbstractMap names = keysImpl(); mSize = 0; - for (;names.hasNext(); names.next()) { + + for (Iterator names = keysImpl(); names.hasNext(); names.next()) { mSize++; } } diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/GenericFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/GenericFilter.java index 0a98a8f3..9b94f40c 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/GenericFilter.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/GenericFilter.java @@ -147,12 +147,12 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl * @see #init() init * @see BeanUtil#configure(Object, java.util.Map, boolean) */ - public void init(FilterConfig pConfig) throws ServletException { + public void init(final FilterConfig pConfig) throws ServletException { if (pConfig == null) { - throw new ServletConfigException("filterconfig == null"); + throw new ServletConfigException("filter config == null"); } - // Store filterconfig + // Store filter config mFilterConfig = pConfig; // Configure this @@ -197,8 +197,8 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl * @see Filter#doFilter Filter.doFilter * @see #doFilterImpl doFilterImpl */ - public final void doFilter(ServletRequest pRequest, ServletResponse pResponse, FilterChain pFilterChain) throws IOException, ServletException { - // If request filter and allready run, continue chain and return fast + 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 (mOncePerRequest && isRunOnce(pRequest)) { pFilterChain.doFilter(pRequest, pResponse); return; @@ -225,8 +225,8 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl * @return {@code true} if the request is allready filtered, otherwise * {@code false}. */ - private boolean isRunOnce(ServletRequest pRequest) { - // If request allready filtered, return true (skip) + private boolean isRunOnce(final ServletRequest pRequest) { + // If request already filtered, return true (skip) if (pRequest.getAttribute(mAttribRunOnce) == ATTRIB_RUN_ONCE_VALUE) { return true; } @@ -299,7 +299,7 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl * @return a {@code String} containing the value of the initialization * parameter */ - public String getInitParameter(String pKey) { + public String getInitParameter(final String pKey) { return mFilterConfig.getInitParameter(pKey); } @@ -322,7 +322,7 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl * @param pMessage the log message * @see ServletContext#log(String) */ - protected void log(String pMessage) { + protected void log(final String pMessage) { getServletContext().log(getFilterName() + ": " + pMessage); } @@ -335,7 +335,7 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl * @param pThrowable the exception * @see ServletContext#log(String,Throwable) */ - protected void log(String pMessage, Throwable pThrowable) { + protected void log(final String pMessage, final Throwable pThrowable) { getServletContext().log(getFilterName() + ": " + pMessage, pThrowable); } @@ -347,12 +347,12 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl * * @deprecated For compatibility only, use {@link #init init} instead. */ - public void setFilterConfig(FilterConfig pFilterConfig) { + public void setFilterConfig(final FilterConfig pFilterConfig) { try { init(pFilterConfig); } catch (ServletException e) { - log("Error in init(), see stacktrace for details.", e); + log("Error in init(), see stack trace for details.", e); } } @@ -376,8 +376,8 @@ public abstract class GenericFilter implements Filter, FilterConfig, Serializabl * once per request * @see #mOncePerRequest */ - @InitParam - public void setOncePerRequest(boolean pOncePerRequest) { + @InitParam(name = "once-per-request") + public void setOncePerRequest(final boolean pOncePerRequest) { mOncePerRequest = pOncePerRequest; } } diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/InitParam.java b/servlet/src/main/java/com/twelvemonkeys/servlet/InitParam.java index 6fb02155..aece7b96 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/InitParam.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/InitParam.java @@ -31,7 +31,7 @@ package com.twelvemonkeys.servlet; import java.lang.annotation.*; /** - * Annotation to be used by serlvets/filters, to have their init-method + * Annotation to be used by servlets/filters, to have their {@code init}-method * automatically convert and set values from their respective configuration. * * @author Harald Kuhr @@ -41,10 +41,12 @@ import java.lang.annotation.*; * @see com.twelvemonkeys.servlet.GenericServlet#init(javax.servlet.ServletConfig) * @see com.twelvemonkeys.servlet.HttpServlet#init(javax.servlet.ServletConfig) */ +// TODO: Actually implement for version 3.0! @Documented @Inherited @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface InitParam { + // TODO: Rename to value, to allow skipping name = "..." String name() default ""; } diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigException.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigException.java index 3d189490..66e8c33e 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigException.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigException.java @@ -53,7 +53,7 @@ public class ServletConfigException extends ServletException { * @param pMessage the exception message * @param pCause the exception cause */ - public ServletConfigException(String pMessage, Throwable pCause) { + public ServletConfigException(final String pMessage, final Throwable pCause) { super(pMessage, pCause); if (getCause() == null) { initCause(pCause); @@ -65,28 +65,10 @@ public class ServletConfigException extends ServletException { * * @param pCause the exception cause */ - public ServletConfigException(Throwable pCause) { - super("Erorr in Servlet configuration: " + pCause.getMessage(), pCause); + public ServletConfigException(final Throwable pCause) { + super("Error in Servlet configuration: " + pCause.getMessage(), pCause); if (getCause() == null) { initCause(pCause); } } - - /** - * Gets the cause of this {@code ServletConfigException}. - * - * @return the cause, or {@code null} if unknown. - * @see #getRootCause() - */ -// public final Throwable getCause() { -// Throwable cause = super.getCause(); -// return cause != null ? cause : super.getRootCause(); -// } - - /** - * @deprecated Use {@link #getCause()} instead. - */ -// public final Throwable getRootCause() { -// return getCause(); -// } } diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigMapAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigMapAdapter.java index d01d611a..822759cb 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigMapAdapter.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigMapAdapter.java @@ -29,6 +29,7 @@ package com.twelvemonkeys.servlet; import com.twelvemonkeys.lang.StringUtil; +import com.twelvemonkeys.lang.Validate; import javax.servlet.FilterConfig; import javax.servlet.ServletConfig; @@ -52,7 +53,6 @@ class ServletConfigMapAdapter extends AbstractMap implements Map ServletConfig, FilterConfig, ServletContext } -// private final boolean mIsServlet; private final ConfigType mType; private final ServletConfig mServletConfig; @@ -62,23 +62,21 @@ class ServletConfigMapAdapter extends AbstractMap implements Map // Cache the entry set private transient Set> mEntrySet; - public ServletConfigMapAdapter(ServletConfig pConfig) { + public ServletConfigMapAdapter(final ServletConfig pConfig) { this(pConfig, ConfigType.ServletConfig); } - public ServletConfigMapAdapter(FilterConfig pConfig) { + public ServletConfigMapAdapter(final FilterConfig pConfig) { this(pConfig, ConfigType.FilterConfig); } - public ServletConfigMapAdapter(ServletContext pContext) { + public ServletConfigMapAdapter(final ServletContext pContext) { this(pContext, ConfigType.ServletContext); } - private ServletConfigMapAdapter(Object pConfig, ConfigType pType) { - if (pConfig == null) { - // Could happen of client code invokes with null reference - throw new IllegalArgumentException("Config == null"); - } + private ServletConfigMapAdapter(final Object pConfig, final ConfigType pType) { + // Could happen if client code invokes with null reference + Validate.notNull(pConfig, "config"); mType = pType; diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/SerlvetHeadersMapAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapter.java similarity index 84% rename from servlet/src/main/java/com/twelvemonkeys/servlet/SerlvetHeadersMapAdapter.java rename to servlet/src/main/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapter.java index 3db799fe..bf4b0bae 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/SerlvetHeadersMapAdapter.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapter.java @@ -7,17 +7,17 @@ import java.util.Enumeration; import java.util.Iterator; /** - * HeaderMap + * ServletHeadersMapAdapter * * @author Harald Kuhr * @author last modified by $Author: haku $ - * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/SerlvetHeadersMapAdapter.java#1 $ + * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapter.java#1 $ */ -class SerlvetHeadersMapAdapter extends AbstractServletMapAdapter { +class ServletHeadersMapAdapter extends AbstractServletMapAdapter { protected final HttpServletRequest mRequest; - public SerlvetHeadersMapAdapter(HttpServletRequest pRequest) { + public ServletHeadersMapAdapter(HttpServletRequest pRequest) { if (pRequest == null) { throw new IllegalArgumentException("request == null"); } diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/SerlvetParametersMapAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletParametersMapAdapter.java similarity index 83% rename from servlet/src/main/java/com/twelvemonkeys/servlet/SerlvetParametersMapAdapter.java rename to servlet/src/main/java/com/twelvemonkeys/servlet/ServletParametersMapAdapter.java index 0665e1fd..9e2ca4ab 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/SerlvetParametersMapAdapter.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletParametersMapAdapter.java @@ -7,17 +7,17 @@ import java.util.Iterator; import java.util.Enumeration; /** - * HeaderMap + * ServletParametersMapAdapter * * @author Harald Kuhr * @author last modified by $Author: haku $ - * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/SerlvetParametersMapAdapter.java#1 $ + * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/ServletParametersMapAdapter.java#1 $ */ -class SerlvetParametersMapAdapter extends AbstractServletMapAdapter { +class ServletParametersMapAdapter extends AbstractServletMapAdapter { protected final HttpServletRequest mRequest; - public SerlvetParametersMapAdapter(HttpServletRequest pRequest) { + public ServletParametersMapAdapter(HttpServletRequest pRequest) { if (pRequest == null) { throw new IllegalArgumentException("request == null"); } diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletUtil.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletUtil.java index df937202..677e993d 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletUtil.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletUtil.java @@ -37,15 +37,12 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.File; -import java.io.PrintStream; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.MalformedURLException; import java.net.URL; -import java.util.Date; -import java.util.Enumeration; import java.util.List; import java.util.Map; @@ -61,52 +58,52 @@ import java.util.Map; public final class ServletUtil { /** - * "javax.servlet.include.request_uri" + * {@code "javax.servlet.include.request_uri"} */ private final static String ATTRIB_INC_REQUEST_URI = "javax.servlet.include.request_uri"; /** - * "javax.servlet.include.context_path" + * {@code "javax.servlet.include.context_path"} */ private final static String ATTRIB_INC_CONTEXT_PATH = "javax.servlet.include.context_path"; /** - * "javax.servlet.include.servlet_path" + * {@code "javax.servlet.include.servlet_path"} */ private final static String ATTRIB_INC_SERVLET_PATH = "javax.servlet.include.servlet_path"; /** - * "javax.servlet.include.path_info" + * {@code "javax.servlet.include.path_info"} */ private final static String ATTRIB_INC_PATH_INFO = "javax.servlet.include.path_info"; /** - * "javax.servlet.include.query_string" + * {@code "javax.servlet.include.query_string"} */ private final static String ATTRIB_INC_QUERY_STRING = "javax.servlet.include.query_string"; /** - * "javax.servlet.forward.request_uri" + * {@code "javax.servlet.forward.request_uri"} */ private final static String ATTRIB_FWD_REQUEST_URI = "javax.servlet.forward.request_uri"; /** - * "javax.servlet.forward.context_path" + * {@code "javax.servlet.forward.context_path"} */ private final static String ATTRIB_FWD_CONTEXT_PATH = "javax.servlet.forward.context_path"; /** - * "javax.servlet.forward.servlet_path" + * {@code "javax.servlet.forward.servlet_path"} */ private final static String ATTRIB_FWD_SERVLET_PATH = "javax.servlet.forward.servlet_path"; /** - * "javax.servlet.forward.path_info" + * {@code "javax.servlet.forward.path_info"} */ private final static String ATTRIB_FWD_PATH_INFO = "javax.servlet.forward.path_info"; /** - * "javax.servlet.forward.query_string" + * {@code "javax.servlet.forward.query_string"} */ private final static String ATTRIB_FWD_QUERY_STRING = "javax.servlet.forward.query_string"; @@ -126,10 +123,10 @@ public final class ServletUtil { * @return the value of the parameter, or the default value, if the * parameter is not set. */ - public static String getParameter(ServletRequest pReq, String pName, String pDefault) { + public static String getParameter(final ServletRequest pReq, final String pName, final String pDefault) { String str = pReq.getParameter(pName); - return ((str != null) ? str : pDefault); + return str != null ? str : pDefault; } /** @@ -148,13 +145,10 @@ public final class ServletUtil { * non-{@code null} and not an instance of {@code pType} * @throws NullPointerException if {@code pReq}, {@code pName} or * {@code pType} is {@code null}. - * @todo Well, it's done. Need some thinking... + * @todo Well, it's done. Need some thinking... We probably don't want default if conversion fails... * @see Converter#toObject */ - - // public static T getParameter(ServletRequest pReq, String pName, - // String pFormat, T pDefault) { - static T getParameter(ServletRequest pReq, String pName, Class pType, String pFormat, T pDefault) { + static T getParameter(final ServletRequest pReq, final String pName, final Class pType, final String pFormat, final T pDefault) { // Test if pDefault is either null or instance of pType if (pDefault != null && !pType.isInstance(pDefault)) { throw new IllegalArgumentException("default value not instance of " + pType + ": " + pDefault.getClass()); @@ -165,6 +159,7 @@ public final class ServletUtil { if (str == null) { return pDefault; } + try { return pType.cast(Converter.getInstance().toObject(str, pType, pFormat)); } @@ -175,20 +170,20 @@ public final class ServletUtil { /** * Gets the value of the given parameter from the request converted to - * a boolean. If the parameter is not set or not parseable, the default + * a {@code boolean}. If the parameter is not set or not parseable, the default * value is returned. * * @param pReq the servlet request * @param pName the parameter name * @param pDefault the default value - * @return the value of the parameter converted to a boolean, or the + * @return the value of the parameter converted to a {@code boolean}, or the * default value, if the parameter is not set. */ - public static boolean getBooleanParameter(ServletRequest pReq, String pName, boolean pDefault) { + public static boolean getBooleanParameter(final ServletRequest pReq, final String pName, final boolean pDefault) { String str = pReq.getParameter(pName); try { - return ((str != null) ? Boolean.valueOf(str) : pDefault); + return str != null ? Boolean.valueOf(str) : pDefault; } catch (NumberFormatException nfe) { return pDefault; @@ -197,20 +192,20 @@ public final class ServletUtil { /** * Gets the value of the given parameter from the request converted to - * an int. If the parameter is not set or not parseable, the default + * an {@code int}. If the parameter is not set or not parseable, the default * value is returned. * * @param pReq the servlet request * @param pName the parameter name * @param pDefault the default value - * @return the value of the parameter converted to an int, or the default + * @return the value of the parameter converted to an {@code int}, or the default * value, if the parameter is not set. */ - public static int getIntParameter(ServletRequest pReq, String pName, int pDefault) { + public static int getIntParameter(final ServletRequest pReq, final String pName, final int pDefault) { String str = pReq.getParameter(pName); try { - return ((str != null) ? Integer.parseInt(str) : pDefault); + return str != null ? Integer.parseInt(str) : pDefault; } catch (NumberFormatException nfe) { return pDefault; @@ -219,20 +214,20 @@ public final class ServletUtil { /** * Gets the value of the given parameter from the request converted to - * an long. If the parameter is not set or not parseable, the default + * an {@code long}. If the parameter is not set or not parseable, the default * value is returned. * * @param pReq the servlet request * @param pName the parameter name * @param pDefault the default value - * @return the value of the parameter converted to an long, or the default + * @return the value of the parameter converted to an {@code long}, or the default * value, if the parameter is not set. */ - public static long getLongParameter(ServletRequest pReq, String pName, long pDefault) { + public static long getLongParameter(final ServletRequest pReq, final String pName, final long pDefault) { String str = pReq.getParameter(pName); try { - return ((str != null) ? Long.parseLong(str) : pDefault); + return str != null ? Long.parseLong(str) : pDefault; } catch (NumberFormatException nfe) { return pDefault; @@ -241,20 +236,20 @@ public final class ServletUtil { /** * Gets the value of the given parameter from the request converted to - * a float. If the parameter is not set or not parseable, the default + * a {@code float}. If the parameter is not set or not parseable, the default * value is returned. * * @param pReq the servlet request * @param pName the parameter name * @param pDefault the default value - * @return the value of the parameter converted to a float, or the default + * @return the value of the parameter converted to a {@code float}, or the default * value, if the parameter is not set. */ - public static float getFloatParameter(ServletRequest pReq, String pName, float pDefault) { + public static float getFloatParameter(final ServletRequest pReq, final String pName, final float pDefault) { String str = pReq.getParameter(pName); try { - return ((str != null) ? Float.parseFloat(str) : pDefault); + return str != null ? Float.parseFloat(str) : pDefault; } catch (NumberFormatException nfe) { return pDefault; @@ -263,20 +258,20 @@ public final class ServletUtil { /** * Gets the value of the given parameter from the request converted to - * a double. If the parameter is not set or not parseable, the default + * a {@code double}. If the parameter is not set or not parseable, the default * value is returned. * * @param pReq the servlet request * @param pName the parameter name * @param pDefault the default value - * @return the value of the parameter converted to n double, or the default + * @return the value of the parameter converted to n {@code double}, or the default * value, if the parameter is not set. */ - public static double getDoubleParameter(ServletRequest pReq, String pName, double pDefault) { + public static double getDoubleParameter(final ServletRequest pReq, final String pName, final double pDefault) { String str = pReq.getParameter(pName); try { - return ((str != null) ? Double.parseDouble(str) : pDefault); + return str != null ? Double.parseDouble(str) : pDefault; } catch (NumberFormatException nfe) { return pDefault; @@ -285,20 +280,20 @@ public final class ServletUtil { /** * Gets the value of the given parameter from the request converted to - * a Date. If the parameter is not set or not parseable, the + * a {@code Date}. If the parameter is not set or not parseable, the * default value is returned. * * @param pReq the servlet request * @param pName the parameter name * @param pDefault the default value - * @return the value of the parameter converted to a Date, or the + * @return the value of the parameter converted to a {@code Date}, or the * default value, if the parameter is not set. * @see com.twelvemonkeys.lang.StringUtil#toDate(String) */ - public static long getDateParameter(ServletRequest pReq, String pName, long pDefault) { + public static long getDateParameter(final ServletRequest pReq, final String pName, final long pDefault) { String str = pReq.getParameter(pName); try { - return ((str != null) ? StringUtil.toDate(str).getTime() : pDefault); + return str != null ? StringUtil.toDate(str).getTime() : pDefault; } catch (IllegalArgumentException iae) { return pDefault; @@ -341,7 +336,7 @@ public final class ServletUtil { * @deprecated Use {@link javax.servlet.http.HttpServletRequest#getRequestURL()} * instead. */ - static StringBuffer buildHTTPURL(HttpServletRequest pRequest) { + static StringBuffer buildHTTPURL(final HttpServletRequest pRequest) { StringBuffer resultURL = new StringBuffer(); // Scheme, as in http, https, ftp etc @@ -381,7 +376,7 @@ public final class ServletUtil { * @see HttpServletRequest#getRequestURI * @since Servlet 2.2 */ - public static String getIncludeRequestURI(ServletRequest pRequest) { + public static String getIncludeRequestURI(final ServletRequest pRequest) { return (String) pRequest.getAttribute(ATTRIB_INC_REQUEST_URI); } @@ -395,7 +390,7 @@ public final class ServletUtil { * @see HttpServletRequest#getContextPath * @since Servlet 2.2 */ - public static String getIncludeContextPath(ServletRequest pRequest) { + public static String getIncludeContextPath(final ServletRequest pRequest) { return (String) pRequest.getAttribute(ATTRIB_INC_CONTEXT_PATH); } @@ -409,7 +404,7 @@ public final class ServletUtil { * @see HttpServletRequest#getServletPath * @since Servlet 2.2 */ - public static String getIncludeServletPath(ServletRequest pRequest) { + public static String getIncludeServletPath(final ServletRequest pRequest) { return (String) pRequest.getAttribute(ATTRIB_INC_SERVLET_PATH); } @@ -423,7 +418,7 @@ public final class ServletUtil { * @see HttpServletRequest#getPathInfo * @since Servlet 2.2 */ - public static String getIncludePathInfo(ServletRequest pRequest) { + public static String getIncludePathInfo(final ServletRequest pRequest) { return (String) pRequest.getAttribute(ATTRIB_INC_PATH_INFO); } @@ -437,7 +432,7 @@ public final class ServletUtil { * @see HttpServletRequest#getQueryString * @since Servlet 2.2 */ - public static String getIncludeQueryString(ServletRequest pRequest) { + public static String getIncludeQueryString(final ServletRequest pRequest) { return (String) pRequest.getAttribute(ATTRIB_INC_QUERY_STRING); } @@ -451,7 +446,7 @@ public final class ServletUtil { * @see HttpServletRequest#getRequestURI * @since Servlet 2.4 */ - public static String getForwardRequestURI(ServletRequest pRequest) { + public static String getForwardRequestURI(final ServletRequest pRequest) { return (String) pRequest.getAttribute(ATTRIB_FWD_REQUEST_URI); } @@ -465,7 +460,7 @@ public final class ServletUtil { * @see HttpServletRequest#getContextPath * @since Servlet 2.4 */ - public static String getForwardContextPath(ServletRequest pRequest) { + public static String getForwardContextPath(final ServletRequest pRequest) { return (String) pRequest.getAttribute(ATTRIB_FWD_CONTEXT_PATH); } @@ -479,7 +474,7 @@ public final class ServletUtil { * @see HttpServletRequest#getServletPath * @since Servlet 2.4 */ - public static String getForwardServletPath(ServletRequest pRequest) { + public static String getForwardServletPath(final ServletRequest pRequest) { return (String) pRequest.getAttribute(ATTRIB_FWD_SERVLET_PATH); } @@ -493,7 +488,7 @@ public final class ServletUtil { * @see HttpServletRequest#getPathInfo * @since Servlet 2.4 */ - public static String getForwardPathInfo(ServletRequest pRequest) { + public static String getForwardPathInfo(final ServletRequest pRequest) { return (String) pRequest.getAttribute(ATTRIB_FWD_PATH_INFO); } @@ -507,7 +502,7 @@ public final class ServletUtil { * @see HttpServletRequest#getQueryString * @since Servlet 2.4 */ - public static String getForwardQueryString(ServletRequest pRequest) { + public static String getForwardQueryString(final ServletRequest pRequest) { return (String) pRequest.getAttribute(ATTRIB_FWD_QUERY_STRING); } @@ -519,7 +514,7 @@ public final class ServletUtil { * @todo Read the spec, seems to be a mismatch with the Servlet API... * @see javax.servlet.http.HttpServletRequest#getServletPath() */ - static String getScriptName(HttpServletRequest pRequest) { + static String getScriptName(final HttpServletRequest pRequest) { String requestURI = pRequest.getRequestURI(); return StringUtil.getLastElement(requestURI, "/"); } @@ -536,11 +531,13 @@ public final class ServletUtil { * @param pRequest the current HTTP request * @return the request URI relative to the current context path. */ - public static String getContextRelativeURI(HttpServletRequest pRequest) { + public static String getContextRelativeURI(final HttpServletRequest pRequest) { String context = pRequest.getContextPath(); + if (!StringUtil.isEmpty(context)) { // "" for root context return pRequest.getRequestURI().substring(context.length()); } + return pRequest.getRequestURI(); } @@ -557,12 +554,14 @@ public final class ServletUtil { * @see ServletContext#getRealPath(java.lang.String) * @see ServletContext#getResource(java.lang.String) */ - public static URL getRealURL(ServletContext pContext, String pPath) throws MalformedURLException { + public static URL getRealURL(final ServletContext pContext, final String pPath) throws MalformedURLException { String realPath = pContext.getRealPath(pPath); + if (realPath != null) { // NOTE: First convert to URI, as of Java 6 File.toURL is deprecated return new File(realPath).toURI().toURL(); } + return null; } @@ -572,20 +571,19 @@ public final class ServletUtil { * @param pContext the servlet context * @return the temp directory */ - public static File getTempDir(ServletContext pContext) { + public static File getTempDir(final ServletContext pContext) { return (File) pContext.getAttribute("javax.servlet.context.tempdir"); } /** - * Gets the identificator string containing the unique identifier assigned - * to this session. + * Gets the unique identifier assigned to this session. * The identifier is assigned by the servlet container and is implementation * dependent. * * @param pRequest The HTTP servlet request object. * @return the session Id */ - public static String getSessionId(HttpServletRequest pRequest) { + public static String getSessionId(final HttpServletRequest pRequest) { HttpSession session = pRequest.getSession(); return (session != null) ? session.getId() : null; @@ -598,11 +596,11 @@ public final class ServletUtil { * operations and iterating over it's {@code keySet}. * For other operations it may not perform well. * - * @param pConfig the serlvet configuration + * @param pConfig the servlet configuration * @return a {@code Map} view of the config * @throws IllegalArgumentException if {@code pConfig} is {@code null} */ - public static Map asMap(ServletConfig pConfig) { + public static Map asMap(final ServletConfig pConfig) { return new ServletConfigMapAdapter(pConfig); } @@ -617,7 +615,7 @@ public final class ServletUtil { * @return a {@code Map} view of the config * @throws IllegalArgumentException if {@code pConfig} is {@code null} */ - public static Map asMap(FilterConfig pConfig) { + public static Map asMap(final FilterConfig pConfig) { return new ServletConfigMapAdapter(pConfig); } @@ -636,6 +634,13 @@ public final class ServletUtil { return new ServletConfigMapAdapter(pContext); } + // TODO? +// public static Map attributesAsMap(final ServletContext pContext) { +// } +// +// public static Map attributesAsMap(final ServletRequest pRequest) { +// } +// /** * Creates an unmodifiable {@code Map} view of the given * {@code HttpServletRequest}s request parameters. @@ -645,7 +650,7 @@ public final class ServletUtil { * @throws IllegalArgumentException if {@code pRequest} is {@code null} */ public static Map> parametersAsMap(final HttpServletRequest pRequest) { - return new SerlvetParametersMapAdapter(pRequest); + return new ServletParametersMapAdapter(pRequest); } /** @@ -657,7 +662,7 @@ public final class ServletUtil { * @throws IllegalArgumentException if {@code pRequest} is {@code null} */ public static Map> headersAsMap(final HttpServletRequest pRequest) { - return new SerlvetHeadersMapAdapter(pRequest); + return new ServletHeadersMapAdapter(pRequest); } /** @@ -700,329 +705,22 @@ public final class ServletUtil { return pImplementation; } - - /** - * Prints the init parameters in a {@code javax.servlet.ServletConfig} - * object to a {@code java.io.PrintStream}. - *

- * - * @param pServletConfig The Servlet Config object. - * @param pPrintStream The {@code java.io.PrintStream} for flushing - * the results. - */ - public static void printDebug(final ServletConfig pServletConfig, final PrintStream pPrintStream) { - Enumeration parameterNames = pServletConfig.getInitParameterNames(); - - while (parameterNames.hasMoreElements()) { - String initParameterName = (String) parameterNames.nextElement(); - - pPrintStream.println(initParameterName + ": " + pServletConfig.getInitParameter(initParameterName)); - } - } - - /** - * Prints the init parameters in a {@code javax.servlet.ServletConfig} - * object to {@code System.out}. - * - * @param pServletConfig the Servlet Config object. - */ - public static void printDebug(final ServletConfig pServletConfig) { - printDebug(pServletConfig, System.out); - } - - /** - * Prints the init parameters in a {@code javax.servlet.ServletContext} - * object to a {@code java.io.PrintStream}. - * - * @param pServletContext the Servlet Context object. - * @param pPrintStream the {@code java.io.PrintStream} for flushing the - * results. - */ - public static void printDebug(final ServletContext pServletContext, final PrintStream pPrintStream) { - Enumeration parameterNames = pServletContext.getInitParameterNames(); - - while (parameterNames.hasMoreElements()) { - String initParameterName = (String) parameterNames.nextElement(); - - pPrintStream.println(initParameterName + ": " + pServletContext.getInitParameter(initParameterName)); - } - } - - /** - * Prints the init parameters in a {@code javax.servlet.ServletContext} - * object to {@code System.out}. - * - * @param pServletContext The Servlet Context object. - */ - public static void printDebug(final ServletContext pServletContext) { - printDebug(pServletContext, System.out); - } - - /** - * Prints an excerpt of the residing information in a - * {@code javax.servlet.http.HttpServletRequest} object to a - * {@code java.io.PrintStream}. - * - * @param pRequest The HTTP servlet request object. - * @param pPrintStream The {@code java.io.PrintStream} for flushing - * the results. - */ - public static void printDebug(final HttpServletRequest pRequest, final PrintStream pPrintStream) { - String indentation = " "; - StringBuilder buffer = new StringBuilder(); - - // Returns the name of the authentication scheme used to protect the - // servlet, for example, "BASIC" or "SSL," or null if the servlet was - // not protected. - buffer.append(indentation); - buffer.append("Authentication scheme: "); - buffer.append(pRequest.getAuthType()); - buffer.append("\n"); - - // Returns the portion of the request URI that indicates the context - // of the request. - buffer.append(indentation); - buffer.append("Context path: "); - buffer.append(pRequest.getContextPath()); - buffer.append("\n"); - - // Returns an enumeration of all the header mNames this request contains. - buffer.append(indentation); - buffer.append("Header:"); - buffer.append("\n"); - Enumeration headerNames = pRequest.getHeaderNames(); - - while (headerNames.hasMoreElements()) { - String headerElement = (String) headerNames.nextElement(); - - buffer.append(indentation); - buffer.append(indentation); - buffer.append(headerElement); - buffer.append(": "); - buffer.append(pRequest.getHeader(headerElement)); - buffer.append("\n"); - } - - // Returns the name of the HTTP method with which this request was made, - // for example, GET, POST, or PUT. - buffer.append(indentation); - buffer.append("HTTP method: "); - buffer.append(pRequest.getMethod()); - buffer.append("\n"); - - // Returns any extra path information associated with the URL the client - // sent when it made this request. - buffer.append(indentation); - buffer.append("Extra path information from client: "); - buffer.append(pRequest.getPathInfo()); - buffer.append("\n"); - - // Returns any extra path information after the servlet name but before - // the query string, and translates it to a real path. - buffer.append(indentation); - buffer.append("Extra translated path information from client: "); - buffer.append(pRequest.getPathTranslated()); - buffer.append("\n"); - - // Returns the login of the user making this request, if the user has - // been authenticated, or null if the user has not been authenticated. - buffer.append(indentation); - String userInfo = pRequest.getRemoteUser(); - - if (StringUtil.isEmpty(userInfo)) { - buffer.append("User is not authenticated"); - } - else { - buffer.append("User logint: "); - buffer.append(userInfo); - } - buffer.append("\n"); - - // Returns the session ID specified by the client. - buffer.append(indentation); - buffer.append("Session ID from client: "); - buffer.append(pRequest.getRequestedSessionId()); - buffer.append("\n"); - - // Returns the server name. - buffer.append(indentation); - buffer.append("Server name: "); - buffer.append(pRequest.getServerName()); - buffer.append("\n"); - - // Returns the part of this request's URL from the protocol name up - // to the query string in the first line of the HTTP request. - buffer.append(indentation); - buffer.append("Request URI: ").append(pRequest.getRequestURI()); - buffer.append("\n"); - - // Returns the path info. - buffer.append(indentation); - buffer.append("Path information: ").append(pRequest.getPathInfo()); - buffer.append("\n"); - - // Returns the part of this request's URL that calls the servlet. - buffer.append(indentation); - buffer.append("Servlet path: ").append(pRequest.getServletPath()); - buffer.append("\n"); - - // Returns the query string that is contained in the request URL after - // the path. - buffer.append(indentation); - buffer.append("Query string: ").append(pRequest.getQueryString()); - buffer.append("\n"); - - // Returns an enumeration of all the parameters bound to this request. - buffer.append(indentation); - buffer.append("Parameters:"); - buffer.append("\n"); - Enumeration parameterNames = pRequest.getParameterNames(); - while (parameterNames.hasMoreElements()) { - String parameterName = (String) parameterNames.nextElement(); - - buffer.append(indentation); - buffer.append(indentation); - buffer.append(parameterName); - buffer.append(": "); - buffer.append(pRequest.getParameter(parameterName)); - buffer.append("\n"); - } - - // Returns an enumeration of all the attribute objects bound to this - // request. - buffer.append(indentation); - buffer.append("Attributes:"); - buffer.append("\n"); - Enumeration attributeNames = pRequest.getAttributeNames(); - while (attributeNames.hasMoreElements()) { - String attributeName = (String) attributeNames.nextElement(); - - buffer.append(indentation); - buffer.append(indentation); - buffer.append(attributeName); - buffer.append(": "); - buffer.append(pRequest.getAttribute(attributeName).toString()); - buffer.append("\n"); - } - pPrintStream.println(buffer.toString()); - } - - /** - * Prints an excerpt of the residing information in a - * {@code javax.servlet.http.HttpServletRequest} object to - * {@code System.out}. - * - * @param pRequest The HTTP servlet request object. - */ - public static void printDebug(final HttpServletRequest pRequest) { - printDebug(pRequest, System.out); - } - - /** - * Prints an excerpt of a {@code javax.servlet.http.HttpSession} object - * to a {@code java.io.PrintStream}. - * - * @param pHttpSession The HTTP Session object. - * @param pPrintStream The {@code java.io.PrintStream} for flushing - * the results. - */ - public static void printDebug(final HttpSession pHttpSession, final PrintStream pPrintStream) { - String indentation = " "; - StringBuilder buffer = new StringBuilder(); - - if (pHttpSession == null) { - buffer.append(indentation); - buffer.append("No session object available"); - buffer.append("\n"); - } - else { - - // Returns a string containing the unique identifier assigned to - //this session - buffer.append(indentation); - buffer.append("Session ID: ").append(pHttpSession.getId()); - buffer.append("\n"); - - // Returns the last time the client sent a request associated with - // this session, as the number of milliseconds since midnight - // January 1, 1970 GMT, and marked by the time the container - // recieved the request - buffer.append(indentation); - buffer.append("Last accessed time: "); - buffer.append(new Date(pHttpSession.getLastAccessedTime())); - buffer.append("\n"); - - // Returns the time when this session was created, measured in - // milliseconds since midnight January 1, 1970 GMT - buffer.append(indentation); - buffer.append("Creation time: "); - buffer.append(new Date(pHttpSession.getCreationTime())); - buffer.append("\n"); - - // Returns true if the client does not yet know about the session - // or if the client chooses not to join the session - buffer.append(indentation); - buffer.append("New session?: "); - buffer.append(pHttpSession.isNew()); - buffer.append("\n"); - - // Returns the maximum time interval, in seconds, that the servlet - // container will keep this session open between client accesses - buffer.append(indentation); - buffer.append("Max inactive interval: "); - buffer.append(pHttpSession.getMaxInactiveInterval()); - buffer.append("\n"); - - // Returns an enumeration of all the attribute objects bound to - // this session - buffer.append(indentation); - buffer.append("Attributes:"); - buffer.append("\n"); - Enumeration attributeNames = pHttpSession.getAttributeNames(); - - while (attributeNames.hasMoreElements()) { - String attributeName = (String) attributeNames.nextElement(); - - buffer.append(indentation); - buffer.append(indentation); - buffer.append(attributeName); - buffer.append(": "); - buffer.append(pHttpSession.getAttribute(attributeName).toString()); - buffer.append("\n"); - } - } - pPrintStream.println(buffer.toString()); - } - - /** - * Prints an excerpt of a {@code javax.servlet.http.HttpSession} - * object to {@code System.out}. - *

- * - * @param pHttpSession The HTTP Session object. - */ - public static void printDebug(final HttpSession pHttpSession) { - printDebug(pHttpSession, System.out); - } - private static class HttpServletResponseHandler implements InvocationHandler { - private ServletResponse mResponse; - private HttpServletResponse mHttpResponse; + private final ServletResponseWrapper mResponse; - HttpServletResponseHandler(ServletResponseWrapper pResponse) { + HttpServletResponseHandler(final ServletResponseWrapper pResponse) { mResponse = pResponse; - mHttpResponse = (HttpServletResponse) pResponse.getResponse(); } - public Object invoke(Object pProxy, Method pMethod, Object[] pArgs) throws Throwable { + public Object invoke(final Object pProxy, final Method pMethod, final Object[] pArgs) throws Throwable { try { + // TODO: Allow partial implementing? if (pMethod.getDeclaringClass().isInstance(mResponse)) { - //System.out.println("Invoking " + pMethod + " on wrapper"); return pMethod.invoke(mResponse, pArgs); } + // Method is not implemented in wrapper - //System.out.println("Invoking " + pMethod + " on wrapped object"); - return pMethod.invoke(mHttpResponse, pArgs); + return pMethod.invoke(mResponse.getResponse(), pArgs); } catch (InvocationTargetException e) { // Unwrap, to avoid UndeclaredThrowableException... @@ -1032,23 +730,21 @@ public final class ServletUtil { } private static class HttpServletRequestHandler implements InvocationHandler { - private ServletRequest mRequest; - private HttpServletRequest mHttpRequest; + private final ServletRequestWrapper mRequest; - HttpServletRequestHandler(ServletRequestWrapper pRequest) { + HttpServletRequestHandler(final ServletRequestWrapper pRequest) { mRequest = pRequest; - mHttpRequest = (HttpServletRequest) pRequest.getRequest(); } - public Object invoke(Object pProxy, Method pMethod, Object[] pArgs) throws Throwable { + public Object invoke(final Object pProxy, final Method pMethod, final Object[] pArgs) throws Throwable { try { + // TODO: Allow partial implementing? if (pMethod.getDeclaringClass().isInstance(mRequest)) { - //System.out.println("Invoking " + pMethod + " on wrapper"); return pMethod.invoke(mRequest, pArgs); } + // Method is not implemented in wrapper - //System.out.println("Invoking " + pMethod + " on wrapped object"); - return pMethod.invoke(mHttpRequest, pArgs); + return pMethod.invoke(mRequest.getRequest(), pArgs); } catch (InvocationTargetException e) { // Unwrap, to avoid UndeclaredThrowableException... diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageFilter.java index 04978301..c551e8c4 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageFilter.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageFilter.java @@ -33,6 +33,7 @@ import com.twelvemonkeys.lang.StringUtil; import com.twelvemonkeys.servlet.GenericFilter; import javax.servlet.*; +import javax.servlet.http.HttpServletResponse; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.io.IOException; @@ -67,7 +68,7 @@ public abstract class ImageFilter extends GenericFilter { * @throws IOException * @throws ServletException */ - protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) + protected void doFilterImpl(final ServletRequest pRequest, final ServletResponse pResponse, final FilterChain pChain) throws IOException, ServletException { //System.out.println("Starting filtering..."); @@ -78,19 +79,12 @@ public abstract class ImageFilter extends GenericFilter { pChain.doFilter(pRequest, pResponse); } else { + // If already wrapped, the image will be encoded later in the chain + // Or, if this is first filter in chain, we must encode when done + boolean encode = !(pResponse instanceof ImageServletResponse); + // For images, we do post filtering only and need to wrap the response - ImageServletResponse imageResponse; - boolean encode; - if (pResponse instanceof ImageServletResponse) { - //System.out.println("Allready ImageServletResponse"); - imageResponse = (ImageServletResponse) pResponse; - encode = false; // Allready wrapped, will be encoded later in the chain - } - else { - //System.out.println("Wrapping in ImageServletResponse"); - imageResponse = new ImageServletResponseImpl(pRequest, pResponse, getServletContext()); - encode = true; // This is first filter in chain, must encode when done - } + ImageServletResponse imageResponse = createImageServletResponse(pRequest, pResponse); //System.out.println("Passing request on to next in chain..."); // Pass the request on @@ -120,7 +114,7 @@ public abstract class ImageFilter extends GenericFilter { if (encode) { //System.out.println("Encoding image..."); - // Encode image to original repsonse + // Encode image to original response if (image != null) { // TODO: Be smarter than this... // TODO: Make sure ETag is same, if image content is the same... @@ -128,8 +122,9 @@ public abstract class ImageFilter extends GenericFilter { // Use last modified of original response? Or keep original resource's, don't set at all? // TODO: Why weak ETag? String etag = "W/\"" + Integer.toHexString(hashCode()) + "-" + Integer.toHexString(image.hashCode()) + "\""; - ((ImageServletResponseImpl) imageResponse).setHeader("ETag", etag); - ((ImageServletResponseImpl) imageResponse).setDateHeader("Last-Modified", (System.currentTimeMillis() / 1000) * 1000); + // TODO: This breaks for wrapped instances, need to either unwrap or test for HttpSR... + ((HttpServletResponse) pResponse).setHeader("ETag", etag); + ((HttpServletResponse) pResponse).setDateHeader("Last-Modified", (System.currentTimeMillis() / 1000) * 1000); imageResponse.flush(); } //System.out.println("Done encoding."); @@ -139,6 +134,25 @@ public abstract class ImageFilter extends GenericFilter { //System.out.println("Filtering done."); } + /** + * Creates the image servlet response for this response. + * + * @param pResponse the original response + * @param pRequest the original request + * @return the new response, or {@code pResponse} if the response is already wrapped + * + * @see com.twelvemonkeys.servlet.image.ImageServletResponseWrapper + */ + private ImageServletResponse createImageServletResponse(final ServletRequest pRequest, final ServletResponse pResponse) { + if (pResponse instanceof ImageServletResponseImpl) { + ImageServletResponseImpl response = (ImageServletResponseImpl) pResponse; +// response.setRequest(pRequest); + return response; + } + + return new ImageServletResponseImpl(pRequest, pResponse, getServletContext()); + } + /** * Tests if the filter should do image filtering/processing. *

@@ -157,7 +171,7 @@ public abstract class ImageFilter extends GenericFilter { * @param pRequest the servlet request * @return {@code true} if the filter should do image filtering */ - protected boolean trigger(ServletRequest pRequest) { + protected boolean trigger(final ServletRequest pRequest) { // If triggerParams not set, assume always trigger if (mTriggerParams == null) { return true; diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java index 3a023428..5b3cb2fa 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java @@ -70,9 +70,10 @@ import java.util.Iterator; */ // TODO: Refactor out HTTP specifcs (if possible). // 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 class ImageServletResponseImpl extends HttpServletResponseWrapper implements ImageServletResponse { - private final ServletRequest mOriginalRequest; + private ServletRequest mOriginalRequest; private final ServletContext mContext; private final ServletResponseStreamDelegate mStreamDelegate; @@ -125,6 +126,10 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima this((HttpServletRequest) pRequest, (HttpServletResponse) pResponse, pContext); } + public void setRequest(ServletRequest pRequest) { + mOriginalRequest = pRequest; + } + /** * Called by the container, do not invoke. * @@ -187,13 +192,6 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima getImage(); } - // For known formats that don't support transparency, convert to opaque - if (("image/jpeg".equals(outputType) || "image/jpg".equals(outputType) - || "image/bmp".equals(outputType) || "image/x-bmp".equals(outputType)) && - mImage.getColorModel().getTransparency() != Transparency.OPAQUE) { - mImage = ImageUtil.toBuffered(mImage, BufferedImage.TYPE_INT_RGB); - } - if (mImage != null) { Iterator writers = ImageIO.getImageWritersByMIMEType(outputType); if (writers.hasNext()) { @@ -203,6 +201,12 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima ImageWriter writer = (ImageWriter) writers.next(); try { ImageWriteParam param = writer.getDefaultWriteParam(); +/////////////////// +// 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); @@ -211,7 +215,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); param.setCompressionQuality(requestQuality != null ? requestQuality : 0.8f); } - +////////////////// ImageOutputStream stream = ImageIO.createImageOutputStream(out); writer.setOutput(stream); @@ -244,6 +248,11 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima } } + private boolean isNonAlphaFormat(String outputType) { + return "image/jpeg".equals(outputType) || "image/jpg".equals(outputType) || + "image/bmp".equals(outputType) || "image/x-bmp".equals(outputType); + } + private String getFormatNameSafe(final ImageWriter pWriter) { try { return pWriter.getOriginatingProvider().getFormatNames()[0]; @@ -255,7 +264,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima } public String getOutputContentType() { - return mOutputContentType != null ? mOutputContentType : mOriginalContentType; + return mOutputContentType != null ? mOutputContentType : mOriginalContentType; } public void setOutputContentType(final String pImageFormat) { @@ -304,18 +313,21 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima // Get default size int originalWidth = reader.getWidth(0); int originalHeight = reader.getHeight(0); - +////////////////// +// PRE-PROCESS (prepare): param, size, format?, request, response? + // TODO: AOI strategy? // Extract AOI from request - Rectangle aoi = extractAOIFromRequest(originalWidth, originalHeight); + Rectangle aoi = extractAOIFromRequest(originalWidth, originalHeight, mOriginalRequest); if (aoi != null) { param.setSourceRegion(aoi); originalWidth = aoi.width; originalHeight = aoi.height; } + // TODO: Size and subsampling strategy? // If possible, extract size from request - Dimension size = extractSizeFromRequest(originalWidth, originalHeight); - double readSubSamplingFactor = getReadSubsampleFactorFromRequest(); + Dimension size = extractSizeFromRequest(originalWidth, originalHeight, mOriginalRequest); + double readSubSamplingFactor = getReadSubsampleFactorFromRequest(mOriginalRequest); if (size != null) { //System.out.println("Size: " + size); if (param.canSetSourceRenderSize()) { @@ -334,26 +346,16 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima // Need base URI for SVG with links/stylesheets etc maybeSetBaseURIFromRequest(param); +///////////////////// + // Finally, read the image using the supplied parameter BufferedImage image = reader.read(0, param); // If reader doesn't support dynamic sizing, scale now - if (image != null && size != null - && (image.getWidth() != size.width || image.getHeight() != size.height)) { - - int resampleAlgorithm = getResampleAlgorithmFromRequest(); - // NOTE: Only use createScaled if IndexColorModel, - // as it's more expensive due to color conversion - if (image.getColorModel() instanceof IndexColorModel) { - image = ImageUtil.createScaled(image, size.width, size.height, resampleAlgorithm); - } - else { - image = ImageUtil.createResampled(image, size.width, size.height, resampleAlgorithm); - } - } + image = resampleImage(image, size); // Fill bgcolor behind image, if transparent - extractAndSetBackgroundColor(image); + extractAndSetBackgroundColor(image); // TODO: Move to flush/POST-PROCESS // Set image mImage = image; @@ -383,27 +385,38 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima return mImage != null ? ImageUtil.toBuffered(mImage) : null; } - private int getResampleAlgorithmFromRequest() { - int resampleAlgoithm; + private BufferedImage resampleImage(final BufferedImage image, final Dimension size) { + if (image != null && size != null && (image.getWidth() != size.width || image.getHeight() != size.height)) { + int resampleAlgorithm = getResampleAlgorithmFromRequest(); + // NOTE: Only use createScaled if IndexColorModel, as it's more expensive due to color conversion + if (image.getColorModel() instanceof IndexColorModel) { + return ImageUtil.createScaled(image, size.width, size.height, resampleAlgorithm); + } + else { + return ImageUtil.createResampled(image, size.width, size.height, resampleAlgorithm); + } + } + return image; + } + + private int getResampleAlgorithmFromRequest() { Object algorithm = mOriginalRequest.getAttribute(ATTRIB_IMAGE_RESAMPLE_ALGORITHM); if (algorithm instanceof Integer && ((Integer) algorithm == Image.SCALE_SMOOTH || (Integer) algorithm == Image.SCALE_FAST || (Integer) algorithm == Image.SCALE_DEFAULT)) { - resampleAlgoithm = (Integer) algorithm; + return (Integer) algorithm; } else { if (algorithm != null) { mContext.log("WARN: Illegal image resampling algorithm: " + algorithm); } - resampleAlgoithm = BufferedImage.SCALE_DEFAULT; + return BufferedImage.SCALE_DEFAULT; } - - return resampleAlgoithm; } - private double getReadSubsampleFactorFromRequest() { + private double getReadSubsampleFactorFromRequest(final ServletRequest pOriginalRequest) { double subsampleFactor; - Object factor = mOriginalRequest.getAttribute(ATTRIB_READ_SUBSAMPLING_FACTOR); + Object factor = pOriginalRequest.getAttribute(ATTRIB_READ_SUBSAMPLING_FACTOR); if (factor instanceof Number && ((Number) factor).doubleValue() >= 1.0) { subsampleFactor = ((Number) factor).doubleValue(); } @@ -411,6 +424,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima if (factor != null) { mContext.log("WARN: Illegal read subsampling factor: " + factor); } + subsampleFactor = 2.0; } @@ -483,7 +497,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima } } - private Dimension extractSizeFromRequest(final int pDefaultWidth, final int pDefaultHeight) { + private Dimension extractSizeFromRequest(final int pDefaultWidth, final int pDefaultHeight, final ServletRequest pOriginalRequest) { // TODO: Allow extraction from request parameters /* int sizeW = ServletUtil.getIntParameter(mOriginalRequest, "size.w", -1); @@ -491,14 +505,14 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima boolean sizePercent = ServletUtil.getBooleanParameter(mOriginalRequest, "size.percent", false); boolean sizeUniform = ServletUtil.getBooleanParameter(mOriginalRequest, "size.uniform", true); */ - Dimension size = (Dimension) mOriginalRequest.getAttribute(ATTRIB_SIZE); + Dimension size = (Dimension) pOriginalRequest.getAttribute(ATTRIB_SIZE); int sizeW = size != null ? size.width : -1; int sizeH = size != null ? size.height : -1; - Boolean b = (Boolean) mOriginalRequest.getAttribute(ATTRIB_SIZE_PERCENT); + Boolean b = (Boolean) pOriginalRequest.getAttribute(ATTRIB_SIZE_PERCENT); boolean sizePercent = b != null && b; // default: false - b = (Boolean) mOriginalRequest.getAttribute(ATTRIB_SIZE_UNIFORM); + b = (Boolean) pOriginalRequest.getAttribute(ATTRIB_SIZE_UNIFORM); boolean sizeUniform = b == null || b; // default: true if (sizeW >= 0 || sizeH >= 0) { @@ -508,7 +522,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima return size; } - private Rectangle extractAOIFromRequest(final int pDefaultWidth, final int pDefaultHeight) { + private Rectangle extractAOIFromRequest(final int pDefaultWidth, final int pDefaultHeight, final ServletRequest pOriginalRequest) { // TODO: Allow extraction from request parameters /* int aoiX = ServletUtil.getIntParameter(mOriginalRequest, "aoi.x", -1); @@ -518,16 +532,16 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima boolean aoiPercent = ServletUtil.getBooleanParameter(mOriginalRequest, "aoi.percent", false); boolean aoiUniform = ServletUtil.getBooleanParameter(mOriginalRequest, "aoi.uniform", false); */ - Rectangle aoi = (Rectangle) mOriginalRequest.getAttribute(ATTRIB_AOI); + Rectangle aoi = (Rectangle) pOriginalRequest.getAttribute(ATTRIB_AOI); int aoiX = aoi != null ? aoi.x : -1; int aoiY = aoi != null ? aoi.y : -1; int aoiW = aoi != null ? aoi.width : -1; int aoiH = aoi != null ? aoi.height : -1; - Boolean b = (Boolean) mOriginalRequest.getAttribute(ATTRIB_AOI_PERCENT); + Boolean b = (Boolean) pOriginalRequest.getAttribute(ATTRIB_AOI_PERCENT); boolean aoiPercent = b != null && b; // default: false - b = (Boolean) mOriginalRequest.getAttribute(ATTRIB_AOI_UNIFORM); + b = (Boolean) pOriginalRequest.getAttribute(ATTRIB_AOI_UNIFORM); boolean aoiUniform = b != null && b; // default: false if (aoiX >= 0 || aoiY >= 0 || aoiW >= 0 || aoiH >= 0) { @@ -552,18 +566,18 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima * @param pHeight the new height of the image, or -1 if unknown * @param pPercent the constant specifying units for width and height * parameter (UNITS_PIXELS or UNITS_PERCENT) - * @param pUniformScale boolean specifying uniform scale or not + * @param pUniform boolean specifying uniform scale or not * @return a Dimension object, with the correct width and heigth * in pixels, for the scaled version of the image. */ - protected static Dimension getSize(int pOriginalWidth, int pOriginalHeight, + static Dimension getSize(int pOriginalWidth, int pOriginalHeight, int pWidth, int pHeight, - boolean pPercent, boolean pUniformScale) { + boolean pPercent, boolean pUniform) { - // If uniform, make sure width and height are scaled the same ammount + // If uniform, make sure width and height are scaled the same amount // (use ONLY height or ONLY width). // - // Algoritm: + // Algorithm: // if uniform // if newHeight not set // find ratio newWidth / oldWidth @@ -602,7 +616,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima // Else: No scale } else { - if (pUniformScale) { + if (pUniform) { if (pWidth >= 0 && pHeight >= 0) { // Compute both ratios ratio = (float) pWidth / (float) pOriginalWidth; @@ -616,7 +630,6 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima else { pHeight = Math.round((float) pOriginalHeight * ratio); } - } else if (pWidth >= 0) { // Find ratio from pWidth @@ -644,10 +657,10 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima return new Dimension(pWidth, pHeight); } - protected static Rectangle getAOI(int pOriginalWidth, int pOriginalHeight, + static Rectangle getAOI(int pOriginalWidth, int pOriginalHeight, int pX, int pY, int pWidth, int pHeight, - boolean pPercent, boolean pUniform) { - // Algoritm: + boolean pPercent, boolean pMaximizeToAspect) { + // Algorithm: // Try to get x and y (default 0,0). // Try to get width and height (default width-x, height-y) // @@ -669,7 +682,6 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima ratio = (float) pWidth / 100f; pWidth = Math.round((float) pOriginalWidth * ratio); pHeight = Math.round((float) pOriginalHeight * ratio); - } else if (pHeight >= 0) { // Find ratio from pHeight @@ -681,7 +693,7 @@ class ImageServletResponseImpl extends HttpServletResponseWrapper implements Ima } else { // Uniform - if (pUniform) { + if (pMaximizeToAspect) { if (pWidth >= 0 && pHeight >= 0) { // Compute both ratios ratio = (float) pWidth / (float) pHeight; diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/log4j/Log4JContextWrapper.java b/servlet/src/main/java/com/twelvemonkeys/servlet/log4j/Log4JContextWrapper.java index a629c438..01e946ed 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/log4j/Log4JContextWrapper.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/log4j/Log4JContextWrapper.java @@ -2,19 +2,18 @@ package com.twelvemonkeys.servlet.log4j; import org.apache.log4j.Logger; -import java.util.Enumeration; -import java.util.Set; -import java.net.URL; -import java.net.MalformedURLException; -import java.io.InputStream; -import java.lang.reflect.Proxy; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; - -import javax.servlet.ServletContext; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; +import javax.servlet.ServletContext; import javax.servlet.ServletException; +import java.io.InputStream; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Set; /** * Log4JContextWrapper @@ -24,6 +23,7 @@ import javax.servlet.ServletException; * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/main/java/com/twelvemonkeys/servlet/log4j/Log4JContextWrapper.java#1 $ */ final class Log4JContextWrapper implements ServletContext { + // TODO: Move to sandbox // TODO: This solution sucks... // How about starting to create some kind of pluggable decorator system, @@ -32,7 +32,7 @@ final class Log4JContextWrapper implements ServletContext { // wrapped object based on configuration. // This way we could simply call ServletUtil.decorate(ServletContext):ServletContext // And the context would be decorated with all configured mixins at once, - // requiring less bolierplate delegation code, and less layers of wrapping + // requiring less boilerplate delegation code, and less layers of wrapping // (alternatively we could decorate the Servlet/FilterConfig objects). // See the ServletUtil.createWrapper methods for some hints.. diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTestCase.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTestCase.java index cd078d9c..b27e6dc6 100755 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTestCase.java +++ b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTestCase.java @@ -47,7 +47,7 @@ public class ServletHeadersMapAdapterTestCase extends MapAbstractTestCase { mockRequest.stubs().method("getHeaderNames").will(returnValue(Collections.enumeration(Collections.emptyList()))); mockRequest.stubs().method("getHeaders").will(returnValue(null)); - return new SerlvetHeadersMapAdapter((HttpServletRequest) mockRequest.proxy()); + return new ServletHeadersMapAdapter((HttpServletRequest) mockRequest.proxy()); } @Override @@ -60,7 +60,7 @@ public class ServletHeadersMapAdapterTestCase extends MapAbstractTestCase { mockRequest.stubs().method("getHeaders").with(eq("X-Foo")).will(returnEnumeration(HEADER_VALUE_FOO)); mockRequest.stubs().method("getHeaders").with(not(or(eq("Date"), or(eq("ETag"), eq("X-Foo"))))).will(returnValue(null)); - return new SerlvetHeadersMapAdapter((HttpServletRequest) mockRequest.proxy()); + return new ServletHeadersMapAdapter((HttpServletRequest) mockRequest.proxy()); } @Override diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTestCase.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTestCase.java index af0f606e..c24e84f3 100755 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTestCase.java +++ b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTestCase.java @@ -47,7 +47,7 @@ public class ServletParametersMapAdapterTestCase extends MapAbstractTestCase { mockRequest.stubs().method("getParameterNames").will(returnValue(Collections.enumeration(Collections.emptyList()))); mockRequest.stubs().method("getParameterValues").will(returnValue(null)); - return new SerlvetParametersMapAdapter((HttpServletRequest) mockRequest.proxy()); + return new ServletParametersMapAdapter((HttpServletRequest) mockRequest.proxy()); } @Override @@ -60,7 +60,7 @@ public class ServletParametersMapAdapterTestCase extends MapAbstractTestCase { mockRequest.stubs().method("getParameterValues").with(eq("foo")).will(returnValue(PARAM_VALUE_FOO.toArray(new String[PARAM_VALUE_FOO.size()]))); mockRequest.stubs().method("getParameterValues").with(not(or(eq("date"), or(eq("tag"), eq("foo"))))).will(returnValue(null)); - return new SerlvetParametersMapAdapter((HttpServletRequest) mockRequest.proxy()); + return new ServletParametersMapAdapter((HttpServletRequest) mockRequest.proxy()); } @Override diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTestCase.java b/servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTestCase.java index fd5456c8..ec769165 100755 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTestCase.java +++ b/servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTestCase.java @@ -25,11 +25,11 @@ import java.util.Arrays; * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTestCase.java#6 $ */ public class ImageServletResponseImplTestCase extends MockObjectTestCase { - private static final String CONTENT_TYPE_BMP = "image/bmp"; - private static final String CONTENT_TYPE_FOO = "foo/bar"; - private static final String CONTENT_TYPE_GIF = "image/gif"; + private static final String CONTENT_TYPE_BMP = "image/bmp"; + private static final String CONTENT_TYPE_FOO = "foo/bar"; + private static final String CONTENT_TYPE_GIF = "image/gif"; private static final String CONTENT_TYPE_JPEG = "image/jpeg"; - private static final String CONTENT_TYPE_PNG = "image/png"; + private static final String CONTENT_TYPE_PNG = "image/png"; private static final String CONTENT_TYPE_TEXT = "text/plain"; private static final String IMAGE_NAME_PNG = "12monkeys-splash.png"; @@ -126,6 +126,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { // Test that wrapper works as a no-op, in case the image does not need to be decoded // This is not a very common use case, as filters should avoid wrapping the response // for performance reasons, but we still want that to work + public void testNoOpResponse() throws IOException { Mock mockResponse = mock(HttpServletResponse.class); mockResponse.expects(once()).method("setContentType").with(eq(CONTENT_TYPE_PNG)); @@ -147,6 +148,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { } // Transcode original PNG to JPEG with no other changes + public void testTranscodeResponse() throws IOException { Mock mockResponse = mock(HttpServletResponse.class); mockResponse.expects(once()).method("setContentType").with(eq(CONTENT_TYPE_JPEG)); @@ -268,7 +270,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { * * @param pExpected the expected image * @param pActual the actual image - * @param pArtifactThreshold the maximum allowed difference between the expected and actual pixel value + * @param pArtifactThreshold the maximum allowed difference between the expected and actual pixel value */ private void assertSimilarImage(final BufferedImage pExpected, final BufferedImage pActual, final float pArtifactThreshold) { for (int y = 0; y < pExpected.getHeight(); y++) { @@ -325,6 +327,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { // More? // Make sure we don't change semantics here... + public void testNotFoundInput() throws IOException { // Need speical setup Mock mockRequest = mock(HttpServletRequest.class); @@ -343,6 +346,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { } // NOTE: This means it's up to some Filter to decide wether we should filter the given request + public void testUnsupportedInput() throws IOException { assertFalse("Test is invalid, rewrite test", ImageIO.getImageReadersByFormatName("txt").hasNext()); @@ -409,7 +413,6 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { // For example: Read a PNG with transparency and store as B/W WBMP - // TODO: Create ImageFilter test case, that tests normal use, as well as chaining @Test @@ -997,6 +1000,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { // ----------------------------------------------------------------------------------------------------------------- // Absolute AOI // ----------------------------------------------------------------------------------------------------------------- + public void testGetAOIAbsolute() { assertEquals(new Rectangle(10, 10, 100, 100), ImageServletResponseImpl.getAOI(200, 200, 10, 10, 100, 100, false, false)); } @@ -1020,6 +1024,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { // ----------------------------------------------------------------------------------------------------------------- // Uniform AOI centered // ----------------------------------------------------------------------------------------------------------------- + @Test public void testGetAOIUniformCenteredS2SUp() { assertEquals(new Rectangle(0, 0, 100, 100), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 333, 333, false, true)); @@ -1148,6 +1153,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { // ----------------------------------------------------------------------------------------------------------------- // Absolute AOI centered // ----------------------------------------------------------------------------------------------------------------- + @Test public void testGetAOICenteredS2SUp() { assertEquals(new Rectangle(0, 0, 100, 100), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 333, 333, false, false)); @@ -1303,4 +1309,7 @@ public class ImageServletResponseImplTestCase extends MockObjectTestCase { assertEquals(new Rectangle(0, 0, 100, 200), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 100, 200, false, false)); } + // TODO: Test percent + + // TODO: Test getSize()... }