From 1ffe694538a6cf5294026afb6ade6df7a4e080a4 Mon Sep 17 00:00:00 2001 From: Harald Kuhr Date: Mon, 4 Mar 2013 14:48:50 +0100 Subject: [PATCH] TMS-XXXX: New map adapters for servlet context and request attributes + minor API tweaks. --- .../servlet/AbstractServletMapAdapter.java | 104 ++++-------- .../servlet/ServletAttributesMapAdapter.java | 134 +++++++++++++++ .../servlet/ServletHeadersMapAdapter.java | 27 +-- .../servlet/ServletParametersMapAdapter.java | 23 +-- .../twelvemonkeys/servlet/ServletUtil.java | 39 +++-- ...ervletAttributesMapAdapterContextTest.java | 156 ++++++++++++++++++ ...ervletAttributesMapAdapterRequestTest.java | 156 ++++++++++++++++++ ....java => ServletConfigMapAdapterTest.java} | 8 +- ...java => ServletHeadersMapAdapterTest.java} | 2 +- ...a => ServletParametersMapAdapterTest.java} | 2 +- 10 files changed, 543 insertions(+), 108 deletions(-) create mode 100644 servlet/src/main/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapter.java create mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterContextTest.java create mode 100755 servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterRequestTest.java rename servlet/src/test/java/com/twelvemonkeys/servlet/{ServletConfigMapAdapterTestCase.java => ServletConfigMapAdapterTest.java} (94%) rename servlet/src/test/java/com/twelvemonkeys/servlet/{ServletHeadersMapAdapterTestCase.java => ServletHeadersMapAdapterTest.java} (94%) rename servlet/src/test/java/com/twelvemonkeys/servlet/{ServletParametersMapAdapterTestCase.java => ServletParametersMapAdapterTest.java} (94%) diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/AbstractServletMapAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/AbstractServletMapAdapter.java index 3d187231..7ee01471 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/AbstractServletMapAdapter.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/AbstractServletMapAdapter.java @@ -1,7 +1,5 @@ package com.twelvemonkeys.servlet; -import com.twelvemonkeys.util.CollectionUtil; - import java.util.*; /** @@ -11,88 +9,53 @@ import java.util.*; * @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 too (instead?) ! - - private final static List NULL_LIST = new ArrayList(); - - private transient Map> cache = new HashMap>(); - private transient int size = -1; - private transient AbstractSet>> entries; +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 Iterator valuesImpl(String pName); + protected abstract T valueImpl(String pName); @Override - public List get(final Object pKey) { + public T get(final Object pKey) { if (pKey instanceof String) { - return getValues((String) pKey); + return valueImpl((String) pKey); } return null; } - private List getValues(final String pName) { - List values = cache.get(pName); - - if (values == null) { - //noinspection unchecked - Iterator headers = valuesImpl(pName); - - if (headers == null) { - cache.put(pName, NULL_LIST); - } - else { - values = toList(headers); - cache.put(pName, values); - } - } - - return values == NULL_LIST ? null : values; - } - - private static List toList(final Iterator pValues) { - List list = new ArrayList(); - CollectionUtil.addAll(list, pValues); - return Collections.unmodifiableList(list); - } - @Override public int size() { - if (size == -1) { - computeSize(); + // Avoid creating expensive entry set for computing size + int size = 0; + + for (Iterator names = keysImpl(); names.hasNext(); names.next()) { + size++; } return size; } - private void computeSize() { - size = 0; - - for (Iterator names = keysImpl(); names.hasNext(); names.next()) { - size++; - } - } - - public Set>> entrySet() { + public Set> entrySet() { if (entries == null) { - entries = new AbstractSet>>() { - public Iterator>> iterator() { - return new Iterator>>() { - Iterator headerNames = keysImpl(); + entries = new AbstractSet>() { + public Iterator> iterator() { + return new Iterator>() { + Iterator keys = keysImpl(); public boolean hasNext() { - return headerNames.hasNext(); + return keys.hasNext(); } - public Entry> next() { + public Entry next() { // TODO: Replace with cached lookup - return new HeaderEntry(headerNames.next()); + return new HeaderEntry(keys.next()); } public void remove() { - throw new UnsupportedOperationException(); + keys.remove(); } }; } @@ -106,34 +69,35 @@ abstract class AbstractServletMapAdapter extends AbstractMap> { - String headerName; + private class HeaderEntry implements Entry { + final String key; - public HeaderEntry(String pHeaderName) { - headerName = pHeaderName; + public HeaderEntry(final String pKey) { + key = pKey; } public String getKey() { - return headerName; + return key; } - public List getValue() { - return get(headerName); + public T getValue() { + return get(key); } - public List setValue(List pValue) { - throw new UnsupportedOperationException(); + public T setValue(final T pValue) { + // Write-through if supported + return put(key, pValue); } @Override public int hashCode() { - List value; - return (headerName == null ? 0 : headerName.hashCode()) ^ - ((value = getValue()) == null ? 0 : value.hashCode()); + T value = getValue(); + return (key == null ? 0 : key.hashCode()) ^ + (value == null ? 0 : value.hashCode()); } @Override - public boolean equals(Object pOther) { + public boolean equals(final Object pOther) { if (pOther == this) { return true; } diff --git a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapter.java new file mode 100644 index 00000000..227f12c7 --- /dev/null +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapter.java @@ -0,0 +1,134 @@ +/* + * 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 "TwelveMonkeys" 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 OWNER 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/ServletHeadersMapAdapter.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapter.java index 76054e11..b547929f 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapter.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapter.java @@ -1,11 +1,11 @@ package com.twelvemonkeys.servlet; -import com.twelvemonkeys.lang.Validate; import com.twelvemonkeys.util.CollectionUtil; import javax.servlet.http.HttpServletRequest; -import java.util.Enumeration; -import java.util.Iterator; +import java.util.*; + +import static com.twelvemonkeys.lang.Validate.notNull; /** * ServletHeadersMapAdapter @@ -14,24 +14,29 @@ import java.util.Iterator; * @author last modified by $Author: haku $ * @version $Id: ServletHeadersMapAdapter.java#1 $ */ -class ServletHeadersMapAdapter extends AbstractServletMapAdapter { +class ServletHeadersMapAdapter extends AbstractServletMapAdapter> { protected final HttpServletRequest request; - public ServletHeadersMapAdapter(HttpServletRequest pRequest) { - request = Validate.notNull(pRequest, "request"); + public ServletHeadersMapAdapter(final HttpServletRequest pRequest) { + request = notNull(pRequest, "request"); } - protected Iterator valuesImpl(String pName) { - //noinspection unchecked + protected List valueImpl(final String pName) { + @SuppressWarnings("unchecked") Enumeration headers = request.getHeaders(pName); - return headers == null ? null : CollectionUtil.iterator(headers); + 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() { - //noinspection unchecked + @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 index 01dca170..9324d2fb 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletParametersMapAdapter.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletParametersMapAdapter.java @@ -1,11 +1,14 @@ package com.twelvemonkeys.servlet; -import com.twelvemonkeys.lang.Validate; import com.twelvemonkeys.util.CollectionUtil; -import javax.servlet.http.HttpServletRequest; +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 @@ -14,23 +17,23 @@ import java.util.Iterator; * @author last modified by $Author: haku $ * @version $Id: ServletParametersMapAdapter.java#1 $ */ -class ServletParametersMapAdapter extends AbstractServletMapAdapter { +class ServletParametersMapAdapter extends AbstractServletMapAdapter> { + // TODO: Be able to piggyback on HttpServletRequest.getParameterMap when available? - protected final HttpServletRequest request; + protected final ServletRequest request; - public ServletParametersMapAdapter(HttpServletRequest pRequest) { - request = Validate.notNull(pRequest, "request"); + public ServletParametersMapAdapter(final ServletRequest pRequest) { + request = notNull(pRequest, "request"); } - protected Iterator valuesImpl(String pName) { + protected List valueImpl(String pName) { String[] values = request.getParameterValues(pName); - return values == null ? null : CollectionUtil.iterator(values); + return values == null ? null : Arrays.asList(values); } protected Iterator keysImpl() { - //noinspection unchecked + @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/ServletUtil.java b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletUtil.java index 16772271..41072fa8 100755 --- a/servlet/src/main/java/com/twelvemonkeys/servlet/ServletUtil.java +++ b/servlet/src/main/java/com/twelvemonkeys/servlet/ServletUtil.java @@ -50,7 +50,7 @@ import java.util.Map; /** * Various servlet related helper methods. * - * @author Harald Kuhr + * @author Harald Kuhr * @author Eirik Torske * @author last modified by $Author: haku $ * @version $Id: ServletUtil.java#3 $ @@ -544,7 +544,7 @@ public final class ServletUtil { /** * Returns a {@code URL} containing the real path for a given virtual * path, on URL form. - * Note that this mehtod will return {@code null} for all the same reasons + * 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 @@ -566,7 +566,7 @@ public final class ServletUtil { } /** - * Gets the temp directory for the given {@code ServletContext} (webapp). + * Gets the temp directory for the given {@code ServletContext} (web app). * * @param pContext the servlet context * @return the temp directory @@ -634,13 +634,30 @@ public final class ServletUtil { return new ServletConfigMapAdapter(pContext); } - // TODO? -// public static Map attributesAsMap(final ServletContext pContext) { -// } -// -// public static Map attributesAsMap(final ServletRequest pRequest) { -// } -// + /** + * Creates an 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. @@ -649,7 +666,7 @@ public final class ServletUtil { * @return a {@code Map} view of the request parameters * @throws IllegalArgumentException if {@code pRequest} is {@code null} */ - public static Map> parametersAsMap(final HttpServletRequest pRequest) { + public static Map> parametersAsMap(final ServletRequest pRequest) { return new ServletParametersMapAdapter(pRequest); } diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterContextTest.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterContextTest.java new file mode 100755 index 00000000..759714e4 --- /dev/null +++ b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterContextTest.java @@ -0,0 +1,156 @@ +/* + * 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 "TwelveMonkeys" 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 OWNER 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.MapAbstractTestCase; +import org.mockito.Mockito; + +import javax.servlet.ServletContext; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +import static org.mockito.Mockito.mock; + +/** + * ServletConfigMapAdapterTestCase + *

+ * + * @author Harald Kuhr + * @version $Id: ServletAttributesMapAdapterTestCase.java#1 $ + */ +public class ServletAttributesMapAdapterContextTest extends MapAbstractTestCase { + 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)}; + } + + @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 new file mode 100755 index 00000000..ee461352 --- /dev/null +++ b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletAttributesMapAdapterRequestTest.java @@ -0,0 +1,156 @@ +/* + * 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 "TwelveMonkeys" 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 OWNER 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.MapAbstractTestCase; +import org.mockito.Mockito; + +import javax.servlet.ServletRequest; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +import static org.mockito.Mockito.mock; + +/** + * ServletConfigMapAdapterTestCase + *

+ * + * @author Harald Kuhr + * @version $Id: ServletAttributesMapAdapterTestCase.java#1 $ + */ +public class ServletAttributesMapAdapterRequestTest extends MapAbstractTestCase { + 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)}; + } + + @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/ServletConfigMapAdapterTestCase.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigMapAdapterTest.java similarity index 94% rename from servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigMapAdapterTestCase.java rename to servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigMapAdapterTest.java index 1994fa4b..9b5c405a 100755 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigMapAdapterTestCase.java +++ b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigMapAdapterTest.java @@ -16,7 +16,7 @@ import java.net.MalformedURLException; * @author Harald Kuhr * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigMapAdapterTestCase.java#3 $ */ -public abstract class ServletConfigMapAdapterTestCase extends MapAbstractTestCase { +public abstract class ServletConfigMapAdapterTest extends MapAbstractTestCase { public boolean isPutAddSupported() { return false; @@ -148,7 +148,7 @@ public abstract class ServletConfigMapAdapterTestCase extends MapAbstractTestCas } } - public static final class ServletConfigMapTestCase extends ServletConfigMapAdapterTestCase { + public static final class ServletConfigMapTestCase extends ServletConfigMapAdapterTest { public Map makeEmptyMap() { ServletConfig config = new TestConfig(); @@ -162,7 +162,7 @@ public abstract class ServletConfigMapAdapterTestCase extends MapAbstractTestCas } } - public static final class FilterConfigMapTestCase extends ServletConfigMapAdapterTestCase { + public static final class FilterConfigMapTestCase extends ServletConfigMapAdapterTest { public Map makeEmptyMap() { FilterConfig config = new TestConfig(); @@ -176,7 +176,7 @@ public abstract class ServletConfigMapAdapterTestCase extends MapAbstractTestCas } } - public static final class ServletContextMapTestCase extends ServletConfigMapAdapterTestCase { + public static final class ServletContextMapTestCase extends ServletConfigMapAdapterTest { public Map makeEmptyMap() { ServletContext config = new TestConfig(); diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTestCase.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTest.java similarity index 94% rename from servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTestCase.java rename to servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTest.java index e462b92f..f70d214c 100755 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTestCase.java +++ b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletHeadersMapAdapterTest.java @@ -17,7 +17,7 @@ import static org.mockito.Mockito.when; * @author Harald Kuhr * @version $Id: ServletHeadersMapAdapterTestCase.java#1 $ */ -public class ServletHeadersMapAdapterTestCase extends MapAbstractTestCase { +public class ServletHeadersMapAdapterTest extends MapAbstractTestCase { private static final List HEADER_VALUE_ETAG = Arrays.asList("\"1234567890abcdef\""); private static final List HEADER_VALUE_DATE = Arrays.asList(new Date().toString()); private static final List HEADER_VALUE_FOO = Arrays.asList("one", "two"); diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTestCase.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTest.java similarity index 94% rename from servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTestCase.java rename to servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTest.java index 9af1ad34..b2590873 100755 --- a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTestCase.java +++ b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTest.java @@ -17,7 +17,7 @@ import static org.mockito.Mockito.when; * @author Harald Kuhr * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTestCase.java#1 $ */ -public class ServletParametersMapAdapterTestCase extends MapAbstractTestCase { +public class ServletParametersMapAdapterTest extends MapAbstractTestCase { private static final List PARAM_VALUE_ETAG = Arrays.asList("\"1234567890abcdef\""); private static final List PARAM_VALUE_DATE = Arrays.asList(new Date().toString()); private static final List PARAM_VALUE_FOO = Arrays.asList("one", "two");