/* * 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; } } } }