From 25f9cc5c55eb319148e92d462753973b68c9da59 Mon Sep 17 00:00:00 2001 From: Harald Kuhr Date: Tue, 14 Dec 2021 19:35:13 +0100 Subject: [PATCH] Delete deprecated Servlet classes (cherry picked from commit b0ad6b2a4b718eafe86d74977fc910d653e8a177) --- .../servlet/AbstractServletMapAdapter.java | 149 -- .../servlet/BrowserHelperFilter.java | 168 -- .../twelvemonkeys/servlet/DebugServlet.java | 122 -- .../twelvemonkeys/servlet/GenericFilter.java | 403 ----- .../twelvemonkeys/servlet/GenericServlet.java | 95 - .../twelvemonkeys/servlet/HttpServlet.java | 95 - .../com/twelvemonkeys/servlet/InitParam.java | 63 - .../servlet/OutputStreamAdapter.java | 127 -- .../servlet/ServletAttributesMapAdapter.java | 136 -- .../servlet/ServletConfigException.java | 84 - .../servlet/ServletConfigMapAdapter.java | 284 --- .../servlet/ServletConfigurator.java | 271 --- .../servlet/ServletHeadersMapAdapter.java | 72 - .../servlet/ServletParametersMapAdapter.java | 69 - .../ServletResponseStreamDelegate.java | 120 -- .../twelvemonkeys/servlet/ServletUtil.java | 785 -------- .../twelvemonkeys/servlet/ThrottleFilter.java | 311 ---- .../twelvemonkeys/servlet/TimingFilter.java | 116 -- .../servlet/TrimWhiteSpaceFilter.java | 246 --- .../servlet/cache/AbstractCacheResponse.java | 82 - .../servlet/cache/CacheFilter.java | 210 --- .../servlet/cache/CacheRequest.java | 57 - .../servlet/cache/CacheResponse.java | 58 - .../servlet/cache/CacheResponseWrapper.java | 266 --- .../servlet/cache/CachedEntity.java | 78 - .../servlet/cache/CachedEntityImpl.java | 174 -- .../servlet/cache/CachedResponse.java | 98 - .../servlet/cache/CachedResponseImpl.java | 220 --- .../servlet/cache/ClientCacheRequest.java | 75 - .../servlet/cache/ClientCacheResponse.java | 56 - .../servlet/cache/HTTPCache.java | 1158 ------------ .../servlet/cache/ResponseResolver.java | 45 - .../cache/SerlvetCacheResponseWrapper.java | 278 --- .../servlet/cache/ServletCacheRequest.java | 88 - .../cache/ServletResponseResolver.java | 72 - .../servlet/cache/WritableCachedResponse.java | 80 - .../cache/WritableCachedResponseImpl.java | 189 -- .../com/twelvemonkeys/servlet/cache/todo.txt | 3 - .../fileupload/FileSizeExceededException.java | 44 - .../servlet/fileupload/FileUploadFilter.java | 129 -- .../fileupload/HttpFileUploadRequest.java | 66 - .../HttpFileUploadRequestWrapper.java | 164 -- .../servlet/fileupload/UploadedFile.java | 89 - .../servlet/fileupload/UploadedFileImpl.java | 94 - .../servlet/gzip/GZIPFilter.java | 151 -- .../servlet/gzip/GZIPResponseWrapper.java | 152 -- .../servlet/image/AWTImageFilterAdapter.java | 76 - .../servlet/image/BufferedImageOpAdapter.java | 71 - .../servlet/image/ColorServlet.java | 216 --- .../servlet/image/ComposeFilter.java | 62 - .../image/ContentNegotiationFilter.java | 443 ----- .../servlet/image/CropFilter.java | 237 --- .../servlet/image/ImageFilter.java | 225 --- .../servlet/image/ImageServletException.java | 58 - .../servlet/image/ImageServletResponse.java | 211 --- .../image/ImageServletResponseImpl.java | 815 --------- .../servlet/image/NullImageFilter.java | 50 - .../servlet/image/RotateFilter.java | 205 --- .../servlet/image/ScaleFilter.java | 333 ---- .../servlet/image/SourceRenderFilter.java | 186 -- .../servlet/image/aoi/AreaOfInterest.java | 51 - .../image/aoi/AreaOfInterestFactory.java | 64 - .../image/aoi/AreaOfInterestWrapper.java | 68 - .../image/aoi/DefaultAreaOfInterest.java | 106 -- .../image/aoi/PercentAreaOfInterest.java | 78 - .../image/aoi/UniformAreaOfInterest.java | 78 - .../servlet/image/package_info.java | 34 +- .../twelvemonkeys/servlet/package_info.java | 34 - .../servlet/FilterAbstractTest.java | 469 ----- .../servlet/GenericFilterTest.java | 181 -- ...ervletAttributesMapAdapterContextTest.java | 162 -- ...ervletAttributesMapAdapterRequestTest.java | 162 -- .../servlet/ServletConfigExceptionTest.java | 131 -- .../servlet/ServletConfigMapAdapterTest.java | 229 --- .../servlet/ServletConfiguratorTest.java | 375 ---- .../servlet/ServletHeadersMapAdapterTest.java | 125 -- .../ServletParametersMapAdapterTest.java | 126 -- .../servlet/ServletResponseAbsrtactTest.java | 53 - .../servlet/TrimWhiteSpaceFilterTest.java | 115 -- .../servlet/cache/HTTPCacheTest.java | 1176 ------------ .../servlet/image/ImageFilterTest.java | 508 ------ .../image/ImageServletResponseImplTest.java | 1612 ----------------- .../servlet/image/aoi/AreaOfInterestTest.java | 365 ---- 83 files changed, 3 insertions(+), 17379 deletions(-) delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/AbstractServletMapAdapter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/BrowserHelperFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/DebugServlet.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/GenericFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/GenericServlet.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/HttpServlet.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/InitParam.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/OutputStreamAdapter.java delete mode 100644 servlet/src/main/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigException.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigMapAdapter.java delete mode 100644 servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigurator.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/ServletParametersMapAdapter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/ServletResponseStreamDelegate.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/ServletUtil.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/ThrottleFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/TimingFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/TrimWhiteSpaceFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/AbstractCacheResponse.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheRequest.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheResponse.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheResponseWrapper.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedEntity.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedEntityImpl.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedResponse.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedResponseImpl.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/ClientCacheRequest.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/ClientCacheResponse.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/HTTPCache.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/ResponseResolver.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/SerlvetCacheResponseWrapper.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/ServletCacheRequest.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/ServletResponseResolver.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/WritableCachedResponse.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/WritableCachedResponseImpl.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/cache/todo.txt delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/FileSizeExceededException.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/FileUploadFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/HttpFileUploadRequest.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/HttpFileUploadRequestWrapper.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/UploadedFile.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/UploadedFileImpl.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/gzip/GZIPFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/gzip/GZIPResponseWrapper.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/AWTImageFilterAdapter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/BufferedImageOpAdapter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/ColorServlet.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/ComposeFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/ContentNegotiationFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/CropFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletException.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponse.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/NullImageFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/RotateFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/ScaleFilter.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/image/SourceRenderFilter.java delete mode 100644 servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterest.java delete mode 100644 servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterestFactory.java delete mode 100644 servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterestWrapper.java delete mode 100644 servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/DefaultAreaOfInterest.java delete mode 100644 servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/PercentAreaOfInterest.java delete mode 100644 servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/UniformAreaOfInterest.java delete mode 100755 servlet/src/main/java/com/twelvemonkeys/servlet/package_info.java delete mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/FilterAbstractTest.java delete mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/GenericFilterTest.java delete mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterContextTest.java delete mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterRequestTest.java delete mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigExceptionTest.java delete mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigMapAdapterTest.java delete mode 100644 servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfiguratorTest.java delete mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTest.java delete mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTest.java delete mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/ServletResponseAbsrtactTest.java delete mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/TrimWhiteSpaceFilterTest.java delete mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/cache/HTTPCacheTest.java delete mode 100644 servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageFilterTest.java delete mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTest.java delete mode 100644 servlet/src/test/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterestTest.java diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/AbstractServletMapAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/AbstractServletMapAdapter.java deleted file mode 100755 index ea76d7dc..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/AbstractServletMapAdapter.java +++ /dev/null @@ -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 Harald Kuhr - * @author last modified by $Author: haku $ - * @version $Id: AbstractServletMapAdapter.java#1 $ - */ -abstract class AbstractServletMapAdapter extends AbstractMap { - // TODO: This map is now a little too lazy.. Should cache entries! - private transient Set> entries; - - protected abstract Iterator 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 names = keysImpl(); names.hasNext(); names.next()) { - size++; - } - - return size; - } - - public Set> entrySet() { - if (entries == null) { - entries = new AbstractSet>() { - public Iterator> iterator() { - return new Iterator>() { - Iterator keys = keysImpl(); - - public boolean hasNext() { - return keys.hasNext(); - } - - public Entry 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 { - 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; - } - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/BrowserHelperFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/BrowserHelperFilter.java deleted file mode 100755 index 9e50b0ef..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/BrowserHelperFilter.java +++ /dev/null @@ -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 Harald Kuhr - * @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 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: - // = - // .accept= - - 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 patterns = new ArrayList(); - List accepts = new ArrayList(); - - 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); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/DebugServlet.java b/servlet/src/main/java/com/twelvemonkeys/servlet/DebugServlet.java deleted file mode 100755 index a198db08..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/DebugServlet.java +++ /dev/null @@ -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 Harald Kuhr - * @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(); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/GenericFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/GenericFilter.java deleted file mode 100755 index f5c88a32..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/GenericFilter.java +++ /dev/null @@ -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. - *

- * {@code GenericFilter} is inspired by {@link GenericServlet}, and - * implements the {@code Filter} and {@code FilterConfig} interfaces. - *

- *

- * {@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. - *

- *

- * {@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. - *

- *

- * To write a generic filter, you need only override the abstract - * {@link #doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)} doFilterImpl} method. - *

- * - * @author Harald Kuhr - * @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}). - *

- * Set this variable to true, to make sure the filter runs once per request. - *

- *

- * NOTE: As of Servlet 2.4, this field - * should always be left to it's default value ({@code false}). - *
- * To run the filter once per request, the {@code filter-mapping} element - * of the web-descriptor should include a {@code dispatcher} element: - *
- *

- *
<dispatcher>REQUEST</dispatcher>
- */ - 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. - *

- * 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, if you are - * overriding this form of the method, - * always call {@code super.init(config)}. - *

- *

- * This implementation will also set all configured key/value pairs, that - * have a matching setter method annotated with {@link InitParam}. - *

- * - * @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. - *

- * Subclasses should not override this method, but rather the - * abstract {@link #doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)} doFilterImpl} method. - *

- * - * @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. - *

- * Note that the method will mark the request as filtered on first - * invocation. - *

- * - * @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; - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/GenericServlet.java b/servlet/src/main/java/com/twelvemonkeys/servlet/GenericServlet.java deleted file mode 100755 index 38010105..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/GenericServlet.java +++ /dev/null @@ -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. - *

- * {@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. - *

- * - * @author Harald Kuhr - * @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. - *

- * 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)}. - *

- *

- * This implementation will also set all configured key/value pairs, that - * have a matching setter method annotated with {@link InitParam}. - *

- * - * @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); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/HttpServlet.java b/servlet/src/main/java/com/twelvemonkeys/servlet/HttpServlet.java deleted file mode 100755 index 849bdb42..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/HttpServlet.java +++ /dev/null @@ -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. - *

- * {@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. - *

- * - * @author Harald Kuhr - * @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. - *

- * 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)}. - *

- *

- * This implementation will also set all configured key/value pairs, that - * have a matching setter method annotated with {@link InitParam}. - *

- * - * @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); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/InitParam.java b/servlet/src/main/java/com/twelvemonkeys/servlet/InitParam.java deleted file mode 100755 index 7306fbf2..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/InitParam.java +++ /dev/null @@ -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 Harald Kuhr - * @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? -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/OutputStreamAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/OutputStreamAdapter.java deleted file mode 100755 index 3c99f45c..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/OutputStreamAdapter.java +++ /dev/null @@ -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:
- * ByteArrayOutputStream buffer = new ByteArraOutputStream();
- * ServletOutputStream adapter = new OutputStreamAdapter(buffer);
- * 
- *

- * 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: - *

- *
- * 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);
- * 
- * - * @author Harald Kuhr - * @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); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapter.java deleted file mode 100644 index 05bd930f..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapter.java +++ /dev/null @@ -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 Harald Kuhr - * @author last modified by $Author: haraldk$ - * @version $Id: ServletAttributesMap.java,v 1.0 01.03.13 10:34 haraldk Exp$ - */ -class ServletAttributesMapAdapter extends AbstractServletMapAdapter { - 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 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 keysImpl() { - final Enumeration keys = getAttributeNames(); - return new Iterator() { - 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; - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigException.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigException.java deleted file mode 100755 index f6effc54..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigException.java +++ /dev/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 Harald Kuhr - * @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); - } - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigMapAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigMapAdapter.java deleted file mode 100755 index 25be94dd..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigMapAdapter.java +++ /dev/null @@ -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. - *

- * This {@code Map} is not synchronized. - *

- * - * @author Harald Kuhr - * @version $Id: ServletConfigMapAdapter.java#2 $ - */ -class ServletConfigMapAdapter extends AbstractMap implements Map, 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> 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> entrySet() { - if (entrySet == null) { - entrySet = createEntrySet(); - } - return entrySet; - } - - private Set> createEntrySet() { - return new AbstractSet>() { - // Cache size, if requested, -1 means not calculated - private int size = -1; - - public Iterator> iterator() { - return new Iterator>() { - // Iterator is backed by initParameterNames enumeration - final Enumeration names = getInitParameterNames(); - - public boolean hasNext() { - return names.hasMoreElements(); - } - - public Entry next() { - final String key = (String) names.nextElement(); - return new Entry() { - 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(); - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigurator.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigurator.java deleted file mode 100644 index 9414748a..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletConfigurator.java +++ /dev/null @@ -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 Harald Kuhr - * @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 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 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 annotatedMethods(final Class pClass, final Class... pAnnotations) { - return new Iterable() { - public Iterator iterator() { - Set methods = new LinkedHashSet(); - - 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(methods.iterator(), new FilterIterator.Filter() { - public boolean accept(final Method pMethod) { - for (Class 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 The Java Language Specification: Classes: Inheritance, Overriding, and Hiding - */ - private boolean isOverriddenWithAnnotation(final Method pMethod, final Class 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; - } - }); - } - }; - } - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapter.java deleted file mode 100755 index f038a7a2..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapter.java +++ /dev/null @@ -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 Harald Kuhr - * @author last modified by $Author: haku $ - * @version $Id: ServletHeadersMapAdapter.java#1 $ - */ -class ServletHeadersMapAdapter extends AbstractServletMapAdapter> { - - protected final HttpServletRequest request; - - public ServletHeadersMapAdapter(final HttpServletRequest pRequest) { - request = notNull(pRequest, "request"); - } - - protected List valueImpl(final String pName) { - @SuppressWarnings("unchecked") - Enumeration headers = request.getHeaders(pName); - return headers == null ? null : toList(CollectionUtil.iterator(headers)); - } - - private static List toList(final Iterator pValues) { - List list = new ArrayList(); - CollectionUtil.addAll(list, pValues); - return Collections.unmodifiableList(list); - } - - protected Iterator keysImpl() { - @SuppressWarnings("unchecked") - Enumeration headerNames = request.getHeaderNames(); - return headerNames == null ? null : CollectionUtil.iterator(headerNames); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletParametersMapAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletParametersMapAdapter.java deleted file mode 100755 index fad767d8..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletParametersMapAdapter.java +++ /dev/null @@ -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 Harald Kuhr - * @author last modified by $Author: haku $ - * @version $Id: ServletParametersMapAdapter.java#1 $ - */ -class ServletParametersMapAdapter extends AbstractServletMapAdapter> { - // 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 valueImpl(String pName) { - String[] values = request.getParameterValues(pName); - return values == null ? null : Arrays.asList(values); - } - - protected Iterator keysImpl() { - @SuppressWarnings("unchecked") - Enumeration names = request.getParameterNames(); - return names == null ? null : CollectionUtil.iterator(names); - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletResponseStreamDelegate.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletResponseStreamDelegate.java deleted file mode 100755 index 3c791c55..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletResponseStreamDelegate.java +++ /dev/null @@ -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. - *

- * Client code should delegate {@code getOutputStream}, {@code getWriter}, - * {@code flushBuffer} and {@code resetBuffer} methods from the servlet response. - *

- * - * @author Harald Kuhr - * @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). - *

- * This implementation simply returns the output stream from the wrapped - * response. - *

- * - * @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; - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletUtil.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletUtil.java deleted file mode 100755 index ce0a377c..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletUtil.java +++ /dev/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 Harald Kuhr - * @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 getParameter(final ServletRequest pReq, final String pName, final Class pType, final String pFormat, final T pDefault) { - // Test if pDefault is either null or instance of pType - if (pDefault != null && !pType.isInstance(pDefault)) { - throw new IllegalArgumentException("default value not instance of " + pType + ": " + pDefault.getClass()); - } - - 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. - *

- * As an example: - *

- *
-     * requestURI = "/webapp/index.jsp"
-     * contextPath = "/webapp"
-     * 
- * 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. - * 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. - * - * @param pConfig the servlet configuration - * @return a {@code Map} view of the config - * @throws IllegalArgumentException if {@code pConfig} is {@code null} - */ - public static Map asMap(final ServletConfig pConfig) { - return new ServletConfigMapAdapter(pConfig); - } - - /** - * Creates an unmodifiable {@code Map} view of the given - * {@code FilterConfig}s init-parameters. - * 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. - * - * @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 asMap(final FilterConfig pConfig) { - return new ServletConfigMapAdapter(pConfig); - } - - /** - * Creates an unmodifiable {@code Map} view of the given - * {@code ServletContext}s init-parameters. - * 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. - * - * @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 initParamsAsMap(final ServletContext pContext) { - return new ServletConfigMapAdapter(pContext); - } - - /** - * Creates an modifiable {@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 attributesAsMap(final ServletContext pContext) { - return new ServletAttributesMapAdapter(pContext); - } - - /** - * Creates an modifiable {@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 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> 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> 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(); - } - } - } -} - diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/ThrottleFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ThrottleFilter.java deleted file mode 100755 index 5ff5e3a0..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ThrottleFilter.java +++ /dev/null @@ -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. - *

- * 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. - *

- * - * @author Harald Kuhr - * @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 responseMessageNames = new HashMap(10); - - /** - * The reposne message sent to user agents, if the request is rejected - */ - private String[] responseMessageTypes = null; - - /** - * Cache for response messages - */ - private Map responseCache = new HashMap(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. - *
- * The format is {@code <mime-type>=<filename>, - * <mime-type>=<filename>}. - *
- * 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 types = new ArrayList(); - - 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 - } - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/TimingFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/TimingFilter.java deleted file mode 100755 index e245d762..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/TimingFilter.java +++ /dev/null @@ -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 Harald Kuhr - * @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); - } - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/TrimWhiteSpaceFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/TrimWhiteSpaceFilter.java deleted file mode 100755 index ad363657..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/TrimWhiteSpaceFilter.java +++ /dev/null @@ -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)}. - *

