Have a look at using ehcache in an endpoint registry impl. In sandbaox for now to avoid yet another impl that doesnt work properly in trunk.

git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@894790 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
antelder 2009-12-31 07:59:29 +00:00
parent cc231b19a1
commit cb17099e7f
9 changed files with 1862 additions and 0 deletions

View file

@ -0,0 +1,28 @@
Manifest-Version: 1.0
Private-Package: org.apache.tuscany.sca.xsd.impl;version="2.0.0"
SCA-Version: 1.1
Bundle-Name: Apache Tuscany SCA Tomcat Tribes Based EndPoint Registry
Bundle-Vendor: The Apache Software Foundation
Bundle-Version: 2.0.0
Bundle-ManifestVersion: 2
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-Description: Apache Tuscany SCA XSD Model
Bundle-SymbolicName: org.apache.tuscany.sca.endpoint.tribes
Bundle-DocURL: http://www.apache.org/
Bundle-RequiredExecutionEnvironment: J2SE-1.5,JavaSE-1.6
Import-Package: org.apache.catalina.tribes,
org.apache.catalina.tribes.group,
org.apache.catalina.tribes.group.interceptors,
org.apache.catalina.tribes.io,
org.apache.catalina.tribes.membership,
org.apache.catalina.tribes.tipis,
org.apache.catalina.tribes.transport,
org.apache.catalina.tribes.util,
org.apache.juli.logging;resolution:=optional,
org.apache.tuscany.sca.assembly;version="2.0.0",
org.apache.tuscany.sca.core;version="2.0.0",
org.apache.tuscany.sca.core.assembly.impl;scope=internal;version="2.0.0";resolution:=optional,
org.apache.tuscany.sca.management;version="2.0.0",
org.apache.tuscany.sca.policy;version="2.0.0",
org.apache.tuscany.sca.runtime;version="2.0.0"
Export-Package: org.apache.tuscany.sca.endpoint.tribes;version="2.0.0"

