/** * Creates a map which decorates the given <code>map</code> and * creates the value collections using the supplied <code>collectionFactory</code>. * * @param <K> the key type * @param <V> the value type * @param <C> the collection class type * @param map the map to decorate * @param collectionFactory the collection factory (must return a Collection object). * @return a new multi-value map * @since 4.0 */ public static <K, V, C extends Collection<V>> MultiValueMap<K, V> multiValueMap(final Map<K, ? super C> map, final Factory<C> collectionFactory) { return new MultiValueMap<>(map, collectionFactory); }
/** * Override superclass to ensure that MultiMap instances are * correctly handled. * <p> * If you call this method with a normal map, each entry is * added using <code>put(Object,Object)</code>. * If you call this method with a multi map, each entry is * added using <code>putAll(Object,Collection)</code>. * * @param map the map to copy (either a normal or multi map) */ @Override @SuppressWarnings("unchecked") public void putAll(final Map<? extends K, ?> map) { if (map instanceof MultiMap) { for (final Map.Entry<? extends K, Object> entry : ((MultiMap<? extends K, V>) map).entrySet()) { putAll(entry.getKey(), (Collection<V>) entry.getValue()); } } else { for (final Map.Entry<? extends K, ?> entry : map.entrySet()) { put(entry.getKey(), entry.getValue()); } } }
/** * Adds the value to the collection associated with the specified key. * <p> * Unlike a normal <code>Map</code> the previous value is not replaced. * Instead the new value is added to the collection stored against the key. * * @param key the key to store against * @param value the value to add to the collection at the key * @return the value added if the map changed and null if the map did not change */ @Override @SuppressWarnings("unchecked") public Object put(final K key, final Object value) { boolean result = false; Collection<V> coll = getCollection(key); if (coll == null) { coll = createCollection(1); // might produce a non-empty collection coll.add((V) value); if (coll.size() > 0) { // only add if non-zero size to maintain class state decorated().put(key, coll); result = true; // map definitely changed } } else { result = coll.add((V) value); } return result ? value : null; }
/** * Removes a specific value from map. * <p> * The item is removed from the collection mapped to the specified key. * Other values attached to that key are unaffected. * <p> * If the last value for a key is removed, <code>null</code> will be returned * from a subsequent <code>get(key)</code>. * * @param key the key to remove from * @param value the value to remove * @return {@code true} if the mapping was removed, {@code false} otherwise */ @Override public boolean removeMapping(final Object key, final Object value) { final Collection<V> valuesForKey = getCollection(key); if (valuesForKey == null) { return false; } final boolean removed = valuesForKey.remove(value); if (removed == false) { return false; } if (valuesForKey.isEmpty()) { remove(key); } return true; }
@Test public void testServesUnzippedContentAndRemovesGzipHeadersIfClientDoesNotAcceptGZipEncoding() throws Exception { final String dummyContent = "hello i'm a page that was cached"; final MultiValueMap headers = new MultiValueMap(); headers.put("Content-Encoding", "gzip"); headers.put("Vary", "Accept-Encoding"); headers.put("Dummy", "Some Value"); final InMemoryCachedEntry cachedPage = new InMemoryCachedEntry(dummyContent.getBytes(), "text/plain", "ASCII", 123, headers, System.currentTimeMillis(), originalURL, -1); when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.useCache, "/test-page", cachedPage)); when(request.getDateHeader("If-Modified-Since")).thenReturn(-1l); when(request.getHeader("User-Agent")).thenReturn("Mozilla/4.0 (MSIE 7.0; Windows NT 5.1)"); when(request.getHeaders("Accept-Encoding")).thenReturn(enumeration()); final ByteArrayOutputStream fakedOut = new ByteArrayOutputStream(); response.setStatus(123); when(response.containsHeader("Dummy")).thenReturn(false); response.addHeader("Dummy", "Some Value"); response.setContentType("text/plain"); response.setCharacterEncoding("ASCII"); response.setContentLength(dummyContent.length()); when(response.getOutputStream()).thenReturn(new SimpleServletOutputStream(fakedOut)); response.flushBuffer(); when(webContext.getResponse()).thenReturn(response); executeNoCacheFilterAndVerify(); assertEquals(dummyContent, fakedOut.toString()); }
/** * Gets the size of the collection mapped to the specified key. * * @param key the key to get size for * @return the size of the collection at the key, zero if key not in map */ public int size(final Object key) { final Collection<V> coll = getCollection(key); if (coll == null) { return 0; } return coll.size(); }
/** * In the parameters variable, adds the value to the collection associated with the specified key. * <p> * Unlike {@link #addParameter(String, Object)} the previous value is overridden. * First, any existing values are removed, then the new value is added to the collection at the specified key * * @param key the key to store against * @param value the value to add to the collection at the key */ protected void addSingletonParameter(String key, Object value) { parameters.remove(key); parameters.put(key, value); }
/** * In the parameters variable, adds the value to the collection associated with the specified key. * <p> * Unlike a normal <code>Map</code> the previous value is not replaced. * Instead the new value is added to the collection stored against the key. * * @param key the key to store against * @param value the value to add to the collection at the key */ public void addParameter(String key, Object value) { parameters.put(key, value); }
/** * Gets an iterator for the collection mapped to the specified key. * * @param key the key to get an iterator for * @return the iterator of the collection at the key, empty iterator if key not in map */ public Iterator<V> iterator(final Object key) { if (!containsKey(key)) { return EmptyIterator.<V>emptyIterator(); } return new ValuesIterator(key); }
@Test public void testUnGZipIfContentIsGZipped() throws IOException { final String s = "hello"; final byte[] gzipped = GZipUtil.gzip(s.getBytes()); final MultiValueMap responseHeaders = new MultiValueMap(); responseHeaders.put("Content-Encoding", "gzip"); final InMemoryCachedEntry p = new InMemoryCachedEntry(gzipped, "text/plain", "cha", 1, responseHeaders, System.currentTimeMillis(), "originalUrl", -1); assertEquals(gzipped, p.getGzippedContent()); assertEquals("hello", new String(p.getPlainContent())); }
/** * Checks whether the collection at the specified key contains the value. * * @param key the key to search for * @param value the value to search for * @return true if the map contains the value */ public boolean containsValue(final Object key, final Object value) { final Collection<V> coll = getCollection(key); if (coll == null) { return false; } return coll.contains(value); }
public void insert(String key, int nn, Object value) { this.map.put(key, nn); this.valuesMap.put(nn, new AttributeDescriptor(key, value)); //System.err.printf("Inserted: %s, %d, %s\n", key, nn, value); }
/** * Creates a map which decorates the given <code>map</code> and * maps keys to collections of type <code>collectionClass</code>. * * @param <K> the key type * @param <V> the value type * @param <C> the collection class type * @param map the map to wrap * @param collectionClass the type of the collection class * @return a new multi-value map * @since 4.0 */ public static <K, V, C extends Collection<V>> MultiValueMap<K, V> multiValueMap(final Map<K, ? super C> map, final Class<C> collectionClass) { return new MultiValueMap<>(map, new ReflectionFactory<>(collectionClass)); }
@Ignore @Test public void testIgnoreEncodingAndServeContentFlatWhenUserAgentIsIE6() throws Exception { final String dummyContent = "hello i'm a page that was cached"; final MultiValueMap headers = new MultiValueMap(); headers.put("Last-Modified", 2000l); headers.put("Dummy", "dummy"); headers.put("Dummy", "dummy2"); final InMemoryCachedEntry cachedPage = new InMemoryCachedEntry(dummyContent.getBytes(), "text/plain", "ASCII", 123, headers, System.currentTimeMillis(), originalURL, -1); when(cachePolicy.shouldCache(cache, aggregationState, flushPolicy)).thenReturn(new CachePolicyResult(CachePolicyResult.useCache, "/test-page", cachedPage)); when(request.getDateHeader("If-Modified-Since")).thenReturn(-1l); when(request.getHeader("User-Agent")).thenReturn("Mozilla/4.0 (MSIE 6.0; Windows NT 5.1)"); final ByteArrayOutputStream fakedOut = new ByteArrayOutputStream(); response.setStatus(123); when(response.containsHeader("Last-Modified")).thenReturn(false); response.addDateHeader("Last-Modified", 2000l); when(response.containsHeader("Dummy")).thenReturn(false); response.addHeader("Dummy", "dummy"); response.addHeader("Dummy", "dummy2"); response.setContentType("text/plain"); response.setCharacterEncoding("ASCII"); response.setContentLength(32); when(response.getOutputStream()).thenReturn(new SimpleServletOutputStream(fakedOut)); response.flushBuffer(); when(webContext.getResponse()).thenReturn(response); when(request.getHeaders("Accept-Encoding")).thenReturn(enumeration("foo", "gzip", "bar")); when(response.containsHeader("Content-Encoding")).thenReturn(true); executeNoCacheFilterAndVerify(); assertTrue(Arrays.equals(dummyContent.getBytes(), fakedOut.toByteArray())); }
/** * Adds a collection of values to the collection associated with * the specified key. * * @param key the key to store against * @param values the values to add to the collection at the key, null ignored * @return true if this map changed */ public boolean putAll(final K key, final Collection<V> values) { if (values == null || values.size() == 0) { return false; } boolean result = false; Collection<V> coll = getCollection(key); if (coll == null) { coll = createCollection(values.size()); // might produce a non-empty collection coll.addAll(values); if (coll.size() > 0) { // only add if non-zero size to maintain class state decorated().put(key, coll); result = true; // map definitely changed } } else { result = coll.addAll(values); } return result; }
/** * Gets the collection mapped to the specified key. * This method is a convenience method to typecast the result of <code>get(key)</code>. * * @param key the key used to retrieve the collection * @return the collection mapped to the key, null if no mapping */ public Collection getParameter(String key) { return parameters.getCollection(key); }
public StructuralIndex() { this.valuesMap = new TreeMap<>(); this.map = new MultiValueMap<>(); }
final String dummyContent = "hello i'm a page that was cached"; final MultiValueMap headers = new MultiValueMap(); headers.put("Last-Modified", 2000l); headers.put("Dummy", "dummy"); headers.put("Dummy", "dummy2");
public Collection<Integer> getList(String key) { if(key.isEmpty()){ Collection<Integer> c = new ArrayList<>(1); c.add(1); return c; } Collection<Integer> r = this.map.getCollection(key); return (r==null) ? Collections.EMPTY_LIST : r; }
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); headers = new MultiValueMap(); Iterator iter = serializableHeadersBackingList.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Entry) iter.next(); Collection c = (Collection) entry.getValue(); for (Iterator ic = c.iterator(); ic.hasNext();) { headers.put(entry.getKey(), ic.next()); } } serializableHeadersBackingList = null; }