- * 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). - *

- *

- * At the moment this filter has no concept of encoding. - * This means, that if some multi-byte escape sequence contains one or more - * bytes that individually is treated as a white space, these bytes - * may be skipped. - * As UTF-8 - * guarantees that no bytes are repeated in this way, this filter can safely - * filter UTF-8. - * Simple 8 bit character encodings, like the - * ISO/IEC 8859 standard, or - * Windows-1252" - * are always safe. - *

- *

- * Configuration - *
- * 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. - *

- *

- * Servlet 2.4 version, filter section: - *

- *
- * <!-- 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>
- * 
- * Filter-mapping section:
- *
- * <!-- 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>
- * 
- * - * @author Harald Kuhr - * @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? - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/AbstractCacheResponse.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/AbstractCacheResponse.java deleted file mode 100755 index e236ce5b..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/AbstractCacheResponse.java +++ /dev/null @@ -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 Harald Kuhr - * @author last modified by $Author: haku $ - * @version $Id: AbstractCacheResponse.java#1 $ - */ -@Deprecated -public abstract class AbstractCacheResponse implements CacheResponse { - private int status; - private final Map> headers = new LinkedHashMap>(); // Insertion order - private final Map> 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 values = pAdd ? headers.get(pHeaderName) : null; - - if (values == null) { - values = new ArrayList(); - headers.put(pHeaderName, values); - } - - values.add(pHeaderValue); - } - - public Map> getHeaders() { - return readableHeaders; - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheFilter.java deleted file mode 100755 index 4ba87b61..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheFilter.java +++ /dev/null @@ -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. - *

- * Originally based on ideas and code found in the ONJava article - * Two - * Servlet Filters Every Web Application Should Have - * by Jayson Falkner. - *

- * - * @author Jayson Falkner - * @author Harald Kuhr - * @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); - } - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheRequest.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheRequest.java deleted file mode 100755 index 5d71f3ae..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheRequest.java +++ /dev/null @@ -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 Harald Kuhr - * @author last modified by $Author: haku $ - * @version $Id: CacheRequest.java#1 $ - */ -@Deprecated -public interface CacheRequest { - URI getRequestURI(); - - String getMethod(); - - Map> getHeaders(); - - Map> getParameters(); - - String getServerName(); - - int getServerPort(); -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheResponse.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheResponse.java deleted file mode 100755 index d95e1df2..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheResponse.java +++ /dev/null @@ -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 Harald Kuhr - * @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> getHeaders(); -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheResponseWrapper.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheResponseWrapper.java deleted file mode 100755 index 26127460..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CacheResponseWrapper.java +++ /dev/null @@ -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. - *

- * Based on ideas and code found in the ONJava article - * Two - * Servlet Filters Every Web Application Should Have - * by Jayson Falkner. - *

- * - * @author Jayson Falkner - * @author Harald Kuhr - * @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); - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedEntity.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedEntity.java deleted file mode 100755 index aad05833..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedEntity.java +++ /dev/null @@ -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 Harald Kuhr - * @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(); -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedEntityImpl.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedEntityImpl.java deleted file mode 100755 index 9f131b5b..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedEntityImpl.java +++ /dev/null @@ -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 Harald Kuhr - * @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 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 : 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 : 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 + "]"; - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedResponse.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedResponse.java deleted file mode 100755 index 3e5acf17..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedResponse.java +++ /dev/null @@ -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 Harald Kuhr - * @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> 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(); -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedResponseImpl.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedResponseImpl.java deleted file mode 100755 index a3eebf89..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/CachedResponseImpl.java +++ /dev/null @@ -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 Harald Kuhr - * @version $Id: CachedResponseImpl.java#4 $ - */ -@Deprecated -class CachedResponseImpl implements CachedResponse { - final protected Map> headers; - protected int headersSize; - protected ByteArrayOutputStream content = null; - int status; - - protected CachedResponseImpl() { - headers = new LinkedHashMap>(); // Keep headers in insertion order - } - - // For use by HTTPCache, when recreating CachedResponses from disk cache - CachedResponseImpl(final int pStatus, final LinkedHashMap> 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 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 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 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; - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ClientCacheRequest.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ClientCacheRequest.java deleted file mode 100755 index 137128fa..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ClientCacheRequest.java +++ /dev/null @@ -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 Harald Kuhr - * @author last modified by $Author: haku $ - * @version $Id: ClientCacheRequest.java#1 $ - */ -@Deprecated -public final class ClientCacheRequest extends AbstractCacheRequest { - private Map> parameters; - private Map> headers; - - public ClientCacheRequest(final URI pRequestURI,final Map> pParameters, final Map> pHeaders) { - super(pRequestURI, "GET"); // TODO: Consider supporting more than get? At least HEAD and OPTIONS... - parameters = normalizeMap(pParameters); - headers = normalizeMap(pHeaders); - } - - private Map normalizeMap(Map pMap) { - return pMap == null ? Collections.emptyMap() : Collections.unmodifiableMap(pMap); - } - - public Map> getParameters() { - return parameters; - } - - public Map> getHeaders() { - return headers; - } - - public String getServerName() { - return getRequestURI().getAuthority(); - } - - public int getServerPort() { - return getRequestURI().getPort(); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ClientCacheResponse.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ClientCacheResponse.java deleted file mode 100755 index fe71093e..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ClientCacheResponse.java +++ /dev/null @@ -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 Harald Kuhr - * @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 - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/HTTPCache.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/HTTPCache.java deleted file mode 100755 index aff48c60..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/HTTPCache.java +++ /dev/null @@ -1,1158 +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.*; -import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletResponse; - -import com.twelvemonkeys.io.FileUtil; -import com.twelvemonkeys.lang.StringUtil; -import com.twelvemonkeys.lang.Validate; -import com.twelvemonkeys.net.HTTPUtil; -import com.twelvemonkeys.net.MIMEUtil; -import com.twelvemonkeys.util.LRUHashMap; -import com.twelvemonkeys.util.NullMap; - -/** - * A "simple" HTTP cache. - * - * - Use a mix of parameters and hashcode + lenght with fixed (max) lenght? - * (Hashcodes of Strings are constant). - * - Store full filenames in .vary, instead of just extension, and use - * short filenames? (and only one .vary per dir). - *

- * - *

