libswarmcache-java-1.0RC2+cvs20071027.orig/0000755000175000017500000000000010711726365017723 5ustar twernertwernerlibswarmcache-java-1.0RC2+cvs20071027.orig/conf/0000755000175000017500000000000010711726346020647 5ustar twernertwernerlibswarmcache-java-1.0RC2+cvs20071027.orig/conf/default.xml0000644000175000017500000001322507712501031023005 0ustar twernertwerner JavaGroups Default Protocol Stack UDP Protocol Sends and receives messages on UDP sockets org.javagroups.protocols.UDP Ping Protocol Find the initial membership org.javagroups.protocols.PING Merge Protocol Periodically tries to detect subgroups and emits MERGE events in that case org.javagroups.protocols.MERGE2 Failure Detection Socket Failure detection based on sockets org.javagroups.protocols.FD Verify Suspect Double-checks that a suspected member is really dead org.javagroups.protocols.VERIFY_SUSPECT Reliable mcast message transission Uses a negative acknowledgement protocol for retransmissions org.javagroups.protocols.pbcast.NAKACK Unicast Protocol Provides lossless transmission of unicast message (similar to TCP) org.javagroups.protocols.UNICAST Stable protocol Distributed message garbage collection protocol. Deletes messages seen by all group members org.javagroups.protocols.pbcast.STABLE Fragmentation Protocol Divides up larger message into smaller pieces org.javagroups.protocols.FRAG PB Cast Group Membership Protocol Maintains the member ship view org.javagroups.protocols.pbcast.GMS libswarmcache-java-1.0RC2+cvs20071027.orig/conf/pbcast.xml0000644000175000017500000000702007712501031022631 0ustar twernertwerner UDP Protocol Sends and receives messages on UDP sockets org.javagroups.protocols.UDP Ping Protocol Find the initial membership org.javagroups.protocols.PING Merge Protocol Periodically tries to detect subgroups and emits MERGE events in that case org.javagroups.protocols.MERGE2 Failure Detection Socket Failure detection based on sockets org.javagroups.protocols.pbcast.FD Verify Suspect Double-checks that a suspected member is really dead org.javagroups.protocols.VERIFY_SUSPECT PBCAST-based message transmission Mcast message transmission based on probabilistic broadcast (Ken Birman et al) org.javagroups.protocols.pbcast.PBCAST Unicast Protocol Provides lossless transmission of unicast message (similar to TCP) org.javagroups.protocols.UNICAST Fragmentation Protocol Divides up larger message into smaller pieces org.javagroups.protocols.FRAG PB Cast Group Membership Protocol Maintains the member ship view org.javagroups.protocols.pbcast.GMS libswarmcache-java-1.0RC2+cvs20071027.orig/conf/smack.xml0000644000175000017500000000561407712501031022462 0ustar twernertwerner Stack based on SMACK and minimal threads. SMACK is a simple reliable multicast transport based on positive acks (sender sends message, receiver sends ack, if sender doesn't receive ack within timeout, message will be retransmitted). UDP Protocol Sends and receives messages on UDP sockets org.javagroups.protocols.UDP FD_SIMPLE FD_SIMPLE org.javagroups.protocols.FD_SIMPLE Unicast Protocol Provides lossless transmission of unicast message (similar to TCP) org.javagroups.protocols.UNICAST SMACK SMACK org.javagroups.protocols.SMACK libswarmcache-java-1.0RC2+cvs20071027.orig/conf/tcp.xml0000644000175000017500000000760407712501031022153 0ustar twernertwerner TCP Protocol Sends and receives messages using TCP org.javagroups.protocols.TCP TCP Ping Protocol Find the initial membership org.javagroups.protocols.TCPPING Failure Detection Socket Failure detection based on sockets org.javagroups.protocols.FD Verify Suspect Double-checks that a suspected member is really dead org.javagroups.protocols.VERIFY_SUSPECT Reliable mcast message transission Uses a negative acknowledgement protocol for retransmissions org.javagroups.protocols.pbcast.NAKACK Stable protocol Distributed message garbage collection protocol. Deletes messages seen by all group members org.javagroups.protocols.pbcast.STABLE PB Cast Group Membership Protocol Maintains the member ship view org.javagroups.protocols.pbcast.GMS libswarmcache-java-1.0RC2+cvs20071027.orig/lib/0000755000175000017500000000000010711726365020471 5ustar twernertwernerlibswarmcache-java-1.0RC2+cvs20071027.orig/all.library0000644000175000017500000000043207646617756022100 0ustar twernertwerner all [lib/commons-collections.jar] [lib/javagroups-all.jar] [lib/commons-logging.jar] libswarmcache-java-1.0RC2+cvs20071027.orig/build.xml0000644000175000017500000001172507746041303021546 0ustar twernertwerner libswarmcache-java-1.0RC2+cvs20071027.orig/changehog.txt0000644000175000017500000000147707746410112022412 0ustar twernertwernerChanges for 0.91 - New distribution package that includes all support jars. Releases in both zip and tar.gz formats. - Updated docs. - Added readme.html. Changes for 1.0RC1 - New cache types: TimerCache and HybridCache. - Moved AutoCache over to a ReferenceMap. - Improved configuration somewhat. - If a cache object is changed (that is, the object is replaced with the same key), then a clear is sent. Changes for 1.0RC2 - Ported over to the latest version of JavaGroups (known now as JGroups): JGroups 2.2 - [Andr Schild] JGroups protocol string adjustments to eliminate a potential deadlock upon start-up. - [Rajeev Kaul] MultiCacheManager now has a method to shut itself down. Communicator also supports a shutDown() method which is implemented by the JavaGroupsCommunicator. - Documenation update. - New public web site.libswarmcache-java-1.0RC2+cvs20071027.orig/readme.html0000644000175000017500000000103107746041303022035 0ustar twernertwerner SwarmCache @version@ Readme

SwarmCache @version@ Readme

The SwarmCache distribution consists of these files: To use SwarmCache, make sure that all four of the .jar files are in your classpath. See http://swarmcache.sf.net for instructions on how to use SwarmCache with your software. libswarmcache-java-1.0RC2+cvs20071027.orig/swarmcache.ipr0000644000175000017500000001072607746366177022601 0ustar twernertwerner libswarmcache-java-1.0RC2+cvs20071027.orig/swarmcache.iws0000644000175000017500000006721207746407423022601 0ustar twernertwerner libswarmcache-java-1.0RC2+cvs20071027.orig/swarmcache.jpx0000644000175000017500000000362607646617757022613 0ustar twernertwerner libswarmcache-java-1.0RC2+cvs20071027.orig/test.bat0000644000175000017500000000041207746040062021364 0ustar twernertwernerjava -Dorg.apache.commons.logging.simplelog.defaultlog=debug -Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog -cp lib/commons-collections.jar;lib/commons-logging.jar;lib/jgroups-all.jar;classes net.sf.swarmcache.CacheTest 239.1.1.1 Timer 10libswarmcache-java-1.0RC2+cvs20071027.orig/testAuto.bat0000644000175000017500000000040607746040062022220 0ustar twernertwernerjava -Dorg.apache.commons.logging.simplelog.defaultlog=debug -Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog -cp lib/commons-collections.jar;lib/commons-logging.jar;lib/jgroups-all.jar;classes net.sf.swarmcache.CacheTest 239.1.1.1 Autolibswarmcache-java-1.0RC2+cvs20071027.orig/testHybrid.bat0000644000175000017500000000041207746040062022526 0ustar twernertwernerjava -Dorg.apache.commons.logging.simplelog.defaultlog=debug -Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog -cp lib/commons-collections.jar;lib/commons-logging.jar;lib/jgroups-all.jar;classes net.sf.swarmcache.CacheTest 239.1.1.1 Hybrid 5libswarmcache-java-1.0RC2+cvs20071027.orig/testLRU.bat0000644000175000017500000000041107746040062021746 0ustar twernertwernerjava -Dorg.apache.commons.logging.simplelog.defaultlog=debug -Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog -cp lib/commons-collections.jar;lib/commons-logging.jar;lib/jgroups-all.jar;classes net.sf.swarmcache.CacheTest 239.1.1.1 LRU 500libswarmcache-java-1.0RC2+cvs20071027.orig/testLRU.sh0000755000175000017500000000042407746040062021621 0ustar twernertwerner#!/bin/sh java -Dorg.apache.commons.logging.simplelog.defaultlog=debug -Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog -cp lib/commons-collections.jar:lib/commons-logging.jar:lib/jgroups-all.jar:classes net.sf.swarmcache.CacheTest 239.1.1.1 LRU 500 libswarmcache-java-1.0RC2+cvs20071027.orig/src/0000755000175000017500000000000010711726365020512 5ustar twernertwernerlibswarmcache-java-1.0RC2+cvs20071027.orig/src/net/0000755000175000017500000000000010711726365021300 5ustar twernertwernerlibswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/0000755000175000017500000000000010711726365021710 5ustar twernertwernerlibswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/0000755000175000017500000000000010711726365024025 5ustar twernertwernerlibswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/AutoCache.java0000644000175000017500000000452407772350645026540 0ustar twernertwernerpackage net.sf.swarmcache; import java.util.*; import java.io.Serializable; import org.apache.commons.logging.*; import org.apache.commons.collections.ReferenceMap; /** * This cache implementation uses soft references so that cached objects are * automatically garbage collected when needed. Note that this maximizes the * cache size at the expense of making no guarantees as to the cache-clearing * algorithm used. So, it makes for good memory use at the possible expense of * cache hit frequency. * * @author John Watkinson */ public class AutoCache implements ObjectCache { Log log = LogFactory.getLog(this.getClass()); //------------------------------------------------------------------------- // Fields //------------------------------------------------------------------------- private String type; private Map cache; //------------------------------------------------------------------------- // Constructors //------------------------------------------------------------------------- /** * Default contsructor required. */ public AutoCache() { cache = Collections.synchronizedMap(new ReferenceMap()); } public AutoCache(String cacheType) { // Use a synchronized map cache = Collections.synchronizedMap(new ReferenceMap()); setType(cacheType); } //------------------------------------------------------------------------- // Public methods //------------------------------------------------------------------------- /** * Sets the common name of the type of objects to cache. */ public void setType(String cacheType) { log.debug("Cache type set to '" + cacheType + "'."); type = cacheType; } public String getType() { return type; } /** * Adds an object to the cache. */ public void put(Serializable key, Object object) { cache.put(key, object); log.debug("Put " + type + " #" + key + " in to cache."); } public Object get(Serializable key) { Object object = cache.get(key); if (object != null) { log.debug("Got " + type + " #" + key + " from cache."); } return object; } public Object clear(Serializable key) { log.debug("Cleared " + type + " #" + key + " from cache."); return cache.remove(key); } public void clearAll() { // Just make a new one log.debug("Cleared entire " + type + " cache."); cache = Collections.synchronizedMap(new ReferenceMap()); } }libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/CacheConfiguration.java0000644000175000017500000002003507746407423030430 0ustar twernertwernerpackage net.sf.swarmcache; /** * A class that contains the configuration information to be fed in to a new {@link CacheFactory CacheFactory}. * * @author John Watkinson */ public class CacheConfiguration { //------------------------------------------------------------------------- // Constants //------------------------------------------------------------------------- /** * The first half of the default channel properties. They default channel properties are: *
	 * UDP(mcast_addr=*.*.*.*;mcast_port=45566;ip_ttl=32;mcast_send_buf_size=150000;mcast_recv_buf_size=80000):PING(timeout=2000;num_initial_members=3):MERGE2(min_interval=5000;max_interval=10000):FD_SOCK:VERIFY_SUSPECT(timeout=1500):pbcast.NAKACK(gc_lag=50;retransmit_timeout=300,600,1200,2400,4800):UNICAST(timeout=5000):pbcast.STABLE(desired_avg_gossip=20000):FRAG(frag_size=8096;down_thread=false;up_thread=false):pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=true)
	 * 
