Author: mgrigorov
Date: Tue Dec 14 13:26:27 2010
New Revision: 1049077
URL: http://svn.apache.org/viewvc?rev=1049077&view=rev
Log:
WICKET-3209 WebApplication MostRecentlyUsedMap based upon Key age not Value age
Introduce a map with maximum capacity and lifetime for its entries.
This map is used to store the responses when redirect to buffer strategy is
used.
Added:
wicket/trunk/wicket-util/src/test/java/org/apache/wicket/util/collections/
wicket/trunk/wicket-util/src/test/java/org/apache/wicket/util/collections/MostRecentlyUsedMapTest.java
(with props)
wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/http/StoredResponsesMap.java
(with props)
wicket/trunk/wicket/src/test/java/org/apache/wicket/protocol/http/StoredResponsesMapTest.java
(with props)
Modified:
wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/collections/MostRecentlyUsedMap.java
wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
Modified:
wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/collections/MostRecentlyUsedMap.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/collections/MostRecentlyUsedMap.java?rev=1049077&r1=1049076&r2=1049077&view=diff
==============================================================================
---
wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/collections/MostRecentlyUsedMap.java
(original)
+++
wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/collections/MostRecentlyUsedMap.java
Tue Dec 14 13:26:27 2010
@@ -34,7 +34,7 @@ public class MostRecentlyUsedMap<K, V> e
private static final long serialVersionUID = 1L;
/** Value most recently removed from map */
- V removedValue;
+ protected V removedValue;
/** Maximum number of entries allowed in this map */
private final int maxEntries;
Added:
wicket/trunk/wicket-util/src/test/java/org/apache/wicket/util/collections/MostRecentlyUsedMapTest.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/test/java/org/apache/wicket/util/collections/MostRecentlyUsedMapTest.java?rev=1049077&view=auto
==============================================================================
---
wicket/trunk/wicket-util/src/test/java/org/apache/wicket/util/collections/MostRecentlyUsedMapTest.java
(added)
+++
wicket/trunk/wicket-util/src/test/java/org/apache/wicket/util/collections/MostRecentlyUsedMapTest.java
Tue Dec 14 13:26:27 2010
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.util.collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+/**
+ *
+ */
+public class MostRecentlyUsedMapTest
+{
+ /**
+ * Tests that {...@link MostRecentlyUsedMap} contains at most 2 entries
+ *
+ * @see <a
href="https://issues.apache.org/jira/browse/WICKET-3209">WICKET-3209</a>
+ */
+ @Test
+ public void max2Entries()
+ {
+ MostRecentlyUsedMap<String, String> map = new
MostRecentlyUsedMap<String, String>(2);
+ assertEquals(0, map.size());
+ map.put("1", "one");
+ assertEquals(1, map.size());
+ map.put("2", "two");
+ assertEquals(2, map.size());
+ map.put("3", "three");
+ assertEquals(2, map.size());
+ assertTrue(map.containsKey("2"));
+ assertTrue(map.containsKey("3"));
+ }
+}
Propchange:
wicket/trunk/wicket-util/src/test/java/org/apache/wicket/util/collections/MostRecentlyUsedMapTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/http/StoredResponsesMap.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/http/StoredResponsesMap.java?rev=1049077&view=auto
==============================================================================
---
wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/http/StoredResponsesMap.java
(added)
+++
wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/http/StoredResponsesMap.java
Tue Dec 14 13:26:27 2010
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.protocol.http;
+
+import java.util.Map;
+
+import org.apache.wicket.util.collections.MostRecentlyUsedMap;
+import org.apache.wicket.util.time.Duration;
+import org.apache.wicket.util.time.Time;
+
+/**
+ * A map that contains the buffered responses. It has a constraint on the
maximum entries that it
+ * can contain, and a constraint on the duration of time an entry is
considered valid/non-expired
+ */
+class StoredResponsesMap extends MostRecentlyUsedMap<String, Object>
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The actual object that is stored as a value of the map. It wraps the
buffered response and
+ * assigns it a creation time.
+ */
+ private static class Value
+ {
+ /** the original response to store */
+ private BufferedWebResponse response;
+
+ /** the time when this response is stored */
+ private Time creationTime;
+ }
+
+ /**
+ * The duration of time before a {...@link Value} is considered as
expired
+ */
+ private final Duration lifetime;
+
+ /**
+ * Construct.
+ *
+ * @param maxEntries
+ * how much entries this map can contain
+ * @param lifetime
+ * the duration of time to keep an entry in the map before
considering it expired
+ */
+ public StoredResponsesMap(int maxEntries, Duration lifetime)
+ {
+ super(maxEntries);
+
+ this.lifetime = lifetime;
+ }
+
+ @Override
+ protected boolean removeEldestEntry(java.util.Map.Entry<String, Object>
eldest)
+ {
+ boolean removed = super.removeEldestEntry(eldest);
+ if (removed == false)
+ {
+ Value value = (Value)eldest.getValue();
+ Duration elapsedTime =
Time.now().subtract(value.creationTime);
+ if (lifetime.lessThanOrEqual(elapsedTime))
+ {
+ removedValue = value.response;
+ removed = true;
+ }
+ }
+ return removed;
+ }
+
+ @Override
+ public BufferedWebResponse put(String key, Object bufferedResponse)
+ {
+ if (!(bufferedResponse instanceof BufferedWebResponse))
+ {
+ throw new
IllegalArgumentException(StoredResponsesMap.class.getSimpleName() +
+ " can store only instances of " +
BufferedWebResponse.class.getSimpleName());
+ }
+
+ Value value = new Value();
+ value.creationTime = Time.now();
+ value.response = (BufferedWebResponse)bufferedResponse;
+ Value oldValue = (Value)super.put(key, value);
+
+ return oldValue != null ? oldValue.response : null;
+ }
+
+ @Override
+ public BufferedWebResponse get(Object key)
+ {
+ BufferedWebResponse result = null;
+ Value value = (Value)super.get(key);
+ if (value != null)
+ {
+ Duration elapsedTime =
Time.now().subtract(value.creationTime);
+ if (lifetime.greaterThan(elapsedTime))
+ {
+ result = value.response;
+ }
+ else
+ {
+ // expired, remove it
+ remove(key);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public BufferedWebResponse remove(Object key)
+ {
+ Value removedValue = (Value)super.remove(key);
+ return removedValue != null ? removedValue.response : null;
+ }
+
+ @Override
+ public void putAll(Map<? extends String, ? extends Object> m)
+ {
+ throw new UnsupportedOperationException();
+ }
+}
Propchange:
wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/http/StoredResponsesMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/http/WebApplication.java?rev=1049077&r1=1049076&r2=1049077&view=diff
==============================================================================
---
wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
(original)
+++
wicket/trunk/wicket/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
Tue Dec 14 13:26:27 2010
@@ -16,10 +16,6 @@
*/
package org.apache.wicket.protocol.http;
-import java.util.Collections;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -54,13 +50,12 @@ import org.apache.wicket.request.resourc
import org.apache.wicket.session.HttpSessionStore;
import org.apache.wicket.session.ISessionStore;
import org.apache.wicket.util.IProvider;
-import org.apache.wicket.util.collections.MostRecentlyUsedMap;
import org.apache.wicket.util.file.FileUploadCleaner;
import org.apache.wicket.util.file.IFileUploadCleaner;
import org.apache.wicket.util.file.IResourceFinder;
import org.apache.wicket.util.file.WebApplicationPath;
import org.apache.wicket.util.lang.Args;
-import org.apache.wicket.util.lang.Generics;
+import org.apache.wicket.util.time.Duration;
import org.apache.wicket.util.watch.IModificationWatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -133,12 +128,6 @@ public abstract class WebApplication ext
}
/**
- * Map of buffered responses that are in progress per session. Buffered
responses are
- * temporarily stored
- */
- private final ConcurrentHashMap<String, Map<String,
BufferedHttpServletResponse>> bufferedResponses =
Generics.newConcurrentHashMap();
-
- /**
* the prefix for storing variables in the actual session (typically
{...@link HttpSession} for
* this application instance.
*/
@@ -391,8 +380,6 @@ public abstract class WebApplication ext
{
super.sessionUnbound(sessionId);
- bufferedResponses.remove(sessionId);
-
IRequestLogger logger = getRequestLogger();
if (logger != null)
{
@@ -438,7 +425,6 @@ public abstract class WebApplication ext
{
resourceWatcher.destroy();
}
- bufferedResponses.clear();
IFileUploadCleaner fileUploadCleaner =
getResourceSettings().getFileUploadCleaner();
if (fileUploadCleaner != null)
@@ -577,35 +563,6 @@ public abstract class WebApplication ext
}
/**
- * Add a buffered response to the redirect buffer.
- *
- * @param sessionId
- * the session id
- * @param bufferId
- * the id that should be used for storing the buffer
- * @param renderedResponse
- * the response to buffer
- */
- final void addBufferedResponse(String sessionId, String bufferId,
- BufferedHttpServletResponse renderedResponse)
- {
- Map<String, BufferedHttpServletResponse> responsesPerSession =
bufferedResponses.get(sessionId);
- if (responsesPerSession == null)
- {
- responsesPerSession = Collections.synchronizedMap(new
MostRecentlyUsedMap<String, BufferedHttpServletResponse>(
- 4));
- Map<String, BufferedHttpServletResponse> previousValue
= bufferedResponses.putIfAbsent(
- sessionId, responsesPerSession);
- if (previousValue != null)
- {
- responsesPerSession = previousValue;
- }
- }
- String bufferKey = bufferId.startsWith("/") ?
bufferId.substring(1) : bufferId;
- responsesPerSession.put(bufferKey, renderedResponse);
- }
-
- /**
* Log that this application is started.
*/
final void logStarted()
@@ -646,8 +603,12 @@ public abstract class WebApplication ext
+
"********************************************************************\n");
}
- // TODO: Do this properly
- private final Map<String, BufferedWebResponse> storedResponses = new
ConcurrentHashMap<String, BufferedWebResponse>();
+ /*
+ * Can contain at most 1000 responses and each entry can live at most
one minute for now there
+ * is no need to configure these parameters externally
+ */
+ private final StoredResponsesMap storedResponses = new
StoredResponsesMap(1000,
+ Duration.seconds(60));
/**
*
@@ -685,35 +646,6 @@ public abstract class WebApplication ext
storedResponses.put(key, response);
}
- // TODO remove after deprecation release
-
- /**
- * Returns the redirect map where the buffered render pages are stored
in and removes it
- * immediately.
- *
- * @param sessionId
- * the session id
- *
- * @param bufferId
- * the id of the buffer as passed in as a request parameter
- * @return the buffered response or null if not found (when this
request is on a different box
- * than the original request came in
- */
- final BufferedHttpServletResponse popBufferedResponse(String sessionId,
String bufferId)
- {
- Map<String, BufferedHttpServletResponse> responsesPerSession =
bufferedResponses.get(sessionId);
- if (responsesPerSession != null)
- {
- BufferedHttpServletResponse buffered =
responsesPerSession.remove(bufferId);
- if (responsesPerSession.size() == 0)
- {
- bufferedResponses.remove(sessionId);
- }
- return buffered;
- }
- return null;
- }
-
@Override
public String getMimeType(String fileName)
{
Added:
wicket/trunk/wicket/src/test/java/org/apache/wicket/protocol/http/StoredResponsesMapTest.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/test/java/org/apache/wicket/protocol/http/StoredResponsesMapTest.java?rev=1049077&view=auto
==============================================================================
---
wicket/trunk/wicket/src/test/java/org/apache/wicket/protocol/http/StoredResponsesMapTest.java
(added)
+++
wicket/trunk/wicket/src/test/java/org/apache/wicket/protocol/http/StoredResponsesMapTest.java
Tue Dec 14 13:26:27 2010
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.protocol.http;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.wicket.util.time.Duration;
+import org.junit.Test;
+
+/**
+ * @see <a
href="https://issues.apache.org/jira/browse/WICKET-3209">WICKET-3209</a>
+ */
+public class StoredResponsesMapTest
+{
+ /**
+ * Verifies that {...@link StoredResponsesMap} will expire the oldest
entry if it is older than 2
+ * seconds
+ *
+ * @throws Exception
+ */
+ @Test
+ public void entriesLife2Seconds() throws Exception
+ {
+ StoredResponsesMap map = new StoredResponsesMap(1000,
Duration.seconds(2));
+ assertEquals(0, map.size());
+ map.put("1", new BufferedWebResponse(null));
+ assertEquals(1, map.size());
+ TimeUnit.SECONDS.sleep(3);
+ map.put("2", new BufferedWebResponse(null));
+ assertEquals(1, map.size());
+ assertTrue(map.containsKey("2"));
+ }
+
+ /**
+ * Verifies that getting a value which is expired will return
<code>null</code>.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getExpiredValue() throws Exception
+ {
+ StoredResponsesMap map = new StoredResponsesMap(1000,
Duration.milliseconds(50));
+ assertEquals(0, map.size());
+ map.put("1", new BufferedWebResponse(null));
+ assertEquals(1, map.size());
+ TimeUnit.MILLISECONDS.sleep(51);
+ Object value = map.get("1");
+ assertNull(value);
+ }
+
+ /**
+ * Verifies that {...@link StoredResponsesMap} can have only {...@link
BufferedWebResponse} values
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void cannotPutArbitraryValue()
+ {
+ StoredResponsesMap map = new StoredResponsesMap(1000,
Duration.days(1));
+ map.put("1", new Object());
+ }
+}
Propchange:
wicket/trunk/wicket/src/test/java/org/apache/wicket/protocol/http/StoredResponsesMapTest.java
------------------------------------------------------------------------------
svn:eol-style = native