View file

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
-->
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.tuscany.sca</groupId>
<artifactId>tuscany-modules</artifactId>
<version>2.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>tuscany-endpoint-echache</artifactId>
<name>Apache Tuscany SCA EndPoint Registry using Ehcache</name>
<repositories>
<repository>
<id>sourceforge</id>
<url>http://oss.sonatype.org/content/groups/sourceforge/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>1.7.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.tuscany.sca</groupId>
<artifactId>tuscany-core-spi</artifactId>
<version>2.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.tuscany.sca</groupId>
<artifactId>tuscany-core</artifactId>
<version>2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tuscany.sca</groupId>
<artifactId>tuscany-deployment</artifactId>
<version>2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tuscany.sca</groupId>
<artifactId>tuscany-implementation-java-runtime</artifactId>
<version>2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,602 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.tuscany.sca.endpoint.ehcache;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.ExportException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Status;
import net.sf.ehcache.distribution.CacheManagerPeerListener;
import net.sf.ehcache.distribution.CacheReplicator;
import net.sf.ehcache.distribution.RMICacheManagerPeerListener;
import net.sf.ehcache.distribution.RMICachePeer;
import net.sf.ehcache.event.CacheEventListener;
/**
* A cache server which exposes available cache operations remotely through RMI.
* <p/>
* It acts as a Decorator to a Cache. It holds an instance of cache, which is a local cache it talks to.
* <p/>
* This class could specify a security manager with code like:
* <pre>
* if (System.getSecurityManager() == null) {
* System.setSecurityManager(new RMISecurityManager());
* }
* </pre>
* Doing so would require the addition of <code>grant</code> statements in the <code>java.policy</code> file.
* <p/>
* Per the JDK documentation: "If no security manager is specified no class loading, by RMI clients or servers, is allowed,
* aside from what can be found in the local CLASSPATH." The classpath of each instance of this class should have
* all required classes to enable distribution, so no remote classloading is required or desirable. Accordingly,
* no security manager is set and there are no special JVM configuration requirements.
* <p/>
* This class opens a ServerSocket. The dispose method should be called for orderly closure of that socket. This class
* has a shutdown hook which calls dispose() as a convenience feature for developers.
*
* @author Greg Luck
* @version $Id: RMICacheManagerPeerListener.java 1012 2009-08-20 04:23:00Z gregluck $
*/
public class TuscanyRMICacheManagerPeerListener implements CacheManagerPeerListener {
private static final Logger LOG = Logger.getLogger(TuscanyRMICacheManagerPeerListener.class.getName());
private static final int MINIMUM_SENSIBLE_TIMEOUT = 200;
private static final int NAMING_UNBIND_RETRY_INTERVAL = 400;
private static final int NAMING_UNBIND_MAX_RETRIES = 10;
/**
* The cache peers. The value is an RMICachePeer.
*/
protected final Map cachePeers = new HashMap();
/**
* status.
*/
protected Status status;
/**
* The RMI listener port
*/
protected Integer port;
private Registry registry;
private boolean registryCreated;
private final String hostName;
private CacheManager cacheManager;
private Integer socketTimeoutMillis;
private Integer remoteObjectPort;
/**
* Constructor with full arguments.
*
* @param hostName may be null, in which case the hostName will be looked up. Machines with multiple
* interfaces should specify this if they do not want it to be the default NIC.
* @param port a port in the range 1025 - 65536
* @param remoteObjectPort the port number on which the remote objects bound in the registry receive calls.
This defaults to a free port if not specified.
* @param cacheManager the CacheManager this listener belongs to
* @param socketTimeoutMillis TCP/IP Socket timeout when waiting on response
*/
public TuscanyRMICacheManagerPeerListener(String hostName, Integer port, Integer remoteObjectPort, CacheManager cacheManager,
Integer socketTimeoutMillis) throws UnknownHostException {
status = Status.STATUS_UNINITIALISED;
if (hostName != null && hostName.length() != 0) {
this.hostName = hostName;
if (hostName.equals("localhost")) {
LOG.log(Level.WARNING, "Explicitly setting the listener hostname to 'localhost' is not recommended. "
+ "It will only work if all CacheManager peers are on the same machine.");
}
} else {
this.hostName = calculateHostAddress();
}
if (port == null || port.intValue() == 0) {
assignFreePort(false);
} else {
this.port = port;
}
//by default is 0, which is ok.
this.remoteObjectPort = remoteObjectPort;
this.cacheManager = cacheManager;
if (socketTimeoutMillis == null || socketTimeoutMillis.intValue() < MINIMUM_SENSIBLE_TIMEOUT) {
throw new IllegalArgumentException("socketTimoutMillis must be a reasonable value greater than 200ms");
}
this.socketTimeoutMillis = socketTimeoutMillis;
}
/**
* Assigns a free port to be the listener port.
*
* @throws IllegalStateException if the statis of the listener is not {@link net.sf.ehcache.Status#STATUS_UNINITIALISED}
*/
protected void assignFreePort(boolean forced) throws IllegalStateException {
if (status != Status.STATUS_UNINITIALISED) {
throw new IllegalStateException("Cannot change the port of an already started listener.");
}
this.port = new Integer(this.getFreePort());
if (forced) {
LOG.log(Level.WARNING, "Resolving RMI port conflict by automatically using a free TCP/IP port to listen on: " + this.port);
} else {
LOG.log(Level.FINE, "Automatically finding a free TCP/IP port to listen on: " + this.port);
}
}
/**
* Calculates the host address as the default NICs IP address
*
* @throws UnknownHostException
*/
protected String calculateHostAddress() throws UnknownHostException {
return InetAddress.getLocalHost().getHostAddress();
}
/**
* Gets a free server socket port.
*
* @return a number in the range 1025 - 65536 that was free at the time this method was executed
* @throws IllegalArgumentException
*/
protected int getFreePort() throws IllegalArgumentException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(0);
return serverSocket.getLocalPort();
} catch (IOException e) {
throw new IllegalArgumentException("Could not acquire a free port number.");
} finally {
if (serverSocket != null && !serverSocket.isClosed()) {
try {
serverSocket.close();
} catch (Exception e) {
LOG.log(Level.FINE, "Error closing ServerSocket: " + e.getMessage());
}
}
}
}
/**
* {@inheritDoc}
*/
public void init() throws CacheException {
if (!status.equals(Status.STATUS_UNINITIALISED)) {
return;
}
RMICachePeer rmiCachePeer = null;
try {
startRegistry();
int counter = 0;
populateListOfRemoteCachePeers();
synchronized (cachePeers) {
for (Iterator iterator = cachePeers.values().iterator(); iterator.hasNext();) {
rmiCachePeer = (RMICachePeer) iterator.next();
bind(rmiCachePeer.getUrl(), rmiCachePeer);
counter++;
}
}
LOG.log(Level.FINE, counter + " RMICachePeers bound in registry for RMI listener");
status = Status.STATUS_ALIVE;
} catch (Exception e) {
String url = null;
if (rmiCachePeer != null) {
url = rmiCachePeer.getUrl();
}
throw new CacheException("Problem starting listener for RMICachePeer "
+ url + ". Initial cause was " + e.getMessage(), e);
}
}
/**
* Bind a cache peer
*
* @param rmiCachePeer
*/
protected void bind(String peerName, RMICachePeer rmiCachePeer) throws Exception {
Naming.rebind(peerName, rmiCachePeer);
}
/**
* Returns a list of bound objects.
* <p/>
* This should match the list of cachePeers i.e. they should always be bound
*
* @return a list of String representations of <code>RMICachePeer</code> objects
*/
protected String[] listBoundRMICachePeers() throws CacheException {
try {
return registry.list();
} catch (RemoteException e) {
throw new CacheException("Unable to list cache peers " + e.getMessage());
}
}
/**
* Returns a reference to the remote object.
*
* @param name the name of the cache e.g. <code>sampleCache1</code>
*/
protected Remote lookupPeer(String name) throws CacheException {
try {
return registry.lookup(name);
} catch (Exception e) {
throw new CacheException("Unable to lookup peer for replicated cache " + name + " "
+ e.getMessage());
}
}
/**
* Should be called on init because this is one of the last things that should happen on CacheManager startup.
*/
protected void populateListOfRemoteCachePeers() throws RemoteException {
String[] names = cacheManager.getCacheNames();
for (int i = 0; i < names.length; i++) {
String name = names[i];
Ehcache cache = cacheManager.getEhcache(name);
synchronized (cachePeers) {
if (cachePeers.get(name) == null) {
if (isDistributed(cache)) {
RMICachePeer peer = new RMICachePeer(cache, hostName, port, remoteObjectPort, socketTimeoutMillis);
cachePeers.put(name, peer);
}
}
}
}
}
/**
* Determine if the given cache is distributed.
*
* @param cache the cache to check
* @return true if a <code>CacheReplicator</code> is found in the listeners
*/
protected boolean isDistributed(Ehcache cache) {
Set listeners = cache.getCacheEventNotificationService().getCacheEventListeners();
for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
CacheEventListener cacheEventListener = (CacheEventListener) iterator.next();
if (cacheEventListener instanceof CacheReplicator) {
return true;
}
}
return false;
}
/**
* Start the rmiregistry.
* <p/>
* The alternative is to use the <code>rmiregistry</code> binary, in which case:
* <ol/>
* <li>rmiregistry running
* <li>-Djava.rmi.server.codebase="file:///Users/gluck/work/ehcache/build/classes/ file:///Users/gluck/work/ehcache/lib/commons-logging-1.0.4.jar"
* </ol>
*
* @throws RemoteException
*/
protected void startRegistry() throws RemoteException {
try {
registry = LocateRegistry.getRegistry(port.intValue());
try {
//may not be created. Let's create it.
registry = LocateRegistry.createRegistry(port.intValue());
registryCreated = true;
} catch (RemoteException e) {
registry.list();
}
} catch (ExportException exception) {
LOG.log(Level.SEVERE, "Exception starting RMI registry. Error was " + exception.getMessage(), exception);
}
}
/**
* Stop the rmiregistry if it was started by this class.
*
* @throws RemoteException
*/
protected void stopRegistry() throws RemoteException {
if (registryCreated) {
// the unexportObject call must be done on the Registry object returned
// by createRegistry not by getRegistry, a NoSuchObjectException is
// thrown otherwise
boolean success = UnicastRemoteObject.unexportObject(registry, true);
if (success) {
LOG.log(Level.FINE, "rmiregistry unexported.");
} else {
LOG.log(Level.WARNING, "Could not unexport rmiregistry.");
}
}
}
/**
* Stop the listener. It
* <ul>
* <li>unbinds the objects from the registry
* <li>unexports Remote objects
* </ul>
*/
public void dispose() throws CacheException {
if (!status.equals(Status.STATUS_ALIVE)) {
return;
}
try {
int counter = 0;
synchronized (cachePeers) {
for (Iterator iterator = cachePeers.values().iterator(); iterator.hasNext();) {
RMICachePeer rmiCachePeer = (RMICachePeer) iterator.next();
disposeRMICachePeer(rmiCachePeer);
counter++;
}
stopRegistry();
}
LOG.log(Level.FINE, counter + " RMICachePeers unbound from registry in RMI listener");
status = Status.STATUS_SHUTDOWN;
} catch (Exception e) {
throw new CacheException("Problem unbinding remote cache peers. Initial cause was " + e.getMessage(), e);
}
}
/**
* A template method to dispose an individual RMICachePeer. This consists of:
* <ol>
* <li>Unbinding the peer from the naming service
* <li>Unexporting the peer
* </ol>
* Override to specialise behaviour
*
* @param rmiCachePeer the cache peer to dispose of
* @throws Exception thrown if something goes wrong
*/
protected void disposeRMICachePeer(RMICachePeer rmiCachePeer) throws Exception {
unbind(rmiCachePeer);
}
/**
* Unbinds an RMICachePeer and unexports it.
* <p/>
* We unbind from the registry first before unexporting.
* Unbinding first removes the very small possibility of a client
* getting the object from the registry while we are trying to unexport it.
* <p/>
* This method may take up to 4 seconds to complete, if we are having trouble
* unexporting the peer.
*
* @param rmiCachePeer the bound and exported cache peer
* @throws Exception
*/
protected void unbind(RMICachePeer rmiCachePeer) throws Exception {
String url = rmiCachePeer.getUrl();
try {
Naming.unbind(url);
} catch (NotBoundException e) {
LOG.log(Level.WARNING, url + " not bound therefore not unbinding.");
}
// Try to gracefully unexport before forcing it.
boolean unexported = UnicastRemoteObject.unexportObject(rmiCachePeer, false);
for (int count = 1; (count < NAMING_UNBIND_MAX_RETRIES) && !unexported; count++) {
try {
Thread.sleep(NAMING_UNBIND_RETRY_INTERVAL);
} catch (InterruptedException ie) {
// break out of the unexportObject loop
break;
}
unexported = UnicastRemoteObject.unexportObject(rmiCachePeer, false);
}
// If we still haven't been able to unexport, force the unexport
// as a last resort.
if (!unexported) {
if (!UnicastRemoteObject.unexportObject(rmiCachePeer, true)) {
LOG.log(Level.WARNING, "Unable to unexport rmiCachePeer: " + rmiCachePeer.getUrl() + ". Skipping.");
}
}
}
/**
* All of the caches which are listening for remote changes.
*
* @return a list of <code>RMICachePeer</code> objects. The list if not live
*/
public List getBoundCachePeers() {
List cachePeerList = new ArrayList();
synchronized (cachePeers) {
for (Iterator iterator = cachePeers.values().iterator(); iterator.hasNext();) {
RMICachePeer rmiCachePeer = (RMICachePeer) iterator.next();
cachePeerList.add(rmiCachePeer);
}
}
return cachePeerList;
}
/**
* Returns the listener status.
*/
public Status getStatus() {
return status;
}
/**
* A listener will normally have a resource that only one instance can use at the same time,
* such as a port. This identifier is used to tell if it is unique and will not conflict with an
* existing instance using the resource.
*
* @return a String identifier for the resource
*/
public String getUniqueResourceIdentifier() {
return "RMI listener port: " + port;
}
/**
* If a conflict is detected in unique resource use, this method signals the listener to attempt
* automatic resolution of the resource conflict.
*
* @throws IllegalStateException if the statis of the listener is not {@link net.sf.ehcache.Status#STATUS_UNINITIALISED}
*/
public void attemptResolutionOfUniqueResourceConflict() throws IllegalStateException, CacheException {
assignFreePort(true);
}
/**
* The replication scheme this listener interacts with.
* Each peer provider has a scheme name, which can be used by caches to specify for replication and bootstrap purposes.
*
* @return the well-known scheme name, which is determined by the replication provider author.
*/
public String getScheme() {
return "RMI";
}
/**
* Called immediately after a cache has been added and activated.
* <p/>
* Note that the CacheManager calls this method from a synchronized method. Any attempt to call a synchronized
* method on CacheManager from this method will cause a deadlock.
* <p/>
* Note that activation will also cause a CacheEventListener status change notification from
* {@link net.sf.ehcache.Status#STATUS_UNINITIALISED} to {@link net.sf.ehcache.Status#STATUS_ALIVE}. Care should be
* taken on processing that notification because:
* <ul>
* <li>the cache will not yet be accessible from the CacheManager.
* <li>the addCaches methods whih cause this notification are synchronized on the CacheManager. An attempt to call
* {@link net.sf.ehcache.CacheManager#getCache(String)} will cause a deadlock.
* </ul>
* The calling method will block until this method returns.
* <p/>
* Repopulates the list of cache peers and rebinds the list.
* This method should be called if a cache is dynamically added
*
* @param cacheName the name of the <code>Cache</code> the operation relates to
* @see net.sf.ehcache.event.CacheEventListener
*/
public void notifyCacheAdded(String cacheName) throws CacheException {
if (LOG.isLoggable(Level.FINE)) {
LOG.log(Level.FINE, "Adding " + cacheName + " to RMI listener");
}
//Don't add if exists.
synchronized (cachePeers) {
if (cachePeers.get(cacheName) != null) {
return;
}
}
Ehcache cache = cacheManager.getEhcache(cacheName);
if (isDistributed(cache)) {
RMICachePeer rmiCachePeer = null;
String url = null;
try {
rmiCachePeer = new RMICachePeer(cache, hostName, port, remoteObjectPort, socketTimeoutMillis);
url = rmiCachePeer.getUrl();
bind(url, rmiCachePeer);
} catch (Exception e) {
throw new CacheException("Problem starting listener for RMICachePeer "
+ url + ". Initial cause was " + e.getMessage(), e);
}
synchronized (cachePeers) {
cachePeers.put(cacheName, rmiCachePeer);
}
}
if (LOG.isLoggable(Level.FINE)) {
LOG.log(Level.FINE, cachePeers.size() + " RMICachePeers bound in registry for RMI listener");
}
}
/**
* Called immediately after a cache has been disposed and removed. The calling method will block until
* this method returns.
* <p/>
* Note that the CacheManager calls this method from a synchronized method. Any attempt to call a synchronized
* method on CacheManager from this method will cause a deadlock.
* <p/>
* Note that a {@link net.sf.ehcache.event.CacheEventListener} status changed will also be triggered. Any attempt from that notification
* to access CacheManager will also result in a deadlock.
*
* @param cacheName the name of the <code>Cache</code> the operation relates to
*/
public void notifyCacheRemoved(String cacheName) {
if (LOG.isLoggable(Level.FINE)) {
LOG.log(Level.FINE, "Removing " + cacheName + " from RMI listener");
}
//don't remove if already removed.
synchronized (cachePeers) {
if (cachePeers.get(cacheName) == null) {
return;
}
}
RMICachePeer rmiCachePeer;
synchronized (cachePeers) {
rmiCachePeer = (RMICachePeer) cachePeers.remove(cacheName);
}
String url = null;
try {
unbind(rmiCachePeer);
} catch (Exception e) {
throw new CacheException("Error removing Cache Peer "
+ url + " from listener. Message was: " + e.getMessage(), e);
}
if (LOG.isLoggable(Level.FINE)) {
LOG.log(Level.FINE, cachePeers.size() + " RMICachePeers bound in registry for RMI listener");
}
}
/**
* Package local method for testing
*/
void addCachePeer(String name, RMICachePeer peer) {
synchronized (cachePeers) {
cachePeers.put(name, peer);
}
}
}

