Author: asmuts Date: Wed Sep 17 14:53:13 2008 New Revision: 696472 URL: http://svn.apache.org/viewvc?rev=696472&view=rev Log: Adding a rmi registry monitor and restore daemon.
Added: jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RegistryKeepAliveRunner.java jakarta/jcs/trunk/src/test/org/apache/jcs/auxiliary/remote/server/RegistryKeepAliveRunnerUnitTest.java Modified: jakarta/jcs/trunk/pom.xml jakarta/jcs/trunk/project.xml jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServer.java jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServerAttributes.java jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServerFactory.java jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheStartupServlet.java jakarta/jcs/trunk/src/test/org/apache/jcs/auxiliary/MockCacheEventLogger.java jakarta/jcs/trunk/xdocs/changes.xml Modified: jakarta/jcs/trunk/pom.xml URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/pom.xml?rev=696472&r1=696471&r2=696472&view=diff ============================================================================== --- jakarta/jcs/trunk/pom.xml (original) +++ jakarta/jcs/trunk/pom.xml Wed Sep 17 14:53:13 2008 @@ -36,7 +36,7 @@ <groupId>org.apache.jcs</groupId> <artifactId>jcs</artifactId> <packaging>pom</packaging> - <version>1.3.2.1-RC</version> + <version>1.3.2.2-RC</version> <name>Jakarta JCS</name> <url>http://jakarta.apache.org/jcs/</url> <inceptionYear>2002</inceptionYear> Modified: jakarta/jcs/trunk/project.xml URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/project.xml?rev=696472&r1=696471&r2=696472&view=diff ============================================================================== --- jakarta/jcs/trunk/project.xml (original) +++ jakarta/jcs/trunk/project.xml Wed Sep 17 14:53:13 2008 @@ -17,7 +17,7 @@ <pomVersion>3</pomVersion> <name>JCS</name> <id>jcs</id> - <currentVersion>1.3.2.1-RC</currentVersion> + <currentVersion>1.3.2.2-RC</currentVersion> <organization> <name>Apache Software Foundation</name> <url>http://jakarta.apache.org/</url> Added: jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RegistryKeepAliveRunner.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RegistryKeepAliveRunner.java?rev=696472&view=auto ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RegistryKeepAliveRunner.java (added) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RegistryKeepAliveRunner.java Wed Sep 17 14:53:13 2008 @@ -0,0 +1,177 @@ +package org.apache.jcs.auxiliary.remote.server; + +import java.rmi.Naming; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jcs.engine.logging.behavior.ICacheEventLogger; + +/** + * This class tries to keep the resitry alive. If if is able to create a registry, it will also + * rebind the remote cache server. + */ +public class RegistryKeepAliveRunner + implements Runnable +{ + /** The logger */ + private final static Log log = LogFactory.getLog( RegistryKeepAliveRunner.class ); + + /** Hostname of the registry */ + private String registryHost; + + /** the port on which to start the registry */ + private int registryPort; + + /** The name of the service to look for. */ + private String serviceName; + + /** An optional event logger */ + private ICacheEventLogger cacheEventLogger; + + /** + * @param registryHost - Hostname of the registry + * @param registryPort - the port on which to start the registry + * @param serviceName + */ + public RegistryKeepAliveRunner( String registryHost, int registryPort, String serviceName ) + { + this.registryHost = registryHost; + this.registryPort = registryPort; + this.serviceName = serviceName; + } + + /** + * Tries to lookup the server. If unsuccessful it will rebind the server using the factory + * rebind method. + * <p> + */ + public void run() + { + checkAndRestoreIfNeeded(); + } + + /** + * Tries to lookup the server. If unsuccessful it will rebind the server using the factory + * rebind method. + */ + protected void checkAndRestoreIfNeeded() + { + String registry = "//" + registryHost + ":" + registryPort + "/" + serviceName; + if ( log.isDebugEnabled() ) + { + log.debug( "looking up server " + registry ); + } + try + { + Object obj = Naming.lookup( registry ); + + // Successful connection to the remote server. + String message = "RMI registry looks fine. Found [" + obj + "] in registry [" + registry + "]"; + if ( cacheEventLogger != null ) + { + cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "Naming.lookup", message ); + } + if ( log.isDebugEnabled() ) + { + log.debug( message ); + } + obj = null; + } + catch ( Exception ex ) + { + // Failed to connect to the remote server. + String message = "Problem finding server at [" + registry + + "]. Will attempt to start registry and rebind."; + log.error( message, ex ); + if ( cacheEventLogger != null ) + { + cacheEventLogger.logError( "RegistryKeepAliveRunner", "Naming.lookup", message + ":" + ex.getMessage() ); + } + createAndRegister( registry ); + } + } + + /** + * Creates the registry and registers the server. + * <p> + * @param registry + */ + protected void createAndRegister( String registry ) + { + createReqistry( registry ); + + registerServer( registry ); + } + + /** + * Try to create the registry. Log errors + * <p> + * @param registry + */ + protected void createReqistry( String registry ) + { + try + { + LocateRegistry.createRegistry( registryPort ); + String message = "Successfully created registry [" + registry + "]."; + if ( cacheEventLogger != null ) + { + cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "createRegistry", message ); + } + } + catch ( RemoteException e ) + { + String message = "Could not start registry [" + registry + "]."; + log.error( message, e ); + if ( cacheEventLogger != null ) + { + cacheEventLogger.logError( "RegistryKeepAliveRunner", "createRegistry", message + ":" + e.getMessage() ); + } + } + } + + /** + * Try to rebind the server. + * <p> + * @param registry + */ + protected void registerServer( String registry ) + { + try + { + // try to rebind anyway + RemoteCacheServerFactory.registerServer( registryHost, registryPort, serviceName ); + String message = "Successfully rebound server to registry [" + registry + "]."; + if ( cacheEventLogger != null ) + { + cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "registerServer", message ); + } + if ( log.isInfoEnabled() ) + { + log.info( message ); + } + } + catch ( RemoteException e ) + { + String message = "Could not rebind server to registry [" + registry + "]."; + log.error( message, e ); + if ( cacheEventLogger != null ) + { + cacheEventLogger.logError( "RegistryKeepAliveRunner", "registerServer", message + ":" + + e.getMessage() ); + } + } + } + + /** + * Allows it to be injected. + * <p> + * @param cacheEventLogger + */ + public void setCacheEventLogger( ICacheEventLogger cacheEventLogger ) + { + this.cacheEventLogger = cacheEventLogger; + } +} Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServer.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServer.java?rev=696472&r1=696471&r2=696472&view=diff ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServer.java (original) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServer.java Wed Sep 17 14:53:13 2008 @@ -564,7 +564,8 @@ public Map getMultiple( String cacheName, Set keys, long requesterId ) throws IOException { - ICacheEvent cacheEvent = createICacheEvent( cacheName, (Serializable) keys, requesterId, ICacheEventLogger.GETMULTIPLE_EVENT ); + ICacheEvent cacheEvent = createICacheEvent( cacheName, (Serializable) keys, requesterId, + ICacheEventLogger.GETMULTIPLE_EVENT ); try { return processGetMultiple( cacheName, keys, requesterId ); @@ -1229,8 +1230,8 @@ } CacheEventQueueFactory fact = new CacheEventQueueFactory(); - ICacheEventQueue q = fact.createCacheEventQueue( listener, id, cacheName, remoteCacheServerAttributes.getEventQueuePoolName(), - remoteCacheServerAttributes.getEventQueueTypeFactoryCode() ); + ICacheEventQueue q = fact.createCacheEventQueue( listener, id, cacheName, remoteCacheServerAttributes + .getEventQueuePoolName(), remoteCacheServerAttributes.getEventQueueTypeFactoryCode() ); eventQMap.put( new Long( listener.getListenerId() ), q ); @@ -1453,7 +1454,7 @@ * <p> * @param item * @param requesterId - * @param eventName + * @param eventName * @return ICacheEvent */ private ICacheEvent createICacheEvent( ICacheElement item, long requesterId, String eventName ) @@ -1473,7 +1474,7 @@ * @param cacheName * @param key * @param requesterId - * @param eventName + * @param eventName * @return ICacheEvent */ private ICacheEvent createICacheEvent( String cacheName, Serializable key, long requesterId, String eventName ) @@ -1489,7 +1490,7 @@ /** * Logs an event if an event logger is configured. * <p> - * @param cacheEvent + * @param cacheEvent */ protected void logICacheEvent( ICacheEvent cacheEvent ) { Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServerAttributes.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServerAttributes.java?rev=696472&r1=696471&r2=696472&view=diff ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServerAttributes.java (original) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServerAttributes.java Wed Sep 17 14:53:13 2008 @@ -72,7 +72,22 @@ /** Connect and read timeout. */ private int rmiSocketFactoryTimeoutMillis = DEFAULT_RMI_SOCKET_FACTORY_TIMEOUT_MS; - + + /** Should we start the registry */ + private boolean DEFAULT_START_REGISTRY = true; + + /** Should we start the registry */ + private boolean startRegistry = DEFAULT_START_REGISTRY; + + /** Should we try to keep the registry alive */ + private boolean DEFAULT_USE_REGISTRY_KEEP_ALIVE = true; + + /** Should we try to keep the registry alive */ + private boolean useRegistryKeepAlive = DEFAULT_USE_REGISTRY_KEEP_ALIVE; + + /** The delay between runs */ + private long registryKeepAliveDelayMillis = 15 * 1000; + /** Default constructor for the RemoteCacheAttributes object */ public RemoteCacheServerAttributes() { @@ -369,6 +384,62 @@ } /** + * Should we try to keep the registry alive + * <p> + * @param useRegistryKeepAlive the useRegistryKeepAlive to set + */ + public void setUseRegistryKeepAlive( boolean useRegistryKeepAlive ) + { + this.useRegistryKeepAlive = useRegistryKeepAlive; + } + + /** + * Should we start the registry + * <p> + * @param startRegistry the startRegistry to set + */ + public void setStartRegistry( boolean startRegistry ) + { + this.startRegistry = startRegistry; + } + + /** + * Should we start the registry + * <p> + * @return the startRegistry + */ + public boolean isStartRegistry() + { + return startRegistry; + } + + /** + * Should we try to keep the registry alive + * <p> + * @return the useRegistryKeepAlive + */ + public boolean isUseRegistryKeepAlive() + { + return useRegistryKeepAlive; + } + + /** + * @param registryKeepAliveDelayMillis the registryKeepAliveDelayMillis to set + */ + public void setRegistryKeepAliveDelayMillis( long registryKeepAliveDelayMillis ) + { + this.registryKeepAliveDelayMillis = registryKeepAliveDelayMillis; + } + + /** + * @return the registryKeepAliveDelayMillis + */ + public long getRegistryKeepAliveDelayMillis() + { + return registryKeepAliveDelayMillis; + } + + /** * @return String details */ public String toString() @@ -384,6 +455,9 @@ buf.append( "\n localClusterConsistency = [" + this.getLocalClusterConsistency() + "]" ); buf.append( "\n configFileName = [" + this.getConfigFileName() + "]" ); buf.append( "\n rmiSocketFactoryTimeoutMillis = [" + this.getRmiSocketFactoryTimeoutMillis() + "]" ); + buf.append( "\n startRegistry = [" + this.isStartRegistry() + "]" ); + buf.append( "\n useRegistryKeepAlive = [" + this.isUseRegistryKeepAlive() + "]" ); + buf.append( "\n registryKeepAliveDelayMillis = [" + this.getRegistryKeepAliveDelayMillis() + "]" ); return buf.toString(); } } Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServerFactory.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServerFactory.java?rev=696472&r1=696471&r2=696472&view=diff ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServerFactory.java (original) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServerFactory.java Wed Sep 17 14:53:13 2008 @@ -24,6 +24,7 @@ import java.rmi.Naming; import java.rmi.NotBoundException; import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.util.Properties; @@ -35,6 +36,9 @@ import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheServiceAdmin; import org.apache.jcs.engine.logging.behavior.ICacheEventLogger; +import EDU.oswego.cs.dl.util.concurrent.ClockDaemon; +import EDU.oswego.cs.dl.util.concurrent.ThreadFactory; + /** * Provides remote cache services. This creates remote cache servers and can proxy command line * requests to a running server. @@ -49,7 +53,10 @@ private static RemoteCacheServer remoteCacheServer; /** The name of the service. */ - private static String serviceName; + private static String serviceName = IRemoteCacheConstants.REMOTE_CACHE_SERVICE_VAL; + + /** Executes the registry keep alive. */ + private static ClockDaemon keepAliveDaemon; /** Constructor for the RemoteCacheServerFactory object. */ private RemoteCacheServerFactory() @@ -113,7 +120,7 @@ log.info( "Creating server with these attributes: " + rcsa ); } - serviceName = rcsa.getRemoteServiceName(); + setServiceName( rcsa.getRemoteServiceName() ); RemoteUtils.configureCustomSocketFactory( rcsa.getRmiSocketFactoryTimeoutMillis() ); @@ -125,7 +132,49 @@ remoteCacheServer = new RemoteCacheServer( rcsa ); remoteCacheServer.setCacheEventLogger( cacheEventLogger ); - registerServer( host, port ); + // START THE REGISTRY + startTheRegistry( port, rcsa ); + + // REGISTER THE SERVER + registerServer( host, port, serviceName ); + + // KEEP THE REGISTRY ALIVE + if ( rcsa.isUseRegistryKeepAlive() ) + { + if ( keepAliveDaemon == null ) + { + keepAliveDaemon = new ClockDaemon(); + keepAliveDaemon.setThreadFactory( new MyThreadFactory() ); + } + RegistryKeepAliveRunner runner = new RegistryKeepAliveRunner( host, port, serviceName ); + runner.setCacheEventLogger( cacheEventLogger ); + keepAliveDaemon.executePeriodically( rcsa.getRegistryKeepAliveDelayMillis(), runner, false ); + } + } + } + + /** + * Starts the registry if needed + * <p> + * @param registryPort + * @param rcsa + */ + private static void startTheRegistry( int registryPort, RemoteCacheServerAttributes rcsa ) + { + if ( rcsa.isStartRegistry() ) + { + try + { + LocateRegistry.createRegistry( registryPort ); + } + catch ( RemoteException e ) + { + log.warn( "Problem creating registry. It may already be started. " + e.getMessage() ); + } + catch ( Throwable t ) + { + log.error( "Problem creating registry.", t ); + } } } @@ -135,11 +184,19 @@ * <p> * @param host * @param port + * @param serviceName * @throws RemoteException */ - protected static void registerServer( String host, int port ) + protected static void registerServer( String host, int port, String serviceName ) throws RemoteException { + if ( remoteCacheServer == null ) + { + String message = "Cannot register the server until it is created. Please start the server first."; + log.error( message ); + throw new RemoteException( message ); + } + if ( log.isInfoEnabled() ) { log.info( "Binding server to " + host + ":" + port + " with the name " + serviceName ); @@ -252,16 +309,16 @@ { return; } - log.info( "Unbinding host=" + host + ", port=" + port + ", serviceName=" + serviceName ); + log.info( "Unbinding host=" + host + ", port=" + port + ", serviceName=" + getServiceName() ); try { - Naming.unbind( "//" + host + ":" + port + "/" + serviceName ); + Naming.unbind( "//" + host + ":" + port + "/" + getServiceName() ); } catch ( MalformedURLException ex ) { // impossible case. throw new IllegalArgumentException( ex.getMessage() + "; host=" + host + ", port=" + port - + ", serviceName=" + serviceName ); + + ", serviceName=" + getServiceName() ); } catch ( NotBoundException ex ) { @@ -382,4 +439,41 @@ RemoteCacheServerFactory.startup( host, port, args.length > 0 ? args[0] : null ); log.debug( "main> done" ); } + + /** + * @param serviceName the serviceName to set + */ + protected static void setServiceName( String serviceName ) + { + RemoteCacheServerFactory.serviceName = serviceName; + } + + /** + * @return the serviceName + */ + protected static String getServiceName() + { + return serviceName; + } + + /** + * Allows us to set the daemon status on the clockdaemon + */ + static class MyThreadFactory + implements ThreadFactory + { + /** + * @param runner + * @return a new thread for the given Runnable + */ + public Thread newThread( Runnable runner ) + { + Thread t = new Thread( runner ); + String oldName = t.getName(); + t.setName( "JCS-RemoteCacheServerFactory-" + oldName ); + t.setDaemon( true ); + t.setPriority( Thread.MIN_PRIORITY ); + return t; + } + } } Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheStartupServlet.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheStartupServlet.java?rev=696472&r1=696471&r2=696472&view=diff ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheStartupServlet.java (original) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheStartupServlet.java Wed Sep 17 14:53:13 2008 @@ -70,8 +70,17 @@ /** The default port to start the registry on. */ private static final int DEFAULT_REGISTRY_PORT = 1101; - /** The default config file name */ - private static final String DEFAULT_PROPS_FILE_NAME = "cache.ccf"; + /** properties file name */ + private static final String DEFAULT_PROPS_FILE_NAME = "cache"; + + /** properties file Suffix */ + private static final String DEFAULT_PROPS_FILE_SUFFIX = "ccf"; + + /** properties file name, must set prior to calling get instance */ + private String propsFileName = DEFAULT_PROPS_FILE_NAME; + + /** properties file name, must set prior to calling get instance */ + private String fullPropsFileName = DEFAULT_PROPS_FILE_NAME + "." + DEFAULT_PROPS_FILE_SUFFIX; /** * Starts the registry and then tries to bind to it. @@ -91,7 +100,7 @@ try { - Properties props = PropertyLoader.loadProperties( DEFAULT_PROPS_FILE_NAME ); + Properties props = PropertyLoader.loadProperties( propsFileName ); if ( props != null ) { String portS = props.getProperty( "registry.port", String.valueOf( DEFAULT_REGISTRY_PORT ) ); @@ -147,7 +156,11 @@ try { - RemoteCacheServerFactory.startup( registryHost, registryPort, "/" + DEFAULT_PROPS_FILE_NAME ); + RemoteCacheServerFactory.startup( registryHost, registryPort, "/" + fullPropsFileName ); + if ( log.isInfoEnabled() ) + { + log.info( "Remote JCS Server started with properties from " + fullPropsFileName ); + } } catch ( IOException e ) { Modified: jakarta/jcs/trunk/src/test/org/apache/jcs/auxiliary/MockCacheEventLogger.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/test/org/apache/jcs/auxiliary/MockCacheEventLogger.java?rev=696472&r1=696471&r2=696472&view=diff ============================================================================== --- jakarta/jcs/trunk/src/test/org/apache/jcs/auxiliary/MockCacheEventLogger.java (original) +++ jakarta/jcs/trunk/src/test/org/apache/jcs/auxiliary/MockCacheEventLogger.java Wed Sep 17 14:53:13 2008 @@ -1,6 +1,8 @@ package org.apache.jcs.auxiliary; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; import org.apache.jcs.engine.behavior.ICacheElement; import org.apache.jcs.engine.logging.CacheEvent; @@ -25,6 +27,9 @@ /** times called */ public int errorEventCalls = 0; + + /** list of messages */ + public List errorMessages = new ArrayList(); /** * @param source @@ -52,6 +57,7 @@ public void logError( String source, String eventName, String errorMessage ) { errorEventCalls++; + errorMessages.add( errorMessage ); } /** Added: jakarta/jcs/trunk/src/test/org/apache/jcs/auxiliary/remote/server/RegistryKeepAliveRunnerUnitTest.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/test/org/apache/jcs/auxiliary/remote/server/RegistryKeepAliveRunnerUnitTest.java?rev=696472&view=auto ============================================================================== --- jakarta/jcs/trunk/src/test/org/apache/jcs/auxiliary/remote/server/RegistryKeepAliveRunnerUnitTest.java (added) +++ jakarta/jcs/trunk/src/test/org/apache/jcs/auxiliary/remote/server/RegistryKeepAliveRunnerUnitTest.java Wed Sep 17 14:53:13 2008 @@ -0,0 +1,31 @@ +package org.apache.jcs.auxiliary.remote.server; + +import junit.framework.TestCase; + +import org.apache.jcs.auxiliary.MockCacheEventLogger; + +/** Unit tests for the registry keep alive runner. */ +public class RegistryKeepAliveRunnerUnitTest + extends TestCase +{ + /** Verify that we get the appropriate event log */ + public void testCheckAndRestoreIfNeeded_failure() + { + // SETUP + String host = "localhost"; + int port = 1234; + String service = "doesn'texist"; + MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger(); + + RegistryKeepAliveRunner runner = new RegistryKeepAliveRunner( host, port, service ); + runner.setCacheEventLogger( cacheEventLogger ); + + // DO WORK + runner.checkAndRestoreIfNeeded(); + + // VERIFY + // 1 for the lookup, one for the rebind since the server isn't created yet + assertEquals( "error tally", 2, cacheEventLogger.errorEventCalls ); + //System.out.println( cacheEventLogger.errorMessages ); + } +} Modified: jakarta/jcs/trunk/xdocs/changes.xml URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/xdocs/changes.xml?rev=696472&r1=696471&r2=696472&view=diff ============================================================================== --- jakarta/jcs/trunk/xdocs/changes.xml (original) +++ jakarta/jcs/trunk/xdocs/changes.xml Wed Sep 17 14:53:13 2008 @@ -21,6 +21,10 @@ <body> <release version="1.4-dev" date="in SVN"> </release> + <release version="1.3.2.2" date="2008-09-17" description="tempbuild"> + <action dev="asmuts" type="update">Added a registry keep alive and + restore option for the remote cache server.</action> + </release> <release version="1.3.2.1" date="2008-09-08" description="tempbuild"> <action dev="asmuts" type="update">Made all disk cache managers handle custom event loggers.</action> --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]