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:
parent
cc231b19a1
commit
cb17099e7f
9 changed files with 1862 additions and 0 deletions
28
sandbox/endpoint-ehcache/META-INF/MANIFEST.MF
Normal file
28
sandbox/endpoint-ehcache/META-INF/MANIFEST.MF
Normal 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"
|
74
sandbox/endpoint-ehcache/pom.xml
Normal file
74
sandbox/endpoint-ehcache/pom.xml
Normal 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>
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
* <cachePeerListenerFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
|
||||
* properties="hostName=localhost, port=5000" />
|
||||
* </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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
741
sandbox/endpoint-ehcache/src/test/resources/ehcache.xml
Normal file
741
sandbox/endpoint-ehcache/src/test/resources/ehcache.xml
Normal 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>
|
46
sandbox/endpoint-ehcache/src/test/resources/ehcache1.xml
Normal file
46
sandbox/endpoint-ehcache/src/test/resources/ehcache1.xml
Normal 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>
|
48
sandbox/endpoint-ehcache/src/test/resources/ehcache2.xml
Normal file
48
sandbox/endpoint-ehcache/src/test/resources/ehcache2.xml
Normal 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>
|
Loading…
Reference in a new issue