View file

@ -0,0 +1,113 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.tuscany.sca.endpoint.ehcache;
import java.net.UnknownHostException;
import java.util.Properties;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.distribution.CacheManagerPeerListener;
import net.sf.ehcache.distribution.CacheManagerPeerListenerFactory;
import net.sf.ehcache.distribution.RMICacheManagerPeerListener;
import net.sf.ehcache.util.PropertyUtil;
/**
* Builds a listener based on RMI.
* <p/>
* Expected configuration line:
* <p/>
* <code>
* &lt;cachePeerListenerFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
* properties="hostName=localhost, port=5000" /&gt;
* </code>
*
* @author Greg Luck
* @version $Id: RMICacheManagerPeerListenerFactory.java 1012 2009-08-20 04:23:00Z gregluck $
*/
public class TuscanyRMICacheManagerPeerListenerFactory extends CacheManagerPeerListenerFactory {
/**
* The default timeout for cache replication for a single replication action.
* This may need to be increased for large data transfers.
*/
public static final Integer DEFAULT_SOCKET_TIMEOUT_MILLIS = new Integer(120000);
private static final String HOSTNAME = "hostName";
private static final String PORT = "port";
private static final String REMOTE_OBJECT_PORT = "remoteObjectPort";
private static final String SOCKET_TIMEOUT_MILLIS = "socketTimeoutMillis";
/**
* @param properties implementation specific properties. These are configured as comma
* separated name value pairs in ehcache.xml
*/
public final CacheManagerPeerListener createCachePeerListener(CacheManager cacheManager, Properties properties)
throws CacheException {
String hostName = PropertyUtil.extractAndLogProperty(HOSTNAME, properties);
String portString = PropertyUtil.extractAndLogProperty(PORT, properties);
Integer port = null;
if (portString != null && portString.length() != 0) {
port = new Integer(portString);
} else {
port = new Integer(0);
}
//0 means any port in UnicastRemoteObject, so it is ok if not specified to make it 0
String remoteObjectPortString = PropertyUtil.extractAndLogProperty(REMOTE_OBJECT_PORT, properties);
Integer remoteObjectPort = null;
if (remoteObjectPortString != null && remoteObjectPortString.length() != 0) {
remoteObjectPort = new Integer(remoteObjectPortString);
} else {
remoteObjectPort = new Integer(0);
}
String socketTimeoutMillisString = PropertyUtil.extractAndLogProperty(SOCKET_TIMEOUT_MILLIS, properties);
Integer socketTimeoutMillis;
if (socketTimeoutMillisString == null || socketTimeoutMillisString.length() == 0) {
socketTimeoutMillis = DEFAULT_SOCKET_TIMEOUT_MILLIS;
} else {
socketTimeoutMillis = new Integer(socketTimeoutMillisString);
}
return doCreateCachePeerListener(hostName, port, remoteObjectPort, cacheManager, socketTimeoutMillis);
}
/**
* A template method to actually create the factory
*
* @param hostName
* @param port
* @param remoteObjectPort
* @param cacheManager
* @param socketTimeoutMillis @return a crate CacheManagerPeerListener
*/
protected CacheManagerPeerListener doCreateCachePeerListener(String hostName,
Integer port,
Integer remoteObjectPort,
CacheManager cacheManager,
Integer socketTimeoutMillis) {
try {
return new TuscanyRMICacheManagerPeerListener(hostName, port, remoteObjectPort, cacheManager, socketTimeoutMillis);
} catch (UnknownHostException e) {
throw new CacheException("Unable to create CacheManagerPeerListener. Initial cause was " + e.getMessage(), e);
}
}
}

