[exo-jcr-commits] exo-jcr SVN: r4604 - kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache and 2 other directories.
do-not-reply at jboss.org
do-not-reply at jboss.org
Wed Jul 6 05:34:02 EDT 2011
Author: nfilotto
Date: 2011-07-06 05:34:01 -0400 (Wed, 06 Jul 2011)
New Revision: 4604
Added:
kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/invalidation/
kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/invalidation/InvalidationExoCache.java
Removed:
kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/InvalidationExoCache.java
Modified:
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/cache.xml
kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/CacheServiceImpl.java
Log:
EXOJCR-1418: Moved InvalidationExoCache in a dedicated package, auto wrap the eXo cache instance into an InvalidationExoCache only if the cache is replicated or distributed and set a better default concurrency level.
Modified: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/cache.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/cache.xml 2011-07-05 15:21:53 UTC (rev 4603)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/cache.xml 2011-07-06 09:34:01 UTC (rev 4604)
@@ -209,12 +209,13 @@
parameter <emphasis>avoidValueReplication</emphasis> to
<emphasis>true</emphasis> in your eXo cache configuration, this will
indicate the CacheService to wrap your eXo cache instance into an
- <emphasis>InvalidationExoCache</emphasis>.</para>
+ <emphasis>InvalidationExoCache</emphasis> in case the cache is
+ defined as replicated or distributed.</para>
</listitem>
<listitem>
<para>Programmatically; You can wrap your eXo cache instance into an
- <emphasis>org.exoplatform.services.cache.impl.InvalidationExoCache</emphasis>
+ <emphasis>org.exoplatform.services.cache.invalidation.InvalidationExoCache</emphasis>
yourself using the public constructors that are available. Please
note that if you use <emphasis>CacheListeners</emphasis> add them to
the InvalidationExoCache instance instead of the nested eXo Cache
@@ -227,7 +228,7 @@
<note>
<para>The invalidation will be efficient if and only if the hash code
method is properly implemented, in other words 2 value objects
- representing the same data will return the same hash code otherwise
+ representing the same data need to return the same hash code otherwise
the infinite loop described above will still be effective.</para>
</note>
</section>
Modified: kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/CacheServiceImpl.java
===================================================================
--- kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/CacheServiceImpl.java 2011-07-05 15:21:53 UTC (rev 4603)
+++ kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/CacheServiceImpl.java 2011-07-06 09:34:01 UTC (rev 4604)
@@ -28,6 +28,7 @@
import org.exoplatform.services.cache.ExoCacheFactory;
import org.exoplatform.services.cache.ExoCacheInitException;
import org.exoplatform.services.cache.SimpleExoCache;
+import org.exoplatform.services.cache.invalidation.InvalidationExoCache;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
@@ -199,9 +200,11 @@
{
managed.registerCache(simple);
}
- // If the flag avoid value replication is enabled we wrap the eXo cache instance
- // into an InvalidationExoCache to enable the invalidation
- return safeConfig.avoidValueReplication() ? new InvalidationExoCache(simple) : simple;
+ // If the flag avoid value replication is enabled and the cache is replicated
+ // or distributed we wrap the eXo cache instance into an InvalidationExoCache
+ // to enable the invalidation
+ return safeConfig.avoidValueReplication() && (safeConfig.isRepicated() || safeConfig.isDistributed())
+ ? new InvalidationExoCache(simple) : simple;
}
public Collection<ExoCache<? extends Serializable, ?>> getAllCacheInstances()
Deleted: kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/InvalidationExoCache.java
===================================================================
--- kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/InvalidationExoCache.java 2011-07-05 15:21:53 UTC (rev 4603)
+++ kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/InvalidationExoCache.java 2011-07-06 09:34:01 UTC (rev 4604)
@@ -1,561 +0,0 @@
-/*
- * Copyright (C) 2011 eXo Platform SAS.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.exoplatform.services.cache.impl;
-
-import org.exoplatform.services.cache.CacheListener;
-import org.exoplatform.services.cache.CacheListenerContext;
-import org.exoplatform.services.cache.CachedObjectSelector;
-import org.exoplatform.services.cache.ExoCache;
-import org.exoplatform.services.cache.ObjectCacheInfo;
-import org.exoplatform.services.log.ExoLogger;
-import org.exoplatform.services.log.Log;
-
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * This eXo cache type is a decorator allowing ExoCache instances that have
- * big values or non serializable values to be replicated thanks to an invalidation
- * mechanism. To prevent infinite loop described below, we replicate the hash code of
- * the value such that if the hash code is the same, we don't invalidate the value locally
- * <ul>
- * <li>Cluster node #1 puts (key1, value1) into the cache</li>
- * <li>On cluster node #2 key1 is invalidated by the put call in node #1</li>
- * <li>Node #2 re-loads key1 and puts (key1, value1) into the cache</li>
- * <li>On cluster node #1 key1 is invalidated, so we get back to step #1</li>
- * </ul>
- *
- * @author <a href="mailto:nfilotto at exoplatform.com">Nicolas Filotto</a>
- * @version $Id$
- *
- */
-public class InvalidationExoCache<K extends Serializable, V> implements ExoCache<K, V>,
- CacheListener<K, InvalidationExoCache.HashCode<V>>
-{
- /**
- * Logger.
- */
- private static final Log LOG = ExoLogger.getLogger("exo.kernel.component.cache.InvalidationExoCache");
-
- /**
- * The eXo cache instance that we would like to replicate using the invalidation
- * mechanism
- */
- private final ExoCache<K, HashCode<V>> delegate;
-
- /**
- * The listeners of the cache
- */
- private final CopyOnWriteArrayList<CacheListener<? super K, ? super V>> listeners;
-
- /**
- * The local cache that contains the real values
- */
- private final ConcurrentMap<K, V> localCache;
-
- /**
- * @param delegate the underneath eXo cache instance, we assume that the eXo cache
- * implementation behind is fully functional.
- */
- public InvalidationExoCache(ExoCache<K, V> delegate)
- {
- this(delegate, 16);
- }
-
- /**
- * @param delegate the underneath eXo cache instance, we assume that the eXo cache
- * implementation behind is fully functional.
- * @concurrencyLevel the estimated number of concurrently
- * updating threads. The implementation performs internal sizing
- * to try to accommodate this many threads.
- */
- @SuppressWarnings("unchecked")
- public InvalidationExoCache(ExoCache<K, V> delegate, int concurrencyLevel)
- {
- this.delegate = (ExoCache<K, HashCode<V>>)delegate;
- // We listen to the cache in order to get a callbacks in case of internal puts for example
- this.delegate.addCacheListener(this);
- this.listeners = new CopyOnWriteArrayList<CacheListener<? super K, ? super V>>();
- this.localCache = new ConcurrentHashMap<K, V>(concurrencyLevel, 0.75f, concurrencyLevel);
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#getName()
- */
- public String getName()
- {
- return delegate.getName();
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#setName(java.lang.String)
- */
- public void setName(String name)
- {
- delegate.setName(name);
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#getLabel()
- */
- public String getLabel()
- {
- return delegate.getLabel();
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#setLabel(java.lang.String)
- */
- public void setLabel(String s)
- {
- delegate.setLabel(s);
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#get(java.io.Serializable)
- */
- public V get(Serializable name)
- {
- HashCode<V> result = delegate.get(name);
- return result == null ? null : localCache.get(name);
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#remove(java.io.Serializable)
- */
- public V remove(Serializable key) throws NullPointerException
- {
- V value = localCache.get(key);
- delegate.remove(key);
- return value;
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#put(java.io.Serializable, java.lang.Object)
- */
- public void put(K key, V value) throws NullPointerException
- {
- delegate.put(key, new HashCode<V>(value));
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#putMap(java.util.Map)
- */
- public void putMap(Map<? extends K, ? extends V> objs) throws NullPointerException, IllegalArgumentException
- {
- if (objs == null)
- {
- throw new NullPointerException("No null map accepted");
- }
- Map<K, HashCode<V>> map = new LinkedHashMap<K, HashCode<V>>();
- for (Entry<? extends K, ? extends V> entry : objs.entrySet())
- {
- if (entry.getKey() == null)
- {
- throw new IllegalArgumentException("No null cache key accepted");
- }
- else if (entry.getValue() == null)
- {
- throw new IllegalArgumentException("No null cache value accepted");
- }
- map.put(entry.getKey(), new HashCode<V>(entry.getValue()));
- }
- delegate.putMap(map);
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#clearCache()
- */
- public void clearCache()
- {
- delegate.clearCache();
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#select(org.exoplatform.services.cache.CachedObjectSelector)
- */
- public void select(CachedObjectSelector<? super K, ? super V> selector) throws Exception
- {
- if (selector == null)
- {
- throw new IllegalArgumentException("No null selector");
- }
- for (Entry<K, V> entry : localCache.entrySet())
- {
- final K key = entry.getKey();
- final V value = entry.getValue();
- ObjectCacheInfo<V> info = new ObjectCacheInfo<V>()
- {
- public V get()
- {
- return value;
- }
-
- public long getExpireTime()
- {
- // Cannot know: The expire time is managed by JBoss Cache itself
- return -1;
- }
- };
- if (selector.select(key, info))
- {
- selector.onSelect(this, key, info);
- }
- }
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#getCacheSize()
- */
- public int getCacheSize()
- {
- return localCache.size();
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#getMaxSize()
- */
- public int getMaxSize()
- {
- return delegate.getMaxSize();
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#setMaxSize(int)
- */
- public void setMaxSize(int max)
- {
- delegate.setMaxSize(max);
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#getLiveTime()
- */
- public long getLiveTime()
- {
- return delegate.getLiveTime();
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#setLiveTime(long)
- */
- public void setLiveTime(long period)
- {
- delegate.setLiveTime(period);
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#getCacheHit()
- */
- public int getCacheHit()
- {
- return delegate.getCacheHit();
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#getCacheMiss()
- */
- public int getCacheMiss()
- {
- return delegate.getCacheMiss();
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#getCachedObjects()
- */
- public List<? extends V> getCachedObjects()
- {
- return new ArrayList<V>(localCache.values());
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#removeCachedObjects()
- */
- public List<? extends V> removeCachedObjects()
- {
- final List<? extends V> list = getCachedObjects();
- clearCache();
- return list;
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#addCacheListener(org.exoplatform.services.cache.CacheListener)
- */
- public void addCacheListener(CacheListener<? super K, ? super V> listener) throws NullPointerException
- {
- if (listener == null)
- {
- throw new NullPointerException();
- }
- listeners.add(listener);
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#isLogEnabled()
- */
- public boolean isLogEnabled()
- {
- return delegate.isLogEnabled();
- }
-
- /**
- * @see org.exoplatform.services.cache.ExoCache#setLogEnabled(boolean)
- */
- public void setLogEnabled(boolean b)
- {
- delegate.setLogEnabled(b);
- }
-
- /**
- * {@inheritDoc}
- */
- public void onExpire(CacheListenerContext context, K key, HashCode<V> obj) throws Exception
- {
- V value = localCache.remove(key);
- if (listeners.isEmpty())
- {
- return;
- }
- for (CacheListener<? super K, ? super V> listener : listeners)
- {
- try
- {
- listener.onExpire(context, key, value);
- }
- catch (Exception e)
- {
- if (LOG.isWarnEnabled())
- LOG.warn("Cannot execute the CacheListener properly", e);
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public void onRemove(CacheListenerContext context, K key, HashCode<V> obj) throws Exception
- {
- V value = localCache.remove(key);
- if (listeners.isEmpty())
- {
- return;
- }
- for (CacheListener<? super K, ? super V> listener : listeners)
- {
- try
- {
- listener.onRemove(context, key, value);
- }
- catch (Exception e)
- {
- if (LOG.isWarnEnabled())
- LOG.warn("Cannot execute the CacheListener properly", e);
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public void onPut(CacheListenerContext context, K key, HashCode<V> obj) throws Exception
- {
- V value = obj.getValue();
- if (value != null)
- {
- // we assume that it is a local put since the value is inside the HashCode object
- localCache.put(key, value);
- }
- else
- {
- // we assume that it is a remote put since the value is not inside the HashCode object
- V currentValue = localCache.get(key);
- if (currentValue != null && obj != null && currentValue.hashCode() == obj.hashCode())
- {
- // We assume that it is the same value so we don't change the value in the cache
- value = currentValue;
- }
- else
- {
- // A new value has been added to the cache so we invalidate the local one
- value = null;
- localCache.remove(key);
- }
- }
- if (listeners.isEmpty())
- {
- return;
- }
- for (CacheListener<? super K, ? super V> listener : listeners)
- try
- {
- listener.onPut(context, key, value);
- }
- catch (Exception e)
- {
- if (LOG.isWarnEnabled())
- LOG.warn("Cannot execute the CacheListener properly", e);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public void onGet(CacheListenerContext context, K key, HashCode<V> obj) throws Exception
- {
- if (listeners.isEmpty())
- {
- return;
- }
- V value = obj == null ? null : localCache.get(key);
- for (CacheListener<? super K, ? super V> listener : listeners)
- try
- {
- listener.onGet(context, key, value);
- }
- catch (Exception e)
- {
- if (LOG.isWarnEnabled())
- LOG.warn("Cannot execute the CacheListener properly", e);
- }
- }
-
- /**
- * @see org.exoplatform.services.cache.CacheListener#onClearCache(org.exoplatform.services.cache.CacheListenerContext)
- */
- public void onClearCache(CacheListenerContext context) throws Exception
- {
- localCache.clear();
- if (listeners.isEmpty())
- {
- return;
- }
- for (CacheListener<? super K, ? super V> listener : listeners)
- {
- try
- {
- listener.onClearCache(context);
- }
- catch (Exception e)
- {
- if (LOG.isWarnEnabled())
- LOG.warn("Cannot execute the CacheListener properly", e);
- }
- }
- }
-
- /**
- * We use this class to propagate the hash code of the value efficiently over the network
- */
- public static class HashCode<V> implements Externalizable
- {
- /**
- * The hash code of the value
- */
- private int hashCode;
-
- /**
- * The corresponding value
- */
- private V value;
-
- public HashCode() {}
-
- public HashCode(V value)
- {
- this.hashCode = value.hashCode();
- this.value = value;
- }
-
- /**
- * @return the value
- */
- public V getValue()
- {
- return value;
- }
-
- /**
- * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
- */
- public void writeExternal(ObjectOutput out) throws IOException
- {
- out.writeInt(hashCode);
- }
-
- /**
- * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
- */
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
- {
- this.hashCode = in.readInt();
- }
-
- /**
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode()
- {
- return hashCode;
- }
-
- /**
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- @SuppressWarnings("rawtypes")
- HashCode other = (HashCode)obj;
- if (hashCode != other.hashCode)
- return false;
- if (value != null && other.value != null)
- {
- return value.equals(other.value);
- }
- return true;
- }
-
- /**
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString()
- {
- return "HashCode [hashCode=" + hashCode + ", value=" + value + "]";
- }
- }
-}
Copied: kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/invalidation/InvalidationExoCache.java (from rev 4603, kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/InvalidationExoCache.java)
===================================================================
--- kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/invalidation/InvalidationExoCache.java (rev 0)
+++ kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/invalidation/InvalidationExoCache.java 2011-07-06 09:34:01 UTC (rev 4604)
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.cache.invalidation;
+
+import org.exoplatform.services.cache.CacheListener;
+import org.exoplatform.services.cache.CacheListenerContext;
+import org.exoplatform.services.cache.CachedObjectSelector;
+import org.exoplatform.services.cache.ExoCache;
+import org.exoplatform.services.cache.ObjectCacheInfo;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * This eXo cache type is a decorator allowing ExoCache instances that have
+ * big values or non serializable values to be replicated thanks to an invalidation
+ * mechanism. To prevent infinite loop described below, we replicate the hash code of
+ * the value such that if the hash code is the same, we don't invalidate the value locally
+ * <ul>
+ * <li>Cluster node #1 puts (key1, value1) into the cache</li>
+ * <li>On cluster node #2 key1 is invalidated by the put call in node #1</li>
+ * <li>Node #2 re-loads key1 and puts (key1, value1) into the cache</li>
+ * <li>On cluster node #1 key1 is invalidated, so we get back to step #1</li>
+ * </ul>
+ *
+ * @author <a href="mailto:nfilotto at exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ *
+ */
+public class InvalidationExoCache<K extends Serializable, V> implements ExoCache<K, V>,
+ CacheListener<K, InvalidationExoCache.HashCode<V>>
+{
+ /**
+ * Logger.
+ */
+ private static final Log LOG = ExoLogger.getLogger("exo.kernel.component.cache.InvalidationExoCache");
+
+ /**
+ * The eXo cache instance that we would like to replicate using the invalidation
+ * mechanism
+ */
+ private final ExoCache<K, HashCode<V>> delegate;
+
+ /**
+ * The listeners of the cache
+ */
+ private final CopyOnWriteArrayList<CacheListener<? super K, ? super V>> listeners;
+
+ /**
+ * The local cache that contains the real values
+ */
+ private final ConcurrentMap<K, V> localCache;
+
+ /**
+ * @param delegate the underneath eXo cache instance, we assume that the eXo cache
+ * implementation behind is fully functional.
+ */
+ public InvalidationExoCache(ExoCache<K, V> delegate)
+ {
+ this(delegate, delegate.getMaxSize() > 0 && delegate.getMaxSize() < 512 ? delegate.getMaxSize() : 512);
+ }
+
+ /**
+ * @param delegate the underneath eXo cache instance, we assume that the eXo cache
+ * implementation behind is fully functional.
+ * @concurrencyLevel the estimated number of concurrently
+ * updating threads. The implementation performs internal sizing
+ * to try to accommodate this many threads.
+ */
+ @SuppressWarnings("unchecked")
+ public InvalidationExoCache(ExoCache<K, V> delegate, int concurrencyLevel)
+ {
+ this.delegate = (ExoCache<K, HashCode<V>>)delegate;
+ // We listen to the cache in order to get a callbacks in case of internal puts for example
+ this.delegate.addCacheListener(this);
+ this.listeners = new CopyOnWriteArrayList<CacheListener<? super K, ? super V>>();
+ this.localCache = new ConcurrentHashMap<K, V>(concurrencyLevel, 0.75f, concurrencyLevel);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getName()
+ */
+ public String getName()
+ {
+ return delegate.getName();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#setName(java.lang.String)
+ */
+ public void setName(String name)
+ {
+ delegate.setName(name);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getLabel()
+ */
+ public String getLabel()
+ {
+ return delegate.getLabel();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#setLabel(java.lang.String)
+ */
+ public void setLabel(String s)
+ {
+ delegate.setLabel(s);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#get(java.io.Serializable)
+ */
+ public V get(Serializable name)
+ {
+ HashCode<V> result = delegate.get(name);
+ return result == null ? null : localCache.get(name);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#remove(java.io.Serializable)
+ */
+ public V remove(Serializable key) throws NullPointerException
+ {
+ V value = localCache.get(key);
+ delegate.remove(key);
+ return value;
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#put(java.io.Serializable, java.lang.Object)
+ */
+ public void put(K key, V value) throws NullPointerException
+ {
+ delegate.put(key, new HashCode<V>(value));
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#putMap(java.util.Map)
+ */
+ public void putMap(Map<? extends K, ? extends V> objs) throws NullPointerException, IllegalArgumentException
+ {
+ if (objs == null)
+ {
+ throw new NullPointerException("No null map accepted");
+ }
+ Map<K, HashCode<V>> map = new LinkedHashMap<K, HashCode<V>>();
+ for (Entry<? extends K, ? extends V> entry : objs.entrySet())
+ {
+ if (entry.getKey() == null)
+ {
+ throw new IllegalArgumentException("No null cache key accepted");
+ }
+ else if (entry.getValue() == null)
+ {
+ throw new IllegalArgumentException("No null cache value accepted");
+ }
+ map.put(entry.getKey(), new HashCode<V>(entry.getValue()));
+ }
+ delegate.putMap(map);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#clearCache()
+ */
+ public void clearCache()
+ {
+ delegate.clearCache();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#select(org.exoplatform.services.cache.CachedObjectSelector)
+ */
+ public void select(CachedObjectSelector<? super K, ? super V> selector) throws Exception
+ {
+ if (selector == null)
+ {
+ throw new IllegalArgumentException("No null selector");
+ }
+ for (Entry<K, V> entry : localCache.entrySet())
+ {
+ final K key = entry.getKey();
+ final V value = entry.getValue();
+ ObjectCacheInfo<V> info = new ObjectCacheInfo<V>()
+ {
+ public V get()
+ {
+ return value;
+ }
+
+ public long getExpireTime()
+ {
+ // Cannot know: The expire time is managed by JBoss Cache itself
+ return -1;
+ }
+ };
+ if (selector.select(key, info))
+ {
+ selector.onSelect(this, key, info);
+ }
+ }
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getCacheSize()
+ */
+ public int getCacheSize()
+ {
+ return localCache.size();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getMaxSize()
+ */
+ public int getMaxSize()
+ {
+ return delegate.getMaxSize();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#setMaxSize(int)
+ */
+ public void setMaxSize(int max)
+ {
+ delegate.setMaxSize(max);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getLiveTime()
+ */
+ public long getLiveTime()
+ {
+ return delegate.getLiveTime();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#setLiveTime(long)
+ */
+ public void setLiveTime(long period)
+ {
+ delegate.setLiveTime(period);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getCacheHit()
+ */
+ public int getCacheHit()
+ {
+ return delegate.getCacheHit();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getCacheMiss()
+ */
+ public int getCacheMiss()
+ {
+ return delegate.getCacheMiss();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getCachedObjects()
+ */
+ public List<? extends V> getCachedObjects()
+ {
+ return new ArrayList<V>(localCache.values());
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#removeCachedObjects()
+ */
+ public List<? extends V> removeCachedObjects()
+ {
+ final List<? extends V> list = getCachedObjects();
+ clearCache();
+ return list;
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#addCacheListener(org.exoplatform.services.cache.CacheListener)
+ */
+ public void addCacheListener(CacheListener<? super K, ? super V> listener) throws NullPointerException
+ {
+ if (listener == null)
+ {
+ throw new NullPointerException();
+ }
+ listeners.add(listener);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#isLogEnabled()
+ */
+ public boolean isLogEnabled()
+ {
+ return delegate.isLogEnabled();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#setLogEnabled(boolean)
+ */
+ public void setLogEnabled(boolean b)
+ {
+ delegate.setLogEnabled(b);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onExpire(CacheListenerContext context, K key, HashCode<V> obj) throws Exception
+ {
+ V value = localCache.remove(key);
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (CacheListener<? super K, ? super V> listener : listeners)
+ {
+ try
+ {
+ listener.onExpire(context, key, value);
+ }
+ catch (Exception e)
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onRemove(CacheListenerContext context, K key, HashCode<V> obj) throws Exception
+ {
+ V value = localCache.remove(key);
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (CacheListener<? super K, ? super V> listener : listeners)
+ {
+ try
+ {
+ listener.onRemove(context, key, value);
+ }
+ catch (Exception e)
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onPut(CacheListenerContext context, K key, HashCode<V> obj) throws Exception
+ {
+ V value = obj.getValue();
+ if (value != null)
+ {
+ // we assume that it is a local put since the value is inside the HashCode object
+ localCache.put(key, value);
+ }
+ else
+ {
+ // we assume that it is a remote put since the value is not inside the HashCode object
+ V currentValue = localCache.get(key);
+ if (currentValue != null && obj != null && currentValue.hashCode() == obj.hashCode())
+ {
+ // We assume that it is the same value so we don't change the value in the cache
+ value = currentValue;
+ }
+ else
+ {
+ // A new value has been added to the cache so we invalidate the local one
+ value = null;
+ localCache.remove(key);
+ }
+ }
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (CacheListener<? super K, ? super V> listener : listeners)
+ try
+ {
+ listener.onPut(context, key, value);
+ }
+ catch (Exception e)
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onGet(CacheListenerContext context, K key, HashCode<V> obj) throws Exception
+ {
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ V value = obj == null ? null : localCache.get(key);
+ for (CacheListener<? super K, ? super V> listener : listeners)
+ try
+ {
+ listener.onGet(context, key, value);
+ }
+ catch (Exception e)
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.CacheListener#onClearCache(org.exoplatform.services.cache.CacheListenerContext)
+ */
+ public void onClearCache(CacheListenerContext context) throws Exception
+ {
+ localCache.clear();
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (CacheListener<? super K, ? super V> listener : listeners)
+ {
+ try
+ {
+ listener.onClearCache(context);
+ }
+ catch (Exception e)
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+ }
+
+ /**
+ * We use this class to propagate the hash code of the value efficiently over the network
+ */
+ public static class HashCode<V> implements Externalizable
+ {
+ /**
+ * The hash code of the value
+ */
+ private int hashCode;
+
+ /**
+ * The corresponding value
+ */
+ private V value;
+
+ public HashCode() {}
+
+ public HashCode(V value)
+ {
+ this.hashCode = value.hashCode();
+ this.value = value;
+ }
+
+ /**
+ * @return the value
+ */
+ public V getValue()
+ {
+ return value;
+ }
+
+ /**
+ * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
+ */
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ out.writeInt(hashCode);
+ }
+
+ /**
+ * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
+ */
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+ {
+ this.hashCode = in.readInt();
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode()
+ {
+ return hashCode;
+ }
+
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ @SuppressWarnings("rawtypes")
+ HashCode other = (HashCode)obj;
+ if (hashCode != other.hashCode)
+ return false;
+ if (value != null && other.value != null)
+ {
+ return value.equals(other.value);
+ }
+ return true;
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return "HashCode [hashCode=" + hashCode + ", value=" + value + "]";
+ }
+ }
+}
More information about the exo-jcr-commits
mailing list