Author: nbelaevski
Date: 2009-07-12 18:59:51 -0400 (Sun, 12 Jul 2009)
New Revision: 14905
Added:
framework/trunk/impl/src/test/java/org/ajax4jsf/cache/LRUMapCacheTest.java
Modified:
framework/trunk/api/
framework/trunk/impl/src/main/java/org/ajax4jsf/cache/CacheManager.java
framework/trunk/impl/src/main/java/org/ajax4jsf/cache/EhCacheCache.java
framework/trunk/impl/src/main/java/org/ajax4jsf/cache/JBossCacheCacheFactory.java
framework/trunk/impl/src/main/java/org/ajax4jsf/cache/LRUMapCache.java
framework/trunk/impl/src/main/java/org/richfaces/resource/CachedResourceImpl.java
framework/trunk/impl/src/main/java/org/richfaces/resource/ResourceHandlerImpl.java
framework/trunk/impl/src/main/java/org/richfaces/resource/ResourceImpl.java
framework/trunk/impl/src/main/java/org/richfaces/resource/TestResource2.java
Log:
Resources: further work on caching
Property changes on: framework/trunk/api
___________________________________________________________________
Name: svn:ignore
- .project
.checkstyle
target
.metadata
.settings
.classpath
+ .project
.checkstyle
target
.metadata
.settings
.classpath
.clover
Modified: framework/trunk/impl/src/main/java/org/ajax4jsf/cache/CacheManager.java
===================================================================
--- framework/trunk/impl/src/main/java/org/ajax4jsf/cache/CacheManager.java 2009-07-12
22:54:35 UTC (rev 14904)
+++ framework/trunk/impl/src/main/java/org/ajax4jsf/cache/CacheManager.java 2009-07-12
22:59:51 UTC (rev 14905)
@@ -34,6 +34,7 @@
/**
* CacheManager is used in J2SE environments for looking up named caches.
*/
+//TODO stop caches on application stop
public class CacheManager {
private static final Log log = LogFactory.getLog(CacheManager.class);
@@ -44,7 +45,7 @@
"org.ajax4jsf.cache.JBossCacheCacheFactory",
"org.ajax4jsf.cache.EhCacheCacheFactory"
};
- protected static CacheManager instance = new CacheManager();
+ protected static CacheManager instance = new CacheManager();
// REVIEW brian(a)quiotix.com
// Should this be a HashMap<String, WeakReference<Cache>>?
Modified: framework/trunk/impl/src/main/java/org/ajax4jsf/cache/EhCacheCache.java
===================================================================
--- framework/trunk/impl/src/main/java/org/ajax4jsf/cache/EhCacheCache.java 2009-07-12
22:54:35 UTC (rev 14904)
+++ framework/trunk/impl/src/main/java/org/ajax4jsf/cache/EhCacheCache.java 2009-07-12
22:59:51 UTC (rev 14905)
@@ -43,7 +43,7 @@
Integer ttl = null;
if (expired != 0) {
eternal = Boolean.FALSE;
- ttl = (int) (expired - System.currentTimeMillis());
+ ttl = (int) (expired - System.currentTimeMillis()) / 1000;
}
Element element = new Element(key, value, eternal, null, ttl);
Modified:
framework/trunk/impl/src/main/java/org/ajax4jsf/cache/JBossCacheCacheFactory.java
===================================================================
---
framework/trunk/impl/src/main/java/org/ajax4jsf/cache/JBossCacheCacheFactory.java 2009-07-12
22:54:35 UTC (rev 14904)
+++
framework/trunk/impl/src/main/java/org/ajax4jsf/cache/JBossCacheCacheFactory.java 2009-07-12
22:59:51 UTC (rev 14905)
@@ -3,8 +3,14 @@
*/
package org.ajax4jsf.cache;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
import java.util.Map;
+import javax.faces.FacesException;
+
+import org.ajax4jsf.resource.util.URLToStreamHelper;
import org.jboss.cache.Cache;
import org.jboss.cache.DefaultCacheFactory;
@@ -23,7 +29,33 @@
}
public org.ajax4jsf.cache.Cache createCache(Map<?, ?> env) {
- Cache<String, Object> cache =
cacheFactory.createCache("/jboss-cache.xml");
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ Cache<String, Object> cache = null;
+ URL cacheConfigurationURL = null;
+ if (contextClassLoader != null) {
+ cacheConfigurationURL = contextClassLoader.getResource("/jboss-cache.xml");
+ }
+
+ if (cacheConfigurationURL != null) {
+ InputStream stream = null;
+ try {
+ stream = URLToStreamHelper.urlToStream(cacheConfigurationURL);
+ cache = cacheFactory.createCache(stream);
+ } catch (IOException e) {
+ throw new FacesException(e.getLocalizedMessage(), e);
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ } else {
+ cache = cacheFactory.createCache();
+ }
return new JBossCacheCache(cache);
}
Modified: framework/trunk/impl/src/main/java/org/ajax4jsf/cache/LRUMapCache.java
===================================================================
--- framework/trunk/impl/src/main/java/org/ajax4jsf/cache/LRUMapCache.java 2009-07-12
22:54:35 UTC (rev 14904)
+++ framework/trunk/impl/src/main/java/org/ajax4jsf/cache/LRUMapCache.java 2009-07-12
22:59:51 UTC (rev 14905)
@@ -32,7 +32,7 @@
*/
public class LRUMapCache implements Cache {
- private static final class CacheMap extends LRUMap<Object, CacheEntry> {
+ protected static final class CacheMap extends LRUMap<Object, CacheEntry> {
/**
*
*/
@@ -46,11 +46,12 @@
super(capacity);
}
- private PriorityQueue<CacheEntry> expirationQueue = new
PriorityQueue<CacheEntry>();
+ protected PriorityQueue<CacheEntry> expirationQueue = new
PriorityQueue<CacheEntry>();
public CacheEntry put(Object key, CacheEntry value) {
CacheEntry entry = super.put(key, value);
if (entry != null) {
+ //prolong
expirationQueue.remove(entry);
expirationQueue.add(value);
} else {
@@ -77,14 +78,16 @@
public void purge() {
CacheEntry queueEntry = null;
- while ((queueEntry = expirationQueue.peek()) != null &&
queueEntry.isExpired()) {
+ while ((queueEntry = expirationQueue.peek()) != null &&
+ queueEntry.isExpired()) {
+
super.remove(queueEntry.getKey());
expirationQueue.remove();
}
}
}
- private static final class CacheEntry implements Comparable<CacheEntry> {
+ protected static final class CacheEntry implements Comparable<CacheEntry> {
private Object key;
@@ -153,7 +156,7 @@
@Override
public String toString() {
- if (expired != 0) {
+ if (expired == 0) {
return key.toString();
} else {
return key + ": " + new Date(expired);
Modified:
framework/trunk/impl/src/main/java/org/richfaces/resource/CachedResourceImpl.java
===================================================================
---
framework/trunk/impl/src/main/java/org/richfaces/resource/CachedResourceImpl.java 2009-07-12
22:54:35 UTC (rev 14904)
+++
framework/trunk/impl/src/main/java/org/richfaces/resource/CachedResourceImpl.java 2009-07-12
22:59:51 UTC (rev 14905)
@@ -54,6 +54,8 @@
private Date lastModified;
+ //serves only to define server cache entry expiration time only
+ //browser cache expiration is controlled by stored HTTP headers value
private long expired = 0;
private void initializeFromHeaders() {
Modified:
framework/trunk/impl/src/main/java/org/richfaces/resource/ResourceHandlerImpl.java
===================================================================
---
framework/trunk/impl/src/main/java/org/richfaces/resource/ResourceHandlerImpl.java 2009-07-12
22:54:35 UTC (rev 14904)
+++
framework/trunk/impl/src/main/java/org/richfaces/resource/ResourceHandlerImpl.java 2009-07-12
22:59:51 UTC (rev 14905)
@@ -68,6 +68,8 @@
CacheFactory cacheFactory = cacheManager.getCacheFactory(envMap);
this.cache = cacheFactory.createCache(envMap);
+ //TODO - who is responsible for caches starting/stopping?
+ this.cache.start();
}
private static final String RESOURCE_CODEC_ATTRIBUTE_NAME =
Modified: framework/trunk/impl/src/main/java/org/richfaces/resource/ResourceImpl.java
===================================================================
--- framework/trunk/impl/src/main/java/org/richfaces/resource/ResourceImpl.java 2009-07-12
22:54:35 UTC (rev 14904)
+++ framework/trunk/impl/src/main/java/org/richfaces/resource/ResourceImpl.java 2009-07-12
22:59:51 UTC (rev 14905)
@@ -68,7 +68,7 @@
}
/**
- * @param resourceContext current {@link ResourceContext}
+ * <b>IMPORTANT:</b> this method returned TTL in RF 3.x, now it returns
expiration time
* @return Returns the expired.
*/
protected long getExpired(FacesContext context) {
@@ -201,9 +201,10 @@
boolean cacheable = isCacheable(facesContext);
if (cacheable) {
+ long currentTime = System.currentTimeMillis();
long expires = getExpired(facesContext);
if (expires <= 0) {
- expires = InternetResource.DEFAULT_EXPIRE;
+ expires = currentTime + InternetResource.DEFAULT_EXPIRE;
}
String entityTag = getEntityTag(facesContext);
@@ -211,8 +212,8 @@
headers.put("ETag", "W/\"" + entityTag +
"\"");
}
- headers.put("Expires", Util.formatHttpDate(expires +
System.currentTimeMillis()));
- headers.put("Cache-Control", "max-age=" + expires / 1000L);
+ headers.put("Expires", Util.formatHttpDate(expires));
+ headers.put("Cache-Control", "max-age=" + (expires - currentTime)
/ 1000L);
} else {
headers.put("Expires", "0");
headers.put("Cache-Control", "max-age=0, no-store, no-cache");
Modified: framework/trunk/impl/src/main/java/org/richfaces/resource/TestResource2.java
===================================================================
---
framework/trunk/impl/src/main/java/org/richfaces/resource/TestResource2.java 2009-07-12
22:54:35 UTC (rev 14904)
+++
framework/trunk/impl/src/main/java/org/richfaces/resource/TestResource2.java 2009-07-12
22:59:51 UTC (rev 14905)
@@ -113,7 +113,7 @@
@Override
protected long getExpired(FacesContext context) {
- return 10000;
+ return System.currentTimeMillis() + 10000;
}
@Override
Added: framework/trunk/impl/src/test/java/org/ajax4jsf/cache/LRUMapCacheTest.java
===================================================================
--- framework/trunk/impl/src/test/java/org/ajax4jsf/cache/LRUMapCacheTest.java
(rev 0)
+++ framework/trunk/impl/src/test/java/org/ajax4jsf/cache/LRUMapCacheTest.java 2009-07-12
22:59:51 UTC (rev 14905)
@@ -0,0 +1,195 @@
+
+package org.ajax4jsf.cache;
+
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.ajax4jsf.cache.LRUMapCache.CacheMap;
+import org.junit.Assert;
+import org.junit.Test;
+
+
+/**
+ * @author Nick Belaevski
+ * @since 4.0
+ */
+public class LRUMapCacheTest {
+
+ @Test
+ public void testname() throws Exception {
+
+ }
+
+ @Test
+ public void testBasic() throws Exception {
+ LRUMapCache cache = new LRUMapCache();
+ cache.start();
+
+ Assert.assertNull(cache.get("key"));
+ cache.put("key", "value", 0);
+ Assert.assertEquals("value", cache.get("key"));
+
+ cache.stop();
+ }
+
+ @Test
+ public void testLRUEviction() throws Exception {
+ LRUMapCache cache = new LRUMapCache(3);
+ cache.start();
+
+ cache.put("key1", "value1", 0);
+ cache.put("key2", "value2", 0);
+ cache.put("key3", "value3", 0);
+
+ Assert.assertEquals("value1", cache.get("key1"));
+ Assert.assertEquals("value2", cache.get("key2"));
+ Assert.assertEquals("value3", cache.get("key3"));
+
+ cache.get("key1");
+ cache.get("key3");
+
+ cache.put("key4", "value4", 0);
+
+ Assert.assertEquals("value1", cache.get("key1"));
+ Assert.assertNull(cache.get("key2"));
+ Assert.assertEquals("value3", cache.get("key3"));
+ Assert.assertEquals("value4", cache.get("key4"));
+
+ cache.stop();
+ }
+
+ @Test
+ public void testCacheMap() throws Exception {
+ CacheMap cacheMap = new LRUMapCache.CacheMap();
+ Assert.assertTrue(cacheMap.expirationQueue.isEmpty());
+
+ LRUMapCache.CacheEntry cacheEntry = new LRUMapCache.CacheEntry("key",
"value", System.currentTimeMillis() + 1000);
+ cacheMap.put("key", cacheEntry);
+
+ Assert.assertNotNull(cacheMap.get("key"));
+ Assert.assertSame(cacheEntry, cacheMap.get("key"));
+ Assert.assertFalse(cacheMap.expirationQueue.isEmpty());
+
+ cacheMap.clear();
+ Assert.assertTrue(cacheMap.expirationQueue.isEmpty());
+
+ cacheMap.put("key2", new LRUMapCache.CacheEntry("key2",
"value2", System.currentTimeMillis() + 1000));
+ Assert.assertNotNull(cacheMap.get("key2"));
+ cacheMap.remove("key2");
+ Assert.assertTrue(cacheMap.expirationQueue.isEmpty());
+ }
+
+ @Test
+ public void testExpiration() throws Exception {
+ //this test uses Thread.sleep, so may fail if debugged
+
+ LRUMapCache cache = new LRUMapCache();
+ cache.start();
+
+ cache.put("key", "value", System.currentTimeMillis() + 1000);
+ cache.put("key2", "value2", System.currentTimeMillis() + 1400);
+ cache.put("key3", "value3", System.currentTimeMillis() + 600);
+ cache.put("key4", "value4", System.currentTimeMillis() + 600);
+
+ Assert.assertNotNull(cache.get("key"));
+ Assert.assertNotNull(cache.get("key2"));
+ Assert.assertNotNull(cache.get("key3"));
+ Assert.assertNotNull(cache.get("key4"));
+
+ //prolong key4
+ cache.put("key4", "new value", System.currentTimeMillis() + 1000);
+
+ Thread.sleep(800);
+
+ Assert.assertNotNull(cache.get("key"));
+ Assert.assertNotNull(cache.get("key2"));
+ Assert.assertNull(cache.get("key3"));
+ Assert.assertNotNull(cache.get("key4"));
+
+ Thread.sleep(400);
+
+ Assert.assertNull(cache.get("key"));
+ Assert.assertNotNull(cache.get("key2"));
+ Assert.assertNull(cache.get("key3"));
+ Assert.assertNull(cache.get("key4"));
+
+ Thread.sleep(400);
+
+ Assert.assertNull(cache.get("key"));
+ Assert.assertNull(cache.get("key2"));
+ Assert.assertNull(cache.get("key3"));
+
+ cache.stop();
+ }
+
+ @Test
+ public void testThreads() throws Exception {
+ final AtomicBoolean failure = new AtomicBoolean();
+
+ final LRUMapCache cache = new LRUMapCache();
+ cache.start();
+
+ Thread[] writerThreads = new Thread[10];
+
+ for (int i = 0; i < writerThreads.length; i++) {
+ writerThreads[i] = new Thread() {
+ public void run() {
+ final String key = UUID.randomUUID().toString();
+ final String value = UUID.randomUUID().toString();
+
+ cache.put(key, value, 0);
+
+ Thread[] threads = new Thread[25];
+ for (int j = 0; j < threads.length; j++) {
+ threads[j] = new Thread() {
+ @Override
+ public void run() {
+ int retries = 1000;
+
+ for (int k = 0; k < retries; k++) {
+ if (!value.equals(cache.get(key))) {
+ failure.set(true);
+ return ;
+ }
+ }
+ }
+ };
+ }
+
+ for (Thread thread : threads) {
+ thread.start();
+ }
+ int retries = 1000;
+
+ for (int k = 0; k < retries; k++) {
+ if (!value.equals(cache.get(key))) {
+ failure.set(true);
+ }
+ }
+
+ for (Thread thread : threads) {
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ failure.set(true);
+ e.printStackTrace();
+ }
+ }
+ };
+ };
+ }
+
+ for (Thread thread : writerThreads) {
+ thread.start();
+ }
+
+ for (Thread thread : writerThreads) {
+ thread.join();
+ }
+
+ Assert.assertFalse(failure.get());
+
+ cache.stop();
+ }
+}