View file

@ -0,0 +1,17 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpointRegistry;ranking=150,address=228.0.0.100,port=50000,timeout=50,scheme=tribes

View file

@ -0,0 +1,193 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.tuscany.sca.endpoint.tribes;
import java.util.Properties;
import junit.framework.Assert;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.bootstrap.BootstrapCacheLoader;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.config.Configuration;
import net.sf.ehcache.config.ConfigurationHelper;
import net.sf.ehcache.config.FactoryConfiguration;
import net.sf.ehcache.config.TerracottaConfiguration;
import net.sf.ehcache.distribution.CacheManagerPeerProvider;
import net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory;
import net.sf.ehcache.distribution.RMICacheManagerPeerListener;
import net.sf.ehcache.distribution.RMICacheReplicatorFactory;
import net.sf.ehcache.event.CacheEventListener;
import net.sf.ehcache.event.RegisteredEventListeners;
import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
import org.junit.Test;
public class RegistryTestCase {
@Test
public void foo() throws InterruptedException {
Cache cache2 = createCache2("ehcache2.xml");
// Thread.sleep(4000);
Cache cache1 = createCache2("ehcache1.xml");
cache1.put(new Element("key1", "bla1"));
Thread.sleep(400);
Assert.assertEquals("bla1", cache2.get("key1").getObjectValue());
cache2.put(new Element("k2", "foo2"));
Thread.sleep(400);
Assert.assertEquals("foo2", cache1.get("k2").getObjectValue());
}
private Cache createCache2(String file) {
CacheManager manager = new CacheManager("target/test-classes/" + file);
Cache test = manager.getCache("sampleDistributedCache1");
manager.addCache("foo");
Cache test2 = manager.getCache("foo");
return test;
}
// final Ehcache createCache(CacheConfiguration cacheConfiguration) {
// boolean terracottaClustered = false;
// String terracottaValueMode = null;
// boolean terracottaCoherentReads = true;
// TerracottaConfiguration tcConfiguration = cacheConfiguration.getTerracottaConfiguration();
// if (tcConfiguration != null) {
// terracottaClustered = tcConfiguration.isClustered();
// terracottaValueMode = tcConfiguration.getValueMode().name();
// terracottaCoherentReads = tcConfiguration.getCoherentReads();
// }
//
// Ehcache cache = new Cache(cacheConfiguration.name,
// cacheConfiguration.maxElementsInMemory,
// cacheConfiguration.memoryStoreEvictionPolicy,
// cacheConfiguration.overflowToDisk,
// getDiskStorePath(),
// cacheConfiguration.eternal,
// cacheConfiguration.timeToLiveSeconds,
// cacheConfiguration.timeToIdleSeconds,
// cacheConfiguration.diskPersistent,
// cacheConfiguration.diskExpiryThreadIntervalSeconds,
// null,
// null,
// cacheConfiguration.maxElementsOnDisk,
// cacheConfiguration.diskSpoolBufferSizeMB,
// cacheConfiguration.clearOnFlush,
// terracottaClustered,
// terracottaValueMode,
// terracottaCoherentReads);
// RegisteredEventListeners listeners = cache.getCacheEventNotificationService();
// registerCacheListeners(cacheConfiguration, listeners);
// registerCacheExtensions(cacheConfiguration, cache);
// BootstrapCacheLoader bootstrapCacheLoader = createBootstrapCacheLoader(
// cacheConfiguration.getBootstrapCacheLoaderFactoryConfiguration());
// cache.setBootstrapCacheLoader(bootstrapCacheLoader);
// registerCacheLoaders(cacheConfiguration, cache);
// cache = applyCacheExceptionHandler(cacheConfiguration, cache);
// return cache;
// }
// private Ehcache create(CacheManager manager, String name) {
// ConfigurationHelper ch = new ConfigurationHelper(manager, null);
// CacheConfiguration cc = new CacheConfiguration();
// cc.
//
//
// Ehcache cache = new Cache(name,
// 10000,
// MemoryStoreEvictionPolicy.LRU,
// false,
// "",
// true,
// 0,
// 0,
// false,
// 0,
// null,
// null,
// 0,
// 0,
// false,
// false,
// null,
// false);
// RegisteredEventListeners listeners = cache.getCacheEventNotificationService();
// Properties properties = new Properties();
// properties.put("asynchronousReplicationIntervalMillis", "100");
// listeners.registerListener(new RMICacheReplicatorFactory().createCacheEventListener(properties));
//// registerCacheListeners(cacheConfiguration, listeners);
//// registerCacheExtensions(cacheConfiguration, cache);
// cache.setBootstrapCacheLoader(new RMIBootstrapCacheLoaderFactory().createBootstrapCacheLoader(null));
//// registerCacheLoaders(cacheConfiguration, cache);
// // cache = applyCacheExceptionHandler(cacheConfiguration, cache);
// return cache;
// }
private Cache createCache(int port, boolean multicast, String remotes) {
Configuration config = new Configuration();
if (remotes != null && remotes.length() > 0) {
FactoryConfiguration factory = new FactoryConfiguration();
factory.setClass("net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory");
factory.setPropertySeparator(",");
factory.setProperties("peerDiscovery=manual,rmiUrls=//" + remotes);
config.addCacheManagerPeerProviderFactory(factory);
}
// <cacheManagerPeerProviderFactory
// class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
// properties="peerDiscovery=automatic,
// multicastGroupAddress=230.0.0.1,
// multicastGroupPort=4446, timeToLive=1"/>
//-->
if (multicast) {
FactoryConfiguration factory = new FactoryConfiguration();
factory.setClass("net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory");
factory.setPropertySeparator(",");
factory.setProperties("peerDiscovery=automatic,multicastGroupAddress=230.0.0.1,multicastGroupPort=4446,timeToLive=1");
config.addCacheManagerPeerProviderFactory(factory);
}
RMICacheManagerPeerListener xxx;
FactoryConfiguration factoryx = new FactoryConfiguration();
factoryx.setClass("net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory");
factoryx.setPropertySeparator(",");
factoryx.setProperties("hostname=192.168.0.101,port=" + port);
config.addCacheManagerPeerListenerFactory(factoryx);
CacheConfiguration defaultCacheConfiguration = new CacheConfiguration();
defaultCacheConfiguration.setDiskPersistent(false);
config.setDefaultCacheConfiguration(defaultCacheConfiguration);
CacheManager singletonManager = new CacheManager(config);
CacheManagerPeerProvider pp = singletonManager.getCacheManagerPeerProvider("RMI");
Cache memoryOnlyCache = new Cache("testCache", 5000, false, false, 5, 2);
// CacheEventListener cacheEventListener = new CacheEventListener();
// memoryOnlyCache.getCacheEventNotificationService().registerListener(cacheEventListener);
singletonManager.addCache(memoryOnlyCache);
Cache test = singletonManager.getCache("testCache");
return test;
}
}

