/*
* Copyright (C) 1999-2009 Jive Software. All rights reserved.
*
* Licensed 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 com.jivesoftware.util.cache;
import com.tangosol.net.cache.CacheLoader;
import com.tangosol.net.cache.LocalCache;
import com.tangosol.net.cache.OldCache;
import com.tangosol.util.SafeHashMap;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheSizes;
import org.jivesoftware.util.cache.Cacheable;
import org.jivesoftware.util.cache.CannotCalculateSizeException;
/**
* Implementation of the Cache interface that uses the Coherence LocalCache class.
*
*/
public class CoherenceCache extends LocalCache implements Cache {
private static final String FLUSH_DELAY_PROP = "cache.local.flushDelay";
private String name = "";
/**
* Default constructor for coherence to create instances.
*/
public CoherenceCache(){
}
public CoherenceCache(int maxSize) {
super(maxSize);
}
public CoherenceCache(int maxSize, int maxLifetime) {
super(maxSize, maxLifetime);
}
public CoherenceCache(int maxSize, int maxLifetime, CacheLoader loader) {
super(maxSize, maxLifetime, loader);
}
/**
* Constructor used only by jive - never called by coherence. If you are creating a subclass, or directly
* instantiating this one, you should only use this constructor, as it does several things not normally required.
* For instance, the low units (low water mark) will be set to 90 percent of the value of <tt>maxSize</tt>. Also,
* if the local jive property <tt>'cache.local.flushDelay'</tt> is set, that value will be used as the number of
* milliseconds passed to {@link #setFlushDelay}. If it is not set, the default value (one minute) will be used.
*
* @param name the name of the cache
* @param maxSize the maximum number of units (bytes, in our case) the cache will hold before evicting older entries.
* @param maxLifetime the time to live (in milliseconds) for entries in the cache.
*/
public CoherenceCache(String name, int maxSize, long maxLifetime) {
super(maxSize<=0?Integer.MAX_VALUE:maxSize, maxLifetime<0?0:(int)maxLifetime);
init(maxSize, name);
}
/**
* Constructor used only by jive - never called by coherence. If you are creating a subclass, or directly
* instantiating this one, you should only use this constructor, as it does several things not normally required.
* For instance, the low units (low water mark) will be set to 90 percent of the value of <tt>maxSize</tt>. Also,
* if the local jive property <tt>'cache.local.flushDelay'</tt> is set, that value will be used as the number of
* milliseconds passed to {@link #setFlushDelay}. If it is not set, the default value (one minute) will be used.
*
* @param name the name of the cache
* @param maxSize the maximum number of units (bytes, in our case) the cache will hold before evicting older entries.
* @param maxLifetime the time to live (in milliseconds) for entries in the cache.
* @param cacheLoader the <tt>CacheLoader</tt> or <tt>CacheStore</tt> to use.
*/
public CoherenceCache(String name, int maxSize, long maxLifetime, CacheLoader cacheLoader) {
super(maxSize<=0?Integer.MAX_VALUE:maxSize, maxLifetime<0?0:(int)maxLifetime, cacheLoader);
init(maxSize, name);
}
private void init(int maxSize, String name) {
if (maxSize > 0) {
setLowUnits((int)(maxSize*.9));
}
String delayProp = JiveGlobals.getProperty(FLUSH_DELAY_PROP);
if (delayProp != null) {
try {
long delay = Long.parseLong(delayProp);
if (delay >=0) {
setFlushDelay((int)delay);
}
}
catch (NumberFormatException nfe) {
Log.warn("Unable to parse " + FLUSH_DELAY_PROP + " using default value of " + delayProp);
}
}
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getMaxCacheSize() {
return getHighUnits();
}
public void setMaxCacheSize(int maxSize) {
setHighUnits(maxSize<=0?Integer.MAX_VALUE:maxSize);
if (maxSize > 0) {
setLowUnits((int)(maxSize*.9));
}
//TODO write these through to coherence configuration
}
public long getMaxLifetime() {
return getExpiryDelay();
}
public void setMaxLifetime(long maxLifetime) {
setExpiryDelay(maxLifetime<0?0:(int)maxLifetime);
//TODO write these through to coherence configuration
}
public int getCacheSize() {
return getUnits();
}
protected SafeHashMap.Entry instantiateEntry() {
return new Entry();
}
/**
* A holder for a cached value.
*/
public class Entry extends OldCache.Entry {
public int calculateUnits(Object object) {
try {
// Coherence puts com.tangosol.util.Binary objects in cache.
if (object instanceof com.tangosol.util.Binary) {
return ((com.tangosol.util.Binary) object).length();
}
// Check for other common types of objects put into cache.
else {
return CacheSizes.sizeOfAnything(object);
}
} catch (CannotCalculateSizeException e) {
Log.warn(e.getMessage(), e);
return 1;
}
}
}
}