- * - * @author Harald Kuhr - * @version $Id: HTTPCache.java#4 $ - */ -// TODO: OMPTIMIZE: Cache parsed vary-info objects, not the properties-files -// TODO: BUG: Better filename handling, as some filenames become too long.. -// TODO: TEST: Battle-testing using some URL-hammer tool and maybe a profiler -// TODO: ETag/Conditional (If-None-Match) support! -// TODO: Rewrite to use java.util.concurrent Locks (if possible) for performance -// Maybe use ConcurrentHashMap instead fo synchronized HashMap? -// TODO: Rewrite to use NIO for performance -// TODO: Allow no tempdir for in-memory only cache -// TODO: Specify max size of disk-cache -@Deprecated -public class HTTPCache { - /** - * The HTTP header {@code "Cache-Control"} - */ - protected static final String HEADER_CACHE_CONTROL = "Cache-Control"; - /** - * The HTTP header {@code "Content-Type"} - */ - protected static final String HEADER_CONTENT_TYPE = "Content-Type"; - /** - * The HTTP header {@code "Date"} - */ - protected static final String HEADER_DATE = "Date"; - /** - * The HTTP header {@code "ETag"} - */ - protected static final String HEADER_ETAG = "ETag"; - /** - * The HTTP header {@code "Expires"} - */ - protected static final String HEADER_EXPIRES = "Expires"; - /** - * The HTTP header {@code "If-Modified-Since"} - */ - protected static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since"; - /** - * The HTTP header {@code "If-None-Match"} - */ - protected static final String HEADER_IF_NONE_MATCH = "If-None-Match"; - /** - * The HTTP header {@code "Last-Modified"} - */ - protected static final String HEADER_LAST_MODIFIED = "Last-Modified"; - /** - * The HTTP header {@code "Pragma"} - */ - protected static final String HEADER_PRAGMA = "Pragma"; - /** - * The HTTP header {@code "Vary"} - */ - protected static final String HEADER_VARY = "Vary"; - /** - * The HTTP header {@code "Warning"} - */ - protected static final String HEADER_WARNING = "Warning"; - /** - * HTTP extension header {@code "X-Cached-At"} - */ - protected static final String HEADER_CACHED_TIME = "X-Cached-At"; - - /** - * The file extension for header files ({@code ".headers"}) - */ - protected static final String FILE_EXT_HEADERS = ".headers"; - /** - * The file extension for varation-info files ({@code ".vary"}) - */ - protected static final String FILE_EXT_VARY = ".vary"; - - /** - * The directory used for the disk-based cache - */ - private File tempDir; - - /** - * Indicates wether the disk-based cache should be deleted when the - * container shuts down/VM exits - */ - private boolean deleteCacheOnExit; - - /** - * In-memory content cache - */ - private final Map contentCache; - /** - * In-memory enity cache - */ - private final Map entityCache; - /** - * In-memory varyiation-info cache - */ - private final Map varyCache; - - private long defaultExpiryTime = -1; - - private final Logger logger; - - // Internal constructor for sublcasses only - protected HTTPCache( - final File pTempFolder, - final long pDefaultCacheExpiryTime, - final int pMaxMemCacheSize, - final int pMaxCachedEntites, - final boolean pDeleteCacheOnExit, - final Logger pLogger - ) { - Validate.notNull(pTempFolder, "temp folder"); - Validate.isTrue(pTempFolder.exists() || pTempFolder.mkdirs(), pTempFolder.getAbsolutePath(), "Could not create required temp directory: %s"); - Validate.isTrue(pTempFolder.canRead() && pTempFolder.canWrite(), pTempFolder.getAbsolutePath(), "Must have read/write access to temp folder: %s"); - - Validate.isTrue(pDefaultCacheExpiryTime >= 0, pDefaultCacheExpiryTime, "Negative expiry time: %d"); - Validate.isTrue(pMaxMemCacheSize >= 0, pDefaultCacheExpiryTime, "Negative maximum memory cache size: %d"); - Validate.isTrue(pMaxCachedEntites >= 0, pDefaultCacheExpiryTime, "Negative maximum number of cached entries: %d"); - - defaultExpiryTime = pDefaultCacheExpiryTime; - - if (pMaxMemCacheSize > 0) { -// Map backing = new SizedLRUMap(pMaxMemCacheSize); // size in bytes -// contentCache = new TimeoutMap(backing, null, pDefaultCacheExpiryTime); - contentCache = new SizedLRUMap(pMaxMemCacheSize); // size in bytes - } - else { - contentCache = new NullMap(); - } - - entityCache = new LRUHashMap(pMaxCachedEntites); - varyCache = new LRUHashMap(pMaxCachedEntites); - - deleteCacheOnExit = pDeleteCacheOnExit; - - tempDir = pTempFolder; - - logger = pLogger != null ? pLogger : Logger.getLogger(getClass().getName()); - } - - /** - * Creates an {@code HTTPCache}. - * - * @param pTempFolder the temp folder for this cache. - * @param pDefaultCacheExpiryTime Default expiry time for cached entities, - * {@code >= 0} - * @param pMaxMemCacheSize Maximum size of in-memory cache for content - * in bytes, {@code >= 0} ({@code 0} means no - * in-memory cache) - * @param pMaxCachedEntites Maximum number of entities in cache - * @param pDeleteCacheOnExit specifies wether the file cache should be - * deleted when the application or VM shuts down - * @throws IllegalArgumentException if {@code pName} or {@code pContext} is - * {@code null} or if any of {@code pDefaultCacheExpiryTime}, - * {@code pMaxMemCacheSize} or {@code pMaxCachedEntites} are - * negative, - * or if the directory as given in the context attribute - * {@code "javax.servlet.context.tempdir"} does not exist, and - * cannot be created. - */ - public HTTPCache(final File pTempFolder, - final long pDefaultCacheExpiryTime, - final int pMaxMemCacheSize, final int pMaxCachedEntites, - final boolean pDeleteCacheOnExit) { - this(pTempFolder, pDefaultCacheExpiryTime, pMaxMemCacheSize, pMaxCachedEntites, pDeleteCacheOnExit, null); - } - - - /** - * Creates an {@code HTTPCache}. - * - * @param pName Name of this cache (should be unique per application). - * Used for temp folder - * @param pContext Servlet context for the application. - * @param pDefaultCacheExpiryTime Default expiry time for cached entities, - * {@code >= 0} - * @param pMaxMemCacheSize Maximum size of in-memory cache for content - * in bytes, {@code >= 0} ({@code 0} means no - * in-memory cache) - * @param pMaxCachedEntites Maximum number of entities in cache - * @param pDeleteCacheOnExit specifies wether the file cache should be - * deleted when the application or VM shuts down - * @throws IllegalArgumentException if {@code pName} or {@code pContext} is - * {@code null} or if any of {@code pDefaultCacheExpiryTime}, - * {@code pMaxMemCacheSize} or {@code pMaxCachedEntites} are - * negative, - * or if the directory as given in the context attribute - * {@code "javax.servlet.context.tempdir"} does not exist, and - * cannot be created. - * @deprecated Use {@link #HTTPCache(File, long, int, int, boolean)} instead. - */ - @Deprecated - public HTTPCache(final String pName, final ServletContext pContext, - final int pDefaultCacheExpiryTime, final int pMaxMemCacheSize, - final int pMaxCachedEntites, final boolean pDeleteCacheOnExit) { - this( - getTempFolder(pName, pContext), - pDefaultCacheExpiryTime, pMaxMemCacheSize, pMaxCachedEntites, pDeleteCacheOnExit, - new CacheFilter.ServletContextLoggerAdapter(pName, pContext) - ); - } - - private static File getTempFolder(String pName, ServletContext pContext) { - Validate.notNull(pName, "name"); - Validate.isTrue(!StringUtil.isEmpty(pName), pName, "empty name: '%s'"); - Validate.notNull(pContext, "context"); - - File tempRoot = (File) pContext.getAttribute("javax.servlet.context.tempdir"); - if (tempRoot == null) { - throw new IllegalStateException("Missing context attribute \"javax.servlet.context.tempdir\""); - } - - return new File(tempRoot, pName); - } - - public String toString() { - StringBuilder buf = new StringBuilder(getClass().getSimpleName()); - buf.append("["); - buf.append("Temp dir: "); - buf.append(tempDir.getAbsolutePath()); - if (deleteCacheOnExit) { - buf.append(" (non-persistent)"); - } - else { - buf.append(" (persistent)"); - } - buf.append(", EntityCache: {"); - buf.append(entityCache.size()); - buf.append(" entries in a "); - buf.append(entityCache.getClass().getName()); - buf.append("}, VaryCache: {"); - buf.append(varyCache.size()); - buf.append(" entries in a "); - buf.append(varyCache.getClass().getName()); - buf.append("}, ContentCache: {"); - buf.append(contentCache.size()); - buf.append(" entries in a "); - buf.append(contentCache.getClass().getName()); - buf.append("}]"); - - return buf.toString(); - } - - void log(final String pMessage) { - logger.log(Level.INFO, pMessage); - } - - void log(final String pMessage, Throwable pException) { - logger.log(Level.WARNING, pMessage, pException); - } - - /** - * Looks up the {@code CachedEntity} for the given request. - * - * @param pRequest the request - * @param pResponse the response - * @param pResolver the resolver - * @throws java.io.IOException if an I/O error occurs - * @throws CacheException if the cached entity can't be resolved for some reason - */ - public void doCached(final CacheRequest pRequest, final CacheResponse pResponse, final ResponseResolver pResolver) throws IOException, CacheException { - // TODO: Expire cached items on PUT/POST/DELETE/PURGE - // If not cachable request, resolve directly - if (!isCacheable(pRequest)) { - pResolver.resolve(pRequest, pResponse); - } - else { - // Generate cacheURI - String cacheURI = generateCacheURI(pRequest); -// System.out.println(" ## HTTPCache ## Request Id (cacheURI): " + cacheURI); - - // Get/create cached entity - CachedEntity cached; - synchronized (entityCache) { - cached = entityCache.get(cacheURI); - if (cached == null) { - cached = new CachedEntityImpl(cacheURI, this); - entityCache.put(cacheURI, cached); - } - } - - // else if (not cached || stale), resolve through wrapped (caching) response - // else render to response - - // TODO: This is a bottleneck for uncachable resources. Should not - // synchronize, if we know (HOW?) the resource is not cachable. - synchronized (cached) { - if (cached.isStale(pRequest) /* TODO: NOT CACHED?! */) { - // Go fetch... - WritableCachedResponse cachedResponse = cached.createCachedResponse(); - pResolver.resolve(pRequest, cachedResponse); - - if (isCachable(cachedResponse)) { -// System.out.println("Registering content: " + cachedResponse.getCachedResponse()); - registerContent(cacheURI, pRequest, cachedResponse.getCachedResponse()); - } - else { - // TODO: What about non-cachable responses? We need to either remove them from cache, or mark them as stale... - // Best is probably to mark as non-cacheable for later, and NOT store content (performance) -// System.out.println("Non-cacheable response: " + cachedResponse); - - // TODO: Write, but should really do this unbuffered.... And some resolver might be able to do just that? - // Might need a resolver.isWriteThroughForUncachableResources() method... - pResponse.setStatus(cachedResponse.getStatus()); - cachedResponse.writeHeadersTo(pResponse); - cachedResponse.writeContentsTo(pResponse.getOutputStream()); - return; - } - } - } - - cached.render(pRequest, pResponse); - } - } - - protected void invalidate(CacheRequest pRequest) { - // Generate cacheURI - String cacheURI = generateCacheURI(pRequest); - - // Get/create cached entity - CachedEntity cached; - synchronized (entityCache) { - cached = entityCache.get(cacheURI); - if (cached != null) { - // TODO; Remove all variants - entityCache.remove(cacheURI); - } - } - - } - - private boolean isCacheable(final CacheRequest pRequest) { - // TODO: Support public/private cache (a cache probably have to be one of the two, when created) - // TODO: Only private caches should cache requests with Authorization - - // TODO: OptimizeMe! - // It's probably best to cache the "cacheableness" of a request and a resource separately - List cacheControlValues = pRequest.getHeaders().get(HEADER_CACHE_CONTROL); - if (cacheControlValues != null) { - Map cacheControl = new HashMap(); - for (String cc : cacheControlValues) { - List directives = Arrays.asList(cc.split(",")); - for (String directive : directives) { - directive = directive.trim(); - if (directive.length() > 0) { - String[] directiveParts = directive.split("=", 2); - cacheControl.put(directiveParts[0], directiveParts.length > 1 ? directiveParts[1] : null); - } - } - } - - if (cacheControl.containsKey("no-cache") || cacheControl.containsKey("no-store")) { - return false; - } - - /* - "no-cache" ; Section 14.9.1 - | "no-store" ; Section 14.9.2 - | "max-age" "=" delta-seconds ; Section 14.9.3, 14.9.4 - | "max-stale" [ "=" delta-seconds ] ; Section 14.9.3 - | "min-fresh" "=" delta-seconds ; Section 14.9.3 - | "no-transform" ; Section 14.9.5 - | "only-if-cached" - */ - } - - return true; - } - - private boolean isCachable(final CacheResponse pResponse) { - if (pResponse.getStatus() != HttpServletResponse.SC_OK) { - return false; - } - - // Vary: * - List values = pResponse.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 = pResponse.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 = pResponse.getHeaders().get(HTTPCache.HEADER_PRAGMA); - if (values != null) { - for (String value : values) { - if (StringUtil.contains(value, "no-cache")) { - return false; - } - } - } - - return true; - } - - - /** - * Allows a server-side cache mechanism to peek at the real file. - * Default implementation return {@code null}. - * - * @param pRequest the request - * @return {@code null}, always - */ - protected File getRealFile(final CacheRequest pRequest) { - // TODO: Create callback for this? Only possible for server-side cache... Maybe we can get away without this? - // For now: Default implementation that returns null - return null; -/* - String contextRelativeURI = ServletUtil.getContextRelativeURI(pRequest); - // System.out.println(" ## HTTPCache ## Context relative URI: " + contextRelativeURI); - - String path = mContext.getRealPath(contextRelativeURI); - // System.out.println(" ## HTTPCache ## Real path: " + path); - - if (path != null) { - return new File(path); - } - - return null; -*/ - } - - private File getCachedFile(final String pCacheURI, final CacheRequest pRequest) { - File file = null; - - // Get base dir - File base = new File(tempDir, "./" + pCacheURI); - final String basePath = base.getAbsolutePath(); - File directory = base.getParentFile(); - - // Get list of files that are candidates - File[] candidates = directory.listFiles(new FileFilter() { - public boolean accept(File pFile) { - return pFile.getAbsolutePath().startsWith(basePath) - && !pFile.getName().endsWith(FILE_EXT_HEADERS) - && !pFile.getName().endsWith(FILE_EXT_VARY); - } - }); - - // Negotiation - if (candidates != null) { - String extension = getVaryExtension(pCacheURI, pRequest); - //System.out.println("-- Vary ext: " + extension); - if (extension != null) { - for (File candidate : candidates) { - //System.out.println("-- Candidate: " + candidates[i]); - - if (extension.equals("ANY") || extension.equals(FileUtil.getExtension(candidate))) { - //System.out.println("-- Candidate selected"); - file = candidate; - break; - } - } - } - } - else if (base.exists()) { - //System.out.println("-- File not a directory: " + directory); - log("File not a directory: " + directory); - } - - return file; - } - - private String getVaryExtension(final String pCacheURI, final CacheRequest pRequest) { - Properties variations = getVaryProperties(pCacheURI); - - String[] varyHeaders = StringUtil.toStringArray(variations.getProperty(HEADER_VARY, "")); -// System.out.println("-- Vary: \"" + variations.getProperty(HEADER_VARY) + "\""); - - String varyKey = createVaryKey(varyHeaders, pRequest); -// System.out.println("-- Vary key: \"" + varyKey + "\""); - - // If no vary, just go with any version... - return StringUtil.isEmpty(varyKey) ? "ANY" : variations.getProperty(varyKey, null); - } - - private String createVaryKey(final String[] pVaryHeaders, final CacheRequest pRequest) { - if (pVaryHeaders == null) { - return null; - } - - StringBuilder headerValues = new StringBuilder(); - for (String varyHeader : pVaryHeaders) { - List varies = pRequest.getHeaders().get(varyHeader); - String headerValue = varies != null && varies.size() > 0 ? varies.get(0) : null; - - headerValues.append(varyHeader); - headerValues.append("__V_"); - headerValues.append(createSafeHeader(headerValue)); - } - - return headerValues.toString(); - } - - private void storeVaryProperties(final String pCacheURI, final Properties pVariations) { - synchronized (pVariations) { - try { - File file = getVaryPropertiesFile(pCacheURI); - if (!file.exists() && deleteCacheOnExit) { - file.deleteOnExit(); - } - - FileOutputStream out = new FileOutputStream(file); - try { - pVariations.store(out, pCacheURI + " Vary info"); - } - finally { - out.close(); - } - } - catch (IOException ioe) { - log("Error: Could not store Vary info: " + ioe); - } - } - } - - private Properties getVaryProperties(final String pCacheURI) { - Properties variations; - - synchronized (varyCache) { - variations = varyCache.get(pCacheURI); - if (variations == null) { - variations = loadVaryProperties(pCacheURI); - varyCache.put(pCacheURI, variations); - } - } - - return variations; - } - - private Properties loadVaryProperties(final String pCacheURI) { - // Read Vary info, for content negotiation - Properties variations = new Properties(); - File vary = getVaryPropertiesFile(pCacheURI); - if (vary.exists()) { - try { - FileInputStream in = new FileInputStream(vary); - try { - variations.load(in); - } - finally { - in.close(); - } - } - catch (IOException ioe) { - log("Error: Could not load Vary info: " + ioe); - } - } - return variations; - } - - private File getVaryPropertiesFile(final String pCacheURI) { - return new File(tempDir, "./" + pCacheURI + FILE_EXT_VARY); - } - - private static String generateCacheURI(final CacheRequest pRequest) { - StringBuilder buffer = new StringBuilder(); - - // Note: As the '/'s are not replaced, the directory structure will be recreated - // TODO: Old mehtod relied on context relativization, that must now be handled byt the ServletCacheRequest -// String contextRelativeURI = ServletUtil.getContextRelativeURI(pRequest); - String contextRelativeURI = pRequest.getRequestURI().getPath(); - buffer.append(contextRelativeURI); - - // Create directory for all resources - if (contextRelativeURI.charAt(contextRelativeURI.length() - 1) != '/') { - buffer.append('/'); - } - - // Get parameters from request, and recreate query to avoid unneccessary - // regeneration/caching when parameters are out of order - // Also makes caching work for POST - appendSortedRequestParams(pRequest, buffer); - - return buffer.toString(); - } - - private static void appendSortedRequestParams(final CacheRequest pRequest, final StringBuilder pBuffer) { - Set names = pRequest.getParameters().keySet(); - if (names.isEmpty()) { - pBuffer.append("defaultVersion"); - return; - } - - // We now have parameters - pBuffer.append('_'); // append '_' for '?', to avoid clash with default - - // Create a sorted map - SortedMap> sortedQueryMap = new TreeMap>(); - for (String name : names) { - List values = pRequest.getParameters().get(name); - - sortedQueryMap.put(name, values); - } - - // Iterate over sorted map, and append to stringbuffer - for (Iterator>> iterator = sortedQueryMap.entrySet().iterator(); iterator.hasNext();) { - Map.Entry> entry = iterator.next(); - pBuffer.append(createSafe(entry.getKey())); - - List values = entry.getValue(); - if (values != null && values.size() > 0) { - pBuffer.append("_V"); // = - for (int i = 0; i < values.size(); i++) { - String value = values.get(i); - if (i != 0) { - pBuffer.append(','); - } - pBuffer.append(createSafe(value)); - } - } - - if (iterator.hasNext()) { - pBuffer.append("_P"); // & - } - } - } - - private static String createSafe(final String pKey) { - return pKey.replace('/', '-') - .replace('&', '-') // In case they are encoded - .replace('#', '-') - .replace(';', '-'); - } - - private static String createSafeHeader(final String pHeaderValue) { - if (pHeaderValue == null) { - return "NULL"; - } - - return pHeaderValue.replace(' ', '_') - .replace(':', '_') - .replace('=', '_'); - } - - /** - * Registers content for the given URI in the cache. - * - * @param pCacheURI the cache URI - * @param pRequest the request - * @param pCachedResponse the cached response - * @throws IOException if the content could not be cached - */ - void registerContent( - final String pCacheURI, - final CacheRequest pRequest, - final CachedResponse pCachedResponse - ) throws IOException { - // System.out.println(" ## HTTPCache ## Registering content for " + pCacheURI); - -// pRequest.removeAttribute(ATTRIB_IS_STALE); -// pRequest.setAttribute(ATTRIB_CACHED_RESPONSE, pCachedResponse); - - if ("HEAD".equals(pRequest.getMethod())) { - // System.out.println(" ## HTTPCache ## Was HEAD request, will NOT store content."); - return; - } - - // TODO: Several resources may have same extension... - String extension = MIMEUtil.getExtension(pCachedResponse.getHeaderValue(HEADER_CONTENT_TYPE)); - if (extension == null) { - extension = "[NULL]"; - } - - synchronized (contentCache) { - contentCache.put(pCacheURI + '.' + extension, pCachedResponse); - - // This will be the default version - if (!contentCache.containsKey(pCacheURI)) { - contentCache.put(pCacheURI, pCachedResponse); - } - } - - // Write the cached content to disk - File content = new File(tempDir, "./" + pCacheURI + '.' + extension); - if (deleteCacheOnExit && !content.exists()) { - content.deleteOnExit(); - } - - File parent = content.getParentFile(); - if (!(parent.exists() || parent.mkdirs())) { - log("Could not create directory " + parent.getAbsolutePath()); - - // TODO: Make sure vary-info is still created in memory - - return; - } - - OutputStream mContentStream = new BufferedOutputStream(new FileOutputStream(content)); - - try { - pCachedResponse.writeContentsTo(mContentStream); - } - finally { - try { - mContentStream.close(); - } - catch (IOException e) { - log("Error closing content stream: " + e.getMessage(), e); - } - } - - // Write the cached headers to disk (in pseudo-properties-format) - File headers = new File(content.getAbsolutePath() + FILE_EXT_HEADERS); - if (deleteCacheOnExit && !headers.exists()) { - headers.deleteOnExit(); - } - - FileWriter writer = new FileWriter(headers); - PrintWriter headerWriter = new PrintWriter(writer); - try { - String[] names = pCachedResponse.getHeaderNames(); - - for (String name : names) { - String[] values = pCachedResponse.getHeaderValues(name); - - headerWriter.print(name); - headerWriter.print(": "); - headerWriter.println(StringUtil.toCSVString(values, "\\")); - } - } - finally { - headerWriter.flush(); - try { - writer.close(); - } - catch (IOException e) { - log("Error closing header stream: " + e.getMessage(), e); - } - } - - // TODO: Make this more robust, if some weird entity is not - // consistent in it's vary-headers.. - // (sometimes Vary, sometimes not, or somtimes different Vary headers). - - // Write extra Vary info to disk - String[] varyHeaders = pCachedResponse.getHeaderValues(HEADER_VARY); - - // If no variations, then don't store vary info - if (varyHeaders != null && varyHeaders.length > 0) { - Properties variations = getVaryProperties(pCacheURI); - - String vary = StringUtil.toCSVString(varyHeaders); - variations.setProperty(HEADER_VARY, vary); - - // Create Vary-key and map to file extension... - String varyKey = createVaryKey(varyHeaders, pRequest); -// System.out.println("varyKey: " + varyKey); -// System.out.println("extension: " + extension); - variations.setProperty(varyKey, extension); - - storeVaryProperties(pCacheURI, variations); - } - } - - /** - * @param pCacheURI the cache URI - * @param pRequest the request - * @return a {@code CachedResponse} object - */ - CachedResponse getContent(final String pCacheURI, final CacheRequest pRequest) { -// System.err.println(" ## HTTPCache ## Looking up content for " + pCacheURI); -// Thread.dumpStack(); - - String extension = getVaryExtension(pCacheURI, pRequest); - - CachedResponse response; - synchronized (contentCache) { -// System.out.println(" ## HTTPCache ## Looking up content with ext: \"" + extension + "\" from memory cache (" + contentCache /*.size()*/ + " entries)..."); - if ("ANY".equals(extension)) { - response = contentCache.get(pCacheURI); - } - else { - response = contentCache.get(pCacheURI + '.' + extension); - } - - if (response == null) { -// System.out.println(" ## HTTPCache ## Content not found in memory cache."); -// -// System.out.println(" ## HTTPCache ## Looking up content from disk cache..."); - // Read from disk-cache - response = readFromDiskCache(pCacheURI, pRequest); - } - -// if (response == null) { -// System.out.println(" ## HTTPCache ## Content not found in disk cache."); -// } -// else { -// System.out.println(" ## HTTPCache ## Content for " + pCacheURI + " found: " + response); -// } - } - - return response; - } - - private CachedResponse readFromDiskCache(String pCacheURI, CacheRequest pRequest) { - CachedResponse response = null; - try { - File content = getCachedFile(pCacheURI, pRequest); - if (content != null && content.exists()) { - // Read contents - byte[] contents = FileUtil.read(content); - - // Read headers - File headers = new File(content.getAbsolutePath() + FILE_EXT_HEADERS); - int headerSize = (int) headers.length(); - - BufferedReader reader = new BufferedReader(new FileReader(headers)); - LinkedHashMap> headerMap = new LinkedHashMap>(); - String line; - while ((line = reader.readLine()) != null) { - int colIdx = line.indexOf(':'); - String name; - String value; - if (colIdx >= 0) { - name = line.substring(0, colIdx); - value = line.substring(colIdx + 2); // ": " - } - else { - name = line; - value = ""; - } - - headerMap.put(name, Arrays.asList(StringUtil.toStringArray(value, "\\"))); - } - - response = new CachedResponseImpl(HttpServletResponse.SC_OK, headerMap, headerSize, contents); - contentCache.put(pCacheURI + '.' + FileUtil.getExtension(content), response); - } - } - catch (IOException e) { - log("Error reading from cache: " + e.getMessage(), e); - } - return response; - } - - boolean isContentStale(final String pCacheURI, final CacheRequest pRequest) { - // NOTE: Content is either stale or not, for the duration of one request, unless re-fetched - // Means that we must retry after a registerContent(), if caching as request-attribute - Boolean stale; -// stale = (Boolean) pRequest.getAttribute(ATTRIB_IS_STALE); -// if (stale != null) { -// return stale; -// } - - stale = isContentStaleImpl(pCacheURI, pRequest); -// pRequest.setAttribute(ATTRIB_IS_STALE, stale); - - return stale; - } - - private boolean isContentStaleImpl(final String pCacheURI, final CacheRequest pRequest) { - CachedResponse response = getContent(pCacheURI, pRequest); - - if (response == null) { - // System.out.println(" ## HTTPCache ## Content is stale (no content)."); - return true; - } - - // TODO: Get max-age=... from REQUEST too! - - // TODO: What about time skew? Now should be (roughly) same as: - // long now = pRequest.getDateHeader("Date"); - // TODO: If the time differs (server "now" vs client "now"), should we - // take that into consideration when testing for stale content? - // Probably, yes. - // TODO: Define rules for how to handle time skews - - // Set timestamp check - // NOTE: HTTP Dates are always in GMT time zone - long now = (System.currentTimeMillis() / 1000L) * 1000L; - long expires = getDateHeader(response.getHeaderValue(HEADER_EXPIRES)); - //long lastModified = getDateHeader(response, HEADER_LAST_MODIFIED); - long lastModified = getDateHeader(response.getHeaderValue(HEADER_CACHED_TIME)); - - // If expires header is not set, compute it - if (expires == -1L) { - /* - // Note: Not all content has Last-Modified header. We should then - // use lastModified() of the cached file, to compute expires time. - if (lastModified == -1L) { - File cached = getCachedFile(pCacheURI, pRequest); - if (cached != null && cached.exists()) { - lastModified = cached.lastModified(); - //// System.out.println(" ## HTTPCache ## Last-Modified is " + HTTPUtil.formatHTTPDate(lastModified) + ", using cachedFile.lastModified()"); - } - } - */ - - // If Cache-Control: max-age is present, use it, otherwise default - int maxAge = getIntHeader(response, HEADER_CACHE_CONTROL, "max-age"); - if (maxAge == -1) { - expires = lastModified + defaultExpiryTime; - //// System.out.println(" ## HTTPCache ## Expires is " + HTTPUtil.formatHTTPDate(expires) + ", using lastModified + defaultExpiry"); - } - else { - expires = lastModified + (maxAge * 1000L); // max-age is seconds - //// System.out.println(" ## HTTPCache ## Expires is " + HTTPUtil.formatHTTPDate(expires) + ", using lastModified + maxAge"); - } - } - /* - else { - // System.out.println(" ## HTTPCache ## Expires header is " + response.getHeaderValue(HEADER_EXPIRES)); - } - */ - - // Expired? - if (expires < now) { - // System.out.println(" ## HTTPCache ## Content is stale (content expired: " - // + HTTPUtil.formatHTTPDate(expires) + " before " + HTTPUtil.formatHTTPDate(now) + ")."); - return true; - } - - /* - if (lastModified == -1L) { - // Note: Not all content has Last-Modified header. We should then - // use lastModified() of the cached file, to compute expires time. - File cached = getCachedFile(pCacheURI, pRequest); - if (cached != null && cached.exists()) { - lastModified = cached.lastModified(); - //// System.out.println(" ## HTTPCache ## Last-Modified is " + HTTPUtil.formatHTTPDate(lastModified) + ", using cachedFile.lastModified()"); - } - } - */ - - // Get the real file for this request, if any - File real = getRealFile(pRequest); - //noinspection RedundantIfStatement - if (real != null && real.exists() && real.lastModified() > lastModified) { - // System.out.println(" ## HTTPCache ## Content is stale (new content" - // + HTTPUtil.formatHTTPDate(lastModified) + " before " + HTTPUtil.formatHTTPDate(real.lastModified()) + ")."); - return true; - } - - return false; - } - - /** - * Parses a cached header with directive to an int. - * E.g: Cache-Control: max-age=60, returns 60 - * - * @param pCached the cached response - * @param pHeaderName the header name (e.g: {@code CacheControl}) - * @param pDirective the directive (e.g: {@code max-age} - * @return the int value, or {@code -1} if not found - */ - private int getIntHeader(final CachedResponse pCached, final String pHeaderName, final String pDirective) { - String[] headerValues = pCached.getHeaderValues(pHeaderName); - int value = -1; - - if (headerValues != null) { - for (String headerValue : headerValues) { - if (pDirective == null) { - if (!StringUtil.isEmpty(headerValue)) { - value = Integer.parseInt(headerValue); - } - break; - } - else { - int start = headerValue.indexOf(pDirective); - - // Directive found - if (start >= 0) { - - int end = headerValue.lastIndexOf(','); - if (end < start) { - end = headerValue.length(); - } - - headerValue = headerValue.substring(start, end); - - if (!StringUtil.isEmpty(headerValue)) { - value = Integer.parseInt(headerValue); - } - - break; - } - } - } - } - - return value; - } - - /** - * Utility to read a date header from a cached response. - * - * @param pHeaderValue the header value - * @return the parsed date as a long, or {@code -1L} if not found - * @see javax.servlet.http.HttpServletRequest#getDateHeader(String) - */ - static long getDateHeader(final String pHeaderValue) { - long date = -1L; - if (pHeaderValue != null) { - date = HTTPUtil.parseHTTPDate(pHeaderValue); - } - return date; - } - - // TODO: Extract and make public? - final static class SizedLRUMap extends LRUHashMap { - int currentSize; - int maxSize; - - public SizedLRUMap(int pMaxSize) { - //super(true); - super(); // Note: super.maxSize doesn't count... - maxSize = pMaxSize; - } - - - // In super (LRUMap?) this could just return 1... - protected int sizeOf(Object pValue) { - // HACK: As this is used as a backing for a TimeoutMap, the values - // will themselves be Entries... - while (pValue instanceof Map.Entry) { - pValue = ((Map.Entry) pValue).getValue(); - } - - CachedResponse cached = (CachedResponse) pValue; - return (cached != null ? cached.size() : 0); - } - - @Override - public V put(K pKey, V pValue) { - currentSize += sizeOf(pValue); - - V old = super.put(pKey, pValue); - if (old != null) { - currentSize -= sizeOf(old); - } - return old; - } - - @Override - public V remove(Object pKey) { - V old = super.remove(pKey); - if (old != null) { - currentSize -= sizeOf(old); - } - return old; - } - - @Override - protected boolean removeEldestEntry(Map.Entry pEldest) { - if (maxSize <= currentSize) { // NOTE: maxSize here is mem size - removeLRU(); - } - return false; - } - - @Override - public void removeLRU() { - while (maxSize <= currentSize) { // NOTE: maxSize here is mem size - super.removeLRU(); - } - } - } - -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ResponseResolver.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ResponseResolver.java deleted file mode 100755 index a27ea28a..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ResponseResolver.java +++ /dev/null @@ -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 Harald Kuhr - * @author last modified by $Author: haku $ - * @version $Id: ResponseResolver.java#2 $ - */ -@Deprecated -public interface ResponseResolver { - void resolve(CacheRequest pRequest, CacheResponse pResponse) throws IOException, CacheException; -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/SerlvetCacheResponseWrapper.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/SerlvetCacheResponseWrapper.java deleted file mode 100755 index a50add40..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/SerlvetCacheResponseWrapper.java +++ /dev/null @@ -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. - *