View file

@ -0,0 +1,741 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
CacheManager Configuration
==========================
An ehcache.xml corresponds to a single CacheManager.
See instructions below or the ehcache schema (ehcache.xsd) on how to configure.
System property tokens can be specified in this file which are replaced when the configuration
is loaded. For example multicastGroupPort=${multicastGroupPort} can be replaced with the
System property either from an environment variable or a system property specified with a
command line switch such as -DmulticastGroupPort=4446.
The attributes of <ehcache> are:
* name - an optional name for the CacheManager. The name is optional and primarily used
for documentation or to distinguish Terracotta clustered cache state. With Terracotta
clustered caches, a combination of CacheManager name and cache name uniquely identify a
particular cache store in the Terracotta clustered memory.
* updateCheck - an optional boolean flag specifying whether this CacheManager should check
for new versions of Ehcache over the Internet. If not specified, updateCheck="true".
* monitoring - an optional setting that determines whether the CacheManager should
automatically register the SampledCacheMBean with the system MBean server.
Currently, this monitoring is only useful when using Terracotta clustering and using the
Terracotta Developer Console. With the "autodetect" value, the presence of Terracotta clustering
will be detected and monitoring, via the Developer Console, will be enabled. Other allowed values
are "on" and "off". The default is "autodetect". This setting does not perform any function when
used with JMX monitors.
-->
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true" monitoring="autodetect">
<!--
DiskStore configuration
=======================
The diskStore element is optional. To turn off disk store path creation, comment out the diskStore
element below.
Configure it if you have overflowToDisk or diskPersistent enabled for any cache.
If it is not configured, and a cache is created which requires a disk store, a warning will be
issued and java.io.tmpdir will automatically be used.
diskStore has only one attribute - "path". It is the path to the directory where
.data and .index files will be created.
If the path is one of the following Java System Property it is replaced by its value in the
running VM. For backward compatibility these are not specified without being enclosed in the ${token}
replacement syntax.
The following properties are translated:
* user.home - User's home directory
* user.dir - User's current working directory
* java.io.tmpdir - Default temp file path
* ehcache.disk.store.dir - A system property you would normally specify on the command line
e.g. java -Dehcache.disk.store.dir=/u01/myapp/diskdir ...
Subdirectories can be specified below the property e.g. java.io.tmpdir/one
-->
<diskStore path="java.io.tmpdir"/>
<!--
CacheManagerEventListener
=========================
Specifies a CacheManagerEventListenerFactory which is notified when Caches are added
or removed from the CacheManager.
The attributes of CacheManagerEventListenerFactory are:
* class - a fully qualified factory class name
* properties - comma separated properties having meaning only to the factory.
Sets the fully qualified class name to be registered as the CacheManager event listener.
The events include:
* adding a Cache
* removing a Cache
Callbacks to listener methods are synchronous and unsynchronized. It is the responsibility
of the implementer to safely handle the potential performance and thread safety issues
depending on what their listener is doing.
If no class is specified, no listener is created. There is no default.
-->
<cacheManagerEventListenerFactory class="" properties=""/>
<!--
CacheManagerPeerProvider
========================
(For distributed operation)
Specifies a CacheManagerPeerProviderFactory which will be used to create a
CacheManagerPeerProvider, which discovers other CacheManagers in the cluster.
One or more providers can be configured. The first one in the ehcache.xml is the default, which is used
for replication and bootstrapping.
The attributes of cacheManagerPeerProviderFactory are:
* class - a fully qualified factory class name
* properties - comma separated properties having meaning only to the factory.
Providers are available for RMI, JGroups and JMS as shown following.
RMICacheManagerPeerProvider
+++++++++++++++++++++++++++
Ehcache comes with a built-in RMI-based distribution system with two means of discovery of
CacheManager peers participating in the cluster:
* automatic, using a multicast group. This one automatically discovers peers and detects
changes such as peers entering and leaving the group
* manual, using manual rmiURL configuration. A hardcoded list of peers is provided at
configuration time.
Configuring Automatic Discovery:
Automatic discovery is configured as per the following example:
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="hostName=fully_qualified_hostname_or_ip,
peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446, timeToLive=32"/>
Valid properties are:
* peerDiscovery (mandatory) - specify "automatic"
* multicastGroupAddress (mandatory) - specify a valid multicast group address
* multicastGroupPort (mandatory) - specify a dedicated port for the multicast heartbeat
traffic
* timeToLive - specify a value between 0 and 255 which determines how far the packets will
propagate.
By convention, the restrictions are:
0 - the same host
1 - the same subnet
32 - the same site
64 - the same region
128 - the same continent
255 - unrestricted
* hostName - the hostname or IP of the interface to be used for sending and receiving multicast packets
(relevant to mulithomed hosts only)
Configuring Manual Discovery:
Manual discovery requires a unique configuration per host. It is contains a list of rmiURLs for the peers, other
than itself. So, if we have server1, server2 and server3 the configuration will be:
In server1's configuration:
<cacheManagerPeerProviderFactory class=
"net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server2:40000/sampleCache1|//server3:40000/sampleCache1
| //server2:40000/sampleCache2|//server3:40000/sampleCache2"
propertySeparator="," />
In server2's configuration:
<cacheManagerPeerProviderFactory class=
"net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server1:40000/sampleCache1|//server3:40000/sampleCache1
| //server1:40000/sampleCache2|//server3:40000/sampleCache2"
propertySeparator="," />
In server3's configuration:
<cacheManagerPeerProviderFactory class=
"net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server1:40000/sampleCache1|//server2:40000/sampleCache1
| //server1:40000/sampleCache2|//server2:40000/sampleCache2"
propertySeparator="," />
Valid properties are:
* peerDiscovery (mandatory) - specify "manual"
* rmiUrls (mandatory) - specify a pipe separated list of rmiUrls, in the form
//hostname:port
* hostname (optional) - the hostname is the hostname of the remote CacheManager peer. The port is the listening
port of the RMICacheManagerPeerListener of the remote CacheManager peer.
JGroupsCacheManagerPeerProvider
+++++++++++++++++++++++++++++++
<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"
properties="connect=UDP(mcast_addr=231.12.21.132;mcast_port=45566;ip_ttl=32;
mcast_send_buf_size=150000;mcast_recv_buf_size=80000):
PING(timeout=2000;num_initial_members=6):
MERGE2(min_interval=5000;max_interval=10000):
FD_SOCK:VERIFY_SUSPECT(timeout=1500):
pbcast.NAKACK(gc_lag=10;retransmit_timeout=3000):
UNICAST(timeout=5000):
pbcast.STABLE(desired_avg_gossip=20000):
FRAG:
pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=false)"
propertySeparator="::"
/>
The only property necessary is the connect String used by jgroups to configure itself. Refer to the Jgroups documentation for explanation
of all the protocols. The example above uses UDP multicast. If the connect property is not specified the default JGroups connection will be
used.
JMSCacheManagerPeerProviderFactory
++++++++++++++++++++++++++++++++++
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.jms.JMSCacheManagerPeerProviderFactory"
properties="..."
propertySeparator=","
/>
The JMS PeerProviderFactory uses JNDI to maintain message queue independence. Refer to the manual for full configuration
examples using ActiveMQ and Open Message Queue.
Valid properties are:
* initialContextFactoryName (mandatory) - the name of the factory used to create the message queue initial context.
* providerURL (mandatory) - the JNDI configuration information for the service provider to use.
* topicConnectionFactoryBindingName (mandatory) - the JNDI binding name for the TopicConnectionFactory
* topicBindingName (mandatory) - the JNDI binding name for the topic name
* getQueueBindingName (mandatory only if using jmsCacheLoader) - the JNDI binding name for the queue name
* securityPrincipalName - the JNDI java.naming.security.principal
* securityCredentials - the JNDI java.naming.security.credentials
* urlPkgPrefixes - the JNDI java.naming.factory.url.pkgs
* userName - the user name to use when creating the TopicConnection to the Message Queue
* password - the password to use when creating the TopicConnection to the Message Queue
* acknowledgementMode - the JMS Acknowledgement mode for both publisher and subscriber. The available choices are
AUTO_ACKNOWLEDGE, DUPS_OK_ACKNOWLEDGE and SESSION_TRANSACTED. The default is AUTO_ACKNOWLEDGE.
-->
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic,
multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446, timeToLive=1"
propertySeparator=","
/>
<!--
CacheManagerPeerListener
========================
(Enable for distributed operation)
Specifies a CacheManagerPeerListenerFactory which will be used to create a
CacheManagerPeerListener, which listens for messages from cache replicators participating in the cluster.
The attributes of cacheManagerPeerListenerFactory are:
class - a fully qualified factory class name
properties - comma separated properties having meaning only to the factory.
Ehcache comes with a built-in RMI-based distribution system. The listener component is
RMICacheManagerPeerListener which is configured using
RMICacheManagerPeerListenerFactory. It is configured as per the following example:
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=fully_qualified_hostname_or_ip,
port=40001,
remoteObjectPort=40002,
socketTimeoutMillis=120000"
propertySeparator="," />
All properties are optional. They are:
* hostName - the hostName of the host the listener is running on. Specify
where the host is multihomed and you want to control the interface over which cluster
messages are received. Defaults to the host name of the default interface if not
specified.
* port - the port the RMI Registry listener listens on. This defaults to a free port if not specified.
* remoteObjectPort - the port number on which the remote objects bound in the registry receive calls.
This defaults to a free port if not specified.
* socketTimeoutMillis - the number of ms client sockets will stay open when sending
messages to the listener. This should be long enough for the slowest message.
If not specified it defaults to 120000ms.
-->
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>
<!--
TerracottaConfig
========================
(Enable for Terracotta clustered operation)
Note: You need to install and run one or more Terracotta servers to use Terracotta clustering.
See http://www.terracotta.org/web/display/orgsite/Download.
Specifies a TerracottaConfig which will be used to configure the Terracotta
runtime for this CacheManager.
Configuration can be specified in two main ways: by reference to a source of
configuration or by use of an embedded Terracotta configuration file.
To specify a reference to a source (or sources) of configuration, use the url
attribute. The url attribute must contain a comma-separated list of:
* path to Terracotta configuration file (usually named tc-config.xml)
* URL to Terracotta configuration file
* <server host>:<port> of running Terracotta Server instance
Simplest example for pointing to a Terracotta server on this machine:
<terracottaConfig url="localhost:9510"/>
Example using a path to Terracotta configuration file:
<terracottaConfig url="/app/config/tc-config.xml"/>
Example using a URL to a Terracotta configuration file:
<terracottaConfig url="http://internal/ehcache/app/tc-config.xml"/>
Example using multiple Terracotta server instance URLs (for fault tolerance):
<terracottaConfig url="host1:9510,host2:9510,host3:9510"/>
To embed a Terracotta configuration file within the ehcache configuration, simply
place a normal Terracotta XML config within the <terracottaConfig> element.
Example:
<terracottaConfig>
<tc-config>
<servers>
<server host="server1" name="s1"/>
<server host="server2" name="s2"/>
</servers>
<clients>
<logs>app/logs-%i</logs>
</clients>
</tc-config>
</terracottaConfig>
For more information on the Terracotta configuration, see the Terracotta documentation.
-->
<!--
Cache configuration
===================
The following attributes are required.
name:
Sets the name of the cache. This is used to identify the cache. It must be unique.
maxElementsInMemory:
Sets the maximum number of objects that will be created in memory
maxElementsOnDisk:
Sets the maximum number of objects that will be maintained in the DiskStore
The default value is zero, meaning unlimited.
eternal:
Sets whether elements are eternal. If eternal, timeouts are ignored and the
element is never expired.
overflowToDisk:
Sets whether elements can overflow to disk when the memory store
has reached the maxInMemory limit.
The following attributes and elements are optional.
timeToIdleSeconds:
Sets the time to idle for an element before it expires.
i.e. The maximum amount of time between accesses before an element expires
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that an Element can idle for infinity.
The default value is 0.
timeToLiveSeconds:
Sets the time to live for an element before it expires.
i.e. The maximum time between creation time and when an element expires.
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that and Element can live for infinity.
The default value is 0.
diskPersistent:
Whether the disk store persists between restarts of the Virtual Machine.
The default value is false.
diskExpiryThreadIntervalSeconds:
The number of seconds between runs of the disk expiry thread. The default value
is 120 seconds.
diskSpoolBufferSizeMB:
This is the size to allocate the DiskStore for a spool buffer. Writes are made
to this area and then asynchronously written to disk. The default size is 30MB.
Each spool buffer is used only by its cache. If you get OutOfMemory errors consider
lowering this value. To improve DiskStore performance consider increasing it. Trace level
logging in the DiskStore will show if put back ups are occurring.
clearOnFlush:
whether the MemoryStore should be cleared when flush() is called on the cache.
By default, this is true i.e. the MemoryStore is cleared.
memoryStoreEvictionPolicy:
Policy would be enforced upon reaching the maxElementsInMemory limit. Default
policy is Least Recently Used (specified as LRU). Other policies available -
First In First Out (specified as FIFO) and Less Frequently Used
(specified as LFU)
Cache elements can also contain sub elements which take the same format of a factory class
and properties. Defined sub-elements are:
* cacheEventListenerFactory - Enables registration of listeners for cache events, such as
put, remove, update, and expire.
* bootstrapCacheLoaderFactory - Specifies a BootstrapCacheLoader, which is called by a
cache on initialisation to prepopulate itself.
* cacheExtensionFactory - Specifies a CacheExtension, a generic mechansim to tie a class
which holds a reference to a cache to the cache lifecycle.
* cacheExceptionHandlerFactory - Specifies a CacheExceptionHandler, which is called when
cache exceptions occur.
* cacheLoaderFactory - Specifies a CacheLoader, which can be used both asynchronously and
synchronously to load objects into a cache. More than one cacheLoaderFactory element
can be added, in which case the loaders form a chain which are executed in order. If a
loader returns null, the next in chain is called.
RMI Cache Replication
+++++++++++++++++++++
Each cache that will be distributed needs to set a cache event listener which replicates
messages to the other CacheManager peers. For the built-in RMI implementation this is done
by adding a cacheEventListenerFactory element of type RMICacheReplicatorFactory to each
distributed cache's configuration as per the following example:
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicatePutsViaCopy=false,
replicateUpdates=true,
replicateUpdatesViaCopy=true,
replicateRemovals=true
asynchronousReplicationIntervalMillis=<number of milliseconds"
propertySeparator="," />
The RMICacheReplicatorFactory recognises the following properties:
* replicatePuts=true|false - whether new elements placed in a cache are
replicated to others. Defaults to true.
* replicatePutsViaCopy=true|false - whether the new elements are
copied to other caches (true), or whether a remove message is sent. Defaults to true.
* replicateUpdates=true|false - whether new elements which override an
element already existing with the same key are replicated. Defaults to true.
* replicateRemovals=true - whether element removals are replicated. Defaults to true.
* replicateAsynchronously=true | false - whether replications are
asynchronous (true) or synchronous (false). Defaults to true.
* replicateUpdatesViaCopy=true | false - whether the new elements are
copied to other caches (true), or whether a remove message is sent. Defaults to true.
* asynchronousReplicationIntervalMillis=<number of milliseconds> - The asynchronous
replicator runs at a set interval of milliseconds. The default is 1000. The minimum
is 10. This property is only applicable if replicateAsynchronously=true
JGroups Replication
+++++++++++++++++++
For the Jgroups replication this is done with:
<cacheEventListenerFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
properties="replicateAsynchronously=true, replicatePuts=true,
replicateUpdates=true, replicateUpdatesViaCopy=false,
replicateRemovals=true,asynchronousReplicationIntervalMillis=1000"/>
This listener supports the same properties as the RMICacheReplicationFactory.
JMS Replication
+++++++++++++++
For JMS-based replication this is done with:
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.jms.JMSCacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=true,
replicateRemovals=true,
asynchronousReplicationIntervalMillis=1000"
propertySeparator=","/>
This listener supports the same properties as the RMICacheReplicationFactory.
Cluster Bootstrapping
+++++++++++++++++++++
Bootstrapping a cluster may use a different mechanism to replication. e.g you can mix
JMS replication with bootstrap via RMI - just make sure you have the cacheManagerPeerProviderFactory
and cacheManagerPeerListenerFactory configured.
There are two bootstrapping mechanisms: RMI and JGroups.
RMI Bootstrap
The RMIBootstrapCacheLoader bootstraps caches in clusters where RMICacheReplicators are
used. It is configured as per the following example:
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=true, maximumChunkSizeBytes=5000000"
propertySeparator="," />
The RMIBootstrapCacheLoaderFactory recognises the following optional properties:
* bootstrapAsynchronously=true|false - whether the bootstrap happens in the background
after the cache has started. If false, bootstrapping must complete before the cache is
made available. The default value is true.
* maximumChunkSizeBytes=<integer> - Caches can potentially be very large, larger than the
memory limits of the VM. This property allows the bootstraper to fetched elements in
chunks. The default chunk size is 5000000 (5MB).
JGroups Bootstrap
Here is an example of bootstrap configuration using JGroups boostrap:
<bootstrapCacheLoaderFactory class="net.sf.ehcache.distribution.jgroups.JGroupsBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=true"/>
The configuration properties are the same as for RMI above. Note that JGroups bootstrap only supports
asynchronous bootstrap mode.
Cache Exception Handling
By default, most cache operations will propagate a runtime CacheException on failure. An
interceptor, using a dynamic proxy, may be configured so that a CacheExceptionHandler can
be configured to intercept Exceptions. Errors are not intercepted.
It is configured as per the following example:
<cacheExceptionHandlerFactory class="com.example.ExampleExceptionHandlerFactory"
properties="logLevel=FINE"/>
Caches with ExceptionHandling configured are not of type Cache, but are of type Ehcache only,
and are not available using CacheManager.getCache(), but using CacheManager.getEhcache().
Cache Loader
A default CacheLoader may be set which loads objects into the cache through asynchronous and
synchronous methods on Cache. This is different to the bootstrap cache loader, which is used
only in distributed caching.
It is configured as per the following example:
<cacheLoaderFactory class="com.example.ExampleCacheLoaderFactory"
properties="type=int,startCounter=10"/>
Cache Extension
CacheExtensions are a general purpose mechanism to allow generic extensions to a Cache.
CacheExtensions are tied into the Cache lifecycle.
CacheExtensions are created using the CacheExtensionFactory which has a
<code>createCacheCacheExtension()</code> method which takes as a parameter a
Cache and properties. It can thus call back into any public method on Cache, including, of
course, the load methods.
Extensions are added as per the following example:
<cacheExtensionFactory class="com.example.FileWatchingCacheRefresherExtensionFactory"
properties="refreshIntervalMillis=18000, loaderTimeout=3000,
flushPeriod=whatever, someOtherProperty=someValue ..."/>
Terracotta Clustering
Cache elements can also contain information about whether the cache can be clustered with Terracotta.
The <terracotta> sub-element has the following attributes:
* clustered=true|false - indicates whether this cache should be clustered with Terracotta. By
default, if the <terracotta> element is included, clustered=true.
* valueMode=serialization|identity - indicates whether this cache should be clustered with
serialized copies of the values or using Terracotta identity mode. By default, values will
be cached in serialization mode which is similar to other replicated Ehcache modes. The identity
mode is only available in certain Terracotta deployment scenarios and will maintain actual object
identity of the keys and values across the cluster. In this case, all users of a value retrieved from
the cache are using the same clustered value and must provide appropriate locking for any changes
made to the value (or objects referred to by the value).
* coherentReads=true|false - indicates whether this cache should have coherent reads with guaranteed
consistency across the cluster. By default, this setting is true. If you set this property to
false, reads are allowed to check the local value without locking, possibly seeing stale values.
This is a performance optimization with weaker concurrency guarantees and should generally be used
with caches that contain read-only data or where the application can tolerate reading stale
data.
Simplest example to indicate clustering:
<terracotta/>
To indicate the cache should not be clustered (or remove the <terracotta> element altogether):
<terracotta clustered="false"/>
To indicate the cache should be clustered using identity mode:
<terracotta clustered="true" valueMode="identity"/>
-->
<!--
Mandatory Default Cache configuration. These settings will be applied to caches
created programmtically using CacheManager.add(String cacheName).
The defaultCache has an implicit name "default" which is a reserved cache name.
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<!--
Sample caches. Following are some example caches. Remove these before use.
-->
<!--
Sample cache named sampleCache1
This cache contains a maximum in memory of 10000 elements, and will expire
an element if it is idle for more than 5 minutes and lives for more than
10 minutes.
If there are more than 10000 elements it will overflow to the
disk cache, which in this configuration will go to wherever java.io.tmp is
defined on your system. On a standard Linux system this will be /tmp"
-->
<cache name="sampleCache1"
maxElementsInMemory="10000"
maxElementsOnDisk="1000"
eternal="false"
overflowToDisk="true"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
/>
<!--
Sample cache named sampleCache2
This cache has a maximum of 1000 elements in memory. There is no overflow to disk, so 1000
is also the maximum cache size. Note that when a cache is eternal, timeToLive and
timeToIdle are not used and do not need to be specified.
-->
<cache name="sampleCache2"
maxElementsInMemory="1000"
eternal="true"
overflowToDisk="false"
memoryStoreEvictionPolicy="FIFO"
/>
<!--
Sample cache named sampleCache3. This cache overflows to disk. The disk store is
persistent between cache and VM restarts. The disk expiry thread interval is set to 10
minutes, overriding the default of 2 minutes.
-->
<cache name="sampleCache3"
maxElementsInMemory="500"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="1"
memoryStoreEvictionPolicy="LFU"
/>
<!--
Sample distributed cache named sampleDistributedCache1.
This cache replicates using defaults.
It also bootstraps from the cluster, using default properties.
-->
<cache name="sampleDistributedCache1"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="100"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
</cache>
<!--
Sample distributed cache named sampleDistributedCache2.
This cache replicates using specific properties.
It only replicates updates and does so synchronously via copy
-->
<cache name="sampleDistributedCache2"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="100"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=false, replicatePuts=false,
replicatePutsViaCopy=false, replicateUpdates=true,
replicateUpdatesViaCopy=true, replicateRemovals=false"/>
</cache>
<!--
Sample distributed cache named sampleDistributedCache3.
This cache replicates using defaults except that the asynchronous replication
interval is set to 200ms.
This one includes / and # which were illegal in ehcache 1.5.
-->
<cache name="sample/DistributedCache3"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="100"
overflowToDisk="true">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="asynchronousReplicationIntervalMillis=200"/>
</cache>
<!--
Sample Terracotta clustered cache named sampleTerracottaCache.
This cache uses Terracotta to cluster the contents of the cache.
-->
<!--
<cache name="sampleTerracottaCache"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="1800"
overflowToDisk="false">
<terracotta/>
</cache>
-->
</ehcache>