* Where *.*.*.* is the specified multicast IP, which defaults to 231.12.21.132. */ public static final String DEFAULT_CHANNEL_PROPERTIES_PRE = "UDP(mcast_addr="; // "UDP(mcast_addr="; /** * The second half of the default channel properties. They default channel properties are: *
	 * UDP(mcast_addr=*.*.*.*;mcast_port=45566;ip_ttl=32;mcast_send_buf_size=150000;mcast_recv_buf_size=80000):PING(timeout=2000;num_initial_members=3):MERGE2(min_interval=5000;max_interval=10000):FD_SOCK:VERIFY_SUSPECT(timeout=1500):pbcast.NAKACK(gc_lag=50;retransmit_timeout=300,600,1200,2400,4800):UNICAST(timeout=5000):pbcast.STABLE(desired_avg_gossip=20000):FRAG(frag_size=8096;down_thread=false;up_thread=false):pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=true)
	 * 
* Where *.*.*.* is the specified multicast IP, which defaults to 231.12.21.132. */ public static final String DEFAULT_CHANNEL_PROPERTIES_POST = // JW: The following are old JavaGroups config strings: // ";mcast_port=45566;ip_ttl=32;mcast_send_buf_size=150000;mcast_recv_buf_size=80000):PING(timeout=2000;num_initial_members=3):MERGE2(min_interval=5000;max_interval=10000):FD_SOCK:VERIFY_SUSPECT(timeout=1500):pbcast.STABLE(desired_avg_gossip=20000):pbcast.NAKACK(gc_lag=50;retransmit_timeout=300,600,1200,2400,4800):UNICAST(timeout=5000):FRAG(frag_size=8096;down_thread=false;up_thread=false):pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=true)"; // ";mcast_port=45566):PING:FD:VERIFY_SUSPECT:pbcast.STABLE:pbcast.NAKACK:UNICAST:FRAG:pbcast.GMS"; // ";mcast_port=5678):PING:FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:STATE_TRANSFER:QUEUE"; // ";mcast_port=45566;ip_ttl=32;mcast_send_buf_size=150000;mcast_recv_buf_size=80000):PING(timeout=2000;num_initial_members=3):MERGE2(min_interval=5000;max_interval=10000):FD_SOCK:VERIFY_SUSPECT(timeout=1500):pbcast.STABLE(desired_avg_gossip=20000):pbcast.NAKACK(gc_lag=50;retransmit_timeout=300,600,1200,2400,4800):UNICAST(timeout=5000):FRAG(frag_size=8096;down_thread=false;up_thread=false):pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=true)"; // JW: The following is the default JGroups 2.2 config string. It's use of FD instead of FD_SOCK is unsatisfying. // ";mcast_port=45566;mcast_send_buf_size=32000;mcast_recv_buf_size=64000;ucast_send_buf_size=32000;ucast_recv_buf_size=64000;use_packet_handler=false;loopback=true;ip_ttl=32):" + // "PING(timeout=2000;num_initial_members=3):" + // "MERGE2(min_interval=5000;max_interval=10000):" + // "FD(timeout=2000;max_tries=3;shun=true):" + // "VERIFY_SUSPECT(timeout=1500):" + // "pbcast.NAKACK(gc_lag=50;retransmit_timeout=600,1200,2400,4800;max_xmit_size=8192;use_mcast_xmit=false):" + // "UNICAST(timeout=1200,2400,3600):" + // "pbcast.STABLE(desired_avg_gossip=20000;max_bytes=0;stability_delay=1000):" + // "FRAG(frag_size=8192;down_thread=false;up_thread=false):" + // "pbcast.GMS(join_timeout=3000;join_retry_timeout=2000;shun=true;print_local_addr=true)"; // JW: This config string is recommended by Andre Schild, it re-arranges the protocols to avoid deadlock. ";mcast_port=45566;ip_ttl=32;mcast_send_buf_size=150000;mcast_recv_buf_size=80000):" + "PING(timeout=2000;num_initial_members=3):" + "MERGE2(min_interval=5000;max_interval=10000):" + "FD_SOCK:" + "VERIFY_SUSPECT(timeout=1500):" + "pbcast.NAKACK(gc_lag=50;retransmit_timeout=300,600,1200,2400,4800):" + "UNICAST(timeout=5000):" + "pbcast.STABLE(desired_avg_gossip=20000):" + "FRAG(frag_size=8096;down_thread=false;up_thread=false):" + "pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=true)"; /** * The default multicast IP to be used by the cache manager. Its value is 231.12.21.132. */ public static final String DEFAULT_MULTICAST_IP = "231.12.21.132"; /** * The default LRU cache size. Its value is 10000. */ public static final int DEFAULT_LRU_CACHE_SIZE = 10000; /** * The LRU cache type. */ public static final String TYPE_LRU = "LRU"; /** * The Automatic cache type. */ public static final String TYPE_AUTO = "Auto"; /** * The Timer cache type. */ public static final String TYPE_TIMER = "Timer"; /** * The Hybrid cache type. */ public static final String TYPE_HYBRID = "Hybrid"; //------------------------------------------------------------------------- // Constants //------------------------------------------------------------------------- private String channelProperties; private String multicastIP; private String cacheType; private String lruCacheSize; //------------------------------------------------------------------------- // Public methods //------------------------------------------------------------------------- /** * Gets the JavaGroups channel properties. * If not specified, default properties will be generated using the multicast IP. * Either this or the multicast IP must be set, or else null will be returned. */ public String getChannelProperties() { if (channelProperties == null) { if (multicastIP == null) { multicastIP = DEFAULT_MULTICAST_IP; } return DEFAULT_CHANNEL_PROPERTIES_PRE + multicastIP + DEFAULT_CHANNEL_PROPERTIES_POST; } else { return channelProperties; } } /** * Sets the JavaGroup channel properties. See the * JavaGroups homepage for more imformation. * If not specified, default properties will be generated using the multicast IP. * Either this or the multicast IP must be set. */ public void setChannelProperties(String v) { channelProperties = v; } /** * Gets the multicast IP address for the JavaGroup. */ public String getMulticastIP() { return multicastIP; } /** * Sets the multicast IP address for the JavaGroup. */ public void setMulticastIP(String v) { multicastIP = v; } /** * Gets the underlying cache type to use on each server. * The two options are LRU and Auto. */ public String getCacheType() { return cacheType; } /** * Sets the underlying cache type to use on each server. * The two options are LRU and Auto. */ public void setCacheType(String v) { cacheType = v; } /** * Gets the capacity of the LRU cache. * If the cache type is LRU, then this is the maximum number of objects in the LRU queue. * Otherwise, this is ignored. */ public String getLRUCacheSize() { if (lruCacheSize == null) { return "" + DEFAULT_LRU_CACHE_SIZE; } else { return lruCacheSize; } } /** * Sets the capacity of the LRU cache. * If the cache type is LRU, then this is the maximum number of objects in the LRU queue. * Otherwise, this is ignored. */ public void setLRUCacheSize(String v) { lruCacheSize = v; } }libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/CacheConfigurationManager.java0000644000175000017500000000675707746366200031737 0ustar twernertwernerpackage net.sf.swarmcache; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.Properties; import java.io.InputStream; import java.io.IOException; /** * CacheConfigurationManager holds a static CacheConfiguration for use * throughout a system. It tries to load configuration properties from a file * named 'swarmcache.properties' in the classpath, and uses the defaults if that * file does not exist. * * @author Jason Carreira */ public class CacheConfigurationManager { private static final Log LOG = LogFactory.getLog(CacheConfigurationManager.class); public static final String SWARMCACHE_PROP_FILE_NAME = "swarmcache.properties"; public static final String SWARMCACHE_CHANNEL_PROPS = "swarmcache.channel.properties"; public static final String SWARMCACHE_MULTICAST_IP = "swarmcache.multicast.ip"; public static final String SWARMCACHE_CACHE_TYPE = "swarmcache.cache.type"; public static final String SWARMCACHE_LRU_SIZE = "swarmcache.lru.size"; private CacheConfigurationManager() { } static Properties defaults = initializeDefaults(); static Properties initializeDefaults() { LOG.debug("Initializing cache configuration defaults."); Properties defaults = new Properties(); defaults.put(SWARMCACHE_MULTICAST_IP, CacheConfiguration.DEFAULT_MULTICAST_IP); defaults.put(SWARMCACHE_CACHE_TYPE, CacheConfiguration.TYPE_LRU); defaults.put(SWARMCACHE_LRU_SIZE, "" + CacheConfiguration.DEFAULT_LRU_CACHE_SIZE); InputStream is = CacheConfigurationManager.class.getClassLoader().getResourceAsStream(SWARMCACHE_PROP_FILE_NAME); if (is != null) { LOG.debug("Reading cache configuration from '" + SWARMCACHE_PROP_FILE_NAME + "'..."); Properties props = new Properties(defaults); try { props.load(is); } catch (IOException e) { final String s = "Unable to load '" + SWARMCACHE_PROP_FILE_NAME + "' due to IOException."; LOG.error(s, e); throw new IllegalStateException(s); } defaults = props; } else { LOG.info("Unable to load '" + SWARMCACHE_PROP_FILE_NAME + "'... Using defaults."); } LOG.debug("Using default values: " + defaults); return defaults; } static CacheConfiguration buildConfigurationInternal(Properties props) { CacheConfiguration myConfig = new CacheConfiguration(); final String channelProps = props.getProperty(SWARMCACHE_CHANNEL_PROPS); final String multicastIp = props.getProperty(SWARMCACHE_MULTICAST_IP); if (channelProps != null) { LOG.debug("Setting channel properties to " + channelProps); myConfig.setChannelProperties(channelProps); } else if (multicastIp != null) { LOG.debug("Setting multicast IP to " + multicastIp); myConfig.setMulticastIP(multicastIp); } else { throw new IllegalArgumentException("Either the channel properties or the multicast IP address must be specified."); } final String cacheType = props.getProperty(SWARMCACHE_CACHE_TYPE); if (cacheType != null) { LOG.debug("Setting cache type to " + cacheType); myConfig.setCacheType(cacheType); } final String lruSize = props.getProperty(SWARMCACHE_LRU_SIZE); if (lruSize != null) { LOG.debug("Setting LRU size to " + lruSize); myConfig.setLRUCacheSize(lruSize); } return myConfig; } public static CacheConfiguration getConfig() { return buildConfigurationInternal(defaults); } public static CacheConfiguration getConfig(Properties props) { Properties defaultedProps = new Properties(defaults); defaultedProps.putAll(props); return buildConfigurationInternal(defaultedProps); } } libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/CacheFactory.java0000644000175000017500000000766107746366200027237 0ustar twernertwernerpackage net.sf.swarmcache; import org.apache.commons.logging.*; /** * A convenient generator of multicast caches using an underlying LRU or Automatic algorithm. * * @author John Watkinson * @author Rajeev Kaul */ public class CacheFactory { Log log = LogFactory.getLog(this.getClass()); //------------------------------------------------------------------------- // Fields //------------------------------------------------------------------------- private Class cacheType; private int lruCacheSize; private boolean isLRU; private MultiCacheManager manager; //------------------------------------------------------------------------- // Constructors //------------------------------------------------------------------------- protected CacheFactory() { } public CacheFactory(CacheConfiguration conf) { cacheType = null; String cacheTypeProperty = conf.getCacheType(); if (cacheTypeProperty != null) { try { // Set up the underlying cache isLRU = false; if (CacheConfiguration.TYPE_LRU.equals(cacheTypeProperty)) { cacheType = LRUCache.class; isLRU = true; } else if ( CacheConfiguration.TYPE_AUTO.equals(cacheTypeProperty)) { cacheType = AutoCache.class; } else if ( CacheConfiguration.TYPE_TIMER.equals(cacheTypeProperty)) { cacheType = TimerCache.class; } else if ( CacheConfiguration.TYPE_HYBRID.equals(cacheTypeProperty)) { cacheType = HybridCache.class; isLRU = true; } else { throw new Exception( "Unknown cache type: " + cacheType + "."); } if (isLRU) { if (conf.getLRUCacheSize() != null) { lruCacheSize = Integer.parseInt(conf.getLRUCacheSize()); } else { lruCacheSize = LRUCache.DEFAULT_CACHE_SIZE; } } // Try to instantiate one to make sure it works ObjectCache sampleCache = (ObjectCache) cacheType.newInstance(); // Set up the Manager String channelProperties = conf.getChannelProperties(); if (channelProperties == null) { throw new Exception("Either the channel properties or the multicast IP address must be specified."); } log.debug( "Creating a JavaGroups cache manager with properties: " + channelProperties); // Set up communication channel manager = MultiCacheManager.getManager(channelProperties); } catch (Exception e) { log.error("Problem instantiating cache:", e); } } } //------------------------------------------------------------------------- // Public methods //------------------------------------------------------------------------- /** * Creates a new cache. * @param name a name for the cache. Useful if there will be multiple caches for various objects. * @return a new cache of either the LRU or AUTO underlying type, based on configuration. */ public ObjectCache createCache(String name) { ObjectCache cache = null; MultiCache multi = null; // // do not create cache, if it already exists if (manager.containsCache(name)) { log.error("Cache of type [" + name + "] already exists."); } else { if (cacheType != null) { try { cache = (ObjectCache) cacheType.newInstance(); if (cache instanceof LRUCache) { ((LRUCache) cache).setSize(lruCacheSize); } else if (cache instanceof HybridCache) { ((HybridCache) cache).setSize(lruCacheSize); } cache.setType(name); multi = new MultiCache(cache, manager); manager.addCache(multi); } catch (Exception e) { log.error("Problem instantiating cache:"); e.printStackTrace(); } } } return multi; } /** * Returns the manager that handles inter-cache communication. */ public MultiCacheManager getCacheManager() { return manager; } /** * CacheFactory lifecycle shutdown method. * This method should be called before exiting an application. * Otherwise, the application will not terminate. */ public void shutdown() { MultiCacheManager.shutDown(); } } libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/CacheNotification.java0000644000175000017500000000127407746366200030250 0ustar twernertwernerpackage net.sf.swarmcache; import java.io.Serializable; /** * The actual object that gets sent to the cluster to indicate that an object * needs to be cleared from the cache. * * @author John Watkinson */ public class CacheNotification implements Serializable { private String type; private Serializable key; public CacheNotification() { } public CacheNotification(String type, Serializable key) { this.type = type; this.key = key; } public void setType(String type) { this.type = type; } public String getType() { return type; } public void setKey(Serializable key) { this.key = key; } public Serializable getKey() { return key; } }libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/CacheTest.java0000644000175000017500000001762307746366200026546 0ustar twernertwernerpackage net.sf.swarmcache; import java.io.*; import java.util.*; import org.apache.commons.logging.*; import java.net.*; /** * Test cache app. Run this on multiple machines at once. * @author John Watkinson */ public class CacheTest { private static Random random = new Random(); /** * String length to use for randomly generated keys. */ public static final int RANDOM_KEY_LENGTH = 20; /** * String length to use for randomly generated values. */ public static final int RANDOM_VALUE_LENGTH = 1000; public static class LoadTester implements Runnable { private ObjectCache cache; private int numKeys; private int operationsPerSecond; private int writesPerThousand; private int numberOfSeconds; public LoadTester(ObjectCache cache, int numKeys, int operationsPerSecond, int writesPerThousand, int numberOfSeconds) { this.cache = cache; this.numKeys = numKeys; this.operationsPerSecond = operationsPerSecond; this.writesPerThousand = writesPerThousand; this.numberOfSeconds = numberOfSeconds; } public void run() { System.out.println(">>> Thread " + Thread.currentThread().getName() + " starting load test."); loadTest(); System.out.println(">>> Thread " + Thread.currentThread().getName() + " completed load test."); } private void loadTest() { // Calculate average time between accesses * 2 and clearsPerSecond * 2 int maxWaitTime = 2 * 1000 / operationsPerSecond; long startTime = System.currentTimeMillis(); long stopTime = startTime + 1000 * numberOfSeconds; long currentTime = System.currentTimeMillis(); while (currentTime < stopTime) { int waitTime = random.nextInt(maxWaitTime); currentTime = System.currentTimeMillis(); // Do access String key = "" + random.nextInt(numKeys); if (random.nextInt(1000) < writesPerThousand) { // Do a write cache.put(key, key); } else { // Do a read cache.get(key); } long pauseTime = waitTime - (System.currentTimeMillis() - currentTime); if (pauseTime > 0) { try { Thread.sleep(waitTime); } catch (InterruptedException e) { } } } } } /** * A String that outputs to STDOUT when it has been finalized. */ public static class FinalizerString { private String s; public FinalizerString(String string) { s = string; } public boolean equals(Object o) { return s.equals(o); } public String toString() { return s; } protected void finalize() throws Throwable { System.out.println("Finalized: \"" + s + "\"."); } } private static String readLine(InputStream in) throws IOException { String result = ""; char c = (char) in.read(); while (c != '\n' && c != '\0') { result += in.read(); c = (char) in.read(); } if (result.length() == 0) { return null; } else { return result; } } private static String randomString(int length) { char[] chars = new char[length]; for (int i = 0; i < length; i++) { chars[i] = (char) ('a' + (int) (Math.random() * 26)); } return new String(chars); } public static void main(String[] args) { try { System.out.println("Local: " + java.net.InetAddress.getLocalHost()); System.out.println("Args: [[[] ] ]"); CacheConfiguration conf = new CacheConfiguration(); if (args.length > 0) { conf.setMulticastIP(args[0]); } if (args.length > 1) { conf.setCacheType(args[1]); } if (args.length > 2) { conf.setLRUCacheSize(args[2]); } boolean finalizerString = false; if (CacheConfiguration.TYPE_AUTO.equals(conf.getCacheType()) || CacheConfiguration.TYPE_HYBRID.equals(conf.getCacheType())) { finalizerString = true; } String local = InetAddress.getLocalHost().getHostAddress(); System.out.println("LOCAL: " + local); // conf.setChannelProperties("UDP(mcast_addr=237.0.0.2;bind_addr=" + local + ";mcast_port=45566;ip_ttl=32;mcast_send_buf_size=150000;mcast_recv_buf_size=80000):PING(timeout=2000;num_initial_members=3):MERGE2(min_interval=5000;max_interval=10000):FD_SOCK:VERIFY_SUSPECT(timeout=1500):pbcast.STABLE(desired_avg_gossip=20000):pbcast.NAKACK(gc_lag=50;retransmit_timeout=300,600,1200,2400,4800):UNICAST(timeout=5000):FRAG(frag_size=8096;down_thread=false;up_thread=false):pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=true)"); CacheFactory factory = new CacheFactory(conf); ObjectCache cache = factory.createCache("TEST"); System.out.println("Cache has been initialized."); BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); System.out.println("New stream created."); String input = in.readLine(); while (input != null) { StringTokenizer st = new StringTokenizer(input); String command = st.nextToken(); if ("PUT".equalsIgnoreCase(command)) { String key = st.nextToken(); String value = st.nextToken(); // Clear old value // cache.clear(key); if (finalizerString) { cache.put(key, new FinalizerString(value)); } else { cache.put(key, value); } System.out.println("Put '" + value + "' in to the cache with key '" + key + "'."); } else if ("GET".equalsIgnoreCase(command)) { String key = st.nextToken(); Object o = cache.get(key); System.out.println("Getting '" + key + "' from cache returned '" + o + "'."); } else if ("CLEAR".equalsIgnoreCase(command)) { String key = st.nextToken(); cache.clear(key); System.out.println("Cleared '" + key + "' from the cache."); } else if ("CLEARALL".equalsIgnoreCase(command)) { cache.clearAll(); System.out.println("Cleared all keys from cache."); } else if ("FILL".equalsIgnoreCase(command)) { int n = Integer.parseInt(st.nextToken()); for (int i = 0; i < n; i++) { String key = randomString(RANDOM_KEY_LENGTH); String value = randomString(RANDOM_VALUE_LENGTH); cache.put(key, value); } System.out.println("Put " + n + " random strings of length " + RANDOM_VALUE_LENGTH + " in to the cache."); } else if ("LOADTEST".equalsIgnoreCase(command)) { // Run loadtester int numKeys = Integer.parseInt(st.nextToken()); int accessesPerSecond = Integer.parseInt(st.nextToken()); int writesPerThousand = Integer.parseInt(st.nextToken()); int numberOfSeconds = Integer.parseInt(st.nextToken()); int numberOfThreads = Integer.parseInt(st.nextToken()); for (int i = 0; i < numberOfThreads; i++) { LoadTester tester = new LoadTester(cache, numKeys, accessesPerSecond, writesPerThousand, numberOfSeconds); new Thread(tester, "LoadTest-" + (i + 1)).start(); } } else if ("MEMORY".equalsIgnoreCase(command)) { int numberOfThreads = Integer.parseInt(st.nextToken()); System.out.println("Causing an OutOfMemoryError with " + numberOfThreads + " threads..."); for (int i = 0; i < numberOfThreads; i++) { new Thread(new Runnable() { public void run() { List l = new LinkedList(); while (true) { l.add(randomString(RANDOM_VALUE_LENGTH)); } } }, "Memory-" + (i + 1)).start(); } } else if ("CPU".equalsIgnoreCase(command)) { final int numberOfSeconds = Integer.parseInt(st.nextToken()); System.out.println("Causing high CPU load for " + numberOfSeconds + " seconds..."); new Thread(new Runnable() { public void run() { long startTime = System.currentTimeMillis(); long endTime = startTime + 1000 * numberOfSeconds; while (System.currentTimeMillis() < endTime) { double a = 0; for (int i = 0; i < 1000; i++) { a = Math.random() * 50000; a = Math.sqrt(a); } } } }, "CPU-loader").start(); } else { System.out.println("Unrecognized command: '" + command + "'."); } input = in.readLine(); } } catch (Exception e) { e.printStackTrace(); } } }libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/Communicator.java0000644000175000017500000000260207746366200027332 0ustar twernertwernerpackage net.sf.swarmcache; /** * Abstract class that handles the communications for SwarmCache. * * To provide a full implementation: *
    *
  • Extend this class and implement a constructor/instantiator that accepts a MultiCacheManager and a group name. *
  • Implement the {@link #send send} method. *
  • Have your communications layer call {@link #receive receive} upon receipt of a cache notification. *
* * @author John Watkinson */ public abstract class Communicator { private String groupName; protected void setGroupName(String groupName) { this.groupName = groupName; } public String getGroupName() { return groupName; } private MultiCacheManager manager; public void setManager(MultiCacheManager manager) { this.manager = manager; } public MultiCacheManager getManager() { return manager; } /** * Call when a notification is received by the communications layer. * @param notification the parsed cache notification. */ protected void receive(CacheNotification notification) { manager.receiveNotification(notification); } /** * Implement this to send a cache notification over the communications layer. * @param notification the cache notification to send. */ protected abstract void send(CacheNotification notification); /** * Called by the cache manager to shut down the communicator. */ public abstract void shutDown(); } libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/HybridCache.java0000644000175000017500000000511007746366200027034 0ustar twernertwernerpackage net.sf.swarmcache; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.collections.LRUMap; import java.util.Map; import java.util.Collections; import java.io.Serializable; /** * A hybrid cache solution that uses a (presumably small) LRU cache backed by a larger AutoCache. * This implementation aims to be a good trade-off between cache hit frequency and agressive memory usage. */ public class HybridCache implements ObjectCache, LRUCacheListener { Log log = LogFactory.getLog(this.getClass()); //------------------------------------------------------------------------- // Fields //------------------------------------------------------------------------- private String type; /** * The LRU Cache. */ private LRUCache lruCache; /** * The LRU Cache. */ private AutoCache autoCache; public HybridCache() { lruCache = new LRUCache(); autoCache = new AutoCache(); // Listen for automatic removals of objects lruCache.setListener(this); } /** * Sets the size of the LRU cache. * Note: this clears the LRU cache! */ public void setSize(int newSize) { lruCache.setSize(newSize); } public String getType() { return type; } public void setType(String type) { log.debug("Cache type set to '" + type + "'."); this.type = type; lruCache.setType(type); autoCache.setType(type); } /** * Called when an object is automatically removed from the LRU cache. */ public void objectRemoved(Serializable key, Object value) { // Put the removed object in the auto cache. autoCache.put(key, value); log.debug("Moved " + type + " #" + key + " to the auto cache."); } public void put(Serializable key, Object object) { lruCache.put(key, object); log.debug("Put " + type + " #" + key + " in to cache."); } public Object get(Serializable key) { Object object = lruCache.get(key); if (object != null) { log.debug("Got " + type + " #" + key + " from LRU cache."); } else { object = autoCache.get(key); if (object != null) { log.debug("Got " + type + " #" + key + " from auto cache."); // Upgrade to LRU cache lruCache.put(key, object); autoCache.clear(key); } } return object; } public Object clear(Serializable key) { log.debug("Cleared " + type + " #" + key + " from cache."); Object o = lruCache.clear(key); if (o != null) { return o; } else { o = autoCache.clear(key); return o; } } public void clearAll() { log.debug("Cleared entire " + type + " cache."); lruCache.clearAll(); autoCache.clearAll(); } } libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/JavaGroupsCommunicator.java0000644000175000017500000000443007746366200031335 0ustar twernertwernerpackage net.sf.swarmcache; import org.jgroups.blocks.*; import org.jgroups.*; import org.apache.commons.logging.*; import java.util.HashMap; import java.io.Serializable; /** * Created by IntelliJ IDEA. * User: jwat * Date: Jul 25, 2003 * Time: 11:47:57 AM * To change this template use Options | File Templates. */ public class JavaGroupsCommunicator extends Communicator implements NotificationBus.Consumer { Log log = LogFactory.getLog(this.getClass()); public static final String BUS_NAME = "CacheBus"; public static final String CHANNEL_PROPERTIES = "multi.cache.properties"; private NotificationBus bus; //------------------------------------------------------------------------- // Constructors //------------------------------------------------------------------------- public JavaGroupsCommunicator(String properties) { log.info("Starting a JavaGroups Communicator..." + properties); setGroupName(BUS_NAME); try { if (properties == null) { bus = new NotificationBus(getGroupName()); } else { bus = new NotificationBus(getGroupName(), properties); } bus.start(); bus.getChannel().setOpt(Channel.LOCAL, new Boolean(false)); bus.getChannel().setOpt(Channel.AUTO_RECONNECT, new Boolean(true)); bus.setConsumer(this); log.info("... finished starting new JavaGroups Communicator."); } catch (Exception e) { log.error("There was a problem initiating the cache notification bus: "); e.printStackTrace(); } } public void shutDown() { bus.stop(); } protected void finalize() throws Throwable { shutDown(); } protected final void send(CacheNotification notification) { bus.sendNotification(notification); } public Serializable getCache() { // We don't care about this, // so let's just return something that identifies us. // return "MultiCacheManager: " + bus.getLocalAddress(); return null; } public void handleNotification(Serializable object) { log.debug("Received cache notification: " + object); CacheNotification notification = (CacheNotification) object; receive(notification); } public void memberJoined(Address who) { log.info("A host has joined the cache notification bus: " + who + "."); } public void memberLeft(Address who) { log.info("A host has left the cache notification bus: " + who + "."); } } libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/LRUCache.java0000644000175000017500000000623607746366200026267 0ustar twernertwernerpackage net.sf.swarmcache; import java.util.*; import org.apache.commons.collections.*; import java.io.Serializable; import org.apache.commons.logging.*; /** * Cache implementation that uses the Least Recently Used algorithm. * This algorithm provides good cache hit frequency. * @author John Watkinson */ public class LRUCache implements ObjectCache { Log log = LogFactory.getLog(this.getClass()); //------------------------------------------------------------------------- // Inner classes //------------------------------------------------------------------------- public class ListeningLRUMap extends LRUMap { public ListeningLRUMap(int size) { super(size); } /** * The listener for objects automatically removed from the cache. */ private LRUCacheListener listener = null; public void setListener(LRUCacheListener l) { listener = l; } protected void processRemovedLRU(Object key, Object value) { if (listener != null) { listener.objectRemoved((Serializable) key, value); } } } //------------------------------------------------------------------------- // Constants //------------------------------------------------------------------------- /** * The property containing the maximum number of objects to cache. */ public static final String LRU_CACHE_SIZE_PROPERTY = "lru.cache.size"; /** * The default cache size (1000). */ public static final int DEFAULT_CACHE_SIZE = 1000; //------------------------------------------------------------------------- // Fields //------------------------------------------------------------------------- private String type; /** * The maximum number of objects that can be cached. */ private int size; /** * The map that will store the cache. */ private Map cache; /** * A reference to underlying ListeningLRUMap */ private ListeningLRUMap map; public LRUCache() { size = DEFAULT_CACHE_SIZE; String property = System.getProperty(LRU_CACHE_SIZE_PROPERTY); if (property != null) { try { size = Integer.parseInt(property); } catch (NumberFormatException nfe) { log.warn("LRU cache size was improperly specified."); nfe.printStackTrace(); } } map = new ListeningLRUMap(size); cache = Collections.synchronizedMap(map); } public void setSize(int newSize) { size = newSize; map.setMaximumSize(newSize); } public String getType() { return type; } public void setType(String type) { log.debug("Cache type set to '" + type + "'."); this.type = type; } public void put(Serializable key, Object object) { cache.put(key, object); log.debug("Put " + type + " #" + key + " in to cache."); } public Object get(Serializable key) { Object object = cache.get(key); if (object != null) { log.debug("Got " + type + " #" + key + " from cache."); } return object; } public Object clear(Serializable key) { log.debug("Cleared " + type + " #" + key + " from cache."); return cache.remove(key); } public void clearAll() { log.debug("Cleared entire " + type + " cache."); cache = Collections.synchronizedMap(new LRUMap(size)); } public void setListener(LRUCacheListener l) { map.setListener(l); } }libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/LRUCacheListener.java0000644000175000017500000000046207746366200027770 0ustar twernertwernerpackage net.sf.swarmcache; import java.io.Serializable; /** * Created by IntelliJ IDEA. * User: jwat * Date: Jun 27, 2003 * Time: 3:22:59 PM * To change this template use Options | File Templates. */ public interface LRUCacheListener { public void objectRemoved(Serializable key, Object value); } libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/MultiCache.java0000644000175000017500000000417707746366200026721 0ustar twernertwernerpackage net.sf.swarmcache; import java.io.Serializable; import org.apache.commons.logging.*; /** * A wrapper cache type that notifies the multicast cache manager. * @author John Watkinson */ public class MultiCache implements ObjectCache { Log log = LogFactory.getLog(this.getClass()); //------------------------------------------------------------------------- // Constants //------------------------------------------------------------------------- /** * The property holding the type of the underlying cache to use. */ public static final String CACHE_TYPE_PROPERTY = "multi.cache.type"; //------------------------------------------------------------------------- // Fields //------------------------------------------------------------------------- /** * The underlying cache */ private ObjectCache cache; /** * The cache manager. */ private MultiCacheManager manager; //------------------------------------------------------------------------- // Constructors //------------------------------------------------------------------------- public MultiCache(ObjectCache cache, MultiCacheManager manager) { this.cache = cache; this.manager = manager; } public String getType() { return cache.getType(); } public void setType(String type) { cache.setType(type); // Register this type with the manager manager.addCache(this); } public void put(Serializable key, Object object) { if (cache.get(key) != null) { clear(key); } cache.put(key, object); } public Object get(Serializable key) { return cache.get(key); } /** * In this implementation, the clear is multicast to all caches. */ public Object clear(Serializable key) { Object returnValue = cache.clear(key); // Multicast the request to other caches manager.sendClear(getType(), key); return returnValue; } /** * Here the clear is actually done. */ public void doClear(Serializable key) { cache.clear(key); } public void clearAll() { cache.clearAll(); // multicast the request manager.sendClear(getType(), MultiCacheManager.CLEAR_ALL); } public void doClearAll() { cache.clearAll(); } }libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/MultiCacheManager.java0000644000175000017500000000662407746366200030213 0ustar twernertwernerpackage net.sf.swarmcache; import java.util.*; import java.io.Serializable; import org.apache.commons.logging.*; /** * Manages the communications between other cache managers. * @author John Watkinson * @author Rajeev Kaul */ public class MultiCacheManager { protected static Map instances = new HashMap(); public static synchronized MultiCacheManager getManager(String channelProperties) { MultiCacheManager manager = (MultiCacheManager) instances.get(channelProperties); if (manager == null) { Communicator communicator = new JavaGroupsCommunicator(channelProperties); manager = new MultiCacheManager(communicator); communicator.setManager(manager); instances.put(channelProperties, manager); } return manager; } /* * Shutdown all the managers in the list * @author Rajeev Kaul */ public static synchronized void shutDown() { if (!instances.isEmpty()) { Set keys = instances.keySet(); Iterator iter = keys.iterator(); String key; MultiCacheManager manager; while (iter.hasNext()) { key = (String) iter.next(); manager = (MultiCacheManager) instances.get(key); manager.close(); } } } /* * closes a manager by stopping its communication bus * @author Rajeev Kaul */ public void close() { comm.shutDown(); } Log log = LogFactory.getLog(this.getClass()); //------------------------------------------------------------------------- // Constants //------------------------------------------------------------------------- public static final String CLEAR_ALL = "(ALL)"; //------------------------------------------------------------------------- // Fields //------------------------------------------------------------------------- private HashMap caches; private Communicator comm; //------------------------------------------------------------------------- // Constructors //------------------------------------------------------------------------- public MultiCacheManager(Communicator comm) { caches = new HashMap(); this.comm = comm; } //------------------------------------------------------------------------- // Public Methods //------------------------------------------------------------------------- public void addCache(MultiCache cache) { caches.put(cache.getType(), cache); } /* * checks if a manager contains the cache of a certain type * @param type of cache * @return true if cache exists, false otherwise * * @author Rajeev Kaul */ public boolean containsCache(String type) { return caches.containsKey(type); } public void sendClear(String type, Serializable key) { CacheNotification notification = new CacheNotification(type, key); // Send this to all cache managers log.debug("Sending a clear to all cache managers: (" + type + ", " + key + ")."); comm.send(notification); } public void receiveNotification(CacheNotification notification) { // Get the cache to clear this object MultiCache cache = (MultiCache) caches.get(notification.getType()); if (cache != null) { if (notification.getKey() == CLEAR_ALL) { log.debug("Received a clear-all: (" + notification.getType() + "."); cache.doClearAll(); } else { log.debug("Received a clear: (" + notification.getType() + ", " + notification.getKey() + ")."); cache.doClear(notification.getKey()); } } else { log.debug("Received info about an object that we do not cache here: " + notification.getType() + "."); } } } libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/ObjectCache.java0000644000175000017500000000140107746366200027020 0ustar twernertwernerpackage net.sf.swarmcache; import java.io.Serializable; /** * Generic caching mechanism. * * @author John Watkinson */ public interface ObjectCache { /** * Gets the common name of the type of objects to cache. */ public String getType(); /** * Sets the common name of the type of objects to cache. */ public void setType(String type); /** * Adds an object to the cache. */ public void put(Serializable key, Object object); /** * Gets an object from the cache by key, or returns null if that object is * not cached. */ public Object get(Serializable key); /** * Clears an object from the cache by key. */ public Object clear(Serializable key); /** * Clears the entire cache. */ public void clearAll(); }libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/TimerCache.java0000644000175000017500000001145707746366200026706 0ustar twernertwernerpackage net.sf.swarmcache; import java.util.*; import org.apache.commons.collections.*; import java.io.Serializable; import org.apache.commons.logging.*; /** * Cache implementation that times out cached elements. * Each item put in the cache is timed out after a specified number of milliseconds (unless removed before the timeout). * * @author John Watkinson */ public class TimerCache implements ObjectCache, Runnable { //------------------------------------------------------------------------- // Inner classes //------------------------------------------------------------------------- static class TStampObject { public long time; public Object object; } Log log = LogFactory.getLog(this.getClass()); //------------------------------------------------------------------------- // Constants //------------------------------------------------------------------------- /** * The property containing the cache timeout (in milliseconds). */ public static final String CACHE_TIMEOUT_PROPERTY = "cache.timeout"; /** * The default cache timeout (1 minute). */ public static final int DEFAULT_CACHE_TIMEOUT = 10000; //------------------------------------------------------------------------- // Fields //------------------------------------------------------------------------- /** * Cache type */ private String type; /** * The next wake-up deadline for the queue thread. */ private long deadline = Long.MAX_VALUE; /** * True if the cache-clearing thread should keep running. */ private boolean running = true; /** * The timer thread that clears cached objects. */ private Thread thread; /** * The cache timeout (in milliseconds). */ private long timeout; /** * The map that will store the cache. */ private UnboundedLRUMap cache; public TimerCache() { timeout = DEFAULT_CACHE_TIMEOUT; // Checks to see if there is a System property that sets the cache timeout. String property = System.getProperty(CACHE_TIMEOUT_PROPERTY); if (property != null) { try { timeout = Long.parseLong(property); } catch (NumberFormatException nfe) { log.warn("Cache timeout was improperly specified."); nfe.printStackTrace(); } } cache = new UnboundedLRUMap(); thread = new Thread(this); thread.start(); } /** * Sets a new timeout value-- only do this before using the cache! */ public void setTimeout(long newTimeout) { timeout = newTimeout; } /** * Called to stop the timer thread. This should only be called once and the cache should not be used afterwards. */ public synchronized void stop() { running = false; notify(); } /** * Gets the cache type name. */ public String getType() { return type; } /** * Sets the cache type name. */ public void setType(String type) { log.debug("Cache type set to '" + type + "'."); this.type = type; thread.setName("TimerCache-" + type); } /** * Caches an object. If object is null, then any object cached at the given key is removed from the cache. */ public void put(Serializable key, Object object) { if (object == null) { clear(key); } else { TStampObject tobj = new TStampObject(); tobj.object = object; tobj.time = System.currentTimeMillis() + timeout; cache.put(key, tobj); setDeadline(tobj.time); log.debug("Put " + type + " #" + key + " in to cache."); } } public Object get(Serializable key) { TStampObject tobj = (TStampObject) cache.get(key); if (tobj != null) { log.debug("Got " + type + " #" + key + " from cache."); tobj.time = System.currentTimeMillis() + timeout; return tobj.object; } else { return null; } } public Object clear(Serializable key) { log.debug("Cleared " + type + " #" + key + " from cache."); return cache.remove(key); } public void clearAll() { log.debug("Cleared entire " + type + " cache."); cache.clear(); } //// Timer methods private synchronized void setDeadline(long time) { if (time < deadline) { deadline = time; notify(); } } public void run() { while (running) { try { synchronized (this) { long now = System.currentTimeMillis(); long waitTime = deadline - now; if (waitTime > 0) { wait(waitTime); } } } catch (Exception e) { log.error(e); } trimQueue(); } } private void trimQueue() { log.debug("Waking up."); Object key = cache.getFirstKey(); TStampObject tobj = (TStampObject) cache.get(key); if (tobj != null) { long now = System.currentTimeMillis(); while ((tobj != null) && (tobj.time <= now)) { cache.remove(key); log.debug("Timed out object with key '" + key + "'."); key = cache.getFirstKey(); tobj = (TStampObject) cache.get(key); } } if (tobj != null) { deadline = tobj.time; } else { deadline = Long.MAX_VALUE; } log.debug("Sleeping."); } }libswarmcache-java-1.0RC2+cvs20071027.orig/src/net/sf/swarmcache/UnboundedLRUMap.java0000644000175000017500000000620607772352316027644 0ustar twernertwernerpackage net.sf.swarmcache; import java.util.*; import org.apache.commons.collections.LRUMap; import java.io.*; import org.apache.commons.logging.*; /** * An LRUMap that allows an unbounded size. * This implementation is an amortized O(1) amount slower than the bounded Jakarta Commons LRUMap implementation. * * @author John Watkinson */ public class UnboundedLRUMap implements Map { Log log = LogFactory.getLog(this.getClass()); public static final int MINIMUM_SIZE = 100; private LRUMap map; int size = MINIMUM_SIZE; public UnboundedLRUMap() { map = new LRUMap(size); } public void clear() { // Shrink the map down to minimum size if (size > MINIMUM_SIZE) { map = new LRUMap(MINIMUM_SIZE); size = MINIMUM_SIZE; } else { map.clear(); } } public boolean containsKey(Object key) { return map.containsKey(key); } public boolean containsValue(Object value) { return map.containsValue(value); } public Set entrySet() { return map.entrySet(); } public boolean equals(Object obj) { return map.equals(((UnboundedLRUMap) obj).map); } public int hashCode() { return map.hashCode(); } public Object get(Object key) { return map.get(key); } public boolean isEmpty() { return map.isEmpty(); } public Set keySet() { return map.keySet(); } public Object put(Object key, Object value) { // See if the "put" is actually a remove if (value == null) { if (map.get(key) != null) { // See if we are using less than %25 of the map if ((map.size() == size / 4) && (size > MINIMUM_SIZE)) { // Shrink the map size = size / 2; log.debug("Map capacity has shrunk to " + size + ", size is " + (map.size() - 1) + "."); LRUMap newMap = new LRUMap(size); newMap.putAll(map); map = newMap; } return map.put(key, value); } else { // Nothing to add return null; } } // Check to see if it will be a replace if (map.get(key) != null) { // Just do the replace return map.put(key, value); } else { // Check and see if we have overflowed this map if (map.size() == size) { // Make a new map of double size size = size * 2; log.debug("Map capacity has grown to " + size + ", size is " + (map.size() + 1) + "."); LRUMap newMap = new LRUMap(size); newMap.putAll(map); map = newMap; } return map.put(key, value); } } public void putAll(Map t) { Iterator keys = t.keySet().iterator(); while (keys.hasNext()) { Object key = keys.next(); put(key, t.get(key)); } } public Object remove(Object key) { if (map.get(key) != null) { // Check to see if we have less than %25 utilization if ((map.size() == size / 4) && (size > MINIMUM_SIZE)) { // Shrink the map size = size / 2; log.debug("Map capacity has shrunk to " + size + ", size is " + (map.size() - 1) + "."); LRUMap newMap = new LRUMap(size); newMap.putAll(map); map = newMap; } return map.remove(key); } else { // Nothing to remove return null; } } public int size() { return map.size(); } public Collection values() { return map.values(); } public Object getFirstKey() { return map.getFirstKey(); } }libswarmcache-java-1.0RC2+cvs20071027.orig/src/swarmcache.properties.SAMPLE0000644000175000017500000000026707737043501025730 0ustar twernertwerner# The Multicast IP address that SwarmCache will use for communication swarmcache.multicast.ip=231.12.21.132 # The maximum number of objects in the LRU cache swarmcache.lru.size=10000 libswarmcache-java-1.0RC2+cvs20071027.orig/web/0000755000175000017500000000000010711726365020500 5ustar twernertwernerlibswarmcache-java-1.0RC2+cvs20071027.orig/web/img/0000755000175000017500000000000010711726365021254 5ustar twernertwernerlibswarmcache-java-1.0RC2+cvs20071027.orig/web/img/swarm.jpg0000644000175000017500000001502307746407423023115 0ustar twernertwernerJFIFddDucky<Adobed       dd !1A"Q2aqB#Rb3$CS4%!1A"Q2aqBRbr3 ?|us1Z-EVuuh55/IeJD-yM ґW1G D}(뼖sJX|+,Mh5!ꆥ^bwaKTyn2R ulԸF%Kķ-@L,,&{i\ ^җ9D_]+""RO\ HYKj*n4MK-zt=Hx}W./'#@m6"={iT~>4QʀbyK K\VDƶ^ATFUi[~dJ 2RIj͊"37:E+Un$T^v0 Reѣ&ӮïmU-5Ē_Օ3|~!AjUd^DГîC'2lYķq;(ER]w jGqy'ۧq/g]L+5QPcl84, "m꺸eukxRuMWP #DBZy4rQaĄSan] VSQ=]VvpDòvp_NN:H384E3#e\,9+APEh]ҕJt% !LPD)quE"U_@dR3!q<9FȑGkDitz/?FJ^rx$tH@ ㆈ(7_DV96FzJ;=P6֟VWk_ow{ѽҗ}-pVSvY_So,~"5CRT_N쭈,ex!T_n8ntI7,GɦJ6bqh2U6hr**3JS𨜪\)QJ8F!=UA%E4%*r &2D6b⪥T_EV@:) 8pJ{q)[m5AbJ]OEQmVE\8vx܆*28`wһhD;2$9䲰琇![`%mޟk5dB\cNSnwǹ[ҵo뾳/b7ỳ2UG-2!^J"'OP{VfTocb1:p )n:O &lvf2FJ)6HJd(HRSWn/ xH%C>mQ%TڪtQ9Ȁ$Y^B:p g!G }ъk5io&m!?pD0HB<3;X٤X@yUQ--zjnuEuWs r '#PR2YΡ35y"TAOUW~_]D#TFYN-cFpV6KUBı ڪ[Jiެr[)4S>?#(J,hpj4vRLv PE/;[4O7$mr#b`E;-O{%ő_2 N`ܼ2APCT(H_*43qxVG UEKJ|t`X!ndqɿ@VaWy Nֵ )&/ sn30zB5!jRE3UhRF^Y5/)JǨ˦0ҢfTzhCc3 'Σ019ށ'BU'^u^L> wLkq ;E!ńVU_-WD<,LrixIfH?0ۈbc 6\^U[8hq X_W]BzRPB:V] P^Q@\u~?&+ .KĿǸ٧BUO:قpy-V\gHцUB7M4$HAUU'1J"At\%ЅX \x,OѧZqmUEanEW8$.q=ٯkZv>>z(j j"DUvji!2 ʦOH9J *r'c+PVl=V; k]rJ%i_[v Aտ9"Rr.*DzDV[Q)r()O ȱ89 T[wۥAq !<` O+ҙ;n\qQqwq$#w)!ѐC" Z <)^Fd3atCrҘ}scWTAtI@WϯM4kD8UbŰ($n DH{/" D>ZOFbDZw}$g?ڠXlG ]}|5+VP=e_u\P29kqe*Fi _ONz!F3:':VB_,1oBhQ!DTB%塚cb)'0T&d#:؉QmŴ-xׯve'ORtEs9adhhHnSu3Q6߇:rɾ[~NO1$Km@*'2j@1KdŲ\R#>bGt]ڤq-U~:NQkR7g5Xb#*O8%rE PV[*$a[-?,7훮}{&}͉"'#qkcV؄k(xPF^>aʠ"*"]Kv&j}<3ޔefXREIg~UE%;#at|lF̝Hn"LʶIKNЌ"yS_C 9I9cN{N+"41ųN 'ULRڢ"R'6eyN#xn71BT I mt1M|VKS(ȝS/8crmVGh\J](Zi7Aב@xp7 9٬ځa Hh4C.Ms;375"z$!EJ6Di!/e䇎uGN74xTtۍBÎzu[0] ZZr8I%"J[Mk0p|Vo$j#-Abj?DSW¶Y9F81<J1rLEj ȩQDS!T"뉔̌m (*[ҥUӡK̜G8hl(csuWĖ=T][剋蔾)qr"Gơ_K.qTꆔ[5KqB;q:.QU.z 9&=C exI[RB$20nG&:aNo mPתx} @eR1 51½DbjˎT$]=*$B3=7@MȪHc֊KKF1$__pyi8t N">/JN \$ROqP3*E7 J9e6Q ZL>5]n- 9I@}׹ouٿzw)mR3Kv\q8^" G\BکQŧ)U5ن,"P@[aհKY]'jhs"Q$9/r0&cq= *j=Ij# #C-ĕ)y6@S3[Q5ټw;ouj~zTH 7||u$nS&\%CvTvDd" I'OZ#O:0.Ql ے#_E)KFWUte?%RK'c5ucP:8@oprNbx96J[au&|R"YIAqictUUGD:EZ4Z(E)hSux q&ƭJzS\RUXԦ/͸@.1!"7.!U+n H/ Y-g9Vw$ c3KUT/Gc"{ bٺvH{.6{?Nlv4gν)Kܾ˹A)#OݽڽݭSpkOm.^,Y_EoMh..uҺݴD:xF{/qD-*jeaEgrEӮGيo?b ™g;R;Gqg?=?%ZiNnϵtճJonK<в>?m|]H libswarmcache-java-1.0RC2+cvs20071027.orig/web/documentation.html0000644000175000017500000002056010134035753024233 0ustar twernertwerner SwarmCache - Cluster-aware Caching for Java
     SwarmCache
Cluster-aware Caching for Java
Please be sure to read the Tutorial section before reading this section.

Caching Algorithms
The following caching algorithms are available for the local caches:

Least Recently Used (LRU)
This is the most common and straightforward caching algorithm. There is a fixed amount of objects that can be cached, and this is configurable. When the caching of a new object is requested but the cache is full, the object that has least recently been requested from the cache (or updated in the cache) is ejected to make space.

Automatic
This algorithm works with the JVM's garbage collector to allow cached objects to be automatically garbage-collected. The cache maintains soft references to cached objects. These allow the cached objects to be garbage collected by the system as necessary. This allows for a cache size that is bounded only by the amount of memory available to the JVM. However, unlike the LRU algorithm, it does not necessarily guarantee that frequently accessed objects will always be available in the cache.

Timeout
This algorithm times out objects that have been untouched for a number of milliseconds. The timeout amount is specified via the property cache.timeout.

Hybrid
This combines the benefits of both the LRU and Automatic algorithms. Two levels of caching are provided. At the first level, an LRU cache ensures that a fixed number of the most recently used objects are available in the cache. At the second level, an Automatic cache holds cached objects that are available to be reclaimed by the garbage collector.

Which one should I use?
The Hybrid algorithm offers the best combination of guaranteed performance for frequently used objects and overall cache size. It is the recommended algorithm. For those developers who want simple, deterministic caching, the LRU algorithm may be preferable.

Configuration Details
The following are all the configuration options available via the CacheConfiguration class:

CacheType
This is the type of the underlying caches that will be used. The options are CacheConfiguration.TYPE_LRU, CacheConfiguration.TYPE_AUTO, CacheConfiguration.TYPE_TIMER and CacheConfiguration.TYPE_HYBRID. The default is LRU.

LRUCacheSize
This is the LRU cache size. This measured in number of objects, not bytes. This value is ignored if CacheType is set to CacheConfiguration.AUTO or CacheConfiguration.TIMER. The default is 10000.

MulticastIP
This is the multicast IP address that will be used to communicate between cache managers. The default value is 231.12.21.132.

ChannelProperties
If you are familiar with JavaGroups, then this allows you to directly set the properties for the JavaGroups channel. Note that setting this property will cause the value of MulticastIP to be ignored. If you are interested, see the Javadocs for the default value.

Writing Cache-Aware Applications
Now that you have this fabulous caching engine built in to your web application, how do you make the most of it? Here are some tips:

Think about what data comprises 90% of all requests.
In the vast majority of web applications, at least 90% of all requests that arrive at the persistence engine are for the same small set of data. So this is the data you want to ensure you have cached. Don't worry so much about that other 10%.

Do not cache compound objects!
Suppose we had a method in the above persistence example called getAllPeople, that returned all people in the database. Should we cache the result of that query? It is often an unwise idea to do so. The problem is that one of those People objects could be updated and yet the cache of the getAllPeople query would not be expired. Of course, you could add extra code to insert, update and delete to clear the compound object from the cache, but it will quickly get messy.

Do not be afraid of single selects.
Suppose again that we are running code similar to the persistence example above. Now that objects are being cached efficiently, it is in our advantage to call the get often. Don't be afraid to replace database joins with mutliple calls to get(long key). This will also result in a more object-oriented use of your data model. As an example of this, suppose you had a one-to-many relationship between an object House and People. This modeled the fact that many people could live in a house. If you had the ID of a Person and wanted to select it and the House in which it lived, you may be tempted to use a join for this. Instead, perform a simple select for the Person with the get method, and then do the same for the House once you have its ID.

Have a means to clear all caches.
If you ever want to make direct database changes, it is often very handy to have a web-accessible admin screen that allows some or all of the caches to be manually cleared.

Credits
SwarmCache was written by John Watkinson (john at autobotcity dot com).
Code and ideas were contributed by Jason Carreira, Rajeev Kaul and Andr Schild. SwarmCache uses JavaGroups and Apache Jakarta Commons. The project is hosted by SourceForge.

SourceForge.net Logo

libswarmcache-java-1.0RC2+cvs20071027.orig/web/favicon.gif0000644000175000017500000000024107746416172022617 0ustar twernertwernerGIF89aeӴq5ymJdrI% :K;'M3۷!,N0Ik`8͔` dilK p,Cbx|pH,:Ȥryx8@Zv.x(tAn߂;libswarmcache-java-1.0RC2+cvs20071027.orig/web/favicon.ico0000644000175000017500000000157607746416236022641 0ustar twernertwernerh( @톭';K';K';K';K';K';K';K';K';K';K';K';K';K';K';K';K % % % % % % % % % % % % % % % %yyyyyyyyyyyyyyyy3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M3M5555555555555555ddddddddddddddddqqqqqqqqqqqqqqqqJmJmJmJmJmJmJmJmJmJmJmJmJmJmJmJmIrIrIrIrIrIrIrIrIrIrIrIrIrIrIrIr::::::::::::::::eeeeeeeeeeeeeeeelibswarmcache-java-1.0RC2+cvs20071027.orig/web/index.html0000644000175000017500000001143710134035753022474 0ustar twernertwerner SwarmCache - Cluster-aware Caching for Java
     SwarmCache
Cluster-aware Caching for Java
Overview
SwarmCache is a simple but effective distributed cache. It uses IP multicast to efficiently communicate with any number of hosts on a LAN. It is specifically designed for use by clustered, database-driven web applications. Such applications typically have many more read operations than write operations, which allows SwarmCache to deliver the greatest performance gains. SwarmCache uses JavaGroups internally to manage the membership and communications of its distributed cache.

News
SwarmCache 1.0 RC2 Released 10.25.2003
This release brings SwarmCache up to JGroups 2.2 compliance. It also solves a potential deadlock problem and provides a controlled shut-down mechanism.
SwarmCache Integrated with Hibernate 10.22.2003
SwarmCache will be available as a pluggable cache module for the fantastic relational persistence engine Hibernate. SwarmCache will allow Hibernate to perform well in a clustered application environment. Release 2.1 Beta 5 of Hibernate will be the first to include support for SwarmCache.
SwarmCache 1.0 RC1 Released 09.19.2003
This release cleans up the code base. There are very few functionality changes. The main addition is the HybridCache. This caching algorithm combines the benefits of the LRU and Automatic caching algorithms, making it the best choice for high-performance caching.
SwarmCache 0.91 Released 04.16.2003
This release is a fully-functional beta. No bugs are known, but it has not seen a lot of time in production systems. However, the previous release (0.9) has been used for some time on heavily-loaded production systems.

libswarmcache-java-1.0RC2+cvs20071027.orig/web/styles.css0000644000175000017500000000326707746407423022552 0ustar twernertwernerBODY { background-color: #FFFFFF; margin: 0pt 0pt 0pt 0pt; border: 0pt 0pt 0pt 0pt; padding:0pt 0pt 0pt 0pt; } BODY, P, DIV, SPAN, TD, LI { font: 10pt Arial, Helvetica, serif; color: #000000; } A { color: #6B81B8; text-decoration: none; } A:hover { color: #6B81B8; text-decoration: underline; } TABLE { margin: 0pt; border: 0pt; padding: 0pt; spacing: 0pt; } .border { background-color: #B2B2B2; } .title { font: 36pt Arial, Helvetica, SansSerif; /*font-weight: bold;*/ color: #FFFFFF; line-height: 80%; /*word-spacing: -0.1em;*/ } .subtitle { font: 11pt Arial, Helvetica, serif; font-style: italic; color: #000000; text-align: right; } .menuitem { background-color: #929292; padding: 2px; vertical-align: middle; } #menu A { color: #FFFFFF; text-decoration: none; } #menu A:hover { color: #FFFFFF; text-decoration: underline; } .contentTable { border-right: 1px dashed #929292; width: 600px; } .content { background-color: #FFFFFF; padding: 2px; vertical-align: top; } .heading { font: 16pt Arial, Helvetica, serif; color: #000000; font-weight: bold; } .subheading { font: 11pt Arial, Helvetica, serif; color: #000000; font-weight: bold; } .copyright { background-color: #FFFFFF; padding: 2px; text-align: right; vertical-align: bottom; font: 8pt Arial, Helvetica, serif; font-style: italic; } .newstable { border-top: 1px solid #929292; width: 100%; } .newsdate { color: #929292; font: 10pt Arial, Helvetica, serif; font-style: italic; text-align: right; } .newsheading { color: #000000; font: 10pt Arial, Helvetica, serif; font-weight: bold; } .newstext { padding-left: 10px; }libswarmcache-java-1.0RC2+cvs20071027.orig/web/tutorial.html0000644000175000017500000001640610134035753023231 0ustar twernertwerner SwarmCache - Cluster-aware Caching for Java
     SwarmCache
Cluster-aware Caching for Java
How It Works
The concept behind SwarmCache is fairly simple. Each server instantiates its own manager. For each type of object that the server wishes to cache, it instantiates a cache and adds it to the manager. The manager joins a multicast group and communicates with other managers in the group. Whenever an object is removed from a cache, the manager notifies all other managers in the group. Those managers then ensure that the object is removed from their respective caches. The result is that a server will not have in its cache a stale version of an object that has been updated or deleted on another server.

Note that the managers only need to communicate when an object is removed from a cache. This only happens when an object is updated or deleted. The managers do not co-operate beyond this. This means that the amount of inter-server communications is proportional to the amount of updates/deletes of the application. As the communications is multicast, it is not proportional to the number of caching hosts. Also notice that there is no "server"; all hosts are equal peers and they can come and go from the cache group as they please without affecting other group members. Thus the operation of the distributed cache is very robust.

Basic Usage
SwarmCache is designed to be integrated in to the persistence layer of a database-driven Java application. However, it could be useful for other types of applications. Once built in to the persistence engine, SwarmCache should be transparent to higher layers of the software. SwarmCache does not directly support transaction management. This can be accomplished by wrapping the cached objects and storing some additional transaction data. This will described and possibly implemented at a later date.

Swarmcache requires that swarmcache.jar, jgroups-all.jar, commons-collections.jar, and commons-logging.jar (included in the download) be in your classpath.

For most applications, it is sufficient to make use of the CacheFactory class to configure and use SwarmCache. Here is an example:

import net.sf.swarmcache.*;

...

CacheFactory cacheFactory;

...

// Configure and Initialize the cache manager
CacheConfiguration conf = new CacheConfiguration();
conf.setCacheType(CacheConfiguration.TYPE_LRU);
cacheFactory = new CacheFactory(conf);

...

// Create a new cache, using a name that describes
//  what kind of object we will store
ObjectCache cache = cacheFactory.createCache("People");

...

// Store something in the cache
String key = "0001";
String person = "John Watkinson";
cache.put(key, person);

...

// Retrieve something from the cache
String person = (String)cache.get("0001");
System.out.println(person);

...

// Clear an object from the cache
// (This results in the sending of a 
//  multicast message to other caching hosts)
cache.clear("0001");
String person = (String)cache.get("0001");
// The following will print 'null'
System.out.println(person);
The example is simple, but running this same code on multiple machines in a network will result in their caches being consistent.

Note that the keys used must be serializable objects-- they must implement java.io.Serializable. The objects themselves that are stored in the cache need not be serializable. And of course, the keys should not be large objects for transmission efficiency purposes.

In order to keep keys distinct, it is usually preferred to have one cache per type of object stored. In that case, it makes sense to follow the convention that the cache be named after the fully-qualified class name of the object type to be stored.

Usage in a Persistence Engine
Here is some skeleton code that demonstrates how SwarmCache could be integrated in to a persistence engine. The following class is responsible for persisting an object of type Person:

public class PersonEntity extends GenericEntity {

	ObjectCache cache;
	
	public PersonEntity(CacheFactory cacheFactory) {
		cache = cacheFactory.createCache("Person");
		// * Other initialization here
	}

	...
	
	public Person get(long key) {
		Long cacheKey = new Long(key);
		Person person = (Person)cache.get(cachekey);
		if (person == null) {
			// * Get the object from the database			
			if (person != null) {
				// Put it in the cache
				cache.put(cacheKey, person);
			}
		}
		return person;
	}
	
	...
	
	public void insert(Person person) {
		// * Do database insert
		// Add new object to cache
		Long cacheKey = new Long(person.getKey());
		cache.put(cacheKey, person);
	}
	
	...
	
	public void update(Person person) {
		// * Do database update
		// Remove object from cache
		// (This causes all caches in the group to be notified)
		Long cacheKey = new Long(person.getKey());
		cache.clear(cacheKey);
		// Re-add the object to the cache
		cache.put(cacheKey, person);
	}
	
	...
	
	public void delete(long key) {
		// * Do database delete
		// Remove object from cache
		// (This causes all caches in the group to be notified)
		Long cacheKey = new Long(key);
		cache.clear(cacheKey);		
	}
	
	...
	
}