- * Based on ideas and code found in the ONJava article - * Two - * Servlet Filters Every Web Application Should Have - * by Jayson Falkner. - *

- * - * @author Jayson Falkner - * @author Harald Kuhr - * @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> headers = pResponse.getHeaders(); - for (Map.Entry> 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 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); - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ServletCacheRequest.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ServletCacheRequest.java deleted file mode 100755 index 8ab24829..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ServletCacheRequest.java +++ /dev/null @@ -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 Harald Kuhr - * @author last modified by $Author: haku $ - * @version $Id: ServletCacheRequest.java#1 $ - */ -@Deprecated -public final class ServletCacheRequest extends AbstractCacheRequest { - private final HttpServletRequest request; - - private Map> headers; - private Map> parameters; - - protected ServletCacheRequest(final HttpServletRequest pRequest) { - super(URI.create(pRequest.getRequestURI()), pRequest.getMethod()); - request = pRequest; - } - - public Map> getHeaders() { - if (headers == null) { - headers = ServletUtil.headersAsMap(request); - } - - return headers; - } - - public Map> 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; - } - -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ServletResponseResolver.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ServletResponseResolver.java deleted file mode 100755 index ace68b33..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/ServletResponseResolver.java +++ /dev/null @@ -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 Harald Kuhr - * @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(); - } - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/WritableCachedResponse.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/WritableCachedResponse.java deleted file mode 100755 index 721d9174..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/WritableCachedResponse.java +++ /dev/null @@ -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 Harald Kuhr - * @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(); -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/WritableCachedResponseImpl.java b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/WritableCachedResponseImpl.java deleted file mode 100755 index 2e0b74bb..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/WritableCachedResponseImpl.java +++ /dev/null @@ -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 Harald Kuhr - * @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> 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 values = pAdd ? cachedResponse.headers.get(pName) : null; - - if (values == null) { - values = new ArrayList(); - - 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(); - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/todo.txt b/servlet/src/main/java/com/twelvemonkeys/servlet/cache/todo.txt deleted file mode 100755 index 7e3fb530..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/cache/todo.txt +++ /dev/null @@ -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 \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/FileSizeExceededException.java b/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/FileSizeExceededException.java deleted file mode 100755 index 79677de7..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/FileSizeExceededException.java +++ /dev/null @@ -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 Harald Kuhr - * @version $Id: FileSizeExceededException.java#1 $ - */ -@Deprecated -public class FileSizeExceededException extends FileUploadException { - public FileSizeExceededException(Throwable pCause) { - super(pCause.getMessage(), pCause); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/FileUploadFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/FileUploadFilter.java deleted file mode 100755 index efc29919..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/FileUploadFilter.java +++ /dev/null @@ -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 - * Form-based File Upload in HTML (RFC1867). - * - * @see HttpFileUploadRequest - * - * @author Harald Kuhr - * @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. - * - * - * @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/"); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/HttpFileUploadRequest.java b/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/HttpFileUploadRequest.java deleted file mode 100755 index a893845e..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/HttpFileUploadRequest.java +++ /dev/null @@ -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 - * Form-based File Upload in HTML (RFC1867). - * - * @author Harald Kuhr - * @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); -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/HttpFileUploadRequestWrapper.java b/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/HttpFileUploadRequestWrapper.java deleted file mode 100755 index ac22ab7a..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/HttpFileUploadRequestWrapper.java +++ /dev/null @@ -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 - * Jakarta Commons FileUpload. - * - * @author Harald Kuhr - * @version $Id: HttpFileUploadRequestWrapper.java#1 $ - */ -@Deprecated -class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements HttpFileUploadRequest { - - private final Map parameters = new HashMap(); - private final Map files = new HashMap(); - - 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 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(); - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/UploadedFile.java b/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/UploadedFile.java deleted file mode 100755 index 4b794916..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/UploadedFile.java +++ /dev/null @@ -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 Harald Kuhr - * @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()? -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/UploadedFileImpl.java b/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/UploadedFileImpl.java deleted file mode 100755 index a9bd2cab..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/fileupload/UploadedFileImpl.java +++ /dev/null @@ -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 - * Jakarta Commons FileUpload. - * - * @author Harald Kuhr - * @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); - } - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/gzip/GZIPFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/gzip/GZIPFilter.java deleted file mode 100755 index 5d135f19..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/gzip/GZIPFilter.java +++ /dev/null @@ -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. - *

- * 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. - *

- *

- * 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. - *

- *

- * Configuration - *
- * 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. - * Servlet 2.4 version, filter section: - *

- *
- *
- * <!-- GZIP Filter Configuration -->
- * <filter>
- *      <filter-name>gzip</filter-name>
- *      <filter-class>com.twelvemonkeys.servlet.GZIPFilter</filter-class>
- * </filter>
- * 
- * Filter-mapping section: - *
- *
- * <!-- 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>
- * 
- *

- * Based on ideas and code found in the ONJava article - * Two - * Servlet Filters Every Web Application Should Have - * by Jayson Falkner. - *

- * - * @author Jayson Falkner - * @author Harald Kuhr - * @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); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/gzip/GZIPResponseWrapper.java b/servlet/src/main/java/com/twelvemonkeys/servlet/gzip/GZIPResponseWrapper.java deleted file mode 100755 index 24f320a5..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/gzip/GZIPResponseWrapper.java +++ /dev/null @@ -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. - *

- * Based on ideas and code found in the ONJava article - * Two Servlet Filters Every Web Application Should Have - * by Jayson Falkner. - *

- * - * @author Jayson Falkner - * @author Harald Kuhr - * @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; - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/AWTImageFilterAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/AWTImageFilterAdapter.java deleted file mode 100755 index 2fff38b4..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/AWTImageFilterAdapter.java +++ /dev/null @@ -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 Harald Kuhr - * @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... - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/BufferedImageOpAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/BufferedImageOpAdapter.java deleted file mode 100755 index 42fe7a93..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/BufferedImageOpAdapter.java +++ /dev/null @@ -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 Harald Kuhr - * @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); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ColorServlet.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/ColorServlet.java deleted file mode 100755 index ddf8f793..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ColorServlet.java +++ /dev/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). - *

- * The class does only byte manipulation, there is no server-side image - * processing involving AWT ({@code Toolkit} class) of any kind. - *

- * - * @author Harald Kuhr - * @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; - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ComposeFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/ComposeFilter.java deleted file mode 100755 index df6fe3c5..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ComposeFilter.java +++ /dev/null @@ -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 Harald Kuhr - * @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; - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ContentNegotiationFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/ContentNegotiationFilter.java deleted file mode 100755 index b5d660d6..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ContentNegotiationFilter.java +++ /dev/null @@ -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 Harald Kuhr - * @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 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: - // = - // .accept= - - 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 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 getFormatQualityMapping() { - synchronized(lock) { - if (formatQuality == null) { - formatQuality = new HashMap(); - - // 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) 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 pFormatQuality) { - String acceptable = null; - float acceptQuality = 0.0f; - for (Map.Entry 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 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 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 - * @param pFormat the format - * @param pFactor the quality factor - */ - private static void adjustQuality(Map 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; - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/CropFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/CropFilter.java deleted file mode 100755 index 5eafc8fc..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/CropFilter.java +++ /dev/null @@ -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. - * - *
- * - * Parameters:
- *
- *
{@code cropX}
- *
integer, the new left edge of the image. - *
{@code cropY}
- *
integer, the new top of the image. - *
{@code cropWidth}
- *
integer, the new width of the image. - *
{@code cropHeight}
- *
integer, the new height of the image. - *
{@code cropUniform}
- *
boolean, wether or not uniform scalnig should be used. Default is - * {@code true}. - *
{@code cropUnits}
- *
string, one of {@code PIXELS}, {@code PERCENT}. - * {@code PIXELS} is default. - * - * - * - *
{@code image}
- *
string, the URL of the image to scale. - * - *
{@code scaleX}
- *
integer, the new width of the image. - * - *
{@code scaleY}
- *
integer, the new height of the image. - * - *
{@code scaleUniform}
- *
boolean, wether or not uniform scalnig should be used. Default is - * {@code true}. - * - *
{@code scaleUnits}
- *
string, one of {@code PIXELS}, {@code PERCENT}. - * {@code PIXELS} is default. - * - *
{@code scaleQuality}
- *
string, one of {@code SCALE_SMOOTH}, {@code SCALE_FAST}, - * {@code SCALE_REPLICATE}, {@code SCALE_AREA_AVERAGING}. - * {@code SCALE_DEFAULT} is default. - * - *
- *

- * Examples: - *
- * <IMG src="/crop/test.jpg?image=http://www.iconmedialab.com/images/random/home_image_12.jpg&cropWidth=500&cropUniform=true"> - *
- * <IMG src="/crop/test.png?cache=false&image=http://www.iconmedialab.com/images/random/home_image_12.jpg&cropWidth=50&cropUnits=PERCENT"> - *

- * - * @author Harald Kuhr - * @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); - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageFilter.java deleted file mode 100755 index 9df33056..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageFilter.java +++ /dev/null @@ -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 Harald Kuhr - * @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. - *

- * This default implementation uses {@link #triggerParams} to test if: - *

- *
- *
{@code mTriggerParams == null}
- *
{@code return true}
- *
{@code mTriggerParams != null}, loop through parameters, and test - * if {@code pRequest} contains the parameter. If match
- *
{@code return true}
- *
Otherwise
- *
{@code return false}
- *
- * - * @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 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; -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletException.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletException.java deleted file mode 100755 index e952449b..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletException.java +++ /dev/null @@ -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 Harald Kuhr - * @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); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponse.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponse.java deleted file mode 100755 index 2ef7e17f..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponse.java +++ /dev/null @@ -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. - *

- * 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. - *

- * - * @author Harald Kuhr - * @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. - *

- * Defaults to {@code null} (original image size). - *

- */ - String ATTRIB_SIZE = "com.twelvemonkeys.servlet.image.ImageServletResponse.SIZE"; - - /** - * Request attribute of type {@link Boolean} controlling image sizing. - *

- * Defaults to {@code Boolean.TRUE}. - *

- */ - String ATTRIB_SIZE_UNIFORM = "com.twelvemonkeys.servlet.image.ImageServletResponse.SIZE_UNIFORM"; - - /** - * Request attribute of type {@link Boolean} controlling image sizing. - *

- * Defaults to {@code Boolean.FALSE}. - *

- */ - 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). - *

- * Defaults to {@code null} (the entire image). - *

- */ - String ATTRIB_AOI = "com.twelvemonkeys.servlet.image.ImageServletResponse.AOI"; - - /** - * Request attribute of type {@link Boolean} controlling image AOI. - *

- * Defaults to {@code Boolean.FALSE}. - *

- */ - String ATTRIB_AOI_UNIFORM = "com.twelvemonkeys.servlet.image.ImageServletResponse.AOI_UNIFORM"; - - /** - * Request attribute of type {@link Boolean} controlling image AOI. - *

- * Defaults to {@code Boolean.FALSE}. - *

- */ - 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. - *

- * Defaults to {@code null} (keeps the transparent areas transparent). - *

- */ - 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. - *

- * Defaults to {@code 0.8f} for JPEG. - *

- */ - 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>}. - *

- * Defaults to {@code 2.0}. - *

- */ - 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}. - *

- * 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. - *

- *

- * Defaults to {@code SCALE_DEFAULT}. - *

- */ - 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". - *

- * 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. - *

- *

- * If not set, the default format is that of the original image. - *

- * - * @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); -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java deleted file mode 100755 index 813058ae..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ImageServletResponseImpl.java +++ /dev/null @@ -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. - *

- * @author Harald Kuhr - * @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); - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/NullImageFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/NullImageFilter.java deleted file mode 100755 index 6a2cc0ef..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/NullImageFilter.java +++ /dev/null @@ -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 Harald Kuhr - * @version $Id: NullImageFilter.java $ - * - */ -@Deprecated -public final class NullImageFilter extends ImageFilter { - protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) { - return pImage; - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/RotateFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/RotateFilter.java deleted file mode 100755 index 51974464..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/RotateFilter.java +++ /dev/null @@ -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. - * - *


- * - * Parameters:
- *
- *
{@code cropX}
- *
integer, the new left edge of the image. - *
{@code cropY}
- *
integer, the new top of the image. - *
{@code cropWidth}
- *
integer, the new width of the image. - *
{@code cropHeight}
- *
integer, the new height of the image. - * - *
- * - *

- * Examples: - *
- * JPEG: - * <IMG src="/scale/test.jpg?image=http://www.iconmedialab.com/images/random/home_image_12.jpg&width=500&uniform=true"> - *
- * PNG: - * <IMG src="/scale/test.png?cache=false&image=http://www.iconmedialab.com/images/random/home_image_12.jpg&width=50&units=PERCENT"> - *

- * - * @author Harald Kuhr - * @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(); - } - } -} - diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ScaleFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/ScaleFilter.java deleted file mode 100755 index 6434d7a0..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/ScaleFilter.java +++ /dev/null @@ -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. - * - *
- * - *

- * Parameters:
- *

- *
- *
{@code scaleX}
- *
integer, the new width of the image. - *
{@code scaleY}
- *
integer, the new height of the image. - *
{@code scaleUniform}
- *
boolean, wether or not uniform scalnig should be used. Default is - * {@code true}. - *
{@code scaleUnits}
- *
string, one of {@code PIXELS}, {@code PERCENT}. - * {@code PIXELS} is default. - *
{@code scaleQuality}
- *
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). - *
- *

- * Examples: - *