View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="false" monitoring="autodetect">
<cacheManagerEventListenerFactory class="" properties=""/>
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//localhost:40009/sampleDistributedCache1"
propertySeparator="," />
<cacheManagerPeerListenerFactory
class="org.apache.tuscany.sca.endpoint.ehcache.TuscanyRMICacheManagerPeerListenerFactory"
properties="localhost,
port=40001,
remoteObjectPort=40002,
socketTimeoutMillis=120000"
propertySeparator="," />
<defaultCache
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="asynchronousReplicationIntervalMillis=100"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=false "/>
</defaultCache>
<cache name="sampleDistributedCache1"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="asynchronousReplicationIntervalMillis=100"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=false "/>
</cache>
</ehcache>

View file

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true" monitoring="autodetect">
<cacheManagerEventListenerFactory class="" properties=""/>
<cacheManagerPeerProviderFactory class=
"net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//localhost:40001/sampleDistributedCache1"
propertySeparator="," />
<cacheManagerPeerListenerFactory
class="org.apache.tuscany.sca.endpoint.ehcache.TuscanyRMICacheManagerPeerListenerFactory"
properties="localhost,
port=40009,
remoteObjectPort=40008,
socketTimeoutMillis=120000"
propertySeparator="," />
<defaultCache
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="asynchronousReplicationIntervalMillis=100"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=false "/>
</defaultCache>
<cache name="sampleDistributedCache1"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="asynchronousReplicationIntervalMillis=100"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=false "/>
</cache>
</ehcache>