mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-03-17 00:00:06 -04:00
Delete deprecated Servlet classes
(cherry picked from commit b0ad6b2a4b)
This commit is contained in:
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* AbstractServletMapAdapter
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: AbstractServletMapAdapter.java#1 $
|
||||
*/
|
||||
abstract class AbstractServletMapAdapter<T> extends AbstractMap<String, T> {
|
||||
// TODO: This map is now a little too lazy.. Should cache entries!
|
||||
private transient Set<Entry<String, T>> entries;
|
||||
|
||||
protected abstract Iterator<String> keysImpl();
|
||||
|
||||
protected abstract T valueImpl(String pName);
|
||||
|
||||
@Override
|
||||
public T get(final Object pKey) {
|
||||
if (pKey instanceof String) {
|
||||
return valueImpl((String) pKey);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
// Avoid creating expensive entry set for computing size
|
||||
int size = 0;
|
||||
|
||||
for (Iterator<String> names = keysImpl(); names.hasNext(); names.next()) {
|
||||
size++;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public Set<Entry<String, T>> entrySet() {
|
||||
if (entries == null) {
|
||||
entries = new AbstractSet<Entry<String, T>>() {
|
||||
public Iterator<Entry<String, T>> iterator() {
|
||||
return new Iterator<Entry<String, T>>() {
|
||||
Iterator<String> keys = keysImpl();
|
||||
|
||||
public boolean hasNext() {
|
||||
return keys.hasNext();
|
||||
}
|
||||
|
||||
public Entry<String, T> next() {
|
||||
// TODO: Replace with cached lookup
|
||||
return new HeaderEntry(keys.next());
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
keys.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return AbstractServletMapAdapter.this.size();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private class HeaderEntry implements Entry<String, T> {
|
||||
final String key;
|
||||
|
||||
public HeaderEntry(final String pKey) {
|
||||
key = pKey;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
public T setValue(final T pValue) {
|
||||
// Write-through if supported
|
||||
return put(key, pValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
T value = getValue();
|
||||
return (key == null ? 0 : key.hashCode()) ^
|
||||
(value == null ? 0 : value.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object pOther) {
|
||||
if (pOther == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pOther instanceof Entry) {
|
||||
Entry other = (Entry) pOther;
|
||||
return ((other.getKey() == null && getKey() == null) ||
|
||||
(getKey() != null && getKey().equals(other.getKey()))) &&
|
||||
((other.getValue() == null && getValue() == null) ||
|
||||
(getValue() != null && getValue().equals(other.getValue())));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
/**
|
||||
* BrowserHelperFilter
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: BrowserHelperFilter.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class BrowserHelperFilter extends GenericFilter {
|
||||
private static final String HTTP_HEADER_ACCEPT = "Accept";
|
||||
protected static final String HTTP_HEADER_USER_AGENT = "User-Agent";
|
||||
|
||||
// TODO: Consider using unmodifiable LinkedHashMap<Pattern, String> instead
|
||||
private Pattern[] knownAgentPatterns;
|
||||
private String[] knownAgentAccepts;
|
||||
|
||||
/**
|
||||
* Sets the accept-mappings for this filter
|
||||
* @param pPropertiesFile name of accept-mappings properties files
|
||||
* @throws ServletConfigException if the accept-mappings properties
|
||||
* file cannot be read.
|
||||
*/
|
||||
@InitParam(name = "accept-mappings-file")
|
||||
public void setAcceptMappingsFile(String pPropertiesFile) throws ServletConfigException {
|
||||
// NOTE: Format is:
|
||||
// <agent-name>=<reg-exp>
|
||||
// <agent-name>.accept=<http-accept-header>
|
||||
|
||||
Properties mappings = new Properties();
|
||||
|
||||
try {
|
||||
log("Reading Accept-mappings properties file: " + pPropertiesFile);
|
||||
mappings.load(getServletContext().getResourceAsStream(pPropertiesFile));
|
||||
|
||||
//System.out.println("--> Loaded file: " + pPropertiesFile);
|
||||
}
|
||||
catch (IOException 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 {
|
||||
if (knownAgentAccepts == null || knownAgentAccepts.length == 0) {
|
||||
throw new ServletConfigException("No User-Agent/Accept mappings for filter: " + getFilterName());
|
||||
}
|
||||
}
|
||||
|
||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||
if (pRequest instanceof HttpServletRequest) {
|
||||
//System.out.println("--> Trying to find User-Agent/Accept headers...");
|
||||
HttpServletRequest request = (HttpServletRequest) pRequest;
|
||||
|
||||
// Check if User-Agent is in list of known agents
|
||||
if (knownAgentPatterns != null && knownAgentPatterns.length > 0) {
|
||||
String agent = request.getHeader(HTTP_HEADER_USER_AGENT);
|
||||
//System.out.println("--> User-Agent: " + agent);
|
||||
|
||||
for (int i = 0; i < knownAgentPatterns.length; i++) {
|
||||
Pattern pattern = knownAgentPatterns[i];
|
||||
//System.out.println("--> Pattern: " + pattern);
|
||||
|
||||
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);
|
||||
|
||||
pRequest = new HttpServletRequestWrapper(request) {
|
||||
public String getHeader(String pName) {
|
||||
if (HTTP_HEADER_ACCEPT.equals(pName)) {
|
||||
return fakeAccept;
|
||||
}
|
||||
|
||||
return super.getHeader(pName);
|
||||
}
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pChain.doFilter(pRequest, pResponse);
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* DebugServlet class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: DebugServlet.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class DebugServlet extends GenericServlet {
|
||||
private long dateModified;
|
||||
|
||||
public final void service(ServletRequest pRequest, ServletResponse pResponse) throws ServletException, IOException {
|
||||
service((HttpServletRequest) pRequest, (HttpServletResponse) pResponse);
|
||||
}
|
||||
|
||||
public void init() throws ServletException {
|
||||
super.init();
|
||||
dateModified = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
|
||||
pResponse.setContentType("text/plain");
|
||||
// Include these to allow browser caching
|
||||
pResponse.setDateHeader("Last-Modified", dateModified);
|
||||
pResponse.setHeader("ETag", getServletName());
|
||||
|
||||
ServletOutputStream out = pResponse.getOutputStream();
|
||||
|
||||
out.println("Remote address: " + pRequest.getRemoteAddr());
|
||||
out.println("Remote host name: " + pRequest.getRemoteHost());
|
||||
out.println("Remote user: " + pRequest.getRemoteUser());
|
||||
out.println();
|
||||
|
||||
out.println("Request Method: " + pRequest.getMethod());
|
||||
out.println("Request Scheme: " + pRequest.getScheme());
|
||||
out.println("Request URI: " + pRequest.getRequestURI());
|
||||
out.println("Request URL: " + pRequest.getRequestURL().toString());
|
||||
out.println("Request PathInfo: " + pRequest.getPathInfo());
|
||||
out.println("Request ContentLength: " + pRequest.getContentLength());
|
||||
out.println();
|
||||
|
||||
out.println("Request Headers:");
|
||||
Enumeration headerNames = pRequest.getHeaderNames();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headerName = (String) headerNames.nextElement();
|
||||
Enumeration headerValues = pRequest.getHeaders(headerName);
|
||||
|
||||
if (headerName != null) {
|
||||
while (headerValues.hasMoreElements()) {
|
||||
String value = (String) headerValues.nextElement();
|
||||
out.println(" " + headerName + ": " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
out.println();
|
||||
|
||||
out.println("Request parameters:");
|
||||
Enumeration paramNames = pRequest.getParameterNames();
|
||||
while (paramNames.hasMoreElements()) {
|
||||
String name = (String) paramNames.nextElement();
|
||||
String[] values = pRequest.getParameterValues(name);
|
||||
|
||||
for (String value : values) {
|
||||
out.println(" " + name + ": " + value);
|
||||
}
|
||||
}
|
||||
out.println();
|
||||
|
||||
out.println("Request attributes:");
|
||||
Enumeration attribNames = pRequest.getAttributeNames();
|
||||
while (attribNames.hasMoreElements()) {
|
||||
String name = (String) attribNames.nextElement();
|
||||
Object value = pRequest.getAttribute(name);
|
||||
out.println(" " + name + ": " + value);
|
||||
}
|
||||
|
||||
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
@@ -1,403 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import com.twelvemonkeys.lang.BeanUtil;
|
||||
|
||||
/**
|
||||
* Defines a generic, protocol-independent filter.
|
||||
* <p>
|
||||
* {@code GenericFilter} is inspired by {@link GenericServlet}, and
|
||||
* implements the {@code Filter} and {@code FilterConfig} interfaces.
|
||||
* </p>
|
||||
* <p>
|
||||
* {@code GenericFilter} makes writing filters easier. It provides simple
|
||||
* versions of the lifecycle methods {@code init} and {@code destroy}
|
||||
* and of the methods in the {@code FilterConfig} interface.
|
||||
* {@code GenericFilter} also implements the {@code log} methods,
|
||||
* declared in the {@code ServletContext} interface.
|
||||
* </p>
|
||||
* <p>
|
||||
* {@code GenericFilter} has an auto-init system, that automatically invokes
|
||||
* the method matching the signature {@code void setX(<Type>)},
|
||||
* for every init-parameter {@code x}. Both camelCase and lisp-style parameter
|
||||
* naming is supported, lisp-style names will be converted to camelCase.
|
||||
* Parameter values are automatically converted from string representation to
|
||||
* most basic types, if necessary.
|
||||
* </p>
|
||||
* <p>
|
||||
* To write a generic filter, you need only override the abstract
|
||||
* {@link #doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)} doFilterImpl} method.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Id: GenericFilter.java#1 $
|
||||
*
|
||||
* @see Filter
|
||||
* @see FilterConfig
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class GenericFilter implements Filter, FilterConfig, Serializable {
|
||||
// TODO: Rewrite to use ServletConfigurator instead of BeanUtil
|
||||
|
||||
/**
|
||||
* The filter config.
|
||||
*/
|
||||
private transient FilterConfig filterConfig = null;
|
||||
|
||||
/**
|
||||
* Makes sure the filter runs once per request
|
||||
*
|
||||
* @see #isRunOnce
|
||||
* @see #ATTRIB_RUN_ONCE_VALUE
|
||||
* @see #oncePerRequest
|
||||
*/
|
||||
private final static String ATTRIB_RUN_ONCE_EXT = ".REQUEST_HANDLED";
|
||||
|
||||
/**
|
||||
* Makes sure the filter runs once per request.
|
||||
* Must be configured through init method, as the filter name is not
|
||||
* available before we have a {@code FilterConfig} object.
|
||||
*
|
||||
* @see #isRunOnce
|
||||
* @see #ATTRIB_RUN_ONCE_VALUE
|
||||
* @see #oncePerRequest
|
||||
*/
|
||||
private String attribRunOnce = null;
|
||||
|
||||
/**
|
||||
* Makes sure the filter runs once per request
|
||||
*
|
||||
* @see #isRunOnce
|
||||
* @see #ATTRIB_RUN_ONCE_EXT
|
||||
* @see #oncePerRequest
|
||||
*/
|
||||
private static final Object ATTRIB_RUN_ONCE_VALUE = new Object();
|
||||
|
||||
/**
|
||||
* Indicates if this filter should run once per request ({@code true}),
|
||||
* or for each forward/include resource ({@code false}).
|
||||
* <p>
|
||||
* Set this variable to true, to make sure the filter runs once per request.
|
||||
* </p>
|
||||
* <p>
|
||||
* <em>NOTE: As of Servlet 2.4, this field
|
||||
* should always be left to it's default value ({@code false}).
|
||||
* <br>
|
||||
* To run the filter once per request, the {@code filter-mapping} element
|
||||
* of the web-descriptor should include a {@code dispatcher} element:
|
||||
* </em>
|
||||
* </p>
|
||||
* <pre><dispatcher>REQUEST</dispatcher></pre>
|
||||
*/
|
||||
protected boolean oncePerRequest = false;
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public GenericFilter() {}
|
||||
|
||||
/**
|
||||
* Called by the web container to indicate to a filter that it is being
|
||||
* placed into service.
|
||||
* <p>
|
||||
* This implementation stores the {@code FilterConfig} object it
|
||||
* receives from the servlet container for later use.
|
||||
* Generally, there's no reason to override this method, override the
|
||||
* no-argument {@code init} instead. However, <em>if</em> you are
|
||||
* overriding this form of the method,
|
||||
* always call {@code super.init(config)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This implementation will also set all configured key/value pairs, that
|
||||
* have a matching setter method annotated with {@link InitParam}.
|
||||
* </p>
|
||||
*
|
||||
* @param pConfig the filter config
|
||||
* @throws ServletException if an error occurs during init
|
||||
*
|
||||
* @see Filter#init(javax.servlet.FilterConfig)
|
||||
* @see #init() init
|
||||
* @see BeanUtil#configure(Object, java.util.Map, boolean)
|
||||
*/
|
||||
public void init(final FilterConfig pConfig) throws ServletException {
|
||||
if (pConfig == null) {
|
||||
throw new ServletConfigException("filter config == null");
|
||||
}
|
||||
|
||||
// Store filter config
|
||||
filterConfig = pConfig;
|
||||
|
||||
// Configure this
|
||||
try {
|
||||
BeanUtil.configure(this, ServletUtil.asMap(pConfig), true);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
throw new ServletConfigException("Could not configure " + getFilterName(), e.getCause());
|
||||
}
|
||||
|
||||
// Create run-once attribute name
|
||||
attribRunOnce = pConfig.getFilterName() + ATTRIB_RUN_ONCE_EXT;
|
||||
log("init (oncePerRequest=" + oncePerRequest + ", attribRunOnce=" + attribRunOnce + ")");
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method which can be overridden so that there's no need to
|
||||
* call {@code super.init(config)}.
|
||||
*
|
||||
* @see #init(FilterConfig)
|
||||
*
|
||||
* @throws ServletException if an error occurs during init
|
||||
*/
|
||||
public void init() throws ServletException {}
|
||||
|
||||
/**
|
||||
* The {@code doFilter} method of the Filter is called by the container
|
||||
* each time a request/response pair is passed through the chain due to a
|
||||
* client request for a resource at the end of the chain.
|
||||
* <p>
|
||||
* Subclasses <em>should not override this method</em>, but rather the
|
||||
* abstract {@link #doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)} doFilterImpl} method.
|
||||
* </p>
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @param pResponse the servlet response
|
||||
* @param pFilterChain the filter chain
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*
|
||||
* @see Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) Filter.doFilter
|
||||
* @see #doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) doFilterImpl
|
||||
*/
|
||||
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 (oncePerRequest && isRunOnce(pRequest)) {
|
||||
pFilterChain.doFilter(pRequest, pResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
// Do real filter
|
||||
doFilterImpl(pRequest, pResponse, pFilterChain);
|
||||
}
|
||||
|
||||
/**
|
||||
* If request is filtered, returns true, otherwise marks request as filtered
|
||||
* and returns false.
|
||||
* A return value of false, indicates that the filter has not yet run.
|
||||
* A return value of true, indicates that the filter has run for this
|
||||
* request, and processing should not continue.
|
||||
* <p>
|
||||
* Note that the method will mark the request as filtered on first
|
||||
* invocation.
|
||||
* </p>
|
||||
*
|
||||
* @see #ATTRIB_RUN_ONCE_EXT
|
||||
* @see #ATTRIB_RUN_ONCE_VALUE
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @return {@code true} if the request is already filtered, otherwise
|
||||
* {@code false}.
|
||||
*/
|
||||
private boolean isRunOnce(final ServletRequest pRequest) {
|
||||
// If request already filtered, return true (skip)
|
||||
if (pRequest.getAttribute(attribRunOnce) == ATTRIB_RUN_ONCE_VALUE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set attribute and return false (continue)
|
||||
pRequest.setAttribute(attribRunOnce, ATTRIB_RUN_ONCE_VALUE);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked once, or each time a request/response pair is passed through the
|
||||
* chain, depending on the {@link #oncePerRequest} member variable.
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @param pResponse the servlet response
|
||||
* @param pChain the filter chain
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ServletException if an exception occurs during the filter process
|
||||
*
|
||||
* @see #oncePerRequest
|
||||
* @see #doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) doFilter
|
||||
* @see Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) Filter.doFilter
|
||||
*/
|
||||
protected abstract void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain)
|
||||
throws IOException, ServletException;
|
||||
|
||||
/**
|
||||
* Called by the web container to indicate to a filter that it is being
|
||||
* taken out of service.
|
||||
*
|
||||
* @see Filter#destroy
|
||||
*/
|
||||
public void destroy() {
|
||||
log("destroy");
|
||||
filterConfig = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filter-name of this filter as defined in the deployment
|
||||
* descriptor.
|
||||
*
|
||||
* @return the filter-name
|
||||
* @see FilterConfig#getFilterName
|
||||
*/
|
||||
public String getFilterName() {
|
||||
return filterConfig.getFilterName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the {@link ServletContext} in which the caller is
|
||||
* executing.
|
||||
*
|
||||
* @return the {@code ServletContext} object, used by the caller to
|
||||
* interact with its servlet container
|
||||
* @see FilterConfig#getServletContext
|
||||
* @see ServletContext
|
||||
*/
|
||||
public ServletContext getServletContext() {
|
||||
return filterConfig.getServletContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code String} containing the value of the named
|
||||
* initialization parameter, or null if the parameter does not exist.
|
||||
*
|
||||
* @param pKey a {@code String} specifying the name of the
|
||||
* initialization parameter
|
||||
* @return a {@code String} containing the value of the initialization
|
||||
* parameter
|
||||
*/
|
||||
public String getInitParameter(final String pKey) {
|
||||
return filterConfig.getInitParameter(pKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of the servlet's initialization parameters as an
|
||||
* {@code Enumeration} of {@code String} objects, or an empty
|
||||
* {@code Enumeration} if the servlet has no initialization parameters.
|
||||
*
|
||||
* @return an {@code Enumeration} of {@code String} objects
|
||||
* containing the mNames of the servlet's initialization parameters
|
||||
*/
|
||||
public Enumeration getInitParameterNames() {
|
||||
return filterConfig.getInitParameterNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the specified message to a servlet log file, prepended by the
|
||||
* filter's name.
|
||||
*
|
||||
* @param pMessage the log message
|
||||
* @see ServletContext#log(String)
|
||||
*/
|
||||
protected void log(final String pMessage) {
|
||||
getServletContext().log(getFilterName() + ": " + pMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an explanatory message and a stack trace for a given
|
||||
* {@code Throwable} to the servlet log file, prepended by the
|
||||
* filter's name.
|
||||
*
|
||||
* @param pMessage the log message
|
||||
* @param pThrowable the exception
|
||||
* @see ServletContext#log(String,Throwable)
|
||||
*/
|
||||
protected void log(final String pMessage, final Throwable pThrowable) {
|
||||
getServletContext().log(getFilterName() + ": " + pMessage, pThrowable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the filter.
|
||||
*
|
||||
* @param pFilterConfig the filter config
|
||||
* @see #init init
|
||||
*
|
||||
* @deprecated For compatibility only, use {@link #init init} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public void setFilterConfig(final FilterConfig pFilterConfig) {
|
||||
try {
|
||||
init(pFilterConfig);
|
||||
}
|
||||
catch (ServletException e) {
|
||||
log("Error in init(), see stack trace for details.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@code FilterConfig} for this filter.
|
||||
*
|
||||
* @return the {@code FilterConfig} for this filter
|
||||
* @see FilterConfig
|
||||
*/
|
||||
public FilterConfig getFilterConfig() {
|
||||
return filterConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if this filter should run once per request ({@code true}),
|
||||
* or for each forward/include resource ({@code false}).
|
||||
* Called automatically from the {@code init}-method, with settings
|
||||
* from web.xml.
|
||||
*
|
||||
* @param pOncePerRequest {@code true} if the filter should run only
|
||||
* once per request
|
||||
* @see #oncePerRequest
|
||||
*/
|
||||
@InitParam(name = "once-per-request")
|
||||
public void setOncePerRequest(final boolean pOncePerRequest) {
|
||||
oncePerRequest = pOncePerRequest;
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import com.twelvemonkeys.lang.BeanUtil;
|
||||
|
||||
/**
|
||||
* Defines a generic, protocol-independent servlet.
|
||||
* <p>
|
||||
* {@code GenericServlet} has an auto-init system, that automatically invokes
|
||||
* the method matching the signature {@code void setX(<Type>)},
|
||||
* for every init-parameter {@code x}. Both camelCase and lisp-style parameter
|
||||
* naming is supported, lisp-style names will be converted to camelCase.
|
||||
* Parameter values are automatically converted from string representation to
|
||||
* most basic types, if necessary.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Id: GenericServlet.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class GenericServlet extends javax.servlet.GenericServlet {
|
||||
// TODO: Rewrite to use ServletConfigurator instead of BeanUtil
|
||||
|
||||
/**
|
||||
* Called by the web container to indicate to a servlet that it is being
|
||||
* placed into service.
|
||||
* <p>
|
||||
* This implementation stores the {@code ServletConfig} object it
|
||||
* receives from the servlet container for later use. When overriding this
|
||||
* form of the method, call {@code super.init(config)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This implementation will also set all configured key/value pairs, that
|
||||
* have a matching setter method annotated with {@link InitParam}.
|
||||
* </p>
|
||||
*
|
||||
* @param pConfig the servlet config
|
||||
* @throws ServletException if the servlet could not be initialized.
|
||||
*
|
||||
* @see javax.servlet.GenericServlet#init
|
||||
* @see #init() init
|
||||
* @see BeanUtil#configure(Object, java.util.Map, boolean)
|
||||
*/
|
||||
@Override
|
||||
public void init(final ServletConfig pConfig) throws ServletException {
|
||||
if (pConfig == null) {
|
||||
throw new ServletConfigException("servlet config == null");
|
||||
}
|
||||
|
||||
try {
|
||||
BeanUtil.configure(this, ServletUtil.asMap(pConfig), true);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
throw new ServletConfigException("Could not configure " + getServletName(), e.getCause());
|
||||
}
|
||||
|
||||
super.init(pConfig);
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import com.twelvemonkeys.lang.BeanUtil;
|
||||
|
||||
/**
|
||||
* Defines a generic, HTTP specific servlet.
|
||||
* <p>
|
||||
* {@code HttpServlet} has an auto-init system, that automatically invokes
|
||||
* the method matching the signature {@code void setX(<Type>)},
|
||||
* for every init-parameter {@code x}. Both camelCase and lisp-style parameter
|
||||
* naming is supported, lisp-style names will be converted to camelCase.
|
||||
* Parameter values are automatically converted from string representation to
|
||||
* most basic types, if necessary.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Id: HttpServlet.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class HttpServlet extends javax.servlet.http.HttpServlet {
|
||||
// TODO: Rewrite to use ServletConfigurator instead of BeanUtil
|
||||
|
||||
/**
|
||||
* Called by the web container to indicate to a servlet that it is being
|
||||
* placed into service.
|
||||
* <p>
|
||||
* This implementation stores the {@code ServletConfig} object it
|
||||
* receives from the servlet container for later use. When overriding this
|
||||
* form of the method, call {@code super.init(config)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This implementation will also set all configured key/value pairs, that
|
||||
* have a matching setter method annotated with {@link InitParam}.
|
||||
* </p>
|
||||
*
|
||||
* @param pConfig the servlet config
|
||||
* @throws ServletException if an error occurred during init
|
||||
*
|
||||
* @see javax.servlet.GenericServlet#init
|
||||
* @see #init() init
|
||||
* @see BeanUtil#configure(Object, java.util.Map, boolean)
|
||||
*/
|
||||
@Override
|
||||
public void init(ServletConfig pConfig) throws ServletException {
|
||||
if (pConfig == null) {
|
||||
throw new ServletConfigException("servlet config == null");
|
||||
}
|
||||
|
||||
try {
|
||||
BeanUtil.configure(this, ServletUtil.asMap(pConfig), true);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
throw new ServletConfigException("Could not configure " + getServletName(), e.getCause());
|
||||
}
|
||||
|
||||
super.init(pConfig);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to be used by servlets/filters, to have their {@code init}-method
|
||||
* automatically convert and set values from their respective configuration.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: InitParam.java#1 $
|
||||
* @see com.twelvemonkeys.servlet.ServletConfigurator
|
||||
* @see com.twelvemonkeys.servlet.GenericFilter#init(javax.servlet.FilterConfig)
|
||||
* @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/*, TODO: ElementType.FIELD*/})
|
||||
@Deprecated
|
||||
public @interface InitParam {
|
||||
static final String UNDEFINED = "";
|
||||
String name() default UNDEFINED;
|
||||
String defaultValue() default UNDEFINED; // TODO: Consider separate annotation?
|
||||
boolean required() default false; // TODO: Consider separate annotation?
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
/**
|
||||
* A {@code ServletOutputStream} implementation backed by a
|
||||
* {@link java.io.OutputStream}. For filters that need to buffer the
|
||||
* response and do post filtering, it may be used like this:<pre>
|
||||
* ByteArrayOutputStream buffer = new ByteArraOutputStream();
|
||||
* ServletOutputStream adapter = new OutputStreamAdapter(buffer);
|
||||
* </pre>
|
||||
* <p>
|
||||
* As a {@code ServletOutputStream} is itself an {@code OutputStream}, this
|
||||
* class may also be used as a superclass for wrappers of other
|
||||
* {@code ServletOutputStream}s, like this:
|
||||
* </p>
|
||||
* <pre>
|
||||
* class FilterServletOutputStream extends OutputStreamAdapter {
|
||||
* public FilterServletOutputStream(ServletOutputStream out) {
|
||||
* super(out);
|
||||
* }
|
||||
*
|
||||
* public void write(int abyte) {
|
||||
* // do filtering...
|
||||
* super.write(...);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* ServletOutputStream original = response.getOutputStream();
|
||||
* ServletOutputStream wrapper = new FilterServletOutputStream(original);
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author $Author: haku $
|
||||
* @version $Id: OutputStreamAdapter.java#1 $
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public class OutputStreamAdapter extends ServletOutputStream {
|
||||
|
||||
/** The wrapped {@code OutputStream}. */
|
||||
protected final OutputStream out;
|
||||
|
||||
/**
|
||||
* Creates an {@code OutputStreamAdapter}.
|
||||
*
|
||||
* @param pOut the wrapped {@code OutputStream}
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code pOut} is {@code null}.
|
||||
*/
|
||||
public OutputStreamAdapter(final OutputStream pOut) {
|
||||
Validate.notNull(pOut, "out");
|
||||
out = pOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped {@code OutputStream}.
|
||||
*
|
||||
* @return the wrapped {@code OutputStream}.
|
||||
*/
|
||||
public OutputStream getOutputStream() {
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServletOutputStream adapted from " + out.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte to the underlying stream.
|
||||
*
|
||||
* @param pByte the byte to write.
|
||||
*
|
||||
* @throws IOException if an error occurs during writing
|
||||
*/
|
||||
public void write(final int pByte) throws IOException {
|
||||
out.write(pByte);
|
||||
}
|
||||
|
||||
// Overide for efficiency
|
||||
public void write(final byte pBytes[]) throws IOException {
|
||||
out.write(pBytes);
|
||||
}
|
||||
|
||||
// Overide for efficiency
|
||||
public void write(final byte pBytes[], final int pOff, final int pLen) throws IOException {
|
||||
out.write(pBytes, pOff, pLen);
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRequest;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
|
||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||
|
||||
/**
|
||||
* ServletAttributesMap
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: ServletAttributesMap.java,v 1.0 01.03.13 10:34 haraldk Exp$
|
||||
*/
|
||||
class ServletAttributesMapAdapter extends AbstractServletMapAdapter<Object> {
|
||||
private final ServletContext context;
|
||||
private final ServletRequest request;
|
||||
|
||||
ServletAttributesMapAdapter(final ServletContext context) {
|
||||
this(notNull(context), null);
|
||||
}
|
||||
|
||||
ServletAttributesMapAdapter(final ServletRequest request) {
|
||||
this(null, notNull(request));
|
||||
}
|
||||
|
||||
private ServletAttributesMapAdapter(final ServletContext context, final ServletRequest request) {
|
||||
this.context = context;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Enumeration<String> getAttributeNames() {
|
||||
return context != null ? context.getAttributeNames() : request.getAttributeNames();
|
||||
}
|
||||
|
||||
private Object getAttribute(final String name) {
|
||||
return context != null ? context.getAttribute(name) : request.getAttribute(name);
|
||||
}
|
||||
|
||||
private Object setAttribute(String name, Object value) {
|
||||
Object oldValue = getAttribute(name);
|
||||
|
||||
if (context != null) {
|
||||
context.setAttribute(name, value);
|
||||
}
|
||||
else {
|
||||
request.setAttribute(name, value);
|
||||
}
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
private Object removeAttribute(String name) {
|
||||
Object oldValue = getAttribute(name);
|
||||
|
||||
if (context != null) {
|
||||
context.removeAttribute(name);
|
||||
}
|
||||
else {
|
||||
request.removeAttribute(name);
|
||||
}
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterator<String> keysImpl() {
|
||||
final Enumeration<String> keys = getAttributeNames();
|
||||
return new Iterator<String>() {
|
||||
private String key;
|
||||
|
||||
public boolean hasNext() {
|
||||
return keys.hasMoreElements();
|
||||
}
|
||||
|
||||
public String next() {
|
||||
key = keys.nextElement();
|
||||
return key;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
// Support removal of attribute through key iterator
|
||||
removeAttribute(key);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object valueImpl(String pName) {
|
||||
return getAttribute(pName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object put(String key, Object value) {
|
||||
return setAttribute(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(Object key) {
|
||||
return key instanceof String ? removeAttribute((String) key) : null;
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
/**
|
||||
* ServletConfigException.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: ServletConfigException.java#2 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class ServletConfigException extends ServletException {
|
||||
|
||||
// TODO: Parameters for init-param at fault, and possibly servlet name?
|
||||
|
||||
/**
|
||||
* Creates a {@code ServletConfigException} with the given message.
|
||||
*
|
||||
* @param pMessage the exception message
|
||||
*/
|
||||
public ServletConfigException(String pMessage) {
|
||||
super(pMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code ServletConfigException} with the given message and cause.
|
||||
*
|
||||
* @param pMessage the exception message
|
||||
* @param pCause the exception cause
|
||||
*/
|
||||
public ServletConfigException(final String pMessage, final Throwable pCause) {
|
||||
super(pMessage, pCause);
|
||||
|
||||
maybeInitCause(pCause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code ServletConfigException} with the cause.
|
||||
*
|
||||
* @param pCause the exception cause
|
||||
*/
|
||||
public ServletConfigException(final Throwable 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) {
|
||||
initCause(pCause);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,284 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* {@code ServletConfig} or {@code FilterConfig} adapter, that implements
|
||||
* the {@code Map} interface for interoperability with collection-based API's.
|
||||
* <p>
|
||||
* This {@code Map} is not synchronized.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: ServletConfigMapAdapter.java#2 $
|
||||
*/
|
||||
class ServletConfigMapAdapter extends AbstractMap<String, String> implements Map<String, String>, Serializable, Cloneable {
|
||||
|
||||
enum ConfigType {
|
||||
ServletConfig, FilterConfig, ServletContext
|
||||
}
|
||||
|
||||
private final ConfigType type;
|
||||
|
||||
private final ServletConfig servletConfig;
|
||||
private final FilterConfig filterConfig;
|
||||
private final ServletContext servletContext;
|
||||
|
||||
// Cache the entry set
|
||||
private transient Set<Entry<String, String>> entrySet;
|
||||
|
||||
public ServletConfigMapAdapter(final ServletConfig pConfig) {
|
||||
this(pConfig, ConfigType.ServletConfig);
|
||||
}
|
||||
|
||||
public ServletConfigMapAdapter(final FilterConfig pConfig) {
|
||||
this(pConfig, ConfigType.FilterConfig);
|
||||
}
|
||||
|
||||
public ServletConfigMapAdapter(final ServletContext pContext) {
|
||||
this(pContext, ConfigType.ServletContext);
|
||||
}
|
||||
|
||||
private ServletConfigMapAdapter(final Object pConfig, final ConfigType pType) {
|
||||
// Could happen if client code invokes with null reference
|
||||
Validate.notNull(pConfig, "config");
|
||||
|
||||
type = pType;
|
||||
|
||||
switch (type) {
|
||||
case ServletConfig:
|
||||
servletConfig = (ServletConfig) pConfig;
|
||||
filterConfig = null;
|
||||
servletContext = null;
|
||||
break;
|
||||
case FilterConfig:
|
||||
servletConfig = null;
|
||||
filterConfig = (FilterConfig) pConfig;
|
||||
servletContext = null;
|
||||
break;
|
||||
case ServletContext:
|
||||
servletConfig = null;
|
||||
filterConfig = null;
|
||||
servletContext = (ServletContext) pConfig;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Wrong type: " + pType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the servlet or filter name from the config.
|
||||
*
|
||||
* @return the servlet or filter name
|
||||
*/
|
||||
public final String getName() {
|
||||
switch (type) {
|
||||
case ServletConfig:
|
||||
return servletConfig.getServletName();
|
||||
case FilterConfig:
|
||||
return filterConfig.getFilterName();
|
||||
case ServletContext:
|
||||
return servletContext.getServletContextName();
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the servlet context from the config.
|
||||
*
|
||||
* @return the servlet context
|
||||
*/
|
||||
public final ServletContext getServletContext() {
|
||||
switch (type) {
|
||||
case ServletConfig:
|
||||
return servletConfig.getServletContext();
|
||||
case FilterConfig:
|
||||
return filterConfig.getServletContext();
|
||||
case ServletContext:
|
||||
return servletContext;
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public final Enumeration getInitParameterNames() {
|
||||
switch (type) {
|
||||
case ServletConfig:
|
||||
return servletConfig.getInitParameterNames();
|
||||
case FilterConfig:
|
||||
return filterConfig.getInitParameterNames();
|
||||
case ServletContext:
|
||||
return servletContext.getInitParameterNames();
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public final String getInitParameter(final String pName) {
|
||||
switch (type) {
|
||||
case ServletConfig:
|
||||
return servletConfig.getInitParameter(pName);
|
||||
case FilterConfig:
|
||||
return filterConfig.getInitParameter(pName);
|
||||
case ServletContext:
|
||||
return servletContext.getInitParameter(pName);
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Entry<String, String>> entrySet() {
|
||||
if (entrySet == null) {
|
||||
entrySet = createEntrySet();
|
||||
}
|
||||
return entrySet;
|
||||
}
|
||||
|
||||
private Set<Entry<String, String>> createEntrySet() {
|
||||
return new AbstractSet<Entry<String, String>>() {
|
||||
// Cache size, if requested, -1 means not calculated
|
||||
private int size = -1;
|
||||
|
||||
public Iterator<Entry<String, String>> iterator() {
|
||||
return new Iterator<Entry<String, String>>() {
|
||||
// Iterator is backed by initParameterNames enumeration
|
||||
final Enumeration names = getInitParameterNames();
|
||||
|
||||
public boolean hasNext() {
|
||||
return names.hasMoreElements();
|
||||
}
|
||||
|
||||
public Entry<String, String> next() {
|
||||
final String key = (String) names.nextElement();
|
||||
return new Entry<String, String>() {
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
public String setValue(String pValue) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// NOTE: Override equals
|
||||
public boolean equals(Object pOther) {
|
||||
if (!(pOther instanceof Map.Entry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Map.Entry e = (Map.Entry) pOther;
|
||||
Object value = get(key);
|
||||
Object rKey = e.getKey();
|
||||
Object rValue = e.getValue();
|
||||
return (key == null ? rKey == null : key.equals(rKey))
|
||||
&& (value == null ? rValue == null : value.equals(rValue));
|
||||
}
|
||||
|
||||
// NOTE: Override hashCode to keep the map's
|
||||
// hashCode constant and compatible
|
||||
public int hashCode() {
|
||||
Object value = get(key);
|
||||
return ((key == null) ? 0 : key.hashCode()) ^
|
||||
((value == null) ? 0 : value.hashCode());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return key + "=" + get(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public int size() {
|
||||
if (size < 0) {
|
||||
size = calculateSize();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private int calculateSize() {
|
||||
final Enumeration names = getInitParameterNames();
|
||||
|
||||
int size = 0;
|
||||
while (names.hasMoreElements()) {
|
||||
size++;
|
||||
names.nextElement();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public String get(Object pKey) {
|
||||
return getInitParameter(StringUtil.valueOf(pKey));
|
||||
}
|
||||
|
||||
/// Unsupported Map methods
|
||||
@Override
|
||||
public String put(String pKey, String pValue) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String remove(Object pKey) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map pMap) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.util.FilterIterator;
|
||||
import com.twelvemonkeys.util.convert.ConversionException;
|
||||
import com.twelvemonkeys.util.convert.Converter;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletConfig;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* ServletConfigurator
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: ServletConfigurator.java,v 1.0 Apr 30, 2010 2:51:38 PM haraldk Exp$
|
||||
* @see com.twelvemonkeys.servlet.InitParam
|
||||
*/
|
||||
final class ServletConfigurator {
|
||||
// TODO: Rethink @InitParam? Allow annotation of method parameters instead? Allows setLocation(@InitParam int x, @InitParam int y)
|
||||
// TODO: At least allow field injection
|
||||
// TODO: defaultValue, required
|
||||
|
||||
private ServletConfigurator() {
|
||||
}
|
||||
|
||||
public static void configure(final Servlet pServlet, final ServletConfig pConfig) throws ServletConfigException {
|
||||
new Configurator(pServlet, pConfig.getServletName()).configure(ServletUtil.asMap(pConfig));
|
||||
}
|
||||
|
||||
public static void configure(final Filter pFilter, final FilterConfig pConfig) throws ServletConfigException {
|
||||
new Configurator(pFilter, pConfig.getFilterName()).configure(ServletUtil.asMap(pConfig));
|
||||
}
|
||||
|
||||
private static class Configurator {
|
||||
private final Object servletOrFilter;
|
||||
private final String name;
|
||||
|
||||
private Configurator(final Object servletOrFilter, final String name) {
|
||||
this.servletOrFilter = servletOrFilter;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
private void configure(final Map<String, String> pMapping) throws ServletConfigException {
|
||||
// Loop over methods with InitParam annotations
|
||||
for (Method method : annotatedMethods(servletOrFilter.getClass(), InitParam.class)) {
|
||||
assertAcceptableMethod(method);
|
||||
|
||||
// Get value or default, throw exception if missing required value
|
||||
Object value = getConfiguredValue(method, pMapping);
|
||||
|
||||
if (value != null) {
|
||||
// Inject value to this method
|
||||
try {
|
||||
method.invoke(servletOrFilter, value);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
// We know the method is accessible, so this should never happen
|
||||
throw new Error(e);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
throw new ServletConfigException(String.format("Could not configure %s: %s", name, e.getCause().getMessage()), e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Loop over fields with InitParam annotations
|
||||
|
||||
// TODO: Log warning for mappings not present among InitParam annotated methods?
|
||||
}
|
||||
|
||||
private Object getConfiguredValue(final Method method, final Map<String, String> mapping) throws ServletConfigException {
|
||||
InitParam initParam = method.getAnnotation(InitParam.class);
|
||||
String paramName = getParameterName(method, initParam);
|
||||
|
||||
// Get parameter value
|
||||
String stringValue = mapping.get(paramName);
|
||||
|
||||
if (stringValue == null && initParam.name().equals(InitParam.UNDEFINED)) {
|
||||
stringValue = mapping.get(StringUtil.camelToLisp(paramName));
|
||||
}
|
||||
|
||||
if (stringValue == null) {
|
||||
// InitParam support required = true and throw exception if not present in map
|
||||
if (initParam.required()) {
|
||||
throw new ServletConfigException(
|
||||
String.format(
|
||||
"Could not configure %s: Required init-parameter \"%s\" of type %s is missing",
|
||||
name, paramName, method.getParameterTypes()[0]
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (!initParam.defaultValue().equals(InitParam.UNDEFINED)) {
|
||||
// Support default values
|
||||
stringValue = initParam.defaultValue();
|
||||
}
|
||||
}
|
||||
|
||||
// Convert value based on method arguments...
|
||||
return stringValue == null ? null : convertValue(method, stringValue);
|
||||
}
|
||||
|
||||
private Object convertValue(final Method method, final String stringValue) throws ServletConfigException {
|
||||
// We know it's a single parameter method
|
||||
Class<?> type = method.getParameterTypes()[0];
|
||||
|
||||
try {
|
||||
return String.class.equals(type) ? stringValue : Converter.getInstance().toObject(stringValue, type);
|
||||
}
|
||||
catch (ConversionException e) {
|
||||
throw new ServletConfigException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getParameterName(final Method method, final InitParam initParam) throws ServletConfigException {
|
||||
String paramName = initParam.name();
|
||||
|
||||
if (paramName.equals(InitParam.UNDEFINED)) {
|
||||
String methodName = method.getName();
|
||||
if (methodName.startsWith("set") && methodName.length() > 3) {
|
||||
paramName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
|
||||
}
|
||||
else {
|
||||
throw new ServletConfigException(
|
||||
String.format(
|
||||
"Could not configure %s: InitParam annotated method must either specify name or follow Bean standard for properties (ie. setFoo => 'foo'): %s",
|
||||
name, method
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return paramName;
|
||||
}
|
||||
|
||||
private void assertAcceptableMethod(final Method method) throws ServletConfigException {
|
||||
// Try to use setAccessible, if not public
|
||||
boolean isAccessible = Modifier.isPublic(method.getModifiers());
|
||||
|
||||
if (!isAccessible) {
|
||||
try {
|
||||
method.setAccessible(true);
|
||||
isAccessible = true;
|
||||
}
|
||||
catch (SecurityException ignore) {
|
||||
// Won't be accessible, we'll fail below
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAccessible || method.getReturnType() != Void.TYPE || method.getParameterTypes().length != 1) {
|
||||
throw new ServletConfigException(
|
||||
String.format(
|
||||
"Could not configure %s: InitParam annotated method must be public void and have a single parameter argument list: %s",
|
||||
name, method
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets all methods annotated with the given annotations.
|
||||
*
|
||||
* @param pClass the class to get annotated methods from
|
||||
* @param pAnnotations the annotations to test for
|
||||
* @return an iterable that allows iterating over all methods with the given annotations.
|
||||
*/
|
||||
private Iterable<Method> annotatedMethods(final Class<?> pClass, final Class<? extends Annotation>... pAnnotations) {
|
||||
return new Iterable<Method>() {
|
||||
public Iterator<Method> iterator() {
|
||||
Set<Method> methods = new LinkedHashSet<Method>();
|
||||
|
||||
Class<?> cl = pClass;
|
||||
while (cl.getSuperclass() != null) { // There's no annotations of interest on java.lang.Object
|
||||
methods.addAll(Arrays.asList(cl.getDeclaredMethods()));
|
||||
|
||||
// TODO: What about interface methods? Do we really want them?
|
||||
Class<?>[] interfaces = cl.getInterfaces();
|
||||
for (Class<?> i : interfaces) {
|
||||
methods.addAll(Arrays.asList(i.getDeclaredMethods()));
|
||||
}
|
||||
|
||||
cl = cl.getSuperclass();
|
||||
}
|
||||
|
||||
return new FilterIterator<Method>(methods.iterator(), new FilterIterator.Filter<Method>() {
|
||||
public boolean accept(final Method pMethod) {
|
||||
for (Class<? extends Annotation> annotation : pAnnotations) {
|
||||
if (!pMethod.isAnnotationPresent(annotation) || isOverriddenWithAnnotation(pMethod, annotation)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pMethod the method to test for override
|
||||
* @param pAnnotation the annotation that must be present
|
||||
* @return {@code true} iff the method is overridden in a subclass, and has annotation
|
||||
* @see <a href="http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.8">The Java Language Specification: Classes: Inheritance, Overriding, and Hiding</a>
|
||||
*/
|
||||
private boolean isOverriddenWithAnnotation(final Method pMethod, final Class<? extends Annotation> pAnnotation) {
|
||||
if (Modifier.isPrivate(pMethod.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Class cl = pClass;
|
||||
|
||||
// Loop down up from subclass to superclass declaring the method
|
||||
while (cl != null && !pMethod.getDeclaringClass().equals(cl)) {
|
||||
try {
|
||||
Method override = cl.getDeclaredMethod(pMethod.getName(), pMethod.getParameterTypes());
|
||||
|
||||
// Overridden, test if it has the annotation present
|
||||
if (override.isAnnotationPresent(pAnnotation)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
catch (NoSuchMethodException ignore) {
|
||||
}
|
||||
|
||||
cl = cl.getSuperclass();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import com.twelvemonkeys.util.CollectionUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
|
||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||
|
||||
/**
|
||||
* ServletHeadersMapAdapter
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: ServletHeadersMapAdapter.java#1 $
|
||||
*/
|
||||
class ServletHeadersMapAdapter extends AbstractServletMapAdapter<List<String>> {
|
||||
|
||||
protected final HttpServletRequest request;
|
||||
|
||||
public ServletHeadersMapAdapter(final HttpServletRequest pRequest) {
|
||||
request = notNull(pRequest, "request");
|
||||
}
|
||||
|
||||
protected List<String> valueImpl(final String pName) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Enumeration<String> headers = request.getHeaders(pName);
|
||||
return headers == null ? null : toList(CollectionUtil.iterator(headers));
|
||||
}
|
||||
|
||||
private static List<String> toList(final Iterator<String> pValues) {
|
||||
List<String> list = new ArrayList<String>();
|
||||
CollectionUtil.addAll(list, pValues);
|
||||
return Collections.unmodifiableList(list);
|
||||
}
|
||||
|
||||
protected Iterator<String> keysImpl() {
|
||||
@SuppressWarnings("unchecked")
|
||||
Enumeration<String> headerNames = request.getHeaderNames();
|
||||
return headerNames == null ? null : CollectionUtil.iterator(headerNames);
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import com.twelvemonkeys.util.CollectionUtil;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||
|
||||
/**
|
||||
* ServletParametersMapAdapter
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: ServletParametersMapAdapter.java#1 $
|
||||
*/
|
||||
class ServletParametersMapAdapter extends AbstractServletMapAdapter<List<String>> {
|
||||
// TODO: Be able to piggyback on HttpServletRequest.getParameterMap when available?
|
||||
|
||||
protected final ServletRequest request;
|
||||
|
||||
public ServletParametersMapAdapter(final ServletRequest pRequest) {
|
||||
request = notNull(pRequest, "request");
|
||||
}
|
||||
|
||||
protected List<String> valueImpl(String pName) {
|
||||
String[] values = request.getParameterValues(pName);
|
||||
return values == null ? null : Arrays.asList(values);
|
||||
}
|
||||
|
||||
protected Iterator<String> keysImpl() {
|
||||
@SuppressWarnings("unchecked")
|
||||
Enumeration<String> names = request.getParameterNames();
|
||||
return names == null ? null : CollectionUtil.iterator(names);
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
/**
|
||||
* A delegate for handling stream support in wrapped servlet responses.
|
||||
* <p>
|
||||
* Client code should delegate {@code getOutputStream}, {@code getWriter},
|
||||
* {@code flushBuffer} and {@code resetBuffer} methods from the servlet response.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: ServletResponseStreamDelegate.java#2 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class ServletResponseStreamDelegate {
|
||||
private Object out = null;
|
||||
protected final ServletResponse response;
|
||||
|
||||
public ServletResponseStreamDelegate(final ServletResponse pResponse) {
|
||||
response = notNull(pResponse, "response");
|
||||
}
|
||||
|
||||
// NOTE: Intentionally NOT thread safe, as one request/response should be handled by one thread ONLY.
|
||||
public final ServletOutputStream getOutputStream() throws IOException {
|
||||
if (out == null) {
|
||||
OutputStream out = createOutputStream();
|
||||
this.out = out instanceof ServletOutputStream ? out : new OutputStreamAdapter(out);
|
||||
}
|
||||
else if (out instanceof PrintWriter) {
|
||||
throw new IllegalStateException("getWriter() already called.");
|
||||
}
|
||||
|
||||
return (ServletOutputStream) out;
|
||||
}
|
||||
|
||||
// NOTE: Intentionally NOT thread safe, as one request/response should be handled by one thread ONLY.
|
||||
public final PrintWriter getWriter() throws IOException {
|
||||
if (out == null) {
|
||||
// NOTE: getCharacterEncoding may/should not return null
|
||||
OutputStream out = createOutputStream();
|
||||
String charEncoding = response.getCharacterEncoding();
|
||||
this.out = new PrintWriter(charEncoding != null ? new OutputStreamWriter(out, charEncoding) : new OutputStreamWriter(out));
|
||||
}
|
||||
else if (out instanceof ServletOutputStream) {
|
||||
throw new IllegalStateException("getOutputStream() already called.");
|
||||
}
|
||||
|
||||
return (PrintWriter) out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code OutputStream}.
|
||||
* Subclasses should override this method to provide a decorated output stream.
|
||||
* This method is guaranteed to be invoked only once for a request/response
|
||||
* (unless {@code resetBuffer} is invoked).
|
||||
* <p>
|
||||
* This implementation simply returns the output stream from the wrapped
|
||||
* response.
|
||||
* </p>
|
||||
*
|
||||
* @return the {@code OutputStream} to use for the response
|
||||
* @throws IOException if an I/O exception occurs
|
||||
*/
|
||||
protected OutputStream createOutputStream() throws IOException {
|
||||
return response.getOutputStream();
|
||||
}
|
||||
|
||||
public void flushBuffer() throws IOException {
|
||||
if (out instanceof ServletOutputStream) {
|
||||
((ServletOutputStream) out).flush();
|
||||
}
|
||||
else if (out != null) {
|
||||
((PrintWriter) out).flush();
|
||||
}
|
||||
}
|
||||
|
||||
public void resetBuffer() {
|
||||
out = null;
|
||||
}
|
||||
}
|
||||
@@ -1,785 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import java.io.File;
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletRequestWrapper;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.ServletResponseWrapper;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.util.convert.ConversionException;
|
||||
import com.twelvemonkeys.util.convert.Converter;
|
||||
|
||||
|
||||
/**
|
||||
* Various servlet related helper methods.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author Eirik Torske
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: ServletUtil.java#3 $
|
||||
*/
|
||||
@Deprecated
|
||||
public final class ServletUtil {
|
||||
|
||||
/**
|
||||
* {@code "javax.servlet.include.request_uri"}
|
||||
*/
|
||||
private final static String ATTRIB_INC_REQUEST_URI = "javax.servlet.include.request_uri";
|
||||
|
||||
/**
|
||||
* {@code "javax.servlet.include.context_path"}
|
||||
*/
|
||||
private final static String ATTRIB_INC_CONTEXT_PATH = "javax.servlet.include.context_path";
|
||||
|
||||
/**
|
||||
* {@code "javax.servlet.include.servlet_path"}
|
||||
*/
|
||||
private final static String ATTRIB_INC_SERVLET_PATH = "javax.servlet.include.servlet_path";
|
||||
|
||||
/**
|
||||
* {@code "javax.servlet.include.path_info"}
|
||||
*/
|
||||
private final static String ATTRIB_INC_PATH_INFO = "javax.servlet.include.path_info";
|
||||
|
||||
/**
|
||||
* {@code "javax.servlet.include.query_string"}
|
||||
*/
|
||||
private final static String ATTRIB_INC_QUERY_STRING = "javax.servlet.include.query_string";
|
||||
|
||||
/**
|
||||
* {@code "javax.servlet.forward.request_uri"}
|
||||
*/
|
||||
private final static String ATTRIB_FWD_REQUEST_URI = "javax.servlet.forward.request_uri";
|
||||
|
||||
/**
|
||||
* {@code "javax.servlet.forward.context_path"}
|
||||
*/
|
||||
private final static String ATTRIB_FWD_CONTEXT_PATH = "javax.servlet.forward.context_path";
|
||||
|
||||
/**
|
||||
* {@code "javax.servlet.forward.servlet_path"}
|
||||
*/
|
||||
private final static String ATTRIB_FWD_SERVLET_PATH = "javax.servlet.forward.servlet_path";
|
||||
|
||||
/**
|
||||
* {@code "javax.servlet.forward.path_info"}
|
||||
*/
|
||||
private final static String ATTRIB_FWD_PATH_INFO = "javax.servlet.forward.path_info";
|
||||
|
||||
/**
|
||||
* {@code "javax.servlet.forward.query_string"}
|
||||
*/
|
||||
private final static String ATTRIB_FWD_QUERY_STRING = "javax.servlet.forward.query_string";
|
||||
|
||||
/**
|
||||
* Don't create, static methods only
|
||||
*/
|
||||
private ServletUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the given parameter from the request, or if the
|
||||
* parameter is not set, the default value.
|
||||
*
|
||||
* @param pReq the servlet request
|
||||
* @param pName the parameter name
|
||||
* @param pDefault the default value
|
||||
* @return the value of the parameter, or the default value, if the
|
||||
* parameter is not set.
|
||||
*/
|
||||
public static String getParameter(final ServletRequest pReq, final String pName, final String pDefault) {
|
||||
String str = pReq.getParameter(pName);
|
||||
|
||||
return str != null ? str : pDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the given parameter from the request converted to
|
||||
* an Object. 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 pType the type of object (class) to return
|
||||
* @param pFormat the format to use (might be {@code null} in many cases)
|
||||
* @param pDefault the default value
|
||||
* @return the value of the parameter converted to a boolean, or the
|
||||
* default value, if the parameter is not set.
|
||||
* @throws IllegalArgumentException if {@code pDefault} is
|
||||
* non-{@code null} and not an instance of {@code pType}
|
||||
* @throws NullPointerException if {@code pReq}, {@code pName} or
|
||||
* {@code pType} is {@code null}.
|
||||
* @see Converter#toObject
|
||||
*/
|
||||
// TODO: Well, it's done. Need some thinking... We probably don't want default if conversion fails...
|
||||
static <T> T getParameter(final ServletRequest pReq, final String pName, final Class<T> 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());
|
||||
}
|
||||
|
||||
String str = pReq.getParameter(pName);
|
||||
|
||||
if (str == null) {
|
||||
return pDefault;
|
||||
}
|
||||
|
||||
try {
|
||||
return pType.cast(Converter.getInstance().toObject(str, pType, pFormat));
|
||||
}
|
||||
catch (ConversionException ce) {
|
||||
return pDefault;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the given parameter from the request converted to
|
||||
* 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 {@code boolean}, or the
|
||||
* default value, if the parameter is not set.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
return pDefault;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the given parameter from the request converted to
|
||||
* 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 {@code int}, or the default
|
||||
* value, if the parameter is not set.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
return pDefault;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the given parameter from the request converted to
|
||||
* 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 {@code long}, or the default
|
||||
* value, if the parameter is not set.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
return pDefault;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the given parameter from the request converted to
|
||||
* 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 {@code float}, or the default
|
||||
* value, if the parameter is not set.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
return pDefault;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the given parameter from the request converted to
|
||||
* 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 {@code double}, or the default
|
||||
* value, if the parameter is not set.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
return pDefault;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the given parameter from the request converted to
|
||||
* 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 {@code Date}, or the
|
||||
* default value, if the parameter is not set.
|
||||
* @see com.twelvemonkeys.lang.StringUtil#toDate(String)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
return pDefault;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the given parameter from the request converted to
|
||||
* a 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 pFormat the date format to use
|
||||
* @param pDefault the default value
|
||||
* @return the value of the parameter converted to a Date, or the
|
||||
* default value, if the parameter is not set.
|
||||
* @see com.twelvemonkeys.lang.StringUtil#toDate(String,String)
|
||||
*/
|
||||
/*
|
||||
public static long getDateParameter(ServletRequest pReq, String pName, String pFormat, long pDefault) {
|
||||
String str = pReq.getParameter(pName);
|
||||
|
||||
try {
|
||||
return ((str != null) ? StringUtil.toDate(str, pFormat).getTime() : pDefault);
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
return pDefault;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Builds a full-blown HTTP/HTTPS URL from a
|
||||
* {@code javax.servlet.http.HttpServletRequest} object.
|
||||
*
|
||||
* @param pRequest The HTTP servlet request object.
|
||||
* @return the reproduced URL
|
||||
* @deprecated Use {@link javax.servlet.http.HttpServletRequest#getRequestURL()}
|
||||
* instead.
|
||||
*/
|
||||
@Deprecated
|
||||
static StringBuffer buildHTTPURL(final HttpServletRequest pRequest) {
|
||||
StringBuffer resultURL = new StringBuffer();
|
||||
|
||||
// Scheme, as in http, https, ftp etc
|
||||
String scheme = pRequest.getScheme();
|
||||
resultURL.append(scheme);
|
||||
resultURL.append("://");
|
||||
resultURL.append(pRequest.getServerName());
|
||||
|
||||
// Append port only if not default port
|
||||
int port = pRequest.getServerPort();
|
||||
if (port > 0 &&
|
||||
!(("http".equals(scheme) && port == 80) ||
|
||||
("https".equals(scheme) && port == 443))) {
|
||||
resultURL.append(":");
|
||||
resultURL.append(port);
|
||||
}
|
||||
|
||||
// Append URI
|
||||
resultURL.append(pRequest.getRequestURI());
|
||||
|
||||
// If present, append extra path info
|
||||
String pathInfo = pRequest.getPathInfo();
|
||||
if (pathInfo != null) {
|
||||
resultURL.append(pathInfo);
|
||||
}
|
||||
|
||||
return resultURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URI of the resource currently included.
|
||||
* The value is read from the request attribute
|
||||
* {@code "javax.servlet.include.request_uri"}
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @return the URI of the included resource, or {@code null} if no include
|
||||
* @see HttpServletRequest#getRequestURI
|
||||
* @since Servlet 2.2
|
||||
*/
|
||||
public static String getIncludeRequestURI(final ServletRequest pRequest) {
|
||||
return (String) pRequest.getAttribute(ATTRIB_INC_REQUEST_URI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the context path of the resource currently included.
|
||||
* The value is read from the request attribute
|
||||
* {@code "javax.servlet.include.context_path"}
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @return the context path of the included resource, or {@code null} if no include
|
||||
* @see HttpServletRequest#getContextPath
|
||||
* @since Servlet 2.2
|
||||
*/
|
||||
public static String getIncludeContextPath(final ServletRequest pRequest) {
|
||||
return (String) pRequest.getAttribute(ATTRIB_INC_CONTEXT_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the servlet path of the resource currently included.
|
||||
* The value is read from the request attribute
|
||||
* {@code "javax.servlet.include.servlet_path"}
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @return the servlet path of the included resource, or {@code null} if no include
|
||||
* @see HttpServletRequest#getServletPath
|
||||
* @since Servlet 2.2
|
||||
*/
|
||||
public static String getIncludeServletPath(final ServletRequest pRequest) {
|
||||
return (String) pRequest.getAttribute(ATTRIB_INC_SERVLET_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path info of the resource currently included.
|
||||
* The value is read from the request attribute
|
||||
* {@code "javax.servlet.include.path_info"}
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @return the path info of the included resource, or {@code null} if no include
|
||||
* @see HttpServletRequest#getPathInfo
|
||||
* @since Servlet 2.2
|
||||
*/
|
||||
public static String getIncludePathInfo(final ServletRequest pRequest) {
|
||||
return (String) pRequest.getAttribute(ATTRIB_INC_PATH_INFO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the query string of the resource currently included.
|
||||
* The value is read from the request attribute
|
||||
* {@code "javax.servlet.include.query_string"}
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @return the query string of the included resource, or {@code null} if no include
|
||||
* @see HttpServletRequest#getQueryString
|
||||
* @since Servlet 2.2
|
||||
*/
|
||||
public static String getIncludeQueryString(final ServletRequest pRequest) {
|
||||
return (String) pRequest.getAttribute(ATTRIB_INC_QUERY_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URI of the resource this request was forwarded from.
|
||||
* The value is read from the request attribute
|
||||
* {@code "javax.servlet.forward.request_uri"}
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @return the URI of the resource, or {@code null} if not forwarded
|
||||
* @see HttpServletRequest#getRequestURI
|
||||
* @since Servlet 2.4
|
||||
*/
|
||||
public static String getForwardRequestURI(final ServletRequest pRequest) {
|
||||
return (String) pRequest.getAttribute(ATTRIB_FWD_REQUEST_URI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the context path of the resource this request was forwarded from.
|
||||
* The value is read from the request attribute
|
||||
* {@code "javax.servlet.forward.context_path"}
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @return the context path of the resource, or {@code null} if not forwarded
|
||||
* @see HttpServletRequest#getContextPath
|
||||
* @since Servlet 2.4
|
||||
*/
|
||||
public static String getForwardContextPath(final ServletRequest pRequest) {
|
||||
return (String) pRequest.getAttribute(ATTRIB_FWD_CONTEXT_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the servlet path of the resource this request was forwarded from.
|
||||
* The value is read from the request attribute
|
||||
* {@code "javax.servlet.forward.servlet_path"}
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @return the servlet path of the resource, or {@code null} if not forwarded
|
||||
* @see HttpServletRequest#getServletPath
|
||||
* @since Servlet 2.4
|
||||
*/
|
||||
public static String getForwardServletPath(final ServletRequest pRequest) {
|
||||
return (String) pRequest.getAttribute(ATTRIB_FWD_SERVLET_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path info of the resource this request was forwarded from.
|
||||
* The value is read from the request attribute
|
||||
* {@code "javax.servlet.forward.path_info"}
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @return the path info of the resource, or {@code null} if not forwarded
|
||||
* @see HttpServletRequest#getPathInfo
|
||||
* @since Servlet 2.4
|
||||
*/
|
||||
public static String getForwardPathInfo(final ServletRequest pRequest) {
|
||||
return (String) pRequest.getAttribute(ATTRIB_FWD_PATH_INFO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the query string of the resource this request was forwarded from.
|
||||
* The value is read from the request attribute
|
||||
* {@code "javax.servlet.forward.query_string"}
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @return the query string of the resource, or {@code null} if not forwarded
|
||||
* @see HttpServletRequest#getQueryString
|
||||
* @since Servlet 2.4
|
||||
*/
|
||||
public static String getForwardQueryString(final ServletRequest pRequest) {
|
||||
return (String) pRequest.getAttribute(ATTRIB_FWD_QUERY_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the servlet or the script that generated the servlet.
|
||||
*
|
||||
* @param pRequest The HTTP servlet request object.
|
||||
* @return the script name.
|
||||
* @see javax.servlet.http.HttpServletRequest#getServletPath()
|
||||
*/
|
||||
// TODO: Read the spec, seems to be a mismatch with the Servlet API...
|
||||
static String getScriptName(final HttpServletRequest pRequest) {
|
||||
String requestURI = pRequest.getRequestURI();
|
||||
return StringUtil.getLastElement(requestURI, "/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the request URI relative to the current context path.
|
||||
* <p>
|
||||
* As an example:
|
||||
* </p>
|
||||
* <pre>
|
||||
* requestURI = "/webapp/index.jsp"
|
||||
* contextPath = "/webapp"
|
||||
* </pre>
|
||||
* The method will return {@code "/index.jsp"}.
|
||||
*
|
||||
* @param pRequest the current HTTP request
|
||||
* @return the request URI relative to the current context path.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code URL} containing the real path for a given virtual
|
||||
* path, on URL form.
|
||||
* Note that this method will return {@code null} for all the same reasons
|
||||
* as {@code ServletContext.getRealPath(java.lang.String)} does.
|
||||
*
|
||||
* @param pContext the servlet context
|
||||
* @param pPath the virtual path
|
||||
* @return a {@code URL} object containing the path, or {@code null}.
|
||||
* @throws MalformedURLException if the path refers to a malformed URL
|
||||
* @see ServletContext#getRealPath(java.lang.String)
|
||||
* @see ServletContext#getResource(java.lang.String)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the temp directory for the given {@code ServletContext} (web app).
|
||||
*
|
||||
* @param pContext the servlet context
|
||||
* @return the temp directory
|
||||
*/
|
||||
public static File getTempDir(final ServletContext pContext) {
|
||||
return (File) pContext.getAttribute("javax.servlet.context.tempdir");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(final HttpServletRequest pRequest) {
|
||||
HttpSession session = pRequest.getSession();
|
||||
|
||||
return (session != null) ? session.getId() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unmodifiable {@code Map} view of the given
|
||||
* {@code ServletConfig}s init-parameters.
|
||||
* <small>Note: The returned {@code Map} is optimized for {@code get}
|
||||
* operations and iterating over it's {@code keySet}.
|
||||
* For other operations it may not perform well.</small>
|
||||
*
|
||||
* @param pConfig the servlet configuration
|
||||
* @return a {@code Map} view of the config
|
||||
* @throws IllegalArgumentException if {@code pConfig} is {@code null}
|
||||
*/
|
||||
public static Map<String, String> asMap(final ServletConfig pConfig) {
|
||||
return new ServletConfigMapAdapter(pConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unmodifiable {@code Map} view of the given
|
||||
* {@code FilterConfig}s init-parameters.
|
||||
* <small>Note: The returned {@code Map} is optimized for {@code get}
|
||||
* operations and iterating over it's {@code keySet}.
|
||||
* For other operations it may not perform well.</small>
|
||||
*
|
||||
* @param pConfig the servlet filter configuration
|
||||
* @return a {@code Map} view of the config
|
||||
* @throws IllegalArgumentException if {@code pConfig} is {@code null}
|
||||
*/
|
||||
public static Map<String, String> asMap(final FilterConfig pConfig) {
|
||||
return new ServletConfigMapAdapter(pConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unmodifiable {@code Map} view of the given
|
||||
* {@code ServletContext}s init-parameters.
|
||||
* <small>Note: The returned {@code Map} is optimized for {@code get}
|
||||
* operations and iterating over it's {@code keySet}.
|
||||
* For other operations it may not perform well.</small>
|
||||
*
|
||||
* @param pContext the servlet context
|
||||
* @return a {@code Map} view of the init parameters
|
||||
* @throws IllegalArgumentException if {@code pContext} is {@code null}
|
||||
*/
|
||||
public static Map<String, String> initParamsAsMap(final ServletContext pContext) {
|
||||
return new ServletConfigMapAdapter(pContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an <em>modifiable</em> {@code Map} view of the given
|
||||
* {@code ServletContext}s attributes.
|
||||
*
|
||||
* @param pContext the servlet context
|
||||
* @return a {@code Map} view of the attributes
|
||||
* @throws IllegalArgumentException if {@code pContext} is {@code null}
|
||||
*/
|
||||
public static Map<String, Object> attributesAsMap(final ServletContext pContext) {
|
||||
return new ServletAttributesMapAdapter(pContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an <em>modifiable</em> {@code Map} view of the given
|
||||
* {@code ServletRequest}s attributes.
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @return a {@code Map} view of the attributes
|
||||
* @throws IllegalArgumentException if {@code pContext} is {@code null}
|
||||
*/
|
||||
public static Map<String, Object> attributesAsMap(final ServletRequest pRequest) {
|
||||
return new ServletAttributesMapAdapter(pRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unmodifiable {@code Map} view of the given
|
||||
* {@code HttpServletRequest}s request parameters.
|
||||
*
|
||||
* @param pRequest the request
|
||||
* @return a {@code Map} view of the request parameters
|
||||
* @throws IllegalArgumentException if {@code pRequest} is {@code null}
|
||||
*/
|
||||
public static Map<String, List<String>> parametersAsMap(final ServletRequest pRequest) {
|
||||
return new ServletParametersMapAdapter(pRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unmodifiable {@code Map} view of the given
|
||||
* {@code HttpServletRequest}s request headers.
|
||||
*
|
||||
* @param pRequest the request
|
||||
* @return a {@code Map} view of the request headers
|
||||
* @throws IllegalArgumentException if {@code pRequest} is {@code null}
|
||||
*/
|
||||
public static Map<String, List<String>> headersAsMap(final HttpServletRequest pRequest) {
|
||||
return new ServletHeadersMapAdapter(pRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a wrapper that implements either {@code ServletResponse} or
|
||||
* {@code HttpServletResponse}, depending on the type of
|
||||
* {@code pImplementation.getResponse()}.
|
||||
*
|
||||
* @param pImplementation the servlet response to create a wrapper for
|
||||
* @return a {@code ServletResponse} or
|
||||
* {@code HttpServletResponse}, depending on the type of
|
||||
* {@code pImplementation.getResponse()}
|
||||
*/
|
||||
public static ServletResponse createWrapper(final ServletResponseWrapper pImplementation) {
|
||||
// TODO: Get all interfaces from implementation
|
||||
if (pImplementation.getResponse() instanceof HttpServletResponse) {
|
||||
return (HttpServletResponse) Proxy.newProxyInstance(pImplementation.getClass().getClassLoader(),
|
||||
new Class[]{HttpServletResponse.class, ServletResponse.class},
|
||||
new HttpServletResponseHandler(pImplementation));
|
||||
}
|
||||
return pImplementation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a wrapper that implements either {@code ServletRequest} or
|
||||
* {@code HttpServletRequest}, depending on the type of
|
||||
* {@code pImplementation.getRequest()}.
|
||||
*
|
||||
* @param pImplementation the servlet request to create a wrapper for
|
||||
* @return a {@code ServletResponse} or
|
||||
* {@code HttpServletResponse}, depending on the type of
|
||||
* {@code pImplementation.getResponse()}
|
||||
*/
|
||||
public static ServletRequest createWrapper(final ServletRequestWrapper pImplementation) {
|
||||
// TODO: Get all interfaces from implementation
|
||||
if (pImplementation.getRequest() instanceof HttpServletRequest) {
|
||||
return (HttpServletRequest) Proxy.newProxyInstance(pImplementation.getClass().getClassLoader(),
|
||||
new Class[]{HttpServletRequest.class, ServletRequest.class},
|
||||
new HttpServletRequestHandler(pImplementation));
|
||||
}
|
||||
return pImplementation;
|
||||
}
|
||||
|
||||
private static class HttpServletResponseHandler implements InvocationHandler {
|
||||
private final ServletResponseWrapper response;
|
||||
|
||||
HttpServletResponseHandler(final ServletResponseWrapper pResponse) {
|
||||
response = pResponse;
|
||||
}
|
||||
|
||||
public Object invoke(final Object pProxy, final Method pMethod, final Object[] pArgs) throws Throwable {
|
||||
try {
|
||||
// TODO: Allow partial implementing?
|
||||
if (pMethod.getDeclaringClass().isInstance(response)) {
|
||||
return pMethod.invoke(response, pArgs);
|
||||
}
|
||||
|
||||
// Method is not implemented in wrapper
|
||||
return pMethod.invoke(response.getResponse(), pArgs);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
// Unwrap, to avoid UndeclaredThrowableException...
|
||||
throw e.getTargetException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class HttpServletRequestHandler implements InvocationHandler {
|
||||
private final ServletRequestWrapper request;
|
||||
|
||||
HttpServletRequestHandler(final ServletRequestWrapper pRequest) {
|
||||
request = pRequest;
|
||||
}
|
||||
|
||||
public Object invoke(final Object pProxy, final Method pMethod, final Object[] pArgs) throws Throwable {
|
||||
try {
|
||||
// TODO: Allow partial implementing?
|
||||
if (pMethod.getDeclaringClass().isInstance(request)) {
|
||||
return pMethod.invoke(request, pArgs);
|
||||
}
|
||||
|
||||
// Method is not implemented in wrapper
|
||||
return pMethod.invoke(request.getRequest(), pArgs);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
// Unwrap, to avoid UndeclaredThrowableException...
|
||||
throw e.getTargetException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,311 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.twelvemonkeys.io.FileUtil;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
/**
|
||||
* ThrottleFilter, a filter for easing server during heavy load.
|
||||
* <p>
|
||||
* Intercepts requests, and returns HTTP response code {@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
|
||||
* response messages sent to the user agent, is configurable from the web
|
||||
* descriptor.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: ThrottleFilter.java#1 $
|
||||
* @see #setMaxConcurrentThreadCount
|
||||
* @see #setResponseMessages
|
||||
*/
|
||||
@Deprecated
|
||||
public class ThrottleFilter extends GenericFilter {
|
||||
|
||||
/**
|
||||
* Minimum free thread count, defaults to {@code 10}
|
||||
*/
|
||||
protected int maxConcurrentThreadCount = 10;
|
||||
|
||||
/**
|
||||
* The number of running request threads
|
||||
*/
|
||||
private int runningThreads = 0;
|
||||
private final Object runningThreadsLock = new Object();
|
||||
|
||||
/**
|
||||
* Default response message sent to user agents, if the request is rejected
|
||||
*/
|
||||
protected final static String DEFUALT_RESPONSE_MESSAGE =
|
||||
"Service temporarily unavailable, please try again later.";
|
||||
|
||||
/**
|
||||
* Default response content type
|
||||
*/
|
||||
protected static final String DEFAULT_TYPE = "text/html";
|
||||
|
||||
/**
|
||||
* The reposne message sent to user agenta, if the request is rejected
|
||||
*/
|
||||
private Map<String, String> responseMessageNames = new HashMap<String, String>(10);
|
||||
|
||||
/**
|
||||
* The reposne message sent to user agents, if the request is rejected
|
||||
*/
|
||||
private String[] responseMessageTypes = null;
|
||||
|
||||
/**
|
||||
* Cache for response messages
|
||||
*/
|
||||
private Map<String, CacheEntry> responseCache = new HashMap<String, CacheEntry>(10);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the minimum free thread count.
|
||||
*
|
||||
* @param pMaxConcurrentThreadCount
|
||||
*/
|
||||
public void setMaxConcurrentThreadCount(String pMaxConcurrentThreadCount) {
|
||||
if (!StringUtil.isEmpty(pMaxConcurrentThreadCount)) {
|
||||
try {
|
||||
maxConcurrentThreadCount = Integer.parseInt(pMaxConcurrentThreadCount);
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
// Use default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the response message sent to the user agent, if the request is
|
||||
* rejected.
|
||||
* <br>
|
||||
* The format is {@code <mime-type>=<filename>,
|
||||
* <mime-type>=<filename>}.
|
||||
* <br>
|
||||
* Example: {@code <text/vnd.wap.wmlgt;=</errors/503.wml>,
|
||||
* <text/html>=</errors/503.html>}
|
||||
*
|
||||
* @param pResponseMessages
|
||||
*/
|
||||
public void setResponseMessages(String pResponseMessages) {
|
||||
// Split string in type=filename pairs
|
||||
String[] mappings = StringUtil.toStringArray(pResponseMessages, ", \r\n\t");
|
||||
List<String> types = new ArrayList<String>();
|
||||
|
||||
for (String pair : mappings) {
|
||||
// Split pairs on '='
|
||||
String[] mapping = StringUtil.toStringArray(pair, "= ");
|
||||
|
||||
// Test for wrong mapping
|
||||
if ((mapping == null) || (mapping.length < 2)) {
|
||||
log("Error in init param \"responseMessages\": " + pResponseMessages);
|
||||
continue;
|
||||
}
|
||||
|
||||
types.add(mapping[0]);
|
||||
responseMessageNames.put(mapping[0], mapping[1]);
|
||||
}
|
||||
|
||||
// Create arrays
|
||||
responseMessageTypes = types.toArray(new String[types.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pRequest
|
||||
* @param pResponse
|
||||
* @param pChain
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||
try {
|
||||
if (beginRequest()) {
|
||||
// Continue request
|
||||
pChain.doFilter(pRequest, pResponse);
|
||||
}
|
||||
else {
|
||||
// Send error and end request
|
||||
// Get HTTP specific versions
|
||||
HttpServletRequest request = (HttpServletRequest) pRequest;
|
||||
HttpServletResponse response = (HttpServletResponse) pResponse;
|
||||
|
||||
// Get content type
|
||||
String contentType = getContentType(request);
|
||||
|
||||
// Note: This is not the way the spec says you should do it.
|
||||
// However, we handle error response this way for preformace reasons.
|
||||
// The "correct" way would be to use sendError() and register a servlet
|
||||
// that does the content negotiation as errorpage in the web descriptor.
|
||||
response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
|
||||
response.setContentType(contentType);
|
||||
response.getWriter().println(getMessage(contentType));
|
||||
|
||||
// Log warning, as this shouldn't happen too often
|
||||
log("Request denied, no more available threads for requestURI=" + request.getRequestURI());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
doneRequest();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the beginning of a request
|
||||
*
|
||||
* @return {@code true} if the request should be handled.
|
||||
*/
|
||||
private boolean beginRequest() {
|
||||
synchronized (runningThreadsLock) {
|
||||
runningThreads++;
|
||||
}
|
||||
|
||||
return (runningThreads <= maxConcurrentThreadCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the end of the request
|
||||
*/
|
||||
private void doneRequest() {
|
||||
synchronized (runningThreadsLock) {
|
||||
runningThreads--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content type for the response, suitable for the requesting user agent.
|
||||
*
|
||||
* @param pRequest
|
||||
* @return the content type
|
||||
*/
|
||||
private String getContentType(HttpServletRequest pRequest) {
|
||||
if (responseMessageTypes != null) {
|
||||
String accept = pRequest.getHeader("Accept");
|
||||
|
||||
for (String type : responseMessageTypes) {
|
||||
// Note: This is not 100% correct way of doing content negotiation
|
||||
// But we just want a compatible result, quick, so this is okay
|
||||
if (StringUtil.contains(accept, type)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If none found, return default
|
||||
return DEFAULT_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the response message for the given content type.
|
||||
*
|
||||
* @param pContentType
|
||||
* @return the message
|
||||
*/
|
||||
private String getMessage(String pContentType) {
|
||||
String fileName = responseMessageNames.get(pContentType);
|
||||
|
||||
// Get cached value
|
||||
CacheEntry entry = responseCache.get(fileName);
|
||||
|
||||
if ((entry == null) || entry.isExpired()) {
|
||||
|
||||
// Create and add or replace cached value
|
||||
entry = new CacheEntry(readMessage(fileName));
|
||||
responseCache.put(fileName, entry);
|
||||
}
|
||||
|
||||
// Return value
|
||||
return (entry.getValue() != null)
|
||||
? (String) entry.getValue()
|
||||
: DEFUALT_RESPONSE_MESSAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the response message from a file in the current web app.
|
||||
*
|
||||
* @param pFileName
|
||||
* @return the message
|
||||
*/
|
||||
private String readMessage(String pFileName) {
|
||||
try {
|
||||
// Read resource from web app
|
||||
InputStream is = getServletContext().getResourceAsStream(pFileName);
|
||||
|
||||
if (is != null) {
|
||||
return new String(FileUtil.read(is));
|
||||
}
|
||||
else {
|
||||
log("File not found: " + pFileName);
|
||||
}
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
log("Error reading file: " + pFileName + " (" + ioe.getMessage() + ")");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps track of Cached objects
|
||||
*/
|
||||
private static class CacheEntry {
|
||||
private Object value;
|
||||
private long timestamp = -1;
|
||||
|
||||
CacheEntry(Object pValue) {
|
||||
value = pValue;
|
||||
timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
boolean isExpired() {
|
||||
return (System.currentTimeMillis() - timestamp) > 60000; // Cache 1 minute
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* TimingFilter class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: TimingFilter.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class TimingFilter extends GenericFilter {
|
||||
|
||||
private String attribUsage = null;
|
||||
|
||||
/**
|
||||
* Method init
|
||||
*
|
||||
* @throws ServletException
|
||||
*/
|
||||
public void init() throws ServletException {
|
||||
attribUsage = getFilterName() + ".timerDelta";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pRequest
|
||||
* @param pResponse
|
||||
* @param pChain
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain)
|
||||
throws IOException, ServletException {
|
||||
// Get total usage of earlier filters on same level
|
||||
Object usageAttrib = pRequest.getAttribute(attribUsage);
|
||||
long total = 0;
|
||||
|
||||
if (usageAttrib instanceof Long) {
|
||||
// If set, get value, and remove attribute for nested resources
|
||||
total = (Long) usageAttrib;
|
||||
pRequest.removeAttribute(attribUsage);
|
||||
}
|
||||
|
||||
// Start timing
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
// Continue chain
|
||||
pChain.doFilter(pRequest, pResponse);
|
||||
}
|
||||
finally {
|
||||
// Stop timing
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
// Get time usage of included resources, add to total usage
|
||||
usageAttrib = pRequest.getAttribute(attribUsage);
|
||||
long usage = 0;
|
||||
if (usageAttrib instanceof Long) {
|
||||
usage = (Long) usageAttrib;
|
||||
}
|
||||
|
||||
// Get the name of the included resource
|
||||
String resourceURI = ServletUtil.getIncludeRequestURI(pRequest);
|
||||
|
||||
// If none, this is probably the parent page itself
|
||||
if (resourceURI == null) {
|
||||
resourceURI = ((HttpServletRequest) pRequest).getRequestURI();
|
||||
}
|
||||
long delta = end - start;
|
||||
|
||||
log(String.format("Request processing time for resource \"%s\": %d ms (accumulated: %d ms).", resourceURI, (delta - usage), delta));
|
||||
|
||||
// Store total usage
|
||||
total += delta;
|
||||
pRequest.setAttribute(attribUsage, total);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,246 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.ServletResponseWrapper;
|
||||
|
||||
/**
|
||||
* Removes extra unneccessary white space from a servlet response.
|
||||
* White space is defined as per {@link Character#isWhitespace(char)}.
|
||||
* <p>
|
||||
* This filter has no understanding of the content in the reponse, and will
|
||||
* remove repeated white space anywhere in the stream. It is intended for
|
||||
* removing white space from HTML or XML streams, but this limitation makes it
|
||||
* less suited for filtering HTML/XHTML with embedded CSS or JavaScript,
|
||||
* in case white space should be significant here. It is strongly reccommended
|
||||
* you keep CSS and JavaScript in separate files (this will have the added
|
||||
* benefit of further reducing the ammount of data communicated between
|
||||
* server and client).
|
||||
* </p>
|
||||
* <p>
|
||||
* <em>At the moment this filter has no concept of encoding</em>.
|
||||
* This means, that if some multi-byte escape sequence contains one or more
|
||||
* bytes that <em>individually</em> is treated as a white space, these bytes
|
||||
* may be skipped.
|
||||
* As <a href="http://en.wikipedia.org/wiki/UTF-8">UTF-8</a>
|
||||
* guarantees that no bytes are repeated in this way, this filter can safely
|
||||
* filter UTF-8.
|
||||
* Simple 8 bit character encodings, like the
|
||||
* <a href="http://en.wikipedia.org/wiki/ISO/IEC_8859">ISO/IEC 8859</a> standard, or
|
||||
* <a href="http://en.wikipedia.org/wiki/Windows-1252">Windows-1252"</a>
|
||||
* are always safe.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Configuration</b>
|
||||
* <br>
|
||||
* To use {@code TrimWhiteSpaceFilter} in your web-application, you simply need
|
||||
* to add it to your web descriptor ({@code web.xml}).
|
||||
* If using a servlet container that supports the Servlet 2.4 spec, the new
|
||||
* {@code dispatcher} element should be used, and set to
|
||||
* {@code REQUEST/FORWARD}, to make sure the filter is invoked only once for
|
||||
* requests.
|
||||
* If using an older web descriptor, set the {@code init-param}
|
||||
* {@code "once-per-request"} to {@code "true"} (this will have the same effect,
|
||||
* but might perform slightly worse than the 2.4 version).
|
||||
* Please see the examples below.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Servlet 2.4 version, filter section:</b>
|
||||
* </p>
|
||||
* <pre>
|
||||
* <!-- TrimWS Filter Configuration -->
|
||||
* <filter>
|
||||
* <filter-name>trimws</filter-name>
|
||||
* <filter-class>com.twelvemonkeys.servlet.TrimWhiteSpaceFilter</filter-class>
|
||||
* <!-- auto-flush=true is the default, may be omitted -->
|
||||
* <init-param>
|
||||
* <param-name>auto-flush</param-name>
|
||||
* <param-value>true</param-value>
|
||||
* </init-param>
|
||||
* </filter>
|
||||
* </pre>
|
||||
* <b>Filter-mapping section:</b><br>
|
||||
* <pre>
|
||||
* <!-- TimWS Filter Mapping -->
|
||||
* <filter-mapping>
|
||||
* <filter-name>trimws</filter-name>
|
||||
* <url-pattern>*.html</url-pattern>
|
||||
* <dispatcher>REQUEST</dispatcher>
|
||||
* <dispatcher>FORWARD</dispatcher>
|
||||
* </filter-mapping>
|
||||
* <filter-mapping>
|
||||
* <filter-name>trimws</filter-name>
|
||||
* <url-pattern>*.jsp</url-pattern>
|
||||
* <dispatcher>REQUEST</dispatcher>
|
||||
* <dispatcher>FORWARD</dispatcher>
|
||||
* </filter-mapping>
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: TrimWhiteSpaceFilter.java#2 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class TrimWhiteSpaceFilter extends GenericFilter {
|
||||
|
||||
private boolean autoFlush = true;
|
||||
|
||||
@InitParam
|
||||
public void setAutoFlush(final boolean pAutoFlush) {
|
||||
autoFlush = pAutoFlush;
|
||||
}
|
||||
|
||||
public void init() throws ServletException {
|
||||
super.init();
|
||||
log("Automatic flushing is " + (autoFlush ? "enabled" : "disabled"));
|
||||
}
|
||||
|
||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||
ServletResponseWrapper wrapped = new TrimWSServletResponseWrapper(pResponse);
|
||||
pChain.doFilter(pRequest, ServletUtil.createWrapper(wrapped));
|
||||
if (autoFlush) {
|
||||
wrapped.flushBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
static final class TrimWSFilterOutputStream extends FilterOutputStream {
|
||||
boolean lastWasWS = true; // Avoids leading WS by init to true
|
||||
|
||||
public TrimWSFilterOutputStream(OutputStream pOut) {
|
||||
super(pOut);
|
||||
}
|
||||
|
||||
// Override this, in case the wrapped outputstream overrides...
|
||||
public final void write(byte pBytes[]) throws IOException {
|
||||
write(pBytes, 0, pBytes.length);
|
||||
}
|
||||
|
||||
// Override this, in case the wrapped outputstream overrides...
|
||||
public final void write(byte pBytes[], int pOff, int pLen) throws IOException {
|
||||
if (pBytes == null) {
|
||||
throw new NullPointerException("bytes == null");
|
||||
}
|
||||
else if (pOff < 0 || pLen < 0 || (pOff + pLen > pBytes.length)) {
|
||||
throw new IndexOutOfBoundsException("Bytes: " + pBytes.length + " Offset: " + pOff + " Length: " + pLen);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pLen ; i++) {
|
||||
write(pBytes[pOff + i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(int pByte) throws IOException {
|
||||
// TODO: Is this good enough for multi-byte encodings like UTF-16?
|
||||
// Consider writing through a Writer that does that for us, and
|
||||
// also buffer whitespace, so we write a linefeed every time there's
|
||||
// one in the original...
|
||||
|
||||
// According to http://en.wikipedia.org/wiki/UTF-8:
|
||||
// "[...] US-ASCII octet values do not appear otherwise in a UTF-8
|
||||
// encoded character stream. This provides compatibility with file
|
||||
// systems or other software (e.g., the printf() function in
|
||||
// C libraries) that parse based on US-ASCII values but are
|
||||
// transparent to other values."
|
||||
|
||||
if (!Character.isWhitespace((char) pByte)) {
|
||||
// If char is not WS, just store
|
||||
super.write(pByte);
|
||||
lastWasWS = false;
|
||||
}
|
||||
else {
|
||||
// TODO: Consider writing only 0x0a (LF) and 0x20 (space)
|
||||
// Else, if char is WS, store first, skip the rest
|
||||
if (!lastWasWS) {
|
||||
if (pByte == 0x0d) { // Convert all CR/LF's to 0x0a
|
||||
super.write(0x0a);
|
||||
}
|
||||
else {
|
||||
super.write(pByte);
|
||||
}
|
||||
}
|
||||
lastWasWS = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class TrimWSStreamDelegate extends ServletResponseStreamDelegate {
|
||||
public TrimWSStreamDelegate(ServletResponse pResponse) {
|
||||
super(pResponse);
|
||||
}
|
||||
|
||||
protected OutputStream createOutputStream() throws IOException {
|
||||
return new TrimWSFilterOutputStream(response.getOutputStream());
|
||||
}
|
||||
}
|
||||
|
||||
static class TrimWSServletResponseWrapper extends ServletResponseWrapper {
|
||||
private final ServletResponseStreamDelegate streamDelegate = new TrimWSStreamDelegate(getResponse());
|
||||
|
||||
public TrimWSServletResponseWrapper(ServletResponse pResponse) {
|
||||
super(pResponse);
|
||||
}
|
||||
|
||||
public ServletOutputStream getOutputStream() throws IOException {
|
||||
return streamDelegate.getOutputStream();
|
||||
}
|
||||
|
||||
public PrintWriter getWriter() throws IOException {
|
||||
return streamDelegate.getWriter();
|
||||
}
|
||||
|
||||
public void setContentLength(int pLength) {
|
||||
// Will be changed by filter, so don't set.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushBuffer() throws IOException {
|
||||
streamDelegate.flushBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetBuffer() {
|
||||
streamDelegate.resetBuffer();
|
||||
}
|
||||
|
||||
// TODO: Consider picking up content-type/encoding, as we can only
|
||||
// filter US-ASCII, UTF-8 and other compatible encodings?
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* AbstractCacheResponse
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: AbstractCacheResponse.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class AbstractCacheResponse implements CacheResponse {
|
||||
private int status;
|
||||
private final Map<String, List<String>> headers = new LinkedHashMap<String, List<String>>(); // Insertion order
|
||||
private final Map<String, List<String>> readableHeaders = Collections.unmodifiableMap(headers);
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int pStatusCode) {
|
||||
status = pStatusCode;
|
||||
}
|
||||
|
||||
public void addHeader(String pHeaderName, String pHeaderValue) {
|
||||
setHeader(pHeaderName, pHeaderValue, true);
|
||||
}
|
||||
|
||||
public void setHeader(String pHeaderName, String pHeaderValue) {
|
||||
setHeader(pHeaderName, pHeaderValue, false);
|
||||
}
|
||||
|
||||
private void setHeader(String pHeaderName, String pHeaderValue, boolean pAdd) {
|
||||
List<String> values = pAdd ? headers.get(pHeaderName) : null;
|
||||
|
||||
if (values == null) {
|
||||
values = new ArrayList<String>();
|
||||
headers.put(pHeaderName, values);
|
||||
}
|
||||
|
||||
values.add(pHeaderValue);
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getHeaders() {
|
||||
return readableHeaders;
|
||||
}
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.servlet.GenericFilter;
|
||||
import com.twelvemonkeys.servlet.ServletConfigException;
|
||||
import com.twelvemonkeys.servlet.ServletUtil;
|
||||
|
||||
/**
|
||||
* A Filter that provides response caching, for HTTP {@code GET} requests.
|
||||
* <p>
|
||||
* Originally based on ideas and code found in the ONJava article
|
||||
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two
|
||||
* Servlet Filters Every Web Application Should Have</a>
|
||||
* by Jayson Falkner.
|
||||
* </p>
|
||||
*
|
||||
* @author Jayson Falkner
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: CacheFilter.java#4 $
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public class CacheFilter extends GenericFilter {
|
||||
|
||||
HTTPCache cache;
|
||||
|
||||
/**
|
||||
* Initializes the filter
|
||||
*
|
||||
* @throws javax.servlet.ServletException
|
||||
*/
|
||||
public void init() throws ServletException {
|
||||
FilterConfig config = getFilterConfig();
|
||||
|
||||
// Default don't delete cache files on exit (persistent cache)
|
||||
boolean deleteCacheOnExit = "TRUE".equalsIgnoreCase(config.getInitParameter("deleteCacheOnExit"));
|
||||
|
||||
// Default expiry time 10 minutes
|
||||
int expiryTime = 10 * 60 * 1000;
|
||||
|
||||
String expiryTimeStr = config.getInitParameter("expiryTime");
|
||||
if (!StringUtil.isEmpty(expiryTimeStr)) {
|
||||
try {
|
||||
// TODO: This is insane.. :-P Let the expiry time be in minutes or seconds..
|
||||
expiryTime = Integer.parseInt(expiryTimeStr);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new ServletConfigException("Could not parse expiryTime: " + e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// Default max mem cache size 10 MB
|
||||
int memCacheSize = 10;
|
||||
|
||||
String memCacheSizeStr = config.getInitParameter("memCacheSize");
|
||||
if (!StringUtil.isEmpty(memCacheSizeStr)) {
|
||||
try {
|
||||
memCacheSize = Integer.parseInt(memCacheSizeStr);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new ServletConfigException("Could not parse memCacheSize: " + e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
int maxCachedEntites = 10000;
|
||||
|
||||
try {
|
||||
cache = new HTTPCache(
|
||||
getTempFolder(),
|
||||
expiryTime,
|
||||
memCacheSize * 1024 * 1024,
|
||||
maxCachedEntites,
|
||||
deleteCacheOnExit,
|
||||
new ServletContextLoggerAdapter(getFilterName(), getServletContext())
|
||||
) {
|
||||
@Override
|
||||
protected File getRealFile(CacheRequest pRequest) {
|
||||
String contextRelativeURI = ServletUtil.getContextRelativeURI(((ServletCacheRequest) pRequest).getRequest());
|
||||
|
||||
String path = getServletContext().getRealPath(contextRelativeURI);
|
||||
|
||||
if (path != null) {
|
||||
return new File(path);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
log("Created cache: " + cache);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new ServletConfigException("Could not create cache: " + e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private File getTempFolder() {
|
||||
File tempRoot = (File) getServletContext().getAttribute("javax.servlet.context.tempdir");
|
||||
if (tempRoot == null) {
|
||||
throw new IllegalStateException("Missing context attribute \"javax.servlet.context.tempdir\"");
|
||||
}
|
||||
return new File(tempRoot, getFilterName());
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
log("Destroying cache: " + cache);
|
||||
cache = null;
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||
// We can only cache HTTP GET/HEAD requests
|
||||
if (!(pRequest instanceof HttpServletRequest
|
||||
&& pResponse instanceof HttpServletResponse
|
||||
&& isCachable((HttpServletRequest) pRequest))) {
|
||||
pChain.doFilter(pRequest, pResponse); // Continue chain
|
||||
}
|
||||
else {
|
||||
ServletCacheRequest cacheRequest = new ServletCacheRequest((HttpServletRequest) pRequest);
|
||||
ServletCacheResponse cacheResponse = new ServletCacheResponse((HttpServletResponse) pResponse);
|
||||
ServletResponseResolver resolver = new ServletResponseResolver(cacheRequest, cacheResponse, pChain);
|
||||
|
||||
// Render fast
|
||||
try {
|
||||
cache.doCached(cacheRequest, cacheResponse, resolver);
|
||||
}
|
||||
catch (CacheException e) {
|
||||
if (e.getCause() instanceof ServletException) {
|
||||
throw (ServletException) e.getCause();
|
||||
}
|
||||
else {
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
pResponse.flushBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCachable(HttpServletRequest pRequest) {
|
||||
// TODO: Get Cache-Control: no-cache/max-age=0 and Pragma: no-cache from REQUEST too?
|
||||
return "GET".equals(pRequest.getMethod()) || "HEAD".equals(pRequest.getMethod());
|
||||
}
|
||||
|
||||
// TODO: Extract, complete and document this class, might be useful in other cases
|
||||
// Maybe add it to the ServletUtil class
|
||||
static class ServletContextLoggerAdapter extends Logger {
|
||||
private final ServletContext context;
|
||||
|
||||
public ServletContextLoggerAdapter(String pName, ServletContext pContext) {
|
||||
super(pName, null);
|
||||
context = pContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level pLevel, String pMessage) {
|
||||
context.log(pMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level pLevel, String pMessage, Throwable pThrowable) {
|
||||
context.log(pMessage, pThrowable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* CacheRequest
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: CacheRequest.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public interface CacheRequest {
|
||||
URI getRequestURI();
|
||||
|
||||
String getMethod();
|
||||
|
||||
Map<String, List<String>> getHeaders();
|
||||
|
||||
Map<String, List<String>> getParameters();
|
||||
|
||||
String getServerName();
|
||||
|
||||
int getServerPort();
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* CacheResponse
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: CacheResponse.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public interface CacheResponse {
|
||||
OutputStream getOutputStream() throws IOException;
|
||||
|
||||
void setStatus(int pStatusCode);
|
||||
|
||||
int getStatus();
|
||||
|
||||
void addHeader(String pHeaderName, String pHeaderValue);
|
||||
|
||||
void setHeader(String pHeaderName, String pHeaderValue);
|
||||
|
||||
Map<String, List<String>> getHeaders();
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.net.HTTPUtil;
|
||||
import com.twelvemonkeys.servlet.ServletResponseStreamDelegate;
|
||||
|
||||
/**
|
||||
* CacheResponseWrapper class description.
|
||||
* <p>
|
||||
* Based on ideas and code found in the ONJava article
|
||||
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two
|
||||
* Servlet Filters Every Web Application Should Have</a>
|
||||
* by Jayson Falkner.
|
||||
* </p>
|
||||
*
|
||||
* @author Jayson Falkner
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: CacheResponseWrapper.java#3 $
|
||||
*/
|
||||
@Deprecated
|
||||
class CacheResponseWrapper extends HttpServletResponseWrapper {
|
||||
private ServletResponseStreamDelegate streamDelegate;
|
||||
|
||||
private CacheResponse response;
|
||||
private CachedEntity cached;
|
||||
private WritableCachedResponse cachedResponse;
|
||||
|
||||
private Boolean cacheable;
|
||||
private int status;
|
||||
|
||||
public CacheResponseWrapper(final ServletCacheResponse pResponse, final CachedEntity pCached) {
|
||||
super(pResponse.getResponse());
|
||||
response = pResponse;
|
||||
cached = pCached;
|
||||
init();
|
||||
}
|
||||
|
||||
/*
|
||||
NOTE: This class defers determining if a response is cacheable until the
|
||||
output stream is needed.
|
||||
This it the reason for the somewhat complicated logic in the add/setHeader
|
||||
methods below.
|
||||
*/
|
||||
private void init() {
|
||||
cacheable = null;
|
||||
status = SC_OK;
|
||||
cachedResponse = cached.createCachedResponse();
|
||||
streamDelegate = new ServletResponseStreamDelegate(this) {
|
||||
protected OutputStream createOutputStream() throws IOException {
|
||||
// Test if this request is really cacheable, otherwise,
|
||||
// just write through to underlying response, and don't cache
|
||||
if (isCacheable()) {
|
||||
return cachedResponse.getOutputStream();
|
||||
}
|
||||
else {
|
||||
cachedResponse.setStatus(status);
|
||||
cachedResponse.writeHeadersTo(CacheResponseWrapper.this.response);
|
||||
return super.getOutputStream();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
CachedResponse getCachedResponse() {
|
||||
return cachedResponse.getCachedResponse();
|
||||
}
|
||||
|
||||
public boolean isCacheable() {
|
||||
// NOTE: Intentionally not synchronized
|
||||
if (cacheable == null) {
|
||||
cacheable = isCacheableImpl();
|
||||
}
|
||||
|
||||
return cacheable;
|
||||
}
|
||||
|
||||
private boolean isCacheableImpl() {
|
||||
if (status != SC_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Vary: *
|
||||
String[] values = cachedResponse.getHeaderValues(HTTPCache.HEADER_VARY);
|
||||
if (values != null) {
|
||||
for (String value : values) {
|
||||
if ("*".equals(value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cache-Control: no-cache, no-store, must-revalidate
|
||||
values = cachedResponse.getHeaderValues(HTTPCache.HEADER_CACHE_CONTROL);
|
||||
if (values != null) {
|
||||
for (String value : values) {
|
||||
if (StringUtil.contains(value, "no-cache")
|
||||
|| StringUtil.contains(value, "no-store")
|
||||
|| StringUtil.contains(value, "must-revalidate")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pragma: no-cache
|
||||
values = cachedResponse.getHeaderValues(HTTPCache.HEADER_PRAGMA);
|
||||
if (values != null) {
|
||||
for (String value : values) {
|
||||
if (StringUtil.contains(value, "no-cache")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void flushBuffer() throws IOException {
|
||||
streamDelegate.flushBuffer();
|
||||
}
|
||||
|
||||
public void resetBuffer() {
|
||||
// Servlet 2.3
|
||||
streamDelegate.resetBuffer();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.reset();
|
||||
}
|
||||
// No else, might be cacheable after all..
|
||||
init();
|
||||
}
|
||||
|
||||
public ServletOutputStream getOutputStream() throws IOException {
|
||||
return streamDelegate.getOutputStream();
|
||||
}
|
||||
|
||||
public PrintWriter getWriter() throws IOException {
|
||||
return streamDelegate.getWriter();
|
||||
}
|
||||
|
||||
public boolean containsHeader(String name) {
|
||||
return cachedResponse.getHeaderValues(name) != null;
|
||||
}
|
||||
|
||||
public void sendError(int pStatusCode, String msg) throws IOException {
|
||||
// NOT cacheable
|
||||
status = pStatusCode;
|
||||
super.sendError(pStatusCode, msg);
|
||||
}
|
||||
|
||||
public void sendError(int pStatusCode) throws IOException {
|
||||
// NOT cacheable
|
||||
status = pStatusCode;
|
||||
super.sendError(pStatusCode);
|
||||
}
|
||||
|
||||
public void setStatus(int pStatusCode, String sm) {
|
||||
// NOTE: This method is deprecated
|
||||
setStatus(pStatusCode);
|
||||
}
|
||||
|
||||
public void setStatus(int pStatusCode) {
|
||||
// NOT cacheable unless pStatusCode == 200 (or a FEW others?)
|
||||
if (pStatusCode != SC_OK) {
|
||||
status = pStatusCode;
|
||||
super.setStatus(pStatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendRedirect(String pLocation) throws IOException {
|
||||
// NOT cacheable
|
||||
status = SC_MOVED_TEMPORARILY;
|
||||
super.sendRedirect(pLocation);
|
||||
}
|
||||
|
||||
public void setDateHeader(String pName, long pValue) {
|
||||
// If in write-trough-mode, set headers directly
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.setDateHeader(pName, pValue);
|
||||
}
|
||||
cachedResponse.setHeader(pName, HTTPUtil.formatHTTPDate(pValue));
|
||||
}
|
||||
|
||||
public void addDateHeader(String pName, long pValue) {
|
||||
// If in write-trough-mode, set headers directly
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.addDateHeader(pName, pValue);
|
||||
}
|
||||
cachedResponse.addHeader(pName, HTTPUtil.formatHTTPDate(pValue));
|
||||
}
|
||||
|
||||
public void setHeader(String pName, String pValue) {
|
||||
// If in write-trough-mode, set headers directly
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.setHeader(pName, pValue);
|
||||
}
|
||||
cachedResponse.setHeader(pName, pValue);
|
||||
}
|
||||
|
||||
public void addHeader(String pName, String pValue) {
|
||||
// If in write-trough-mode, set headers directly
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.addHeader(pName, pValue);
|
||||
}
|
||||
cachedResponse.addHeader(pName, pValue);
|
||||
}
|
||||
|
||||
public void setIntHeader(String pName, int pValue) {
|
||||
// If in write-trough-mode, set headers directly
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.setIntHeader(pName, pValue);
|
||||
}
|
||||
cachedResponse.setHeader(pName, String.valueOf(pValue));
|
||||
}
|
||||
|
||||
public void addIntHeader(String pName, int pValue) {
|
||||
// If in write-trough-mode, set headers directly
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.addIntHeader(pName, pValue);
|
||||
}
|
||||
cachedResponse.addHeader(pName, String.valueOf(pValue));
|
||||
}
|
||||
|
||||
public final void setContentType(String type) {
|
||||
setHeader(HTTPCache.HEADER_CONTENT_TYPE, type);
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* CachedEntity
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: CachedEntity.java#3 $
|
||||
*/
|
||||
@Deprecated
|
||||
interface CachedEntity {
|
||||
|
||||
/**
|
||||
* Renders the cached entity to the response.
|
||||
*
|
||||
* @param pRequest the request
|
||||
* @param pResponse the response
|
||||
* @throws java.io.IOException if an I/O exception occurs
|
||||
*/
|
||||
void render(CacheRequest pRequest, CacheResponse pResponse) throws IOException;
|
||||
|
||||
/**
|
||||
* Captures (caches) the response for the given request.
|
||||
*
|
||||
* @param pRequest the request
|
||||
* @param pResponse the response
|
||||
* @throws java.io.IOException if an I/O exception occurs
|
||||
*
|
||||
* @see #createCachedResponse()
|
||||
*/
|
||||
void capture(CacheRequest pRequest, CachedResponse pResponse) throws IOException;
|
||||
|
||||
/**
|
||||
* Tests if the content of this entity is stale for the given request.
|
||||
*
|
||||
* @param pRequest the request
|
||||
* @return {@code true} if content is stale
|
||||
*/
|
||||
boolean isStale(CacheRequest pRequest);
|
||||
|
||||
/**
|
||||
* Creates a {@code WritableCachedResponse} to use to capture the response.
|
||||
*
|
||||
* @return a {@code WritableCachedResponse}
|
||||
*/
|
||||
WritableCachedResponse createCachedResponse();
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
/**
|
||||
* CachedEntity
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: CachedEntityImpl.java#3 $
|
||||
*/
|
||||
@Deprecated
|
||||
class CachedEntityImpl implements CachedEntity {
|
||||
private String cacheURI;
|
||||
private HTTPCache cache;
|
||||
|
||||
CachedEntityImpl(String pCacheURI, HTTPCache pCache) {
|
||||
cacheURI = Validate.notNull(pCacheURI, "cacheURI");
|
||||
cache = pCache;
|
||||
}
|
||||
|
||||
public void render(CacheRequest pRequest, CacheResponse pResponse) throws IOException {
|
||||
// Get cached content
|
||||
CachedResponse cached = cache.getContent(cacheURI, pRequest);
|
||||
|
||||
// Sanity check
|
||||
if (cached == null) {
|
||||
throw new IllegalStateException("Tried to render non-cached response (cache == null).");
|
||||
}
|
||||
|
||||
// If the cached entity is not modified since the date of the browsers
|
||||
// version, then simply send a "304 Not Modified" response
|
||||
// Otherwise send the full response.
|
||||
|
||||
// TODO: WHY DID I COMMENT OUT THIS LINE AND REPLACE IT WITH THE ONE BELOW??
|
||||
//long lastModified = HTTPCache.getDateHeader(cached.getHeaderValue(HTTPCache.HEADER_LAST_MODIFIED));
|
||||
long lastModified = HTTPCache.getDateHeader(cached.getHeaderValue(HTTPCache.HEADER_CACHED_TIME));
|
||||
|
||||
// TODO: Consider handling time skews between server "now" and client "now"?
|
||||
// NOTE: The If-Modified-Since is probably right according to the server
|
||||
// even in a time skew situation, as the client should use either the
|
||||
// Date or Last-Modifed dates from the response headers (server generated)
|
||||
long ifModifiedSince = -1L;
|
||||
try {
|
||||
List<String> ifmh = pRequest.getHeaders().get(HTTPCache.HEADER_IF_MODIFIED_SINCE);
|
||||
ifModifiedSince = ifmh != null ? HTTPCache.getDateHeader(ifmh.get(0)) : -1L;
|
||||
if (ifModifiedSince != -1L) {
|
||||
/*
|
||||
long serverTime = DateUtil.currentTimeMinute();
|
||||
long clientTime = DateUtil.roundToMinute(pRequest.getDateHeader(HTTPCache.HEADER_DATE));
|
||||
|
||||
// Test if time skew is greater than time skew threshold (currently 1 minute)
|
||||
if (Math.abs(serverTime - clientTime) > 1) {
|
||||
// TODO: Correct error in ifModifiedSince?
|
||||
}
|
||||
*/
|
||||
|
||||
// System.out.println(" << CachedEntity >> If-Modified-Since present: " + ifModifiedSince + " --> " + NetUtil.formatHTTPDate(ifModifiedSince) + "==" + pRequest.getHeader(HTTPCache.HEADER_IF_MODIFIED_SINCE));
|
||||
// System.out.println(" << CachedEntity >> Last-Modified for entity: " + lastModified + " --> " + NetUtil.formatHTTPDate(lastModified));
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
// Seems to be a bug in FireFox 1.0.2..?!
|
||||
cache.log("Error in date header from user-agent. User-Agent: " + pRequest.getHeaders().get("User-Agent"), e);
|
||||
}
|
||||
|
||||
if (lastModified == -1L || (ifModifiedSince < (lastModified / 1000L) * 1000L)) {
|
||||
pResponse.setStatus(cached.getStatus());
|
||||
cached.writeHeadersTo(pResponse);
|
||||
if (isStale(pRequest)) {
|
||||
// Add warning header
|
||||
// Warning: 110 <server>:<port> Content is stale
|
||||
pResponse.addHeader(HTTPCache.HEADER_WARNING, "110 " + getHost(pRequest) + " Content is stale.");
|
||||
}
|
||||
|
||||
// NOTE: At the moment we only ever try to cache HEAD and GET requests
|
||||
if (!"HEAD".equals(pRequest.getMethod())) {
|
||||
cached.writeContentsTo(pResponse.getOutputStream());
|
||||
}
|
||||
}
|
||||
else {
|
||||
pResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
// System.out.println(" << CachedEntity >> Not modified: " + toString());
|
||||
if (isStale(pRequest)) {
|
||||
// Add warning header
|
||||
// Warning: 110 <server>:<port> Content is stale
|
||||
pResponse.addHeader(HTTPCache.HEADER_WARNING, "110 " + getHost(pRequest) + " Content is stale.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Utility method to get Host header */
|
||||
private static String getHost(CacheRequest pRequest) {
|
||||
return pRequest.getServerName() + ":" + pRequest.getServerPort();
|
||||
}
|
||||
|
||||
public void capture(CacheRequest pRequest, CachedResponse pResponse) throws IOException {
|
||||
// if (!(pResponse instanceof CacheResponseWrapper)) {
|
||||
// throw new IllegalArgumentException("Response must be created by CachedEntity.createResponseWrapper()");
|
||||
// }
|
||||
//
|
||||
// CacheResponseWrapper response = (CacheResponseWrapper) pResponse;
|
||||
|
||||
// if (response.isCacheable()) {
|
||||
cache.registerContent(
|
||||
cacheURI,
|
||||
pRequest,
|
||||
pResponse instanceof WritableCachedResponse ? ((WritableCachedResponse) pResponse).getCachedResponse() : pResponse
|
||||
);
|
||||
// }
|
||||
// else {
|
||||
// Else store that the response for this request is not cachable
|
||||
// pRequest.setAttribute(ATTRIB_NOT_CACHEABLE, Boolean.TRUE);
|
||||
|
||||
// TODO: Store this in HTTPCache, for subsequent requests to same resource?
|
||||
// }
|
||||
}
|
||||
|
||||
public boolean isStale(CacheRequest pRequest) {
|
||||
return cache.isContentStale(cacheURI, pRequest);
|
||||
}
|
||||
|
||||
public WritableCachedResponse createCachedResponse() {
|
||||
return new WritableCachedResponseImpl();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return (cacheURI != null ? cacheURI.hashCode() : 0) + 1397;
|
||||
}
|
||||
|
||||
public boolean equals(Object pOther) {
|
||||
return pOther instanceof CachedEntityImpl &&
|
||||
((cacheURI == null && ((CachedEntityImpl) pOther).cacheURI == null) ||
|
||||
cacheURI != null && cacheURI.equals(((CachedEntityImpl) pOther).cacheURI));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "CachedEntity[URI=" + cacheURI + "]";
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* CachedResponse
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: CachedResponse.java#3 $
|
||||
*/
|
||||
@Deprecated
|
||||
interface CachedResponse {
|
||||
/**
|
||||
* Writes the cached headers to the response
|
||||
*
|
||||
* @param pResponse the servlet response
|
||||
*/
|
||||
void writeHeadersTo(CacheResponse pResponse);
|
||||
|
||||
/**
|
||||
* Writes the cahced content to the response
|
||||
*
|
||||
* @param pStream the response output stream
|
||||
* @throws IOException if an I/O exception occurs during write
|
||||
*/
|
||||
void writeContentsTo(OutputStream pStream) throws IOException;
|
||||
|
||||
int getStatus();
|
||||
|
||||
// TODO: Map<String, List<String>> getHeaders()
|
||||
|
||||
/**
|
||||
* Gets the header names of all headers set in this response.
|
||||
*
|
||||
* @return an array of {@code String}s
|
||||
*/
|
||||
String[] getHeaderNames();
|
||||
|
||||
/**
|
||||
* Gets all header values set for the given header in this response. If the
|
||||
* header is not set, {@code null} is returned.
|
||||
*
|
||||
* @param pHeaderName the header name
|
||||
* @return an array of {@code String}s, or {@code null} if there is no
|
||||
* such header in this response.
|
||||
*/
|
||||
String[] getHeaderValues(String pHeaderName);
|
||||
|
||||
/**
|
||||
* Gets the first header value set for the given header in this response.
|
||||
* If the header is not set, {@code null} is returned.
|
||||
* Useful for headers that don't have multiple values, like
|
||||
* {@code "Content-Type"} or {@code "Content-Length"}.
|
||||
*
|
||||
* @param pHeaderName the header name
|
||||
* @return a {@code String}, or {@code null} if there is no
|
||||
* such header in this response.
|
||||
*/
|
||||
String getHeaderValue(String pHeaderName);
|
||||
|
||||
/**
|
||||
* Returns the size of this cached response in bytes.
|
||||
*
|
||||
* @return the size
|
||||
*/
|
||||
int size();
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
/**
|
||||
* CachedResponseImpl
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: CachedResponseImpl.java#4 $
|
||||
*/
|
||||
@Deprecated
|
||||
class CachedResponseImpl implements CachedResponse {
|
||||
final protected Map<String, List<String>> headers;
|
||||
protected int headersSize;
|
||||
protected ByteArrayOutputStream content = null;
|
||||
int status;
|
||||
|
||||
protected CachedResponseImpl() {
|
||||
headers = new LinkedHashMap<String, List<String>>(); // Keep headers in insertion order
|
||||
}
|
||||
|
||||
// For use by HTTPCache, when recreating CachedResponses from disk cache
|
||||
CachedResponseImpl(final int pStatus, final LinkedHashMap<String, List<String>> pHeaders, final int pHeaderSize, final byte[] pContent) {
|
||||
status = pStatus;
|
||||
headers = Validate.notNull(pHeaders, "headers");
|
||||
headersSize = pHeaderSize;
|
||||
content = new FastByteArrayOutputStream(pContent);
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the cached headers to the response
|
||||
*
|
||||
* @param pResponse the response
|
||||
*/
|
||||
public void writeHeadersTo(final CacheResponse pResponse) {
|
||||
String[] headers = getHeaderNames();
|
||||
for (String header : headers) {
|
||||
// HACK...
|
||||
// Strip away internal headers
|
||||
if (HTTPCache.HEADER_CACHED_TIME.equals(header)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Replace Last-Modified with X-Cached-At? See CachedEntityImpl
|
||||
|
||||
String[] headerValues = getHeaderValues(header);
|
||||
|
||||
for (int i = 0; i < headerValues.length; i++) {
|
||||
String headerValue = headerValues[i];
|
||||
|
||||
if (i == 0) {
|
||||
pResponse.setHeader(header, headerValue);
|
||||
}
|
||||
else {
|
||||
pResponse.addHeader(header, headerValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the cached content to the response
|
||||
*
|
||||
* @param pStream the response stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
public void writeContentsTo(final OutputStream pStream) throws IOException {
|
||||
if (content == null) {
|
||||
throw new IOException("Cache is null, no content to write.");
|
||||
}
|
||||
|
||||
content.writeTo(pStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the header names of all headers set in this response.
|
||||
*
|
||||
* @return an array of {@code String}s
|
||||
*/
|
||||
public String[] getHeaderNames() {
|
||||
Set<String> headers = this.headers.keySet();
|
||||
|
||||
return headers.toArray(new String[headers.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all header values set for the given header in this response. If the
|
||||
* header is not set, {@code null} is returned.
|
||||
*
|
||||
* @param pHeaderName the header name
|
||||
* @return an array of {@code String}s, or {@code null} if there is no
|
||||
* such header in this response.
|
||||
*/
|
||||
public String[] getHeaderValues(final String pHeaderName) {
|
||||
List<String> values = headers.get(pHeaderName);
|
||||
|
||||
return values == null ? null : values.toArray(new String[values.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first header value set for the given header in this response.
|
||||
* If the header is not set, {@code null} is returned.
|
||||
* Useful for headers that don't have multiple values, like
|
||||
* {@code "Content-Type"} or {@code "Content-Length"}.
|
||||
*
|
||||
* @param pHeaderName the header name
|
||||
* @return a {@code String}, or {@code null} if there is no
|
||||
* such header in this response.
|
||||
*/
|
||||
public String getHeaderValue(final String pHeaderName) {
|
||||
List<String> values = headers.get(pHeaderName);
|
||||
|
||||
return (values != null && values.size() > 0) ? values.get(0) : null;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
// content.size() is exact size in bytes, headersSize is an estimate
|
||||
return (content != null ? content.size() : 0) + headersSize;
|
||||
}
|
||||
|
||||
public boolean equals(final Object pOther) {
|
||||
if (this == pOther) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pOther instanceof CachedResponseImpl) {
|
||||
// "Fast"
|
||||
return equalsImpl((CachedResponseImpl) pOther);
|
||||
}
|
||||
else if (pOther instanceof CachedResponse) {
|
||||
// Slow
|
||||
return equalsGeneric((CachedResponse) pOther);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean equalsImpl(final CachedResponseImpl pOther) {
|
||||
return headersSize == pOther.headersSize &&
|
||||
(content == null ? pOther.content == null : content.equals(pOther.content)) &&
|
||||
headers.equals(pOther.headers);
|
||||
}
|
||||
|
||||
private boolean equalsGeneric(final CachedResponse pOther) {
|
||||
if (size() != pOther.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] headers = getHeaderNames();
|
||||
String[] otherHeaders = pOther.getHeaderNames();
|
||||
if (!Arrays.equals(headers, otherHeaders)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (headers != null) {
|
||||
for (String header : headers) {
|
||||
String[] values = getHeaderValues(header);
|
||||
String[] otherValues = pOther.getHeaderValues(header);
|
||||
|
||||
if (!Arrays.equals(values, otherValues)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = headers.hashCode();
|
||||
result = 29 * result + headersSize;
|
||||
result = 37 * result + (content != null ? content.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ClientCacheRequest
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: ClientCacheRequest.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public final class ClientCacheRequest extends AbstractCacheRequest {
|
||||
private Map<String, List<String>> parameters;
|
||||
private Map<String, List<String>> headers;
|
||||
|
||||
public ClientCacheRequest(final URI pRequestURI,final Map<String, List<String>> pParameters, final Map<String, List<String>> pHeaders) {
|
||||
super(pRequestURI, "GET"); // TODO: Consider supporting more than get? At least HEAD and OPTIONS...
|
||||
parameters = normalizeMap(pParameters);
|
||||
headers = normalizeMap(pHeaders);
|
||||
}
|
||||
|
||||
private <K, V> Map<K, V> normalizeMap(Map<K, V> pMap) {
|
||||
return pMap == null ? Collections.<K, V>emptyMap() : Collections.unmodifiableMap(pMap);
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return getRequestURI().getAuthority();
|
||||
}
|
||||
|
||||
public int getServerPort() {
|
||||
return getRequestURI().getPort();
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* ClientCacheResponse
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: ClientCacheResponse.java#2 $
|
||||
*/
|
||||
@Deprecated
|
||||
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 would be nice if we could bypass that...
|
||||
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
throw new UnsupportedOperationException("Method getOutputStream not implemented"); // TODO: Implement
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
throw new UnsupportedOperationException("Method getInputStream not implemented"); // TODO: Implement
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* ResponseResolver
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: ResponseResolver.java#2 $
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ResponseResolver {
|
||||
void resolve(CacheRequest pRequest, CacheResponse pResponse) throws IOException, CacheException;
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.net.HTTPUtil;
|
||||
import com.twelvemonkeys.servlet.ServletResponseStreamDelegate;
|
||||
|
||||
/**
|
||||
* CacheResponseWrapper class description.
|
||||
* <p>
|
||||
* Based on ideas and code found in the ONJava article
|
||||
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two
|
||||
* Servlet Filters Every Web Application Should Have</a>
|
||||
* by Jayson Falkner.
|
||||
* </p>
|
||||
*
|
||||
* @author Jayson Falkner
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: SerlvetCacheResponseWrapper.java#2 $
|
||||
*/
|
||||
@Deprecated
|
||||
class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
|
||||
private ServletResponseStreamDelegate streamDelegate;
|
||||
|
||||
private CacheResponse cacheResponse;
|
||||
|
||||
private Boolean cacheable;
|
||||
private int status;
|
||||
|
||||
public SerlvetCacheResponseWrapper(final HttpServletResponse pServletResponse, final CacheResponse pResponse) {
|
||||
super(pServletResponse);
|
||||
cacheResponse = pResponse;
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
NOTE: This class defers determining if a response is cacheable until the
|
||||
output stream is needed.
|
||||
This it the reason for the somewhat complicated logic in the add/setHeader
|
||||
methods below.
|
||||
*/
|
||||
private void init() {
|
||||
cacheable = null;
|
||||
status = SC_OK;
|
||||
streamDelegate = new ServletResponseStreamDelegate(this) {
|
||||
protected OutputStream createOutputStream() throws IOException {
|
||||
// Test if this request is really cacheable, otherwise,
|
||||
// just write through to underlying response, and don't cache
|
||||
if (isCacheable()) {
|
||||
return cacheResponse.getOutputStream();
|
||||
}
|
||||
else {
|
||||
// TODO: We need to tell the cache about this, somehow...
|
||||
writeHeaders(cacheResponse, (HttpServletResponse) getResponse());
|
||||
return super.getOutputStream();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void writeHeaders(final CacheResponse pResponse, final HttpServletResponse pServletResponse) {
|
||||
Map<String,List<String>> headers = pResponse.getHeaders();
|
||||
for (Map.Entry<String, List<String>> header : headers.entrySet()) {
|
||||
for (int i = 0; i < header.getValue().size(); i++) {
|
||||
String value = header.getValue().get(i);
|
||||
if (i == 0) {
|
||||
pServletResponse.setHeader(header.getKey(), value);
|
||||
}
|
||||
else {
|
||||
pServletResponse.addHeader(header.getKey(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCacheable() {
|
||||
// NOTE: Intentionally not synchronized
|
||||
if (cacheable == null) {
|
||||
cacheable = isCacheableImpl();
|
||||
}
|
||||
|
||||
return cacheable;
|
||||
}
|
||||
|
||||
private boolean isCacheableImpl() {
|
||||
// TODO: This code is duped in the cache...
|
||||
if (status != SC_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Vary: *
|
||||
List<String> values = cacheResponse.getHeaders().get(HTTPCache.HEADER_VARY);
|
||||
if (values != null) {
|
||||
for (String value : values) {
|
||||
if ("*".equals(value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cache-Control: no-cache, no-store, must-revalidate
|
||||
values = cacheResponse.getHeaders().get(HTTPCache.HEADER_CACHE_CONTROL);
|
||||
if (values != null) {
|
||||
for (String value : values) {
|
||||
if (StringUtil.contains(value, "no-cache")
|
||||
|| StringUtil.contains(value, "no-store")
|
||||
|| StringUtil.contains(value, "must-revalidate")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pragma: no-cache
|
||||
values = cacheResponse.getHeaders().get(HTTPCache.HEADER_PRAGMA);
|
||||
if (values != null) {
|
||||
for (String value : values) {
|
||||
if (StringUtil.contains(value, "no-cache")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void flushBuffer() throws IOException {
|
||||
streamDelegate.flushBuffer();
|
||||
}
|
||||
|
||||
public void resetBuffer() {
|
||||
// Servlet 2.3
|
||||
streamDelegate.resetBuffer();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.reset();
|
||||
}
|
||||
// No else, might be cacheable after all..
|
||||
init();
|
||||
}
|
||||
|
||||
public ServletOutputStream getOutputStream() throws IOException {
|
||||
return streamDelegate.getOutputStream();
|
||||
}
|
||||
|
||||
public PrintWriter getWriter() throws IOException {
|
||||
return streamDelegate.getWriter();
|
||||
}
|
||||
|
||||
public boolean containsHeader(String name) {
|
||||
return cacheResponse.getHeaders().get(name) != null;
|
||||
}
|
||||
|
||||
public void sendError(int pStatusCode, String msg) throws IOException {
|
||||
// NOT cacheable
|
||||
status = pStatusCode;
|
||||
super.sendError(pStatusCode, msg);
|
||||
}
|
||||
|
||||
public void sendError(int pStatusCode) throws IOException {
|
||||
// NOT cacheable
|
||||
status = pStatusCode;
|
||||
super.sendError(pStatusCode);
|
||||
}
|
||||
|
||||
public void setStatus(int pStatusCode, String sm) {
|
||||
// NOTE: This method is deprecated
|
||||
setStatus(pStatusCode);
|
||||
}
|
||||
|
||||
public void setStatus(int pStatusCode) {
|
||||
// NOT cacheable unless pStatusCode == 200 (or a FEW others?)
|
||||
if (pStatusCode != SC_OK) {
|
||||
status = pStatusCode;
|
||||
super.setStatus(pStatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendRedirect(String pLocation) throws IOException {
|
||||
// NOT cacheable
|
||||
status = SC_MOVED_TEMPORARILY;
|
||||
super.sendRedirect(pLocation);
|
||||
}
|
||||
|
||||
public void setDateHeader(String pName, long pValue) {
|
||||
// If in write-trough-mode, set headers directly
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.setDateHeader(pName, pValue);
|
||||
}
|
||||
cacheResponse.setHeader(pName, HTTPUtil.formatHTTPDate(pValue));
|
||||
}
|
||||
|
||||
public void addDateHeader(String pName, long pValue) {
|
||||
// If in write-trough-mode, set headers directly
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.addDateHeader(pName, pValue);
|
||||
}
|
||||
cacheResponse.addHeader(pName, HTTPUtil.formatHTTPDate(pValue));
|
||||
}
|
||||
|
||||
public void setHeader(String pName, String pValue) {
|
||||
// If in write-trough-mode, set headers directly
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.setHeader(pName, pValue);
|
||||
}
|
||||
cacheResponse.setHeader(pName, pValue);
|
||||
}
|
||||
|
||||
public void addHeader(String pName, String pValue) {
|
||||
// If in write-trough-mode, set headers directly
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.addHeader(pName, pValue);
|
||||
}
|
||||
cacheResponse.addHeader(pName, pValue);
|
||||
}
|
||||
|
||||
public void setIntHeader(String pName, int pValue) {
|
||||
// If in write-trough-mode, set headers directly
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.setIntHeader(pName, pValue);
|
||||
}
|
||||
cacheResponse.setHeader(pName, String.valueOf(pValue));
|
||||
}
|
||||
|
||||
public void addIntHeader(String pName, int pValue) {
|
||||
// If in write-trough-mode, set headers directly
|
||||
if (Boolean.FALSE.equals(cacheable)) {
|
||||
super.addIntHeader(pName, pValue);
|
||||
}
|
||||
cacheResponse.addHeader(pName, String.valueOf(pValue));
|
||||
}
|
||||
|
||||
public final void setContentType(String type) {
|
||||
setHeader(HTTPCache.HEADER_CONTENT_TYPE, type);
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.twelvemonkeys.servlet.ServletUtil;
|
||||
|
||||
/**
|
||||
* ServletCacheRequest
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: ServletCacheRequest.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public final class ServletCacheRequest extends AbstractCacheRequest {
|
||||
private final HttpServletRequest request;
|
||||
|
||||
private Map<String, List<String>> headers;
|
||||
private Map<String, List<String>> parameters;
|
||||
|
||||
protected ServletCacheRequest(final HttpServletRequest pRequest) {
|
||||
super(URI.create(pRequest.getRequestURI()), pRequest.getMethod());
|
||||
request = pRequest;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getHeaders() {
|
||||
if (headers == null) {
|
||||
headers = ServletUtil.headersAsMap(request);
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getParameters() {
|
||||
if (parameters == null) {
|
||||
parameters = ServletUtil.parametersAsMap(request);
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return request.getServerName();
|
||||
}
|
||||
|
||||
public int getServerPort() {
|
||||
return request.getServerPort();
|
||||
}
|
||||
|
||||
HttpServletRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* ServletResponseResolver
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: ServletResponseResolver.java#2 $
|
||||
*/
|
||||
@Deprecated
|
||||
final class ServletResponseResolver implements ResponseResolver {
|
||||
final private ServletCacheRequest request;
|
||||
final private ServletCacheResponse response;
|
||||
final private FilterChain chain;
|
||||
|
||||
ServletResponseResolver(final ServletCacheRequest pRequest, final ServletCacheResponse pResponse, final FilterChain pChain) {
|
||||
request = pRequest;
|
||||
response = pResponse;
|
||||
chain = pChain;
|
||||
}
|
||||
|
||||
public void resolve(final CacheRequest pRequest, final CacheResponse pResponse) throws IOException, CacheException {
|
||||
// Need only wrap if pResponse is not response...
|
||||
HttpServletResponse response = pResponse == this.response ? this.response.getResponse() : new SerlvetCacheResponseWrapper(this.response.getResponse(), pResponse);
|
||||
|
||||
try {
|
||||
chain.doFilter(request.getRequest(), response);
|
||||
}
|
||||
catch (ServletException e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
finally {
|
||||
response.flushBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* WritableCachedResponse
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: WritableCachedResponse.java#2 $
|
||||
*/
|
||||
@Deprecated
|
||||
public interface WritableCachedResponse extends CachedResponse, CacheResponse {
|
||||
/**
|
||||
* Gets the {@code OutputStream} for this cached response.
|
||||
* This allows a client to write to the cached response.
|
||||
*
|
||||
* @return the {@code OutputStream} for this response.
|
||||
*/
|
||||
OutputStream getOutputStream();
|
||||
|
||||
/**
|
||||
* Sets a header key/value pair for this response.
|
||||
* Any prior header value for the given header key will be overwritten.
|
||||
*
|
||||
* @see #addHeader(String, String)
|
||||
*
|
||||
* @param pName the header name
|
||||
* @param pValue the header value
|
||||
*/
|
||||
void setHeader(String pName, String pValue);
|
||||
|
||||
/**
|
||||
* Adds a header key/value pair for this response.
|
||||
* If a value allready exists for the given key, the value will be appended.
|
||||
*
|
||||
* @see #setHeader(String, String)
|
||||
*
|
||||
* @param pName the header name
|
||||
* @param pValue the header value
|
||||
*/
|
||||
void addHeader(String pName, String pValue);
|
||||
|
||||
/**
|
||||
* Returns the final (immutable) {@code CachedResponse} created by this
|
||||
* {@code WritableCachedResponse}.
|
||||
*
|
||||
* @return the {@code CachedResponse}
|
||||
*/
|
||||
CachedResponse getCachedResponse();
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||
import com.twelvemonkeys.net.HTTPUtil;
|
||||
|
||||
/**
|
||||
* WritableCachedResponseImpl
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: WritableCachedResponseImpl.java#3 $
|
||||
*/
|
||||
@Deprecated
|
||||
class WritableCachedResponseImpl implements WritableCachedResponse {
|
||||
private final CachedResponseImpl cachedResponse;
|
||||
|
||||
/**
|
||||
* Creates a {@code WritableCachedResponseImpl}.
|
||||
*/
|
||||
protected WritableCachedResponseImpl() {
|
||||
cachedResponse = new CachedResponseImpl();
|
||||
// Hmmm..
|
||||
setHeader(HTTPCache.HEADER_CACHED_TIME, HTTPUtil.formatHTTPDate(System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
public CachedResponse getCachedResponse() {
|
||||
return cachedResponse;
|
||||
}
|
||||
|
||||
public void setHeader(String pName, String pValue) {
|
||||
setHeader(pName, pValue, false);
|
||||
}
|
||||
|
||||
public void addHeader(String pName, String pValue) {
|
||||
setHeader(pName, pValue, true);
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getHeaders() {
|
||||
return cachedResponse.headers;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pName the header name
|
||||
* @param pValue the new header value
|
||||
* @param pAdd {@code true} if the value should add to the list of values, not replace existing value
|
||||
*/
|
||||
private void setHeader(String pName, String pValue, boolean pAdd) {
|
||||
// System.out.println(" ++ CachedResponse ++ " + (pAdd ? "addHeader(" : "setHeader(") + pName + ", " + pValue + ")");
|
||||
// If adding, get list and append, otherwise replace list
|
||||
List<String> values = pAdd ? cachedResponse.headers.get(pName) : null;
|
||||
|
||||
if (values == null) {
|
||||
values = new ArrayList<String>();
|
||||
|
||||
if (pAdd) {
|
||||
// Add length of pName
|
||||
cachedResponse.headersSize += (pName != null ? pName.length() : 0);
|
||||
}
|
||||
else {
|
||||
// Remove length of potential replaced old values + pName
|
||||
String[] oldValues = getHeaderValues(pName);
|
||||
|
||||
if (oldValues != null) {
|
||||
for (String oldValue : oldValues) {
|
||||
cachedResponse.headersSize -= oldValue.length();
|
||||
}
|
||||
}
|
||||
else {
|
||||
cachedResponse.headersSize += (pName != null ? pName.length() : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add value, if not null
|
||||
if (pValue != null) {
|
||||
values.add(pValue);
|
||||
|
||||
// Add length of pValue
|
||||
cachedResponse.headersSize += pValue.length();
|
||||
}
|
||||
|
||||
// Always add to headers
|
||||
cachedResponse.headers.put(pName, values);
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
// TODO: Hmm.. Smells like DCL..?
|
||||
if (cachedResponse.content == null) {
|
||||
createOutputStream();
|
||||
}
|
||||
return cachedResponse.content;
|
||||
}
|
||||
|
||||
public void setStatus(int pStatusCode) {
|
||||
cachedResponse.status = pStatusCode;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return cachedResponse.getStatus();
|
||||
}
|
||||
|
||||
private synchronized void createOutputStream() {
|
||||
ByteArrayOutputStream cache = cachedResponse.content;
|
||||
if (cache == null) {
|
||||
String contentLengthStr = getHeaderValue("Content-Length");
|
||||
if (contentLengthStr != null) {
|
||||
int contentLength = Integer.parseInt(contentLengthStr);
|
||||
cache = new FastByteArrayOutputStream(contentLength);
|
||||
}
|
||||
else {
|
||||
cache = new FastByteArrayOutputStream(1024);
|
||||
}
|
||||
cachedResponse.content = cache;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeHeadersTo(CacheResponse pResponse) {
|
||||
cachedResponse.writeHeadersTo(pResponse);
|
||||
}
|
||||
|
||||
public void writeContentsTo(OutputStream pStream) throws IOException {
|
||||
cachedResponse.writeContentsTo(pStream);
|
||||
}
|
||||
|
||||
public String[] getHeaderNames() {
|
||||
return cachedResponse.getHeaderNames();
|
||||
}
|
||||
|
||||
public String[] getHeaderValues(String pHeaderName) {
|
||||
return cachedResponse.getHeaderValues(pHeaderName);
|
||||
}
|
||||
|
||||
public String getHeaderValue(String pHeaderName) {
|
||||
return cachedResponse.getHeaderValue(pHeaderName);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return cachedResponse.size();
|
||||
}
|
||||
|
||||
public boolean equals(Object pOther) {
|
||||
if (pOther instanceof WritableCachedResponse) {
|
||||
// Take advantage of faster implementation
|
||||
return cachedResponse.equals(((WritableCachedResponse) pOther).getCachedResponse());
|
||||
}
|
||||
return cachedResponse.equals(pOther);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return cachedResponse.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
- Keep filter and servlet specific implementations in servlet module
|
||||
- Move most of the implementation out of servlet module (HTTPCache + interfaces + abstract impl)
|
||||
- Move client cache implementation classes out of servlet module, and to separate package
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.fileupload;
|
||||
|
||||
/**
|
||||
* FileSizeExceededException
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: FileSizeExceededException.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class FileSizeExceededException extends FileUploadException {
|
||||
public FileSizeExceededException(Throwable pCause) {
|
||||
super(pCause.getMessage(), pCause);
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.fileupload;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.twelvemonkeys.io.FileUtil;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.servlet.GenericFilter;
|
||||
import com.twelvemonkeys.servlet.ServletUtil;
|
||||
|
||||
/**
|
||||
* A servlet {@code Filter} for processing HTTP file upload requests, as
|
||||
* specified by
|
||||
* <a href="http://www.ietf.org/rfc/rfc1867.txt">Form-based File Upload in HTML (RFC1867)</a>.
|
||||
*
|
||||
* @see HttpFileUploadRequest
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: FileUploadFilter.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class FileUploadFilter extends GenericFilter {
|
||||
private File uploadDir;
|
||||
private long maxFileSize = 1024 * 1024; // 1 MByte
|
||||
|
||||
/**
|
||||
* This method is called by the server before the filter goes into service,
|
||||
* and here it determines the file upload directory.
|
||||
*
|
||||
* @throws ServletException
|
||||
*/
|
||||
public void init() throws ServletException {
|
||||
// Get the name of the upload directory.
|
||||
String uploadDirParam = getInitParameter("uploadDir");
|
||||
|
||||
if (!StringUtil.isEmpty(uploadDirParam)) {
|
||||
try {
|
||||
URL uploadDirURL = getServletContext().getResource(uploadDirParam);
|
||||
uploadDir = FileUtil.toFile(uploadDirURL);
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
throw new ServletException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
if (uploadDir == null) {
|
||||
uploadDir = ServletUtil.getTempDir(getServletContext());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets max filesize allowed for upload.
|
||||
* <!-- used by automagic init -->
|
||||
*
|
||||
* @param pMaxSize
|
||||
*/
|
||||
public void setMaxFileSize(long pMaxSize) {
|
||||
log("maxFileSize=" + pMaxSize);
|
||||
maxFileSize = pMaxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Examines the request content type, and if it is a
|
||||
* {@code multipart/*} request, wraps the request with a
|
||||
* {@code HttpFileUploadRequest}.
|
||||
*
|
||||
* @param pRequest The servlet request
|
||||
* @param pResponse The servlet response
|
||||
* @param pChain The filter chain
|
||||
*
|
||||
* @throws ServletException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||
HttpServletRequest request = (HttpServletRequest) pRequest;
|
||||
|
||||
// Get the content type from the request
|
||||
String contentType = request.getContentType();
|
||||
|
||||
// If the content type is multipart, wrap
|
||||
if (isMultipartFileUpload(contentType)) {
|
||||
pRequest = new HttpFileUploadRequestWrapper(request, uploadDir, maxFileSize);
|
||||
}
|
||||
|
||||
pChain.doFilter(pRequest, pResponse);
|
||||
}
|
||||
|
||||
private boolean isMultipartFileUpload(String pContentType) {
|
||||
return pContentType != null && pContentType.startsWith("multipart/");
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.fileupload;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* This interface represents an HTTP file upload request, as specified by
|
||||
* <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>
|
||||
* @version $Id: HttpFileUploadRequest.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public interface HttpFileUploadRequest extends HttpServletRequest {
|
||||
/**
|
||||
* Returns the value of a request parameter as an {@code UploadedFile},
|
||||
* or {@code null} if the parameter does not exist.
|
||||
* You should only use this method when you are sure the parameter has only
|
||||
* one value.
|
||||
*
|
||||
* @param pName the name of the requested parameter
|
||||
* @return a {@code UoploadedFile} or {@code null}
|
||||
*
|
||||
* @see #getUploadedFiles(String)
|
||||
*/
|
||||
UploadedFile getUploadedFile(String pName);
|
||||
|
||||
/**
|
||||
* Returns an array of {@code UploadedFile} objects containing all the
|
||||
* values for the given request parameter,
|
||||
* or {@code null} if the parameter does not exist.
|
||||
*
|
||||
* @param pName the name of the requested parameter
|
||||
* @return an array of {@code UoploadedFile}s or {@code null}
|
||||
*/
|
||||
UploadedFile[] getUploadedFiles(String pName);
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.fileupload;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.fileupload.FileUpload;
|
||||
import org.apache.commons.fileupload.FileUploadBase;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||
import org.apache.commons.fileupload.servlet.ServletRequestContext;
|
||||
|
||||
/**
|
||||
* An {@code HttpFileUploadRequest} implementation, based on
|
||||
* <a href="http://jakarta.apache.org/commons/fileupload/">Jakarta Commons FileUpload</a>.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: HttpFileUploadRequestWrapper.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements HttpFileUploadRequest {
|
||||
|
||||
private final Map<String, String[]> parameters = new HashMap<String, String[]>();
|
||||
private final Map<String, UploadedFile[]> files = new HashMap<String, UploadedFile[]>();
|
||||
|
||||
public HttpFileUploadRequestWrapper(HttpServletRequest pRequest, File pUploadDir, long pMaxSize) throws ServletException {
|
||||
super(pRequest);
|
||||
|
||||
DiskFileItemFactory factory = new DiskFileItemFactory(
|
||||
128 * 1024, // 128 KByte
|
||||
new File(pUploadDir.getAbsolutePath())
|
||||
);
|
||||
FileUpload upload = new FileUpload(factory);
|
||||
upload.setSizeMax(pMaxSize);
|
||||
|
||||
// TODO: Defer request parsing??
|
||||
try {
|
||||
//noinspection unchecked
|
||||
List<FileItem> items = upload.parseRequest(new ServletRequestContext(pRequest));
|
||||
for (FileItem item : items) {
|
||||
if (item.isFormField()) {
|
||||
processFormField(item.getFieldName(), item.getString());
|
||||
}
|
||||
else {
|
||||
processeFile(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileUploadBase.SizeLimitExceededException e) {
|
||||
throw new FileSizeExceededException(e);
|
||||
}
|
||||
catch (org.apache.commons.fileupload.FileUploadException e) {
|
||||
throw new FileUploadException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void processeFile(final FileItem pItem) {
|
||||
UploadedFile value = new UploadedFileImpl(pItem);
|
||||
String name = pItem.getFieldName();
|
||||
|
||||
UploadedFile[] values;
|
||||
UploadedFile[] oldValues = files.get(name);
|
||||
|
||||
if (oldValues != null) {
|
||||
values = new UploadedFile[oldValues.length + 1];
|
||||
System.arraycopy(oldValues, 0, values, 0, oldValues.length);
|
||||
values[oldValues.length] = value;
|
||||
}
|
||||
else {
|
||||
values = new UploadedFile[] {value};
|
||||
}
|
||||
|
||||
files.put(name, values);
|
||||
|
||||
// Also add to normal fields
|
||||
processFormField(name, value.getName());
|
||||
}
|
||||
|
||||
private void processFormField(String pName, String pValue) {
|
||||
// Multiple parameter values are not that common, so it's
|
||||
// probably faster to just use arrays...
|
||||
// TODO: Research and document...
|
||||
String[] values;
|
||||
String[] oldValues = parameters.get(pName);
|
||||
|
||||
if (oldValues != null) {
|
||||
values = new String[oldValues.length + 1];
|
||||
System.arraycopy(oldValues, 0, values, 0, oldValues.length);
|
||||
values[oldValues.length] = pValue;
|
||||
}
|
||||
else {
|
||||
values = new String[] {pValue};
|
||||
}
|
||||
|
||||
parameters.put(pName, values);
|
||||
}
|
||||
|
||||
public Map getParameterMap() {
|
||||
// TODO: The spec dicates immutable map, but what about the value arrays?!
|
||||
// Probably just leave as-is, for performance
|
||||
return Collections.unmodifiableMap(parameters);
|
||||
}
|
||||
|
||||
public Enumeration getParameterNames() {
|
||||
return Collections.enumeration(parameters.keySet());
|
||||
}
|
||||
|
||||
public String getParameter(String pString) {
|
||||
String[] values = getParameterValues(pString);
|
||||
return values != null ? values[0] : null;
|
||||
}
|
||||
|
||||
public String[] getParameterValues(String pString) {
|
||||
// TODO: Optimize?
|
||||
return parameters.get(pString).clone();
|
||||
}
|
||||
|
||||
public UploadedFile getUploadedFile(String pName) {
|
||||
UploadedFile[] files = getUploadedFiles(pName);
|
||||
return files != null ? files[0] : null;
|
||||
}
|
||||
|
||||
public UploadedFile[] getUploadedFiles(String pName) {
|
||||
// TODO: Optimize?
|
||||
return files.get(pName).clone();
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.fileupload;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* This class represents an uploaded file.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: UploadedFile.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public interface UploadedFile {
|
||||
/**
|
||||
* Returns the length of file, in bytes.
|
||||
*
|
||||
* @return length of file
|
||||
*/
|
||||
long length();
|
||||
|
||||
/**
|
||||
* Returns the original file name (from client).
|
||||
*
|
||||
* @return original name
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns the content type of the file.
|
||||
*
|
||||
* @return the content type
|
||||
*/
|
||||
String getContentType();
|
||||
|
||||
/**
|
||||
* Returns the file data, as an {@code InputStream}.
|
||||
* The file data may be read from disk, or from an in-memory source,
|
||||
* depending on implementation.
|
||||
*
|
||||
* @return an {@code InputStream} containing the file data
|
||||
* @throws IOException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
InputStream getInputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* Writes the file data to the given {@code File}.
|
||||
* Note that implementations are free to optimize this to a rename
|
||||
* operation, if the file is allready cached to disk.
|
||||
*
|
||||
* @param pFile the {@code File} (file name) to write to.
|
||||
* @throws IOException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
void writeTo(File pFile) throws IOException;
|
||||
|
||||
// TODO: void delete()?
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.fileupload;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.fileupload.FileUploadException;
|
||||
|
||||
/**
|
||||
* An {@code UploadedFile} implementation, based on
|
||||
* <a href="http://jakarta.apache.org/commons/fileupload/">Jakarta Commons FileUpload</a>.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: UploadedFileImpl.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
class UploadedFileImpl implements UploadedFile {
|
||||
private final FileItem item;
|
||||
|
||||
public UploadedFileImpl(FileItem pItem) {
|
||||
if (pItem == null) {
|
||||
throw new IllegalArgumentException("fileitem == null");
|
||||
}
|
||||
|
||||
item = pItem;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return item.getContentType();
|
||||
}
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return item.getInputStream();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return item.getName();
|
||||
}
|
||||
|
||||
public long length() {
|
||||
return item.getSize();
|
||||
}
|
||||
|
||||
public void writeTo(File pFile) throws IOException {
|
||||
try {
|
||||
item.write(pFile);
|
||||
}
|
||||
catch(RuntimeException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (FileUploadException e) {
|
||||
// We deliberately change this exception to an IOException, as it really is
|
||||
throw (IOException) new IOException(e.getMessage()).initCause(e);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Should not really happen, ever
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.gzip;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.twelvemonkeys.servlet.GenericFilter;
|
||||
|
||||
/**
|
||||
* A filter to reduce the output size of web resources.
|
||||
* <p>
|
||||
* The HTTP protocol supports compression of the content to reduce network
|
||||
* bandwidth. The important headers involved, are the {@code Accept-Encoding}
|
||||
* request header, and the {@code Content-Encoding} response header.
|
||||
* This feature can be used to further reduce the number of bytes transferred
|
||||
* over the network, at the cost of some extra processing time at both endpoints.
|
||||
* Most modern browsers supports compression in GZIP format, which is fairly
|
||||
* efficient in cost/compression ratio.
|
||||
* </p>
|
||||
* <p>
|
||||
* The filter tests for the presence of an {@code Accept-Encoding} header with a
|
||||
* value of {@code "gzip"} (several different encoding header values are
|
||||
* possible in one header). If not present, the filter simply passes the
|
||||
* request/response pair through, leaving it untouched. If present, the
|
||||
* {@code Content-Encoding} header is set, with the value {@code "gzip"},
|
||||
* and the response is wrapped.
|
||||
* The response output stream is wrapped in a
|
||||
* {@link java.util.zip.GZIPOutputStream} which performs the GZIP encoding.
|
||||
* For efficiency, the filter does not buffer the response, but writes through
|
||||
* the gzipped output stream.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Configuration</b>
|
||||
* <br>
|
||||
* To use {@code GZIPFilter} in your web-application, you simply need to add it
|
||||
* to your web descriptor ({@code web.xml}). If using a servlet container that
|
||||
* supports the Servlet 2.4 spec, the new {@code dispatcher} element should be
|
||||
* used, and set to {@code REQUEST/FORWARD}, to make sure the filter is invoked
|
||||
* only once for requests.
|
||||
* If using an older web descriptor, set the {@code init-param}
|
||||
* {@code "once-per-request"} to {@code "true"} (this will have the same effect,
|
||||
* but might perform slightly worse than the 2.4 version).
|
||||
* Please see the examples below.
|
||||
* <b>Servlet 2.4 version, filter section:</b>
|
||||
* </p>
|
||||
* <br>
|
||||
* <pre>
|
||||
* <!-- GZIP Filter Configuration -->
|
||||
* <filter>
|
||||
* <filter-name>gzip</filter-name>
|
||||
* <filter-class>com.twelvemonkeys.servlet.GZIPFilter</filter-class>
|
||||
* </filter>
|
||||
* </pre>
|
||||
* <b>Filter-mapping section:</b>
|
||||
* <br>
|
||||
* <pre>
|
||||
* <!-- GZIP Filter Mapping -->
|
||||
* <filter-mapping>
|
||||
* <filter-name>gzip</filter-name>
|
||||
* <url-pattern>*.html</url-pattern>
|
||||
* <dispatcher>REQUEST</dispatcher>
|
||||
* <dispatcher>FORWARD</dispatcher>
|
||||
* </filter-mapping>
|
||||
* <filter-mapping>
|
||||
* <filter-name>gzip</filter-name>
|
||||
* <url-pattern>*.jsp< /url-pattern>
|
||||
* <dispatcher>REQUEST</dispatcher>
|
||||
* <dispatcher>FORWARD</dispatcher>
|
||||
* </filter-mapping>
|
||||
* </pre>
|
||||
* <p>
|
||||
* Based on ideas and code found in the ONJava article
|
||||
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two
|
||||
* Servlet Filters Every Web Application Should Have</a>
|
||||
* by Jayson Falkner.
|
||||
* </p>
|
||||
*
|
||||
* @author Jayson Falkner
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: GZIPFilter.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class GZIPFilter extends GenericFilter {
|
||||
|
||||
{
|
||||
oncePerRequest = true;
|
||||
}
|
||||
|
||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||
// Can only filter HTTP responses
|
||||
if (pRequest instanceof HttpServletRequest) {
|
||||
HttpServletRequest request = (HttpServletRequest) pRequest;
|
||||
HttpServletResponse response = (HttpServletResponse) pResponse;
|
||||
|
||||
// If GZIP is supported, use compression
|
||||
String accept = request.getHeader("Accept-Encoding");
|
||||
if (accept != null && accept.contains("gzip")) {
|
||||
//System.out.println("GZIP supported, compressing.");
|
||||
GZIPResponseWrapper wrapped = new GZIPResponseWrapper(response);
|
||||
|
||||
try {
|
||||
pChain.doFilter(pRequest, wrapped);
|
||||
}
|
||||
finally {
|
||||
wrapped.flushResponse();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Else, continue chain
|
||||
pChain.doFilter(pRequest, pResponse);
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.gzip;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import com.twelvemonkeys.servlet.OutputStreamAdapter;
|
||||
|
||||
/**
|
||||
* GZIPResponseWrapper class description.
|
||||
* <p>
|
||||
* Based on ideas and code found in the ONJava article
|
||||
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two Servlet Filters Every Web Application Should Have</a>
|
||||
* by Jayson Falkner.
|
||||
* </p>
|
||||
*
|
||||
* @author Jayson Falkner
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: GZIPResponseWrapper.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class GZIPResponseWrapper extends HttpServletResponseWrapper {
|
||||
// TODO: Remove/update ETags if needed? Read the spec (RFC 2616) on Vary/ETag for caching
|
||||
|
||||
protected ServletOutputStream out;
|
||||
protected PrintWriter writer;
|
||||
protected GZIPOutputStream gzipOut;
|
||||
protected int contentLength = -1;
|
||||
|
||||
public GZIPResponseWrapper(final HttpServletResponse response) {
|
||||
super(response);
|
||||
|
||||
response.addHeader("Content-Encoding", "gzip");
|
||||
response.addHeader("Vary", "Accept");
|
||||
}
|
||||
|
||||
public ServletOutputStream createOutputStream() throws IOException {
|
||||
// FIX: Write directly to servlet output stream, for faster responses.
|
||||
// Relies on chunked streams, or buffering in the servlet engine.
|
||||
if (contentLength >= 0) {
|
||||
gzipOut = new GZIPOutputStream(getResponse().getOutputStream(), contentLength);
|
||||
}
|
||||
else {
|
||||
gzipOut = new GZIPOutputStream(getResponse().getOutputStream());
|
||||
}
|
||||
|
||||
// Wrap in ServletOutputStream and return
|
||||
return new OutputStreamAdapter(gzipOut);
|
||||
}
|
||||
|
||||
// TODO: Move this to flushbuffer or something? Hmmm..
|
||||
public void flushResponse() throws IOException {
|
||||
try {
|
||||
// Finish GZIP encodig
|
||||
if (gzipOut != null) {
|
||||
gzipOut.finish();
|
||||
}
|
||||
|
||||
flushBuffer();
|
||||
}
|
||||
finally {
|
||||
// Close stream
|
||||
if (writer != null) {
|
||||
writer.close();
|
||||
}
|
||||
else {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void flushBuffer() throws IOException {
|
||||
if (writer != null) {
|
||||
writer.flush();
|
||||
}
|
||||
else if (out != null) {
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public ServletOutputStream getOutputStream() throws IOException {
|
||||
if (writer != null) {
|
||||
throw new IllegalStateException("getWriter() has already been called!");
|
||||
}
|
||||
|
||||
if (out == null) {
|
||||
out = createOutputStream();
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
public PrintWriter getWriter() throws IOException {
|
||||
if (writer != null) {
|
||||
return (writer);
|
||||
}
|
||||
|
||||
if (out != null) {
|
||||
throw new IllegalStateException("getOutputStream() has already been called!");
|
||||
}
|
||||
|
||||
out = createOutputStream();
|
||||
|
||||
// TODO: This is wrong. Should use getCharacterEncoding() or "ISO-8859-1" if getCE returns null.
|
||||
writer = new PrintWriter(new OutputStreamWriter(out, "UTF-8"));
|
||||
|
||||
return writer;
|
||||
}
|
||||
|
||||
public void setContentLength(int pLength) {
|
||||
// NOTE: Do not call super, as we will shrink the size.
|
||||
contentLength = pLength;
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
|
||||
/**
|
||||
* AWTImageFilterAdapter
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: AWTImageFilterAdapter.java#1 $
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public class AWTImageFilterAdapter extends ImageFilter {
|
||||
|
||||
private java.awt.image.ImageFilter imageFilter = null;
|
||||
|
||||
public void setImageFilter(String pFilterClass) {
|
||||
try {
|
||||
Class filterClass = Class.forName(pFilterClass);
|
||||
imageFilter = (java.awt.image.ImageFilter) filterClass.newInstance();
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
log("Could not load filter class.", e);
|
||||
}
|
||||
catch (InstantiationException e) {
|
||||
log("Could not instantiate filter.", e);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
log("Could not access filter class.", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||
// Filter
|
||||
Image img = ImageUtil.filter(pImage, imageFilter);
|
||||
|
||||
// Create BufferedImage & return
|
||||
return ImageUtil.toBuffered(img, BufferedImage.TYPE_INT_RGB); // TODO: This is ok for JPEG only...
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
import java.awt.image.RenderedImage;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
/**
|
||||
* BufferedImageOpAdapter
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: BufferedImageOpAdapter.java#1 $
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public class BufferedImageOpAdapter extends ImageFilter {
|
||||
|
||||
private BufferedImageOp filter = null;
|
||||
|
||||
public void setImageFilter(String pFilterClass) {
|
||||
try {
|
||||
Class filterClass = Class.forName(pFilterClass);
|
||||
filter = (BufferedImageOp) filterClass.newInstance();
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
log("Could not instantiate filter class.", e);
|
||||
}
|
||||
catch (InstantiationException e) {
|
||||
log("Could not instantiate filter.", e);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
log("Could not access filter class.", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||
// Filter & return
|
||||
return filter.filter(pImage, null);
|
||||
}
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import com.twelvemonkeys.servlet.GenericServlet;
|
||||
|
||||
/**
|
||||
* Creates a minimal 1 x 1 pixel PNG image, in a color specified by the
|
||||
* {@code "color"} parameter. The color is HTML-style #RRGGBB, with two
|
||||
* digits hex number for red, green and blue (the hash, '#', is optional).
|
||||
* <p>
|
||||
* The class does only byte manipulation, there is no server-side image
|
||||
* processing involving AWT ({@code Toolkit} class) of any kind.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: ColorServlet.java#2 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class ColorServlet extends GenericServlet {
|
||||
private final static String RGB_PARAME = "color";
|
||||
|
||||
// A minimal, one color indexed PNG
|
||||
private final static byte[] PNG_IMG = new byte[]{
|
||||
(byte) 0x89, (byte) 'P', (byte) 'N', (byte) 'G', // PNG signature (8 bytes)
|
||||
0x0d, 0x0a, 0x1a, 0x0a,
|
||||
|
||||
0x00, 0x00, 0x00, 0x0d, // IHDR length (13)
|
||||
(byte) 'I', (byte) 'H', (byte) 'D', (byte) 'R', // Image header
|
||||
0x00, 0x00, 0x00, 0x01, // width
|
||||
0x00, 0x00, 0x00, 0x01, // height
|
||||
0x01, 0x03, 0x00, 0x00, 0x00, // bits, color type, compression, filter, interlace
|
||||
0x25, (byte) 0xdb, 0x56, (byte) 0xca, // IHDR CRC
|
||||
|
||||
0x00, 0x00, 0x00, 0x03, // PLTE length (3)
|
||||
(byte) 'P', (byte) 'L', (byte) 'T', (byte) 'E', // Palette
|
||||
0x00, 0x00, (byte) 0xff, // red, green, blue (updated by this servlet)
|
||||
(byte) 0x8a, (byte) 0x78, (byte) 0xd2, 0x57, // PLTE CRC
|
||||
|
||||
0x00, 0x00, 0x00, 0x0a, // IDAT length (10)
|
||||
(byte) 'I', (byte) 'D', (byte) 'A', (byte) 'T', // Image data
|
||||
0x78, (byte) 0xda, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,
|
||||
(byte) 0xe5, 0x27, (byte) 0xde, (byte) 0xfc, // IDAT CRC
|
||||
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, // IEND length (0)
|
||||
(byte) 'I', (byte) 'E', (byte) 'N', (byte) 'D', // Image end
|
||||
(byte) 0xae, (byte) 0x42, (byte) 0x60, (byte) 0x82 // IEND CRC
|
||||
};
|
||||
|
||||
private final static int PLTE_CHUNK_START = 37; // after chunk length
|
||||
private final static int PLTE_CHUNK_LENGTH = 7; // chunk name & data
|
||||
|
||||
private final static int RED_IDX = 4;
|
||||
private final static int GREEN_IDX = RED_IDX + 1;
|
||||
private final static int BLUE_IDX = GREEN_IDX + 1;
|
||||
|
||||
private final CRC32 crc = new CRC32();
|
||||
|
||||
/**
|
||||
* Creates a ColorDroplet.
|
||||
*/
|
||||
public ColorServlet() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the 1 x 1 single color PNG to the response.
|
||||
*
|
||||
* @see ColorServlet class description
|
||||
*
|
||||
* @param pRequest the request
|
||||
* @param pResponse the response
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
public void service(ServletRequest pRequest, ServletResponse pResponse) throws IOException, ServletException {
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
int blue = 0;
|
||||
|
||||
// Get color parameter and parse color
|
||||
String rgb = pRequest.getParameter(RGB_PARAME);
|
||||
if (rgb != null && rgb.length() >= 6 && rgb.length() <= 7) {
|
||||
int index = 0;
|
||||
|
||||
// If the hash ('#') character is included, skip it.
|
||||
if (rgb.length() == 7) {
|
||||
index++;
|
||||
}
|
||||
|
||||
try {
|
||||
// Two digit hex for each color
|
||||
String r = rgb.substring(index, index += 2);
|
||||
red = Integer.parseInt(r, 0x10);
|
||||
|
||||
String g = rgb.substring(index, index += 2);
|
||||
green = Integer.parseInt(g, 0x10);
|
||||
|
||||
String b = rgb.substring(index, index += 2);
|
||||
blue = Integer.parseInt(b, 0x10);
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
log("Wrong color format for ColorDroplet: " + rgb + ". Must be RRGGBB.");
|
||||
}
|
||||
}
|
||||
|
||||
// Set MIME type for PNG
|
||||
pResponse.setContentType("image/png");
|
||||
ServletOutputStream out = pResponse.getOutputStream();
|
||||
|
||||
try {
|
||||
// Write header (and palette chunk length)
|
||||
out.write(PNG_IMG, 0, PLTE_CHUNK_START);
|
||||
|
||||
// Create palette chunk, excl lenght, and write
|
||||
byte[] palette = makePalette(red, green, blue);
|
||||
out.write(palette);
|
||||
|
||||
// Write image data until end
|
||||
int pos = PLTE_CHUNK_START + PLTE_CHUNK_LENGTH + 4;
|
||||
out.write(PNG_IMG, pos, PNG_IMG.length - pos);
|
||||
}
|
||||
finally {
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the CRC for a byte array. Note that the byte array must be at
|
||||
* least {@code pOff + pLen + 4} bytes long, as the CRC is stored in the
|
||||
* 4 last bytes.
|
||||
*
|
||||
* @param pBytes the bytes to create CRC for
|
||||
* @param pOff the offset into the byte array to create CRC for
|
||||
* @param pLen the length of the byte array to create CRC for
|
||||
*/
|
||||
private void updateCRC(byte[] pBytes, int pOff, int pLen) {
|
||||
int value;
|
||||
|
||||
synchronized (crc) {
|
||||
crc.reset();
|
||||
crc.update(pBytes, pOff, pLen);
|
||||
value = (int) crc.getValue();
|
||||
}
|
||||
|
||||
pBytes[pOff + pLen ] = (byte) ((value >> 24) & 0xff);
|
||||
pBytes[pOff + pLen + 1] = (byte) ((value >> 16) & 0xff);
|
||||
pBytes[pOff + pLen + 2] = (byte) ((value >> 8) & 0xff);
|
||||
pBytes[pOff + pLen + 3] = (byte) ( value & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PNG palette (PLTE) chunk with one color.
|
||||
* The palette chunk data is always 3 bytes in length (one byte per color
|
||||
* component).
|
||||
* The returned byte array is then {@code 4 + 3 + 4 = 11} bytes,
|
||||
* including chunk header, data and CRC.
|
||||
*
|
||||
* @param pRed the red component
|
||||
* @param pGreen the reen component
|
||||
* @param pBlue the blue component
|
||||
*
|
||||
* @return the bytes for the PLTE chunk, including CRC (but not length)
|
||||
*/
|
||||
private byte[] makePalette(int pRed, int pGreen, int pBlue) {
|
||||
byte[] palette = new byte[PLTE_CHUNK_LENGTH + 4];
|
||||
System.arraycopy(PNG_IMG, PLTE_CHUNK_START, palette, 0, PLTE_CHUNK_LENGTH);
|
||||
|
||||
palette[RED_IDX] = (byte) pRed;
|
||||
palette[GREEN_IDX] = (byte) pGreen;
|
||||
palette[BLUE_IDX] = (byte) pBlue;
|
||||
|
||||
updateCRC(palette, 0, PLTE_CHUNK_LENGTH);
|
||||
|
||||
return palette;
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
/**
|
||||
* ComposeFilter
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: ComposeFilter.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class ComposeFilter extends ImageFilter {
|
||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) throws IOException {
|
||||
// 1. Load different image, locally (using ServletContext.getResource)
|
||||
// - Allow loading other filtered sources, or servlets? For example to
|
||||
// apply filename or timestamps?
|
||||
// - Allow applying text directly? Variables?
|
||||
// 2. Apply transformations from config
|
||||
// - Relative positioning
|
||||
// - Relative scaling
|
||||
// - Repeat (fill-pattern)?
|
||||
// - Rotation?
|
||||
// - Transparency?
|
||||
// - Background or foreground (layers)?
|
||||
// 3. Apply loaded image to original image (or vice versa?).
|
||||
return pImage;
|
||||
}
|
||||
}
|
||||
@@ -1,443 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
/**
|
||||
* This filter implements server side content negotiation and transcoding for
|
||||
* images.
|
||||
**
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: ContentNegotiationFilter.java#1 $
|
||||
*/
|
||||
// TODO: Add support for automatic recognition of known browsers, to avoid
|
||||
// unneccessary conversion (as IE supports PNG, the latests FireFox supports
|
||||
// JPEG and GIF, etc. even though they both don't explicitly list these formats
|
||||
// in their Accept headers).
|
||||
@Deprecated
|
||||
public class ContentNegotiationFilter extends ImageFilter {
|
||||
|
||||
private final static String MIME_TYPE_IMAGE_PREFIX = "image/";
|
||||
private static final String MIME_TYPE_IMAGE_ANY = MIME_TYPE_IMAGE_PREFIX + "*";
|
||||
private static final String MIME_TYPE_ANY = "*/*";
|
||||
private static final String HTTP_HEADER_ACCEPT = "Accept";
|
||||
private static final String HTTP_HEADER_VARY = "Vary";
|
||||
protected static final String HTTP_HEADER_USER_AGENT = "User-Agent";
|
||||
|
||||
private static final String FORMAT_JPEG = "image/jpeg";
|
||||
private static final String FORMAT_WBMP = "image/wbmp";
|
||||
private static final String FORMAT_GIF = "image/gif";
|
||||
private static final String FORMAT_PNG = "image/png";
|
||||
|
||||
private final static String[] sKnownFormats = new String[] {
|
||||
FORMAT_JPEG, FORMAT_PNG, FORMAT_GIF, FORMAT_WBMP
|
||||
};
|
||||
private float[] knownFormatQuality = new float[] {
|
||||
1f, 1f, 0.99f, 0.5f
|
||||
};
|
||||
|
||||
private HashMap<String, Float> formatQuality; // HashMap, as I need to clone this for each request
|
||||
private final Object lock = new Object();
|
||||
|
||||
/*
|
||||
private Pattern[] mKnownAgentPatterns;
|
||||
private String[] mKnownAgentAccpets;
|
||||
*/
|
||||
{
|
||||
// Hack: Make sure the filter don't trigger all the time
|
||||
// See: super.trigger(ServletRequest)
|
||||
triggerParams = new String[] {};
|
||||
}
|
||||
|
||||
/*
|
||||
public void setAcceptMappings(String pPropertiesFile) {
|
||||
// NOTE: Supposed to be:
|
||||
// <agent-name>=<reg-exp>
|
||||
// <agent-name>.accept=<http-accept-header>
|
||||
|
||||
Properties mappings = new Properties();
|
||||
try {
|
||||
mappings.load(getServletContext().getResourceAsStream(pPropertiesFile));
|
||||
|
||||
List patterns = new ArrayList();
|
||||
List accepts = new ArrayList();
|
||||
|
||||
for (Iterator iterator = mappings.keySet().iterator(); iterator.hasNext();) {
|
||||
String agent = (String) iterator.next();
|
||||
if (agent.endsWith(".accept")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
patterns.add(Pattern.compile((String) mappings.get(agent)));
|
||||
|
||||
// TODO: Consider preparsing ACCEPT header??
|
||||
accepts.add(mappings.get(agent + ".accept"));
|
||||
}
|
||||
catch (PatternSyntaxException e) {
|
||||
log("Could not parse User-Agent identification for " + agent, e);
|
||||
}
|
||||
|
||||
mKnownAgentPatterns = (Pattern[]) patterns.toArray(new Pattern[patterns.size()]);
|
||||
mKnownAgentAccpets = (String[]) accepts.toArray(new String[accepts.size()]);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log("Could not read accetp-mappings properties file: " + pPropertiesFile, e);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||
// NOTE: super invokes trigger() and image specific doFilter() if needed
|
||||
super.doFilterImpl(pRequest, pResponse, pChain);
|
||||
|
||||
if (pResponse instanceof HttpServletResponse) {
|
||||
// Update the Vary HTTP header field
|
||||
((HttpServletResponse) pResponse).addHeader(HTTP_HEADER_VARY, HTTP_HEADER_ACCEPT);
|
||||
//((HttpServletResponse) pResponse).addHeader(HTTP_HEADER_VARY, HTTP_HEADER_USER_AGENT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure the filter triggers for unknown file formats.
|
||||
*
|
||||
* @param pRequest the request
|
||||
* @return {@code true} if the filter should execute, {@code false}
|
||||
* otherwise
|
||||
*/
|
||||
protected boolean trigger(ServletRequest pRequest) {
|
||||
boolean trigger = false;
|
||||
|
||||
if (pRequest instanceof HttpServletRequest) {
|
||||
HttpServletRequest request = (HttpServletRequest) pRequest;
|
||||
String accept = getAcceptedFormats(request);
|
||||
String originalFormat = getServletContext().getMimeType(request.getRequestURI());
|
||||
|
||||
//System.out.println("Accept: " + accept);
|
||||
//System.out.println("Original format: " + originalFormat);
|
||||
|
||||
// Only override original format if it is not accpeted by the client
|
||||
// Note: Only explicit matches are okay, */* or image/* is not.
|
||||
if (!StringUtil.contains(accept, originalFormat)) {
|
||||
trigger = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Call super, to allow content negotiation even though format is supported
|
||||
return trigger || super.trigger(pRequest);
|
||||
}
|
||||
|
||||
private String getAcceptedFormats(HttpServletRequest pRequest) {
|
||||
return pRequest.getHeader(HTTP_HEADER_ACCEPT);
|
||||
}
|
||||
|
||||
/*
|
||||
private String getAcceptedFormats(HttpServletRequest pRequest) {
|
||||
String accept = pRequest.getHeader(HTTP_HEADER_ACCEPT);
|
||||
|
||||
// Check if User-Agent is in list of known agents
|
||||
if (mKnownAgentPatterns != null) {
|
||||
String agent = pRequest.getHeader(HTTP_HEADER_USER_AGENT);
|
||||
for (int i = 0; i < mKnownAgentPatterns.length; i++) {
|
||||
Pattern pattern = mKnownAgentPatterns[i];
|
||||
if (pattern.matcher(agent).matches()) {
|
||||
// Merge known with real accpet, in case plugins add extra capabilities
|
||||
accept = mergeAccept(mKnownAgentAccpets[i], accept);
|
||||
System.out.println("--> User-Agent: " + agent + " accepts: " + accept);
|
||||
return accept;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("No agent match, defaulting to Accept header: " + accept);
|
||||
return accept;
|
||||
}
|
||||
|
||||
private String mergeAccept(String pKnown, String pAccept) {
|
||||
// TODO: Make sure there are no duplicates...
|
||||
return pKnown + ", " + pAccept;
|
||||
}
|
||||
*/
|
||||
|
||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) throws IOException {
|
||||
if (pRequest instanceof HttpServletRequest) {
|
||||
HttpServletRequest request = (HttpServletRequest) pRequest;
|
||||
|
||||
Map<String, Float> formatQuality = getFormatQualityMapping();
|
||||
|
||||
// TODO: Consider adding original format, and use as fallback in worst case?
|
||||
// TODO: Original format should have some boost, to avoid unneccesary convertsion?
|
||||
|
||||
// Update source quality settings from image properties
|
||||
adjustQualityFromImage(formatQuality, pImage);
|
||||
//System.out.println("Source quality mapping: " + formatQuality);
|
||||
|
||||
adjustQualityFromAccept(formatQuality, request);
|
||||
//System.out.println("Final media scores: " + formatQuality);
|
||||
|
||||
// Find the formats with the highest quality factor, and use the first (predictable)
|
||||
String acceptable = findBestFormat(formatQuality);
|
||||
|
||||
//System.out.println("Acceptable: " + acceptable);
|
||||
|
||||
// Send HTTP 406 Not Acceptable
|
||||
if (acceptable == null) {
|
||||
if (pResponse instanceof HttpServletResponse) {
|
||||
((HttpServletResponse) pResponse).sendError(HttpURLConnection.HTTP_NOT_ACCEPTABLE);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
// TODO: Only if the format was changed!
|
||||
// Let other filters/caches/proxies know we changed the image
|
||||
}
|
||||
|
||||
// Set format
|
||||
pResponse.setOutputContentType(acceptable);
|
||||
//System.out.println("Set format: " + acceptable);
|
||||
}
|
||||
|
||||
return pImage;
|
||||
}
|
||||
|
||||
private Map<String, Float> getFormatQualityMapping() {
|
||||
synchronized(lock) {
|
||||
if (formatQuality == null) {
|
||||
formatQuality = new HashMap<String, Float>();
|
||||
|
||||
// Use ImageIO to find formats we can actually write
|
||||
String[] formats = ImageIO.getWriterMIMETypes();
|
||||
|
||||
// All known formats qs are initially 1.0
|
||||
// Others should be 0.1 or something like that...
|
||||
for (String format : formats) {
|
||||
formatQuality.put(format, getKnownFormatQuality(format));
|
||||
}
|
||||
}
|
||||
}
|
||||
//noinspection unchecked
|
||||
return (Map<String, Float>) formatQuality.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the best available format.
|
||||
*
|
||||
* @param pFormatQuality the format to quality mapping
|
||||
* @return the mime type of the best available format
|
||||
*/
|
||||
private static String findBestFormat(Map<String, Float> pFormatQuality) {
|
||||
String acceptable = null;
|
||||
float acceptQuality = 0.0f;
|
||||
for (Map.Entry<String, Float> entry : pFormatQuality.entrySet()) {
|
||||
float qValue = entry.getValue();
|
||||
if (qValue > acceptQuality) {
|
||||
acceptQuality = qValue;
|
||||
acceptable = entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
//System.out.println("Accepted format: " + acceptable);
|
||||
//System.out.println("Accepted quality: " + acceptQuality);
|
||||
return acceptable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust quality from HTTP Accept header
|
||||
*
|
||||
* @param pFormatQuality the format to quality mapping
|
||||
* @param pRequest the request
|
||||
*/
|
||||
private void adjustQualityFromAccept(Map<String, Float> pFormatQuality, HttpServletRequest pRequest) {
|
||||
// Multiply all q factors with qs factors
|
||||
// No q=.. should be interpreted as q=1.0
|
||||
|
||||
// Apache does some extras; if both explicit types and wildcards
|
||||
// (without qaulity factor) are present, */* is interpreted as
|
||||
// */*;q=0.01 and image/* is interpreted as image/*;q=0.02
|
||||
// See: http://httpd.apache.org/docs-2.0/content-negotiation.html
|
||||
|
||||
String accept = getAcceptedFormats(pRequest);
|
||||
//System.out.println("Accept: " + accept);
|
||||
|
||||
float anyImageFactor = getQualityFactor(accept, MIME_TYPE_IMAGE_ANY);
|
||||
anyImageFactor = (anyImageFactor == 1) ? 0.02f : anyImageFactor;
|
||||
|
||||
float anyFactor = getQualityFactor(accept, MIME_TYPE_ANY);
|
||||
anyFactor = (anyFactor == 1) ? 0.01f : anyFactor;
|
||||
|
||||
for (String format : pFormatQuality.keySet()) {
|
||||
//System.out.println("Trying format: " + format);
|
||||
|
||||
String formatMIME = MIME_TYPE_IMAGE_PREFIX + format;
|
||||
float qFactor = getQualityFactor(accept, formatMIME);
|
||||
qFactor = (qFactor == 0f) ? Math.max(anyFactor, anyImageFactor) : qFactor;
|
||||
adjustQuality(pFormatQuality, format, qFactor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pAccept the accpet header value
|
||||
* @param pContentType the content type to get the quality factor for
|
||||
* @return the q factor of the given format, according to the accept header
|
||||
*/
|
||||
private static float getQualityFactor(String pAccept, String pContentType) {
|
||||
float qFactor = 0;
|
||||
int foundIndex = pAccept.indexOf(pContentType);
|
||||
if (foundIndex >= 0) {
|
||||
int startQIndex = foundIndex + pContentType.length();
|
||||
if (startQIndex < pAccept.length() && pAccept.charAt(startQIndex) == ';') {
|
||||
while (startQIndex < pAccept.length() && pAccept.charAt(startQIndex++) == ' ') {
|
||||
// Skip over whitespace
|
||||
}
|
||||
|
||||
if (pAccept.charAt(startQIndex++) == 'q' && pAccept.charAt(startQIndex++) == '=') {
|
||||
int endQIndex = pAccept.indexOf(',', startQIndex);
|
||||
if (endQIndex < 0) {
|
||||
endQIndex = pAccept.length();
|
||||
}
|
||||
|
||||
try {
|
||||
qFactor = Float.parseFloat(pAccept.substring(startQIndex, endQIndex));
|
||||
//System.out.println("Found qFactor " + qFactor);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
// TODO: Determine what to do here.. Maybe use a very low value?
|
||||
// Ahem.. The specs don't say anything about how to interpret a wrong q factor..
|
||||
//System.out.println("Unparseable q setting; " + e.getMessage());
|
||||
}
|
||||
}
|
||||
// TODO: Determine what to do here.. Maybe use a very low value?
|
||||
// Unparseable q value, use 0
|
||||
}
|
||||
else {
|
||||
// Else, assume quality is 1.0
|
||||
qFactor = 1;
|
||||
}
|
||||
}
|
||||
return qFactor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adjusts source quality settings from image properties.
|
||||
*
|
||||
* @param pFormatQuality the format to quality mapping
|
||||
* @param pImage the image
|
||||
*/
|
||||
private static void adjustQualityFromImage(Map<String, Float> pFormatQuality, BufferedImage pImage) {
|
||||
// NOTE: The values are all made-up. May need tuning.
|
||||
|
||||
// If pImage.getColorModel() instanceof IndexColorModel
|
||||
// JPEG qs*=0.6
|
||||
// If NOT binary or 2 color index
|
||||
// WBMP qs*=0.5
|
||||
// Else
|
||||
// GIF qs*=0.02
|
||||
// PNG qs*=0.9 // JPEG is smaller/faster
|
||||
if (pImage.getColorModel() instanceof IndexColorModel) {
|
||||
adjustQuality(pFormatQuality, FORMAT_JPEG, 0.6f);
|
||||
|
||||
if (pImage.getType() != BufferedImage.TYPE_BYTE_BINARY || ((IndexColorModel) pImage.getColorModel()).getMapSize() != 2) {
|
||||
adjustQuality(pFormatQuality, FORMAT_WBMP, 0.5f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
adjustQuality(pFormatQuality, FORMAT_GIF, 0.01f);
|
||||
adjustQuality(pFormatQuality, FORMAT_PNG, 0.99f); // JPEG is smaller/faster
|
||||
}
|
||||
|
||||
// If pImage.getColorModel().hasTransparentPixels()
|
||||
// JPEG qs*=0.05
|
||||
// WBMP qs*=0.05
|
||||
// If NOT transparency == BITMASK
|
||||
// GIF qs*=0.8
|
||||
if (ImageUtil.hasTransparentPixels(pImage, true)) {
|
||||
adjustQuality(pFormatQuality, FORMAT_JPEG, 0.009f);
|
||||
adjustQuality(pFormatQuality, FORMAT_WBMP, 0.009f);
|
||||
|
||||
if (pImage.getColorModel().getTransparency() != Transparency.BITMASK) {
|
||||
adjustQuality(pFormatQuality, FORMAT_GIF, 0.8f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the quality in the map.
|
||||
*
|
||||
* @param pFormatQuality Map<String,Float>
|
||||
* @param pFormat the format
|
||||
* @param pFactor the quality factor
|
||||
*/
|
||||
private static void adjustQuality(Map<String, Float> pFormatQuality, String pFormat, float pFactor) {
|
||||
Float oldValue = pFormatQuality.get(pFormat);
|
||||
if (oldValue != null) {
|
||||
pFormatQuality.put(pFormat, oldValue * pFactor);
|
||||
//System.out.println("New vallue after multiplying with " + pFactor + " is " + pFormatQuality.get(pFormat));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the initial quality if this is a known format, otherwise 0.1
|
||||
*
|
||||
* @param pFormat the format name
|
||||
* @return the q factor of the given format
|
||||
*/
|
||||
private float getKnownFormatQuality(String pFormat) {
|
||||
for (int i = 0; i < sKnownFormats.length; i++) {
|
||||
if (pFormat.equals(sKnownFormats[i])) {
|
||||
return knownFormatQuality[i];
|
||||
}
|
||||
}
|
||||
return 0.1f;
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
import com.twelvemonkeys.servlet.ServletUtil;
|
||||
|
||||
/**
|
||||
* This Servlet is able to render a cropped part of an image.
|
||||
*
|
||||
* <HR>
|
||||
*
|
||||
* <A name="parameters"></A><STRONG>Parameters:</STRONG><BR>
|
||||
* <DL>
|
||||
* <DT>{@code cropX}</DT>
|
||||
* <DD>integer, the new left edge of the image.
|
||||
* <DT>{@code cropY}</DT>
|
||||
* <DD>integer, the new top of the image.
|
||||
* <DT>{@code cropWidth}</DT>
|
||||
* <DD>integer, the new width of the image.
|
||||
* <DT>{@code cropHeight}</DT>
|
||||
* <DD>integer, the new height of the image.
|
||||
* <DT>{@code cropUniform}</DT>
|
||||
* <DD>boolean, wether or not uniform scalnig should be used. Default is
|
||||
* {@code true}.
|
||||
* <DT>{@code cropUnits}</DT>
|
||||
* <DD>string, one of {@code PIXELS}, {@code PERCENT}.
|
||||
* {@code PIXELS} is default.
|
||||
*
|
||||
* <!-- inherited from ScaleImage below: -->
|
||||
*
|
||||
* <DT>{@code image}</DT>
|
||||
* <DD>string, the URL of the image to scale.
|
||||
*
|
||||
* <DT>{@code scaleX}</DT>
|
||||
* <DD>integer, the new width of the image.
|
||||
*
|
||||
* <DT>{@code scaleY}</DT>
|
||||
* <DD>integer, the new height of the image.
|
||||
*
|
||||
* <DT>{@code scaleUniform}</DT>
|
||||
* <DD>boolean, wether or not uniform scalnig should be used. Default is
|
||||
* {@code true}.
|
||||
*
|
||||
* <DT>{@code scaleUnits}</DT>
|
||||
* <DD>string, one of {@code PIXELS}, {@code PERCENT}.
|
||||
* {@code PIXELS} is default.
|
||||
*
|
||||
* <DT>{@code scaleQuality}</DT>
|
||||
* <DD>string, one of {@code SCALE_SMOOTH}, {@code SCALE_FAST},
|
||||
* {@code SCALE_REPLICATE}, {@code SCALE_AREA_AVERAGING}.
|
||||
* {@code SCALE_DEFAULT} is default.
|
||||
*
|
||||
* </DL>
|
||||
* <p>
|
||||
* Examples:
|
||||
* <br>
|
||||
* <IMG src="/crop/test.jpg?image=http://www.iconmedialab.com/images/random/home_image_12.jpg&cropWidth=500&cropUniform=true">
|
||||
* <br>
|
||||
* <IMG src="/crop/test.png?cache=false&image=http://www.iconmedialab.com/images/random/home_image_12.jpg&cropWidth=50&cropUnits=PERCENT">
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: CropFilter.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class CropFilter extends ScaleFilter {
|
||||
/** {@code cropX}*/
|
||||
protected final static String PARAM_CROP_X = "cropX";
|
||||
/** {@code cropY}*/
|
||||
protected final static String PARAM_CROP_Y = "cropY";
|
||||
/** {@code cropWidth}*/
|
||||
protected final static String PARAM_CROP_WIDTH = "cropWidth";
|
||||
/** {@code cropHeight}*/
|
||||
protected final static String PARAM_CROP_HEIGHT = "cropHeight";
|
||||
/** {@code cropUniform}*/
|
||||
protected final static String PARAM_CROP_UNIFORM = "cropUniform";
|
||||
/** {@code cropUnits}*/
|
||||
protected final static String PARAM_CROP_UNITS = "cropUnits";
|
||||
|
||||
/**
|
||||
* Reads the image from the requested URL, scales it, crops it, and returns
|
||||
* it in the
|
||||
* Servlet stream. See above for details on parameters.
|
||||
*/
|
||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||
// Get crop coordinates
|
||||
int x = ServletUtil.getIntParameter(pRequest, PARAM_CROP_X, -1);
|
||||
int y = ServletUtil.getIntParameter(pRequest, PARAM_CROP_Y, -1);
|
||||
int width = ServletUtil.getIntParameter(pRequest, PARAM_CROP_WIDTH, -1);
|
||||
int height = ServletUtil.getIntParameter(pRequest, PARAM_CROP_HEIGHT, -1);
|
||||
|
||||
boolean uniform =
|
||||
ServletUtil.getBooleanParameter(pRequest, PARAM_CROP_UNIFORM, false);
|
||||
|
||||
int units = getUnits(ServletUtil.getParameter(pRequest, PARAM_CROP_UNITS, null));
|
||||
|
||||
// Get crop bounds
|
||||
Rectangle bounds =
|
||||
getBounds(x, y, width, height, units, uniform, pImage);
|
||||
|
||||
// Return cropped version
|
||||
return pImage.getSubimage((int) bounds.getX(), (int) bounds.getY(),
|
||||
(int) bounds.getWidth(),
|
||||
(int) bounds.getHeight());
|
||||
//return scaled.getSubimage(x, y, width, height);
|
||||
}
|
||||
|
||||
protected Rectangle getBounds(int pX, int pY, int pWidth, int pHeight,
|
||||
int pUnits, boolean pUniform,
|
||||
BufferedImage pImg) {
|
||||
// Algoritm:
|
||||
// Try to get x and y (default 0,0).
|
||||
// Try to get width and height (default width-x, height-y)
|
||||
//
|
||||
// If percent, get ratio
|
||||
//
|
||||
// If uniform
|
||||
//
|
||||
|
||||
int oldWidth = pImg.getWidth();
|
||||
int oldHeight = pImg.getHeight();
|
||||
float ratio;
|
||||
|
||||
if (pUnits == UNITS_PERCENT) {
|
||||
if (pWidth >= 0 && pHeight >= 0) {
|
||||
// Non-uniform
|
||||
pWidth = (int) ((float) oldWidth * (float) pWidth / 100f);
|
||||
pHeight = (int) ((float) oldHeight * (float) pHeight / 100f);
|
||||
}
|
||||
else if (pWidth >= 0) {
|
||||
// Find ratio from pWidth
|
||||
ratio = (float) pWidth / 100f;
|
||||
pWidth = (int) ((float) oldWidth * ratio);
|
||||
pHeight = (int) ((float) oldHeight * ratio);
|
||||
|
||||
}
|
||||
else if (pHeight >= 0) {
|
||||
// Find ratio from pHeight
|
||||
ratio = (float) pHeight / 100f;
|
||||
pWidth = (int) ((float) oldWidth * ratio);
|
||||
pHeight = (int) ((float) oldHeight * ratio);
|
||||
}
|
||||
// Else: No crop
|
||||
}
|
||||
//else if (UNITS_PIXELS.equalsIgnoreCase(pUnits)) {
|
||||
else if (pUnits == UNITS_PIXELS) {
|
||||
// Uniform
|
||||
if (pUniform) {
|
||||
if (pWidth >= 0 && pHeight >= 0) {
|
||||
// Compute both ratios
|
||||
ratio = (float) pWidth / (float) oldWidth;
|
||||
float heightRatio = (float) pHeight / (float) oldHeight;
|
||||
|
||||
// Find the largest ratio, and use that for both
|
||||
if (heightRatio < ratio) {
|
||||
ratio = heightRatio;
|
||||
pWidth = (int) ((float) oldWidth * ratio);
|
||||
}
|
||||
else {
|
||||
pHeight = (int) ((float) oldHeight * ratio);
|
||||
}
|
||||
|
||||
}
|
||||
else if (pWidth >= 0) {
|
||||
// Find ratio from pWidth
|
||||
ratio = (float) pWidth / (float) oldWidth;
|
||||
pHeight = (int) ((float) oldHeight * ratio);
|
||||
}
|
||||
else if (pHeight >= 0) {
|
||||
// Find ratio from pHeight
|
||||
ratio = (float) pHeight / (float) oldHeight;
|
||||
pWidth = (int) ((float) oldWidth * ratio);
|
||||
}
|
||||
// Else: No crop
|
||||
}
|
||||
}
|
||||
// Else: No crop
|
||||
|
||||
// Not specified, or outside bounds: Use original dimensions
|
||||
if (pWidth < 0 || (pX < 0 && pWidth > oldWidth)
|
||||
|| (pX >= 0 && (pX + pWidth) > oldWidth)) {
|
||||
pWidth = (pX >= 0 ? oldWidth - pX : oldWidth);
|
||||
}
|
||||
if (pHeight < 0 || (pY < 0 && pHeight > oldHeight)
|
||||
|| (pY >= 0 && (pY + pHeight) > oldHeight)) {
|
||||
pHeight = (pY >= 0 ? oldHeight - pY : oldHeight);
|
||||
}
|
||||
|
||||
// Center
|
||||
if (pX < 0) {
|
||||
pX = (pImg.getWidth() - pWidth) / 2;
|
||||
}
|
||||
if (pY < 0) {
|
||||
pY = (pImg.getHeight() - pHeight) / 2;
|
||||
}
|
||||
|
||||
//System.out.println("x: " + pX + " y: " + pY
|
||||
// + " w: " + pWidth + " h " + pHeight);
|
||||
|
||||
return new Rectangle(pX, pY, pWidth, pHeight);
|
||||
}
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.servlet.GenericFilter;
|
||||
|
||||
/**
|
||||
* Abstract base class for image filters. Automatically decoding and encoding of
|
||||
* the image is handled in the {@code doFilterImpl} method.
|
||||
*
|
||||
* @see #doFilter(java.awt.image.BufferedImage,javax.servlet.ServletRequest,ImageServletResponse)
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: ImageFilter.java#2 $
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class ImageFilter extends GenericFilter {
|
||||
// TODO: Take the design back to the drawing board (see ImageServletResponseImpl)
|
||||
// - Allow multiple filters to set size attribute
|
||||
// - Allow a later filter to reset, to get pass-through given certain criteria...
|
||||
// - Or better yet, allow a filter to decide if it wants to decode, based on image metadata on the original image (ie: width/height)
|
||||
|
||||
protected String[] triggerParams = null;
|
||||
|
||||
/**
|
||||
* The {@code doFilterImpl} method is called once, or each time a
|
||||
* request/response pair is passed through the chain, depending on the
|
||||
* {@link #oncePerRequest} member variable.
|
||||
*
|
||||
* @see #oncePerRequest
|
||||
* @see com.twelvemonkeys.servlet.GenericFilter#doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) doFilter
|
||||
* @see Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) Filter.doFilter
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @param pResponse the servlet response
|
||||
* @param pChain the filter chain
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
protected void doFilterImpl(final ServletRequest pRequest, final ServletResponse pResponse, final FilterChain pChain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
//System.out.println("Starting filtering...");
|
||||
// Test for trigger params
|
||||
if (!trigger(pRequest)) {
|
||||
//System.out.println("Passing request on to next in chain (skipping " + getFilterName() + ")...");
|
||||
// Pass the request on
|
||||
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 = createImageServletResponse(pRequest, pResponse);
|
||||
|
||||
//System.out.println("Passing request on to next in chain...");
|
||||
// Pass the request on
|
||||
pChain.doFilter(pRequest, imageResponse);
|
||||
|
||||
//System.out.println("Post filtering...");
|
||||
|
||||
// Get image
|
||||
//System.out.println("Getting image from ImageServletResponse...");
|
||||
// Get the image from the wrapped response
|
||||
RenderedImage image = imageResponse.getImage();
|
||||
//System.out.println("Got image: " + image);
|
||||
|
||||
// Note: Image will be null if this is a HEAD request, the
|
||||
// If-Modified-Since header is present, or similar.
|
||||
if (image != null) {
|
||||
// Do the image filtering
|
||||
//System.out.println("Filtering image (" + getFilterName() + ")...");
|
||||
image = doFilter(ImageUtil.toBuffered(image), pRequest, imageResponse);
|
||||
//System.out.println("Done filtering.");
|
||||
|
||||
//System.out.println("Making image available...");
|
||||
// Make image available to other filters (avoid unnecessary serializing/deserializing)
|
||||
imageResponse.setImage(image);
|
||||
//System.out.println("Done.");
|
||||
}
|
||||
if (encode) {
|
||||
//System.out.println("Encoding image...");
|
||||
// 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...
|
||||
// Use ETag of original response (or derived from)
|
||||
// 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()) + "\"";
|
||||
// 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.");
|
||||
}
|
||||
}
|
||||
//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.ImageServletResponseImpl
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
* This default implementation uses {@link #triggerParams} to test if:
|
||||
* </p>
|
||||
* <dl>
|
||||
* <dt>{@code mTriggerParams == null}</dt>
|
||||
* <dd>{@code return true}</dd>
|
||||
* <dt>{@code mTriggerParams != null}, loop through parameters, and test
|
||||
* if {@code pRequest} contains the parameter. If match</dt>
|
||||
* <dd>{@code return true}</dd>
|
||||
* <dt>Otherwise</dt>
|
||||
* <dd>{@code return false}</dd>
|
||||
* </dl>
|
||||
*
|
||||
* @param pRequest the servlet request
|
||||
* @return {@code true} if the filter should do image filtering
|
||||
*/
|
||||
protected boolean trigger(final ServletRequest pRequest) {
|
||||
// If triggerParams not set, assume always trigger
|
||||
if (triggerParams == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Trigger only for certain request parameters
|
||||
for (String triggerParam : triggerParams) {
|
||||
if (pRequest.getParameter(triggerParam) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't trigger
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the trigger parameters.
|
||||
* The parameter is supposed to be a comma-separated string of parameter
|
||||
* names.
|
||||
*
|
||||
* @param pTriggerParams a comma-separated string of parameter names.
|
||||
*/
|
||||
// TODO: Make it an @InitParam, and make sure we may set String[]/Collection<String> as parameter?
|
||||
public void setTriggerParams(final String pTriggerParams) {
|
||||
triggerParams = StringUtil.toStringArray(pTriggerParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the image for this request.
|
||||
*
|
||||
* @param pImage the image to filter
|
||||
* @param pRequest the servlet request
|
||||
* @param pResponse the servlet response
|
||||
*
|
||||
* @return the filtered image
|
||||
* @throws java.io.IOException if an I/O error occurs during filtering
|
||||
*/
|
||||
protected abstract RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) throws IOException;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
/**
|
||||
* This exception is a subclass of ServletException, and acts just as a marker
|
||||
* for exceptions thrown by the ImageServlet API.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Id: ImageServletException.java#2 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class ImageServletException extends ServletException {
|
||||
|
||||
public ImageServletException(String pMessage) {
|
||||
super(pMessage);
|
||||
}
|
||||
|
||||
public ImageServletException(Throwable pThrowable) {
|
||||
super(pThrowable);
|
||||
}
|
||||
|
||||
public ImageServletException(String pMessage, Throwable pThrowable) {
|
||||
super(pMessage, pThrowable);
|
||||
}
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
/**
|
||||
* ImageServletResponse.
|
||||
* <p>
|
||||
* The request attributes regarding image size and source region (AOI) are used
|
||||
* in the decoding process, and must be set before the first invocation of
|
||||
* {@link #getImage()} to have any effect.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: ImageServletResponse.java#4 $
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ImageServletResponse extends ServletResponse {
|
||||
/**
|
||||
* Request attribute of type {@link java.awt.Dimension} controlling image
|
||||
* size.
|
||||
* If either {@code width} or {@code height} is negative, the size is
|
||||
* computed, using uniform scaling.
|
||||
* Else, if {@code SIZE_UNIFORM} is {@code true}, the size will be
|
||||
* computed to the largest possible area (with correct aspect ratio)
|
||||
* fitting inside the target area.
|
||||
* Otherwise, the image is scaled to the given size, with no regard to
|
||||
* aspect ratio.
|
||||
* <p>
|
||||
* Defaults to {@code null} (original image size).
|
||||
* </p>
|
||||
*/
|
||||
String ATTRIB_SIZE = "com.twelvemonkeys.servlet.image.ImageServletResponse.SIZE";
|
||||
|
||||
/**
|
||||
* Request attribute of type {@link Boolean} controlling image sizing.
|
||||
* <p>
|
||||
* Defaults to {@code Boolean.TRUE}.
|
||||
* </p>
|
||||
*/
|
||||
String ATTRIB_SIZE_UNIFORM = "com.twelvemonkeys.servlet.image.ImageServletResponse.SIZE_UNIFORM";
|
||||
|
||||
/**
|
||||
* Request attribute of type {@link Boolean} controlling image sizing.
|
||||
* <p>
|
||||
* Defaults to {@code Boolean.FALSE}.
|
||||
* </p>
|
||||
*/
|
||||
String ATTRIB_SIZE_PERCENT = "com.twelvemonkeys.servlet.image.ImageServletResponse.SIZE_PERCENT";
|
||||
|
||||
/**
|
||||
* Request attribute of type {@link java.awt.Rectangle} controlling image
|
||||
* source region (area of interest).
|
||||
* <p>
|
||||
* Defaults to {@code null} (the entire image).
|
||||
* </p>
|
||||
*/
|
||||
String ATTRIB_AOI = "com.twelvemonkeys.servlet.image.ImageServletResponse.AOI";
|
||||
|
||||
/**
|
||||
* Request attribute of type {@link Boolean} controlling image AOI.
|
||||
* <p>
|
||||
* Defaults to {@code Boolean.FALSE}.
|
||||
* </p>
|
||||
*/
|
||||
String ATTRIB_AOI_UNIFORM = "com.twelvemonkeys.servlet.image.ImageServletResponse.AOI_UNIFORM";
|
||||
|
||||
/**
|
||||
* Request attribute of type {@link Boolean} controlling image AOI.
|
||||
* <p>
|
||||
* Defaults to {@code Boolean.FALSE}.
|
||||
* </p>
|
||||
*/
|
||||
String ATTRIB_AOI_PERCENT = "com.twelvemonkeys.servlet.image.ImageServletResponse.AOI_PERCENT";
|
||||
|
||||
/**
|
||||
* Request attribute of type {@link java.awt.Color} controlling background
|
||||
* color for any transparent/translucent areas of the image.
|
||||
* <p>
|
||||
* Defaults to {@code null} (keeps the transparent areas transparent).
|
||||
* </p>
|
||||
*/
|
||||
String ATTRIB_BG_COLOR = "com.twelvemonkeys.servlet.image.ImageServletResponse.BG_COLOR";
|
||||
|
||||
/**
|
||||
* Request attribute of type {@link Float} controlling image output compression/quality.
|
||||
* Used for formats that accepts compression or quality settings,
|
||||
* like JPEG (quality), PNG (compression only) etc.
|
||||
* <p>
|
||||
* Defaults to {@code 0.8f} for JPEG.
|
||||
* </p>
|
||||
*/
|
||||
String ATTRIB_OUTPUT_QUALITY = "com.twelvemonkeys.servlet.image.ImageServletResponse.OUTPUT_QUALITY";
|
||||
|
||||
/**
|
||||
* Request attribute of type {@link Double} controlling image read
|
||||
* subsampling factor. Controls the maximum sample pixels in each direction,
|
||||
* that is read per pixel in the output image, if the result will be
|
||||
* downscaled.
|
||||
* Larger values will result in better quality, at the expense of higher
|
||||
* memory consumption and CPU usage.
|
||||
* However, using values above {@code 3.0} will usually not improve image
|
||||
* quality.
|
||||
* Legal values are in the range {@code [1.0 .. positive infinity>}.
|
||||
* <p>
|
||||
* Defaults to {@code 2.0}.
|
||||
* </p>
|
||||
*/
|
||||
String ATTRIB_READ_SUBSAMPLING_FACTOR = "com.twelvemonkeys.servlet.image.ImageServletResponse.READ_SUBSAMPLING_FACTOR";
|
||||
|
||||
/**
|
||||
* Request attribute of type {@link Integer} controlling image resample
|
||||
* algorithm.
|
||||
* Legal values are {@link java.awt.Image#SCALE_DEFAULT SCALE_DEFAULT},
|
||||
* {@link java.awt.Image#SCALE_FAST SCALE_FAST} or
|
||||
* {@link java.awt.Image#SCALE_SMOOTH SCALE_SMOOTH}.
|
||||
* <p>
|
||||
* Note: When using a value of {@code SCALE_FAST}, you should also use a
|
||||
* subsampling factor of {@code 1.0}, for fast read/scale.
|
||||
* Otherwise, use a subsampling factor of {@code 2.0} for better quality.
|
||||
* </p>
|
||||
* <p>
|
||||
* Defaults to {@code SCALE_DEFAULT}.
|
||||
* </p>
|
||||
*/
|
||||
String ATTRIB_IMAGE_RESAMPLE_ALGORITHM = "com.twelvemonkeys.servlet.image.ImageServletResponse.IMAGE_RESAMPLE_ALGORITHM";
|
||||
|
||||
/**
|
||||
* Gets the image format for this response, such as "image/gif" or "image/jpeg".
|
||||
* If not set, the default format is that of the original image.
|
||||
*
|
||||
* @return the image format for this response.
|
||||
* @see #setOutputContentType(String)
|
||||
*/
|
||||
String getOutputContentType();
|
||||
|
||||
/**
|
||||
* Sets the image format for this response, such as "image/gif" or "image/jpeg".
|
||||
* <p>
|
||||
* As an example, a custom filter could do content negotiation based on the
|
||||
* request header fields and write the image back in an appropriate format.
|
||||
* </p>
|
||||
* <p>
|
||||
* If not set, the default format is that of the original image.
|
||||
* </p>
|
||||
*
|
||||
* @param pImageFormat the image format for this response.
|
||||
*/
|
||||
void setOutputContentType(String pImageFormat);
|
||||
|
||||
//TODO: ?? void setCompressionQuality(float pQualityFactor);
|
||||
//TODO: ?? float getCompressionQuality();
|
||||
|
||||
/**
|
||||
* Writes the image to the original {@code ServletOutputStream}.
|
||||
* If no format is {@linkplain #setOutputContentType(String) set} in this response,
|
||||
* the image is encoded in the same format as the original image.
|
||||
*
|
||||
* @throws java.io.IOException if an I/O exception occurs during writing
|
||||
*/
|
||||
void flush() throws IOException;
|
||||
|
||||
/**
|
||||
* Gets the decoded image from the response.
|
||||
*
|
||||
* @return a {@code BufferedImage} or {@code null} if the image could not be read.
|
||||
*
|
||||
* @throws java.io.IOException if an I/O exception occurs during reading
|
||||
*/
|
||||
BufferedImage getImage() throws IOException;
|
||||
|
||||
/**
|
||||
* Sets the image for this response.
|
||||
*
|
||||
* @param pImage the new response image.
|
||||
*/
|
||||
void setImage(RenderedImage pImage);
|
||||
}
|
||||
@@ -1,815 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.IIOImage;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.servlet.ServletResponseStreamDelegate;
|
||||
import com.twelvemonkeys.servlet.ServletUtil;
|
||||
import com.twelvemonkeys.servlet.image.aoi.AreaOfInterest;
|
||||
import com.twelvemonkeys.servlet.image.aoi.AreaOfInterestFactory;
|
||||
|
||||
/**
|
||||
* This {@link ImageServletResponse} implementation can be used with image
|
||||
* requests, to have the image immediately decoded to a {@code BufferedImage}.
|
||||
* The image may be optionally subsampled, scaled and/or cropped.
|
||||
* The response also automatically handles writing the image back to the underlying response stream
|
||||
* in the preferred format, when the response is flushed.
|
||||
* <p>
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: ImageServletResponseImpl.java#10 $
|
||||
*/
|
||||
// TODO: Refactor out HTTP specifics (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
|
||||
// TODO: Allow different scaling algorithm based on input image (use case: IndexColorModel does not scale well using default, smooth may be slow for large images)
|
||||
// TODO: Support pluggable pre- and post-processing steps
|
||||
@Deprecated
|
||||
class ImageServletResponseImpl extends HttpServletResponseWrapper implements ImageServletResponse {
|
||||
private ServletRequest originalRequest;
|
||||
private final ServletContext context;
|
||||
private final ServletResponseStreamDelegate streamDelegate;
|
||||
|
||||
private FastByteArrayOutputStream bufferedOut;
|
||||
|
||||
private RenderedImage image;
|
||||
private String outputContentType;
|
||||
|
||||
private String originalContentType;
|
||||
private int originalContentLength = -1;
|
||||
|
||||
/**
|
||||
* Creates an {@code ImageServletResponseImpl}.
|
||||
*
|
||||
* @param pRequest the request
|
||||
* @param pResponse the response
|
||||
* @param pContext the servlet context
|
||||
*/
|
||||
public ImageServletResponseImpl(final HttpServletRequest pRequest, final HttpServletResponse pResponse, final ServletContext pContext) {
|
||||
super(pResponse);
|
||||
originalRequest = pRequest;
|
||||
streamDelegate = new ServletResponseStreamDelegate(pResponse) {
|
||||
@Override
|
||||
protected OutputStream createOutputStream() throws IOException {
|
||||
if (originalContentLength >= 0) {
|
||||
bufferedOut = new FastByteArrayOutputStream(originalContentLength);
|
||||
}
|
||||
else {
|
||||
bufferedOut = new FastByteArrayOutputStream(0);
|
||||
}
|
||||
|
||||
return bufferedOut;
|
||||
}
|
||||
};
|
||||
context = pContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@code ImageServletResponseImpl}.
|
||||
*
|
||||
* @param pRequest the request
|
||||
* @param pResponse the response
|
||||
* @param pContext the servlet context
|
||||
*
|
||||
* @throws ClassCastException if {@code pRequest} is not an {@link javax.servlet.http.HttpServletRequest} or
|
||||
* {@code pResponse} is not an {@link javax.servlet.http.HttpServletResponse}.
|
||||
*/
|
||||
public ImageServletResponseImpl(final ServletRequest pRequest, final ServletResponse pResponse, final ServletContext pContext) {
|
||||
// Cheat for now...
|
||||
this((HttpServletRequest) pRequest, (HttpServletResponse) pResponse, pContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the container, do not invoke.
|
||||
*
|
||||
* @param pMimeType the content (MIME) type
|
||||
*/
|
||||
public void setContentType(final String pMimeType) {
|
||||
// Throw exception is already set
|
||||
if (originalContentType != null) {
|
||||
throw new IllegalStateException("ContentType already set.");
|
||||
}
|
||||
|
||||
originalContentType = pMimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the container. Do not invoke.
|
||||
*
|
||||
* @return the response's {@code OutputStream}
|
||||
* @throws IOException
|
||||
*/
|
||||
public ServletOutputStream getOutputStream() throws IOException {
|
||||
return streamDelegate.getOutputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the container. Do not invoke.
|
||||
*
|
||||
* @return the response's {@code PrintWriter}
|
||||
* @throws IOException
|
||||
*/
|
||||
public PrintWriter getWriter() throws IOException {
|
||||
return streamDelegate.getWriter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the container. Do not invoke.
|
||||
*
|
||||
* @param pLength the content length
|
||||
*/
|
||||
public void setContentLength(final int pLength) {
|
||||
if (originalContentLength != -1) {
|
||||
throw new IllegalStateException("ContentLength already set.");
|
||||
}
|
||||
|
||||
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}.
|
||||
* If no format is set in this response, the image is encoded in the same
|
||||
* format as the original image.
|
||||
*
|
||||
* @throws IOException if an I/O exception occurs during writing
|
||||
*/
|
||||
public void flush() throws IOException {
|
||||
String outputType = getOutputContentType();
|
||||
|
||||
// Force transcoding, if no other filtering is done
|
||||
if (outputType != null && !outputType.equals(originalContentType)) {
|
||||
getImage();
|
||||
}
|
||||
|
||||
if (image != null) {
|
||||
Iterator writers = ImageIO.getImageWritersByMIMEType(outputType);
|
||||
if (writers.hasNext()) {
|
||||
super.setContentType(outputType);
|
||||
OutputStream out = super.getOutputStream();
|
||||
try {
|
||||
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) && image.getColorModel().getTransparency() != Transparency.OPAQUE) {
|
||||
image = ImageUtil.toBuffered(image, BufferedImage.TYPE_INT_RGB);
|
||||
}
|
||||
|
||||
Float requestQuality = (Float) originalRequest.getAttribute(ImageServletResponse.ATTRIB_OUTPUT_QUALITY);
|
||||
|
||||
// The default JPEG quality is not good enough, so always adjust compression/quality
|
||||
if ((requestQuality != null || "jpeg".equalsIgnoreCase(getFormatNameSafe(writer))) && param.canWriteCompressed()) {
|
||||
// TODO: See http://blog.apokalyptik.com/2009/09/16/quality-time-with-your-jpegs/ for better adjusting the (default) JPEG quality
|
||||
// OR: Use the metadata of the original image
|
||||
|
||||
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||
|
||||
// WORKAROUND: Known bug in GIFImageWriter in certain JDK versions, compression type is not set by default
|
||||
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);
|
||||
}
|
||||
|
||||
if ("gif".equalsIgnoreCase(getFormatNameSafe(writer)) && !(image.getColorModel() instanceof IndexColorModel)
|
||||
/*&& image.getColorModel().getTransparency() != Transparency.OPAQUE*/) {
|
||||
// WORKAROUND: Bug in GIFImageWriter may throw NPE if transparent pixels
|
||||
// See: http://bugs.sun.com/view_bug.do?bug_id=6287936
|
||||
image = ImageUtil.createIndexed(
|
||||
ImageUtil.toBuffered(image), 256, null,
|
||||
(image.getColorModel().getTransparency() == Transparency.OPAQUE ? ImageUtil.TRANSPARENCY_OPAQUE : ImageUtil.TRANSPARENCY_BITMASK) | ImageUtil.DITHER_DIFFUSION_ALTSCANS
|
||||
);
|
||||
}
|
||||
//////////////////
|
||||
ImageOutputStream stream = ImageIO.createImageOutputStream(out);
|
||||
|
||||
writer.setOutput(stream);
|
||||
try {
|
||||
writer.write(null, new IIOImage(image, null, null), param);
|
||||
}
|
||||
finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
writer.dispose();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
else {
|
||||
context.log("ERROR: No writer for content-type: " + outputType);
|
||||
throw new IIOException("Unable to transcode image: No suitable image writer found (content-type: " + outputType + ").");
|
||||
}
|
||||
}
|
||||
else {
|
||||
super.setContentType(originalContentType);
|
||||
|
||||
ServletOutputStream out = super.getOutputStream();
|
||||
|
||||
try {
|
||||
if (bufferedOut != null) {
|
||||
bufferedOut.writeTo(out);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
// NPE, AIOOBE, etc..
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getOutputContentType() {
|
||||
return outputContentType != null ? outputContentType : originalContentType;
|
||||
}
|
||||
|
||||
public void setOutputContentType(final String pImageFormat) {
|
||||
outputContentType = pImageFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the image for this response.
|
||||
*
|
||||
* @param pImage the {@code RenderedImage} that will be written to the
|
||||
* response stream
|
||||
*/
|
||||
public void setImage(final RenderedImage pImage) {
|
||||
image = pImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the decoded image from the response.
|
||||
*
|
||||
* @return a {@code BufferedImage} or {@code null} if the image could
|
||||
* not be read.
|
||||
*
|
||||
* @throws java.io.IOException if an I/O exception occurs during reading
|
||||
*/
|
||||
public BufferedImage getImage() throws IOException {
|
||||
if (image == null) {
|
||||
// No content, no image
|
||||
if (bufferedOut == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Read from the byte buffer
|
||||
InputStream byteStream = bufferedOut.createInputStream();
|
||||
ImageInputStream input = null;
|
||||
try {
|
||||
input = ImageIO.createImageInputStream(byteStream);
|
||||
Iterator readers = ImageIO.getImageReaders(input);
|
||||
if (readers.hasNext()) {
|
||||
// Get the correct reader
|
||||
ImageReader reader = (ImageReader) readers.next();
|
||||
try {
|
||||
reader.setInput(input);
|
||||
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
|
||||
// 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, originalRequest);
|
||||
|
||||
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, originalRequest);
|
||||
double readSubSamplingFactor = getReadSubsampleFactorFromRequest(originalRequest);
|
||||
|
||||
if (size != null) {
|
||||
//System.out.println("Size: " + size);
|
||||
if (param.canSetSourceRenderSize()) {
|
||||
param.setSourceRenderSize(size);
|
||||
}
|
||||
else {
|
||||
int subX = (int) Math.max(originalWidth / (size.width * readSubSamplingFactor), 1.0);
|
||||
int subY = (int) Math.max(originalHeight / (size.height * readSubSamplingFactor), 1.0);
|
||||
|
||||
if (subX > 1 || subY > 1) {
|
||||
param.setSourceSubsampling(subX, subY, subX > 1 ? subX / 2 : 0, subY > 1 ? subY / 2 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// TODO: If we sub-sampled, it would be a good idea to blur before resampling,
|
||||
// to avoid jagged lines artifacts
|
||||
|
||||
// If reader doesn't support dynamic sizing, scale now
|
||||
image = resampleImage(image, size);
|
||||
|
||||
// Fill bgcolor behind image, if transparent
|
||||
extractAndSetBackgroundColor(image); // TODO: Move to flush/POST-PROCESS
|
||||
|
||||
// Set image
|
||||
this.image = image;
|
||||
}
|
||||
finally {
|
||||
reader.dispose();
|
||||
}
|
||||
}
|
||||
else {
|
||||
context.log("ERROR: No suitable image reader found (content-type: " + originalContentType + ").");
|
||||
context.log("ERROR: Available formats: " + getFormatsString());
|
||||
|
||||
throw new IIOException("Unable to transcode image: No suitable image reader found (content-type: " + originalContentType + ").");
|
||||
}
|
||||
|
||||
// Free resources, as the image is now either read, or unreadable
|
||||
bufferedOut = null;
|
||||
}
|
||||
finally {
|
||||
if (input != null) {
|
||||
input.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Image is usually a BufferedImage, but may also be a RenderedImage
|
||||
return image != null ? ImageUtil.toBuffered(image) : null;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// TODO: One possibility is to NOT handle index color here, and only handle it later, IF NEEDED (read: GIF,
|
||||
// possibly also for PNG) when we know the output format (flush method).
|
||||
// This will make the filter faster (and better quality, possibly at the expense of more bytes being sent
|
||||
// over the wire) in the general case. Who uses GIF nowadays anyway?
|
||||
// Also, this means we could either keep the original IndexColorModel in the filter, or go through the
|
||||
// expensive operation of re-calculating the optimal palette for the new image (the latter might improve quality).
|
||||
|
||||
// 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);
|
||||
BufferedImage resampled = ImageUtil.createResampled(image, size.width, size.height, resampleAlgorithm);
|
||||
return ImageUtil.createIndexed(resampled, (IndexColorModel) image.getColorModel(), null, ImageUtil.DITHER_NONE | ImageUtil.TRANSPARENCY_BITMASK);
|
||||
// return ImageUtil.createIndexed(resampled, 256, null, ImageUtil.COLOR_SELECTION_QUALITY | ImageUtil.DITHER_NONE | ImageUtil.TRANSPARENCY_BITMASK);
|
||||
}
|
||||
else {
|
||||
*/
|
||||
return ImageUtil.createResampled(image, size.width, size.height, resampleAlgorithm);
|
||||
// }
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
int getResampleAlgorithmFromRequest() {
|
||||
Object algorithm = originalRequest.getAttribute(ATTRIB_IMAGE_RESAMPLE_ALGORITHM);
|
||||
if (algorithm instanceof Integer && ((Integer) algorithm == Image.SCALE_SMOOTH || (Integer) algorithm == Image.SCALE_FAST || (Integer) algorithm == Image.SCALE_DEFAULT)) {
|
||||
return (Integer) algorithm;
|
||||
}
|
||||
else {
|
||||
if (algorithm != null) {
|
||||
context.log("WARN: Illegal image resampling algorithm: " + algorithm);
|
||||
}
|
||||
|
||||
return BufferedImage.SCALE_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
private double getReadSubsampleFactorFromRequest(final ServletRequest pOriginalRequest) {
|
||||
double subsampleFactor;
|
||||
|
||||
Object factor = pOriginalRequest.getAttribute(ATTRIB_READ_SUBSAMPLING_FACTOR);
|
||||
if (factor instanceof Number && ((Number) factor).doubleValue() >= 1.0) {
|
||||
subsampleFactor = ((Number) factor).doubleValue();
|
||||
}
|
||||
else {
|
||||
if (factor != null) {
|
||||
context.log("WARN: Illegal read subsampling factor: " + factor);
|
||||
}
|
||||
|
||||
subsampleFactor = 2.0;
|
||||
}
|
||||
|
||||
return subsampleFactor;
|
||||
}
|
||||
|
||||
private void extractAndSetBackgroundColor(final BufferedImage pImage) {
|
||||
// TODO: bgColor request attribute instead of parameter?
|
||||
if (pImage.getColorModel().hasAlpha()) {
|
||||
String bgColor = originalRequest.getParameter("bg.color");
|
||||
if (bgColor != null) {
|
||||
Color color = StringUtil.toColor(bgColor);
|
||||
|
||||
Graphics2D g = pImage.createGraphics();
|
||||
try {
|
||||
g.setColor(color);
|
||||
g.setComposite(AlphaComposite.DstOver);
|
||||
g.fillRect(0, 0, pImage.getWidth(), pImage.getHeight());
|
||||
}
|
||||
finally {
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getFormatsString() {
|
||||
String[] formats = ImageIO.getReaderFormatNames();
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (int i = 0; i < formats.length; i++) {
|
||||
String format = formats[i];
|
||||
if (i > 0) {
|
||||
buf.append(", ");
|
||||
}
|
||||
buf.append(format);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private void maybeSetBaseURIFromRequest(final ImageReadParam pParam) {
|
||||
if (originalRequest instanceof HttpServletRequest) {
|
||||
try {
|
||||
// If there's a setBaseURI method, we'll try to use that (uses reflection, to avoid dependency on plugins)
|
||||
Method setBaseURI;
|
||||
try {
|
||||
setBaseURI = pParam.getClass().getMethod("setBaseURI", String.class);
|
||||
}
|
||||
catch (NoSuchMethodException ignore) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get URL for resource and set as base
|
||||
String baseURI = ServletUtil.getContextRelativeURI((HttpServletRequest) originalRequest);
|
||||
|
||||
URL resourceURL = context.getResource(baseURI);
|
||||
|
||||
if (resourceURL == null) {
|
||||
resourceURL = ServletUtil.getRealURL(context, baseURI);
|
||||
}
|
||||
|
||||
if (resourceURL != null) {
|
||||
setBaseURI.invoke(pParam, resourceURL.toExternalForm());
|
||||
}
|
||||
else {
|
||||
context.log("WARN: Resource URL not found for URI: " + baseURI);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
context.log("WARN: Could not set base URI: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Dimension extractSizeFromRequest(final int pDefaultWidth, final int pDefaultHeight, final ServletRequest pOriginalRequest) {
|
||||
// TODO: Allow extraction from request parameters
|
||||
/*
|
||||
int sizeW = ServletUtil.getIntParameter(originalRequest, "size.w", -1);
|
||||
int sizeH = ServletUtil.getIntParameter(originalRequest, "size.h", -1);
|
||||
boolean sizePercent = ServletUtil.getBooleanParameter(originalRequest, "size.percent", false);
|
||||
boolean sizeUniform = ServletUtil.getBooleanParameter(originalRequest, "size.uniform", true);
|
||||
*/
|
||||
Dimension size = (Dimension) pOriginalRequest.getAttribute(ATTRIB_SIZE);
|
||||
int sizeW = size != null ? size.width : -1;
|
||||
int sizeH = size != null ? size.height : -1;
|
||||
|
||||
Boolean b = (Boolean) pOriginalRequest.getAttribute(ATTRIB_SIZE_PERCENT);
|
||||
boolean sizePercent = b != null && b; // default: false
|
||||
|
||||
b = (Boolean) pOriginalRequest.getAttribute(ATTRIB_SIZE_UNIFORM);
|
||||
boolean sizeUniform = b == null || b; // default: true
|
||||
|
||||
if (sizeW >= 0 || sizeH >= 0) {
|
||||
size = getSize(pDefaultWidth, pDefaultHeight, sizeW, sizeH, sizePercent, sizeUniform);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private Rectangle extractAOIFromRequest(final int pDefaultWidth, final int pDefaultHeight, final ServletRequest pOriginalRequest) {
|
||||
// TODO: Allow extraction from request parameters
|
||||
/*
|
||||
int aoiX = ServletUtil.getIntParameter(originalRequest, "aoi.x", -1);
|
||||
int aoiY = ServletUtil.getIntParameter(originalRequest, "aoi.y", -1);
|
||||
int aoiW = ServletUtil.getIntParameter(originalRequest, "aoi.w", -1);
|
||||
int aoiH = ServletUtil.getIntParameter(originalRequest, "aoi.h", -1);
|
||||
boolean aoiPercent = ServletUtil.getBooleanParameter(originalRequest, "aoi.percent", false);
|
||||
boolean aoiUniform = ServletUtil.getBooleanParameter(originalRequest, "aoi.uniform", false);
|
||||
*/
|
||||
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) pOriginalRequest.getAttribute(ATTRIB_AOI_PERCENT);
|
||||
boolean aoiPercent = b != null && b; // default: false
|
||||
|
||||
b = (Boolean) pOriginalRequest.getAttribute(ATTRIB_AOI_UNIFORM);
|
||||
boolean aoiUniform = b != null && b; // default: false
|
||||
|
||||
if (aoiX >= 0 || aoiY >= 0 || aoiW >= 0 || aoiH >= 0) {
|
||||
|
||||
AreaOfInterest areaOfInterest = AreaOfInterestFactory.getDefault().
|
||||
createAreaOfInterest(pDefaultWidth, pDefaultHeight, aoiPercent, aoiUniform);
|
||||
aoi = areaOfInterest.getAOI(new Rectangle(aoiX, aoiY, aoiW, aoiH));
|
||||
return aoi;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: Move these to ImageUtil or similar, as they are often used...
|
||||
// TODO: Consider separate methods for percent and pixels
|
||||
/**
|
||||
* Gets the dimensions (height and width) of the scaled image. The
|
||||
* dimensions are computed based on the old image's dimensions, the units
|
||||
* used for specifying new dimensions and whether or not uniform scaling
|
||||
* should be used (se algorithm below).
|
||||
*
|
||||
* @param pOriginalWidth the original width of the image
|
||||
* @param pOriginalHeight the original height of the image
|
||||
* @param pWidth the new width of the image, or -1 if unknown
|
||||
* @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 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.
|
||||
*/
|
||||
static Dimension getSize(int pOriginalWidth, int pOriginalHeight,
|
||||
int pWidth, int pHeight,
|
||||
boolean pPercent, boolean pUniform) {
|
||||
|
||||
// If uniform, make sure width and height are scaled the same amount
|
||||
// (use ONLY height or ONLY width).
|
||||
//
|
||||
// Algorithm:
|
||||
// if uniform
|
||||
// if newHeight not set
|
||||
// find ratio newWidth / oldWidth
|
||||
// oldHeight *= ratio
|
||||
// else if newWidth not set
|
||||
// find ratio newWidth / oldWidth
|
||||
// oldHeight *= ratio
|
||||
// else
|
||||
// find both ratios and use the smallest one
|
||||
// (this will be the largest version of the image that fits
|
||||
// inside the rectangle given)
|
||||
// (if PERCENT, just use smallest percentage).
|
||||
//
|
||||
// If units is percent, we only need old height and width
|
||||
|
||||
float ratio;
|
||||
|
||||
if (pPercent) {
|
||||
if (pWidth >= 0 && pHeight >= 0) {
|
||||
// Non-uniform
|
||||
pWidth = Math.round((float) pOriginalWidth * (float) pWidth / 100f);
|
||||
pHeight = Math.round((float) pOriginalHeight * (float) pHeight / 100f);
|
||||
}
|
||||
else if (pWidth >= 0) {
|
||||
// Find ratio from pWidth
|
||||
ratio = (float) pWidth / 100f;
|
||||
pWidth = Math.round((float) pOriginalWidth * ratio);
|
||||
pHeight = Math.round((float) pOriginalHeight * ratio);
|
||||
}
|
||||
else if (pHeight >= 0) {
|
||||
// Find ratio from pHeight
|
||||
ratio = (float) pHeight / 100f;
|
||||
pWidth = Math.round((float) pOriginalWidth * ratio);
|
||||
pHeight = Math.round((float) pOriginalHeight * ratio);
|
||||
}
|
||||
// Else: No scale
|
||||
}
|
||||
else {
|
||||
if (pUniform) {
|
||||
if (pWidth >= 0 && pHeight >= 0) {
|
||||
// Compute both ratios
|
||||
ratio = (float) pWidth / (float) pOriginalWidth;
|
||||
float heightRatio = (float) pHeight / (float) pOriginalHeight;
|
||||
|
||||
// Find the largest ratio, and use that for both
|
||||
if (heightRatio < ratio) {
|
||||
ratio = heightRatio;
|
||||
pWidth = Math.round((float) pOriginalWidth * ratio);
|
||||
}
|
||||
else {
|
||||
pHeight = Math.round((float) pOriginalHeight * ratio);
|
||||
}
|
||||
}
|
||||
else if (pWidth >= 0) {
|
||||
// Find ratio from pWidth
|
||||
ratio = (float) pWidth / (float) pOriginalWidth;
|
||||
pHeight = Math.round((float) pOriginalHeight * ratio);
|
||||
}
|
||||
else if (pHeight >= 0) {
|
||||
// Find ratio from pHeight
|
||||
ratio = (float) pHeight / (float) pOriginalHeight;
|
||||
pWidth = Math.round((float) pOriginalWidth * ratio);
|
||||
}
|
||||
// Else: No scale
|
||||
}
|
||||
}
|
||||
|
||||
// Default is no scale, just work as a proxy
|
||||
if (pWidth < 0) {
|
||||
pWidth = pOriginalWidth;
|
||||
}
|
||||
if (pHeight < 0) {
|
||||
pHeight = pOriginalHeight;
|
||||
}
|
||||
|
||||
// Create new Dimension object and return
|
||||
return new Dimension(pWidth, pHeight);
|
||||
}
|
||||
|
||||
static Rectangle getAOI(int pOriginalWidth, int pOriginalHeight,
|
||||
int pX, int pY, int pWidth, int pHeight,
|
||||
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)
|
||||
//
|
||||
// If percent, get ratio
|
||||
//
|
||||
// If uniform
|
||||
//
|
||||
|
||||
float ratio;
|
||||
|
||||
if (pPercent) {
|
||||
if (pWidth >= 0 && pHeight >= 0) {
|
||||
// Non-uniform
|
||||
pWidth = Math.round((float) pOriginalWidth * (float) pWidth / 100f);
|
||||
pHeight = Math.round((float) pOriginalHeight * (float) pHeight / 100f);
|
||||
}
|
||||
else if (pWidth >= 0) {
|
||||
// Find ratio from pWidth
|
||||
ratio = (float) pWidth / 100f;
|
||||
pWidth = Math.round((float) pOriginalWidth * ratio);
|
||||
pHeight = Math.round((float) pOriginalHeight * ratio);
|
||||
}
|
||||
else if (pHeight >= 0) {
|
||||
// Find ratio from pHeight
|
||||
ratio = (float) pHeight / 100f;
|
||||
pWidth = Math.round((float) pOriginalWidth * ratio);
|
||||
pHeight = Math.round((float) pOriginalHeight * ratio);
|
||||
}
|
||||
// Else: No crop
|
||||
}
|
||||
else {
|
||||
// Uniform
|
||||
if (pMaximizeToAspect) {
|
||||
if (pWidth >= 0 && pHeight >= 0) {
|
||||
// Compute both ratios
|
||||
ratio = (float) pWidth / (float) pHeight;
|
||||
float originalRatio = (float) pOriginalWidth / (float) pOriginalHeight;
|
||||
if (ratio > originalRatio) {
|
||||
pWidth = pOriginalWidth;
|
||||
pHeight = Math.round((float) pOriginalWidth / ratio);
|
||||
}
|
||||
else {
|
||||
pHeight = pOriginalHeight;
|
||||
pWidth = Math.round((float) pOriginalHeight * ratio);
|
||||
}
|
||||
}
|
||||
else if (pWidth >= 0) {
|
||||
// Find ratio from pWidth
|
||||
ratio = (float) pWidth / (float) pOriginalWidth;
|
||||
pHeight = Math.round((float) pOriginalHeight * ratio);
|
||||
}
|
||||
else if (pHeight >= 0) {
|
||||
// Find ratio from pHeight
|
||||
ratio = (float) pHeight / (float) pOriginalHeight;
|
||||
pWidth = Math.round((float) pOriginalWidth * ratio);
|
||||
}
|
||||
// Else: No crop
|
||||
}
|
||||
}
|
||||
|
||||
// Not specified, or outside bounds: Use original dimensions
|
||||
if (pWidth < 0 || (pX < 0 && pWidth > pOriginalWidth)
|
||||
|| (pX >= 0 && (pX + pWidth) > pOriginalWidth)) {
|
||||
pWidth = (pX >= 0 ? pOriginalWidth - pX : pOriginalWidth);
|
||||
}
|
||||
if (pHeight < 0 || (pY < 0 && pHeight > pOriginalHeight)
|
||||
|| (pY >= 0 && (pY + pHeight) > pOriginalHeight)) {
|
||||
pHeight = (pY >= 0 ? pOriginalHeight - pY : pOriginalHeight);
|
||||
}
|
||||
|
||||
// Center
|
||||
if (pX < 0) {
|
||||
pX = (pOriginalWidth - pWidth) / 2;
|
||||
}
|
||||
if (pY < 0) {
|
||||
pY = (pOriginalHeight - pHeight) / 2;
|
||||
}
|
||||
|
||||
// System.out.println("x: " + pX + " y: " + pY
|
||||
// + " w: " + pWidth + " h " + pHeight);
|
||||
|
||||
return new Rectangle(pX, pY, pWidth, pHeight);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
/**
|
||||
* An {@code ImageFilter} that does nothing. Useful for debugging purposes.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: NullImageFilter.java $
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public final class NullImageFilter extends ImageFilter {
|
||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||
return pImage;
|
||||
}
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.servlet.ServletUtil;
|
||||
|
||||
/**
|
||||
* This Servlet is able to render a cropped part of an image.
|
||||
*
|
||||
* <hr>
|
||||
*
|
||||
* <a name="parameters"></a><strong>Parameters:</strong><br>
|
||||
* <DL>
|
||||
* <DT>{@code cropX}</DT>
|
||||
* <DD>integer, the new left edge of the image.
|
||||
* <DT>{@code cropY}</DT>
|
||||
* <DD>integer, the new top of the image.
|
||||
* <DT>{@code cropWidth}</DT>
|
||||
* <DD>integer, the new width of the image.
|
||||
* <DT>{@code cropHeight}</DT>
|
||||
* <DD>integer, the new height of the image.
|
||||
* <!--
|
||||
* <DT>{@code cropUniform}</DT>
|
||||
* <DD>boolean, wether or not uniform scalnig should be used. Default is
|
||||
* {@code true}.
|
||||
* <DT>{@code cropUnits}</DT>
|
||||
* <DD>string, one of {@code PIXELS}, {@code PERCENT}.
|
||||
* {@code PIXELS} is default. -->
|
||||
* </DL>
|
||||
*
|
||||
* <p>
|
||||
* Examples:
|
||||
* <br>
|
||||
* JPEG:
|
||||
* <IMG src="/scale/test.jpg?image=http://www.iconmedialab.com/images/random/home_image_12.jpg&width=500&uniform=true">
|
||||
* <br>
|
||||
* PNG:
|
||||
* <IMG src="/scale/test.png?cache=false&image=http://www.iconmedialab.com/images/random/home_image_12.jpg&width=50&units=PERCENT">
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: RotateFilter.java#1 $
|
||||
*/
|
||||
// TODO: Correct rounding errors, resulting in black borders when rotating 90
|
||||
// degrees, and one of width or height is odd length...
|
||||
@Deprecated
|
||||
public class RotateFilter extends ImageFilter {
|
||||
/** {@code angle}*/
|
||||
protected final static String PARAM_ANGLE = "angle";
|
||||
/** {@code angleUnits (RADIANS|DEGREES)}*/
|
||||
protected final static String PARAM_ANGLE_UNITS = "angleUnits";
|
||||
/** {@code crop}*/
|
||||
protected final static String PARAM_CROP = "rotateCrop";
|
||||
/** {@code bgcolor}*/
|
||||
protected final static String PARAM_BGCOLOR = "rotateBgcolor";
|
||||
|
||||
/** {@code degrees}*/
|
||||
private final static String ANGLE_DEGREES = "degrees";
|
||||
/** {@code radians}*/
|
||||
//private final static String ANGLE_RADIANS = "radians";
|
||||
|
||||
/**
|
||||
* Reads the image from the requested URL, rotates it, and returns
|
||||
* it in the
|
||||
* Servlet stream. See above for details on parameters.
|
||||
*/
|
||||
|
||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||
// Get angle
|
||||
double ang = getAngle(pRequest);
|
||||
|
||||
// Get bounds
|
||||
Rectangle2D rect = getBounds(pRequest, pImage, ang);
|
||||
int width = (int) rect.getWidth();
|
||||
int height = (int) rect.getHeight();
|
||||
|
||||
// Create result image
|
||||
BufferedImage res = ImageUtil.createTransparent(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = res.createGraphics();
|
||||
|
||||
// Get background color and clear
|
||||
String str = pRequest.getParameter(PARAM_BGCOLOR);
|
||||
if (!StringUtil.isEmpty(str)) {
|
||||
Color bgcolor = StringUtil.toColor(str);
|
||||
g.setBackground(bgcolor);
|
||||
g.clearRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
// Set mHints (why do I always get jagged edgdes?)
|
||||
RenderingHints hints = new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
||||
hints.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
|
||||
hints.add(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
|
||||
hints.add(new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC));
|
||||
|
||||
g.setRenderingHints(hints);
|
||||
|
||||
// Rotate around center
|
||||
AffineTransform at = AffineTransform
|
||||
.getRotateInstance(ang, width / 2.0, height / 2.0);
|
||||
|
||||
// Move to center
|
||||
at.translate(width / 2.0 - pImage.getWidth() / 2.0,
|
||||
height / 2.0 - pImage.getHeight() / 2.0);
|
||||
|
||||
// Draw it, centered
|
||||
g.drawImage(pImage, at, null);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the angle of rotation.
|
||||
*/
|
||||
|
||||
private double getAngle(ServletRequest pReq) {
|
||||
double angle = 0.0;
|
||||
String str = pReq.getParameter(PARAM_ANGLE);
|
||||
if (!StringUtil.isEmpty(str)) {
|
||||
angle = Double.parseDouble(str);
|
||||
|
||||
// Convert to radians, if needed
|
||||
str = pReq.getParameter(PARAM_ANGLE_UNITS);
|
||||
if (!StringUtil.isEmpty(str)
|
||||
&& ANGLE_DEGREES.equalsIgnoreCase(str)) {
|
||||
angle = Math.toRadians(angle);
|
||||
}
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bounding rectangle of the rotated image.
|
||||
*/
|
||||
|
||||
private Rectangle2D getBounds(ServletRequest pReq, BufferedImage pImage,
|
||||
double pAng) {
|
||||
// Get dimensions of original image
|
||||
int width = pImage.getWidth(); // loads the image
|
||||
int height = pImage.getHeight();
|
||||
|
||||
// Test if we want to crop image (default)
|
||||
// if true
|
||||
// - find the largest bounding box INSIDE the rotated image,
|
||||
// that matches the original proportions (nearest 90deg)
|
||||
// (scale up to fit dimensions?)
|
||||
// else
|
||||
// - find the smallest bounding box OUTSIDE the rotated image.
|
||||
// - that matches the original proportions (nearest 90deg) ?
|
||||
// (scale down to fit dimensions?)
|
||||
AffineTransform at =
|
||||
AffineTransform.getRotateInstance(pAng, width / 2.0, height / 2.0);
|
||||
|
||||
Rectangle2D orig = new Rectangle(width, height);
|
||||
Shape rotated = at.createTransformedShape(orig);
|
||||
|
||||
if (ServletUtil.getBooleanParameter(pReq, PARAM_CROP, false)) {
|
||||
// TODO: Inside box
|
||||
return rotated.getBounds2D();
|
||||
}
|
||||
else {
|
||||
return rotated.getBounds2D();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,333 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.servlet.ServletUtil;
|
||||
|
||||
|
||||
/**
|
||||
* This filter renders a scaled version of an image read from a
|
||||
* given URL. The image can be output as a GIF, JPEG or PNG image
|
||||
* or similar<!--,
|
||||
* with optional caching of the rendered image files-->.
|
||||
*
|
||||
* <hr>
|
||||
*
|
||||
* <p>
|
||||
* <A name="parameters"></A><STRONG>Parameters:</STRONG><BR>
|
||||
* </p>
|
||||
* <DL>
|
||||
* <DT>{@code scaleX}</DT>
|
||||
* <DD>integer, the new width of the image.
|
||||
* <DT>{@code scaleY}</DT>
|
||||
* <DD>integer, the new height of the image.
|
||||
* <DT>{@code scaleUniform}</DT>
|
||||
* <DD>boolean, wether or not uniform scalnig should be used. Default is
|
||||
* {@code true}.
|
||||
* <DT>{@code scaleUnits}</DT>
|
||||
* <DD>string, one of {@code PIXELS}, {@code PERCENT}.
|
||||
* {@code PIXELS} is default.
|
||||
* <DT>{@code scaleQuality}</DT>
|
||||
* <DD>string, one of {@code SCALE_SMOOTH}, {@code SCALE_FAST},
|
||||
* {@code SCALE_REPLICATE}, {@code SCALE_AREA_AVERAGING}.
|
||||
* {@code SCALE_DEFAULT} is default (see
|
||||
* {@link java.awt.Image#getScaledInstance(int,int,int)}, {@link java.awt.Image}
|
||||
* for more details).
|
||||
* </DL>
|
||||
* <p>
|
||||
* Examples:
|
||||
* </p>
|
||||
* <pre>
|
||||
* <IMG src="/scale/test.jpg?scaleX=500&scaleUniform=false">
|
||||
* <IMG src="/scale/test.png?scaleY=50&scaleUnits=PERCENT">
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: ScaleFilter.java#1 $
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public class ScaleFilter extends ImageFilter {
|
||||
|
||||
/**
|
||||
* Width and height are absolute pixels. The default.
|
||||
*/
|
||||
public static final int UNITS_PIXELS = 1;
|
||||
/**
|
||||
* Width and height are percentage of original width and height.
|
||||
*/
|
||||
public static final int UNITS_PERCENT = 5;
|
||||
/**
|
||||
* Ahh, good choice!
|
||||
*/
|
||||
//private static final int UNITS_METRIC = 42;
|
||||
/**
|
||||
* The root of all evil...
|
||||
*/
|
||||
//private static final int UNITS_INCHES = 666;
|
||||
/**
|
||||
* Unknown units. <!-- Oops, what now? -->
|
||||
*/
|
||||
public static final int UNITS_UNKNOWN = 0;
|
||||
|
||||
/**
|
||||
* {@code scaleQuality}
|
||||
*/
|
||||
protected final static String PARAM_SCALE_QUALITY = "scaleQuality";
|
||||
/**
|
||||
* {@code scaleUnits}
|
||||
*/
|
||||
protected final static String PARAM_SCALE_UNITS = "scaleUnits";
|
||||
/**
|
||||
* {@code scaleUniform}
|
||||
*/
|
||||
protected final static String PARAM_SCALE_UNIFORM = "scaleUniform";
|
||||
/**
|
||||
* {@code scaleX}
|
||||
*/
|
||||
protected final static String PARAM_SCALE_X = "scaleX";
|
||||
/**
|
||||
* {@code scaleY}
|
||||
*/
|
||||
protected final static String PARAM_SCALE_Y = "scaleY";
|
||||
/**
|
||||
* {@code image}
|
||||
*/
|
||||
protected final static String PARAM_IMAGE = "image";
|
||||
|
||||
/** */
|
||||
protected int defaultScaleQuality = Image.SCALE_DEFAULT;
|
||||
|
||||
/**
|
||||
* Reads the image from the requested URL, scales it, and returns it in the
|
||||
* Servlet stream. See above for details on parameters.
|
||||
*/
|
||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||
|
||||
// Get quality setting
|
||||
// SMOOTH | FAST | REPLICATE | DEFAULT | AREA_AVERAGING
|
||||
// See Image (mHints)
|
||||
int quality = getQuality(pRequest.getParameter(PARAM_SCALE_QUALITY));
|
||||
|
||||
// Get units, default is pixels
|
||||
// PIXELS | PERCENT | METRIC | INCHES
|
||||
int units = getUnits(pRequest.getParameter(PARAM_SCALE_UNITS));
|
||||
if (units == UNITS_UNKNOWN) {
|
||||
log("Unknown units for scale, returning original.");
|
||||
return pImage;
|
||||
}
|
||||
|
||||
// Use uniform scaling? Default is true
|
||||
boolean uniformScale = ServletUtil.getBooleanParameter(pRequest, PARAM_SCALE_UNIFORM, true);
|
||||
|
||||
// Get dimensions
|
||||
int width = ServletUtil.getIntParameter(pRequest, PARAM_SCALE_X, -1);
|
||||
int height = ServletUtil.getIntParameter(pRequest, PARAM_SCALE_Y, -1);
|
||||
|
||||
// Get dimensions for scaled image
|
||||
Dimension dim = getDimensions(pImage, width, height, units, uniformScale);
|
||||
|
||||
width = (int) dim.getWidth();
|
||||
height = (int) dim.getHeight();
|
||||
|
||||
// Return scaled instance directly
|
||||
return ImageUtil.createScaled(pImage, width, height, quality);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the quality constant for the scaling, from the string argument.
|
||||
*
|
||||
* @param pQualityStr The string representation of the scale quality
|
||||
* constant.
|
||||
* @return The matching quality constant, or the default quality if none
|
||||
* was found.
|
||||
* @see java.awt.Image
|
||||
* @see java.awt.Image#getScaledInstance(int,int,int)
|
||||
*/
|
||||
protected int getQuality(String pQualityStr) {
|
||||
if (!StringUtil.isEmpty(pQualityStr)) {
|
||||
try {
|
||||
// Get quality constant from Image using reflection
|
||||
Class cl = Image.class;
|
||||
Field field = cl.getField(pQualityStr.toUpperCase());
|
||||
|
||||
return field.getInt(null);
|
||||
}
|
||||
catch (IllegalAccessException ia) {
|
||||
log("Unable to get quality.", ia);
|
||||
}
|
||||
catch (NoSuchFieldException nsf) {
|
||||
log("Unable to get quality.", nsf);
|
||||
}
|
||||
}
|
||||
|
||||
return defaultScaleQuality;
|
||||
}
|
||||
|
||||
public void setDefaultScaleQuality(String pDefaultScaleQuality) {
|
||||
defaultScaleQuality = getQuality(pDefaultScaleQuality);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the units constant for the width and height arguments, from the
|
||||
* given string argument.
|
||||
*
|
||||
* @param pUnitStr The string representation of the units constant,
|
||||
* can be one of "PIXELS" or "PERCENT".
|
||||
* @return The mathcing units constant, or UNITS_UNKNOWN if none was found.
|
||||
*/
|
||||
protected int getUnits(String pUnitStr) {
|
||||
if (StringUtil.isEmpty(pUnitStr)
|
||||
|| pUnitStr.equalsIgnoreCase("PIXELS")) {
|
||||
return UNITS_PIXELS;
|
||||
}
|
||||
else if (pUnitStr.equalsIgnoreCase("PERCENT")) {
|
||||
return UNITS_PERCENT;
|
||||
}
|
||||
else {
|
||||
return UNITS_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the dimensions (height and width) of the scaled image. The
|
||||
* dimensions are computed based on the old image's dimensions, the units
|
||||
* used for specifying new dimensions and whether or not uniform scaling
|
||||
* should be used (se algorithm below).
|
||||
*
|
||||
* @param pImage the image to be scaled
|
||||
* @param pWidth the new width of the image, or -1 if unknown
|
||||
* @param pHeight the new height of the image, or -1 if unknown
|
||||
* @param pUnits the constant specifying units for width and height
|
||||
* parameter (UNITS_PIXELS or UNITS_PERCENT)
|
||||
* @param pUniformScale 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 Dimension getDimensions(Image pImage, int pWidth, int pHeight,
|
||||
int pUnits, boolean pUniformScale) {
|
||||
|
||||
// If uniform, make sure width and height are scaled the same ammount
|
||||
// (use ONLY height or ONLY width).
|
||||
//
|
||||
// Algoritm:
|
||||
// if uniform
|
||||
// if newHeight not set
|
||||
// find ratio newWidth / oldWidth
|
||||
// oldHeight *= ratio
|
||||
// else if newWidth not set
|
||||
// find ratio newWidth / oldWidth
|
||||
// oldHeight *= ratio
|
||||
// else
|
||||
// find both ratios and use the smallest one
|
||||
// (this will be the largest version of the image that fits
|
||||
// inside the rectangle given)
|
||||
// (if PERCENT, just use smallest percentage).
|
||||
//
|
||||
// If units is percent, we only need old height and width
|
||||
|
||||
int oldWidth = ImageUtil.getWidth(pImage);
|
||||
int oldHeight = ImageUtil.getHeight(pImage);
|
||||
float ratio;
|
||||
|
||||
if (pUnits == UNITS_PERCENT) {
|
||||
if (pWidth >= 0 && pHeight >= 0) {
|
||||
// Non-uniform
|
||||
pWidth = (int) ((float) oldWidth * (float) pWidth / 100f);
|
||||
pHeight = (int) ((float) oldHeight * (float) pHeight / 100f);
|
||||
}
|
||||
else if (pWidth >= 0) {
|
||||
// Find ratio from pWidth
|
||||
ratio = (float) pWidth / 100f;
|
||||
pWidth = (int) ((float) oldWidth * ratio);
|
||||
pHeight = (int) ((float) oldHeight * ratio);
|
||||
}
|
||||
else if (pHeight >= 0) {
|
||||
// Find ratio from pHeight
|
||||
ratio = (float) pHeight / 100f;
|
||||
pWidth = (int) ((float) oldWidth * ratio);
|
||||
pHeight = (int) ((float) oldHeight * ratio);
|
||||
}
|
||||
// Else: No scale
|
||||
}
|
||||
else if (pUnits == UNITS_PIXELS) {
|
||||
if (pUniformScale) {
|
||||
if (pWidth >= 0 && pHeight >= 0) {
|
||||
// Compute both ratios
|
||||
ratio = (float) pWidth / (float) oldWidth;
|
||||
float heightRatio = (float) pHeight / (float) oldHeight;
|
||||
|
||||
// Find the largest ratio, and use that for both
|
||||
if (heightRatio < ratio) {
|
||||
ratio = heightRatio;
|
||||
pWidth = (int) ((float) oldWidth * ratio);
|
||||
}
|
||||
else {
|
||||
pHeight = (int) ((float) oldHeight * ratio);
|
||||
}
|
||||
|
||||
}
|
||||
else if (pWidth >= 0) {
|
||||
// Find ratio from pWidth
|
||||
ratio = (float) pWidth / (float) oldWidth;
|
||||
pHeight = (int) ((float) oldHeight * ratio);
|
||||
}
|
||||
else if (pHeight >= 0) {
|
||||
// Find ratio from pHeight
|
||||
ratio = (float) pHeight / (float) oldHeight;
|
||||
pWidth = (int) ((float) oldWidth * ratio);
|
||||
}
|
||||
// Else: No scale
|
||||
}
|
||||
}
|
||||
|
||||
// Default is no scale, just work as a proxy
|
||||
if (pWidth < 0) {
|
||||
pWidth = oldWidth;
|
||||
}
|
||||
if (pHeight < 0) {
|
||||
pHeight = oldHeight;
|
||||
}
|
||||
|
||||
// Create new Dimension object and return
|
||||
return new Dimension(pWidth, pHeight);
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import com.twelvemonkeys.servlet.ServletUtil;
|
||||
|
||||
/**
|
||||
* A {@link javax.servlet.Filter} that extracts request parameters, and sets the
|
||||
* corresponding request attributes from {@link ImageServletResponse}.
|
||||
* Only affects how the image is decoded, and must be applied before any
|
||||
* other image filters in the chain.
|
||||
*
|
||||
* @see ImageServletResponse#ATTRIB_SIZE
|
||||
* @see ImageServletResponse#ATTRIB_AOI
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: SourceRenderFilter.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
public class SourceRenderFilter extends ImageFilter {
|
||||
private String sizeWidthParam = "size.w";
|
||||
private String sizeHeightParam = "size.h";
|
||||
private String sizePercentParam = "size.percent";
|
||||
private String sizeUniformParam = "size.uniform";
|
||||
|
||||
private String regionWidthParam = "aoi.w";
|
||||
private String regionHeightParam = "aoi.h";
|
||||
private String regionLeftParam = "aoi.x";
|
||||
private String regionTopParam = "aoi.y";
|
||||
private String regionPercentParam = "aoi.percent";
|
||||
private String regionUniformParam = "aoi.uniform";
|
||||
|
||||
public void setRegionHeightParam(String pRegionHeightParam) {
|
||||
regionHeightParam = pRegionHeightParam;
|
||||
}
|
||||
|
||||
public void setRegionWidthParam(String pRegionWidthParam) {
|
||||
regionWidthParam = pRegionWidthParam;
|
||||
}
|
||||
|
||||
public void setRegionLeftParam(String pRegionLeftParam) {
|
||||
regionLeftParam = pRegionLeftParam;
|
||||
}
|
||||
|
||||
public void setRegionTopParam(String pRegionTopParam) {
|
||||
regionTopParam = pRegionTopParam;
|
||||
}
|
||||
|
||||
public void setSizeHeightParam(String pSizeHeightParam) {
|
||||
sizeHeightParam = pSizeHeightParam;
|
||||
}
|
||||
|
||||
public void setSizeWidthParam(String pSizeWidthParam) {
|
||||
sizeWidthParam = pSizeWidthParam;
|
||||
}
|
||||
|
||||
public void setRegionPercentParam(String pRegionPercentParam) {
|
||||
regionPercentParam = pRegionPercentParam;
|
||||
}
|
||||
|
||||
public void setRegionUniformParam(String pRegionUniformParam) {
|
||||
regionUniformParam = pRegionUniformParam;
|
||||
}
|
||||
|
||||
public void setSizePercentParam(String pSizePercentParam) {
|
||||
sizePercentParam = pSizePercentParam;
|
||||
}
|
||||
|
||||
public void setSizeUniformParam(String pSizeUniformParam) {
|
||||
sizeUniformParam = pSizeUniformParam;
|
||||
}
|
||||
|
||||
public void init() throws ServletException {
|
||||
if (triggerParams == null) {
|
||||
// Add all params as triggers
|
||||
triggerParams = new String[]{sizeWidthParam, sizeHeightParam,
|
||||
sizeUniformParam, sizePercentParam,
|
||||
regionLeftParam, regionTopParam,
|
||||
regionWidthParam, regionHeightParam,
|
||||
regionUniformParam, regionPercentParam};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts request parameters, and sets the corresponding request
|
||||
* attributes if specified.
|
||||
*
|
||||
* @param pRequest
|
||||
* @param pResponse
|
||||
* @param pChain
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||
// TODO: Max size configuration, to avoid DOS attacks? OutOfMemory
|
||||
|
||||
// Size parameters
|
||||
int width = ServletUtil.getIntParameter(pRequest, sizeWidthParam, -1);
|
||||
int height = ServletUtil.getIntParameter(pRequest, sizeHeightParam, -1);
|
||||
if (width > 0 || height > 0) {
|
||||
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE, new Dimension(width, height));
|
||||
}
|
||||
|
||||
// Size uniform/percent
|
||||
boolean uniform = ServletUtil.getBooleanParameter(pRequest, sizeUniformParam, true);
|
||||
if (!uniform) {
|
||||
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_UNIFORM, Boolean.FALSE);
|
||||
}
|
||||
boolean percent = ServletUtil.getBooleanParameter(pRequest, sizePercentParam, false);
|
||||
if (percent) {
|
||||
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_PERCENT, Boolean.TRUE);
|
||||
}
|
||||
|
||||
// Area of interest parameters
|
||||
int x = ServletUtil.getIntParameter(pRequest, regionLeftParam, -1); // Default is center
|
||||
int y = ServletUtil.getIntParameter(pRequest, regionTopParam, -1); // Default is center
|
||||
width = ServletUtil.getIntParameter(pRequest, regionWidthParam, -1);
|
||||
height = ServletUtil.getIntParameter(pRequest, regionHeightParam, -1);
|
||||
if (width > 0 || height > 0) {
|
||||
pRequest.setAttribute(ImageServletResponse.ATTRIB_AOI, new Rectangle(x, y, width, height));
|
||||
}
|
||||
|
||||
// AOI uniform/percent
|
||||
uniform = ServletUtil.getBooleanParameter(pRequest, regionUniformParam, false);
|
||||
if (uniform) {
|
||||
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_UNIFORM, Boolean.TRUE);
|
||||
}
|
||||
percent = ServletUtil.getBooleanParameter(pRequest, regionPercentParam, false);
|
||||
if (percent) {
|
||||
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_PERCENT, Boolean.TRUE);
|
||||
}
|
||||
|
||||
super.doFilterImpl(pRequest, pResponse, pChain);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation does no filtering, and simply returns the image
|
||||
* passed in.
|
||||
*
|
||||
* @param pImage
|
||||
* @param pRequest
|
||||
* @param pResponse
|
||||
* @return {@code pImage}
|
||||
*/
|
||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||
return pImage;
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image.aoi;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:erlend@escenic.com">Erlend Hamnaberg</a>
|
||||
* @version $Revision: $
|
||||
*/
|
||||
@Deprecated
|
||||
public interface AreaOfInterest {
|
||||
|
||||
Rectangle getAOI(Rectangle pCrop);
|
||||
|
||||
Dimension getOriginalDimension();
|
||||
|
||||
int calculateX(Dimension pOriginalDimension, Rectangle pCrop);
|
||||
|
||||
int calculateY(Dimension pOriginalDimension, Rectangle pCrop);
|
||||
|
||||
Dimension getCrop(Dimension pOriginalDimension, Rectangle pCrop);
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image.aoi;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:erlend@escenic.com">Erlend Hamnaberg</a>
|
||||
* @version $Revision: $
|
||||
*/
|
||||
@Deprecated
|
||||
public class AreaOfInterestFactory {
|
||||
private final static AtomicReference<AreaOfInterestFactory> DEFAULT =
|
||||
new AtomicReference<AreaOfInterestFactory>(new AreaOfInterestFactory());
|
||||
|
||||
public static void setDefault(AreaOfInterestFactory factory) {
|
||||
DEFAULT.set(factory);
|
||||
}
|
||||
|
||||
public static AreaOfInterestFactory getDefault() {
|
||||
return DEFAULT.get();
|
||||
}
|
||||
|
||||
public AreaOfInterest createAreaOfInterest(int pDefaultWidth, int pDefaultHeight, boolean aoiPercent, boolean aoiUniform) {
|
||||
if (aoiPercent && aoiUniform) {
|
||||
throw new IllegalArgumentException("Cannot be both uniform and percent Area of Interest");
|
||||
}
|
||||
if (aoiPercent) {
|
||||
return new PercentAreaOfInterest(pDefaultWidth, pDefaultHeight);
|
||||
}
|
||||
else if (aoiUniform) {
|
||||
return new UniformAreaOfInterest(pDefaultWidth, pDefaultHeight);
|
||||
}
|
||||
return new DefaultAreaOfInterest(pDefaultWidth, pDefaultHeight);
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image.aoi;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:erlend@escenic.com">Erlend Hamnaberg</a>
|
||||
* @version $Revision: $
|
||||
*/
|
||||
@Deprecated
|
||||
public class AreaOfInterestWrapper implements AreaOfInterest {
|
||||
private AreaOfInterest mDelegate;
|
||||
|
||||
public AreaOfInterestWrapper(AreaOfInterest mDelegate) {
|
||||
this.mDelegate = Validate.notNull(mDelegate);
|
||||
}
|
||||
|
||||
public Rectangle getAOI(Rectangle pCrop) {
|
||||
return mDelegate.getAOI(pCrop);
|
||||
}
|
||||
|
||||
public Dimension getOriginalDimension() {
|
||||
return mDelegate.getOriginalDimension();
|
||||
}
|
||||
|
||||
public int calculateX(Dimension pOriginalDimension, Rectangle pCrop) {
|
||||
return mDelegate.calculateX(pOriginalDimension, pCrop);
|
||||
}
|
||||
|
||||
public int calculateY(Dimension pOriginalDimension, Rectangle pCrop) {
|
||||
return mDelegate.calculateY(pOriginalDimension, pCrop);
|
||||
}
|
||||
|
||||
public Dimension getCrop(Dimension pOriginalDimension, Rectangle pCrop) {
|
||||
return mDelegate.getCrop(pOriginalDimension, pCrop);
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image.aoi;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author <a href="mailto:erlend@hamnaberg.net">Erlend Hamnaberg</a>
|
||||
* @version $Revision: $
|
||||
*/
|
||||
@Deprecated
|
||||
public class DefaultAreaOfInterest implements AreaOfInterest {
|
||||
private final int mOriginalWidth;
|
||||
private final int mOriginalHeight;
|
||||
|
||||
public DefaultAreaOfInterest(int pOriginalWidth, int pOriginalHeight) {
|
||||
this.mOriginalWidth = pOriginalWidth;
|
||||
this.mOriginalHeight = pOriginalHeight;
|
||||
}
|
||||
|
||||
public DefaultAreaOfInterest(Dimension pOriginalDimension) {
|
||||
this(pOriginalDimension.width, pOriginalDimension.height);
|
||||
}
|
||||
|
||||
Rectangle getAOI(final int pX, final int pY, final int pWidth, final int pHeight) {
|
||||
return getAOI(new Rectangle(pX, pY, pWidth, pHeight));
|
||||
}
|
||||
|
||||
public Rectangle getAOI(final Rectangle pCrop) {
|
||||
int y = pCrop.y;
|
||||
int x = pCrop.x;
|
||||
Dimension dimension = getOriginalDimension();
|
||||
|
||||
Dimension crop = getCrop(dimension, pCrop);
|
||||
|
||||
// Center
|
||||
if (y < 0) {
|
||||
y = calculateY(dimension, new Rectangle(x, y, crop.width, crop.height));
|
||||
}
|
||||
|
||||
if (x < 0) {
|
||||
x = calculateX(dimension, new Rectangle(x, y, crop.width, crop.height));
|
||||
}
|
||||
return new Rectangle(x, y, crop.width, crop.height);
|
||||
}
|
||||
|
||||
public Dimension getOriginalDimension() {
|
||||
return new Dimension(mOriginalWidth, mOriginalHeight);
|
||||
}
|
||||
|
||||
public int calculateX(Dimension pOriginalDimension, Rectangle pCrop) {
|
||||
return (pOriginalDimension.width - pCrop.width) / 2;
|
||||
}
|
||||
|
||||
public int calculateY(Dimension pOriginalDimension, Rectangle pCrop) {
|
||||
return (pOriginalDimension.height - pCrop.height) / 2;
|
||||
}
|
||||
|
||||
public Dimension getCrop(Dimension pOriginalDimension, final Rectangle pCrop) {
|
||||
int mOriginalWidth1 = pOriginalDimension.width;
|
||||
int mOriginalHeight1 = pOriginalDimension.height;
|
||||
int x = pCrop.x;
|
||||
int y = pCrop.y;
|
||||
int cropWidth = pCrop.width;
|
||||
int cropHeight = pCrop.height;
|
||||
|
||||
if (cropWidth < 0 || (x < 0 && cropWidth > mOriginalWidth1)
|
||||
|| (x >= 0 && (x + cropWidth) > mOriginalWidth1)) {
|
||||
cropWidth = (x >= 0 ? mOriginalWidth1 - x : mOriginalWidth1);
|
||||
}
|
||||
if (cropHeight < 0 || (y < 0 && cropHeight > mOriginalHeight1)
|
||||
|| (y >= 0 && (y + cropHeight) > mOriginalHeight1)) {
|
||||
cropHeight = (y >= 0 ? mOriginalHeight1 - y : mOriginalHeight1);
|
||||
}
|
||||
return new Dimension(cropWidth, cropHeight);
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image.aoi;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:erlend@escenic.com">Erlend Hamnaberg</a>
|
||||
* @version $Revision: $
|
||||
*/
|
||||
@Deprecated
|
||||
public class PercentAreaOfInterest extends DefaultAreaOfInterest {
|
||||
|
||||
public PercentAreaOfInterest(Dimension pOriginalDimension) {
|
||||
super(pOriginalDimension);
|
||||
}
|
||||
|
||||
public PercentAreaOfInterest(int pOriginalWidth, int pOriginalHeight) {
|
||||
super(pOriginalWidth, pOriginalHeight);
|
||||
}
|
||||
|
||||
public Dimension getCrop(Dimension pOriginalDimension, final Rectangle pCrop) {
|
||||
int cropWidth = pCrop.width;
|
||||
int cropHeight = pCrop.height;
|
||||
float ratio;
|
||||
|
||||
if (cropWidth >= 0 && cropHeight >= 0) {
|
||||
// Non-uniform
|
||||
cropWidth = Math.round((float) pOriginalDimension.width * (float) pCrop.width / 100f);
|
||||
cropHeight = Math.round((float) pOriginalDimension.height * (float) pCrop.height / 100f);
|
||||
}
|
||||
else if (cropWidth >= 0) {
|
||||
// Find ratio from pWidth
|
||||
ratio = (float) cropWidth / 100f;
|
||||
cropWidth = Math.round((float) pOriginalDimension.width * ratio);
|
||||
cropHeight = Math.round((float) pOriginalDimension.height * ratio);
|
||||
|
||||
}
|
||||
else if (cropHeight >= 0) {
|
||||
// Find ratio from pHeight
|
||||
ratio = (float) cropHeight / 100f;
|
||||
cropWidth = Math.round((float) pOriginalDimension.width * ratio);
|
||||
cropHeight = Math.round((float) pOriginalDimension.height * ratio);
|
||||
}
|
||||
// Else: No crop
|
||||
|
||||
return new Dimension(cropWidth, cropHeight);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image.aoi;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:erlend@escenic.com">Erlend Hamnaberg</a>
|
||||
* @version $Revision: $
|
||||
*/
|
||||
@Deprecated
|
||||
public class UniformAreaOfInterest extends DefaultAreaOfInterest {
|
||||
|
||||
public UniformAreaOfInterest(Dimension pOriginalDimension) {
|
||||
super(pOriginalDimension);
|
||||
}
|
||||
|
||||
public UniformAreaOfInterest(int pOriginalWidth, int pOriginalHeight) {
|
||||
super(pOriginalWidth, pOriginalHeight);
|
||||
}
|
||||
|
||||
public Dimension getCrop(Dimension pOriginalDimension, final Rectangle pCrop) {
|
||||
float ratio;
|
||||
if (pCrop.width >= 0 && pCrop.height >= 0) {
|
||||
// Compute both ratios
|
||||
ratio = (float) pCrop.width / (float) pCrop.height;
|
||||
float originalRatio = (float) pOriginalDimension.width / (float) pOriginalDimension.height;
|
||||
if (ratio > originalRatio) {
|
||||
pCrop.width = pOriginalDimension.width;
|
||||
pCrop.height = Math.round((float) pOriginalDimension.width / ratio);
|
||||
}
|
||||
else {
|
||||
pCrop.height = pOriginalDimension.height;
|
||||
pCrop.width = Math.round((float) pOriginalDimension.height * ratio);
|
||||
}
|
||||
}
|
||||
else if (pCrop.width >= 0) {
|
||||
// Find ratio from pWidth
|
||||
ratio = (float) pCrop.width / (float) pOriginalDimension.width;
|
||||
pCrop.height = Math.round((float) pOriginalDimension.height * ratio);
|
||||
}
|
||||
else if (pCrop.height >= 0) {
|
||||
// Find ratio from pHeight
|
||||
ratio = (float) pCrop.height / (float) pOriginalDimension.height;
|
||||
pCrop.width = Math.round((float) pOriginalDimension.width * ratio);
|
||||
}
|
||||
// Else: No crop
|
||||
return new Dimension(pCrop.width, pCrop.height);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* Copyright (c) 2021, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -29,35 +29,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Contains various image-outputting filters, that should run under any
|
||||
* servlet engine.
|
||||
* <P>
|
||||
* 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
|
||||
* run with JRE <STRONG>1.4</STRONG> or later, and with the option:
|
||||
* <DL>
|
||||
* <DD>{@code -Djawa.awt.headless=true}</DD>
|
||||
* </DL>
|
||||
* See the document
|
||||
* <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.
|
||||
* <P>
|
||||
* If you cannot use JRE 1.4 or later, or do not want to use the X
|
||||
* libraries, one possibility is to use the
|
||||
* <A href="http://www.eteks.com/pja/en/">PJA package</A> (com.eteks.pja),
|
||||
* and start the JVM with the following options:
|
||||
* <DL>
|
||||
* <DD>{@code -Xbootclasspath/a:<path to pja.jar>}</DD>
|
||||
* <DD>{@code -Dawt.toolkit=com.eteks.awt.PJAToolkit}</DD>
|
||||
* <DD>{@code -Djava.awt.graphicsenv=com.eteks.java2d.PJAGraphicsEnvironment}</DD>
|
||||
* <DD>{@code -Djava.awt.fonts=<path where True Type fonts files will be loaded from>}</DD>
|
||||
* </DL>
|
||||
* <P>
|
||||
* Please note that creation of PNG images (from bytes or URL's) are only
|
||||
* supported in JRE 1.3 and later, trying to load them from an earlier version,
|
||||
* will result in errors.
|
||||
*
|
||||
* @see com.twelvemonkeys.servlet.image.ImageServlet
|
||||
* @see com.twelvemonkeys.servlet.image.ImagePainterServlet
|
||||
* Contains the context listener required for bundling ImageIO plugins
|
||||
* inside a web application.
|
||||
*/
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Contains servlet support classes.
|
||||
*/
|
||||
package com.twelvemonkeys.servlet;
|
||||
@@ -1,469 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import com.twelvemonkeys.lang.ObjectAbstractTest;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.servlet.*;
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* FilterAbstractTestCase
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/FilterAbstractTestCase.java#1 $
|
||||
*/
|
||||
public abstract class FilterAbstractTest extends ObjectAbstractTest {
|
||||
protected Object makeObject() {
|
||||
return makeFilter();
|
||||
}
|
||||
|
||||
protected abstract Filter makeFilter();
|
||||
|
||||
// TODO: Is it a good thing to have an API like this?
|
||||
protected FilterConfig makeFilterConfig() {
|
||||
return makeFilterConfig(new HashMap());
|
||||
}
|
||||
|
||||
protected FilterConfig makeFilterConfig(Map pParams) {
|
||||
return new MockFilterConfig(pParams);
|
||||
}
|
||||
|
||||
protected ServletRequest makeRequest() {
|
||||
return new MockServletRequest();
|
||||
}
|
||||
|
||||
protected ServletResponse makeResponse() {
|
||||
return new MockServletResponse();
|
||||
}
|
||||
|
||||
protected FilterChain makeFilterChain() {
|
||||
return new MockFilterChain();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitNull() {
|
||||
Filter filter = makeFilter();
|
||||
|
||||
// The spec seems to be a little unclear on this issue, but anyway,
|
||||
// the container should never invoke init(null)...
|
||||
try {
|
||||
filter.init(null);
|
||||
fail("Should throw Exception on init(null)");
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
// Good
|
||||
}
|
||||
catch (NullPointerException e) {
|
||||
// Bad (but not unreasonable)
|
||||
}
|
||||
catch (ServletException e) {
|
||||
// Hmmm.. The jury is still out.
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInit() {
|
||||
Filter filter = makeFilter();
|
||||
|
||||
try {
|
||||
filter.init(makeFilterConfig());
|
||||
}
|
||||
catch (ServletException e) {
|
||||
assertNotNull(e.getMessage());
|
||||
}
|
||||
finally {
|
||||
filter.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifeCycle() throws ServletException {
|
||||
Filter filter = makeFilter();
|
||||
|
||||
try {
|
||||
filter.init(makeFilterConfig());
|
||||
}
|
||||
finally {
|
||||
filter.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterBasic() throws ServletException, IOException {
|
||||
Filter filter = makeFilter();
|
||||
|
||||
try {
|
||||
filter.init(makeFilterConfig());
|
||||
|
||||
filter.doFilter(makeRequest(), makeResponse(), makeFilterChain());
|
||||
}
|
||||
finally {
|
||||
filter.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDestroy() {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
static class MockFilterConfig implements FilterConfig {
|
||||
private final Map<String, String> params;
|
||||
|
||||
MockFilterConfig(Map<String, String> pParams) {
|
||||
if (pParams == null) {
|
||||
throw new IllegalArgumentException("params == null");
|
||||
}
|
||||
params = pParams;
|
||||
}
|
||||
|
||||
public String getFilterName() {
|
||||
return "mock-filter";
|
||||
}
|
||||
|
||||
public String getInitParameter(String pName) {
|
||||
return params.get(pName);
|
||||
}
|
||||
|
||||
public Enumeration getInitParameterNames() {
|
||||
return Collections.enumeration(params.keySet());
|
||||
}
|
||||
|
||||
public ServletContext getServletContext() {
|
||||
return new MockServletContext();
|
||||
}
|
||||
|
||||
private static class MockServletContext implements ServletContext {
|
||||
private final Map<String, Object> attributes;
|
||||
private final Map<String, String> params;
|
||||
|
||||
MockServletContext() {
|
||||
attributes = new HashMap<>();
|
||||
params = new HashMap<>();
|
||||
}
|
||||
|
||||
public Object getAttribute(String s) {
|
||||
return attributes.get(s);
|
||||
}
|
||||
|
||||
public Enumeration getAttributeNames() {
|
||||
return Collections.enumeration(attributes.keySet());
|
||||
}
|
||||
|
||||
public ServletContext getContext(String s) {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getInitParameter(String s) {
|
||||
return params.get(s);
|
||||
}
|
||||
|
||||
public Enumeration getInitParameterNames() {
|
||||
return Collections.enumeration(params.keySet());
|
||||
}
|
||||
|
||||
public int getMajorVersion() {
|
||||
return 0; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getMimeType(String s) {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public int getMinorVersion() {
|
||||
return 0; // TODO: Implement
|
||||
}
|
||||
|
||||
public RequestDispatcher getNamedDispatcher(String s) {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getRealPath(String s) {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public RequestDispatcher getRequestDispatcher(String s) {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public URL getResource(String s) throws MalformedURLException {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public InputStream getResourceAsStream(String s) {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public Set getResourcePaths(String s) {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getServerInfo() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public Servlet getServlet(String s) throws ServletException {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getServletContextName() {
|
||||
return "mock";
|
||||
}
|
||||
|
||||
public Enumeration getServletNames() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public Enumeration getServlets() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public void log(Exception exception, String s) {
|
||||
}
|
||||
|
||||
public void log(String s) {
|
||||
}
|
||||
|
||||
public void log(String s, Throwable throwable) {
|
||||
}
|
||||
|
||||
public void removeAttribute(String s) {
|
||||
attributes.remove(s);
|
||||
}
|
||||
|
||||
public void setAttribute(String s, Object obj) {
|
||||
attributes.put(s, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class MockServletRequest implements ServletRequest {
|
||||
final private Map<String, Object> attributes;
|
||||
|
||||
public MockServletRequest() {
|
||||
attributes = new HashMap<String, Object>();
|
||||
}
|
||||
|
||||
public Object getAttribute(String pKey) {
|
||||
return attributes.get(pKey);
|
||||
}
|
||||
|
||||
public Enumeration getAttributeNames() {
|
||||
return Collections.enumeration(attributes.keySet());
|
||||
}
|
||||
|
||||
public String getCharacterEncoding() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public void setCharacterEncoding(String pMessage) throws UnsupportedEncodingException {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
public int getContentLength() {
|
||||
return 0; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getParameter(String pMessage) {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public Enumeration getParameterNames() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public String[] getParameterValues(String pMessage) {
|
||||
return new String[0]; // TODO: Implement
|
||||
}
|
||||
|
||||
public Map getParameterMap() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getScheme() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public int getServerPort() {
|
||||
return 0; // TODO: Implement
|
||||
}
|
||||
|
||||
public BufferedReader getReader() throws IOException {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getRemoteAddr() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getRemoteHost() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public void setAttribute(String pKey, Object pValue) {
|
||||
attributes.put(pKey, pValue);
|
||||
}
|
||||
|
||||
public void removeAttribute(String pKey) {
|
||||
attributes.remove(pKey);
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public Enumeration getLocales() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public boolean isSecure() {
|
||||
return false; // TODO: Implement
|
||||
}
|
||||
|
||||
public RequestDispatcher getRequestDispatcher(String pMessage) {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getRealPath(String pMessage) {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public int getRemotePort() {
|
||||
throw new UnsupportedOperationException("Method getRemotePort not implemented");// TODO: Implement
|
||||
}
|
||||
|
||||
public String getLocalName() {
|
||||
throw new UnsupportedOperationException("Method getLocalName not implemented");// TODO: Implement
|
||||
}
|
||||
|
||||
public String getLocalAddr() {
|
||||
throw new UnsupportedOperationException("Method getLocalAddr not implemented");// TODO: Implement
|
||||
}
|
||||
|
||||
public int getLocalPort() {
|
||||
throw new UnsupportedOperationException("Method getLocalPort not implemented");// TODO: Implement
|
||||
}
|
||||
}
|
||||
|
||||
static class MockServletResponse implements ServletResponse {
|
||||
public void flushBuffer() throws IOException {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
public int getBufferSize() {
|
||||
return 0; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getCharacterEncoding() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
throw new UnsupportedOperationException("Method getContentType not implemented");// TODO: Implement
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public ServletOutputStream getOutputStream() throws IOException {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public PrintWriter getWriter() throws IOException {
|
||||
return null; // TODO: Implement
|
||||
}
|
||||
|
||||
public void setCharacterEncoding(String charset) {
|
||||
throw new UnsupportedOperationException("Method setCharacterEncoding not implemented");// TODO: Implement
|
||||
}
|
||||
|
||||
public boolean isCommitted() {
|
||||
return false; // TODO: Implement
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
public void resetBuffer() {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
public void setBufferSize(int pLength) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
public void setContentLength(int pLength) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
public void setContentType(String pMessage) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
public void setLocale(Locale pLocale) {
|
||||
// TODO: Implement
|
||||
}
|
||||
}
|
||||
|
||||
static class MockFilterChain implements FilterChain {
|
||||
public void doFilter(ServletRequest pRequest, ServletResponse pResponse) throws IOException, ServletException {
|
||||
// TODO: Implement
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.servlet.*;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* GenericFilterTestCase
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/GenericFilterTestCase.java#1 $
|
||||
*/
|
||||
public final class GenericFilterTest extends FilterAbstractTest {
|
||||
protected Filter makeFilter() {
|
||||
return new GenericFilterImpl();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitOncePerRequest() {
|
||||
// Default FALSE
|
||||
GenericFilter filter = new GenericFilterImpl();
|
||||
|
||||
try {
|
||||
filter.init(makeFilterConfig());
|
||||
}
|
||||
catch (ServletException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertFalse("OncePerRequest should default to false", filter.oncePerRequest);
|
||||
filter.destroy();
|
||||
|
||||
// TRUE
|
||||
filter = new GenericFilterImpl();
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("once-per-request", "true");
|
||||
|
||||
try {
|
||||
filter.init(makeFilterConfig(params));
|
||||
}
|
||||
catch (ServletException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertTrue("oncePerRequest should be true", filter.oncePerRequest);
|
||||
filter.destroy();
|
||||
|
||||
// TRUE
|
||||
filter = new GenericFilterImpl();
|
||||
params = new HashMap<>();
|
||||
params.put("oncePerRequest", "true");
|
||||
|
||||
try {
|
||||
filter.init(makeFilterConfig(params));
|
||||
}
|
||||
catch (ServletException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertTrue("oncePerRequest should be true", filter.oncePerRequest);
|
||||
filter.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterOnlyOnce() {
|
||||
final GenericFilterImpl filter = new GenericFilterImpl();
|
||||
filter.setOncePerRequest(true);
|
||||
|
||||
try {
|
||||
filter.init(makeFilterConfig());
|
||||
}
|
||||
catch (ServletException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
FilterChain chain = new MyFilterChain(new Filter[] {filter, filter, filter});
|
||||
|
||||
try {
|
||||
chain.doFilter(makeRequest(), makeResponse());
|
||||
}
|
||||
catch (IOException | ServletException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals("Filter was invoked more than once!", 1, filter.invocationCount);
|
||||
|
||||
filter.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterMultiple() {
|
||||
final GenericFilterImpl filter = new GenericFilterImpl();
|
||||
|
||||
try {
|
||||
filter.init(makeFilterConfig());
|
||||
}
|
||||
catch (ServletException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
FilterChain chain = new MyFilterChain(new Filter[] {
|
||||
filter, filter, filter, filter, filter
|
||||
});
|
||||
|
||||
try {
|
||||
chain.doFilter(makeRequest(), makeResponse());
|
||||
}
|
||||
catch (IOException | ServletException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals("Filter was invoked not invoked five times!", 5, filter.invocationCount);
|
||||
|
||||
filter.destroy();
|
||||
}
|
||||
|
||||
private static class GenericFilterImpl extends GenericFilter {
|
||||
int invocationCount;
|
||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||
invocationCount++;
|
||||
pChain.doFilter(pRequest, pResponse);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyFilterChain implements FilterChain {
|
||||
|
||||
Filter[] mFilters;
|
||||
int mCurrentFilter;
|
||||
|
||||
public MyFilterChain(Filter[] pFilters) {
|
||||
if (pFilters == null) {
|
||||
throw new IllegalArgumentException("filters == null");
|
||||
}
|
||||
mFilters = pFilters;
|
||||
mCurrentFilter = 0;
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest pRequest, ServletResponse pResponse) throws IOException, ServletException {
|
||||
if (mCurrentFilter < mFilters.length) {
|
||||
mFilters[mCurrentFilter++].doFilter(pRequest, pResponse, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import com.twelvemonkeys.util.MapAbstractTest;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* ServletConfigMapAdapterTestCase
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: ServletAttributesMapAdapterTestCase.java#1 $
|
||||
*/
|
||||
public class ServletAttributesMapAdapterContextTest extends MapAbstractTest {
|
||||
private static final String ATTRIB_VALUE_ETAG = "\"1234567890abcdef\"";
|
||||
private static final Date ATTRIB_VALUE_DATE = new Date();
|
||||
private static final List<Integer> ATTRIB_VALUE_FOO = Arrays.asList(1, 2);
|
||||
|
||||
@Override
|
||||
public boolean isTestSerialization() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowNullKey() {
|
||||
return false; // Makes no sense...
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowNullValue() {
|
||||
return false; // Should be allowed, but the tests don't handle the put(foo, null) == remove(foo) semantics
|
||||
}
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
MockServletContextImpl context = mock(MockServletContextImpl.class, Mockito.CALLS_REAL_METHODS);
|
||||
context.attributes = createAttributes(false);
|
||||
|
||||
return new ServletAttributesMapAdapter(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map makeFullMap() {
|
||||
MockServletContextImpl context = mock(MockServletContextImpl.class, Mockito.CALLS_REAL_METHODS);
|
||||
context.attributes = createAttributes(true);
|
||||
|
||||
return new ServletAttributesMapAdapter(context);
|
||||
}
|
||||
|
||||
private Map<String, Object> createAttributes(boolean initialValues) {
|
||||
Map<String, Object> map = new ConcurrentHashMap<>();
|
||||
|
||||
if (initialValues) {
|
||||
String[] sampleKeys = (String[]) getSampleKeys();
|
||||
for (int i = 0; i < sampleKeys.length; i++) {
|
||||
map.put(sampleKeys[i], getSampleValues()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getSampleKeys() {
|
||||
return new String[] {"Date", "ETag", "X-Foo"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getSampleValues() {
|
||||
return new Object[] {ATTRIB_VALUE_DATE, ATTRIB_VALUE_ETAG, ATTRIB_VALUE_FOO};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getNewSampleValues() {
|
||||
// Needs to be same length but different values
|
||||
return new Object[] {new Date(-1L), "foo/bar", Arrays.asList(2, 3, 4)};
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void testMapPutNullValue() {
|
||||
// Special null semantics
|
||||
resetFull();
|
||||
|
||||
int size = map.size();
|
||||
String key = getClass().getName() + ".someNewKey";
|
||||
map.put(key, null);
|
||||
assertEquals(size, map.size());
|
||||
assertFalse(map.containsKey(key));
|
||||
|
||||
map.put(getSampleKeys()[0], null);
|
||||
assertEquals(size - 1, map.size());
|
||||
assertFalse(map.containsKey(getSampleKeys()[0]));
|
||||
|
||||
map.remove(getSampleKeys()[1]);
|
||||
assertEquals(size - 2, map.size());
|
||||
assertFalse(map.containsKey(getSampleKeys()[1]));
|
||||
}
|
||||
|
||||
private static abstract class MockServletContextImpl implements ServletContext {
|
||||
Map<String, Object> attributes;
|
||||
|
||||
public Object getAttribute(String name) {
|
||||
return attributes.get(name);
|
||||
}
|
||||
|
||||
public Enumeration getAttributeNames() {
|
||||
return Collections.enumeration(attributes.keySet());
|
||||
}
|
||||
|
||||
public void setAttribute(String name, Object o) {
|
||||
if (o == null) {
|
||||
attributes.remove(name);
|
||||
}
|
||||
else {
|
||||
attributes.put(name, o);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAttribute(String name) {
|
||||
attributes.remove(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import com.twelvemonkeys.util.MapAbstractTest;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* ServletConfigMapAdapterTestCase
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: ServletAttributesMapAdapterTestCase.java#1 $
|
||||
*/
|
||||
public class ServletAttributesMapAdapterRequestTest extends MapAbstractTest {
|
||||
private static final String ATTRIB_VALUE_ETAG = "\"1234567890abcdef\"";
|
||||
private static final Date ATTRIB_VALUE_DATE = new Date();
|
||||
private static final List<Integer> ATTRIB_VALUE_FOO = Arrays.asList(1, 2);
|
||||
|
||||
@Override
|
||||
public boolean isTestSerialization() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowNullKey() {
|
||||
return false; // Makes no sense...
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowNullValue() {
|
||||
return false; // Should be allowed, but the tests don't handle the put(foo, null) == remove(foo) semantics
|
||||
}
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
MockServletRequestImpl request = mock(MockServletRequestImpl.class, Mockito.CALLS_REAL_METHODS);
|
||||
request.attributes = createAttributes(false);
|
||||
|
||||
return new ServletAttributesMapAdapter(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map makeFullMap() {
|
||||
MockServletRequestImpl request = mock(MockServletRequestImpl.class, Mockito.CALLS_REAL_METHODS);
|
||||
request.attributes = createAttributes(true);
|
||||
|
||||
return new ServletAttributesMapAdapter(request);
|
||||
}
|
||||
|
||||
private Map<String, Object> createAttributes(boolean initialValues) {
|
||||
Map<String, Object> map = new ConcurrentHashMap<>();
|
||||
|
||||
if (initialValues) {
|
||||
String[] sampleKeys = (String[]) getSampleKeys();
|
||||
for (int i = 0; i < sampleKeys.length; i++) {
|
||||
map.put(sampleKeys[i], getSampleValues()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getSampleKeys() {
|
||||
return new String[] {"Date", "ETag", "X-Foo"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getSampleValues() {
|
||||
return new Object[] {ATTRIB_VALUE_DATE, ATTRIB_VALUE_ETAG, ATTRIB_VALUE_FOO};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getNewSampleValues() {
|
||||
// Needs to be same length but different values
|
||||
return new Object[] {new Date(-1L), "foo/bar", Arrays.asList(2, 3, 4)};
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void testMapPutNullValue() {
|
||||
// Special null semantics
|
||||
resetFull();
|
||||
|
||||
int size = map.size();
|
||||
String key = getClass().getName() + ".someNewKey";
|
||||
map.put(key, null);
|
||||
assertEquals(size, map.size());
|
||||
assertFalse(map.containsKey(key));
|
||||
|
||||
map.put(getSampleKeys()[0], null);
|
||||
assertEquals(size - 1, map.size());
|
||||
assertFalse(map.containsKey(getSampleKeys()[0]));
|
||||
|
||||
map.remove(getSampleKeys()[1]);
|
||||
assertEquals(size - 2, map.size());
|
||||
assertFalse(map.containsKey(getSampleKeys()[1]));
|
||||
}
|
||||
|
||||
private static abstract class MockServletRequestImpl implements ServletRequest {
|
||||
Map<String, Object> attributes;
|
||||
|
||||
public Object getAttribute(String name) {
|
||||
return attributes.get(name);
|
||||
}
|
||||
|
||||
public Enumeration getAttributeNames() {
|
||||
return Collections.enumeration(attributes.keySet());
|
||||
}
|
||||
|
||||
public void setAttribute(String name, Object o) {
|
||||
if (o == null) {
|
||||
attributes.remove(name);
|
||||
}
|
||||
else {
|
||||
attributes.put(name, o);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAttribute(String name) {
|
||||
attributes.remove(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import com.twelvemonkeys.io.NullOutputStream;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
/**
|
||||
* ServletConfigExceptionTestCase
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigExceptionTestCase.java#2 $
|
||||
*/
|
||||
public class ServletConfigExceptionTest {
|
||||
@Test
|
||||
public void testThrowCatchPrintStacktrace() {
|
||||
try {
|
||||
throw new ServletConfigException("FooBar!");
|
||||
}
|
||||
catch (ServletConfigException e) {
|
||||
e.printStackTrace(new PrintWriter(new NullOutputStream()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThrowCatchGetNoCause() {
|
||||
try {
|
||||
throw new ServletConfigException("FooBar!");
|
||||
}
|
||||
catch (ServletConfigException e) {
|
||||
assertNull(e.getRootCause()); // Old API
|
||||
assertNull(e.getCause());
|
||||
|
||||
e.printStackTrace(new PrintWriter(new NullOutputStream()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThrowCatchInitCauseNull() {
|
||||
try {
|
||||
ServletConfigException e = new ServletConfigException("FooBar!");
|
||||
e.initCause(null);
|
||||
throw e;
|
||||
}
|
||||
catch (ServletConfigException e) {
|
||||
assertNull(e.getRootCause()); // Old API
|
||||
assertNull(e.getCause());
|
||||
|
||||
e.printStackTrace(new PrintWriter(new NullOutputStream()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThrowCatchInitCause() {
|
||||
//noinspection ThrowableInstanceNeverThrown
|
||||
Exception cause = new Exception();
|
||||
try {
|
||||
ServletConfigException exception = new ServletConfigException("FooBar!");
|
||||
exception.initCause(cause);
|
||||
throw exception;
|
||||
}
|
||||
catch (ServletConfigException e) {
|
||||
// NOTE: We don't know how the superclass is implemented, so we assume nothing here
|
||||
//assertEquals(null, e.getRootCause()); // Old API
|
||||
assertSame(cause, e.getCause());
|
||||
|
||||
e.printStackTrace(new PrintWriter(new NullOutputStream()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThrowCatchGetNullCause() {
|
||||
try {
|
||||
throw new ServletConfigException("FooBar!", null);
|
||||
}
|
||||
catch (ServletConfigException e) {
|
||||
assertNull(e.getRootCause()); // Old API
|
||||
assertNull(e.getCause());
|
||||
|
||||
e.printStackTrace(new PrintWriter(new NullOutputStream()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThrowCatchGetCause() {
|
||||
IllegalStateException cause = new IllegalStateException();
|
||||
try {
|
||||
throw new ServletConfigException("FooBar caused by stupid API!", cause);
|
||||
}
|
||||
catch (ServletConfigException e) {
|
||||
assertSame(cause, e.getRootCause()); // Old API
|
||||
assertSame(cause, e.getCause());
|
||||
|
||||
e.printStackTrace(new PrintWriter(new NullOutputStream()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import com.twelvemonkeys.util.MapAbstractTest;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
|
||||
import javax.servlet.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* ServletConfigMapAdapterTestCase
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigMapAdapterTestCase.java#3 $
|
||||
*/
|
||||
@RunWith(Suite.class)
|
||||
@Suite.SuiteClasses({AbstractServletConfigMapAdapterTest.ServletConfigMapTest.class, AbstractServletConfigMapAdapterTest.FilterConfigMapTest.class, AbstractServletConfigMapAdapterTest.ServletContextMapTest.class})
|
||||
public final class ServletConfigMapAdapterTest {
|
||||
}
|
||||
|
||||
abstract class AbstractServletConfigMapAdapterTest extends MapAbstractTest {
|
||||
|
||||
public boolean isPutAddSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isPutChangeSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isRemoveSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isSetValueSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class TestConfig implements ServletConfig, FilterConfig, ServletContext, Serializable, Cloneable {
|
||||
Map map = new HashMap();
|
||||
|
||||
public String getServletName() {
|
||||
return "dummy"; // Not needed for this test
|
||||
}
|
||||
|
||||
public String getFilterName() {
|
||||
return getServletName();
|
||||
}
|
||||
|
||||
public String getServletContextName() {
|
||||
return getServletName();
|
||||
}
|
||||
|
||||
|
||||
public ServletContext getServletContext() {
|
||||
throw new UnsupportedOperationException("Method getSerlvetContext not implemented");
|
||||
}
|
||||
|
||||
public String getInitParameter(String s) {
|
||||
return (String) map.get(s);
|
||||
}
|
||||
|
||||
public Enumeration getInitParameterNames() {
|
||||
//noinspection unchecked
|
||||
return Collections.enumeration(map.keySet());
|
||||
}
|
||||
|
||||
public ServletContext getContext(String uripath) {
|
||||
throw new UnsupportedOperationException("Method getContext not implemented");
|
||||
}
|
||||
|
||||
public int getMajorVersion() {
|
||||
throw new UnsupportedOperationException("Method getMajorVersion not implemented");
|
||||
}
|
||||
|
||||
public int getMinorVersion() {
|
||||
throw new UnsupportedOperationException("Method getMinorVersion not implemented");
|
||||
}
|
||||
|
||||
public String getMimeType(String file) {
|
||||
throw new UnsupportedOperationException("Method getMimeType not implemented");
|
||||
}
|
||||
|
||||
public Set getResourcePaths(String path) {
|
||||
throw new UnsupportedOperationException("Method getResourcePaths not implemented");
|
||||
}
|
||||
|
||||
public URL getResource(String path) throws MalformedURLException {
|
||||
throw new UnsupportedOperationException("Method getResource not implemented");
|
||||
}
|
||||
|
||||
public InputStream getResourceAsStream(String path) {
|
||||
throw new UnsupportedOperationException("Method getResourceAsStream not implemented");
|
||||
}
|
||||
|
||||
public RequestDispatcher getRequestDispatcher(String path) {
|
||||
throw new UnsupportedOperationException("Method getRequestDispatcher not implemented");
|
||||
}
|
||||
|
||||
public RequestDispatcher getNamedDispatcher(String name) {
|
||||
throw new UnsupportedOperationException("Method getNamedDispatcher not implemented");
|
||||
}
|
||||
|
||||
public Servlet getServlet(String name) throws ServletException {
|
||||
throw new UnsupportedOperationException("Method getServlet not implemented");
|
||||
}
|
||||
|
||||
public Enumeration getServlets() {
|
||||
throw new UnsupportedOperationException("Method getServlets not implemented");
|
||||
}
|
||||
|
||||
public Enumeration getServletNames() {
|
||||
throw new UnsupportedOperationException("Method getServletNames not implemented");
|
||||
}
|
||||
|
||||
public void log(String msg) {
|
||||
throw new UnsupportedOperationException("Method log not implemented");
|
||||
}
|
||||
|
||||
public void log(Exception exception, String msg) {
|
||||
throw new UnsupportedOperationException("Method log not implemented");
|
||||
}
|
||||
|
||||
public void log(String message, Throwable throwable) {
|
||||
throw new UnsupportedOperationException("Method log not implemented");
|
||||
}
|
||||
|
||||
public String getRealPath(String path) {
|
||||
throw new UnsupportedOperationException("Method getRealPath not implemented");
|
||||
}
|
||||
|
||||
public String getServerInfo() {
|
||||
throw new UnsupportedOperationException("Method getServerInfo not implemented");
|
||||
}
|
||||
|
||||
public Object getAttribute(String name) {
|
||||
throw new UnsupportedOperationException("Method getAttribute not implemented");
|
||||
}
|
||||
|
||||
public Enumeration getAttributeNames() {
|
||||
throw new UnsupportedOperationException("Method getAttributeNames not implemented");
|
||||
}
|
||||
|
||||
public void setAttribute(String name, Object object) {
|
||||
throw new UnsupportedOperationException("Method setAttribute not implemented");
|
||||
}
|
||||
|
||||
public void removeAttribute(String name) {
|
||||
throw new UnsupportedOperationException("Method removeAttribute not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ServletConfigMapTest extends AbstractServletConfigMapAdapterTest {
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
ServletConfig config = new TestConfig();
|
||||
return new ServletConfigMapAdapter(config);
|
||||
}
|
||||
|
||||
public Map makeFullMap() {
|
||||
ServletConfig config = new TestConfig();
|
||||
addSampleMappings(((TestConfig) config).map);
|
||||
return new ServletConfigMapAdapter(config);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class FilterConfigMapTest extends AbstractServletConfigMapAdapterTest {
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
FilterConfig config = new TestConfig();
|
||||
return new ServletConfigMapAdapter(config);
|
||||
}
|
||||
|
||||
public Map makeFullMap() {
|
||||
FilterConfig config = new TestConfig();
|
||||
addSampleMappings(((TestConfig) config).map);
|
||||
return new ServletConfigMapAdapter(config);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ServletContextMapTest extends AbstractServletConfigMapAdapterTest {
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
ServletContext config = new TestConfig();
|
||||
return new ServletConfigMapAdapter(config);
|
||||
}
|
||||
|
||||
public Map makeFullMap() {
|
||||
FilterConfig config = new TestConfig();
|
||||
addSampleMappings(((TestConfig) config).map);
|
||||
return new ServletConfigMapAdapter(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,375 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletConfig;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* ServletConfiguratorTestCase
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: ServletConfiguratorTestCase.java,v 1.0 May 2, 2010 3:08:33 PM haraldk Exp$
|
||||
*/
|
||||
public class ServletConfiguratorTest {
|
||||
|
||||
// TODO: Test error conditions:
|
||||
// - Missing name = ... or non-bean conforming method
|
||||
// - Non-accessible? How..?
|
||||
// - Missing required value
|
||||
|
||||
// TODO: Clean up tests to test only one thing at a time
|
||||
// - Public method
|
||||
// - Public method with override
|
||||
// - Public method overridden without annotation
|
||||
// - Protected method
|
||||
// - Protected method with override
|
||||
// - Protected method overridden without annotation
|
||||
// - Package protected method
|
||||
// - Package protected method with override
|
||||
// - Package protected method overridden without annotation
|
||||
// - Private method
|
||||
// - Multiple private methods with same signature (should invoke all, as private methods can't be overridden)
|
||||
|
||||
@Test
|
||||
public void testConfigureAnnotatedServlet() throws ServletConfigException {
|
||||
AnnotatedServlet servlet = mock(AnnotatedServlet.class);
|
||||
|
||||
ServletConfig config = mock(ServletConfig.class);
|
||||
when(config.getServletName()).thenReturn("FooServlet");
|
||||
when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("x", "foo", "bar")));
|
||||
when(config.getInitParameter("x")).thenReturn("99");
|
||||
when(config.getInitParameter("foo")).thenReturn("Foo");
|
||||
when(config.getInitParameter("bar")).thenReturn("-1, 2, 0, 42");
|
||||
|
||||
ServletConfigurator.configure(servlet, config);
|
||||
|
||||
// Verify
|
||||
verify(servlet, times(1)).setX(99);
|
||||
verify(servlet, times(1)).setFoo("Foo");
|
||||
verify(servlet, times(1)).configTheBar(-1, 2, 0, 42);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigureAnnotatedFilter() throws ServletConfigException {
|
||||
AnnotatedServlet servlet = mock(AnnotatedServlet.class);
|
||||
|
||||
FilterConfig config = mock(FilterConfig.class);
|
||||
when(config.getFilterName()).thenReturn("FooFilter");
|
||||
when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("x", "foo", "bar")));
|
||||
when(config.getInitParameter("x")).thenReturn("99");
|
||||
when(config.getInitParameter("foo")).thenReturn("Foo");
|
||||
when(config.getInitParameter("bar")).thenReturn("-1, 2, 0, 42");
|
||||
|
||||
ServletConfigurator.configure(servlet, config);
|
||||
|
||||
// Verify
|
||||
verify(servlet, times(1)).setX(99);
|
||||
verify(servlet, times(1)).setFoo("Foo");
|
||||
verify(servlet, times(1)).configTheBar(-1, 2, 0, 42);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigurePrivateMethod() throws ServletConfigException {
|
||||
AnnotatedServlet servlet = mock(AnnotatedServlet.class);
|
||||
|
||||
ServletConfig config = mock(ServletConfig.class);
|
||||
when(config.getServletName()).thenReturn("FooServlet");
|
||||
when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Collections.singletonList("private")));
|
||||
when(config.getInitParameter("private")).thenReturn("99");
|
||||
|
||||
ServletConfigurator.configure(servlet, config);
|
||||
|
||||
// Verify
|
||||
assertEquals(servlet.priv, "99");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigurePrivateShadowedMethod() throws ServletConfigException {
|
||||
abstract class SubclassedServlet extends AnnotatedServlet {
|
||||
@InitParam(name = "package-private")
|
||||
abstract void setPrivate(String priv);
|
||||
}
|
||||
|
||||
SubclassedServlet servlet = mock(SubclassedServlet.class);
|
||||
|
||||
ServletConfig config = mock(ServletConfig.class);
|
||||
when(config.getServletName()).thenReturn("FooServlet");
|
||||
when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Collections.singletonList("private")));
|
||||
when(config.getInitParameter("private")).thenReturn("private");
|
||||
when(config.getInitParameter("package-private")).thenReturn("package");
|
||||
|
||||
ServletConfigurator.configure(servlet, config);
|
||||
|
||||
// Verify
|
||||
assertEquals(servlet.priv, "private");
|
||||
verify(servlet, times(1)).setPrivate("package");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigureSubclassedServlet() throws ServletConfigException {
|
||||
abstract class SubclassedServlet extends AnnotatedServlet {
|
||||
@InitParam(name = "flag")
|
||||
abstract void configureMeToo(boolean flag);
|
||||
}
|
||||
|
||||
SubclassedServlet servlet = mock(SubclassedServlet.class);
|
||||
|
||||
ServletConfig config = mock(ServletConfig.class);
|
||||
when(config.getServletName()).thenReturn("FooServlet");
|
||||
when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("x", "foo", "bar", "flag")));
|
||||
when(config.getInitParameter("x")).thenReturn("99");
|
||||
when(config.getInitParameter("foo")).thenReturn("Foo");
|
||||
when(config.getInitParameter("bar")).thenReturn("-1, 2, 0, 42");
|
||||
when(config.getInitParameter("flag")).thenReturn("true");
|
||||
|
||||
ServletConfigurator.configure(servlet, config);
|
||||
|
||||
// Verify
|
||||
verify(servlet, times(1)).setX(99);
|
||||
verify(servlet, times(1)).setFoo("Foo");
|
||||
verify(servlet, times(1)).configTheBar(-1, 2, 0, 42);
|
||||
verify(servlet, times(1)).configureMeToo(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigureAnnotatedServletWithLispStyle() throws ServletConfigException {
|
||||
abstract class SubclassedServlet extends AnnotatedServlet {
|
||||
@InitParam(name = "the-explicit-x")
|
||||
abstract public void setExplicitX(int x);
|
||||
|
||||
@InitParam
|
||||
abstract public void setTheOtherX(int x);
|
||||
}
|
||||
|
||||
SubclassedServlet servlet = mock(SubclassedServlet.class);
|
||||
|
||||
ServletConfig config = mock(ServletConfig.class);
|
||||
when(config.getServletName()).thenReturn("FooServlet");
|
||||
when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("the-explicit-x", "the-other-x")));
|
||||
when(config.getInitParameter("the-explicit-x")).thenReturn("-1");
|
||||
when(config.getInitParameter("the-other-x")).thenReturn("42");
|
||||
|
||||
ServletConfigurator.configure(servlet, config);
|
||||
|
||||
// Verify
|
||||
verify(servlet, times(1)).setExplicitX(-1);
|
||||
verify(servlet, times(1)).setTheOtherX(42);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigureSubclassedServletWithOverride() throws ServletConfigException {
|
||||
abstract class SubclassedServlet extends AnnotatedServlet {
|
||||
@Override
|
||||
@InitParam(name = "y")
|
||||
public void setX(int x) {
|
||||
}
|
||||
}
|
||||
|
||||
SubclassedServlet servlet = mock(SubclassedServlet.class);
|
||||
|
||||
ServletConfig config = mock(ServletConfig.class);
|
||||
when(config.getServletName()).thenReturn("FooServlet");
|
||||
when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("x", "y")));
|
||||
when(config.getInitParameter("x")).thenReturn("99");
|
||||
when(config.getInitParameter("y")).thenReturn("-66");
|
||||
|
||||
ServletConfigurator.configure(servlet, config);
|
||||
|
||||
// Verify
|
||||
verify(servlet, times(1)).setX(-66);
|
||||
verify(servlet, times(1)).setX(anyInt()); // We don't want multiple invocations, only the overridden method
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigureSubclassedServletWithOverrideNoParam() throws ServletConfigException {
|
||||
// NOTE: We must allow overriding the methods without annotation present, in order to allow CGLib/proxies of the class...
|
||||
abstract class SubclassedServlet extends AnnotatedServlet {
|
||||
@Override
|
||||
@InitParam(name = "<THIS PARAMETER DOES NOT EXIST>")
|
||||
public void setX(int x) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFoo(String foo) {
|
||||
}
|
||||
}
|
||||
|
||||
SubclassedServlet servlet = mock(SubclassedServlet.class);
|
||||
|
||||
ServletConfig config = mock(ServletConfig.class);
|
||||
when(config.getServletName()).thenReturn("FooServlet");
|
||||
when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("x", "foo")));
|
||||
when(config.getInitParameter("x")).thenReturn("99");
|
||||
when(config.getInitParameter("foo")).thenReturn("Foo");
|
||||
|
||||
ServletConfigurator.configure(servlet, config);
|
||||
|
||||
// Verify
|
||||
verify(servlet, never()).setX(anyInt());
|
||||
verify(servlet, times(1)).setFoo("Foo");
|
||||
verify(servlet, times(1)).setFoo(anyString()); // We don't want multiple invocations
|
||||
}
|
||||
|
||||
// Test interface
|
||||
@Test
|
||||
public void testConfigureServletWithInterface() throws ServletConfigException {
|
||||
abstract class InterfacedServlet implements Servlet, Annotated {
|
||||
}
|
||||
|
||||
InterfacedServlet servlet = mock(InterfacedServlet.class);
|
||||
|
||||
ServletConfig config = mock(ServletConfig.class);
|
||||
when(config.getServletName()).thenReturn("FooServlet");
|
||||
when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Collections.singletonList("foo")));
|
||||
when(config.getInitParameter("foo")).thenReturn("Foo");
|
||||
|
||||
ServletConfigurator.configure(servlet, config);
|
||||
|
||||
// Verify
|
||||
verify(servlet, times(1)).annotated("Foo");
|
||||
}
|
||||
|
||||
// TODO: Test override/shadow of package protected method outside package
|
||||
|
||||
@Test
|
||||
public void testRequiredParameter() throws ServletConfigException {
|
||||
abstract class SubclassedServlet extends AnnotatedServlet {
|
||||
@InitParam(required = true)
|
||||
abstract void setRequired(String value);
|
||||
}
|
||||
|
||||
SubclassedServlet servlet = mock(SubclassedServlet.class);
|
||||
|
||||
ServletConfig config = mock(ServletConfig.class);
|
||||
when(config.getServletName()).thenReturn("FooServlet");
|
||||
when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Collections.singletonList("required")));
|
||||
when(config.getInitParameter("required")).thenReturn("the required value");
|
||||
|
||||
ServletConfigurator.configure(servlet, config);
|
||||
|
||||
// Verify
|
||||
verify(servlet, times(1)).setRequired("the required value");
|
||||
verify(servlet, times(1)).setRequired(anyString()); // We don't want multiple invocations
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingParameter() throws ServletConfigException {
|
||||
abstract class SubclassedServlet extends AnnotatedServlet {
|
||||
@InitParam()
|
||||
abstract void setNonRequired(String value);
|
||||
}
|
||||
|
||||
SubclassedServlet servlet = mock(SubclassedServlet.class);
|
||||
|
||||
ServletConfig config = mock(ServletConfig.class);
|
||||
when(config.getServletName()).thenReturn("FooServlet");
|
||||
when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Collections.emptyList()));
|
||||
|
||||
ServletConfigurator.configure(servlet, config);
|
||||
|
||||
// Verify
|
||||
verify(servlet, never()).setNonRequired(anyString()); // Simply not configured
|
||||
}
|
||||
|
||||
@Test(expected = ServletConfigException.class)
|
||||
public void testMissingRequiredParameter() throws ServletConfigException {
|
||||
abstract class SubclassedServlet extends AnnotatedServlet {
|
||||
@Override
|
||||
@InitParam(required = true)
|
||||
protected abstract void setFoo(String value);
|
||||
}
|
||||
|
||||
SubclassedServlet servlet = mock(SubclassedServlet.class);
|
||||
|
||||
ServletConfig config = mock(ServletConfig.class);
|
||||
when(config.getServletName()).thenReturn("FooServlet");
|
||||
when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Collections.emptyList()));
|
||||
|
||||
ServletConfigurator.configure(servlet, config); // Should throw exception
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingParameterDefaultValue() throws ServletConfigException {
|
||||
abstract class SubclassedServlet extends AnnotatedServlet {
|
||||
@InitParam(defaultValue = "1, 2, 3")
|
||||
abstract void setNonRequired(int[] value);
|
||||
}
|
||||
|
||||
SubclassedServlet servlet = mock(SubclassedServlet.class);
|
||||
|
||||
ServletConfig config = mock(ServletConfig.class);
|
||||
when(config.getServletName()).thenReturn("FooServlet");
|
||||
when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Collections.emptyList()));
|
||||
|
||||
ServletConfigurator.configure(servlet, config);
|
||||
|
||||
// Verify
|
||||
verify(servlet, times(1)).setNonRequired(new int[] {1, 2, 3});
|
||||
verify(servlet, times(1)).setNonRequired((int[]) any());
|
||||
}
|
||||
|
||||
|
||||
public interface Annotated {
|
||||
@InitParam(name = "foo")
|
||||
void annotated(String an);
|
||||
}
|
||||
|
||||
public abstract class AnnotatedServlet implements Servlet, Filter {
|
||||
String priv;
|
||||
|
||||
// Implicit name "x"
|
||||
@InitParam
|
||||
public abstract void setX(int x);
|
||||
|
||||
// Implicit name "foo"
|
||||
@InitParam
|
||||
protected abstract void setFoo(String foo);
|
||||
|
||||
@InitParam(name = "bar")
|
||||
abstract void configTheBar(int... bar);
|
||||
|
||||
@InitParam(name = "private")
|
||||
private void setPrivate(String priv) {
|
||||
this.priv = priv;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import com.twelvemonkeys.util.MapAbstractTest;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* ServletConfigMapAdapterTest
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: ServletHeadersMapAdapterTest.java#1 $
|
||||
*/
|
||||
public class ServletHeadersMapAdapterTest extends MapAbstractTest {
|
||||
private static final List<String> HEADER_VALUE_ETAG = Collections.singletonList("\"1234567890abcdef\"");
|
||||
private static final List<String> HEADER_VALUE_DATE = Collections.singletonList(new Date().toString());
|
||||
private static final List<String> HEADER_VALUE_FOO = Arrays.asList("one", "two");
|
||||
|
||||
public boolean isPutAddSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isPutChangeSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isRemoveSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isSetValueSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTestSerialization() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||
when(request.getHeaderNames()).thenAnswer(returnEnumeration(Collections.emptyList()));
|
||||
|
||||
return new ServletHeadersMapAdapter(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map makeFullMap() {
|
||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||
when(request.getHeaderNames()).thenAnswer(returnEnumeration(Arrays.asList(getSampleKeys())));
|
||||
when(request.getHeaders("Date")).thenAnswer(returnEnumeration(HEADER_VALUE_DATE));
|
||||
when(request.getHeaders("ETag")).thenAnswer(returnEnumeration(HEADER_VALUE_ETAG));
|
||||
when(request.getHeaders("X-Foo")).thenAnswer(returnEnumeration(HEADER_VALUE_FOO));
|
||||
|
||||
return new ServletHeadersMapAdapter(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getSampleKeys() {
|
||||
return new String[] {"Date", "ETag", "X-Foo"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getSampleValues() {
|
||||
return new Object[] {HEADER_VALUE_DATE, HEADER_VALUE_ETAG, HEADER_VALUE_FOO};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getNewSampleValues() {
|
||||
// Needs to be same length but different values
|
||||
return new Object[3];
|
||||
}
|
||||
|
||||
protected static <T> ReturnNewEnumeration<T> returnEnumeration(final Collection<T> collection) {
|
||||
return new ReturnNewEnumeration<>(collection);
|
||||
}
|
||||
|
||||
private static class ReturnNewEnumeration<T> implements Answer<Enumeration<T>> {
|
||||
private final Collection<T> collection;
|
||||
|
||||
private ReturnNewEnumeration(final Collection<T> collection) {
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
public Enumeration<T> answer(InvocationOnMock invocation) throws Throwable {
|
||||
return Collections.enumeration(collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import com.twelvemonkeys.util.MapAbstractTest;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* ServletConfigMapAdapterTest
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTest.java#1 $
|
||||
*/
|
||||
public class ServletParametersMapAdapterTest extends MapAbstractTest {
|
||||
private static final List<String> PARAM_VALUE_ETAG = Collections.singletonList("\"1234567890abcdef\"");
|
||||
private static final List<String> PARAM_VALUE_DATE = Collections.singletonList(new Date().toString());
|
||||
private static final List<String> PARAM_VALUE_FOO = Arrays.asList("one", "two");
|
||||
|
||||
public boolean isPutAddSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isPutChangeSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isRemoveSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isSetValueSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTestSerialization() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Map makeEmptyMap() {
|
||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||
when(request.getParameterNames()).thenAnswer(returnEnumeration(Collections.emptyList()));
|
||||
|
||||
return new ServletParametersMapAdapter(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map makeFullMap() {
|
||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||
|
||||
when(request.getParameterNames()).thenAnswer(returnEnumeration(Arrays.asList("tag", "date", "foo")));
|
||||
when(request.getParameterValues("date")).thenReturn(PARAM_VALUE_DATE.toArray(new String[PARAM_VALUE_DATE.size()]));
|
||||
when(request.getParameterValues("tag")).thenReturn(PARAM_VALUE_ETAG.toArray(new String[PARAM_VALUE_ETAG.size()]));
|
||||
when(request.getParameterValues("foo")).thenReturn(PARAM_VALUE_FOO.toArray(new String[PARAM_VALUE_FOO.size()]));
|
||||
|
||||
return new ServletParametersMapAdapter(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getSampleKeys() {
|
||||
return new String[] {"date", "tag", "foo"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getSampleValues() {
|
||||
return new Object[] {PARAM_VALUE_DATE, PARAM_VALUE_ETAG, PARAM_VALUE_FOO};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getNewSampleValues() {
|
||||
// Needs to be same length but different values
|
||||
return new Object[3];
|
||||
}
|
||||
|
||||
protected static <T> ReturnNewEnumeration<T> returnEnumeration(final Collection<T> collection) {
|
||||
return new ReturnNewEnumeration<>(collection);
|
||||
}
|
||||
|
||||
private static class ReturnNewEnumeration<T> implements Answer<Enumeration<T>> {
|
||||
private final Collection<T> collection;
|
||||
|
||||
private ReturnNewEnumeration(final Collection<T> collection) {
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
public Enumeration<T> answer(InvocationOnMock invocation) throws Throwable {
|
||||
return Collections.enumeration(collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import com.twelvemonkeys.lang.ObjectAbstractTest;
|
||||
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
/**
|
||||
* ServletResponseAbsrtactTestCase
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/ServletResponseAbsrtactTestCase.java#1 $
|
||||
*/
|
||||
public abstract class ServletResponseAbsrtactTest extends ObjectAbstractTest {
|
||||
protected Object makeObject() {
|
||||
return makeServletResponse();
|
||||
}
|
||||
|
||||
protected abstract ServletResponse makeServletResponse();
|
||||
|
||||
// TODO: Implement
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
package com.twelvemonkeys.servlet;
|
||||
|
||||
import com.twelvemonkeys.io.OutputStreamAbstractTest;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.ServletResponse;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* TrimWhiteSpaceFilterTestCase
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/TrimWhiteSpaceFilterTestCase.java#1 $
|
||||
*/
|
||||
public class TrimWhiteSpaceFilterTest extends FilterAbstractTest {
|
||||
protected Filter makeFilter() {
|
||||
return new TrimWhiteSpaceFilter();
|
||||
}
|
||||
|
||||
public static final class TrimWSFilterOutputStreamTest extends OutputStreamAbstractTest {
|
||||
protected OutputStream makeObject() {
|
||||
// NOTE: ByteArrayOutputStream does not implement flush or close...
|
||||
return makeOutputStream(new ByteArrayOutputStream(16));
|
||||
}
|
||||
|
||||
protected OutputStream makeOutputStream(OutputStream pWrapped) {
|
||||
return new TrimWhiteSpaceFilter.TrimWSFilterOutputStream(pWrapped);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTrimWSOnlyWS() throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(64);
|
||||
OutputStream trim = makeOutputStream(out);
|
||||
|
||||
String input = " \n\n\t \t" + (char) 0x0a + ' ' + (char) 0x0d + "\r ";
|
||||
|
||||
trim.write(input.getBytes());
|
||||
trim.flush();
|
||||
trim.close();
|
||||
|
||||
assertEquals("Should be trimmed", "\"\"", '"' + new String(out.toByteArray()) + '"');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTrimWSLeading() throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(64);
|
||||
OutputStream trim = makeOutputStream(out);
|
||||
|
||||
byte[] input = " \n<?xml version=\"1.0\"?>\n\t <not-really-well-formed/> \t".getBytes();
|
||||
String trimmed = "<?xml version=\"1.0\"?>\n<not-really-well-formed/> "; // TODO: This is pr spec (the trailing space). But probably quite stupid...
|
||||
|
||||
trim.write(input);
|
||||
trim.flush();
|
||||
trim.close();
|
||||
|
||||
assertEquals("Should be trimmed", '"' + trimmed + '"', '"' + new String(out.toByteArray()) + '"');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTrimWSOffsetLength() throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(64);
|
||||
OutputStream trim = makeOutputStream(out);
|
||||
|
||||
// Kindly generated by http://lipsum.org/ :-)
|
||||
byte[] input = (" \n\tLorem ipsum dolor sit amet, consectetuer adipiscing elit.\n\r\n\r" +
|
||||
"Etiam arcu neque, \n\rmalesuada blandit,\t\n\r\n\r\n\n\n\r\n\r\r\n\n\t rutrum quis, molestie at, diam.\n" +
|
||||
" Nulla elementum elementum eros.\n \t\t\n\r" +
|
||||
"Ut rhoncus, turpis in pellentesque volutpat, sapien sem accumsan augue, a scelerisque nibh erat vel magna.\n" +
|
||||
" Phasellus diam orci, dignissim et, gravida vitae, venenatis eu, elit.\n" +
|
||||
"\t\t\tSuspendisse dictum enim at nisl. Integer magna erat, viverra sit amet, consectetuer nec, accumsan ut, mi.\n" +
|
||||
"\n\r\r\r\n\rNunc ultricies \n\n\n consectetuer mauris. " +
|
||||
"Nulla lectus mauris, viverra ac, pulvinar a, commodo quis, nulla.\n " +
|
||||
"Ut eget nulla. In est dolor, convallis \t non, tincidunt \tvestibulum, porttitor et, eros.\n " +
|
||||
"\t\t \t \n\rDonec vehicula ultrices nisl.").getBytes();
|
||||
|
||||
String trimmed = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n" +
|
||||
"Etiam arcu neque, malesuada blandit,\trutrum quis, molestie at, diam.\n" +
|
||||
"Nulla elementum elementum eros.\n" +
|
||||
"Ut rhoncus, turpis in pellentesque volutpat, sapien sem accumsan augue, a scelerisque nibh erat vel magna.\n" +
|
||||
"Phasellus diam orci, dignissim et, gravida vitae, venenatis eu, elit.\n" +
|
||||
"Suspendisse dictum enim at nisl. Integer magna erat, viverra sit amet, consectetuer nec, accumsan ut, mi.\n" +
|
||||
"Nunc ultricies consectetuer mauris. Nulla lectus mauris, viverra ac, pulvinar a, commodo quis, nulla.\n" +
|
||||
"Ut eget nulla. In est dolor, convallis non, tincidunt vestibulum, porttitor et, eros.\n" +
|
||||
"Donec vehicula ultrices nisl.";
|
||||
|
||||
int chunkLenght = 5;
|
||||
int bytesLeft = input.length;
|
||||
while (bytesLeft > chunkLenght) {
|
||||
trim.write(input, input.length - bytesLeft, chunkLenght);
|
||||
bytesLeft -= chunkLenght;
|
||||
}
|
||||
trim.write(input, input.length - bytesLeft, bytesLeft);
|
||||
|
||||
trim.flush();
|
||||
trim.close();
|
||||
|
||||
assertEquals("Should be trimmed", '"' + trimmed + '"', '"' + new String(out.toByteArray()) + '"');
|
||||
}
|
||||
|
||||
// TODO: Test that we DON'T remove too much...
|
||||
}
|
||||
|
||||
public static final class TrimWSServletResponseWrapperTest extends ServletResponseAbsrtactTest {
|
||||
protected ServletResponse makeServletResponse() {
|
||||
return new TrimWhiteSpaceFilter.TrimWSServletResponseWrapper(new MockServletResponse());
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,508 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import com.twelvemonkeys.io.FileUtil;
|
||||
import com.twelvemonkeys.servlet.OutputStreamAdapter;
|
||||
import com.twelvemonkeys.util.StringTokenIterator;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* ImageFilterTest
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: ImageFilterTest.java,v 1.0 07.04.11 14.14 haraldk Exp$
|
||||
*/
|
||||
public class ImageFilterTest {
|
||||
|
||||
@Test
|
||||
public void passThroughIfNotTrigger() throws ServletException, IOException {
|
||||
// Filter init & setup
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
|
||||
FilterConfig filterConfig = mock(FilterConfig.class);
|
||||
when(filterConfig.getFilterName()).thenReturn("dummy");
|
||||
when(filterConfig.getServletContext()).thenReturn(context);
|
||||
when(filterConfig.getInitParameterNames()).thenReturn(new StringTokenIterator("foo, bar"));
|
||||
|
||||
DummyFilter filter = new DummyFilter() {
|
||||
@Override
|
||||
protected boolean trigger(ServletRequest pRequest) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
filter.init(filterConfig);
|
||||
|
||||
// Request/response setup
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
|
||||
// Execute
|
||||
filter.doFilter(request, response, chain);
|
||||
|
||||
// Verifications
|
||||
verify(chain).doFilter(request, response);
|
||||
verify(response, never()).getOutputStream();
|
||||
verify(response, never()).getWriter();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalFilter() throws ServletException, IOException {
|
||||
// Filter init & setup
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
|
||||
FilterConfig filterConfig = mock(FilterConfig.class);
|
||||
when(filterConfig.getFilterName()).thenReturn("dummy");
|
||||
when(filterConfig.getServletContext()).thenReturn(context);
|
||||
when(filterConfig.getInitParameterNames()).thenReturn(new StringTokenIterator("foo, bar"));
|
||||
|
||||
DummyFilter filter = new DummyFilter();
|
||||
filter.init(filterConfig);
|
||||
|
||||
// Request/response setup
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
ServletOutputStream out = spy(new OutputStreamAdapter(stream));
|
||||
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||
when(response.getOutputStream()).thenReturn(out);
|
||||
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
doAnswer(new Answer<Void>() {
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
HttpServletResponse response = (HttpServletResponse) invocation.getArguments()[1];
|
||||
|
||||
response.setContentType("image/png");
|
||||
response.setContentLength(104417);
|
||||
InputStream stream = getClass().getResourceAsStream("/com/twelvemonkeys/servlet/image/12monkeys-splash.png");
|
||||
assertNotNull("Missing test resource", stream);
|
||||
FileUtil.copy(stream, response.getOutputStream());
|
||||
|
||||
return null;
|
||||
}
|
||||
}).when(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
|
||||
// Execute
|
||||
filter.doFilter(request, response, chain);
|
||||
|
||||
// Verifications
|
||||
int length = stream.size();
|
||||
|
||||
verify(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
verify(response).setContentType("image/png");
|
||||
verify(response, atMost(1)).setContentLength(length); // setContentLength not implemented, avoid future bugs
|
||||
verify(out, atLeastOnce()).flush();
|
||||
|
||||
// Extra verification here, until we come up with something better
|
||||
assertTrue(
|
||||
String.format("Unlikely length for PNG (please run manual check): %s bytes, expected about 85000 bytes", length),
|
||||
length >= 60000 && length <= 120000
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterNoContent() throws ServletException, IOException {
|
||||
// Filter init & setup
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
|
||||
FilterConfig filterConfig = mock(FilterConfig.class);
|
||||
when(filterConfig.getFilterName()).thenReturn("dummy");
|
||||
when(filterConfig.getServletContext()).thenReturn(context);
|
||||
when(filterConfig.getInitParameterNames()).thenReturn(new StringTokenIterator("foo, bar"));
|
||||
|
||||
DummyFilter filter = new DummyFilter();
|
||||
filter.init(filterConfig);
|
||||
|
||||
// Request/response setup
|
||||
ServletOutputStream out = mock(ServletOutputStream.class);
|
||||
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||
when(response.getOutputStream()).thenReturn(out);
|
||||
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
doAnswer(new Answer<Void>() {
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
HttpServletResponse response = (HttpServletResponse) invocation.getArguments()[1];
|
||||
|
||||
response.setContentType("image/x-imaginary");
|
||||
|
||||
return null;
|
||||
}
|
||||
}).when(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
|
||||
// Execute
|
||||
filter.doFilter(request, response, chain);
|
||||
|
||||
// Verifications
|
||||
verify(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
verify(response).setContentType("image/x-imaginary");
|
||||
verify(out, atLeastOnce()).flush();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void triggerWhenTriggerParamsNull() throws ServletException {
|
||||
// Filter init & setup
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
|
||||
FilterConfig filterConfig = mock(FilterConfig.class);
|
||||
when(filterConfig.getFilterName()).thenReturn("dummy");
|
||||
when(filterConfig.getServletContext()).thenReturn(context);
|
||||
when(filterConfig.getInitParameterNames()).thenReturn(new StringTokenIterator("foo, bar"));
|
||||
|
||||
DummyFilter filter = new DummyFilter();
|
||||
|
||||
filter.init(filterConfig);
|
||||
|
||||
// Execute/Verifications
|
||||
assertTrue(filter.trigger(mock(HttpServletRequest.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void triggerWithTriggerParams() throws ServletException {
|
||||
// Filter init & setup
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
|
||||
FilterConfig filterConfig = mock(FilterConfig.class);
|
||||
when(filterConfig.getFilterName()).thenReturn("dummy");
|
||||
when(filterConfig.getServletContext()).thenReturn(context);
|
||||
when(filterConfig.getInitParameterNames()).thenReturn(new StringTokenIterator("triggerParams"));
|
||||
when(filterConfig.getInitParameter("triggerParams")).thenReturn("foo");
|
||||
|
||||
DummyFilter filter = new DummyFilter();
|
||||
|
||||
filter.init(filterConfig);
|
||||
|
||||
// Request/response setup
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getParameter("foo")).thenReturn("doit");
|
||||
|
||||
|
||||
// Execute/Verifications
|
||||
assertTrue(filter.trigger(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dontTriggerWithoutTriggerParams() throws ServletException {
|
||||
// Filter init & setup
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
|
||||
FilterConfig filterConfig = mock(FilterConfig.class);
|
||||
when(filterConfig.getFilterName()).thenReturn("dummy");
|
||||
when(filterConfig.getServletContext()).thenReturn(context);
|
||||
when(filterConfig.getInitParameterNames()).thenReturn(new StringTokenIterator("triggerParams"));
|
||||
when(filterConfig.getInitParameter("triggerParams")).thenReturn("foo");
|
||||
|
||||
DummyFilter filter = new DummyFilter();
|
||||
|
||||
filter.init(filterConfig);
|
||||
|
||||
// Request/response setup
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
|
||||
|
||||
// Execute/Verifications
|
||||
assertFalse(filter.trigger(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChaining() throws ServletException, IOException {
|
||||
// Filter init & setup
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
|
||||
FilterConfig fooConfig = mock(FilterConfig.class);
|
||||
when(fooConfig.getFilterName()).thenReturn("foo");
|
||||
when(fooConfig.getServletContext()).thenReturn(context);
|
||||
when(fooConfig.getInitParameterNames()).thenReturn(new StringTokenIterator(""));
|
||||
|
||||
final AtomicReference<BufferedImage> imageRef = new AtomicReference<BufferedImage>();
|
||||
final AtomicReference<ImageServletResponse> responseRef = new AtomicReference<ImageServletResponse>();
|
||||
|
||||
DummyFilter fooFilter = new DummyFilter() {
|
||||
@Override
|
||||
protected RenderedImage doFilter(BufferedImage image, ServletRequest request, ImageServletResponse response) throws IOException {
|
||||
// NOTE: Post-filtering, this method is run after barFilter.doFilter
|
||||
assertEquals(imageRef.get(), image);
|
||||
assertEquals(responseRef.get(), response);
|
||||
|
||||
return image;
|
||||
}
|
||||
};
|
||||
fooFilter.init(fooConfig);
|
||||
|
||||
FilterConfig barConfig = mock(FilterConfig.class);
|
||||
when(barConfig.getFilterName()).thenReturn("bar");
|
||||
when(barConfig.getServletContext()).thenReturn(context);
|
||||
when(barConfig.getInitParameterNames()).thenReturn(new StringTokenIterator(""));
|
||||
|
||||
final DummyFilter barFilter = new DummyFilter() {
|
||||
@Override
|
||||
protected RenderedImage doFilter(BufferedImage image, ServletRequest request, ImageServletResponse response) throws IOException {
|
||||
// NOTE: Post-filtering, this method is run before fooFilter.doFilter
|
||||
Graphics2D graphics = image.createGraphics();
|
||||
try {
|
||||
graphics.drawRect(10, 10, 100, 100);
|
||||
}
|
||||
finally {
|
||||
graphics.dispose();
|
||||
}
|
||||
|
||||
// Store references for later, make sure this is first and only set.
|
||||
assertTrue(imageRef.compareAndSet(null, image));
|
||||
assertTrue(responseRef.compareAndSet(null, response));
|
||||
|
||||
return image;
|
||||
}
|
||||
};
|
||||
barFilter.init(barConfig);
|
||||
|
||||
// Request/response setup
|
||||
ServletOutputStream out = mock(ServletOutputStream.class);
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||
when(response.getOutputStream()).thenReturn(out);
|
||||
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
final AtomicBoolean first = new AtomicBoolean(false);
|
||||
doAnswer(new Answer<Void>() {
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
HttpServletRequest request = (HttpServletRequest) invocation.getArguments()[0];
|
||||
HttpServletResponse response = (HttpServletResponse) invocation.getArguments()[1];
|
||||
|
||||
// Fake chaining here..
|
||||
if (first.compareAndSet(false, true)) {
|
||||
barFilter.doFilter(request, response, (FilterChain) invocation.getMock());
|
||||
return null;
|
||||
}
|
||||
|
||||
// Otherwise, fake servlet/file response
|
||||
response.setContentType("image/gif");
|
||||
InputStream stream = getClass().getResourceAsStream("/com/twelvemonkeys/servlet/image/tux.gif");
|
||||
assertNotNull("Missing test resource", stream);
|
||||
FileUtil.copy(stream, response.getOutputStream());
|
||||
|
||||
return null;
|
||||
}
|
||||
}).when(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
|
||||
// Execute
|
||||
fooFilter.doFilter(request, response, chain);
|
||||
|
||||
// Verifications
|
||||
verify(chain, times(2)).doFilter(any(ServletRequest.class), any(ImageServletResponse.class));
|
||||
verify(response).setContentType("image/gif");
|
||||
verify(out, atLeastOnce()).flush();
|
||||
|
||||
// NOTE:
|
||||
// We verify that the image is the same in both ImageFilter implementations, to make sure the image is only
|
||||
// decoded once, then encoded once.
|
||||
// But this test is not necessarily 100% reliable...
|
||||
}
|
||||
|
||||
@Test(expected = ServletException.class)
|
||||
public void passThroughIfNotTriggerException() throws ServletException, IOException {
|
||||
// Filter init & setup
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
|
||||
FilterConfig filterConfig = mock(FilterConfig.class);
|
||||
when(filterConfig.getFilterName()).thenReturn("dummy");
|
||||
when(filterConfig.getServletContext()).thenReturn(context);
|
||||
when(filterConfig.getInitParameterNames()).thenReturn(new StringTokenIterator("foo, bar"));
|
||||
|
||||
DummyFilter filter = new DummyFilter() {
|
||||
@Override
|
||||
protected boolean trigger(ServletRequest pRequest) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
filter.init(filterConfig);
|
||||
|
||||
// Request/response setup
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
doThrow(new ServletException("Something went terribly wrong. Take shelter.")).when(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
|
||||
// Execute
|
||||
try {
|
||||
filter.doFilter(request, response, chain);
|
||||
}
|
||||
finally {
|
||||
// Verifications
|
||||
verify(chain).doFilter(request, response);
|
||||
verify(response, never()).getOutputStream();
|
||||
verify(response, never()).getWriter();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = ServletException.class)
|
||||
public void normalFilterException() throws ServletException, IOException {
|
||||
// Filter init & setup
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
|
||||
FilterConfig filterConfig = mock(FilterConfig.class);
|
||||
when(filterConfig.getFilterName()).thenReturn("dummy");
|
||||
when(filterConfig.getServletContext()).thenReturn(context);
|
||||
when(filterConfig.getInitParameterNames()).thenReturn(new StringTokenIterator("foo, bar"));
|
||||
|
||||
DummyFilter filter = new DummyFilter();
|
||||
filter.init(filterConfig);
|
||||
|
||||
// Request/response setup
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
ServletOutputStream out = spy(new OutputStreamAdapter(stream));
|
||||
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||
when(response.getOutputStream()).thenReturn(out);
|
||||
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
doThrow(new ServletException("Something went terribly wrong. Take shelter.")).when(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
|
||||
// Execute
|
||||
try {
|
||||
filter.doFilter(request, response, chain);
|
||||
}
|
||||
finally {
|
||||
// Verifications
|
||||
verify(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void passThroughIfNotTriggerSendError() throws ServletException, IOException {
|
||||
// Filter init & setup
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
|
||||
FilterConfig filterConfig = mock(FilterConfig.class);
|
||||
when(filterConfig.getFilterName()).thenReturn("dummy");
|
||||
when(filterConfig.getServletContext()).thenReturn(context);
|
||||
when(filterConfig.getInitParameterNames()).thenReturn(new StringTokenIterator("foo, bar"));
|
||||
|
||||
DummyFilter filter = new DummyFilter() {
|
||||
@Override
|
||||
protected boolean trigger(ServletRequest pRequest) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
filter.init(filterConfig);
|
||||
|
||||
// Request/response setup
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
doAnswer(new Answer<Void>() {
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
HttpServletResponse response = (HttpServletResponse) invocation.getArguments()[1];
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "I'm afraid I can't do that.");
|
||||
|
||||
return null;
|
||||
}
|
||||
}).when(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
|
||||
// Execute
|
||||
filter.doFilter(request, response, chain);
|
||||
|
||||
// Verifications
|
||||
verify(chain).doFilter(request, response);
|
||||
verify(response, never()).getOutputStream();
|
||||
verify(response, never()).getWriter();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalFilterSendError() throws ServletException, IOException {
|
||||
// Filter init & setup
|
||||
ServletContext context = mock(ServletContext.class);
|
||||
|
||||
FilterConfig filterConfig = mock(FilterConfig.class);
|
||||
when(filterConfig.getFilterName()).thenReturn("dummy");
|
||||
when(filterConfig.getServletContext()).thenReturn(context);
|
||||
when(filterConfig.getInitParameterNames()).thenReturn(new StringTokenIterator("foo, bar"));
|
||||
|
||||
DummyFilter filter = new DummyFilter();
|
||||
filter.init(filterConfig);
|
||||
|
||||
// Request/response setup
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
ServletOutputStream out = spy(new OutputStreamAdapter(stream));
|
||||
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||
when(response.getOutputStream()).thenReturn(out);
|
||||
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
doAnswer(new Answer<Void>() {
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
HttpServletResponse response = (HttpServletResponse) invocation.getArguments()[1];
|
||||
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "I've just picked up a fault in the AE35 unit.");
|
||||
|
||||
return null;
|
||||
}
|
||||
}).when(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
|
||||
// Execute
|
||||
filter.doFilter(request, response, chain);
|
||||
|
||||
// Verifications
|
||||
verify(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class));
|
||||
verify(response, atMost(1)).setContentLength(stream.size()); // setContentLength not implemented, avoid future bugs
|
||||
verify(out, atLeastOnce()).flush();
|
||||
}
|
||||
|
||||
private static class DummyFilter extends ImageFilter {
|
||||
@Override
|
||||
protected RenderedImage doFilter(BufferedImage image, ServletRequest request, ImageServletResponse response) throws IOException {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,365 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image.aoi;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:erlend@escenic.com">Erlend Hamnaberg</a>
|
||||
* @version $Revision: $
|
||||
*/
|
||||
public class AreaOfInterestTest {
|
||||
private static final Dimension SQUARE_200_200 = new Dimension(200, 200);
|
||||
private static final Dimension PORTRAIT_100_200 = new Dimension(100, 200);
|
||||
private static final Dimension LANDSCAPE_200_100 = new Dimension(200, 100);
|
||||
private static final Dimension SQUARE_100_100 = new Dimension(100, 100);
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Absolute AOI
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@Test
|
||||
public void testGetAOIAbsolute() {
|
||||
assertEquals(new Rectangle(10, 10, 100, 100), new DefaultAreaOfInterest(SQUARE_200_200).getAOI(10, 10, 100, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIAbsoluteOverflowX() {
|
||||
assertEquals(new Rectangle(10, 10, 90, 100), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(10, 10, 100, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIAbsoluteOverflowW() {
|
||||
assertEquals(new Rectangle(0, 10, 100, 100), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(0, 10, 110, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIAbsoluteOverflowY() {
|
||||
assertEquals(new Rectangle(10, 10, 100, 90), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(10, 10, 100, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIAbsoluteOverflowH() {
|
||||
assertEquals(new Rectangle(10, 0, 100, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(10, 0, 100, 110));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Uniform AOI centered
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredS2SUp() {
|
||||
assertEquals(new Rectangle(0, 0, 100, 100), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 333, 333));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredS2SDown() {
|
||||
assertEquals(new Rectangle(0, 0, 100, 100), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 33, 33));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredS2SNormalized() {
|
||||
assertEquals(new Rectangle(0, 0, 100, 100), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 100, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredS2W() {
|
||||
assertEquals(new Rectangle(0, 25, 100, 50), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 200, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredS2WNormalized() {
|
||||
assertEquals(new Rectangle(0, 25, 100, 50), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 100, 50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredS2N() {
|
||||
assertEquals(new Rectangle(25, 0, 50, 100), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 100, 200));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredS2NNormalized() {
|
||||
assertEquals(new Rectangle(25, 0, 50, 100), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 50, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredW2S() {
|
||||
assertEquals(new Rectangle(50, 0, 100, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 333, 333));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredW2SNormalized() {
|
||||
assertEquals(new Rectangle(50, 0, 100, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 100, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredW2W() {
|
||||
assertEquals(new Rectangle(0, 0, 200, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 100, 50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredW2WW() {
|
||||
assertEquals(new Rectangle(0, 25, 200, 50), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 200, 50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredW2WN() {
|
||||
assertEquals(new Rectangle(25, 0, 150, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 75, 50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredW2WNNormalized() {
|
||||
assertEquals(new Rectangle(25, 0, 150, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 150, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredW2WNormalized() {
|
||||
assertEquals(new Rectangle(0, 0, 200, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 200, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredW2N() {
|
||||
assertEquals(new Rectangle(75, 0, 50, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 100, 200));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredW2NNormalized() {
|
||||
assertEquals(new Rectangle(75, 0, 50, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 50, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredN2S() {
|
||||
assertEquals(new Rectangle(0, 50, 100, 100), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 333, 333));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredN2SNormalized() {
|
||||
assertEquals(new Rectangle(0, 50, 100, 100), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredN2W() {
|
||||
assertEquals(new Rectangle(0, 75, 100, 50), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 200, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredN2WNormalized() {
|
||||
assertEquals(new Rectangle(0, 75, 100, 50), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredN2N() {
|
||||
assertEquals(new Rectangle(0, 0, 100, 200), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 50, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredN2NN() {
|
||||
assertEquals(new Rectangle(25, 0, 50, 200), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 25, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredN2NW() {
|
||||
assertEquals(new Rectangle(0, 33, 100, 133), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 75, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredN2NWNormalized() {
|
||||
assertEquals(new Rectangle(0, 37, 100, 125), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 125));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOIUniformCenteredN2NNormalized() {
|
||||
assertEquals(new Rectangle(0, 0, 100, 200), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 200));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Absolute AOI centered
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredS2SUp() {
|
||||
assertEquals(new Rectangle(0, 0, 100, 100), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 333, 333));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredS2SDown() {
|
||||
assertEquals(new Rectangle(33, 33, 33, 33), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 33, 33));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredS2SSame() {
|
||||
assertEquals(new Rectangle(0, 0, 100, 100), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 100, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredS2WOverflow() {
|
||||
assertEquals(new Rectangle(0, 0, 100, 100), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 200, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredS2W() {
|
||||
assertEquals(new Rectangle(40, 45, 20, 10), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 20, 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredS2WMax() {
|
||||
assertEquals(new Rectangle(0, 25, 100, 50), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 100, 50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredS2NOverflow() {
|
||||
assertEquals(new Rectangle(0, 0, 100, 100), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 100, 200));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredS2N() {
|
||||
assertEquals(new Rectangle(45, 40, 10, 20), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 10, 20));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredS2NMax() {
|
||||
assertEquals(new Rectangle(25, 0, 50, 100), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 50, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredW2SOverflow() {
|
||||
assertEquals(new Rectangle(0, 0, 200, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 333, 333));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredW2S() {
|
||||
assertEquals(new Rectangle(75, 25, 50, 50), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 50, 50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredW2SMax() {
|
||||
assertEquals(new Rectangle(50, 0, 100, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 100, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredW2WOverflow() {
|
||||
assertEquals(new Rectangle(0, 0, 200, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 300, 200));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredW2W() {
|
||||
assertEquals(new Rectangle(50, 25, 100, 50), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 100, 50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredW2WW() {
|
||||
assertEquals(new Rectangle(10, 40, 180, 20), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 180, 20));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredW2WN() {
|
||||
assertEquals(new Rectangle(62, 25, 75, 50), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 75, 50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredW2WSame() {
|
||||
assertEquals(new Rectangle(0, 0, 200, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 200, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredW2NOverflow() {
|
||||
assertEquals(new Rectangle(50, 0, 100, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 100, 200));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredW2N() {
|
||||
assertEquals(new Rectangle(83, 25, 33, 50), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 33, 50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredW2NMax() {
|
||||
assertEquals(new Rectangle(75, 0, 50, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 50, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredN2S() {
|
||||
assertEquals(new Rectangle(33, 83, 33, 33), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 33, 33));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredN2SMax() {
|
||||
assertEquals(new Rectangle(0, 50, 100, 100), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredN2WOverflow() {
|
||||
assertEquals(new Rectangle(0, 50, 100, 100), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 200, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredN2W() {
|
||||
assertEquals(new Rectangle(40, 95, 20, 10), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 20, 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredN2WMax() {
|
||||
assertEquals(new Rectangle(0, 75, 100, 50), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredN2N() {
|
||||
assertEquals(new Rectangle(45, 90, 10, 20), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 10, 20));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredN2NSame() {
|
||||
assertEquals(new Rectangle(0, 0, 100, 200), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 200));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredN2NN() {
|
||||
assertEquals(new Rectangle(37, 50, 25, 100), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 25, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredN2NW() {
|
||||
assertEquals(new Rectangle(12, 50, 75, 100), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 75, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredN2NWMax() {
|
||||
assertEquals(new Rectangle(0, 37, 100, 125), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 125));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAOICenteredN2NMax() {
|
||||
assertEquals(new Rectangle(0, 0, 100, 200), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 200));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user