- *
- * <IMG src="/scale/test.jpg?scaleX=500&scaleUniform=false">
- * <IMG src="/scale/test.png?scaleY=50&scaleUnits=PERCENT">
- * 
- * - * @author Harald Kuhr - * @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. - */ - 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); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/SourceRenderFilter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/SourceRenderFilter.java deleted file mode 100755 index 727458ba..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/SourceRenderFilter.java +++ /dev/null @@ -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 Harald Kuhr - * @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; - } -} \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterest.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterest.java deleted file mode 100644 index f46d37c7..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterest.java +++ /dev/null @@ -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 Erlend Hamnaberg - * @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); -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterestFactory.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterestFactory.java deleted file mode 100644 index fc2c500a..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterestFactory.java +++ /dev/null @@ -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 Erlend Hamnaberg - * @version $Revision: $ - */ -@Deprecated -public class AreaOfInterestFactory { - private final static AtomicReference DEFAULT = - new AtomicReference(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); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterestWrapper.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterestWrapper.java deleted file mode 100644 index 9f7b0672..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterestWrapper.java +++ /dev/null @@ -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 Erlend Hamnaberg - * @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); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/DefaultAreaOfInterest.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/DefaultAreaOfInterest.java deleted file mode 100644 index 5cd86a00..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/DefaultAreaOfInterest.java +++ /dev/null @@ -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 Harald Kuhr - * @author Erlend Hamnaberg - * @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); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/PercentAreaOfInterest.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/PercentAreaOfInterest.java deleted file mode 100644 index 1605d2df..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/PercentAreaOfInterest.java +++ /dev/null @@ -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 Erlend Hamnaberg - * @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); - } - -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/UniformAreaOfInterest.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/UniformAreaOfInterest.java deleted file mode 100644 index aa04e779..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/aoi/UniformAreaOfInterest.java +++ /dev/null @@ -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 Erlend Hamnaberg - * @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); - } -} diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/image/package_info.java b/servlet/src/main/java/com/twelvemonkeys/servlet/image/package_info.java index 4ab97f32..d6ec9af3 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/image/package_info.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/image/package_info.java @@ -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. - *

- * 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 1.4 or later, and with the option: - *

- *
{@code -Djawa.awt.headless=true}
- *
- * See the document - * AWT Enhancements and bugtraq report - * 4281163 for more information on this issue. - *

- * If you cannot use JRE 1.4 or later, or do not want to use the X - * libraries, one possibility is to use the - * PJA package (com.eteks.pja), - * and start the JVM with the following options: - *

- *
{@code -Xbootclasspath/a:<path to pja.jar>}
- *
{@code -Dawt.toolkit=com.eteks.awt.PJAToolkit}
- *
{@code -Djava.awt.graphicsenv=com.eteks.java2d.PJAGraphicsEnvironment}
- *
{@code -Djava.awt.fonts=<path where True Type fonts files will be loaded from>}
- *
- *

- * 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; \ No newline at end of file diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/package_info.java b/servlet/src/main/java/com/twelvemonkeys/servlet/package_info.java deleted file mode 100755 index 84545a85..00000000 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/package_info.java +++ /dev/null @@ -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; diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/FilterAbstractTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/FilterAbstractTest.java deleted file mode 100755 index f5dd73b6..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/FilterAbstractTest.java +++ /dev/null @@ -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 - *

- * - * @author Harald Kuhr - * @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 params; - - MockFilterConfig(Map 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 attributes; - private final Map 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 attributes; - - public MockServletRequest() { - attributes = new HashMap(); - } - - 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 - } - } -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/GenericFilterTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/GenericFilterTest.java deleted file mode 100755 index 1340a3d9..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/GenericFilterTest.java +++ /dev/null @@ -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 - *

- * - * @author Harald Kuhr - * @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 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); - } - } - } -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterContextTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterContextTest.java deleted file mode 100755 index 6f88a2b4..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterContextTest.java +++ /dev/null @@ -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 - *

- * - * @author Harald Kuhr - * @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 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 createAttributes(boolean initialValues) { - Map 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 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); - } - } -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterRequestTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterRequestTest.java deleted file mode 100755 index 765564a7..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterRequestTest.java +++ /dev/null @@ -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 - *

- * - * @author Harald Kuhr - * @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 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 createAttributes(boolean initialValues) { - Map 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 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); - } - } -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigExceptionTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigExceptionTest.java deleted file mode 100755 index f49efb72..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigExceptionTest.java +++ /dev/null @@ -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 Harald Kuhr - * @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())); - } - } -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigMapAdapterTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigMapAdapterTest.java deleted file mode 100755 index 4f972f81..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigMapAdapterTest.java +++ /dev/null @@ -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 - *

- * - * @author Harald Kuhr - * @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); - } - } -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfiguratorTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfiguratorTest.java deleted file mode 100644 index 2b9820ec..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfiguratorTest.java +++ /dev/null @@ -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 Harald Kuhr - * @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 = "") - 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; - } - } -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTest.java deleted file mode 100755 index c930aac3..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTest.java +++ /dev/null @@ -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 - *

- * - * @author Harald Kuhr - * @version $Id: ServletHeadersMapAdapterTest.java#1 $ - */ -public class ServletHeadersMapAdapterTest extends MapAbstractTest { - private static final List HEADER_VALUE_ETAG = Collections.singletonList("\"1234567890abcdef\""); - private static final List HEADER_VALUE_DATE = Collections.singletonList(new Date().toString()); - private static final List 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 ReturnNewEnumeration returnEnumeration(final Collection collection) { - return new ReturnNewEnumeration<>(collection); - } - - private static class ReturnNewEnumeration implements Answer> { - private final Collection collection; - - private ReturnNewEnumeration(final Collection collection) { - this.collection = collection; - } - - public Enumeration answer(InvocationOnMock invocation) throws Throwable { - return Collections.enumeration(collection); - } - } -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTest.java deleted file mode 100755 index 5ea4c4f5..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTest.java +++ /dev/null @@ -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 - *

- * - * @author Harald Kuhr - * @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 PARAM_VALUE_ETAG = Collections.singletonList("\"1234567890abcdef\""); - private static final List PARAM_VALUE_DATE = Collections.singletonList(new Date().toString()); - private static final List 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 ReturnNewEnumeration returnEnumeration(final Collection collection) { - return new ReturnNewEnumeration<>(collection); - } - - private static class ReturnNewEnumeration implements Answer> { - private final Collection collection; - - private ReturnNewEnumeration(final Collection collection) { - this.collection = collection; - } - - public Enumeration answer(InvocationOnMock invocation) throws Throwable { - return Collections.enumeration(collection); - } - } -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletResponseAbsrtactTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletResponseAbsrtactTest.java deleted file mode 100755 index 819871b7..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletResponseAbsrtactTest.java +++ /dev/null @@ -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 - *

- * - * @author Harald Kuhr - * @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 -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/TrimWhiteSpaceFilterTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/TrimWhiteSpaceFilterTest.java deleted file mode 100755 index 498496ac..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/TrimWhiteSpaceFilterTest.java +++ /dev/null @@ -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 - *

