start implementation of guava based CacheManager

This commit is contained in:
Sebastian Sdorra
2013-03-24 19:52:06 +01:00
parent d2a107d112
commit 57f5e31a54
6 changed files with 948 additions and 0 deletions

View File

@@ -0,0 +1,231 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of SCM-Manager;
* 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 REGENTS 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.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.cache;
//~--- JDK imports ------------------------------------------------------------
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author Sebastian Sdorra
*/
@XmlRootElement(name = "cache")
@XmlAccessorType(XmlAccessType.FIELD)
public class CacheConfiguration
{
/**
* Method description
*
*
* @return
*/
public Integer getConcurrencyLevel()
{
return concurrencyLevel;
}
/**
* Method description
*
*
* @return
*/
public CopyStrategy getCopyStrategy()
{
return copyStrategy;
}
/**
* Method description
*
*
* @return
*/
public Long getExpireAfterAccess()
{
return expireAfterAccess;
}
/**
* Method description
*
*
* @return
*/
public Long getExpireAfterWrite()
{
return expireAfterWrite;
}
/**
* Method description
*
*
* @return
*/
public Integer getInitialCapacity()
{
return initialCapacity;
}
/**
* Method description
*
*
* @return
*/
public Long getMaximumSize()
{
return maximumSize;
}
/**
* Method description
*
*
* @return
*/
public Long getMaximumWeight()
{
return maximumWeight;
}
/**
* Method description
*
*
* @return
*/
public String getName()
{
return name;
}
/**
* Method description
*
*
* @return
*/
public Boolean getRecordStats()
{
return recordStats;
}
/**
* Method description
*
*
* @return
*/
public Boolean getSoftValues()
{
return softValues;
}
/**
* Method description
*
*
* @return
*/
public Boolean getWeakKeys()
{
return weakKeys;
}
/**
* Method description
*
*
* @return
*/
public Boolean getWeakValues()
{
return weakValues;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
@XmlAttribute
private Integer concurrencyLevel;
/** Field description */
@XmlAttribute
private CopyStrategy copyStrategy;
/** Field description */
@XmlAttribute
private Long expireAfterAccess;
/** Field description */
@XmlAttribute
private Long expireAfterWrite;
/** Field description */
@XmlAttribute
private Integer initialCapacity;
/** Field description */
@XmlAttribute
private Long maximumSize;
/** Field description */
@XmlAttribute
private Long maximumWeight;
/** Field description */
@XmlAttribute
private String name;
/** Field description */
@XmlAttribute
private Boolean recordStats;
/** Field description */
@XmlAttribute
private Boolean softValues;
/** Field description */
@XmlAttribute
private Boolean weakKeys;
/** Field description */
@XmlAttribute
private Boolean weakValues;
}

View File

@@ -0,0 +1,85 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of SCM-Manager;
* 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 REGENTS 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.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.cache;
/**
*
* @author Sebastian Sdorra
*/
public class CacheException extends RuntimeException
{
/** Field description */
private static final long serialVersionUID = -1108209749696572319L;
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*/
public CacheException() {}
/**
* Constructs ...
*
*
* @param message
*/
public CacheException(String message)
{
super(message);
}
/**
* Constructs ...
*
*
* @param cause
*/
public CacheException(Throwable cause)
{
super(cause);
}
/**
* Constructs ...
*
*
* @param message
* @param cause
*/
public CacheException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@@ -0,0 +1,83 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of SCM-Manager;
* 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 REGENTS 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.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.cache;
//~--- JDK imports ------------------------------------------------------------
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author Sebastian Sdorra
*/
@XmlRootElement(name = "caches")
@XmlAccessorType(XmlAccessType.FIELD)
public class CacheManagerConfiguration
{
/**
* Method description
*
*
* @return
*/
public List<CacheConfiguration> getCaches()
{
return caches;
}
/**
* Method description
*
*
* @return
*/
public CacheConfiguration getDefaultCache()
{
return defaultCache;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
@XmlElement(name = "cache")
private List<CacheConfiguration> caches;
/** Field description */
@XmlElement(name = "cache")
private CacheConfiguration defaultCache;
}

View File

@@ -0,0 +1,147 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of SCM-Manager;
* 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 REGENTS 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.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.cache;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.io.DeepCopy;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.util.Locale;
/**
*
* @author Sebastian Sdorra
*/
public enum CopyStrategy
{
NONE(false, false), READ(true, false), WRITE(false, true),
READWRITE(true, true);
/**
* Constructs ...
*
*
* @param copyOnRead
* @param copyOnWrite
*/
private CopyStrategy(boolean copyOnRead, boolean copyOnWrite)
{
this.copyOnRead = copyOnRead;
this.copyOnWrite = copyOnWrite;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param value
*
* @return
*/
public static CopyStrategy fromString(String value)
{
return valueOf(value.toUpperCase(Locale.ENGLISH).replace("-", ""));
}
/**
* Method description
*
*
* @param object
* @param <T>
*
* @return
*/
public <T> T copyOnRead(T object)
{
return copyOnRead
? deepCopy(object)
: object;
}
/**
* Method description
*
*
* @param object
* @param <T>
*
* @return
*/
public <T> T copyOnWrite(T object)
{
return copyOnWrite
? deepCopy(object)
: object;
}
/**
* Method description
*
*
* @param object
* @param <T>
*
* @return
*/
private <T> T deepCopy(T object)
{
T copy = null;
try
{
copy = DeepCopy.copy(object);
}
catch (IOException ex)
{
throw new CacheException(
"could not create a copy of ".concat(object.toString()), ex);
}
return copy;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private boolean copyOnRead;
/** Field description */
private boolean copyOnWrite;
}

View File

@@ -0,0 +1,280 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of SCM-Manager;
* 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 REGENTS 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.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.cache;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.Filter;
//~--- JDK imports ------------------------------------------------------------
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
*
* @author Sebastian Sdorra
*
* @param <K>
* @param <V>
*/
public class GuavaCache<K, V> implements Cache<K, V>
{
/**
* the logger for GuavaCache
*/
private static final Logger logger =
LoggerFactory.getLogger(GuavaCache.class);
//~--- constructors ---------------------------------------------------------
private String name;
/**
* Constructs ...
*
*
* @param configuration
*/
public GuavaCache(CacheConfiguration configuration)
{
this.name = configuration.getName();
if (configuration.getCopyStrategy() != null)
{
copyStrategy = configuration.getCopyStrategy();
}
CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder();
if (configuration.getConcurrencyLevel() != null)
{
builder.concurrencyLevel(configuration.getConcurrencyLevel());
}
if (configuration.getExpireAfterAccess() != null)
{
builder.expireAfterAccess(configuration.getExpireAfterAccess(),
TimeUnit.MILLISECONDS);
}
if (configuration.getExpireAfterWrite() != null)
{
builder.expireAfterWrite(configuration.getExpireAfterWrite(),
TimeUnit.MILLISECONDS);
}
if (configuration.getInitialCapacity() != null)
{
builder.initialCapacity(configuration.getInitialCapacity());
}
if (configuration.getMaximumSize() != null)
{
builder.maximumSize(configuration.getMaximumSize());
}
if (configuration.getMaximumWeight() != null)
{
builder.maximumWeight(configuration.getMaximumWeight());
}
if (isEnabled(configuration.getRecordStats()))
{
builder.recordStats();
}
if (isEnabled(configuration.getSoftValues()))
{
builder.softValues();
}
if (isEnabled(configuration.getWeakKeys()))
{
builder.weakKeys();
}
if (isEnabled(configuration.getWeakValues()))
{
builder.weakKeys();
}
cache = builder.build();
if (logger.isTraceEnabled())
{
logger.trace("create new guava cache from builder: {}", builder);
}
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*/
@Override
public void clear()
{
if (logger.isDebugEnabled())
{
logger.debug("clear cache {}", name);
}
cache.invalidateAll();
}
/**
* Method description
*
*
* @param key
*
* @return
*/
@Override
public boolean contains(K key)
{
return cache.getIfPresent(key) != null;
}
/**
* Method description
*
*
* @param key
* @param value
*/
@Override
public void put(K key, V value)
{
cache.put(key, copyStrategy.copyOnWrite(value));
}
/**
* Method description
*
*
* @param key
*
* @return
*/
@Override
public boolean remove(K key)
{
cache.invalidate(key);
return true;
}
/**
* Method description
*
*
* @param filter
*
* @return
*/
@Override
public boolean removeAll(Filter<K> filter)
{
Set<K> keysToRemove = Sets.newHashSet();
for (K key : cache.asMap().keySet())
{
if (filter.accept(key))
{
keysToRemove.add(key);
}
}
boolean result = false;
if (!keysToRemove.isEmpty())
{
cache.invalidateAll(keysToRemove);
result = true;
}
return result;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param key
*
* @return
*/
@Override
public V get(K key)
{
V value = cache.getIfPresent(key);
if (value != null)
{
value = copyStrategy.copyOnRead(value);
}
return value;
}
/**
* Method description
*
*
* @param v
*
* @return
*/
private boolean isEnabled(Boolean v)
{
return (v != null) && v;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private com.google.common.cache.Cache<K, V> cache;
/** Field description */
private CopyStrategy copyStrategy = CopyStrategy.NONE;
}

View File

@@ -0,0 +1,122 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of SCM-Manager;
* 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 REGENTS 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.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.cache;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.util.Map;
/**
*
* @author Sebastian Sdorra
*/
public class GuavaCacheManager implements CacheManager
{
/**
* the logger for GuavaCacheManager
*/
private static final Logger logger =
LoggerFactory.getLogger(GuavaCacheManager.class);
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @throws IOException
*/
@Override
public void close() throws IOException
{
logger.info("close guava cache manager");
for (Cache c : cacheMap.values())
{
c.clear();
}
cacheMap.clear();
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param key
* @param value
* @param name
* @param <K>
* @param <V>
*
* @return
*/
@Override
public <K, V> GuavaCache<K, V> getCache(Class<K> key, Class<V> value,
String name)
{
logger.trace("try to retrieve cache {}", name);
GuavaCache<K, V> cache = cacheMap.get(name);
if (cache == null)
{
logger.debug(
"cache {} does not exists, creating a new instance from default configuration: {}",
name, defaultConfiguration);
cache = new GuavaCache<K, V>(defaultConfiguration);
cacheMap.put(name, cache);
}
return cache;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private Map<String, GuavaCache> cacheMap = Maps.newConcurrentMap();
/** Field description */
private CacheConfiguration defaultConfiguration;
}