- * - * @author Harald Kuhr - * @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\n\t \t".getBytes(); - String trimmed = "\n "; // 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()); - } - } -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/cache/HTTPCacheTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/cache/HTTPCacheTest.java deleted file mode 100755 index 6a84e130..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/cache/HTTPCacheTest.java +++ /dev/null @@ -1,1176 +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 com.twelvemonkeys.net.HTTPUtil; - -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.rules.TestName; -import org.mockito.InOrder; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletResponse; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.*; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -/** - * HTTPCacheTest - * - * @author Harald Kuhr - * @author last modified by $Author: haku $ - * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/cache/HTTPCacheTestCase.java#2 $ - */ -public class HTTPCacheTest { - @Rule - public final TestName name = new TestName(); - - @Rule - public final TemporaryFolder temporaryFolder = new TemporaryFolder(); - - private File createTempRoot() throws IOException { - return temporaryFolder.newFolder("cache-test"); - } - - private CacheRequest configureRequest(CacheRequest request, String pRequestURI) { - return configureRequest(request, "GET", pRequestURI, null, null); - } - - private CacheRequest configureRequest(CacheRequest request, String pMethod, String pRequestURI, Map> pParameters, final Map> pHeaders) { - reset(request); - - when(request.getRequestURI()).thenReturn(URI.create(pRequestURI)); - when(request.getParameters()).thenReturn(pParameters == null ? Collections.>emptyMap() : pParameters); - when(request.getHeaders()).thenReturn(pHeaders == null ? Collections.>emptyMap() : pHeaders); - when(request.getMethod()).thenReturn(pMethod); - - return request; - } - - @SuppressWarnings("deprecation") - @Test - public void testCreateNegativeNoName() { - try { - new HTTPCache(null, mock(ServletContext.class), 500, 0, 10, true); - fail("Expected creation failure, no name"); - } - catch (IllegalArgumentException expected) { - String message = expected.getMessage().toLowerCase(); - assertTrue(message.contains("name")); - assertTrue(message.contains("null")); - } - - try { - new HTTPCache("", mock(ServletContext.class), 500, 0, 10, true); - fail("Expected creation failure, empty name"); - } - catch (IllegalArgumentException expected) { - String message = expected.getMessage().toLowerCase(); - assertTrue(message.contains("name")); - assertTrue(message.contains("empty")); - } - } - - @SuppressWarnings("deprecation") - @Test - public void testCreateNegativeNoContext() { - try { - new HTTPCache("Dummy", null, 500, 0, 10, true); - fail("Expected creation failure, no context"); - } - catch (IllegalArgumentException expected) { - String message = expected.getMessage().toLowerCase(); - assertTrue(message.contains("context")); - assertTrue(message.contains("null")); - } - - } - - @Test - public void testCreateNegativeNoTempFolder() { - try { - new HTTPCache(null, 500, 0, 10, true); - fail("Expected creation failure, no temp folder"); - } - catch (IllegalArgumentException expected) { - String message = expected.getMessage().toLowerCase(); - assertTrue(message.contains("temp")); - assertTrue(message.contains("folder")); - assertTrue(message.contains("null")); - } - } - - @Test - public void testCreateNegativeValues() throws IOException { - File tempRoot = createTempRoot(); - - try { - new HTTPCache(tempRoot, -1, 0, 10, true); - fail("Expected creation failure"); - } - catch (IllegalArgumentException expected) { - String message = expected.getMessage().toLowerCase(); - assertTrue(message.contains("negative")); - assertTrue(message.contains("expiry time")); - } - - try { - new HTTPCache(tempRoot, 1000, -1, 10, false); - fail("Expected creation failure"); - } - catch (IllegalArgumentException expected) { - String message = expected.getMessage().toLowerCase(); - assertTrue(message.contains("negative")); - assertTrue(message.contains("cache size")); - } - - try { - new HTTPCache(tempRoot, 1000, 128, -1, true); - fail("Expected creation failure"); - } - catch (IllegalArgumentException expected) { - String message = expected.getMessage().toLowerCase(); - assertTrue(message.contains("negative")); - assertTrue(message.contains("number")); - } - } - - @Test - public void testCreate() throws IOException { - new HTTPCache(createTempRoot(), 500, 0, 10, true); - } - - @SuppressWarnings("deprecation") - @Test - public void testCreateServletContext() throws IOException { - ServletContext mockContext = mock(ServletContext.class); - // Currently context is used for tempdir and logging - when(mockContext.getAttribute(eq("javax.servlet.context.tempdir"))).thenReturn(createTempRoot()); - - new HTTPCache("cache", mockContext, 500, 0, 10, true); - } - - @Test - public void testCacheableRequest() throws IOException, CacheException { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), createRequestURI()); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - final byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new ResolveAnswer(value)).when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - private String createRequestURI() { - return "http://www.foo.com/" + name.getMethodName() + ".bar"; - } - - @Test - public void testCacheableRequestWithParameters() throws IOException, CacheException { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - Map> parameters = new HashMap<>(); - parameters.put("foo", Collections.singletonList("bar")); - parameters.put("params", Arrays.asList("une", "due", "tres")); - CacheRequest request = configureRequest(mock(CacheRequest.class), "GET", createRequestURI(), parameters, null); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - final byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - ResponseResolver resolver = mock(ResponseResolver.class, "MY-RESOLVER-1"); - doAnswer(new ResolveAnswer(value)).when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - @Test - public void testCacheablePersistentRepeatedRequest() throws IOException, CacheException { - File tempRoot = createTempRoot(); - HTTPCache cache = new HTTPCache(tempRoot, 60000, 1024 * 1024, 10, true); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), createRequestURI()); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - final byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - ResponseResolver resolver = mock(ResponseResolver.class, "MY-RESOLVER-2"); - doAnswer(new ResolveAnswer(value)).when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).getOutputStream(); - - // Reset - result.reset(); - reset(response); - when(response.getOutputStream()).thenReturn(result); - - // Test request again, make sure resolve is executed exactly once - HTTPCache cache2 = new HTTPCache(tempRoot, 60000, 1024 * 1024, 10, true); - cache2.doCached(request, response, resolver); - - // Test that second response is equal to first - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - @Test - public void testCacheableRepeatedRequest() throws IOException, CacheException { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), createRequestURI()); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - final byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - ResponseResolver resolver = mock(ResponseResolver.class, "MY-RESOLVER-3"); - doAnswer(new ResolveAnswer(value)).when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that reponse is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).getOutputStream(); - - // Reset - result.reset(); - reset(response); - - // Reconfigure - when(response.getOutputStream()).thenReturn(result); - - // Test request again, make sure resolve is executed exactly once - cache.doCached(request, response, resolver); - - // Test that second response is equal to first - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - @Test - public void testNonCacheableRequestHeader() throws Exception { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), "GET", createRequestURI(), null, Collections.singletonMap("Cache-Control", Collections.singletonList("no-store"))); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - final byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new ResolveAnswer(value)).when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // TODO: How do we know that the response was NOT cached? - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - @Test - public void testNonCacheableRequestHeaderRepeated() throws Exception { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - String requestURI = createRequestURI(); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), requestURI); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - - final byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new ResolveAnswer(value)).when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Reset - result.reset(); - reset(response, resolver); - - // Reconfigure - request = configureRequest(request, "GET", requestURI, null, Collections.singletonMap("Cache-Control", Collections.singletonList("no-cache"))); - when(response.getOutputStream()).thenReturn(result); - doAnswer(new ResolveAnswer(value)).when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - value[3] = 'B'; // Make sure we have a different value second time - - // This request should not be cached - cache.doCached(request, response, resolver); - - // Verify that second response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - @Test - public void testNonCacheableResponseHeader() throws Exception { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), createRequestURI()); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - final byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_OK, value, Collections.singletonMap("Cache-Control", Collections.singletonList("no-cache")))) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).setHeader(eq("Cache-Control"), eq("no-cache")); - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - @Test - public void testNonCacheableResponseHeaderRepeated() throws Exception { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), createRequestURI()); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - final byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_OK, value, Collections.singletonMap("Cache-Control", Collections.singletonList("no-store")))) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).setHeader(eq("Cache-Control"), eq("no-store")); - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Reset - result.reset(); - reset(response, resolver); - - // Reconfigure - when(response.getOutputStream()).thenReturn(result); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_OK, value, Collections.singletonMap("Cache-Control", Collections.singletonList("no-store")))) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - value[3] = 'B'; - - // Repeat invocation - cache.doCached(request, response, resolver); - - // Verify that reponse is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).setHeader(eq("Cache-Control"), eq("no-store")); - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - // Test non-cacheable response - @Test - public void testNonCacheableResponse() throws Exception { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), createRequestURI()); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - final byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, value, null)) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - // Test non-cacheable response - @Test - public void testNonCacheableResponseRepeated() throws Exception { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), createRequestURI()); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - final byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, value, null)) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that reponse is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Reset - result.reset(); - reset(response, resolver); - - // Reconfigure - when(response.getOutputStream()).thenReturn(result); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, value, null)) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - value[3] = 'B'; - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - // Verify new resolve - verify(response).setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - // Test that request headers are forwarded to resolver... - @Test - public void testRequestHeadersForwarded() throws Exception { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - final Map> headers = new LinkedHashMap<>(); - headers.put("Cache-Control", Collections.singletonList("no-cache")); - headers.put("X-Custom", Arrays.asList("FOO", "BAR")); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), "HEAD", createRequestURI(), null, headers); - CacheResponse response = mock(CacheResponse.class); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new Answer() { - public Void answer(InvocationOnMock invocation) { - CacheRequest req = (CacheRequest) invocation.getArguments()[0]; - - Map> reqHeaders = req.getHeaders(); - assertEquals(headers, reqHeaders); - - // Make sure that we preserve insertion order - Set>> expected = headers.entrySet(); - Iterator>> actual = reqHeaders.entrySet().iterator(); - - for (Map.Entry> entry : expected) { - assertEquals(entry, actual.next()); - } - - return null; - } - }).when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that custom resolve was invoked - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - // Test that response headers are preserved - @Test - public void testCacheablePreserveResponseHeaders() throws IOException, CacheException { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), createRequestURI()); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - final byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new Answer() { - public Void answer(InvocationOnMock invocation) throws Throwable { - CacheResponse res = (CacheResponse) invocation.getArguments()[1]; - - res.setStatus(HttpServletResponse.SC_OK); - res.setHeader("Date", HTTPUtil.formatHTTPDate(System.currentTimeMillis())); - res.setHeader("Cache-Control", "public"); - res.addHeader("X-Custom", "FOO"); - res.addHeader("X-Custom", "BAR"); - res.getOutputStream().write(value); - - return null; - } - }).when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response).setHeader(eq("Cache-Control"), eq("public")); - - InOrder ordered = inOrder(response); - // TODO: This test is to fragile, as it relies on internal knowledge of the code tested - // (it doesn't really matter if first invocation is setHeader or addHeader) - // See if we can create a custom VerificationMode for "either/or" - ordered.verify(response).setHeader(eq("X-Custom"), eq("FOO")); - ordered.verify(response).addHeader(eq("X-Custom"), eq("BAR")); - - verify(response, atLeastOnce()).getOutputStream(); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - // Test Vary - @Test - public void testVaryMissingRequestHeader() throws Exception { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), createRequestURI()); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - HashMap> headers = new HashMap<>(); - headers.put(HTTPCache.HEADER_CONTENT_TYPE, Collections.singletonList("x-foo/bar")); - headers.put("Vary", Collections.singletonList("X-Foo")); - headers.put("X-Foo", Collections.singletonList("foobar")); - headers.put("X-Other", Collections.singletonList("don't care")); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_OK, value, headers)) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).getOutputStream(); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).setHeader("Vary", "X-Foo"); - - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Reset - result.reset(); - reset(response, resolver); - - // Reconfigure - when(response.getOutputStream()).thenReturn(result); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_OK, value, headers)) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Repeat invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).getOutputStream(); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).setHeader("Vary", "X-Foo"); - - verifyNoMoreInteractions(resolver); - } - - @Test - public void testVaryMissingRequestHeaderRepeated() throws Exception { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - String requestURI = createRequestURI(); - CacheRequest request = configureRequest(mock(CacheRequest.class), requestURI); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - HashMap> headers = new HashMap<>(); - headers.put(HTTPCache.HEADER_CONTENT_TYPE, Collections.singletonList("x-foo/bar")); - headers.put("Vary", Collections.singletonList("X-Foo")); - headers.put("X-Other", Collections.singletonList("don't care")); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_OK, value, headers)) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).getOutputStream(); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).setHeader("Vary", "X-Foo"); - - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Reset - result.reset(); - request = configureRequest(request, "GET", requestURI, null, Collections.singletonMap("X-Foo", Collections.singletonList("foobar"))); - reset(response, resolver); - - // Reconfigure - when(response.getOutputStream()).thenReturn(result); - - doAnswer(new ResolveAnswer(HttpServletResponse.SC_OK, value, headers)) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - value[3] = 'B'; - - // Repeat invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).getOutputStream(); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).setHeader("Vary", "X-Foo"); - - // Different X-Foo header, must re-validate - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - @Test - public void testVarySameResourceIsCached() throws Exception { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), "GET", createRequestURI(), null, Collections.singletonMap("X-Foo", Collections.singletonList("foobar value"))); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - HashMap> headers = new HashMap<>(); - headers.put(HTTPCache.HEADER_CONTENT_TYPE, Collections.singletonList("x-foo/bar")); - headers.put("Vary", Collections.singletonList("X-Foo")); - headers.put("X-Other", Collections.singletonList("don't care")); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_OK, value, headers)) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that reponse is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).getOutputStream(); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).setHeader("Vary", "X-Foo"); - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Reset - reset(response); - result.reset(); - - // Reconfigure - when(response.getOutputStream()).thenReturn(result); - - // Repeat invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).getOutputStream(); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).setHeader("Vary", "X-Foo"); - - verifyNoMoreInteractions(resolver); - } - - @Test - public void testVaryDifferentResources() throws Exception { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - String requestURI = createRequestURI(); - CacheRequest request = configureRequest(mock(CacheRequest.class), requestURI); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - HashMap> headers = new HashMap<>(); - headers.put(HTTPCache.HEADER_CONTENT_TYPE, Collections.singletonList("x-foo/bar")); - headers.put("Vary", Collections.singletonList("X-Foo")); - headers.put("X-Other", Collections.singletonList("don't care")); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_OK, value, headers)) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).getOutputStream(); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).setHeader("Vary", "X-Foo"); - - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Reset - result.reset(); - request = configureRequest(request, "GET", requestURI, null, Collections.singletonMap("X-Foo", Collections.singletonList("bar"))); - reset(response, resolver); - - // Reconfigure - when(response.getOutputStream()).thenReturn(result); - headers.put("Cache-Control", Collections.singletonList("no-store")); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_OK, value, headers)) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - value[0] = 'b'; - value[1] = 'a'; - value[2] = 'r'; - - // Repeat invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).getOutputStream(); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).setHeader("Vary", "X-Foo"); - verify(response, atLeastOnce()).setHeader("Cache-Control", "no-store"); - - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - @Test - public void testVaryStarNonCached() throws Exception { - HTTPCache cache = new HTTPCache(createTempRoot(), 60000, 1024 * 1024, 10, true); - - // Custom setup - CacheRequest request = configureRequest(mock(CacheRequest.class), createRequestURI()); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - CacheResponse response = mock(CacheResponse.class); - when(response.getOutputStream()).thenReturn(result); - - byte[] value = "foobar".getBytes(StandardCharsets.UTF_8); - - HashMap> headers = new HashMap<>(); - headers.put(HTTPCache.HEADER_CONTENT_TYPE, Collections.singletonList("x-foo/bar")); - headers.put("Vary", Collections.singletonList("*")); - - ResponseResolver resolver = mock(ResponseResolver.class); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_OK, value, headers)) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Do the invocation - cache.doCached(request, response, resolver); - - // Verify that reponse is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).getOutputStream(); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).setHeader("Vary", "*"); - - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - // Reset - result.reset(); - reset(response, resolver); - - // Reconfigure - when(response.getOutputStream()).thenReturn(result); - headers.put("Cache-Control", Collections.singletonList("no-store")); - doAnswer(new ResolveAnswer(HttpServletResponse.SC_OK, value, headers)) - .when(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - - value[3] = 'B'; - - // Repeat invocation - cache.doCached(request, response, resolver); - - // Verify that response is ok - assertEquals(value.length, result.size()); - assertEquals(new String(value, StandardCharsets.UTF_8), new String(result.toByteArray(), StandardCharsets.UTF_8)); - assertArrayEquals(value, result.toByteArray()); - - verify(response).setStatus(HttpServletResponse.SC_OK); - verify(response, atLeastOnce()).getOutputStream(); - verify(response, atLeastOnce()).setHeader(eq("Date"), anyString()); - verify(response, atLeastOnce()).setHeader("Vary", "*"); - - verify(resolver).resolve(any(CacheRequest.class), any(CacheResponse.class)); - } - - @Ignore("TODO") - @Test - public void testVaryVariations() { - fail("TODO"); - } - - @Ignore("TODO") - @Test - public void testVariationsWithSameContentType() { - // I believe there is a bug if two variations has same content type... - fail("TODO"); - } - - @Ignore("TODO") - @Test - // Test failing request (IOException) - public void testIOException() { - fail("TODO"); - } - - @Ignore("TODO") - @Test - public void testCacheException() { - fail("TODO"); - } - - @Ignore("TODO") - @Test - public void testRuntimeException() { - fail("TODO"); - } - - @Ignore("TODO") - @Test - // Test failing (negative) HTTP response (401, 404, 410, 500, etc) - public void testNegativeCache() { - fail("TODO"); - } - - @Ignore("TODO") - @Test - public void testNegativeCacheExpires() { - fail("TODO"); - } - - @Ignore("TODO") - @Test - // Test If-None-Match/ETag support - public void testIfNoneMatch() { - fail("TODO"); - } - - @Ignore("TODO") - @Test - // Test If-Modified-Since support - public void testIfModifiedSince() { - fail("TODO"); - } - - @Ignore("TODO") - @Test - // Test that data really expires when TTL is over - public void testTimeToLive() { - fail("TODO"); - } - - @Ignore("TODO") - @Test - public void testMaxAgeRequest() { - fail("TODO"); - } - - @Ignore("TODO") - @Test - // Test that for requests with authorization, responses are not shared between different authorized users, unless response is marked as Cache-Control: public - public void testAuthorizedRequestPublic() { - fail("TODO"); - } - - @Ignore("TODO") - @Test - public void testAuthorizedRequestPrivate() { - fail("TODO"); - } - - @Ignore("TODO") - @Test - public void testPutPostDeleteInvalidatesCache() { - fail("TODO"); - } - - @Ignore("TODO") - @Test - // TODO: Move out to separate package/test, just keep it here for PoC - public void testClientRequest() { - fail("Not implemented"); - } - - @Ignore("TODO") - @Test - // TODO: Move out to separate package/test, just keep it here for PoC - public void testServletRequest() { - fail("Not implemented"); - } - - private static class ResolveAnswer implements Answer { - private final int status; - private final byte[] value; - private final Map> headers; - - public ResolveAnswer(byte[] value) { - this(HttpServletResponse.SC_OK, value, null); - } - - public ResolveAnswer(final int status, byte[] value, Map> headers) { - this.status = status; - this.value = value; - this.headers = headers != null ? headers : Collections.>emptyMap(); - } - - public Void answer(InvocationOnMock invocation) throws Throwable { - CacheResponse res = (CacheResponse) invocation.getArguments()[1]; - - res.setStatus(status); - res.setHeader("Date", HTTPUtil.formatHTTPDate(System.currentTimeMillis())); - - for (Map.Entry> header : headers.entrySet()) { - for (String value : header.getValue()) { - res.addHeader(header.getKey(), value); - } - } - - res.getOutputStream().write(value); - - return null; - } - } -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageFilterTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageFilterTest.java deleted file mode 100644 index 8868a964..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageFilterTest.java +++ /dev/null @@ -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 Harald Kuhr - * @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() { - 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() { - 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 imageRef = new AtomicReference(); - final AtomicReference responseRef = new AtomicReference(); - - 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() { - 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() { - 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() { - 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; - } - } -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTest.java deleted file mode 100755 index c50f9ae8..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTest.java +++ /dev/null @@ -1,1612 +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 com.twelvemonkeys.image.BufferedImageIcon; -import com.twelvemonkeys.image.ImageUtil; -import com.twelvemonkeys.io.FastByteArrayOutputStream; -import com.twelvemonkeys.io.FileUtil; -import com.twelvemonkeys.servlet.OutputStreamAdapter; -import org.junit.Before; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import javax.imageio.ImageIO; -import javax.servlet.ServletContext; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.swing.*; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.awt.image.IndexColorModel; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -/** - * ImageServletResponseImplTest - * - * @author Harald Kuhr - * @author last modified by $Author: haku $ - * @version $Id: twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/image/ImageServletResponseImplTest.java#6 $ - */ -public class ImageServletResponseImplTest { - private static final String CONTENT_TYPE_BMP = "image/bmp"; - private static final String CONTENT_TYPE_FOO = "foo/bar"; - private static final String CONTENT_TYPE_GIF = "image/gif"; - private static final String CONTENT_TYPE_JPEG = "image/jpeg"; - private static final String CONTENT_TYPE_PNG = "image/png"; - private static final String CONTENT_TYPE_TEXT = "text/plain"; - - private static final String IMAGE_NAME_PNG = "12monkeys-splash.png"; - private static final String IMAGE_NAME_GIF = "tux.gif"; - private static final String IMAGE_NAME_PNG_INDEXED = "star.png"; - - private static final Dimension IMAGE_DIMENSION_PNG = new Dimension(300, 410); - private static final Dimension IMAGE_DIMENSION_GIF = new Dimension(250, 250); - private static final Dimension IMAGE_DIMENSION_PNG_INDEXED = new Dimension(199, 192); - - private static final int STREAM_DEFAULT_SIZE = 2000; - - private HttpServletRequest request; - private ServletContext context; - - @Before - public void init() throws Exception { - request = mock(HttpServletRequest.class); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_PNG); - - context = mock(ServletContext.class); - when(context.getResource("/" + IMAGE_NAME_PNG)).thenReturn(getClass().getResource(IMAGE_NAME_PNG)); - when(context.getResource("/" + IMAGE_NAME_GIF)).thenReturn(getClass().getResource(IMAGE_NAME_GIF)); - when(context.getResource("/" + IMAGE_NAME_PNG_INDEXED)).thenReturn(getClass().getResource(IMAGE_NAME_PNG_INDEXED)); - when(context.getMimeType("file.bmp")).thenReturn(CONTENT_TYPE_BMP); - when(context.getMimeType("file.foo")).thenReturn(CONTENT_TYPE_FOO); - when(context.getMimeType("file.gif")).thenReturn(CONTENT_TYPE_GIF); - when(context.getMimeType("file.jpeg")).thenReturn(CONTENT_TYPE_JPEG); - when(context.getMimeType("file.png")).thenReturn(CONTENT_TYPE_PNG); - when(context.getMimeType("file.txt")).thenReturn(CONTENT_TYPE_TEXT); - - MockLogger mockLogger = new MockLogger(); - doAnswer(mockLogger).when(context).log(anyString()); - doAnswer(mockLogger).when(context).log(anyString(), any(Throwable.class)); - //noinspection deprecation - doAnswer(mockLogger).when(context).log(any(Exception.class), anyString()); - } - - private void fakeResponse(HttpServletRequest pRequest, ImageServletResponseImpl pImageResponse) throws IOException { - String uri = pRequest.getRequestURI(); - int index = uri.lastIndexOf('/'); - assertTrue(uri, index >= 0); - - String name = uri.substring(index + 1); - InputStream in = getClass().getResourceAsStream(name); - - if (in == null) { - pImageResponse.sendError(HttpServletResponse.SC_NOT_FOUND, uri + " not found"); - } - else { - String ext = name.substring(name.lastIndexOf(".")); - pImageResponse.setContentType(context.getMimeType("file" + ext)); - pImageResponse.setContentLength(234); - try { - ServletOutputStream out = pImageResponse.getOutputStream(); - try { - FileUtil.copy(in, out); - } - finally { - out.close(); - } - } - finally { - in.close(); - } - } - } - - @Test - public void testBasicResponse() throws IOException { - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Make sure image is correctly loaded - BufferedImage image = imageResponse.getImage(); - assertNotNull(image); - assertEquals(IMAGE_DIMENSION_PNG.width, image.getWidth()); - assertEquals(IMAGE_DIMENSION_PNG.height, image.getHeight()); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(image.getWidth(), outImage.getWidth()); - assertEquals(image.getHeight(), outImage.getHeight()); - - verify(response).setContentType(CONTENT_TYPE_PNG); - verify(response).getOutputStream(); - } - - // Test that wrapper works as a no-op, in case the image does not need to be decoded - // This is not a very common use case, as filters should avoid wrapping the response - // for performance reasons, but we still want that to work - - @Test - public void testNoOpResponse() throws IOException { - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // TODO: Is there a way we can avoid calling flush? - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is untouched - assertTrue("Data differs", Arrays.equals(FileUtil.read(getClass().getResourceAsStream(IMAGE_NAME_PNG)), out.toByteArray())); - - verify(response).setContentType(CONTENT_TYPE_PNG); - verify(response).getOutputStream(); - } - - // Transcode original PNG to JPEG with no other changes - @Test - public void testTranscodeResponsePNGToJPEG() throws IOException { - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Force transcode to JPEG - imageResponse.setOutputContentType("image/jpeg"); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Assert JPEG - ByteArrayInputStream input = out.createInputStream(); - assertEquals(0xFF, input.read()); - assertEquals(0xD8, input.read()); - assertEquals(0xFF, input.read()); - - // Test that image data is still readable - /* - File tempFile = File.createTempFile("imageservlet-test-", ".jpeg"); - FileOutputStream stream = new FileOutputStream(tempFile); - out.writeTo(stream); - stream.close(); - System.err.println("open " + tempFile); - */ - - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(IMAGE_DIMENSION_PNG.width, outImage.getWidth()); - assertEquals(IMAGE_DIMENSION_PNG.height, outImage.getHeight()); - - BufferedImage image = flatten(ImageIO.read(context.getResource("/" + IMAGE_NAME_PNG)), Color.BLACK); - - /* - tempFile = File.createTempFile("imageservlet-test-", ".png"); - stream = new FileOutputStream(tempFile); - ImageIO.write(image, "PNG", stream); - stream.close(); - System.err.println("open " + tempFile); - */ - - // JPEG compression trashes the image completely... - assertSimilarImage(image, outImage, 144f); - - verify(response).setContentType(CONTENT_TYPE_JPEG); - verify(response).getOutputStream(); - } - - // WORKAROUND: Bug in GIFImageWriteParam, compression type is not set by default - // (even if there's only one possible compression mode/type combo; MODE_EXPLICIT/"LZW") - @Test - public void testTranscodeResponsePNGToGIFWithQuality() throws IOException { - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - when(request.getAttribute(ImageServletResponse.ATTRIB_OUTPUT_QUALITY)).thenReturn(.5f); // Force quality setting in param - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Force transcode to GIF - imageResponse.setOutputContentType("image/gif"); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Assert GIF - ByteArrayInputStream stream = out.createInputStream(); - assertEquals('G', stream.read()); - assertEquals('I', stream.read()); - assertEquals('F', stream.read()); - assertEquals('8', stream.read()); - assertEquals('9', stream.read()); - assertEquals('a', stream.read()); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(IMAGE_DIMENSION_PNG.width, outImage.getWidth()); - assertEquals(IMAGE_DIMENSION_PNG.height, outImage.getHeight()); - - BufferedImage image = ImageIO.read(context.getResource("/" + IMAGE_NAME_PNG)); - - // Should keep transparency, but is now binary -// showIt(image, outImage, null); - assertSimilarImageTransparent(image, outImage, 50f); - - verify(response).setContentType(CONTENT_TYPE_GIF); - verify(response).getOutputStream(); - } - - // WORKAROUND: Bug in GIFImageWriter may throw NPE if transparent pixels - // See: http://bugs.sun.com/view_bug.do?bug_id=6287936 - @Test - public void testTranscodeResponsePNGToGIF() throws IOException { - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Force transcode to GIF - imageResponse.setOutputContentType("image/gif"); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(IMAGE_DIMENSION_PNG.width, outImage.getWidth()); - assertEquals(IMAGE_DIMENSION_PNG.height, outImage.getHeight()); - - BufferedImage image = ImageIO.read(context.getResource("/" + IMAGE_NAME_PNG)); - - // Should keep transparency, but is now binary -// showIt(image, outImage, null); - assertSimilarImageTransparent(image, outImage, 50f); - - verify(response).setContentType(CONTENT_TYPE_GIF); - verify(response).getOutputStream(); - } - - @Test - public void testTranscodeResponseIndexColorModelGIFToJPEG() throws IOException { - // Custom setup - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_GIF); - - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Force transcode to JPEG - imageResponse.setOutputContentType("image/jpeg"); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Assert JPEG - ByteArrayInputStream stream = out.createInputStream(); - assertEquals(0xFF, stream.read()); - assertEquals(0xD8, stream.read()); - assertEquals(0xFF, stream.read()); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(IMAGE_DIMENSION_GIF.width, outImage.getWidth()); - assertEquals(IMAGE_DIMENSION_GIF.height, outImage.getHeight()); - - BufferedImage image = flatten(ImageIO.read(context.getResource("/" + IMAGE_NAME_GIF)), Color.WHITE); - - assertSimilarImage(image, outImage, 96f); - } - - @Test - // TODO: Insert bug id/reference here for regression tracking - public void testIndexedColorModelResizePNG() throws IOException { - // Results differ with algorithm, so we test each algorithm by itself - int[] algorithms = new int[] {Image.SCALE_DEFAULT, Image.SCALE_FAST, Image.SCALE_SMOOTH, Image.SCALE_REPLICATE, Image.SCALE_AREA_AVERAGING, 77}; - - for (int algorithm : algorithms) { - Dimension size = new Dimension(100, 100); - - // Custom setup - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getAttribute(ImageServletResponse.ATTRIB_SIZE)).thenReturn(size); - when(request.getAttribute(ImageServletResponse.ATTRIB_SIZE_UNIFORM)).thenReturn(false); - when(request.getAttribute(ImageServletResponse.ATTRIB_IMAGE_RESAMPLE_ALGORITHM)).thenReturn(algorithm); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_PNG_INDEXED); - - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - imageResponse.getImage(); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Assert format is still PNG - ByteArrayInputStream inputStream = out.createInputStream(); - assertEquals(0x89, inputStream.read()); - assertEquals('P', inputStream.read()); - assertEquals('N', inputStream.read()); - assertEquals('G', inputStream.read()); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(size.width, outImage.getWidth()); - assertEquals(size.height, outImage.getHeight()); - - BufferedImage read = ImageIO.read(context.getResource("/" + IMAGE_NAME_PNG_INDEXED)); - BufferedImage image = ImageUtil.createResampled(read, size.width, size.height, imageResponse.getResampleAlgorithmFromRequest()); - -// showIt(image, outImage, null); - - assertSimilarImageTransparent(image, outImage, 10f); - } - } - - private static BufferedImage flatten(final BufferedImage pImage, final Color pBackgroundColor) { - BufferedImage image = ImageUtil.toBuffered(pImage, BufferedImage.TYPE_INT_ARGB); - - Graphics2D g = image.createGraphics(); - try { - g.setComposite(AlphaComposite.DstOver); - g.setColor(pBackgroundColor); - g.fillRect(0, 0, pImage.getWidth(), pImage.getHeight()); - } - finally { - g.dispose(); - } - - return image; - } - - /** - * Makes sure images are the same, taking JPEG artifacts into account. - * - * @param pExpected the expected image - * @param pActual the actual image - * @param pArtifactThreshold the maximum allowed difference between the expected and actual pixel value - */ - private void assertSimilarImage(final BufferedImage pExpected, final BufferedImage pActual, final float pArtifactThreshold) { - for (int y = 0; y < pExpected.getHeight(); y++) { - for (int x = 0; x < pExpected.getWidth(); x++) { - int expected = pExpected.getRGB(x, y); - int actual = pActual.getRGB(x, y); - - // Multiply in the alpha component - float alpha = ((expected >> 24) & 0xff) / 255f; - - assertEquals(alpha * ((expected >> 16) & 0xff), (actual >> 16) & 0xff, pArtifactThreshold); - assertEquals(alpha * ((expected >> 8) & 0xff), (actual >> 8) & 0xff, pArtifactThreshold); - assertEquals(alpha * ((expected) & 0xff), actual & 0xff, pArtifactThreshold); - } - } - } - - private void assertSimilarImageTransparent(final BufferedImage pExpected, final BufferedImage pActual, final float pArtifactThreshold) { - IndexColorModel icm = pActual.getColorModel() instanceof IndexColorModel ? (IndexColorModel) pActual.getColorModel() : null; - Object pixel = null; - - for (int y = 0; y < pExpected.getHeight(); y++) { - for (int x = 0; x < pExpected.getWidth(); x++) { - int expected = pExpected.getRGB(x, y); - int actual = pActual.getRGB(x, y); - - if (icm != null) { - // Look up, using ICM - - int alpha = (expected >> 24) & 0xff; - boolean transparent = alpha < 0x40; - - if (transparent) { - int expectedLookedUp = icm.getRGB(icm.getTransparentPixel()); - assertRGBEquals(x, y, expectedLookedUp & 0xff000000, actual & 0xff000000, 0); - } - else { - pixel = icm.getDataElements(expected, pixel); - int expectedLookedUp = icm.getRGB(pixel); - assertRGBEquals(x, y, expectedLookedUp & 0xffffff, actual & 0xffffff, pArtifactThreshold); - } - } - else { - // Multiply out alpha for each component if pre-multiplied -// int expectedR = (int) ((((expected >> 16) & 0xff) * alpha) / 255f); -// int expectedG = (int) ((((expected >> 8) & 0xff) * alpha) / 255f); -// int expectedB = (int) (((expected & 0xff) * alpha) / 255f); - - assertRGBEquals(x, y, expected, actual, pArtifactThreshold); - } - } - } - } - - private void assertRGBEquals(int x, int y, int expected, int actual, float pArtifactThreshold) { - int expectedA = (expected >> 24) & 0xff; - int expectedR = (expected >> 16) & 0xff; - int expectedG = (expected >> 8) & 0xff; - int expectedB = expected & 0xff; - - try { - assertEquals("Alpha", expectedA, (actual >> 24) & 0xff, pArtifactThreshold); - assertEquals("RGB", 0, (Math.abs(expectedR - ((actual >> 16) & 0xff)) + - Math.abs(expectedG - ((actual >> 8) & 0xff)) + - Math.abs(expectedB - ((actual) & 0xff))) / 3.0, pArtifactThreshold); - } - catch (AssertionError e) { - AssertionError assertionError = new AssertionError(String.format("@[%d,%d] expected: 0x%08x but was: 0x%08x", x, y, expected, actual)); - assertionError.initCause(e); - throw assertionError; - } - } - - @Test - public void testReplaceResponse() throws IOException { - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Make sure image is correctly loaded - BufferedImage image = imageResponse.getImage(); - assertNotNull(image); - - // Do something with image - // NOTE: BMP writer can't write ARGB so this image is converted (same goes for JPEG) - // TODO: Make conversion testing more explicit - image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - imageResponse.setImage(image); - imageResponse.setOutputContentType("image/bmp"); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(image.getWidth(), outImage.getWidth()); - assertEquals(image.getHeight(), outImage.getHeight()); - assertSimilarImage(image, outImage, 0); - - verify(response).getOutputStream(); - verify(response).setContentType(CONTENT_TYPE_BMP); - } - - // TODO: Test with AOI attributes (rename thes to source-region?) - // TODO: Test with scale attributes - // More? - - // Make sure we don't change semantics here... - - @Test - public void testNotFoundInput() throws IOException { - // Need special setup - request = mock(HttpServletRequest.class); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/monkey-business.gif"); - - HttpServletResponse response = mock(HttpServletResponse.class); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), anyString()); - } - - // NOTE: This means it's up to some Filter to decide wether we should filter the given request - - @Test - public void testUnsupportedInput() throws IOException { - assertFalse("Test is invalid, rewrite test", ImageIO.getImageReadersByFormatName("txt").hasNext()); - - // Need special setup - request = mock(HttpServletRequest.class); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/foo.txt"); - - HttpServletResponse response = mock(HttpServletResponse.class); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - - fakeResponse(request, imageResponse); - try { - // Force transcode - imageResponse.setOutputContentType("image/png"); - - // Flush image to wrapped response - imageResponse.flush(); - - fail("Should throw IOException in case of unspupported input"); - } - catch (IOException e) { - String message = e.getMessage().toLowerCase(); - assertTrue("Wrong message: " + e.getMessage(), message.contains("transcode")); - assertTrue("Wrong message: " + e.getMessage(), message.contains("reader")); - assertTrue("Wrong message: " + e.getMessage(), message.contains("text")); - - // Failure here suggests a different error condition than the one we expected - } - } - - @Test - public void testUnsupportedOutput() throws IOException { - assertFalse("Test is invalid, rewrite test", ImageIO.getImageWritersByFormatName("foo").hasNext()); - - HttpServletResponse response = mock(HttpServletResponse.class); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - - fakeResponse(request, imageResponse); - try { - // Force transcode to unsupported format - imageResponse.setOutputContentType("application/xml+foo"); - - // Flush image to wrapped response - imageResponse.flush(); - - fail("Should throw IOException in case of unspupported output"); - } - catch (IOException e) { - String message = e.getMessage().toLowerCase(); - assertTrue("Wrong message: " + e.getMessage(), message.contains("transcode")); - assertTrue("Wrong message: " + e.getMessage(), message.contains("writer")); - assertTrue("Wrong message: " + e.getMessage(), message.contains("foo")); - - // Failure here suggests a different error condition than the one we expected - } - } - - // TODO: Test that we handle image conversion to a suitable format, before writing response - // For example: Read a PNG with transparency and store as B/W WBMP - - - // TODO: Create ImageFilter test case, that tests normal use, as well as chaining - - @Test - public void testReadWithSourceRegion() throws IOException { - Rectangle sourceRegion = new Rectangle(100, 100, 100, 100); - // Custom setup - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI)).thenReturn(sourceRegion); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_PNG); - - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Make sure image is correctly loaded - BufferedImage image = imageResponse.getImage(); - assertNotNull(image); - assertEquals(sourceRegion.width, image.getWidth()); - assertEquals(sourceRegion.height, image.getHeight()); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(image.getWidth(), outImage.getWidth()); - assertEquals(image.getHeight(), outImage.getHeight()); - - verify(response).getOutputStream(); - verify(response).setContentType(CONTENT_TYPE_PNG); - } - - @Test - public void testReadWithNonSquareSourceRegion() throws IOException { - Rectangle sourceRegion = new Rectangle(100, 100, 100, 80); - // Custom setup - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI)).thenReturn(sourceRegion); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_PNG); - - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Make sure image is correctly loaded - BufferedImage image = imageResponse.getImage(); - assertNotNull(image); - assertEquals(sourceRegion.width, image.getWidth()); - assertEquals(sourceRegion.height, image.getHeight()); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(image.getWidth(), outImage.getWidth()); - assertEquals(image.getHeight(), outImage.getHeight()); - - verify(response).getOutputStream(); - verify(response).setContentType(CONTENT_TYPE_PNG); - } - - @Test - public void testReadWithCenteredUniformSourceRegion() throws IOException { - // Negative x/y values means centered - Rectangle sourceRegion = new Rectangle(-1, -1, 300, 300); - - // Custom setup - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI_UNIFORM)).thenReturn(true); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI)).thenReturn(sourceRegion); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_PNG); - - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Make sure image is correctly loaded - BufferedImage image = imageResponse.getImage(); - assertNotNull(image); - - assertEquals(sourceRegion.width, image.getWidth()); - assertEquals(sourceRegion.height, image.getHeight()); - - BufferedImage original = ImageIO.read(getClass().getResource(IMAGE_NAME_PNG)); - - // Sanity check - assertNotNull(original); - assertEquals(IMAGE_DIMENSION_PNG.width, original.getWidth()); - assertEquals(IMAGE_DIMENSION_PNG.height, original.getHeight()); - - // Center - sourceRegion.setLocation( - (int) Math.round((IMAGE_DIMENSION_PNG.width - sourceRegion.getWidth()) / 2.0), - (int) Math.round((IMAGE_DIMENSION_PNG.height - sourceRegion.getHeight()) / 2.0) - ); - - // Test that we have exactly the pixels we should - for (int y = 0; y < sourceRegion.height; y++) { - for (int x = 0; x < sourceRegion.width; x++) { - assertEquals(original.getRGB(x + sourceRegion.x, y + sourceRegion.y), image.getRGB(x, y)); - } - } - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(image.getWidth(), outImage.getWidth()); - assertEquals(image.getHeight(), outImage.getHeight()); - - verify(response).getOutputStream(); - verify(response).setContentType(CONTENT_TYPE_PNG); - } - - @Test - public void testReadWithCenteredUniformNonSquareSourceRegion() throws IOException { - // Negative x/y values means centered - Rectangle sourceRegion = new Rectangle(-1, -1, 410, 300); - - // Custom setup - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI_UNIFORM)).thenReturn(true); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI)).thenReturn(sourceRegion); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_PNG); - - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Make sure image is correctly loaded - BufferedImage image = imageResponse.getImage(); - assertNotNull(image); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Image wider than bounding box", IMAGE_DIMENSION_PNG.width >= image.getWidth()); - assertTrue("Image taller than bounding box", IMAGE_DIMENSION_PNG.height >= image.getHeight()); - assertTrue("Image not maximized to bounding box", IMAGE_DIMENSION_PNG.width == image.getWidth() || IMAGE_DIMENSION_PNG.height == image.getHeight()); - - // Above tests that one of the sides equal, we now need to test that the other follows aspect - double destAspect = sourceRegion.getWidth() / sourceRegion.getHeight(); - double srcAspect = IMAGE_DIMENSION_PNG.getWidth() / IMAGE_DIMENSION_PNG.getHeight(); - - if (srcAspect >= destAspect) { - // Dst is narrower than src - assertEquals(IMAGE_DIMENSION_PNG.height, image.getHeight()); - assertEquals( - "Image width does not follow aspect", - Math.round(IMAGE_DIMENSION_PNG.getHeight() * destAspect), image.getWidth() - ); - } - else { - // Dst is wider than src - assertEquals(IMAGE_DIMENSION_PNG.width, image.getWidth()); - assertEquals( - "Image height does not follow aspect", - Math.round(IMAGE_DIMENSION_PNG.getWidth() / destAspect), image.getHeight() - ); - } - - BufferedImage original = ImageIO.read(getClass().getResource(IMAGE_NAME_PNG)); - - // Sanity check - assertNotNull(original); - assertEquals(IMAGE_DIMENSION_PNG.width, original.getWidth()); - assertEquals(IMAGE_DIMENSION_PNG.height, original.getHeight()); - - // Center - sourceRegion.setLocation( - (int) Math.round((IMAGE_DIMENSION_PNG.width - image.getWidth()) / 2.0), - (int) Math.round((IMAGE_DIMENSION_PNG.height - image.getHeight()) / 2.0) - ); - sourceRegion.setSize(image.getWidth(), image.getHeight()); - - // Test that we have exactly the pixels we should - for (int y = 0; y < sourceRegion.height; y++) { - for (int x = 0; x < sourceRegion.width; x++) { - assertEquals(original.getRGB(x + sourceRegion.x, y + sourceRegion.y), image.getRGB(x, y)); - } - } - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(image.getWidth(), outImage.getWidth()); - assertEquals(image.getHeight(), outImage.getHeight()); - - verify(response).getOutputStream(); - verify(response).setContentType(CONTENT_TYPE_PNG); - } - - @Test - public void testReadWithResize() throws IOException { - Dimension size = new Dimension(100, 120); - - // Custom setup - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getAttribute(ImageServletResponse.ATTRIB_SIZE)).thenReturn(size); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_PNG); - - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Make sure image is correctly loaded - BufferedImage image = imageResponse.getImage(); - assertNotNull(image); - - assertTrue("Image wider than bounding box", size.width >= image.getWidth()); - assertTrue("Image taller than bounding box", size.height >= image.getHeight()); - assertTrue("Image not maximized to bounding box", size.width == image.getWidth() || size.height == image.getHeight()); - - // Above tests that one of the sides equal, we now need to test that the other follows aspect - if (size.width == image.getWidth()) { - assertEquals(Math.round(size.getWidth() * IMAGE_DIMENSION_PNG.getWidth() / IMAGE_DIMENSION_PNG.getHeight()), image.getHeight()); - } - else { - assertEquals(Math.round(size.getHeight() * IMAGE_DIMENSION_PNG.getWidth() / IMAGE_DIMENSION_PNG.getHeight()), image.getWidth()); - } - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(image.getWidth(), outImage.getWidth()); - assertEquals(image.getHeight(), outImage.getHeight()); - - verify(response).getOutputStream(); - verify(response).setContentType(CONTENT_TYPE_PNG); - } - - @Test - public void testReadWithNonUniformResize() throws IOException { - Dimension size = new Dimension(150, 150); - // Custom setup - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getAttribute(ImageServletResponse.ATTRIB_SIZE)).thenReturn(size); - when(request.getAttribute(ImageServletResponse.ATTRIB_SIZE_UNIFORM)).thenReturn(false); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_PNG); - - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Make sure image is correctly loaded - BufferedImage image = imageResponse.getImage(); - assertNotNull(image); - assertEquals(size.width, image.getWidth()); - assertEquals(size.height, image.getHeight()); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(image.getWidth(), outImage.getWidth()); - assertEquals(image.getHeight(), outImage.getHeight()); - - verify(response).getOutputStream(); - verify(response).setContentType(CONTENT_TYPE_PNG); - } - - @Test - public void testReadWithSourceRegionAndResize() throws IOException { - Rectangle sourceRegion = new Rectangle(100, 100, 200, 200); - Dimension size = new Dimension(100, 120); - - // Custom setup - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI)).thenReturn(sourceRegion); - when(request.getAttribute(ImageServletResponse.ATTRIB_SIZE)).thenReturn(size); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_PNG); - - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Make sure image is correctly loaded - BufferedImage image = imageResponse.getImage(); - assertNotNull(image); - - assertTrue("Image wider than bounding box", size.width >= image.getWidth()); - assertTrue("Image taller than bounding box", size.height >= image.getHeight()); - assertTrue("Image not maximized to bounding box", size.width == image.getWidth() || size.height == image.getHeight()); - - // Above tests that one of the sides equal, we now need to test that the other follows aspect - if (size.width == image.getWidth()) { - assertEquals(Math.round(size.getWidth() * sourceRegion.getWidth() / sourceRegion.getHeight()), image.getHeight()); - } - else { - assertEquals(Math.round(size.getHeight() * sourceRegion.getWidth() / sourceRegion.getHeight()), image.getWidth()); - } - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(image.getWidth(), outImage.getWidth()); - assertEquals(image.getHeight(), outImage.getHeight()); - - verify(response).getOutputStream(); - verify(response).setContentType(CONTENT_TYPE_PNG); - } - - @Test - public void testReadWithSourceRegionAndNonUniformResize() throws IOException { - Rectangle sourceRegion = new Rectangle(100, 100, 200, 200); - Dimension size = new Dimension(150, 150); - // Custom setup - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI)).thenReturn(sourceRegion); - when(request.getAttribute(ImageServletResponse.ATTRIB_SIZE)).thenReturn(size); - when(request.getAttribute(ImageServletResponse.ATTRIB_SIZE_UNIFORM)).thenReturn(false); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_PNG); - - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Make sure image is correctly loaded - BufferedImage image = imageResponse.getImage(); - assertNotNull(image); - assertEquals(size.width, image.getWidth()); - assertEquals(size.height, image.getHeight()); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(image.getWidth(), outImage.getWidth()); - assertEquals(image.getHeight(), outImage.getHeight()); - - verify(response).getOutputStream(); - verify(response).setContentType(CONTENT_TYPE_PNG); - } - - @Test - public void testReadWithUniformSourceRegionAndResizeSquare() throws IOException { - Rectangle sourceRegion = new Rectangle(-1, -1, 300, 300); - Dimension size = new Dimension(100, 120); - - // Custom setup - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI_UNIFORM)).thenReturn(true); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI)).thenReturn(sourceRegion); - when(request.getAttribute(ImageServletResponse.ATTRIB_SIZE)).thenReturn(size); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_PNG); - - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Make sure image is correctly loaded - BufferedImage image = imageResponse.getImage(); - assertNotNull(image); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Image wider than bounding box", size.width >= image.getWidth()); - assertTrue("Image taller than bounding box", size.height >= image.getHeight()); - assertTrue("Image not maximized to bounding box", size.width == image.getWidth() || size.height == image.getHeight()); - - // Above tests that one of the sides equal, we now need to test that the other follows aspect - if (size.width == image.getWidth()) { - assertEquals( - "Image height does not follow aspect", - Math.round(size.getWidth() / (sourceRegion.getWidth() / sourceRegion.getHeight())), image.getHeight() - ); - } - else { - System.out.println("size: " + size); - System.out.println("image: " + new Dimension(image.getWidth(), image.getHeight())); - assertEquals( - "Image width does not follow aspect", - Math.round(size.getHeight() * (sourceRegion.getWidth() / sourceRegion.getHeight())), image.getWidth() - ); - } - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(image.getWidth(), outImage.getWidth()); - assertEquals(image.getHeight(), outImage.getHeight()); - - verify(response).getOutputStream(); - verify(response).setContentType(CONTENT_TYPE_PNG); - } - - @Test - public void testReadWithNonSquareUniformSourceRegionAndResize() throws IOException { - Rectangle sourceRegion = new Rectangle(-1, -1, 170, 300); - Dimension size = new Dimension(150, 120); - - // Custom setup - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI_UNIFORM)).thenReturn(true); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI)).thenReturn(sourceRegion); - when(request.getAttribute(ImageServletResponse.ATTRIB_SIZE)).thenReturn(size); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_PNG); - - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Make sure image is correctly loaded - BufferedImage image = imageResponse.getImage(); - assertNotNull(image); - - // Flush image to wrapped response - imageResponse.flush(); - -// File tempFile = File.createTempFile("test", ".png"); -// FileUtil.write(tempFile, out.toByteArray()); -// System.out.println("tempFile: " + tempFile); - - assertTrue("Image wider than bounding box", size.width >= image.getWidth()); - assertTrue("Image taller than bounding box", size.height >= image.getHeight()); - assertTrue("Image not maximized to bounding box", size.width == image.getWidth() || size.height == image.getHeight()); - - // Above tests that one of the sides equal, we now need to test that the other follows aspect - if (size.width == image.getWidth()) { - assertEquals( - "Image height does not follow aspect", - Math.round(size.getWidth() / (sourceRegion.getWidth() / sourceRegion.getHeight())), image.getHeight() - ); - } - else { -// System.out.println("size: " + size); -// System.out.println("image: " + new Dimension(image.getWidth(), image.getHeight())); - assertEquals( - "Image width does not follow aspect", - Math.round(size.getHeight() * (sourceRegion.getWidth() / sourceRegion.getHeight())), image.getWidth() - ); - } - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(image.getWidth(), outImage.getWidth()); - assertEquals(image.getHeight(), outImage.getHeight()); - - verify(response).getOutputStream(); - verify(response).setContentType(CONTENT_TYPE_PNG); - } - - @Test - public void testReadWithAllNegativeSourceRegion() throws IOException { - Rectangle sourceRegion = new Rectangle(-1, -1, -1, -1); - Dimension size = new Dimension(100, 120); - - // Custom setup - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI_UNIFORM)).thenReturn(true); - when(request.getAttribute(ImageServletResponse.ATTRIB_AOI)).thenReturn(sourceRegion); - when(request.getAttribute(ImageServletResponse.ATTRIB_SIZE)).thenReturn(size); - when(request.getContextPath()).thenReturn("/ape"); - when(request.getRequestURI()).thenReturn("/ape/" + IMAGE_NAME_PNG); - - FastByteArrayOutputStream out = new FastByteArrayOutputStream(STREAM_DEFAULT_SIZE); - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.getOutputStream()).thenReturn(new OutputStreamAdapter(out)); - - ImageServletResponseImpl imageResponse = new ImageServletResponseImpl(request, response, context); - fakeResponse(request, imageResponse); - - // Make sure image is correctly loaded - BufferedImage image = imageResponse.getImage(); - assertNotNull(image); - - assertTrue("Image wider than bounding box", size.width >= image.getWidth()); - assertTrue("Image taller than bounding box", size.height >= image.getHeight()); - assertTrue("Image not maximized to bounding box", size.width == image.getWidth() || size.height == image.getHeight()); - - // Flush image to wrapped response - imageResponse.flush(); - - assertTrue("Content has no data", out.size() > 0); - - // Test that image data is still readable - BufferedImage outImage = ImageIO.read(out.createInputStream()); - assertNotNull(outImage); - assertEquals(image.getWidth(), outImage.getWidth()); - assertEquals(image.getHeight(), outImage.getHeight()); - - verify(response).getOutputStream(); - verify(response).setContentType(CONTENT_TYPE_PNG); - } - - // ----------------------------------------------------------------------------------------------------------------- - // Absolute AOI - // ----------------------------------------------------------------------------------------------------------------- - - @Test - public void testGetAOIAbsolute() { - assertEquals(new Rectangle(10, 10, 100, 100), ImageServletResponseImpl.getAOI(200, 200, 10, 10, 100, 100, false, false)); - } - - @Test - public void testGetAOIAbsoluteOverflowX() { - assertEquals(new Rectangle(10, 10, 90, 100), ImageServletResponseImpl.getAOI(100, 200, 10, 10, 100, 100, false, false)); - } - - @Test - public void testGetAOIAbsoluteOverflowW() { - assertEquals(new Rectangle(0, 10, 100, 100), ImageServletResponseImpl.getAOI(100, 200, 0, 10, 110, 100, false, false)); - } - - @Test - public void testGetAOIAbsoluteOverflowY() { - assertEquals(new Rectangle(10, 10, 100, 90), ImageServletResponseImpl.getAOI(200, 100, 10, 10, 100, 100, false, false)); - } - - @Test - public void testGetAOIAbsoluteOverflowH() { - assertEquals(new Rectangle(10, 0, 100, 100), ImageServletResponseImpl.getAOI(200, 100, 10, 0, 100, 110, false, false)); - } - - // ----------------------------------------------------------------------------------------------------------------- - // Uniform AOI centered - // ----------------------------------------------------------------------------------------------------------------- - - @Test - public void testGetAOIUniformCenteredS2SUp() { - assertEquals(new Rectangle(0, 0, 100, 100), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 333, 333, false, true)); - } - - @Test - public void testGetAOIUniformCenteredS2SDown() { - assertEquals(new Rectangle(0, 0, 100, 100), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 33, 33, false, true)); - } - - @Test - public void testGetAOIUniformCenteredS2SNormalized() { - assertEquals(new Rectangle(0, 0, 100, 100), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 100, 100, false, true)); - } - - @Test - public void testGetAOIUniformCenteredS2W() { - assertEquals(new Rectangle(0, 25, 100, 50), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 200, 100, false, true)); - } - - @Test - public void testGetAOIUniformCenteredS2WNormalized() { - assertEquals(new Rectangle(0, 25, 100, 50), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 100, 50, false, true)); - } - - @Test - public void testGetAOIUniformCenteredS2N() { - assertEquals(new Rectangle(25, 0, 50, 100), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 100, 200, false, true)); - } - - @Test - public void testGetAOIUniformCenteredS2NNormalized() { - assertEquals(new Rectangle(25, 0, 50, 100), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 50, 100, false, true)); - } - - @Test - public void testGetAOIUniformCenteredW2S() { - assertEquals(new Rectangle(50, 0, 100, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 333, 333, false, true)); - } - - @Test - public void testGetAOIUniformCenteredW2SNormalized() { - assertEquals(new Rectangle(50, 0, 100, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 100, 100, false, true)); - } - - @Test - public void testGetAOIUniformCenteredW2W() { - assertEquals(new Rectangle(0, 0, 200, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 100, 50, false, true)); - } - - @Test - public void testGetAOIUniformCenteredW2WW() { - assertEquals(new Rectangle(0, 25, 200, 50), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 200, 50, false, true)); - } - - @Test - public void testGetAOIUniformCenteredW2WN() { - assertEquals(new Rectangle(25, 0, 150, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 75, 50, false, true)); - } - - @Test - public void testGetAOIUniformCenteredW2WNNormalized() { - assertEquals(new Rectangle(25, 0, 150, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 150, 100, false, true)); - } - - @Test - public void testGetAOIUniformCenteredW2WNormalized() { - assertEquals(new Rectangle(0, 0, 200, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 200, 100, false, true)); - } - - @Test - public void testGetAOIUniformCenteredW2N() { - assertEquals(new Rectangle(75, 0, 50, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 100, 200, false, true)); - } - - @Test - public void testGetAOIUniformCenteredW2NNormalized() { - assertEquals(new Rectangle(75, 0, 50, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 50, 100, false, true)); - } - - @Test - public void testGetAOIUniformCenteredN2S() { - assertEquals(new Rectangle(0, 50, 100, 100), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 333, 333, false, true)); - } - - @Test - public void testGetAOIUniformCenteredN2SNormalized() { - assertEquals(new Rectangle(0, 50, 100, 100), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 100, 100, false, true)); - } - - @Test - public void testGetAOIUniformCenteredN2W() { - assertEquals(new Rectangle(0, 75, 100, 50), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 200, 100, false, true)); - } - - @Test - public void testGetAOIUniformCenteredN2WNormalized() { - assertEquals(new Rectangle(0, 75, 100, 50), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 100, 50, false, true)); - } - - @Test - public void testGetAOIUniformCenteredN2N() { - assertEquals(new Rectangle(0, 0, 100, 200), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 50, 100, false, true)); - } - - @Test - public void testGetAOIUniformCenteredN2NN() { - assertEquals(new Rectangle(25, 0, 50, 200), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 25, 100, false, true)); - } - - @Test - public void testGetAOIUniformCenteredN2NW() { - assertEquals(new Rectangle(0, 33, 100, 133), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 75, 100, false, true)); - } - - @Test - public void testGetAOIUniformCenteredN2NWNormalized() { - assertEquals(new Rectangle(0, 37, 100, 125), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 100, 125, false, true)); - } - - @Test - public void testGetAOIUniformCenteredN2NNormalized() { - assertEquals(new Rectangle(0, 0, 100, 200), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 100, 200, false, true)); - } - - // ----------------------------------------------------------------------------------------------------------------- - // Absolute AOI centered - // ----------------------------------------------------------------------------------------------------------------- - - @Test - public void testGetAOICenteredS2SUp() { - assertEquals(new Rectangle(0, 0, 100, 100), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 333, 333, false, false)); - } - - @Test - public void testGetAOICenteredS2SDown() { - assertEquals(new Rectangle(33, 33, 33, 33), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 33, 33, false, false)); - } - - @Test - public void testGetAOICenteredS2SSame() { - assertEquals(new Rectangle(0, 0, 100, 100), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 100, 100, false, false)); - } - - @Test - public void testGetAOICenteredS2WOverflow() { - assertEquals(new Rectangle(0, 0, 100, 100), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 200, 100, false, false)); - } - - @Test - public void testGetAOICenteredS2W() { - assertEquals(new Rectangle(40, 45, 20, 10), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 20, 10, false, false)); - } - - @Test - public void testGetAOICenteredS2WMax() { - assertEquals(new Rectangle(0, 25, 100, 50), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 100, 50, false, false)); - } - - @Test - public void testGetAOICenteredS2NOverflow() { - assertEquals(new Rectangle(0, 0, 100, 100), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 100, 200, false, false)); - } - - @Test - public void testGetAOICenteredS2N() { - assertEquals(new Rectangle(45, 40, 10, 20), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 10, 20, false, false)); - } - - @Test - public void testGetAOICenteredS2NMax() { - assertEquals(new Rectangle(25, 0, 50, 100), ImageServletResponseImpl.getAOI(100, 100, -1, -1, 50, 100, false, false)); - } - - @Test - public void testGetAOICenteredW2SOverflow() { - assertEquals(new Rectangle(0, 0, 200, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 333, 333, false, false)); - } - - @Test - public void testGetAOICenteredW2S() { - assertEquals(new Rectangle(75, 25, 50, 50), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 50, 50, false, false)); - } - - @Test - public void testGetAOICenteredW2SMax() { - assertEquals(new Rectangle(50, 0, 100, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 100, 100, false, false)); - } - - @Test - public void testGetAOICenteredW2WOverflow() { - assertEquals(new Rectangle(0, 0, 200, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 300, 200, false, false)); - } - - @Test - public void testGetAOICenteredW2W() { - assertEquals(new Rectangle(50, 25, 100, 50), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 100, 50, false, false)); - } - - @Test - public void testGetAOICenteredW2WW() { - assertEquals(new Rectangle(10, 40, 180, 20), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 180, 20, false, false)); - } - - @Test - public void testGetAOICenteredW2WN() { - assertEquals(new Rectangle(62, 25, 75, 50), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 75, 50, false, false)); - } - - @Test - public void testGetAOICenteredW2WSame() { - assertEquals(new Rectangle(0, 0, 200, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 200, 100, false, false)); - } - - @Test - public void testGetAOICenteredW2NOverflow() { - assertEquals(new Rectangle(50, 0, 100, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 100, 200, false, false)); - } - - @Test - public void testGetAOICenteredW2N() { - assertEquals(new Rectangle(83, 25, 33, 50), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 33, 50, false, false)); - } - - @Test - public void testGetAOICenteredW2NMax() { - assertEquals(new Rectangle(75, 0, 50, 100), ImageServletResponseImpl.getAOI(200, 100, -1, -1, 50, 100, false, false)); - } - - @Test - public void testGetAOICenteredN2S() { - assertEquals(new Rectangle(33, 83, 33, 33), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 33, 33, false, false)); - } - - @Test - public void testGetAOICenteredN2SMax() { - assertEquals(new Rectangle(0, 50, 100, 100), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 100, 100, false, false)); - } - - @Test - public void testGetAOICenteredN2WOverflow() { - assertEquals(new Rectangle(0, 50, 100, 100), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 200, 100, false, false)); - } - - @Test - public void testGetAOICenteredN2W() { - assertEquals(new Rectangle(40, 95, 20, 10), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 20, 10, false, false)); - } - - @Test - public void testGetAOICenteredN2WMax() { - assertEquals(new Rectangle(0, 75, 100, 50), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 100, 50, false, false)); - } - - @Test - public void testGetAOICenteredN2N() { - assertEquals(new Rectangle(45, 90, 10, 20), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 10, 20, false, false)); - } - - @Test - public void testGetAOICenteredN2NSame() { - assertEquals(new Rectangle(0, 0, 100, 200), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 100, 200, false, false)); - } - - @Test - public void testGetAOICenteredN2NN() { - assertEquals(new Rectangle(37, 50, 25, 100), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 25, 100, false, false)); - } - - @Test - public void testGetAOICenteredN2NW() { - assertEquals(new Rectangle(12, 50, 75, 100), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 75, 100, false, false)); - } - - @Test - public void testGetAOICenteredN2NWMax() { - assertEquals(new Rectangle(0, 37, 100, 125), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 100, 125, false, false)); - } - - @Test - public void testGetAOICenteredN2NMax() { - assertEquals(new Rectangle(0, 0, 100, 200), ImageServletResponseImpl.getAOI(100, 200, -1, -1, 100, 200, false, false)); - } - - // TODO: Test percent - - // TODO: Test getSize()... - - private static class BlackLabel extends JLabel { - private final Paint checkeredBG; - private boolean opaque = true; - - public BlackLabel(final String text, final BufferedImage outImage) { - super(text, new BufferedImageIcon(outImage), JLabel.CENTER); - setOpaque(true); - setBackground(Color.BLACK); - setForeground(Color.WHITE); - setVerticalAlignment(JLabel.CENTER); - setVerticalTextPosition(JLabel.BOTTOM); - setHorizontalTextPosition(JLabel.CENTER); - - checkeredBG = createTexture(); - } - - @Override - public boolean isOpaque() { - return opaque && super.isOpaque(); - } - - @Override - protected void paintComponent(Graphics graphics) { - Graphics2D g = (Graphics2D) graphics; - - int iconHeight = getIcon() == null ? 0 : getIcon().getIconHeight() + getIconTextGap(); - - // Paint checkered bg behind icon - g.setPaint(checkeredBG); - g.fillRect(0, 0, getWidth(), getHeight()); - - // Paint black bg behind text - g.setColor(getBackground()); - g.fillRect(0, iconHeight, getWidth(), getHeight() - iconHeight); - - try { - opaque = false; - super.paintComponent(g); - } - finally { - opaque = true; - } - } - - private static Paint createTexture() { - GraphicsConfiguration graphicsConfiguration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); - BufferedImage pattern = graphicsConfiguration.createCompatibleImage(20, 20); - Graphics2D g = pattern.createGraphics(); - try { - g.setColor(Color.LIGHT_GRAY); - g.fillRect(0, 0, pattern.getWidth(), pattern.getHeight()); - g.setColor(Color.GRAY); - g.fillRect(0, 0, pattern.getWidth() / 2, pattern.getHeight() / 2); - g.fillRect(pattern.getWidth() / 2, pattern.getHeight() / 2, pattern.getWidth() / 2, pattern.getHeight() / 2); - } - finally { - g.dispose(); - } - - return new TexturePaint(pattern, new Rectangle(pattern.getWidth(), pattern.getHeight())); - } - } - - private static class MockLogger implements Answer { - public Void answer(InvocationOnMock invocation) throws Throwable { - // either log(String), log(String, Throwable) or log(Exception, String) - Object[] arguments = invocation.getArguments(); - - String msg = (String) (arguments[0] instanceof String ? arguments[0] : arguments[1]); - Throwable t = (Throwable) (arguments[0] instanceof Exception ? arguments[0] : arguments.length > 1 ? arguments[1] : null); - - System.out.println("mock-context: " + msg); - if (t != null) { - t.printStackTrace(System.out); - } - - return null; - } - } - -} diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterestTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterestTest.java deleted file mode 100644 index db0c9525..00000000 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/image/aoi/AreaOfInterestTest.java +++ /dev/null @@ -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 Erlend Hamnaberg - * @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)); - } - -}