JBoss Cache SVN: r4253 - pojo/trunk/src/main/java/org/jboss/cache and 1 other directory.
by jbosscache-commits@lists.jboss.org
Author: jason.greene(a)jboss.com
Date: 2007-08-14 18:45:16 -0400 (Tue, 14 Aug 2007)
New Revision: 4253
Added:
pojo/trunk/src/main/java/org/jboss/cache/pojo/
Removed:
core/trunk/src-old/org/jboss/cache/pojo/
Log:
Relocate source files
Copied: pojo/trunk/src/main/java/org/jboss/cache/pojo (from rev 4250, core/trunk/src-old/org/jboss/cache/pojo)
17 years, 4 months
JBoss Cache SVN: r4252 - in core/trunk: src/main/java/org/jboss/cache and 1 other directories.
by jbosscache-commits@lists.jboss.org
Author: jason.greene(a)jboss.com
Date: 2007-08-14 18:38:44 -0400 (Tue, 14 Aug 2007)
New Revision: 4252
Added:
core/trunk/src/main/java/org/jboss/cache/AbstractNode.java
core/trunk/src/main/java/org/jboss/cache/Cache.java
core/trunk/src/main/java/org/jboss/cache/CacheException.java
core/trunk/src/main/java/org/jboss/cache/CacheFactory.java
core/trunk/src/main/java/org/jboss/cache/CacheImpl.java
core/trunk/src/main/java/org/jboss/cache/CacheSPI.java
core/trunk/src/main/java/org/jboss/cache/CacheStatus.java
core/trunk/src/main/java/org/jboss/cache/ConsoleListener.java
core/trunk/src/main/java/org/jboss/cache/DefaultCacheFactory.java
core/trunk/src/main/java/org/jboss/cache/Fqn.java
core/trunk/src/main/java/org/jboss/cache/FqnComparator.java
core/trunk/src/main/java/org/jboss/cache/InvocationContext.java
core/trunk/src/main/java/org/jboss/cache/Modification.java
core/trunk/src/main/java/org/jboss/cache/Node.java
core/trunk/src/main/java/org/jboss/cache/NodeFactory.java
core/trunk/src/main/java/org/jboss/cache/NodeNotExistsException.java
core/trunk/src/main/java/org/jboss/cache/NodeSPI.java
core/trunk/src/main/java/org/jboss/cache/RPCManager.java
core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
core/trunk/src/main/java/org/jboss/cache/Region.java
core/trunk/src/main/java/org/jboss/cache/RegionImpl.java
core/trunk/src/main/java/org/jboss/cache/RegionManager.java
core/trunk/src/main/java/org/jboss/cache/RegionNotEmptyException.java
core/trunk/src/main/java/org/jboss/cache/ReplicationException.java
core/trunk/src/main/java/org/jboss/cache/ReplicationQueue.java
core/trunk/src/main/java/org/jboss/cache/SuspectException.java
core/trunk/src/main/java/org/jboss/cache/TreeCacheViewMBean.java
core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
core/trunk/src/main/java/org/jboss/cache/Version.java
core/trunk/src/main/java/org/jboss/cache/VersionedNode.java
core/trunk/src/main/java/org/jboss/cache/buddyreplication/
core/trunk/src/main/java/org/jboss/cache/config/
core/trunk/src/main/java/org/jboss/cache/demo/
core/trunk/src/main/java/org/jboss/cache/eviction/
core/trunk/src/main/java/org/jboss/cache/factories/
core/trunk/src/main/java/org/jboss/cache/interceptors/
core/trunk/src/main/java/org/jboss/cache/jmx/
core/trunk/src/main/java/org/jboss/cache/loader/
core/trunk/src/main/java/org/jboss/cache/lock/
core/trunk/src/main/java/org/jboss/cache/marshall/
core/trunk/src/main/java/org/jboss/cache/notifications/
core/trunk/src/main/java/org/jboss/cache/optimistic/
core/trunk/src/main/java/org/jboss/cache/statetransfer/
core/trunk/src/main/java/org/jboss/cache/transaction/
core/trunk/src/main/java/org/jboss/cache/util/
core/trunk/src/main/java/org/jboss/cache/xml/
Removed:
core/trunk/src-old/org/jboss/cache/AbstractNode.java
core/trunk/src-old/org/jboss/cache/Cache.java
core/trunk/src-old/org/jboss/cache/CacheException.java
core/trunk/src-old/org/jboss/cache/CacheFactory.java
core/trunk/src-old/org/jboss/cache/CacheImpl.java
core/trunk/src-old/org/jboss/cache/CacheSPI.java
core/trunk/src-old/org/jboss/cache/CacheStatus.java
core/trunk/src-old/org/jboss/cache/ConsoleListener.java
core/trunk/src-old/org/jboss/cache/DefaultCacheFactory.java
core/trunk/src-old/org/jboss/cache/Fqn.java
core/trunk/src-old/org/jboss/cache/FqnComparator.java
core/trunk/src-old/org/jboss/cache/InvocationContext.java
core/trunk/src-old/org/jboss/cache/Modification.java
core/trunk/src-old/org/jboss/cache/Node.java
core/trunk/src-old/org/jboss/cache/NodeFactory.java
core/trunk/src-old/org/jboss/cache/NodeNotExistsException.java
core/trunk/src-old/org/jboss/cache/NodeSPI.java
core/trunk/src-old/org/jboss/cache/RPCManager.java
core/trunk/src-old/org/jboss/cache/RPCManagerImpl.java
core/trunk/src-old/org/jboss/cache/Region.java
core/trunk/src-old/org/jboss/cache/RegionImpl.java
core/trunk/src-old/org/jboss/cache/RegionManager.java
core/trunk/src-old/org/jboss/cache/RegionNotEmptyException.java
core/trunk/src-old/org/jboss/cache/ReplicationException.java
core/trunk/src-old/org/jboss/cache/ReplicationQueue.java
core/trunk/src-old/org/jboss/cache/SuspectException.java
core/trunk/src-old/org/jboss/cache/TreeCacheViewMBean.java
core/trunk/src-old/org/jboss/cache/UnversionedNode.java
core/trunk/src-old/org/jboss/cache/Version.java
core/trunk/src-old/org/jboss/cache/VersionedNode.java
core/trunk/src-old/org/jboss/cache/buddyreplication/
core/trunk/src-old/org/jboss/cache/config/
core/trunk/src-old/org/jboss/cache/demo/
core/trunk/src-old/org/jboss/cache/eviction/
core/trunk/src-old/org/jboss/cache/factories/
core/trunk/src-old/org/jboss/cache/interceptors/
core/trunk/src-old/org/jboss/cache/jmx/
core/trunk/src-old/org/jboss/cache/loader/
core/trunk/src-old/org/jboss/cache/lock/
core/trunk/src-old/org/jboss/cache/marshall/
core/trunk/src-old/org/jboss/cache/notifications/
core/trunk/src-old/org/jboss/cache/optimistic/
core/trunk/src-old/org/jboss/cache/statetransfer/
core/trunk/src-old/org/jboss/cache/transaction/
core/trunk/src-old/org/jboss/cache/util/
core/trunk/src-old/org/jboss/cache/xml/
Modified:
core/trunk/pom.xml
Log:
Relocate source files
Modified: core/trunk/pom.xml
===================================================================
--- core/trunk/pom.xml 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/pom.xml 2007-08-14 22:38:44 UTC (rev 4252)
@@ -44,6 +44,21 @@
<version>1.7.0</version>
</dependency>
<dependency>
+ <groupId>net.jcip</groupId>
+ <artifactId>jcip-annotations</artifactId>
+ <version>1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>beanshell</groupId>
+ <artifactId>bsh</artifactId>
+ <version>2.0b4</version>
+ </dependency>
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-j2ee</artifactId>
+ <version>4.2.0.GA</version>
+ </dependency>
+ <dependency>
<groupId>org.jboss.microcontainer</groupId>
<artifactId>jboss-aop-mc-int</artifactId>
<version>2.0.0-SNAPSHOT</version>
Copied: core/trunk/src/main/java/org/jboss/cache/AbstractNode.java (from rev 4250, core/trunk/src-old/org/jboss/cache/AbstractNode.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/AbstractNode.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/AbstractNode.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,58 @@
+/**
+ *
+ */
+package org.jboss.cache;
+
+import java.util.Map;
+
+/**
+ * Base class for {@link UnversionedNode}.
+ *
+ * @author manik
+ */
+public abstract class AbstractNode<K, V> implements Node<K, V>
+{
+ protected boolean deleted;
+ protected Map<Object, Node<K, V>> children;
+ protected Fqn fqn;
+
+ public boolean isDeleted()
+ {
+ return deleted;
+ }
+
+ public void markAsDeleted(boolean marker)
+ {
+ markAsDeleted(marker, false);
+ }
+
+ public void markAsDeleted(boolean marker, boolean recursive)
+ {
+ deleted = marker;
+ if (recursive && children != null)
+ {
+ synchronized (this)
+ {
+ for (Node child : children.values())
+ {
+ ((AbstractNode) child).markAsDeleted(marker, true);
+ }
+ }
+ }
+ }
+
+ public boolean equals(Object another)
+ {
+ if (another instanceof AbstractNode)
+ {
+ AbstractNode anotherNode = (AbstractNode) another;
+ return fqn == null && anotherNode.fqn == null || !(fqn == null || anotherNode.fqn == null) && fqn.equals(anotherNode.fqn);
+ }
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return fqn.hashCode();
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/Cache.java (from rev 4250, core/trunk/src-old/org/jboss/cache/Cache.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Cache.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/Cache.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,373 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.cache.config.Configuration;
+import org.jgroups.Address;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Interface for a Cache where data mappings are grouped and stored in a tree data
+ * structure consisting of {@link Node}s.
+ * <p/>
+ * This is the central construct and basic client API of JBoss Cache and is used for
+ * cache-wide operations.
+ * <p/>
+ * The cache is constructed using a {@link CacheFactory} and is started
+ * using {@link #start}, if not already started by the CacheFactory.
+ * <p/>
+ * Once constructed, the Cache interface can be used to create or access {@link Node}s, which contain data. Once references
+ * to {@link Node}s are obtained, data can be stored in them,
+ * <p/>
+ * As a convenience (and mainly to provide a familiar API to the older JBoss Cache 1.x.x releases) methods are provided that
+ * operate directly on nodes.
+ * <ul>
+ * <li>{@link #put(Fqn,Object,Object)} </li>
+ * <li>{@link #put(Fqn,java.util.Map)} </li>
+ * <li>{@link #get(Fqn,Object)} </li>
+ * <li>{@link #remove(Fqn,Object)} </li>
+ * <li>{@link #removeNode(Fqn)} </li>
+ * </ul>
+ * <p/>
+ * A simple example of usage:
+ * <pre>
+ * // creates with default settings and starts the cache
+ * Cache cache = DefaultCacheFactory.getInstance().createCache();
+ * Fqn personRecords = Fqn.fromString("/org/mycompany/personRecords");
+ * <p/>
+ * Node rootNode = cache.getRoot();
+ * Node personRecordsNode = rootNode.addChild(personRecords);
+ * <p/>
+ * // now add some person records.
+ * Fqn peterGriffin = Fqn.fromString("/peterGriffin");
+ * Fqn stewieGriffin = Fqn.fromString("/stewieGriffin");
+ * <p/>
+ * // the addChild() API uses relative Fqns
+ * Node peter = personRecordsNode.addChild(peterGriffin);
+ * Node stewie = personRecordsNode.addChild(stewieGriffin);
+ * <p/>
+ * peter.put("name", "Peter Griffin");
+ * peter.put("ageGroup", "MidLifeCrisis");
+ * peter.put("homicidal", Boolean.FALSE);
+ * <p/>
+ * stewie.put("name", "Stewie Griffin");
+ * stewie.put("ageGroup", "Infant");
+ * stewie.put("homicidal", Boolean.TRUE);
+ * <p/>
+ * peter.getFqn().toString(); // will print out /org/mycompany/personRecords/peterGriffin
+ * stewie.getFqn().toString(); // will print out /org/mycompany/personRecords/stewieGriffin
+ * <p/>
+ * peter.getFqn().getParent().equals(stewie.getFqn().getParent()); // will return true
+ * <p/>
+ * </pre>
+ * <p/>
+ * For more information, please read the JBoss Cache user guide and tutorial, available on <a href="http://labs.jboss.com/portal/jbosscache/docs/index.html" target="_BLANK">the JBoss Cache documentation site</a>,
+ * and look through the examples <a href="http://labs.jboss.com/portal/jbosscache/download/index.html" target="_BLANK">shipped with the JBoss Cache distribution</a>.
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ * @see Node
+ * @see CacheFactory
+ * @since 2.0.0
+ */
+@ThreadSafe
+public interface Cache<K, V>
+{
+ /**
+ * Retrieves the configuration of this cache.
+ *
+ * @return the configuration.
+ */
+ Configuration getConfiguration();
+
+ /**
+ * Returns the root node of this cache.
+ *
+ * @return the root node
+ */
+ Node<K, V> getRoot();
+
+ /**
+ * Adds a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object to the entire cache. The object passed in needs to be properly annotated with the
+ * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
+ *
+ * @param listener listener to add
+ */
+ void addCacheListener(Object listener);
+
+ /**
+ * Adds a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object to a given region. The object passed in needs to be properly annotated with the
+ * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
+ *
+ * @param region region to add listener to
+ * @param listener listener to add
+ */
+ void addCacheListener(Fqn<?> region, Object listener);
+
+ /**
+ * Removes a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object from the cache. The object passed in needs to be properly annotated with the
+ * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
+ *
+ * @param listener listener to remove
+ */
+ void removeCacheListener(Object listener);
+
+ /**
+ * Removes a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object from a given region. The object passed in needs to be properly annotated with the
+ * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
+ *
+ * @param region region from which to remove listener
+ * @param listener listener to remove
+ */
+ void removeCacheListener(Fqn<?> region, Object listener);
+
+ /**
+ * Retrieves an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to the cache.
+ *
+ * @return an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to the cache.
+ */
+ Set<Object> getCacheListeners();
+
+ /**
+ * Retrieves an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to a specific region.
+ *
+ * @return an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to a specific region.
+ */
+ Set<Object> getCacheListeners(Fqn<?> region);
+
+ /**
+ * Associates the specified value with the specified key for a {@link Node} in this cache.
+ * If the {@link Node} previously contained a mapping for this key, the old value is replaced by the specified value.
+ *
+ * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
+ * @param key key with which the specified value is to be associated.
+ * @param value value to be associated with the specified key.
+ * @return previous value associated with specified key, or <code>null</code> if there was no mapping for key.
+ * A <code>null</code> return can also indicate that the Node previously associated <code>null</code> with the specified key, if the implementation supports null values.
+ */
+ V put(Fqn<?> fqn, K key, V value);
+
+ /**
+ * Under special operating behavior, associates the value with the specified key for a node identified by the Fqn passed in.
+ * <ul>
+ * <li> Only goes through if the node specified does not exist; no-op otherwise.</i>
+ * <li> Force asynchronous mode for replication or invalidation to prevent any blocking.</li>
+ * <li> 0ms lock timeout to prevent any blocking here either. If the lock is not acquired, this method is a no-op, and swallows the timeout exception.</li>
+ * <li> Ongoing transactions are suspended before this call, so failures here will not affect any ongoing transactions.</li>
+ * <li> Errors and exceptions are 'silent' - logged at a much lower level than normal, and this method does not throw exceptions</li>
+ * </ul>
+ * This method is for caching data that has an external representation in storage, where, concurrent modification and
+ * transactions are not a consideration, and failure to put the data in the cache should be treated as a 'suboptimal outcome'
+ * rather than a 'failing outcome'.
+ * <p/>
+ * An example of when this method is useful is when data is read from, for example, a legacy datastore, and is cached before
+ * returning the data to the caller. Subsequent calls would prefer to get the data from the cache and if the data doesn't exist
+ * in the cache, fetch again from the legacy datastore.
+ * <p/>
+ * See <a href="http://jira.jboss.com/jira/browse/JBCACHE-848">JBCACHE-848</a> for details around this feature.
+ * <p/>
+ *
+ * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
+ * @param key key with which the specified value is to be associated.
+ * @param value value to be associated with the specified key.
+ */
+ void putForExternalRead(Fqn<?> fqn, K key, V value);
+
+ /**
+ * Copies all of the mappings from the specified map to a {@link Node}.
+ *
+ * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to copy the data to
+ * @param data mappings to copy
+ */
+ void put(Fqn<?> fqn, Map<K, V> data);
+
+ /**
+ * Removes the mapping for this key from a Node.
+ * Returns the value to which the Node previously associated the key, or
+ * <code>null</code> if the Node contained no mapping for this key.
+ *
+ * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
+ * @param key key whose mapping is to be removed from the Node
+ * @return previous value associated with specified Node's key
+ */
+ V remove(Fqn<?> fqn, K key);
+
+ /**
+ * Removes a {@link Node} indicated by absolute {@link Fqn}.
+ *
+ * @param fqn {@link Node} to remove
+ * @return true if the node was removed, false if the node was not found
+ */
+ boolean removeNode(Fqn<?> fqn);
+
+ /**
+ * Convenience method that allows for direct access to the data in a {@link Node}.
+ *
+ * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
+ * @param key key under which value is to be retrieved.
+ * @return returns data held under specified key in {@link Node} denoted by specified Fqn.
+ */
+ V get(Fqn<?> fqn, K key);
+
+ /**
+ * Eviction call that evicts the specified {@link Node} from memory.
+ *
+ * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be evicted.
+ * @param recursive evicts children as well
+ */
+ void evict(Fqn<?> fqn, boolean recursive);
+
+ /**
+ * Retrieves a {@link Region} for a given {@link Fqn}. If the region does not exist,
+ * and <li>createIfAbsent</li> is true, then one is created.
+ * <p/>
+ * If not, parent Fqns will be consulted in turn for registered regions, gradually working up to
+ * Fqn.ROOT. If no regions are defined in any of the parents either, a null is returned.
+ *
+ * @param fqn Fqn that is contained in a region.
+ * @param createIfAbsent If true, will create a new associated region if not found.
+ * @return a MarshRegion. Null if none is found.
+ * @throws UnsupportedOperationException if the region cannot be defined.
+ * @see Region
+ */
+ Region getRegion(Fqn<?> fqn, boolean createIfAbsent);
+
+ /**
+ * Removes a region denoted by the Fqn passed in.
+ *
+ * @param fqn of the region to remove
+ * @return true if a region did exist and was removed; false otherwise.
+ */
+ boolean removeRegion(Fqn<?> fqn);
+
+ /**
+ * Lifecycle method that initializes configuration state, the root node, etc.
+ *
+ * @throws CacheException if there are creation problems
+ */
+ void create() throws CacheException;
+
+ /**
+ * Lifecycle method that starts the cache loader,
+ * starts cache replication, starts the region manager, etc., and (if configured) warms the cache using a
+ * state transfer or cache loader preload.
+ *
+ * @throws CacheException if there are startup problems
+ */
+ void start() throws CacheException;
+
+ /**
+ * Lifecycle method that stops the cache, including replication,
+ * clustering, cache loading, notifications, etc., and clears all cache in-memory state.
+ * <p/>
+ * State can be reconstituted by using either a cache loader or state transfer when the cache starts again.
+ */
+ void stop();
+
+ /**
+ * Lifecycle method that destroys the cache and removes any interceptors/configuration elements.
+ * Cache can then be restarted (potentially after reconfiguring) using {@link #create()} and {@link #start()}.
+ */
+ void destroy();
+
+ /**
+ * Gets where the cache currently is its lifecycle transitions.
+ *
+ * @return the CacheStatus. Will not return <code>null</code>.
+ */
+ CacheStatus getCacheStatus();
+
+ /**
+ * @return the current invocation context for the current invocation and cache instance.
+ * @see org.jboss.cache.InvocationContext
+ */
+ InvocationContext getInvocationContext();
+
+ /**
+ * Sets the passed in {@link org.jboss.cache.InvocationContext} as current.
+ *
+ * @param ctx invocation context to use
+ */
+ void setInvocationContext(InvocationContext ctx);
+
+ /**
+ * Returns the local address of this cache in a cluster, or <code>null</code>
+ * if running in local mode.
+ *
+ * @return the local address of this cache in a cluster, or <code>null</code>
+ * if running in local mode.
+ */
+ Address getLocalAddress();
+
+ /**
+ * Returns a list of members in the cluster, or <code>null</code>
+ * if running in local mode.
+ *
+ * @return a {@link List} of members in the cluster, or <code>null</code>
+ * if running in local mode.
+ */
+ List<Address> getMembers();
+
+ /**
+ * Moves a part of the cache to a different subtree.
+ * <p/>
+ * E.g.:
+ * <p/>
+ * assume a cache structure such as:
+ * <p/>
+ * <pre>
+ * /a/b/c
+ * /a/b/d
+ * /a/b/e
+ * <p/>
+ * <p/>
+ * Fqn f1 = Fqn.fromString("/a/b/c");
+ * Fqn f2 = Fqn.fromString("/a/b/d");
+ * <p/>
+ * cache.move(f1, f2);
+ * </pre>
+ * <p/>
+ * Will result in:
+ * <pre>
+ * <p/>
+ * /a/b/d/c
+ * /a/b/e
+ * <p/>
+ * </pre>
+ * <p/>
+ * and now
+ * <p/>
+ * <pre>
+ * Fqn f3 = Fqn.fromString("/a/b/e");
+ * Fqn f4 = Fqn.fromString("/a");
+ * cache.move(f3, f4);
+ * </pre>
+ * <p/>
+ * will result in:
+ * <pre>
+ * /a/b/d/c
+ * /a/e
+ * </pre>
+ * No-op if the node to be moved is the root node.
+ *
+ * @param nodeToMove the Fqn of the node to move.
+ * @param newParent new location under which to attach the node being moved.
+ * @throws NodeNotExistsException may throw one of these if the target node does not exist or if a different thread has moved this node elsewhere already.
+ */
+ void move(Fqn<?> nodeToMove, Fqn<?> newParent) throws NodeNotExistsException;
+
+ /**
+ * Returns the version of the cache as a string.
+ *
+ * @return the version string of the cache.
+ * @see Version#printVersion
+ */
+ String getVersion();
+}
Copied: core/trunk/src/main/java/org/jboss/cache/CacheException.java (from rev 4250, core/trunk/src-old/org/jboss/cache/CacheException.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/CacheException.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/CacheException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,45 @@
+// $Id$
+
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.cache;
+
+/**
+ * Thrown when operations on {@link org.jboss.cache.Cache} or {@link org.jboss.cache.Node} fail unexpectedly.
+ * <p/>
+ * Specific subclasses such as {@link org.jboss.cache.lock.TimeoutException}, {@link org.jboss.cache.config.ConfigurationException} and {@link org.jboss.cache.lock.LockingException}
+ * have more specific uses.
+ *
+ * @author <a href="mailto:bela@jboss.org">Bela Ban</a>
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
+ */
+public class CacheException extends RuntimeException
+{
+
+ private static final long serialVersionUID = -4386393072593859164L;
+
+ public CacheException()
+ {
+ super();
+ }
+
+ public CacheException(Throwable cause)
+ {
+ super(cause);
+ }
+
+ public CacheException(String msg)
+ {
+ super(msg);
+ }
+
+ public CacheException(String msg, Throwable cause)
+ {
+ super(msg, cause);
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/CacheFactory.java (from rev 4250, core/trunk/src-old/org/jboss/cache/CacheFactory.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/CacheFactory.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/CacheFactory.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,112 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.ConfigurationException;
+
+/**
+ * This factory constructs a cache from a given or default configuration set.
+ * <p/>
+ * Typical usage would be:
+ * <p/>
+ * <pre>
+ * CacheFactory factory = DefaultCacheFactory.getInstance();
+ * Cache cache = factory.createCache("replSync-service.xml"); // expects this file to be in classpath
+ * cache.stop();
+ * </pre>
+ * Factory methods provide options for creating a cache using
+ * <ul>
+ * <li>default configuration settings</li>
+ * <li>an XML file containing the configuration</li>
+ * <li>a constructed and populated {@link org.jboss.cache.config.Configuration} object</li>
+ * </ul>
+ * In addition, methods provide anadditional option to create and return a cache without starting it.
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ * @see org.jboss.cache.Cache
+ * @see org.jboss.cache.DefaultCacheFactory
+ * @see org.jboss.cache.pojo.PojoCacheFactory
+ * @since 2.0.0
+ */
+@ThreadSafe
+public interface CacheFactory<K, V>
+{
+ /**
+ * Creates and starts a {@link Cache} instance using default configuration settings. See {@link Configuration} for default values.
+ *
+ * @return a cache
+ * @throws ConfigurationException if there are problems with the default configuration
+ */
+ Cache<K, V> createCache() throws ConfigurationException;
+
+ /**
+ * Creates and optionally starts a {@link Cache} instance using default configuration settings. See {@link Configuration} for default values.
+ *
+ * @param start if true, starts the cache
+ * @return a cache
+ * @throws ConfigurationException if there are problems with the default configuration
+ */
+ Cache<K, V> createCache(boolean start) throws ConfigurationException;
+
+ /**
+ * Creates and starts a {@link org.jboss.cache.Cache} instance. The following are all valid calls:
+ * <pre>
+ * factory.createCache("myCacheService.xml"); // file is in class path
+ * factory.createCache("etc/myCacheService.xml"); // file is in etc/ relative to the directory you started the JVM
+ * factory.createCache("/home/jbosscache/myCacheService.xml"); // file is in the /home/jbosscache directory
+ * </pre>
+ *
+ * @param configFileName the named XML file should exist in the classpath or should be a fully qualified or relative (to your JVM working directory) path to a file on the local file system. Note that the classpath is checked first for the existence of this file.
+ * @return a running {@link org.jboss.cache.Cache} instance
+ * @throws org.jboss.cache.config.ConfigurationException
+ * if there are problems with the configuration
+ */
+ Cache<K, V> createCache(String configFileName) throws ConfigurationException;
+
+ /**
+ * Creates {@link Cache} instance, and optionally starts it.
+ *
+ * @param configFileName the named XML file should exist in the classpath or should be a fully qualified or relative (to your JVM working directory) path to a file on the local file system. Note that the classpath is checked first for the existence of this file.
+ * @param start if true, the cache is started before returning.
+ * @return an optionally running {@link Cache} instance
+ * @throws org.jboss.cache.config.ConfigurationException
+ * if there are problems with the configuration
+ * @see #createCache(String) for examples on valid config file names.
+ */
+ Cache<K, V> createCache(String configFileName, boolean start) throws ConfigurationException;
+
+ /**
+ * Creates a {@link Cache} instance based on a {@link org.jboss.cache.config.Configuration} passed in.
+ * <p/>
+ * Ensure that the Configuration you pass in is not used by another cache instance in the same JVM,
+ * as it may be concurrently modified. Clone the configuration, if shared, using
+ * {@link org.jboss.cache.config.Configuration#clone()}.
+ *
+ * @param configuration the {@link Configuration} object that is passed in to setCache the {@link Cache}.
+ * @return a running {@link Cache} instance
+ * @throws org.jboss.cache.config.ConfigurationException
+ * if there are problems with the configuration
+ */
+ Cache<K, V> createCache(Configuration configuration) throws ConfigurationException;
+
+ /**
+ * Creates {@link Cache} instance, and optionally starts it, based on a {@link org.jboss.cache.config.Configuration} passed in.
+ * <p/>
+ * Ensure that the Configuration you pass in is not used by another cache instance in the same JVM,
+ * as it may be concurrently modified. Clone the configuration, if shared, using
+ * {@link org.jboss.cache.config.Configuration#clone()}.
+ *
+ * @param configuration the {@link Configuration} object that is passed in to setCache the {@link Cache}.
+ * @param start if true, the cache is started before returning.
+ * @return an optionally running {@link Cache} instance
+ * @throws org.jboss.cache.config.ConfigurationException
+ * if there are problems with the configuration
+ */
+ Cache<K, V> createCache(Configuration configuration, boolean start) throws ConfigurationException;
+}
Copied: core/trunk/src/main/java/org/jboss/cache/CacheImpl.java (from rev 4250, core/trunk/src-old/org/jboss/cache/CacheImpl.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/CacheImpl.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/CacheImpl.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,4411 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.buddyreplication.BuddyGroup;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.cache.buddyreplication.BuddyNotInitException;
+import org.jboss.cache.buddyreplication.GravitateResult;
+import org.jboss.cache.config.BuddyReplicationConfig;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.config.RuntimeConfig;
+import org.jboss.cache.factories.InterceptorChainFactory;
+import org.jboss.cache.interceptors.Interceptor;
+import org.jboss.cache.loader.CacheLoader;
+import org.jboss.cache.loader.CacheLoaderManager;
+import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.lock.LockStrategyFactory;
+import org.jboss.cache.lock.LockUtil;
+import org.jboss.cache.lock.LockingException;
+import org.jboss.cache.lock.NodeLock;
+import org.jboss.cache.lock.TimeoutException;
+import org.jboss.cache.marshall.InactiveRegionAwareRpcDispatcher;
+import org.jboss.cache.marshall.Marshaller;
+import org.jboss.cache.marshall.MethodCall;
+import org.jboss.cache.marshall.MethodCallFactory;
+import org.jboss.cache.marshall.MethodDeclarations;
+import org.jboss.cache.marshall.NodeData;
+import org.jboss.cache.marshall.VersionAwareMarshaller;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.statetransfer.StateTransferManager;
+import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.transaction.OptimisticTransactionEntry;
+import org.jboss.cache.transaction.TransactionEntry;
+import org.jboss.cache.transaction.TransactionManagerLookup;
+import org.jboss.cache.transaction.TransactionTable;
+import org.jboss.cache.util.ExposedByteArrayOutputStream;
+import org.jboss.cache.util.ThreadGate;
+import org.jboss.cache.util.concurrent.ConcurrentHashSet;
+import org.jboss.util.stream.MarshalledValueInputStream;
+import org.jboss.util.stream.MarshalledValueOutputStream;
+import org.jgroups.Address;
+import org.jgroups.Channel;
+import org.jgroups.ChannelClosedException;
+import org.jgroups.ChannelException;
+import org.jgroups.ChannelFactory;
+import org.jgroups.ChannelNotConnectedException;
+import org.jgroups.ExtendedMembershipListener;
+import org.jgroups.ExtendedMessageListener;
+import org.jgroups.JChannel;
+import org.jgroups.Message;
+import org.jgroups.View;
+import org.jgroups.blocks.GroupRequest;
+import org.jgroups.blocks.RpcDispatcher;
+import org.jgroups.util.Rsp;
+import org.jgroups.util.RspList;
+import org.jgroups.util.Util;
+
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.NotSerializableException;
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * The default implementation class of {@link org.jboss.cache.Cache} and {@link org.jboss.cache.CacheSPI}. This class
+ * has its roots in the legacy (JBoss Cache 1.x.x) org.jboss.cache.TreeCache class.
+ * <p/>
+ * You should not use this class directly, or attempt to cast {@link org.jboss.cache.Cache} or {@link org.jboss.cache.CacheSPI}
+ * interfaces directly to this class.
+ *
+ * @author Bela Ban
+ * @author Ben Wang
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ * @author Brian Stansberry
+ * @author Daniel Huang (dhuang(a)jboss.org)
+ * @see org.jboss.cache.Cache
+ */
+public class CacheImpl<K, V> implements CacheSPI<K, V>
+{
+
+ /**
+ * CacheImpl log.
+ */
+ private Log log = LogFactory.getLog(CacheImpl.class);
+
+ /**
+ * Thread gate used to block Dispatcher during JGroups FLUSH protocol
+ */
+ private final ThreadGate flushBlockGate = new ThreadGate();
+
+ /**
+ * Root node.
+ */
+ private NodeSPI<K, V> root;
+
+ /**
+ * Cache's region manager.
+ */
+ private RegionManager regionManager = null;
+
+ /**
+ * The JGroups JChannel in use.
+ */
+ protected Channel channel = null;
+
+ /**
+ * True if this CacheImpl is the coordinator.
+ */
+ private boolean coordinator = false;
+
+ /**
+ * List of cluster group members.
+ */
+ private final Vector<Address> members = new Vector<Address>();
+
+ /**
+ * JGroups RpcDispatcher in use.
+ */
+ private RpcDispatcher disp = null;
+
+ /**
+ * JGroups message listener.
+ */
+ private MessageListenerAdaptor ml = new MessageListenerAdaptor();
+
+ /**
+ * Maintains mapping of transactions (keys) and Modifications/Undo-Operations
+ */
+ private final TransactionTable tx_table = new TransactionTable();
+
+ /**
+ * HashMap<Thread, List<Lock>, maintains locks acquired by threads (used when no TXs are used)
+ */
+ private Map<Thread, List<NodeLock>> lock_table;
+
+ /**
+ * Set<Fqn> of Fqns of the topmost node of internal regions that should
+ * not included in standard state transfers.
+ */
+ private Set<Fqn> internalFqns = new ConcurrentHashSet<Fqn>();
+
+ /**
+ * True if state was initialized during start-up.
+ */
+ private volatile boolean isStateSet = false;
+
+ /**
+ * Class name used to handle evictions.
+ */
+ private String evictionInterceptorClass = "org.jboss.cache.interceptors.EvictionInterceptor";
+
+ /**
+ * Marshaller if register to handle marshalling
+ */
+ private Marshaller marshaller_ = null;
+
+ /**
+ * {@link #invokeMethod(org.jboss.cache.marshall.MethodCall,boolean)} will dispatch to this chain of interceptors.
+ * In the future, this will be replaced with JBossAop. This is a first step towards refactoring JBossCache.
+ */
+ private Interceptor interceptor_chain = null;
+
+ /**
+ * Method to acquire a TransactionManager. By default we use JBossTransactionManagerLookup. Has
+ * to be set before calling {@link #start()}
+ */
+ private TransactionManagerLookup tm_lookup = null;
+
+ /**
+ * Used to get the Transaction associated with the current thread
+ */
+ private TransactionManager tm = null;
+
+ /**
+ * Cache loader manager.
+ */
+ private CacheLoaderManager cacheLoaderManager;
+
+ /**
+ * Queue used to replicate updates when mode is repl-async
+ */
+ private ReplicationQueue repl_queue = null;
+
+ /**
+ * The current lifecycle state.
+ */
+ CacheStatus cacheStatus;
+
+ /**
+ * Buddy Manager
+ */
+ private BuddyManager buddyManager;
+
+ /**
+ * State transfer manager. Do not access this field directly -- use the getter
+ */
+ private StateTransferManager stateTransferManager;
+
+ /**
+ * Cache notifier handler class.
+ */
+ private Notifier notifier;
+
+ private ThreadLocal<InvocationContext> invocationContextContainer = new ThreadLocal<InvocationContext>()
+ {
+ @Override
+ protected InvocationContext initialValue()
+ {
+ return new InvocationContext();
+ }
+ };
+
+ private Configuration configuration;
+
+ /**
+ * Constructs an uninitialized CacheImpl.
+ */
+ protected CacheImpl() throws Exception
+ {
+ configuration = new Configuration(this);
+ notifier = new Notifier(this);
+ regionManager = new RegionManager(this);
+ cacheStatus = CacheStatus.INSTANTIATED;
+ }
+
+ public StateTransferManager getStateTransferManager()
+ {
+ if (stateTransferManager == null)
+ {
+ stateTransferManager = new StateTransferManager(this);
+ }
+ return stateTransferManager;
+ }
+
+ public void setStateTransferManager(StateTransferManager manager)
+ {
+ this.stateTransferManager = manager;
+ }
+
+ public Configuration getConfiguration()
+ {
+ return configuration;
+ }
+
+ /**
+ * Returns the CacheImpl implementation version.
+ */
+ public String getVersion()
+ {
+ return Version.printVersion();
+ }
+
+ /**
+ * Returns the root node.
+ */
+ public NodeSPI<K, V> getRoot()
+ {
+ return root;
+ }
+
+ /**
+ * Returns the local channel address.
+ */
+ public Address getLocalAddress()
+ {
+ return channel != null ? channel.getLocalAddress() : null;
+ }
+
+ /**
+ * Returns the members as a List.
+ * This list may be concurrently modified.
+ */
+ public List<Address> getMembers()
+ {
+ synchronized (members)
+ {
+ return new ArrayList<Address>(members);
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if this node is the group coordinator.
+ */
+ public boolean isCoordinator()
+ {
+ return coordinator;
+ }
+
+ /**
+ * Returns the transaction table.
+ */
+ public TransactionTable getTransactionTable()
+ {
+ return tx_table;
+ }
+
+ /**
+ * Returns the lock table.
+ */
+ public Map<Thread, List<NodeLock>> getLockTable()
+ {
+ if (lock_table == null)
+ {
+ lock_table = new ConcurrentHashMap<Thread, List<NodeLock>>();
+ }
+ return lock_table;
+ }
+
+ /**
+ * Returns the contents of the TransactionTable as a string.
+ */
+ public String dumpTransactionTable()
+ {
+ return tx_table.toString(true);
+ }
+
+ /**
+ * Used for testing only - sets the interceptor chain.
+ */
+ public void setInterceptorChain(Interceptor i)
+ {
+ interceptor_chain = i;
+ }
+
+ /**
+ * @return the list of interceptors.
+ */
+ public List<Interceptor> getInterceptors()
+ {
+ return InterceptorChainFactory.getInstance().asList(interceptor_chain);
+ }
+
+ /**
+ * Returns the underlying cache loader in use.
+ */
+ public CacheLoader getCacheLoader()
+ {
+ if (cacheLoaderManager == null)
+ return null;
+ return cacheLoaderManager.getCacheLoader();
+ }
+
+ public String getEvictionInterceptorClass()
+ {
+ return this.evictionInterceptorClass;
+ }
+
+ private void setUseReplQueue(boolean flag)
+ {
+ if (flag)
+ {
+ if (repl_queue == null)
+ {
+ repl_queue = new ReplicationQueue(this, configuration.getReplQueueInterval(), configuration.getReplQueueMaxElements());
+ if (configuration.getReplQueueInterval() >= 0)
+ {
+ repl_queue.start();
+ }
+ }
+ }
+ else
+ {
+ if (repl_queue != null)
+ {
+ repl_queue.stop();
+ repl_queue = null;
+ }
+ }
+ }
+
+
+ /**
+ * Returns the replication queue.
+ */
+ public ReplicationQueue getReplicationQueue()
+ {
+ return repl_queue;
+ }
+
+ /**
+ * Sets the cache locking isolation level.
+ */
+ private void setIsolationLevel(IsolationLevel level)
+ {
+ LockStrategyFactory.setIsolationLevel(level);
+ }
+
+ /**
+ * Sets the TransactionManagerLookup object
+ */
+ public void setTransactionManagerLookup(TransactionManagerLookup l)
+ {
+ this.tm_lookup = l;
+ }
+
+ /**
+ * Returns the transaction manager in use.
+ */
+ public TransactionManager getTransactionManager()
+ {
+ return tm;
+ }
+
+ /**
+ * Fetches the group state from the current coordinator. If successful, this
+ * will trigger JChannel setState() call.
+ */
+ public void fetchState(long timeout) throws ChannelClosedException, ChannelNotConnectedException
+ {
+ if (channel == null)
+ {
+ throw new ChannelNotConnectedException();
+ }
+ boolean rc = channel.getState(null, timeout);
+ if (rc)
+ {
+ log.debug("fetchState(): state was retrieved successfully");
+ }
+ else
+ {
+ log.debug("fetchState(): state could not be retrieved (first member)");
+ }
+ }
+
+ void fetchPartialState(List<Address> sources, Fqn sourceTarget, Fqn integrationTarget) throws Exception
+ {
+ String encodedStateId = sourceTarget + StateTransferManager.PARTIAL_STATE_DELIMITER + integrationTarget;
+ fetchPartialState(sources, encodedStateId);
+ }
+
+ void fetchPartialState(List<Address> sources, Fqn subtree) throws Exception
+ {
+ if (subtree == null)
+ {
+ throw new IllegalArgumentException("Cannot fetch partial state. Null subtree.");
+ }
+ fetchPartialState(sources, subtree.toString());
+ }
+
+ private void fetchPartialState(List<Address> sources, String stateId) throws Exception
+ {
+ if (sources == null || sources.isEmpty() || stateId == null)
+ {
+ // should this really be throwing an exception? Are there valid use cases where partial state may not be available? - Manik
+ // Yes -- cache is configured LOCAL but app doesn't know it -- Brian
+ //throw new IllegalArgumentException("Cannot fetch partial state, targets are " + sources + " and stateId is " + stateId);
+ if (log.isWarnEnabled())
+ {
+ log.warn("Cannot fetch partial state, targets are " + sources +
+ " and stateId is " + stateId);
+ }
+ return;
+ }
+
+ List<Address> targets = new LinkedList<Address>(sources);
+
+ //skip *this* node as a target
+ targets.remove(getLocalAddress());
+
+ if (targets.isEmpty())
+ {
+ // Definitely no exception here -- this happens every time the 1st node in the
+ // cluster activates a region!! -- Brian
+ log.debug("Cannot fetch partial state. There are no target members specified");
+ return;
+ }
+
+ log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from members " + targets);
+ boolean successfulTransfer = false;
+ for (Address target : targets)
+ {
+ log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from member " + target);
+ isStateSet = false;
+ successfulTransfer = channel.getState(target, stateId, configuration.getStateRetrievalTimeout());
+ if (successfulTransfer)
+ {
+ try
+ {
+ ml.waitForState();
+ }
+ catch (Exception transferFailed)
+ {
+ successfulTransfer = false;
+ }
+ }
+ log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from member " + target + (successfulTransfer ? " successful" : " failed"));
+ if (successfulTransfer)
+ break;
+ }
+
+ if (!successfulTransfer)
+ {
+ log.debug("Node " + getLocalAddress() + " could not fetch partial state " + stateId + " from any member " + targets);
+ }
+ }
+
+ /**
+ * Lifecycle method. This is like initialize.
+ *
+ * @throws Exception
+ */
+ public void create() throws CacheException
+ {
+ if (!cacheStatus.createAllowed())
+ {
+ if (cacheStatus.needToDestroyFailedCache())
+ destroy();
+ else
+ return;
+ }
+
+ try
+ {
+ internalCreate();
+ }
+ catch (Throwable t)
+ {
+ handleLifecycleTransitionFailure(t);
+ }
+ }
+
+ /**
+ * Sets the cacheStatus to FAILED and rethrows the problem as one
+ * of the declared types. Converts any non-RuntimeException Exception
+ * to CacheException.
+ *
+ * @param t
+ * @throws CacheException
+ * @throws RuntimeException
+ * @throws Error
+ */
+ private void handleLifecycleTransitionFailure(Throwable t)
+ throws CacheException, RuntimeException, Error
+ {
+ cacheStatus = CacheStatus.FAILED;
+ if (t instanceof CacheException)
+ throw (CacheException) t;
+ else if (t instanceof RuntimeException)
+ throw (RuntimeException) t;
+ else if (t instanceof Error)
+ throw (Error) t;
+ else
+ throw new CacheException(t);
+ }
+
+ /**
+ * The actual create implementation.
+ *
+ * @throws CacheException
+ */
+ private void internalCreate() throws CacheException
+ {
+ // Include our clusterName in our log category
+ configureLogCategory();
+
+ // initialise the node factory and set this in the runtime.
+ NodeFactory<K, V> nf;
+ if ((nf = configuration.getRuntimeConfig().getNodeFactory()) == null)
+ {
+ nf = new NodeFactory<K, V>(this);
+ configuration.getRuntimeConfig().setNodeFactory(nf);
+ }
+ else
+ {
+ // don't create a new one each and every time. After stopping and starting the cache, the old NodeFactory may still be valid.
+ nf.init();
+ }
+
+ if (notifier == null)
+ notifier = new Notifier(this);
+
+ // create a new root temporarily.
+ NodeSPI<K, V> tempRoot = nf.createRootDataNode();
+ // if we don't already have a root or the new (temp) root is of a different class (optimistic vs pessimistic) to
+ // the current root, then we use the new one. Helps preserve data between cache restarts.
+ if (root == null || !root.getClass().equals(tempRoot.getClass()))
+ root = tempRoot;
+
+ if (configuration.getCacheLoaderConfig() != null && cacheLoaderManager == null)
+ {
+ initialiseCacheLoaderManager();
+ }
+ // first set up the Buddy Manager and an RPCManager
+ if (configuration.getCacheMode() != Configuration.CacheMode.LOCAL)
+ {
+ getConfiguration().getRuntimeConfig().setRPCManager(new RPCManagerImpl(this));
+ setBuddyReplicationConfig(configuration.getBuddyReplicationConfig());
+ }
+ // build interceptor chain
+ try
+ {
+ interceptor_chain = InterceptorChainFactory.getInstance().buildInterceptorChain(this);
+ }
+ catch (Exception e)
+ {
+ throw new CacheException("Unable to build interceptor chain", e);
+ }
+
+
+ setUseReplQueue(configuration.isUseReplQueue());
+ setIsolationLevel(configuration.getIsolationLevel());
+
+ getRegionManager();// make sure we create one
+ createEvictionPolicy();
+
+ getRegionManager().setDefaultInactive(configuration.isInactiveOnStartup());
+
+ cacheStatus = CacheStatus.CREATED;
+ }
+
+ private void createTransactionManager()
+ {
+ // See if we had a TransactionManager injected into our config
+ this.tm = configuration.getRuntimeConfig().getTransactionManager();
+ if (tm == null)
+ {
+ // Nope. See if we can look it up from JNDI
+ if (this.tm_lookup == null && configuration.getTransactionManagerLookupClass() != null)
+ {
+ try
+ {
+ Class clazz = Thread.currentThread().getContextClassLoader().loadClass(configuration.getTransactionManagerLookupClass());
+ this.tm_lookup = (TransactionManagerLookup) clazz.newInstance();
+ }
+ catch (Exception e)
+ {
+ throw new CacheException("Problems creating the cache", e);
+ }
+ }
+
+ try
+ {
+ if (tm_lookup != null)
+ {
+ tm = tm_lookup.getTransactionManager();
+ configuration.getRuntimeConfig().setTransactionManager(tm);
+ }
+ else
+ {
+ if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC)
+ {
+ log.fatal("No transaction manager lookup class has been defined. Transactions cannot be used and thus OPTIMISTIC locking cannot be used");
+ }
+ else
+ {
+ log.info("No transaction manager lookup class has been defined. Transactions cannot be used");
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ log.debug("failed looking up TransactionManager, will not use transactions", e);
+ }
+ }
+ }
+
+ protected boolean shouldFetchStateOnStartup()
+ {
+ boolean loaderFetch = cacheLoaderManager != null && cacheLoaderManager.isFetchPersistentState();
+ return !configuration.isInactiveOnStartup() && buddyManager == null && (configuration.isFetchInMemoryState() || loaderFetch);
+ }
+
+ /**
+ * Lifecyle method.
+ *
+ * @throws CacheException
+ */
+ public void start() throws CacheException
+ {
+ if (!cacheStatus.startAllowed())
+ {
+ if (cacheStatus.needToDestroyFailedCache())
+ destroy(); // this will take us back to DESTROYED
+
+ if (cacheStatus.needCreateBeforeStart())
+ create();
+ else
+ return;
+ }
+
+ try
+ {
+ internalStart();
+ }
+ catch (Throwable t)
+ {
+ handleLifecycleTransitionFailure(t);
+ }
+ }
+
+ /**
+ * The actual start implementation.
+ *
+ * @throws CacheException
+ * @throws IllegalArgumentException
+ */
+ private void internalStart() throws CacheException, IllegalArgumentException
+ {
+ cacheStatus = CacheStatus.STARTING;
+
+ createTransactionManager();
+
+ // cache loaders should be initialised *before* any state transfers take place to prevent
+ // exceptions involving cache loaders not being started. - Manik
+ // create cache loader
+ if (cacheLoaderManager != null)
+ {
+ cacheLoaderManager.startCacheLoader();
+ }
+ // now that we have a TM we can init the interceptor chain
+ InterceptorChainFactory.getInstance().initialiseInterceptors(interceptor_chain, this);
+
+ switch (configuration.getCacheMode())
+ {
+ case LOCAL:
+ log.debug("cache mode is local, will not create the channel");
+ break;
+ case REPL_SYNC:
+ case REPL_ASYNC:
+ case INVALIDATION_ASYNC:
+ case INVALIDATION_SYNC:
+ if (log.isDebugEnabled()) log.debug("cache mode is " + configuration.getCacheMode());
+ initialiseChannelAndRpcDispatcher();
+
+ try
+ {
+ channel.connect(configuration.getClusterName());
+ }
+ catch (ChannelException e)
+ {
+ throw new CacheException("Unable to connect to JGroups channel", e);
+ }
+
+ if (log.isInfoEnabled())
+ {
+ log.info("CacheImpl local address is " + channel.getLocalAddress());
+ }
+ if (shouldFetchStateOnStartup())
+ {
+ try
+ {
+ fetchStateOnStartup();
+ }
+ catch (Exception e)
+ {
+ // make sure we disconnect from the channel before we throw this exception!
+ // JBCACHE-761
+ channel.disconnect();
+ channel.close();
+ throw new CacheException("Unable to fetch state on startup", e);
+ }
+ }
+ if (buddyManager != null)
+ {
+ buddyManager.init(this);
+ if (configuration.isUseReplQueue())
+ {
+ log.warn("Replication queue not supported when using buddy replication. Disabling repliction queue.");
+ configuration.setUseReplQueue(false);
+ repl_queue = null;
+ }
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("cache mode " + configuration.getCacheMode() + " is invalid");
+ }
+
+ //now attempt to preload the cache from the loader - Manik
+ if (cacheLoaderManager != null)
+ {
+ cacheLoaderManager.preloadCache();
+ }
+
+ // Find out if we are coordinator (blocks until view is received)
+ determineCoordinator();
+
+ // start any eviction threads.
+ if (regionManager.isUsingEvictions())
+ {
+ regionManager.startEvictionThread();
+ }
+
+ notifier.notifyCacheStarted(this, getInvocationContext());
+
+ // install a VM shutdown hook
+ Thread shutdownHook = new Thread()
+ {
+ public void run()
+ {
+ CacheImpl.this.stop();
+ }
+ };
+
+ Runtime.getRuntime().addShutdownHook(shutdownHook);
+
+ log.info("JBoss Cache version: " + getVersion());
+
+ cacheStatus = CacheStatus.STARTED;
+ }
+
+ /**
+ * Lifecycle method.
+ */
+ public void destroy()
+ {
+ if (!cacheStatus.destroyAllowed())
+ {
+ if (cacheStatus.needStopBeforeDestroy())
+ {
+ try
+ {
+ stop();
+ }
+ catch (CacheException e)
+ {
+ log.warn("Needed to call stop() before destroying but stop() " +
+ "threw exception. Proceeding to destroy", e);
+ }
+ }
+ else
+ return;
+ }
+
+ try
+ {
+ internalDestroy();
+ }
+ finally
+ {
+ // We always progress to destroyed
+ cacheStatus = CacheStatus.DESTROYED;
+ }
+ }
+
+ /**
+ * The actual destroy implementation.
+ */
+ private void internalDestroy()
+ {
+ cacheStatus = CacheStatus.DESTROYING;
+ regionManager = null;
+ notifier = null;
+
+ // The rest of these should have already been taken care of in stop,
+ // but we do it here as well in case stop failed.
+
+ if (channel != null)
+ {
+ if (channel.isOpen())
+ {
+ try
+ {
+ channel.close();
+ channel.disconnect();
+ }
+ catch (Exception toLog)
+ {
+ log.error("Problem closing channel; setting it to null", toLog);
+ }
+ }
+ channel = null;
+ configuration.getRuntimeConfig().setChannel(null);
+ }
+ disp = null;
+ tm = null;
+ }
+
+ /**
+ * Lifecycle method.
+ */
+ public void stop()
+ {
+ if (!cacheStatus.stopAllowed())
+ {
+ return;
+ }
+
+ // Trying to stop() from FAILED is valid, but may not work
+ boolean failed = cacheStatus == CacheStatus.FAILED;
+
+ try
+ {
+ internalStop();
+ }
+ catch (Throwable t)
+ {
+ if (failed)
+ {
+ log.warn("Attempted to stop() from FAILED state, " +
+ "but caught exception; try calling destroy()", t);
+ }
+ handleLifecycleTransitionFailure(t);
+ }
+ }
+
+ /**
+ * The actual stop implementation.
+ */
+ private void internalStop()
+ {
+ cacheStatus = CacheStatus.STOPPING;
+
+ // before closing the channel stop the buddy manager
+ if (buddyManager != null && buddyManager.isEnabled())
+ {
+ log.debug("stop(): stopping buddy manager");
+ buddyManager.stop();
+ }
+
+ if (channel != null)
+ {
+ log.info("stop(): closing the channel");
+ killChannel();
+ channel = null;
+ configuration.getRuntimeConfig().setChannel(null);
+ }
+
+ if (disp != null)
+ {
+ log.info("stop(): stopping the dispatcher");
+ disp.stop();
+ disp = null;
+ }
+ if (members != null)
+ {
+ synchronized (members)
+ {
+ members.clear();
+ }
+ }
+
+ coordinator = false;
+
+ if (repl_queue != null)
+ {
+ repl_queue.stop();
+ }
+
+ if (cacheLoaderManager != null)
+ {
+ log.debug("stop(): stopping cache loader manager");
+ cacheLoaderManager.stopCacheLoader();
+ }
+
+ if (regionManager.isUsingEvictions()) regionManager.stopEvictionThread();
+
+ if (notifier != null)
+ {
+ notifier.notifyCacheStopped(this, getInvocationContext());
+ notifier.removeAllCacheListeners();
+ }
+
+ // unset transaction manager reference
+ tm = null;
+
+ cacheStatus = CacheStatus.STOPPED;
+
+ // empty in-memory state
+ root.clearDataDirect();
+ root.removeChildrenDirect();
+ }
+
+ public CacheStatus getCacheStatus()
+ {
+ return cacheStatus;
+ }
+
+ /* ----------------------- End of MBeanSupport ----------------------- */
+
+ /* ----------------------- Start of buddy replication specific methods ------------*/
+
+ /**
+ * Sets the buddy replication configuration element
+ *
+ * @param config
+ */
+ private void setBuddyReplicationConfig(BuddyReplicationConfig config)
+ {
+ if (config != null)
+ {
+ buddyManager = new BuddyManager(config);
+ if (!buddyManager.isEnabled())
+ {
+ buddyManager = null;
+ }
+ else
+ {
+ internalFqns.add(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
+ }
+ }
+ }
+
+ /**
+ * Retrieves the Buddy Manager configured.
+ *
+ * @return null if buddy replication is not enabled.
+ */
+ public BuddyManager getBuddyManager()
+ {
+ return buddyManager;
+ }
+
+ /**
+ * Returns a Set<Fqn> of Fqns of the topmost node of internal regions that
+ * should not included in standard state transfers. Will include
+ * {@link BuddyManager#BUDDY_BACKUP_SUBTREE} if buddy replication is
+ * enabled.
+ *
+ * @return an unmodifiable Set<Fqn>. Will not return <code>null</code>.
+ */
+ public Set<Fqn> getInternalFqns()
+ {
+ return Collections.unmodifiableSet(internalFqns);
+ }
+
+ /* ----------------------- End of buddy replication specific methods ------------*/
+
+ protected void createEvictionPolicy()
+ {
+ if (configuration.getEvictionConfig() != null
+ && configuration.getEvictionConfig().isValidConfig())
+ {
+ regionManager.setEvictionConfig(configuration.getEvictionConfig());
+ regionManager.setUsingEvictions(true);
+ }
+ else
+ {
+ regionManager.setUsingEvictions(false);
+ log.debug("Not using an EvictionPolicy");
+ }
+ }
+
+ /**
+ * Loads the indicated Fqn, plus all parents recursively from the
+ * CacheLoader. If no CacheLoader is present, this is a no-op
+ *
+ * @param fqn
+ * @throws Exception
+ */
+ public void load(String fqn) throws Exception
+ {
+ if (cacheLoaderManager != null)
+ {
+ cacheLoaderManager.preload(Fqn.fromString(fqn), true, true);
+ }
+ }
+
+ private void determineCoordinator()
+ {
+ // Synchronize on members to make the answer atomic for the current view
+ synchronized (members)
+ {
+ Address coord = getCoordinator();
+ coordinator = (coord == null ? false : coord.equals(getLocalAddress()));
+ }
+ }
+
+ /**
+ * Returns the address of the coordinator or null if there is no
+ * coordinator.
+ * Waits until the membership view is updated.
+ */
+ public Address getCoordinator()
+ {
+ if (channel == null)
+ {
+ return null;
+ }
+
+ synchronized (members)
+ {
+ while (members.isEmpty())
+ {
+ log.debug("getCoordinator(): waiting on viewAccepted()");
+ try
+ {
+ members.wait();
+ }
+ catch (InterruptedException e)
+ {
+ log.error("getCoordinator(): Interrupted while waiting for members to be set", e);
+ break;
+ }
+ }
+ return members.size() > 0 ? members.get(0) : null;
+ }
+ }
+
+ // ----------- Marshalling and State Transfer -----------------------
+
+ /**
+ * Creates a subtree in the local cache.
+ * Returns the DataNode created.
+ */
+ protected Node createSubtreeRootNode(Fqn<?> subtree) throws CacheException
+ {
+ NodeSPI<K, V> parent = root;
+ NodeSPI<K, V> child = null;
+ Object owner = getOwnerForLock();
+ Object name;
+ NodeFactory<K, V> factory = configuration.getRuntimeConfig().getNodeFactory();
+
+ for (int i = 0; i < subtree.size(); i++)
+ {
+ name = subtree.get(i);
+ child = parent.getChildDirect(name);
+ if (child == null)
+ {
+ // Lock the parent, create and add the child
+ try
+ {
+ parent.getLock().acquire(owner, configuration.getSyncReplTimeout(), NodeLock.LockType.WRITE);
+ }
+ catch (InterruptedException e)
+ {
+ log.error("Interrupted while locking" + parent.getFqn(), e);
+ throw new CacheException(e.getLocalizedMessage(), e);
+ }
+
+ try
+ {
+ child = factory.createDataNode(name,
+ subtree.getAncestor(i + 1),
+ parent, null, true);
+ parent.addChild(name, child);
+ }
+ finally
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("forcing release of locks in " + parent.getFqn());
+ }
+ try
+ {
+ parent.getLock().releaseAll();
+ }
+ catch (Throwable t)
+ {
+ log.error("failed releasing locks", t);
+ }
+ }
+ }
+
+ parent = child;
+ }
+
+ return child;
+ }
+
+ /**
+ * Evicts the node at <code>subtree</code> along with all descendant nodes.
+ *
+ * @param subtree Fqn indicating the uppermost node in the
+ * portion of the cache that should be evicted.
+ * @throws CacheException
+ */
+ protected void _evictSubtree(Fqn subtree) throws CacheException
+ {
+
+ if (!exists(subtree))
+ {
+ return;// node does not exist. Maybe it has been recursively removed.
+ }
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("_evictSubtree(" + subtree + ")");
+ }
+
+ // Recursively remove any children
+ Set children = getChildrenNames(subtree);
+ if (children != null)
+ {
+ for (Object s : children)
+ {
+
+ Fqn<Object> tmp = new Fqn<Object>(subtree, s);
+ _remove(null, // no tx
+ tmp,
+ false, // no undo ops
+ false, // no nodeEvent
+ true);// is an eviction
+ }
+ }
+
+ // Remove the root node of the subtree
+ _remove(null, subtree, false, false, true);
+
+ }
+
+ private void removeLocksForDeadMembers(NodeSPI<K, V> node, List deadMembers)
+ {
+ Set<GlobalTransaction> deadOwners = new HashSet<GlobalTransaction>();
+ NodeLock lock = node.getLock();
+ Object owner = lock.getWriterOwner();
+
+ if (isLockOwnerDead(owner, deadMembers))
+ {
+ deadOwners.add((GlobalTransaction) owner);
+ }
+
+ for (Object readOwner : lock.getReaderOwners())
+ {
+ if (isLockOwnerDead(readOwner, deadMembers))
+ {
+ deadOwners.add((GlobalTransaction) readOwner);
+ }
+ }
+
+ for (GlobalTransaction deadOwner : deadOwners)
+ {
+ boolean localTx = deadOwner.getAddress().equals(getLocalAddress());
+ boolean broken = LockUtil.breakTransactionLock(lock, deadOwner, localTx, this);
+
+ if (broken && log.isTraceEnabled())
+ {
+ log.trace("Broke lock for node " + node.getFqn() +
+ " held by " + deadOwner);
+ }
+ }
+
+ // Recursively unlock children
+ for (NodeSPI<K, V> child : node.getChildrenDirect())
+ {
+ removeLocksForDeadMembers(child, deadMembers);
+ }
+ }
+
+ private boolean isLockOwnerDead(Object owner, List deadMembers)
+ {
+ boolean result = false;
+ if (owner != null && owner instanceof GlobalTransaction)
+ {
+ Object addr = ((GlobalTransaction) owner).getAddress();
+ result = deadMembers.contains(addr);
+ }
+ return result;
+ }
+
+ protected void fetchStateOnStartup() throws Exception
+ {
+ long start, stop;
+ isStateSet = false;
+ start = System.currentTimeMillis();
+ boolean rc = channel.getState(null, configuration.getStateRetrievalTimeout());
+ if (rc)
+ {
+ ml.waitForState();
+ stop = System.currentTimeMillis();
+ if (log.isDebugEnabled())
+ {
+ log.debug("state was retrieved successfully (in " + (stop - start) + " milliseconds)");
+ }
+ }
+ else
+ {
+ // No one provided us with state. We need to find out if that's because
+ // we are the coordinator. But we don't know if the viewAccepted() callback
+ // has been invoked, so call determineCoordinator(), which will block until
+ // viewAccepted() is called at least once
+ determineCoordinator();
+
+ if (isCoordinator())
+ {
+ log.debug("State could not be retrieved (we are the first member in group)");
+ }
+ else
+ {
+ throw new CacheException("Initial state transfer failed: " +
+ "Channel.getState() returned false");
+ }
+ }
+ }
+
+ // ----------- End Marshalling and State Transfer -----------------------
+
+ /**
+ * @param fqn fqn String name to retrieve from cache
+ * @return DataNode corresponding to the fqn. Null if does not exist. No guarantees wrt replication,
+ * cache loading are given if the underlying node is modified
+ */
+ public Node get(String fqn) throws CacheException
+ {
+ return get(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Returns a DataNode corresponding to the fully qualified name or null if
+ * does not exist.
+ * No guarantees wrt replication, cache loading are given if the underlying node is modified
+ *
+ * @param fqn name of the DataNode to retreive
+ */
+ public Node<K, V> get(Fqn<?> fqn) throws CacheException
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.getNodeMethodLocal, fqn);
+ return (Node<K, V>) invokeMethod(m, true);
+ }
+
+ /**
+ * Returns the raw data of the node; called externally internally.
+ */
+ public Node<K, V> _get(Fqn<?> fqn) throws CacheException
+ {
+ return findNode(fqn);
+ }
+
+ /**
+ * Returns the raw data of the node; called externally internally.
+ */
+ public Map _getData(Fqn<?> fqn)
+ {
+ NodeSPI n = findNode(fqn);
+ if (n == null) return null;
+ return n.getDataDirect();
+ }
+
+ /**
+ * Returns a set of attribute keys for the Fqn.
+ * Returns null if the node is not found, otherwise a Set.
+ * The set is a copy of the actual keys for this node.
+ *
+ * @param fqn name of the node
+ */
+ public Set getKeys(String fqn) throws CacheException
+ {
+ return getKeys(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Returns a set of attribute keys for the Fqn.
+ * Returns null if the node is not found, otherwise a Set.
+ * The set is a copy of the actual keys for this node.
+ *
+ * @param fqn name of the node
+ */
+ public Set<K> getKeys(Fqn<?> fqn) throws CacheException
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.getKeysMethodLocal, fqn);
+ return (Set<K>) invokeMethod(m, true);
+ }
+
+
+ /**
+ * Retrieves a defensively copied data map of the underlying node.
+ *
+ * @param fqn
+ * @return map of data, or an empty map
+ * @throws CacheException
+ */
+ public Map<K, V> getData(Fqn<?> fqn) throws CacheException
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.getDataMapMethodLocal, fqn);
+ return (Map<K, V>) invokeMethod(m, true);
+ }
+
+ public Set _getKeys(Fqn<?> fqn) throws CacheException
+ {
+ NodeSPI<K, V> n = findNode(fqn);
+ if (n == null)
+ {
+ return null;
+ }
+ Set<K> keys = n.getKeysDirect();
+ return new HashSet<K>(keys);
+ }
+
+ /**
+ * Finds a node given its name and returns the value associated with a given key in its <code>data</code>
+ * map. Returns null if the node was not found in the cache or the key was not found in the hashmap.
+ *
+ * @param fqn The fully qualified name of the node.
+ * @param key The key.
+ */
+ public V get(String fqn, K key) throws CacheException
+ {
+ return get(Fqn.fromString(fqn), key);
+ }
+
+
+ /**
+ * Finds a node given its name and returns the value associated with a given key in its <code>data</code>
+ * map. Returns null if the node was not found in the cache or the key was not found in the hashmap.
+ *
+ * @param fqn The fully qualified name of the node.
+ * @param key The key.
+ */
+ public V get(Fqn<?> fqn, K key) throws CacheException
+ {
+ return get(fqn, key, true);
+ }
+
+ public V _get(Fqn<?> fqn, K key, boolean sendNodeEvent) throws CacheException
+ {
+ InvocationContext ctx = getInvocationContext();
+ if (log.isTraceEnabled())
+ {
+ log.trace(new StringBuffer("_get(").append("\"").append(fqn).append("\", \"").append(key).append("\", \"").
+ append(sendNodeEvent).append("\")"));
+ }
+ if (sendNodeEvent) notifier.notifyNodeVisited(fqn, true, ctx);
+ NodeSPI<K, V> n = findNode(fqn);
+ if (n == null)
+ {
+ log.trace("node not found");
+ return null;
+ }
+ if (sendNodeEvent) notifier.notifyNodeVisited(fqn, false, ctx);
+ return n.getDirect(key);
+ }
+
+
+ protected V get(Fqn<?> fqn, K key, boolean sendNodeEvent) throws CacheException
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.getKeyValueMethodLocal, fqn, key, sendNodeEvent);
+ return (V) invokeMethod(m, true);
+ }
+
+ /**
+ * Checks whether a given node exists in current in-memory state of the cache.
+ * Does not acquire any locks in doing so (result may be dirty read). Does
+ * not attempt to load nodes from a cache loader (may return false if a
+ * node has been evicted).
+ *
+ * @param fqn The fully qualified name of the node
+ * @return boolean Whether or not the node exists
+ */
+ public boolean exists(String fqn)
+ {
+ return exists(Fqn.fromString(fqn));
+ }
+
+
+ /**
+ * Checks whether a given node exists in current in-memory state of the cache.
+ * Does not acquire any locks in doing so (result may be dirty read). Does
+ * not attempt to load nodes from a cache loader (may return false if a
+ * node has been evicted).
+ *
+ * @param fqn The fully qualified name of the node
+ * @return boolean Whether or not the node exists
+ */
+ public boolean exists(Fqn<?> fqn)
+ {
+ Node n = peek(fqn, false);
+ return n != null;
+ }
+
+ /**
+ * Gets node without attempt to load it from CacheLoader if not present
+ *
+ * @param fqn
+ */
+ public NodeSPI<K, V> peek(Fqn<?> fqn, boolean includeDeletedNodes)
+ {
+ if (fqn == null || fqn.size() == 0) return root;
+ NodeSPI<K, V> n = root;
+ int fqnSize = fqn.size();
+ for (int i = 0; i < fqnSize; i++)
+ {
+ Object obj = fqn.get(i);
+ n = n.getChildDirect(obj);
+ if (n == null)
+ {
+ return null;
+ }
+ else if (!includeDeletedNodes && n.isDeleted())
+ {
+ return null;
+ }
+ }
+ return n;
+ }
+
+
+ /**
+ * @param fqn
+ * @param key
+ */
+ public boolean exists(String fqn, Object key)
+ {
+ return exists(Fqn.fromString(fqn), key);
+ }
+
+
+ /**
+ * Checks whether a given key exists in the given node. Does not interact with CacheLoader, so the behavior is
+ * different from {@link #get(Fqn,Object)}
+ *
+ * @param fqn The fully qualified name of the node
+ * @param key
+ * @return boolean Whether or not the node exists
+ */
+ public boolean exists(Fqn<?> fqn, Object key)
+ {
+ NodeSPI n = peek(fqn, false);
+ return n != null && n.getKeysDirect().contains(key);
+ }
+
+
+ /**
+ * Adds a new node to the cache and sets its data. If the node doesn not yet exist, it will be created.
+ * Also, parent nodes will be created if not existent. If the node already has data, then the new data
+ * will override the old one. If the node already existed, a nodeModified() notification will be generated.
+ * Otherwise a nodeCreated() motification will be emitted.
+ *
+ * @param fqn The fully qualified name of the new node
+ * @param data The new data. May be null if no data should be set in the node.
+ */
+ public void put(String fqn, Map data) throws CacheException
+ {
+ put(Fqn.fromString(fqn), data);
+ }
+
+ /**
+ * Sets a node's data. If the node does not yet exist, it will be created.
+ * Also, parent nodes will be created if not existent. If the node already has data, then the new data
+ * will override the old one. If the node already existed, a nodeModified() notification will be generated.
+ * Otherwise a nodeCreated() motification will be emitted.
+ *
+ * @param fqn The fully qualified name of the new node
+ * @param data The new data. May be null if no data should be set in the node.
+ */
+ public void put(Fqn<?> fqn, Map<K, V> data) throws CacheException
+ {
+ put(fqn, data, false);
+ }
+
+ public void put(Fqn<?> fqn, Map<K, V> data, boolean erase) throws CacheException
+ {
+ GlobalTransaction tx = getCurrentTransaction();
+ MethodCall m;
+ if (erase)
+ {
+ m = MethodCallFactory.create(MethodDeclarations.putDataEraseMethodLocal, tx, fqn, data, true, true);
+ }
+ else
+ {
+ m = MethodCallFactory.create(MethodDeclarations.putDataMethodLocal, tx, fqn, data, true);
+ }
+ invokeMethod(m, true);
+ }
+
+ /**
+ * Adds a key and value to a given node. If the node doesn't exist, it will be created. If the node
+ * already existed, a nodeModified() notification will be generated. Otherwise a
+ * nodeCreated() motification will be emitted.
+ *
+ * @param fqn The fully qualified name of the node
+ * @param key The key
+ * @param value The value
+ * @return Object The previous value (if any), if node was present
+ */
+ public V put(String fqn, K key, V value) throws CacheException
+ {
+ return put(Fqn.fromString(fqn), key, value);
+ }
+
+ /**
+ * Adds a key and value to a given node. If the node doesn't exist, it will be created. If the node
+ * already existed, a nodeModified() notification will be generated. Otherwise a
+ * nodeCreated() motification will be emitted.
+ *
+ * @param fqn The fully qualified name of the node
+ * @param key The key
+ * @param value The value
+ * @return Object The previous value (if any), if node was present
+ */
+ public V put(Fqn<?> fqn, K key, V value) throws CacheException
+ {
+ GlobalTransaction tx = getCurrentTransaction();
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, value, true);
+ return (V) invokeMethod(m, true);
+ }
+
+ /**
+ * Removes the node from the cache.
+ *
+ * @param fqn The fully qualified name of the node.
+ */
+ public void remove(String fqn) throws CacheException
+ {
+ remove(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Removes the node from the cache.
+ *
+ * @param fqn The fully qualified name of the node.
+ */
+ public boolean remove(Fqn fqn) throws CacheException
+ {
+ GlobalTransaction tx = getCurrentTransaction();
+ // special case if we are removing the root. Remove all children instead.
+ if (fqn.isRoot())
+ {
+ boolean result = true;
+ // we need to preserve options
+ InvocationContext ctx = getInvocationContext();
+ Option o = ctx.getOptionOverrides();
+ for (Object childName : _getChildrenNames(fqn))
+ {
+ ctx.setOptionOverrides(o);
+ result = remove(new Fqn<Object>(fqn, childName)) && result;
+ }
+
+ return result;
+ }
+ else
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, tx, fqn, true);
+ Object retval = invokeMethod(m, true);
+ return retval != null && (Boolean) retval;
+ }
+ }
+
+ /**
+ * Called by eviction policy provider. Note that eviction is done only in
+ * local mode, that is, it doesn't replicate the node removal. This will
+ * cause the replication nodes to not be synchronizing, which is fine since
+ * the value will be fetched again when {@link #get} returns null. After
+ * that, the contents will be in sync.
+ *
+ * @param fqn Will remove everythign assoicated with this fqn.
+ * @throws CacheException
+ */
+ public void evict(Fqn fqn) throws CacheException
+ {
+ if (fqn.isRoot())
+ {
+ // special treatment for root eviction
+ // we need to preserve options
+ InvocationContext ctx = getInvocationContext();
+ Option o = ctx.getOptionOverrides();
+ for (Object childName : _getChildrenNames(fqn))
+ {
+ ctx.setOptionOverrides(o);
+ evict(new Fqn<Object>(fqn, childName));
+ }
+ }
+ else
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, fqn);
+ invokeMethod(m, true);
+ }
+ }
+
+ /**
+ * Removes <code>key</code> from the node's hashmap
+ *
+ * @param fqn The fullly qualified name of the node
+ * @param key The key to be removed
+ * @return The previous value, or null if none was associated with the given key
+ */
+ public V remove(String fqn, K key) throws CacheException
+ {
+ return remove(Fqn.fromString(fqn), key);
+ }
+
+ /**
+ * Removes <code>key</code> from the node's hashmap
+ *
+ * @param fqn The fullly qualified name of the node
+ * @param key The key to be removed
+ * @return The previous value, or null if none was associated with the given key
+ */
+ public V remove(Fqn<?> fqn, K key) throws CacheException
+ {
+ GlobalTransaction tx = getCurrentTransaction();
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal, tx, fqn, key, true);
+ return (V) invokeMethod(m, true);
+ }
+
+ /**
+ * Removes the keys and properties from a node.
+ */
+ public void removeData(String fqn) throws CacheException
+ {
+ removeData(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Removes the keys and properties from a named node.
+ */
+ public void removeData(Fqn fqn) throws CacheException
+ {
+ GlobalTransaction tx = getCurrentTransaction();
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.removeDataMethodLocal, tx, fqn, true);
+ invokeMethod(m, true);
+ }
+
+ /**
+ * Lock a given node (or the entire subtree starting at this node)
+ * @param fqn The FQN of the node
+ * @param owner The owner. This is simply a key into a hashtable, and can be anything, e.g.
+ * a GlobalTransaction, the current thread, or a special object. If null, it is set to Thread.currentThread()
+ * @param lock_type The type of lock (RO, RW). Needs to be of type DataNode.LOCK_TYPE_READ or DataNode.LOCK_TYPE_WRITE
+ * @param lock_recursive If true, the entire subtree is locked, else only the given node
+ * @throws CacheException If node doesn't exist, a NodeNotExistsException is throw. Other exceptions are
+ * LockingException, TimeoutException and UpgradeException
+ */
+ // public void lock(Fqn fqn, Object owner, int lock_type, boolean lock_recursive) throws CacheException {
+ //
+ // }
+
+ /**
+ * Unlock a given node (or the entire subtree starting at this node)
+ * @param fqn The FQN of the node
+ * @param owner The owner. This is simply a key into a hashtable, and can be anything, e.g.
+ * a GlobalTransaction, the current thread, or a special object. If null, it is set to Thread.currentThread()
+ * @param unlock_recursive If true, the entire subtree is unlocked, else only the given node
+ * @param force Release the lock even if we're not the owner
+ */
+ // public void unlock(Fqn fqn, Object owner, boolean unlock_recursive, boolean force) {
+ //
+ // }
+
+ /**
+ * Releases all locks for this node and the entire node subtree.
+ */
+ public void releaseAllLocks(String fqn)
+ {
+ releaseAllLocks(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Releases all locks for this node and the entire node subtree.
+ */
+ public void releaseAllLocks(Fqn fqn)
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.releaseAllLocksMethodLocal, fqn);
+ try
+ {
+ invokeMethod(m, true);
+ }
+ catch (CacheException e)
+ {
+ log.error("failed releasing all locks for " + fqn, e);
+ }
+ }
+
+ /**
+ * Prints a representation of the node defined by <code>fqn</code>.
+ * Output includes name, fqn and data.
+ */
+ public String print(String fqn)
+ {
+ return print(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Prints a representation of the node defined by <code>fqn</code>.
+ * Output includes name, fqn and data.
+ */
+ public String print(Fqn fqn)
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.printMethodLocal, fqn);
+ Object retval = null;
+ try
+ {
+ retval = invokeMethod(m, true);
+ }
+ catch (Throwable e)
+ {
+ retval = e;
+ }
+ if (retval != null)
+ {
+ return retval.toString();
+ }
+ else
+ {
+ return "";
+ }
+ }
+
+
+ /**
+ * Returns all children of a given node.
+ * Returns null of the parent node was not found, or if there are no
+ * children.
+ * The set is unmodifiable.
+ *
+ * @param fqn The fully qualified name of the node
+ * @return Set A list of child names (as Strings)
+ * @see #getChildrenNames(Fqn)
+ */
+ public Set getChildrenNames(String fqn) throws CacheException
+ {
+ return getChildrenNames(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Returns all children of a given node. Returns an empty set if there are no children.
+ * The set is unmodifiable.
+ *
+ * @param fqn The fully qualified name of the node
+ * @return Set an unmodifiable set of children names, Object.
+ */
+ public <E> Set<E> getChildrenNames(Fqn<E> fqn) throws CacheException
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.getChildrenNamesMethodLocal, fqn);
+ Set<E> retval = null;
+ retval = (Set<E>) invokeMethod(m, true);
+ if (retval != null)
+ retval = Collections.unmodifiableSet(new HashSet<E>(retval));
+ else
+ retval = Collections.emptySet();
+ return retval;
+ }
+
+ public <E> Set<E> _getChildrenNames(Fqn<E> fqn) throws CacheException
+ {
+ NodeSPI<K, V> n = findNode(fqn);
+ if (n == null) return null;
+ Set childNames = new HashSet();
+ Map childrenMap = n.getChildrenMapDirect();
+ if (childrenMap == null || childrenMap.isEmpty()) return Collections.emptySet();
+ Collection s = childrenMap.values();
+ // prune deleted children - JBCACHE-1136
+ for (Object c : s)
+ {
+ NodeSPI child = (NodeSPI) c;
+ if (!child.isDeleted()) childNames.add(child.getFqn().getLastElement());
+ }
+ return childNames;
+ }
+
+ /**
+ * Returns true if the FQN exists and the node has children.
+ */
+ public boolean hasChild(Fqn fqn)
+ {
+ if (fqn == null) return false;
+
+ NodeSPI n = findNode(fqn);
+ return n != null && n.hasChildrenDirect();
+ }
+
+ /**
+ * Returns a debug string with few details.
+ */
+ public String toString()
+ {
+ return toString(true);
+ }
+
+
+ /**
+ * Returns a debug string with optional details of contents.
+ */
+ public String toString(boolean details)
+ {
+ StringBuffer sb = new StringBuffer();
+ int indent = 0;
+
+ if (!details)
+ {
+ sb.append(getClass().getName()).append(" [").append(getNumberOfNodes()).append(" nodes, ");
+ sb.append(getNumberOfLocksHeld()).append(" locks]");
+ }
+ else
+ {
+ if (root == null)
+ return sb.toString();
+ for (NodeSPI n : root.getChildrenDirect())
+ {
+ n.print(sb, indent);
+ sb.append("\n");
+ }
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * Prints information about the contents of the nodes in the cache's current
+ * in-memory state. Does not load any previously evicted nodes from a
+ * cache loader, so evicted nodes will not be included.
+ */
+ public String printDetails()
+ {
+ StringBuffer sb = new StringBuffer();
+ root.printDetails(sb, 0);
+ sb.append("\n");
+ return sb.toString();
+ }
+
+ /**
+ * Returns lock information.
+ */
+ public String printLockInfo()
+ {
+ StringBuffer sb = new StringBuffer("\n");
+ int indent = 0;
+
+ for (NodeSPI n : root.getChildrenDirect())
+ {
+ n.getLock().printLockInfo(sb, indent);
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns the number of read or write locks held across the entire cache.
+ */
+ public int getNumberOfLocksHeld()
+ {
+ return numLocks(root);
+ }
+
+ private int numLocks(NodeSPI<K, V> n)
+ {
+ int num = 0;
+ if (n.getLock().isLocked())
+ {
+ num++;
+ }
+ for (NodeSPI<K, V> cn : n.getChildrenDirect(true))
+ {
+ num += numLocks(cn);
+ }
+ return num;
+ }
+
+ /**
+ * Returns an <em>approximation</em> of the total number of nodes in the
+ * cache. Since this method doesn't acquire any locks, the number might be
+ * incorrect, or the method might even throw a
+ * ConcurrentModificationException
+ */
+ public int getNumberOfNodes()
+ {
+ return numNodes(root) - 1;
+ }
+
+ private int numNodes(NodeSPI<K, V> n)
+ {
+ int count = 1;// for n
+ for (NodeSPI<K, V> child : n.getChildrenDirect())
+ {
+ count += numNodes(child);
+ }
+ return count;
+ }
+
+ /**
+ * Returns an <em>approximation</em> of the total number of attributes in
+ * the cache. Since this method doesn't acquire any locks, the number might
+ * be incorrect, or the method might even throw a
+ * ConcurrentModificationException
+ */
+ public int getNumberOfAttributes()
+ {
+ return numAttributes(root);
+ }
+
+ /**
+ * Returns an <em>approximation</em> of the total number of attributes in
+ * this sub cache.
+ *
+ * @see #getNumberOfAttributes
+ */
+ public int getNumberOfAttributes(Fqn fqn)
+ {
+ return numAttributes(findNode(fqn));
+ }
+
+ private int numAttributes(NodeSPI<K, V> n)
+ {
+ int count = 0;
+ for (NodeSPI<K, V> child : n.getChildrenDirect())
+ {
+ count += numAttributes(child);
+ }
+ count += n.getDataDirect().size();
+ return count;
+ }
+
+ /* ---------------------- Remote method calls -------------------- */
+
+ /**
+ * @param mbrs
+ * @param method_call
+ * @param synchronous
+ * @param exclude_self
+ * @param timeout
+ * @return
+ * @throws Exception
+ * @deprecated Note this is due to be moved to an interceptor.
+ */
+ @Deprecated
+ public List callRemoteMethods(List<Address> mbrs, MethodCall method_call,
+ boolean synchronous, boolean exclude_self, long timeout)
+ throws Exception
+ {
+ return callRemoteMethods(mbrs, method_call, synchronous ? GroupRequest.GET_ALL : GroupRequest.GET_NONE, exclude_self, timeout);
+ }
+
+
+ /**
+ * Overloaded to allow a finer grained control over JGroups mode
+ *
+ * @param mbrs
+ * @param method_call
+ * @param mode
+ * @param exclude_self
+ * @param timeout
+ * @return
+ * @throws Exception
+ * @deprecated Note this is due to be moved to an interceptor.
+ */
+ @Deprecated
+ public List callRemoteMethods(List<Address> mbrs, MethodCall method_call, int mode, boolean exclude_self, long timeout)
+ throws Exception
+ {
+ RspList rsps = null;
+ Rsp rsp;
+ List retval;
+ Vector<Address> validMembers;
+
+ if (disp == null)
+ {
+ return null;
+ }
+
+ validMembers = null;
+ if (mbrs != null)
+ validMembers = new Vector<Address>(mbrs);
+ else
+ {
+ synchronized (members)
+ {
+ validMembers = new Vector<Address>(this.members);
+ }
+ }
+
+ if (exclude_self && !validMembers.isEmpty())
+ {
+ Object local_addr = getLocalAddress();
+ if (local_addr != null)
+ {
+ validMembers.remove(local_addr);
+ }
+ }
+ if (validMembers.isEmpty())
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("destination list is empty, discarding call");
+ }
+ return null;
+ }
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("callRemoteMethods(): valid members are " + validMembers + " methods: " + method_call.getArgs()[0]);
+ }
+
+ if (channel.flushSupported())
+ {
+ flushBlockGate.await(configuration.getStateRetrievalTimeout());
+ rsps = disp.callRemoteMethods(validMembers, method_call, mode, timeout, buddyManager != null && buddyManager.isEnabled());
+ }
+ else
+ {
+ rsps = disp.callRemoteMethods(validMembers, method_call, mode, timeout, buddyManager != null && buddyManager.isEnabled());
+ }
+
+ // a null response is 99% likely to be due to a marshalling problem - we throw a NSE, this needs to be changed when
+ // JGroups supports http://jira.jboss.com/jira/browse/JGRP-193
+ if (rsps == null)
+ {
+ // return null;
+ throw new NotSerializableException("RpcDispatcher returned a null. This is most often caused by args for " + method_call + " not being serializable.");
+ }
+ if (mode == GroupRequest.GET_NONE)
+ {
+ return Collections.EMPTY_LIST;// async case
+ }
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("(" + getLocalAddress() + "): responses for method " + method_call.getName() + ":\n" + rsps);
+ }
+
+ retval = new ArrayList(rsps.size());
+ for (int i = 0; i < rsps.size(); i++)
+ {
+ rsp = (Rsp) rsps.elementAt(i);
+ if (rsp.wasSuspected() || !rsp.wasReceived())
+ {
+ CacheException ex;
+ if (rsp.wasSuspected())
+ {
+ ex = new SuspectException("Suspected member: " + rsp.getSender());
+ }
+ else
+ {
+ ex = new TimeoutException("Replication timeout for " + rsp.getSender());
+ }
+ retval.add(new ReplicationException("rsp=" + rsp, ex));
+ }
+ else
+ {
+ retval.add(rsp.getValue());
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * @param members
+ * @param method
+ * @param args
+ * @param synchronous
+ * @param exclude_self
+ * @param timeout
+ * @return
+ * @throws Exception
+ * @deprecated Note this is due to be moved to an interceptor.
+ */
+ @Deprecated
+ public List callRemoteMethods(List<Address> members, Method method, Object[] args,
+ boolean synchronous, boolean exclude_self, long timeout)
+ throws Exception
+ {
+ return callRemoteMethods(members, MethodCallFactory.create(method, args), synchronous, exclude_self, timeout);
+ }
+
+ /**
+ * @param members
+ * @param method_name
+ * @param types
+ * @param args
+ * @param synchronous
+ * @param exclude_self
+ * @param timeout
+ * @return
+ * @throws Exception
+ * @deprecated Note this is due to be moved to an interceptor.
+ */
+ @Deprecated
+ public List callRemoteMethods(Vector<Address> members, String method_name,
+ Class[] types, Object[] args,
+ boolean synchronous, boolean exclude_self, long timeout)
+ throws Exception
+ {
+ Method method = getClass().getDeclaredMethod(method_name, types);
+ return callRemoteMethods(members, method, args, synchronous, exclude_self, timeout);
+ }
+
+ /* -------------------- End Remote method calls ------------------ */
+
+ /* --------------------- Callbacks -------------------------- */
+
+ /* ----- These are VERSIONED callbacks to facilitate JBCACHE-843. Also see docs/design/DataVersion.txt --- */
+
+ public void _putForExternalRead(GlobalTransaction gtx, Fqn fqn, K key, V value, DataVersion dv) throws CacheException
+ {
+ _putForExternalRead(gtx, fqn, key, value);
+ }
+
+ public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, DataVersion dv) throws CacheException
+ {
+ _put(tx, fqn, data, create_undo_ops, false, dv);
+ }
+
+ public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, boolean erase_contents, DataVersion dv) throws CacheException
+ {
+ _put(tx, fqn, data, create_undo_ops, erase_contents);
+ }
+
+ public Object _put(GlobalTransaction tx, Fqn fqn, K key, V value, boolean create_undo_ops, DataVersion dv) throws CacheException
+ {
+ return _put(tx, fqn, key, value, create_undo_ops);
+ }
+
+ public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, DataVersion dv) throws CacheException
+ {
+ return _remove(tx, fqn, create_undo_ops, true);
+ }
+
+ public Object _remove(GlobalTransaction tx, Fqn fqn, K key, boolean create_undo_ops, DataVersion dv) throws CacheException
+ {
+ return _remove(tx, fqn, key, create_undo_ops);
+ }
+
+ public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, DataVersion dv) throws CacheException
+ {
+
+ _removeData(tx, fqn, create_undo_ops, true);
+ }
+
+ /* ----- End VERSIONED callbacks - Now for the NORMAL callbacks. -------- */
+
+ /**
+ * Internal put method.
+ * Does the real work. Needs to acquire locks if accessing nodes, depending on
+ * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
+ * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
+ * that were created to {@link TransactionEntry}'s node list and (c) create
+ * {@link Modification}s and add them to {@link TransactionEntry}'s modification
+ * list and (d) create compensating modifications to undo the changes in case
+ * of a rollback
+ *
+ * @param fqn
+ * @param data
+ * @param create_undo_ops If true, undo operations will be created (default is true).
+ * Otherwise they will not be created (used by rollback()).
+ */
+ public void _put(GlobalTransaction tx, String fqn, Map<K, V> data, boolean create_undo_ops)
+ throws CacheException
+ {
+ _put(tx, Fqn.fromString(fqn), data, create_undo_ops);
+ }
+
+
+ /**
+ * Internal put method.
+ * Does the real work. Needs to acquire locks if accessing nodes, depending on
+ * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
+ * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
+ * that were created to {@link TransactionEntry}'s node list and (c) create
+ * {@link Modification}s and add them to {@link TransactionEntry}'s modification
+ * list and (d) create compensating modifications to undo the changes in case
+ * of a rollback
+ *
+ * @param fqn
+ * @param data
+ * @param create_undo_ops If true, undo operations will be created (default is true).
+ * Otherwise they will not be created (used by rollback()).
+ */
+ public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops)
+ throws CacheException
+ {
+ _put(tx, fqn, data, create_undo_ops, false);
+ }
+
+ /**
+ * Internal put method.
+ * Does the real work. Needs to acquire locks if accessing nodes, depending on
+ * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
+ * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
+ * that were created to {@link TransactionEntry}'s node list and (c) create
+ * {@link Modification}s and add them to {@link TransactionEntry}'s modification
+ * list and (d) create compensating modifications to undo the changes in case
+ * of a rollback
+ *
+ * @param fqn
+ * @param data
+ * @param create_undo_ops If true, undo operations will be created (default is true).
+ * @param erase_contents Clear the existing hashmap before putting the new data into it
+ * Otherwise they will not be created (used by rollback()).
+ */
+ public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, boolean erase_contents)
+ throws CacheException
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("_put(" + tx + ", \"" + fqn + "\", " + data + " undo=" + create_undo_ops + " erase=" + erase_contents + ")");
+ }
+ InvocationContext ctx = getInvocationContext();
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+ NodeSPI<K, V> n = findNodeCheck(tx, fqn);
+ Map<K, V> rawData = n.getDataDirect();
+ if (!isRollback) notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_MAP, rawData, ctx);
+
+ // create a compensating method call (reverting the effect of
+ // this modification) and put it into the TX's undo list.
+ if (tx != null && create_undo_ops)
+ {
+ // erase and set to previous hashmap contents
+ MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.putDataEraseMethodLocal, tx, fqn, new HashMap(rawData), false, true);
+ tx_table.addUndoOperation(tx, undo_op);
+ }
+
+ if (erase_contents)
+ n.clearDataDirect();
+ n.putAllDirect(data);
+
+ if (!isRollback)
+ notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.PUT_MAP, n.getDataDirect(), ctx);
+ }
+
+ /**
+ * Internal put method.
+ *
+ * @return Previous value (if any)
+ */
+ public Object _put(GlobalTransaction tx, String fqn, K key, V value, boolean create_undo_ops)
+ throws CacheException
+ {
+ return _put(tx, Fqn.fromString(fqn), key, value, create_undo_ops);
+ }
+
+ private boolean checkIsRollingBack(Transaction tx)
+ {
+ try
+ {
+ return tx != null && (
+ tx.getStatus() == javax.transaction.Status.STATUS_ROLLEDBACK ||
+ tx.getStatus() == javax.transaction.Status.STATUS_ROLLING_BACK ||
+ tx.getStatus() == javax.transaction.Status.STATUS_MARKED_ROLLBACK);
+ }
+ catch (Exception e)
+ {
+ // can't get a hold of a transaction - probably no tx rolling back
+ return false;
+ }
+ }
+
+ /**
+ * Internal put method.
+ *
+ * @return Previous value (if any)
+ */
+ public Object _put(GlobalTransaction tx, Fqn fqn, K key, V value, boolean create_undo_ops)
+ throws CacheException
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace(new StringBuffer("_put(").append(tx).append(", \"").
+ append(fqn).append("\", k=").append(key).append(", v=").append(value).append(")"));
+ }
+
+
+ InvocationContext ctx = getInvocationContext();
+ // if this is a rollback then don't fire notifications.
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+
+ NodeSPI<K, V> n = findNodeCheck(tx, fqn);
+ Map<K, V> rawData = n.getDataDirect();
+ if (!isRollback)
+ notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_DATA, rawData, ctx);
+
+ V old_value = n.putDirect(key, value);
+
+ // create a compensating method call (reverting the effect of
+ // this modification) and put it into the TX's undo list.
+ if (tx != null && create_undo_ops)
+ {
+ MethodCall undo_op;
+ if (old_value == null)
+ {
+ undo_op = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal, tx, fqn, key, false);
+ }
+ else
+ {
+ undo_op = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, old_value, false);
+ }
+ // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
+ tx_table.addUndoOperation(tx, undo_op);
+ }
+
+ Map<K, V> newData = Collections.singletonMap(key, value);
+ if (!isRollback)
+ notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.PUT_DATA, newData, ctx);
+ return old_value;
+ }
+
+ /**
+ * Internal remove method.
+ */
+ public void _remove(GlobalTransaction tx, String fqn, boolean create_undo_ops) throws CacheException
+ {
+ _remove(tx, Fqn.fromString(fqn), create_undo_ops);
+ }
+
+ /**
+ * Internal remove method.
+ */
+ public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops) throws CacheException
+ {
+ return _remove(tx, fqn, create_undo_ops, true);
+ }
+
+ public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent)
+ throws CacheException
+ {
+ return _remove(tx, fqn, create_undo_ops, sendNodeEvent, false);
+ }
+
+ /**
+ * Internal method to remove a node.
+ *
+ * @param tx
+ * @param fqn
+ * @param create_undo_ops
+ * @param sendNodeEvent
+ */
+ public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction)
+ throws CacheException
+ {
+ return _remove(tx, fqn, create_undo_ops, sendNodeEvent, eviction, null);
+ }
+
+ /**
+ * Internal method to remove a node.
+ * Performs a remove on a node, passing in a {@link DataVersion} which is used with optimistically locked nodes. Pass
+ * in a null if optimistic locking is not used.
+ *
+ * @param tx
+ * @param fqn
+ * @param create_undo_ops
+ * @param sendNodeEvent
+ * @param eviction
+ * @param version
+ * @return true if the node was removed, false if not found
+ * @throws CacheException
+ */
+ public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction, DataVersion version)
+ throws CacheException
+ {
+
+ NodeSPI<K, V> n;
+ NodeSPI<K, V> parent_node;
+ MethodCall undo_op = null;
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("_remove(" + tx + ", \"" + fqn + "\", undo=" + create_undo_ops + ")");
+ }
+ InvocationContext ctx = getInvocationContext();
+ // check if this is triggered by a rollback operation ...
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+ if (tx != null)
+ {
+ try
+ {
+ if (isRollback)
+ {
+ log.trace("This remove call is triggered by a transaction rollback, as a compensation operation. Do a realRemove() instead.");
+ return realRemove(fqn, true);
+ }
+ }
+ catch (Exception e)
+ {
+ // what do we do here?
+ log.warn("Unable to get a hold of the transaction for a supposedly transactional call! This *may* result in stale locks!", e);
+ }
+ }
+
+ // Find the node. This will add the temporarily created parent nodes to the TX's node list if tx != null)
+ n = findNode(fqn, version);
+ if (n == null)
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("node " + fqn + " not found");
+ }
+ return false;
+ }
+
+ if (!isRollback)
+ {
+ if (eviction)
+ {
+ notifier.notifyNodeEvicted(fqn, true, ctx);
+ }
+ else
+ {
+ notifier.notifyNodeRemoved(fqn, true, n.getDataDirect(), ctx);
+ }
+ }
+
+ parent_node = n.getParent();
+ boolean found;
+
+ // remove subtree from parent
+ if (eviction || configuration.isNodeLockingOptimistic())
+ {
+ // if there is no parent node and the fqn is root, found == true otherwise found == false.
+ found = parent_node == null ? fqn.isRoot() : parent_node.removeChildDirect(n.getFqn().getLastElement());
+ }
+ else
+ {
+ found = !n.isDeleted();
+ n.markAsDeleted(true);
+ }
+
+ if (eviction && parent_node != null)
+ {
+ parent_node.setChildrenLoaded(false);
+ }
+
+ // release all locks for the entire subtree
+ // n.getNodeSPI().getLock().releaseAll(tx != null ? tx : (Object) Thread.currentThread());
+
+ // create a compensating method call (reverting the effect of
+ // this modification) and put it into the TX's undo list.
+ if (tx != null && create_undo_ops && !eviction)
+ {
+ undo_op = MethodCallFactory.create(MethodDeclarations.addChildMethodLocal, tx, parent_node.getFqn(), n.getFqn().getLastElement(), n, false);
+
+ // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
+ tx_table.addUndoOperation(tx, undo_op);
+ }
+
+ if (!isRollback)
+ {
+ if (eviction)
+ {
+ notifier.notifyNodeEvicted(fqn, false, ctx);
+ }
+ else
+ {
+ notifier.notifyNodeRemoved(fqn, false, null, ctx);
+ }
+ }
+
+ return found;
+ }
+
+ /**
+ * Internal method to remove a key.
+ *
+ * @param fqn
+ * @param key
+ * @return Object
+ */
+ public V _remove(GlobalTransaction tx, String fqn, K key, boolean create_undo_ops)
+ throws CacheException
+ {
+ return _remove(tx, Fqn.fromString(fqn), key, create_undo_ops);
+ }
+
+ /**
+ * Internal method to remove a key.
+ *
+ * @param fqn
+ * @param key
+ * @return Object
+ */
+ public V _remove(GlobalTransaction tx, Fqn fqn, K key, boolean create_undo_ops)
+ throws CacheException
+ {
+ MethodCall undo_op = null;
+ V old_value = null;
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("_remove(" + tx + ", \"" + fqn + "\", key=" + key + ")");
+ }
+
+ // Find the node. This will lock it (if <tt>locking</tt> is true) and
+ // add the temporarily created parent nodes to the TX's node list if tx != null)
+ NodeSPI<K, V> n = findNode(fqn);
+ if (n == null)
+ {
+ log.warn("node " + fqn + " not found");
+ return null;
+ }
+ InvocationContext ctx = getInvocationContext();
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+ if (!isRollback)
+ notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, n.getDataDirect(), ctx);
+
+ old_value = n.removeDirect(key);
+
+ // create a compensating method call (reverting the effect of
+ // this modification) and put it into the TX's undo list.
+ if (tx != null && create_undo_ops && old_value != null)
+ {
+ undo_op = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, old_value, false);
+ // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
+ tx_table.addUndoOperation(tx, undo_op);
+ }
+
+ Map<K, V> removedData = Collections.singletonMap(key, old_value);
+ if (!isRollback)
+ notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, removedData, ctx);
+
+ return old_value;
+ }
+
+ /**
+ * Internal method to remove data from a node.
+ */
+ public void _removeData(GlobalTransaction tx, String fqn, boolean create_undo_ops)
+ throws CacheException
+ {
+ _removeData(tx, Fqn.fromString(fqn), create_undo_ops);
+ }
+
+ /**
+ * Internal method to remove data from a node.
+ */
+ public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops)
+ throws CacheException
+ {
+ _removeData(tx, fqn, create_undo_ops, true);
+ }
+
+ /**
+ * Internal method to remove data from a node.
+ */
+ public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent)
+ throws CacheException
+ {
+ _removeData(tx, fqn, create_undo_ops, sendNodeEvent, false);
+ }
+
+ /**
+ * Internal method to remove data from a node.
+ */
+ public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction)
+ throws CacheException
+ {
+ _removeData(tx, fqn, create_undo_ops, sendNodeEvent, eviction, null);
+ }
+
+ /**
+ * Internal method to remove data from a node.
+ */
+ public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction, DataVersion version)
+ throws CacheException
+ {
+ MethodCall undo_op = null;
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("_removeData(" + tx + ", \"" + fqn + "\")");
+ }
+
+ // Find the node. This will lock it (if <tt>locking</tt> is true) and
+ // add the temporarily created parent nodes to the TX's node list if tx != null)
+ NodeSPI n = findNode(fqn, version);
+ if (n == null)
+ {
+ log.warn("node " + fqn + " not found");
+ return;
+ }
+
+ Map<K, V> data = n.getDataDirect();
+ InvocationContext ctx = getInvocationContext();
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+ // create a compensating method call (reverting the effect of
+ // this modification) and put it into the TX's undo list.
+ if (tx != null && create_undo_ops && !eviction)
+ {
+ if (!data.isEmpty())
+ {
+ undo_op = MethodCallFactory.create(MethodDeclarations.putDataMethodLocal,
+ tx, fqn, new HashMap<K,V>(data), false);
+ }
+ }
+
+ if (!isRollback)
+ {
+ if (eviction)
+ {
+ notifier.notifyNodeEvicted(fqn, true, ctx);
+ }
+ else
+ {
+ notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
+ }
+ }
+
+ n.clearDataDirect();
+ if (eviction)
+ {
+ n.setDataLoaded(false);
+ }
+
+ if (!isRollback)
+ {
+ if (sendNodeEvent)
+ {
+ notifier.notifyNodeVisited(fqn, false, ctx);
+ }
+ else
+ {// FIXME Bela did this so GUI view can refresh the view after node is evicted. But this breaks eviction policy, especially AOP!!!!
+ if (eviction)
+ {
+ notifier.notifyNodeEvicted(fqn, false, ctx);
+ }
+ else
+ {
+ notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
+ }
+ }
+ }
+
+ // put undo-op in TX' undo-operations list (needed to rollback TX)
+ if (tx != null && create_undo_ops)
+ {
+ tx_table.addUndoOperation(tx, undo_op);
+ }
+ }
+
+
+ /**
+ * Internal evict method called by eviction policy provider.
+ *
+ * @param fqn removes everything assoicated with this FQN
+ * @return <code>true</code> if the node has been completely removed,
+ * <code>false</code> if only the data map was removed, due
+ * to the presence of children
+ * @throws CacheException
+ */
+ public boolean _evict(Fqn fqn) throws CacheException
+ {
+ if (!exists(fqn))
+ return true;// node does not exist. Maybe it has been recursively removed.
+ // use remove method now if there is a child node. Otherwise, it is removed
+ boolean create_undo_ops = false;
+ boolean sendNodeEvent = false;
+ boolean eviction = true;
+ if (log.isTraceEnabled())
+ {
+ log.trace("_evict(" + fqn + ")");
+ }
+ if (hasChild(fqn))
+ {
+ _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction);
+ return false;
+ }
+ else
+ {
+ _remove(null, fqn, create_undo_ops, sendNodeEvent, eviction);
+ return true;
+ }
+ }
+
+ /**
+ * Internal evict method called by eviction policy provider.
+ *
+ * @param fqn
+ * @param version
+ * @return <code>true</code> if the node has been completely removed,
+ * <code>false</code> if only the data map was removed, due
+ * to the presence of children
+ * @throws CacheException
+ */
+ public boolean _evict(Fqn fqn, DataVersion version) throws CacheException
+ {
+ if (!exists(fqn))
+ return true;// node does not exist
+
+ boolean create_undo_ops = false;
+ boolean sendNodeEvent = false;
+ boolean eviction = true;
+ if (log.isTraceEnabled())
+ {
+ log.trace("_evict(" + fqn + ", " + version + ")");
+ }
+ if (hasChild(fqn))
+ {
+ _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction, version);
+ return false;
+ }
+ else
+ {
+ _remove(null, fqn, create_undo_ops, sendNodeEvent, eviction, version);
+ return true;
+ }
+ }
+
+ /**
+ * Evicts a key/value pair from a node's attributes. Note that this is <em>local</em>, will not be replicated.
+ * @param fqn
+ * @param key
+ * @throws CacheException
+ */
+ // public void _evict(Fqn fqn, Object key) throws CacheException {
+ // if(!exists(fqn)) return;
+ // boolean create_undo_ops = false;
+ // boolean sendNodeEvent = false;
+ // boolean eviction=true;
+ // _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction);
+ // }
+
+
+ /**
+ * Compensating method to {@link #_remove(GlobalTransaction,Fqn,boolean)}.
+ */
+ public void _addChild(GlobalTransaction gtx, Fqn parent_fqn, Object child_name, Node cn, boolean undoOps)
+ throws CacheException
+ {
+ NodeSPI childNode = (NodeSPI) cn;
+ if (log.isTraceEnabled())
+ {
+ log.trace("_addChild(\"" + parent_fqn + "\", \"" + child_name + "\", node=" + childNode + ")");
+ }
+
+ if (parent_fqn == null || child_name == null || childNode == null)
+ {
+ log.error("parent_fqn or child_name or childNode was null");
+ return;
+ }
+ NodeSPI parentNode = findNode(parent_fqn);
+ if (parentNode == null)
+ {
+ log.warn("node " + parent_fqn + " not found");
+ return;
+ }
+ InvocationContext ctx = getInvocationContext();
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+ Fqn fqn = new Fqn(parent_fqn, child_name);
+ if (!isRollback) notifier.notifyNodeCreated(fqn, true, ctx);
+ parentNode.addChild(child_name, childNode);
+
+ childNode.markAsDeleted(false, true);
+
+ if (gtx != null && undoOps)
+ {
+ // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
+ tx_table.addUndoOperation(gtx, MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, gtx, fqn, false));
+ }
+
+ if (!isRollback) notifier.notifyNodeCreated(fqn, false, ctx);
+ }
+
+
+ /**
+ * Replicates changes across to other nodes in the cluster. Invoked by the
+ * ReplicationInterceptor. Calls need to be forwarded to the
+ * ReplicationInterceptor in this interceptor chain. This method will later
+ * be moved entirely into the ReplicationInterceptor.
+ */
+ public Object _replicate(MethodCall method_call) throws Throwable
+ {
+ try
+ {
+ Object retVal = invokeMethod(method_call, false);
+ // we only need to return values for a set of remote calls; not every call.
+ if (MethodDeclarations.returnValueForRemoteCall(method_call.getMethodId()))
+ {
+ return retVal;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ catch (Throwable ex)
+ {
+ log.warn("replication failure with method_call " + method_call + " exception", ex);
+ throw ex;
+ }
+ }
+
+ /**
+ * Replicates a list of method calls.
+ */
+ public void _replicate(List<MethodCall> methodCalls) throws Throwable
+ {
+ for (MethodCall methodCall : methodCalls) _replicate(methodCall);
+ }
+
+ /**
+ * A 'clustered get' call, called from a remote ClusteredCacheLoader.
+ *
+ * @return a List containing 2 elements: (true or false) and a value (Object). If buddy replication
+ * is used one further element is added - an Fqn of the backup subtree in which this node may be found.
+ */
+ public List _clusteredGet(MethodCall methodCall, Boolean searchBackupSubtrees)
+ {
+ MethodCall call = methodCall;
+ if (log.isTraceEnabled()) log.trace("Clustered Get called with params: " + call + ", " + searchBackupSubtrees);
+ Method m = call.getMethod();
+ Object[] args = call.getArgs();
+
+ Object callResults = null;
+
+ try
+ {
+ Fqn fqn = (Fqn) args[0];
+
+ if (log.isTraceEnabled()) log.trace("Clustered get: invoking call " + m + " with Fqn " + fqn);
+ callResults = m.invoke(this, args);
+ boolean found = validResult(callResults, call, fqn);
+ if (log.isTraceEnabled()) log.trace("Got result " + callResults + ", found=" + found);
+ if (found && callResults == null) callResults = createEmptyResults(call);
+ }
+ catch (Exception e)
+ {
+ log.warn("Problems processing clusteredGet call", e);
+ }
+
+ List<Object> results = new ArrayList<Object>(2);
+ if (callResults != null)
+ {
+ results.add(true);
+ results.add(callResults);
+ }
+ else
+ {
+ results.add(false);
+ results.add(null);
+ }
+ return results;
+ }
+
+ /**
+ * Used with buddy replication's data gravitation interceptor. If marshalling is necessary, ensure that the cache is
+ * configured to use {@link org.jboss.cache.config.Configuration#useRegionBasedMarshalling} and the {@link org.jboss.cache.Region}
+ * pertaining to the Fqn passed in is activated, and has an appropriate ClassLoader.
+ *
+ * @param fqn the fqn to gravitate
+ * @param searchSubtrees if true, buddy backup subtrees are searched and if false, they are not.
+ * @return a GravitateResult which contains the data for the gravitation
+ */
+ public GravitateResult gravitateData(Fqn fqn, boolean searchSubtrees)
+ throws CacheException
+ {
+ // we need to get the state for this Fqn and its sub-nodes.
+
+ // for now, perform a very simple series of getData calls.
+ InvocationContext ctx = getInvocationContext();
+
+ log.debug("*****************>>>>> " + printLockInfo());
+
+ try
+ {
+ ctx.setOriginLocal(false);
+
+ NodeSPI<K, V> actualNode = findNode(fqn);
+ Fqn backupNodeFqn = null;
+ if (actualNode == null && searchSubtrees)
+ {
+ NodeSPI backupSubtree = findNode(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
+ if (backupSubtree != null)
+ {
+ // need to loop through backupSubtree's children
+ Set childNames = backupSubtree.getChildrenNamesDirect();
+ if (childNames != null)
+ {
+ for (Object childName : childNames)
+ {
+ // childName is the name of a buddy group since all child names in this
+ // collection are direct children of BUDDY_BACKUP_SUBTREE_FQN
+ backupNodeFqn = BuddyManager.getBackupFqn(childName.toString(), fqn);
+ actualNode = findNode(backupNodeFqn);
+ if (actualNode != null) break;
+ }
+ }
+ /*Map children = backupSubtree.getChildrenMapDirect();
+ if (children != null)
+ {
+ Iterator childNames = children.keySet().iterator();
+ while (childNames.hasNext() && actualNode == null)
+ {
+ backupNodeFqn = BuddyManager.getBackupFqn(childNames.next().toString(), fqn);
+ actualNode = findNode(backupNodeFqn);
+ }
+ }*/
+ }
+ }
+
+ if (actualNode == null)
+ {
+ return GravitateResult.noDataFound();
+ }
+
+ if (backupNodeFqn == null && searchSubtrees)
+ {
+ backupNodeFqn = BuddyManager.getBackupFqn(BuddyManager.getGroupNameFromAddress(getLocalAddress()), fqn);
+ }
+
+ List<NodeData> list = getNodeData(new LinkedList<NodeData>(), actualNode);
+
+ return GravitateResult.subtreeResult(list, backupNodeFqn);
+ }
+ finally
+ {
+ ctx.setOriginLocal(true);
+ }
+ }
+
+ private List<NodeData> getNodeData(List<NodeData> list, NodeSPI<K, V> node)
+ {
+ NodeData data = new NodeData(BuddyManager.getActualFqn(node.getFqn()), node.getDataDirect());
+ list.add(data);
+ for (NodeSPI<K, V> childNode : node.getChildrenDirect())
+ {
+ getNodeData(list, childNode);
+ }
+ return list;
+ }
+
+ // ------------- start: buddy replication specific 'lifecycle' method calls
+
+ public void _remoteAssignToBuddyGroup(BuddyGroup group, Map<Fqn, byte[]> state) throws Exception
+ {
+ if (buddyManager != null)
+ buddyManager.handleAssignToBuddyGroup(group, state);
+ else if (log.isWarnEnabled())
+ log.warn("Received assignToBuddyGroup call from group owner [" + group.getDataOwner() + "] but buddy replication is not enabled on this node!");
+ }
+
+ public void _remoteRemoveFromBuddyGroup(String groupName) throws BuddyNotInitException
+ {
+ if (buddyManager != null)
+ buddyManager.handleRemoveFromBuddyGroup(groupName);
+ else if (log.isWarnEnabled())
+ log.warn("Received removeFromBuddyGroup call for group name [" + groupName + "] but buddy replication is not enabled on this node!");
+
+ }
+
+ public void _remoteAnnounceBuddyPoolName(Address address, String buddyPoolName)
+ {
+ if (buddyManager != null)
+ buddyManager.handlePoolNameBroadcast(address, buddyPoolName);
+ else if (log.isWarnEnabled())
+ log.warn("Received annouceBuddyPoolName call from [" + address + "] but buddy replication is not enabled on this node!");
+ }
+
+ public void _dataGravitationCleanup(GlobalTransaction gtx, Fqn primary, Fqn backup) throws Exception
+ {
+ MethodCall primaryDataCleanup, backupDataCleanup;
+ if (buddyManager.isDataGravitationRemoveOnFind())
+ {
+ if (log.isTraceEnabled())
+ log.trace("DataGravitationCleanup: Removing primary (" + primary + ") and backup (" + backup + ")");
+ primaryDataCleanup = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, null, primary, false);
+ backupDataCleanup = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, null, backup, false);
+ }
+ else
+ {
+ if (log.isTraceEnabled())
+ log.trace("DataGravitationCleanup: Evicting primary (" + primary + ") and backup (" + backup + ")");
+ primaryDataCleanup = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, primary);
+ backupDataCleanup = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, backup);
+ }
+
+ invokeMethod(primaryDataCleanup, true);
+ invokeMethod(backupDataCleanup, true);
+ }
+
+ // ------------- end: buddy replication specific 'lifecycle' method calls
+
+
+ /**
+ * Returns true if the call results returned a valid result.
+ */
+ private boolean validResult(Object callResults, MethodCall mc, Fqn fqn)
+ {
+ switch (mc.getMethodId())
+ {
+ case MethodDeclarations.getDataMapMethodLocal_id:
+ case MethodDeclarations.getChildrenNamesMethodLocal_id:
+ return callResults != null || exists(fqn);
+ case MethodDeclarations.existsMethod_id:
+ return (Boolean) callResults;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Creates an empty Collection class based on the return type of the method called.
+ */
+ private Object createEmptyResults(MethodCall mc)
+ {
+ switch (mc.getMethodId())
+ {
+ case MethodDeclarations.getDataMapMethodLocal_id:
+ case MethodDeclarations.getChildrenNamesMethodLocal_id:
+ return Collections.emptyMap();
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Releases all locks for a FQN.
+ */
+ public void _releaseAllLocks(Fqn fqn)
+ {
+ NodeSPI<K, V> n;
+
+ try
+ {
+ n = findNode(fqn);
+ if (n == null)
+ {
+ log.error("releaseAllLocks(): node " + fqn + " not found");
+ return;
+ }
+ releaseAll(n);
+ }
+ catch (Throwable t)
+ {
+ log.error("releaseAllLocks(): failed", t);
+ }
+ }
+
+ private void releaseAll(NodeSPI<K, V> n)
+ {
+ for (NodeSPI<K, V> child : n.getChildrenDirect())
+ {
+ releaseAll(child);
+ }
+ n.getLock().releaseAll();
+ }
+
+
+ /**
+ * Finds and returns the string value for the Fqn.
+ * Returns null if not found or upon error.
+ */
+ public String _print(Fqn fqn)
+ {
+ try
+ {
+ Node n = findNode(fqn);
+ if (n == null) return null;
+ return n.toString();
+ }
+ catch (Throwable t)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Should not be called.
+ */
+ public void _lock(Fqn fqn, NodeLock.LockType lock_type, boolean recursive)
+ throws TimeoutException, LockingException
+ {
+ throw new UnsupportedOperationException("method _lock() should not be invoked on CacheImpl");
+ }
+
+ /**
+ * Throws UnsupportedOperationException.
+ */
+ public void optimisticPrepare(GlobalTransaction gtx, List modifications, Map data, Address address, boolean onePhaseCommit)
+ {
+ throw new UnsupportedOperationException("optimisticPrepare() should not be called on CacheImpl directly");
+ }
+
+ /**
+ * Throws UnsupportedOperationException.
+ */
+ public void prepare(GlobalTransaction global_tx, List modifications, Address coord, boolean onePhaseCommit)
+ {
+ throw new UnsupportedOperationException("prepare() should not be called on CacheImpl directly");
+ }
+
+ /**
+ * Throws UnsupportedOperationException.
+ */
+ public void commit(GlobalTransaction tx)
+ {
+ throw new UnsupportedOperationException("commit() should not be called on CacheImpl directly");
+ }
+
+ /**
+ * Throws UnsupportedOperationException.
+ */
+ public void rollback(GlobalTransaction tx)//, Boolean hasMods)
+ {
+ throw new UnsupportedOperationException("rollback() should not be called on CacheImpl directly");
+ }
+
+ /* ----------------- End of Callbacks ---------------------- */
+
+ /**
+ * Adds an undo operatoin to the transaction table.
+ */
+ public void addUndoOperation(GlobalTransaction gtx, MethodCall undo_op)
+ {
+ tx_table.addUndoOperation(gtx, undo_op);
+ }
+
+ /**
+ * Returns the CacheLoaderManager.
+ */
+ public CacheLoaderManager getCacheLoaderManager()
+ {
+ return cacheLoaderManager;
+ }
+
+ /**
+ * Sets the CacheLoaderManager.
+ */
+ public void setCacheLoaderManager(CacheLoaderManager cacheLoaderManager)
+ {
+ this.cacheLoaderManager = cacheLoaderManager;
+ }
+
+ public void setConfiguration(Configuration configuration)
+ {
+ this.configuration = configuration;
+ configuration.setCacheImpl(this);
+ }
+
+ /**
+ * @return an instance of {@link Notifier} which has been configured with this instance of CacheImpl.
+ */
+ public Notifier getNotifier()
+ {
+ return notifier;
+ }
+
+ public InvocationContext getInvocationContext()
+ {
+ InvocationContext ctx = invocationContextContainer.get();
+ if (ctx == null)
+ {
+ ctx = new InvocationContext();
+ invocationContextContainer.set(ctx);
+ }
+ return ctx;
+ }
+
+ public void setInvocationContext(InvocationContext ctx)
+ {
+ invocationContextContainer.set(ctx);
+ }
+
+ /**
+ * New API to efficiently relocate a node
+ *
+ * @since 2.0.0
+ */
+ public void move(Fqn<?> nodeToMove, Fqn<?> newParent)
+ {
+ // this needs to be passed up the interceptor chain
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.moveMethodLocal, nodeToMove, newParent);
+ invokeMethod(m, true);
+ }
+
+ /**
+ * Called by reflection
+ *
+ * @param newParentFqn
+ * @param nodeToMoveFqn
+ */
+ public void _move(Fqn nodeToMoveFqn, Fqn newParentFqn)
+ {
+ // the actual move algorithm.
+ NodeSPI<K, V> newParent = findNode(newParentFqn);
+
+ if (newParent == null)
+ {
+ throw new NodeNotExistsException("New parent node " + newParentFqn + " does not exist when attempting to move node!!");
+ }
+
+ NodeSPI<K, V> node = findNode(nodeToMoveFqn);
+
+ if (node == null)
+ {
+ throw new NodeNotExistsException("Node " + nodeToMoveFqn + " does not exist when attempting to move node!!");
+ }
+
+ NodeSPI oldParent = node.getParent();
+ Object nodeName = nodeToMoveFqn.getLastElement();
+
+ // now that we have the parent and target nodes:
+ // first correct the pointers at the pruning point
+ oldParent.removeChildDirect(nodeName);
+ newParent.addChild(nodeName, node);
+ InvocationContext ctx = getInvocationContext();
+ // parent pointer is calculated on the fly using Fqns.
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+
+ // notify
+ if (!isRollback)
+ notifier.notifyNodeMoved(nodeToMoveFqn, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), true, ctx);
+
+ // now adjust Fqns of node and all children.
+ moveFqns(node, newParent.getFqn());
+
+ if (!isRollback)
+ notifier.notifyNodeMoved(nodeToMoveFqn, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), false, ctx);
+
+ // now register an undo op
+ if (ctx.getTransaction() != null)
+ {
+ MethodCall undo = MethodCallFactory.create(MethodDeclarations.moveMethodLocal, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), oldParent.getFqn());
+ tx_table.addUndoOperation(ctx.getGlobalTransaction(), undo);
+ }
+ }
+
+ public void _block()
+ {
+ //intentionally empty, used only for reflection in MethodDeclarations.blockChannelLocal
+ }
+
+ public void _unblock()
+ {
+ //intentionally empty, used only for reflection in MethodDeclarations.unblockChannelLocal
+ }
+
+ private void moveFqns(NodeSPI node, Fqn newBase)
+ {
+ Fqn newFqn = new Fqn(newBase, node.getFqn().getLastElement());
+ node.setFqn(newFqn);
+ }
+
+ /**
+ * Set our log category to include our clusterName, if we have one.
+ */
+ private void configureLogCategory()
+ {
+ StringBuffer category = new StringBuffer(getClass().getName());
+ if (configuration != null)
+ {
+ String clusterName = configuration.getClusterName();
+ if (clusterName != null)
+ {
+ category.append('.');
+ category.append(clusterName);
+ }
+ }
+
+ log = LogFactory.getLog(category.toString());
+ }
+
+ /**
+ * Kills the JGroups channel; an unclean channel disconnect
+ */
+ public void killChannel()
+ {
+ if (channel != null)
+ {
+ channel.close();
+ channel.disconnect();
+ }
+ }
+
+ protected class MessageListenerAdaptor implements ExtendedMessageListener
+ {
+ /**
+ * Reference to an exception that was raised during
+ * state installation on this node.
+ */
+ protected volatile Exception setStateException;
+ private final Object stateLock = new Object();
+
+ protected MessageListenerAdaptor()
+ {
+ }
+
+ public void waitForState() throws Exception
+ {
+ synchronized (stateLock)
+ {
+ while (!isStateSet)
+ {
+ if (setStateException != null)
+ {
+ throw setStateException;
+ }
+
+ try
+ {
+ stateLock.wait();
+ }
+ catch (InterruptedException iex)
+ {
+ }
+ }
+ }
+ }
+
+ protected void stateReceivedSuccess()
+ {
+ isStateSet = true;
+ setStateException = null;
+ }
+
+ protected void stateReceivingFailed(Throwable t)
+ {
+ if (t instanceof CacheException)
+ {
+ log.debug(t);
+ }
+ else
+ {
+ log.error("failed setting state", t);
+ }
+ if (t instanceof Exception)
+ {
+ setStateException = (Exception) t;
+ }
+ else
+ {
+ setStateException = new Exception(t);
+ }
+ }
+
+ protected void stateProducingFailed(Throwable t)
+ {
+ if (t instanceof CacheException)
+ {
+ log.debug(t);
+ }
+ else
+ {
+ log.error("Caught " + t.getClass().getName()
+ + " while responding to state transfer request", t);
+ }
+ }
+
+ /**
+ * Callback, does nothing.
+ */
+ public void receive(Message msg)
+ {
+ }
+
+ public byte[] getState()
+ {
+ MarshalledValueOutputStream out = null;
+ byte[] result = null;
+ ExposedByteArrayOutputStream baos = new ExposedByteArrayOutputStream(16 * 1024);
+ try
+ {
+ out = new MarshalledValueOutputStream(baos);
+
+ getStateTransferManager().getState(out, Fqn.ROOT, configuration.getStateRetrievalTimeout(), true, true);
+ }
+ catch (Throwable t)
+ {
+ stateProducingFailed(t);
+ }
+ finally
+ {
+ result = baos.getRawBuffer();
+ Util.close(out);
+ }
+ return result;
+ }
+
+ public void setState(byte[] new_state)
+ {
+ if (new_state == null)
+ {
+ log.debug("transferred state is null (may be first member in cluster)");
+ return;
+ }
+ ByteArrayInputStream bais = new ByteArrayInputStream(new_state);
+ MarshalledValueInputStream in = null;
+ try
+ {
+ in = new MarshalledValueInputStream(bais);
+ getStateTransferManager().setState(in, Fqn.ROOT);
+ stateReceivedSuccess();
+ }
+ catch (Throwable t)
+ {
+ stateReceivingFailed(t);
+ }
+ finally
+ {
+ Util.close(in);
+ synchronized (stateLock)
+ {
+ // Notify wait that state has been set.
+ stateLock.notifyAll();
+ }
+ }
+ }
+
+ public byte[] getState(String state_id)
+ {
+ MarshalledValueOutputStream out = null;
+ String sourceRoot = state_id;
+ byte[] result = null;
+
+ boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
+ if (hasDifferentSourceAndIntegrationRoots)
+ {
+ sourceRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[0];
+ }
+
+ ExposedByteArrayOutputStream baos = new ExposedByteArrayOutputStream(16 * 1024);
+ try
+ {
+ out = new MarshalledValueOutputStream(baos);
+
+ getStateTransferManager().getState(out, Fqn.fromString(sourceRoot),
+ configuration.getStateRetrievalTimeout(), true, true);
+ }
+ catch (Throwable t)
+ {
+ stateProducingFailed(t);
+ }
+ finally
+ {
+ result = baos.getRawBuffer();
+ Util.close(out);
+ }
+ return result;
+ }
+
+ public void getState(OutputStream ostream)
+ {
+ MarshalledValueOutputStream out = null;
+ try
+ {
+ out = new MarshalledValueOutputStream(ostream);
+ getStateTransferManager().getState(out, Fqn.ROOT, configuration.getStateRetrievalTimeout(), true, true);
+ }
+ catch (Throwable t)
+ {
+ stateProducingFailed(t);
+ }
+ finally
+ {
+ Util.close(out);
+ }
+ }
+
+ public void getState(String state_id, OutputStream ostream)
+ {
+ String sourceRoot = state_id;
+ MarshalledValueOutputStream out = null;
+ boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
+ if (hasDifferentSourceAndIntegrationRoots)
+ {
+ sourceRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[0];
+ }
+ try
+ {
+ out = new MarshalledValueOutputStream(ostream);
+ getStateTransferManager().getState(out, Fqn.fromString(sourceRoot), configuration.getStateRetrievalTimeout(), true, true);
+ }
+ catch (Throwable t)
+ {
+ stateProducingFailed(t);
+ }
+ finally
+ {
+ Util.close(out);
+ }
+ }
+
+ public void setState(InputStream istream)
+ {
+ if (istream == null)
+ {
+ log.debug("stream is null (may be first member in cluster)");
+ return;
+ }
+ MarshalledValueInputStream in = null;
+ try
+ {
+ in = new MarshalledValueInputStream(istream);
+ getStateTransferManager().setState(in, Fqn.ROOT);
+ stateReceivedSuccess();
+ }
+ catch (Throwable t)
+ {
+ stateReceivingFailed(t);
+ }
+ finally
+ {
+ Util.close(in);
+ synchronized (stateLock)
+ {
+ // Notify wait that state has been set.
+ stateLock.notifyAll();
+ }
+ }
+ }
+
+ public void setState(String state_id, byte[] state)
+ {
+ if (state == null)
+ {
+ log.debug("partial transferred state is null");
+ return;
+ }
+
+ MarshalledValueInputStream in = null;
+ String targetRoot = state_id;
+ boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
+ if (hasDifferentSourceAndIntegrationRoots)
+ {
+ targetRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[1];
+ }
+ try
+ {
+ log.debug("Setting received partial state for subroot " + state_id);
+ Fqn subroot = Fqn.fromString(targetRoot);
+// Region region = regionManager.getRegion(subroot, false);
+// ClassLoader cl = null;
+// if (region != null)
+// {
+// // If a classloader is registered for the node's region, use it
+// cl = region.getClassLoader();
+// }
+ ByteArrayInputStream bais = new ByteArrayInputStream(state);
+ in = new MarshalledValueInputStream(bais);
+ //getStateTransferManager().setState(in, subroot, cl);
+ getStateTransferManager().setState(in, subroot);
+ stateReceivedSuccess();
+ }
+ catch (Throwable t)
+ {
+ stateReceivingFailed(t);
+ }
+ finally
+ {
+ Util.close(in);
+ synchronized (stateLock)
+ {
+ // Notify wait that state has been set.
+ stateLock.notifyAll();
+ }
+ }
+ }
+
+ public void setState(String state_id, InputStream istream)
+ {
+ String targetRoot = state_id;
+ MarshalledValueInputStream in = null;
+ boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
+ if (hasDifferentSourceAndIntegrationRoots)
+ {
+ targetRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[1];
+ }
+ if (istream == null)
+ {
+ log.debug("stream is null (may be first member in cluster). State is not set");
+ return;
+ }
+
+ try
+ {
+ log.debug("Setting received partial state for subroot " + state_id);
+ in = new MarshalledValueInputStream(istream);
+ Fqn subroot = Fqn.fromString(targetRoot);
+// Region region = regionManager.getRegion(subroot, false);
+// ClassLoader cl = null;
+// if (region != null)
+// {
+// // If a classloader is registered for the node's region, use it
+// cl = region.getClassLoader();
+// }
+ //getStateTransferManager().setState(in, subroot, cl);
+ getStateTransferManager().setState(in, subroot);
+ stateReceivedSuccess();
+ }
+ catch (Throwable t)
+ {
+ stateReceivingFailed(t);
+ }
+ finally
+ {
+ Util.close(in);
+ synchronized (stateLock)
+ {
+ // Notify wait that state has been set.
+ stateLock.notifyAll();
+ }
+ }
+ }
+ }
+
+ /*-------------------- End of MessageListener ----------------------*/
+
+ /*----------------------- MembershipListener ------------------------*/
+
+ protected class MembershipListenerAdaptor implements ExtendedMembershipListener
+ {
+
+ public void viewAccepted(View new_view)
+ {
+ Vector<Address> new_mbrs = new_view.getMembers();
+ if (log.isInfoEnabled()) log.info("viewAccepted(): " + new_view);
+ synchronized (members)
+ {
+ boolean needNotification = false;
+ if (new_mbrs != null)
+ {
+ // Determine what members have been removed
+ // and roll back any tx and break any locks
+ Vector<Address> removed = new Vector<Address>(members);
+ removed.removeAll(new_mbrs);
+ removeLocksForDeadMembers(root, removed);
+
+ members.removeAllElements();
+ members.addAll(new_mbrs);
+
+ needNotification = true;
+ }
+
+ // Now that we have a view, figure out if we are the coordinator
+ coordinator = (members.size() != 0 && members.get(0).equals(getLocalAddress()));
+
+ // now notify listeners - *after* updating the coordinator. - JBCACHE-662
+ if (needNotification && notifier != null)
+ {
+ InvocationContext ctx = getInvocationContext();
+ notifier.notifyViewChange(new_view, ctx);
+ }
+
+ // Wake up any threads that are waiting to know who the members
+ // are so they can figure out who the coordinator is
+ members.notifyAll();
+ }
+ }
+
+ /**
+ * Called when a member is suspected.
+ */
+ public void suspect(Address suspected_mbr)
+ {
+ }
+
+ /**
+ * Indicates that a channel has received a BLOCK event from FLUSH protocol.
+ */
+ public void block()
+ {
+ flushBlockGate.close();
+ if (log.isDebugEnabled())
+ {
+ log.debug("Block received at " + getLocalAddress());
+ }
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.blockChannelLocal);
+ getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
+ invokeMethod(m, true);
+ if (log.isDebugEnabled())
+ {
+ log.debug("Block processed at " + getLocalAddress());
+ }
+ }
+
+ /**
+ * Indicates that a channel has received a UNBLOCK event from FLUSH protocol.
+ */
+ public void unblock()
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("UnBlock received at " + getLocalAddress());
+ }
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.unblockChannelLocal);
+ getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
+ invokeMethod(m, true);
+ if (log.isDebugEnabled())
+ {
+ log.debug("UnBlock processed at " + getLocalAddress());
+ }
+ flushBlockGate.open();
+ }
+
+ }
+
+ /*------------------- End of MembershipListener ----------------------*/
+
+ /* ------------------------------ Private methods --------------------------- */
+
+ /**
+ * Returns the transaction associated with the current thread. We get the
+ * initial context and a reference to the TransactionManager to get the
+ * transaction. This method is used by {@link #getCurrentTransaction()}
+ */
+ protected Transaction getLocalTransaction()
+ {
+ if (tm == null)
+ {
+ return null;
+ }
+ try
+ {
+ return tm.getTransaction();
+ }
+ catch (Throwable t)
+ {
+ return null;
+ }
+ }
+
+
+ /**
+ * Returns true if transaction is ACTIVE or PREPARING, false otherwise.
+ */
+ private boolean isValid(Transaction tx)
+ {
+ if (tx == null) return false;
+ int status = -1;
+ try
+ {
+ status = tx.getStatus();
+ return status == Status.STATUS_ACTIVE || status == Status.STATUS_PREPARING;
+ }
+ catch (SystemException e)
+ {
+ log.error("failed getting transaction status", e);
+ return false;
+ }
+ }
+
+
+ /**
+ * Returns the transaction associated with the current thread.
+ * If a local transaction exists, but doesn't yet have a mapping to a
+ * GlobalTransaction, a new GlobalTransaction will be created and mapped to
+ * the local transaction. Note that if a local transaction exists, but is
+ * not ACTIVE or PREPARING, null is returned.
+ *
+ * @return A GlobalTransaction, or null if no (local) transaction was associated with the current thread
+ */
+ public GlobalTransaction getCurrentTransaction()
+ {
+ return getCurrentTransaction(true);
+ }
+
+ /**
+ * Returns the transaction associated with the thread; optionally creating
+ * it if is does not exist.
+ */
+ public GlobalTransaction getCurrentTransaction(boolean createIfNotExists)
+ {
+ Transaction tx;
+
+ if ((tx = getLocalTransaction()) == null)
+ {// no transaction is associated with the current thread
+ return null;
+ }
+
+ if (!isValid(tx))
+ {// we got a non-null transaction, but it is not active anymore
+ int status = -1;
+ try
+ {
+ status = tx.getStatus();
+ }
+ catch (SystemException e)
+ {
+ }
+
+ // JBCACHE-982 -- don't complain if COMMITTED
+ if (status != Status.STATUS_COMMITTED)
+ {
+ log.warn("status is " + status + " (not ACTIVE or PREPARING); returning null)", new Throwable());
+ }
+ else
+ {
+ log.trace("status is COMMITTED; returning null");
+ }
+
+ return null;
+ }
+
+ return getCurrentTransaction(tx, createIfNotExists);
+ }
+
+ /**
+ * Returns the global transaction for this local transaction.
+ */
+ public GlobalTransaction getCurrentTransaction(Transaction tx)
+ {
+ return getCurrentTransaction(tx, true);
+ }
+
+ /**
+ * Returns the global transaction for this local transaction.
+ *
+ * @param createIfNotExists if true, if a global transaction is not found; one is created
+ */
+ public GlobalTransaction getCurrentTransaction(Transaction tx, boolean createIfNotExists)
+ {
+ // removed synchronization on tx_table because underlying implementation is thread safe
+ // and JTA spec (section 3.4.3 Thread of Control, par 2) says that only one thread may
+ // operate on the transaction at one time so no concern about 2 threads trying to call
+ // this method for the same Transaction instance at the same time
+ //
+ GlobalTransaction gtx = tx_table.get(tx);
+ if (gtx == null && createIfNotExists)
+ {
+ Address addr = getLocalAddress();
+ gtx = GlobalTransaction.create(addr);
+ tx_table.put(tx, gtx);
+ TransactionEntry ent = configuration.isNodeLockingOptimistic() ? new OptimisticTransactionEntry() : new TransactionEntry();
+ ent.setTransaction(tx);
+ tx_table.put(gtx, ent);
+ if (log.isTraceEnabled())
+ {
+ log.trace("created new GTX: " + gtx + ", local TX=" + tx);
+ }
+ }
+ return gtx;
+ }
+
+
+ /**
+ * Invokes a method against this object. Contains the logger_ic for handling
+ * the various use cases, e.g. mode (local, repl_async, repl_sync),
+ * transaction (yes or no) and locking (yes or no).
+ * <p/>
+ * Only sets originLocal on the invocation context IF this is explicitly passed in as <tt>false</tt>
+ * If passed in as <tt>true</tt> then it is not set; but whatever default exists in the invocation
+ * context is used. For example, it may be set prior to calling invokeMethod()
+ */
+ protected Object invokeMethod(MethodCall m, boolean originLocal) throws CacheException
+ {
+ // don't create a new one; get it from ThreadLocal just this once, in case a user has added any overrides.
+ InvocationContext ctx = getInvocationContext();
+
+ // BR methods should NOT block on the cache being started, since the cache depends on these completing to start.
+ if (!MethodDeclarations.isBuddyGroupOrganisationMethod(m.getMethodId()) && !cacheStatus.allowInvocations() && !ctx.getOptionOverrides().isSkipCacheStatusCheck())
+ throw new IllegalStateException("Cache not in STARTED state!");
+
+ MethodCall oldCall = null;
+ try
+ {
+ // check if we had a method call lurking around
+ oldCall = ctx.getMethodCall();
+ ctx.setMethodCall(m);
+ // only set this if originLocal is EXPLICITLY passed in as FALSE. Otherwise leave it as a default.
+ if (!originLocal) ctx.setOriginLocal(false);
+ return interceptor_chain.invoke(ctx);
+ }
+ catch (CacheException e)
+ {
+ throw e;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (Throwable t)
+ {
+ throw new RuntimeException(t);
+ }
+ finally
+ {
+ if (!originLocal) ctx.setOriginLocal(true);
+ // reset old method call
+ ctx.setMethodCall(oldCall);
+ }
+ }
+
+ /**
+ * Returns an object suitable for use in node locking, either the current
+ * transaction or the current thread if there is no transaction.
+ */
+ protected Object getOwnerForLock()
+ {
+ Object owner = getCurrentTransaction();
+ if (owner == null)
+ {
+ owner = Thread.currentThread();
+ }
+
+ return owner;
+ }
+
+ /**
+ * Finds a node given a fully qualified name.
+ * Whenever nodes are created, and the global transaction is not null, the created
+ * nodes have to be added to the transaction's {@link TransactionEntry}
+ * field.<br>
+ * When a lock is acquired on a node, a reference to the lock has to be
+ * {@link TransactionEntry#addLock(org.jboss.cache.lock.NodeLock) added to the list of locked nodes}
+ * in the {@link TransactionEntry}.
+ * <p>This operation will also apply different locking to the cache nodes, depending on
+ * <tt>operation_type</tt>. If it is <tt>read</tt> type, all nodes will be acquired with
+ * read lock. Otherwise, the operation is <tt>write</tt> type, all parent nodes will be acquired
+ * with read lock while the destination node acquires write lock.</p>
+ *
+ * @param fqn Fully qualified name for the corresponding node.
+ * @return DataNode
+ */
+ public NodeSPI<K, V> findNode(Fqn fqn)
+ {
+ try
+ {
+ return findNode(fqn, null);
+ }
+ catch (CacheException e)
+ {
+ log.warn("Unexpected error", e);
+ return null;
+ }
+ }
+
+ private NodeSPI<K, V> findNodeCheck(GlobalTransaction tx, Fqn fqn)
+ {
+ NodeSPI<K, V> n = findNode(fqn);
+ if (n == null)
+ {
+ String errStr = "node " + fqn + " not found (gtx=" + tx + ", caller=" + Thread.currentThread() + ")";
+ if (log.isTraceEnabled())
+ {
+ log.trace(errStr);
+ }
+ throw new NodeNotExistsException(errStr);
+ }
+ return n;
+ }
+
+ /**
+ * Internal method; not to be used externally.
+ * Returns true if the node was found, false if not.
+ *
+ * @param f
+ */
+ public boolean realRemove(Fqn f, boolean skipMarkerCheck)
+ {
+ NodeSPI n = peek(f, true);
+ if (n == null)
+ {
+ return false;
+ }
+
+ if (log.isTraceEnabled()) log.trace("Performing a real remove for node " + f + ", marked for removal.");
+ if (skipMarkerCheck || n.isDeleted())
+ {
+ if (n.getFqn().isRoot())
+ {
+ // do not actually delete; just remove deletion marker
+ n.markAsDeleted(true);
+ // but now remove all children, since the call has been to remove("/")
+ n.removeChildrenDirect();
+ return true;
+ }
+ else
+ {
+ return n.getParent().removeChildDirect(n.getFqn().getLastElement());
+ }
+ }
+ else
+ {
+ if (log.isDebugEnabled()) log.debug("Node " + f + " NOT marked for removal as expected, not removing!");
+ return false;
+ }
+ }
+
+ /**
+ * Finds a node given a fully qualified name and DataVersion.
+ */
+ private NodeSPI<K, V> findNode(Fqn fqn, DataVersion version) throws CacheException
+ {
+ if (fqn == null) return null;
+
+ NodeSPI<K, V> toReturn = peek(fqn, false);
+
+ if (version != null && configuration.isNodeLockingOptimistic())
+ {
+ // we need to check the version of the data node...
+ DataVersion nodeVersion = toReturn.getVersion();
+ if (log.isTraceEnabled())
+ {
+ log.trace("looking for optimistic node [" + fqn + "] with version [" + version + "]. My version is [" + nodeVersion + "]");
+ }
+ if (nodeVersion.newerThan(version))
+ {
+ // we have a versioning problem; throw an exception!
+ throw new CacheException("Unable to validate versions.");
+ }
+ }
+ return toReturn;
+ }
+
+ public synchronized RegionManager getRegionManager()
+ {
+ if (regionManager == null)
+ {
+ regionManager = new RegionManager(this);
+ }
+ return regionManager;
+ }
+
+
+ public Marshaller getMarshaller()
+ {
+ if (marshaller_ == null)
+ {
+ synchronized (this)
+ {
+ if (marshaller_ == null)
+ {
+ if (configuration.getMarshallerClass() == null || configuration.getMarshallerClass().equals(VersionAwareMarshaller.class.getName()))
+ {
+ marshaller_ = new VersionAwareMarshaller(getRegionManager(), configuration);
+ }
+ else
+ {
+ try
+ {
+ marshaller_ = (Marshaller) org.jboss.cache.util.Util.loadClass(configuration.getMarshallerClass()).newInstance();
+ }
+ catch (Exception e)
+ {
+ log.error("Unable to load marshaller " + configuration.getMarshallerClass() + ". Falling back to default (" + VersionAwareMarshaller.class.getName() + ")");
+ marshaller_ = new VersionAwareMarshaller(getRegionManager(), configuration);
+ }
+ }
+ if (log.isTraceEnabled()) log.trace("Using marshaller " + marshaller_.getClass().getName());
+ }
+ }
+ }
+ return marshaller_;
+ }
+
+ /**
+ * Returns the default JGroup properties.
+ * Subclasses may wish to override this method.
+ */
+ protected String getDefaultProperties()
+ {
+ return "UDP(mcast_addr=224.0.0.36;mcast_port=55566;ip_ttl=32;" +
+ "mcast_send_buf_size=150000;mcast_recv_buf_size=80000):" +
+ "PING(timeout=1000;num_initial_members=2):" +
+ "MERGE2(min_interval=5000;max_interval=10000):" +
+ "FD_SOCK:" +
+ "VERIFY_SUSPECT(timeout=1500):" +
+ "pbcast.NAKACK(gc_lag=50;max_xmit_size=8192;retransmit_timeout=600,1200,2400,4800):" +
+ "UNICAST(timeout=600,1200,2400,4800):" +
+ "pbcast.STABLE(desired_avg_gossip=20000):" +
+ "FRAG(frag_size=8192;down_thread=false;up_thread=false):" +
+ "pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;" +
+ "shun=false;print_local_addr=true):" +
+ "pbcast.STATE_TRANSFER";
+ }
+
+ private void initialiseCacheLoaderManager() throws CacheException
+ {
+ if (cacheLoaderManager == null)
+ {
+ cacheLoaderManager = new CacheLoaderManager();
+ }
+ cacheLoaderManager.setConfig(configuration.getCacheLoaderConfig(), this);
+ }
+
+ /**
+ * Sets the CacheLoader to use.
+ * Provided for backwards compatibility.
+ *
+ * @param loader
+ * @deprecated only provided for backward compat
+ */
+ @Deprecated
+ public void setCacheLoader(CacheLoader loader)
+ {
+ log.warn("Using deprecated config method setCacheLoader. This element will be removed in future, please use CacheLoaderConfiguration instead.");
+
+ try
+ {
+ if (cacheLoaderManager == null) initialiseCacheLoaderManager();
+ }
+ catch (Exception e)
+ {
+ log.warn("Problem setting cache loader. Perhaps your cache loader config has not been set yet?");
+ }
+ cacheLoaderManager.setCacheLoader(loader);
+ }
+
+ /**
+ * Purges the contents of all configured {@link CacheLoader}s
+ */
+ public void purgeCacheLoaders() throws Exception
+ {
+ if (cacheLoaderManager != null) cacheLoaderManager.purgeLoaders(true);
+ }
+
+ // ---------------------------------------------------------------
+ // END: Methods to provide backward compatibility with older cache loader config settings
+ // ---------------------------------------------------------------
+
+ private void initialiseChannelAndRpcDispatcher() throws CacheException
+ {
+ channel = configuration.getRuntimeConfig().getChannel();
+ if (channel == null)
+ {
+ // Try to create a multiplexer channel
+ channel = getMultiplexerChannel();
+
+ if (channel != null)
+ {
+ configuration.setUsingMultiplexer(true);
+ if (log.isDebugEnabled())
+ {
+ log.debug("Created Multiplexer Channel for cache cluster " + configuration.getClusterName() +
+ " using stack " + configuration.getMultiplexerStack());
+ }
+ }
+ else
+ {
+ if (configuration.getClusterConfig() == null)
+ {
+ log.debug("setting cluster properties to default value");
+ configuration.setClusterConfig(getDefaultProperties());
+ }
+ try
+ {
+ channel = new JChannel(configuration.getClusterConfig());
+ }
+ catch (Exception e)
+ {
+ throw new CacheException("Unable to create JGroups channel", e);
+ }
+ if (log.isTraceEnabled())
+ {
+ log.trace("cache properties: " + configuration.getClusterConfig());
+ }
+ }
+
+ configuration.getRuntimeConfig().setChannel(channel);
+ }
+
+ channel.setOpt(Channel.AUTO_RECONNECT, true);
+ channel.setOpt(Channel.AUTO_GETSTATE, true);
+ channel.setOpt(Channel.BLOCK, true);
+
+ // always use the InactiveRegionAwareRpcDispatcher - exceptions due to regions not being active should not propagate to remote
+ // nodes as errors. - Manik
+ disp = new InactiveRegionAwareRpcDispatcher(channel, ml, new MembershipListenerAdaptor(), this);
+ // disp = new RpcDispatcher(channel, ml, this, this);
+
+ disp.setRequestMarshaller(getMarshaller());
+ disp.setResponseMarshaller(getMarshaller());
+ }
+
+ private JChannel getMultiplexerChannel() throws CacheException
+ {
+ String stackName = configuration.getMultiplexerStack();
+
+ RuntimeConfig rtc = configuration.getRuntimeConfig();
+ ChannelFactory channelFactory = rtc.getMuxChannelFactory();
+ JChannel muxchannel = null;
+
+ if (channelFactory != null)
+ {
+ try
+ {
+ muxchannel = (JChannel) channelFactory.createMultiplexerChannel(stackName, configuration.getClusterName());
+ }
+ catch (Exception e)
+ {
+ throw new CacheException("Failed to create multiplexed channel using stack " + stackName, e);
+ }
+ }
+
+ return muxchannel;
+ }
+
+ // ================== methods to implement Cache and CacheSPI interfaces ============================
+
+ public List<Interceptor> getInterceptorChain()
+ {
+ List<Interceptor> modifiable = getInterceptors();
+ return modifiable == null ? null : Collections.unmodifiableList(modifiable);
+ }
+
+ public void addCacheListener(Object listener)
+ {
+ getNotifier().addCacheListener(listener);
+ }
+
+ public void addCacheListener(Fqn<?> region, Object listener)
+ {
+ throw new UnsupportedOperationException("Not implemented in this release");
+ }
+
+ public void removeCacheListener(Object listener)
+ {
+ // BES 2007/5/23 workaround to avoid NPE while we decide whether
+ // to remove notifier in destroy()
+ Notifier n = getNotifier();
+ if (n != null)
+ n.removeCacheListener(listener);
+ }
+
+ public void removeCacheListener(Fqn<?> region, Object listener)
+ {
+ throw new UnsupportedOperationException("Not implemented in this release");
+ }
+
+ public Set<Object> getCacheListeners()
+ {
+ return getNotifier().getCacheListeners();
+ }
+
+ public Set<Object> getCacheListeners(Fqn<?> region)
+ {
+ throw new UnsupportedOperationException("Not implemented in this release");
+ }
+
+ public synchronized void addInterceptor(Interceptor i, int position)
+ {
+ List<Interceptor> interceptors = getInterceptors();
+
+ i.setCache(this);
+
+ interceptors.add(position, i);
+
+ // now correct the chaining of interceptors...
+ Interceptor linkedChain = InterceptorChainFactory.getInstance().correctInterceptorChaining(interceptors);
+
+ setInterceptorChain(linkedChain);
+ }
+
+ public synchronized void removeInterceptor(int position)
+ {
+ List<Interceptor> i = getInterceptors();
+ i.remove(position);
+ setInterceptorChain(InterceptorChainFactory.getInstance().correctInterceptorChaining(i));
+ }
+
+ public RPCManager getRPCManager()
+ {
+ return configuration.getRuntimeConfig().getRPCManager();
+ }
+
+ public String getClusterName()
+ {
+ return getConfiguration().getClusterName();
+ }
+
+ public void evict(Fqn<?> fqn, boolean recursive)
+ {
+ if (recursive)
+ {
+ Node<K, V> n = get(fqn);
+ if (n != null)
+ {
+ evictChildren((NodeSPI<K, V>) n);
+ }
+ }
+ else
+ {
+ evict(fqn);
+ }
+ }
+
+ private void evictChildren(NodeSPI<K, V> n)
+ {
+ for (NodeSPI<K, V> child : n.getChildrenDirect())
+ {
+ evictChildren(child);
+ }
+ evict(n.getFqn());
+ }
+
+ public Region getRegion(Fqn<?> fqn, boolean createIfAbsent)
+ {
+ return getRegionManager().getRegion(fqn, createIfAbsent);
+ }
+
+ public boolean removeRegion(Fqn<?> fqn)
+ {
+ return getRegionManager().removeRegion(fqn);
+ }
+
+ public boolean removeNode(Fqn<?> fqn)
+ {
+ return remove(fqn);
+ }
+
+ public void putForExternalRead(Fqn<?> fqn, K key, V value)
+ {
+ // if the node exists then this should be a no-op.
+ if (!exists(fqn))
+ {
+ getInvocationContext().getOptionOverrides().setFailSilently(true);
+ GlobalTransaction tx = getCurrentTransaction();
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.putForExternalReadMethodLocal, tx, fqn, key, value);
+ invokeMethod(m, true);
+ }
+ else
+ {
+ if (log.isDebugEnabled())
+ log.debug("putForExternalRead() called with Fqn " + fqn + " and this node already exists. This method is hence a no op.");
+ }
+ }
+
+ public void _putForExternalRead(GlobalTransaction gtx, Fqn fqn, K key, V value)
+ {
+ _put(gtx, fqn, key, value, true);
+ }
+
+ public boolean isStarted()
+ {
+ return getCacheStatus() == CacheStatus.STARTED;
+ }
+
+ protected void setMessageListener(MessageListenerAdaptor ml)
+ {
+ this.ml = ml;
+ }
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/CacheSPI.java (from rev 4250, core/trunk/src-old/org/jboss/cache/CacheSPI.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/CacheSPI.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/CacheSPI.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,186 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.cache.buddyreplication.GravitateResult;
+import org.jboss.cache.interceptors.Interceptor;
+import org.jboss.cache.loader.CacheLoader;
+import org.jboss.cache.loader.CacheLoaderManager;
+import org.jboss.cache.lock.NodeLock;
+import org.jboss.cache.marshall.Marshaller;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.statetransfer.StateTransferManager;
+import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.transaction.TransactionTable;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A more detailed interface to {@link Cache}, which is used when writing plugins for or extending JBoss Cache. A reference
+ * to this interface should only be obtained when it is passed in to your code, for example when you write an
+ * {@link Interceptor} or {@link CacheLoader}.
+ * <p/>
+ * <B><I>You should NEVER attempt to directly cast a {@link Cache} instance to this interface. In future, the implementation may not allow it.</I></B>
+ * <p/>
+ * This interface contains overridden method signatures of some methods from {@link Cache}, overridden to ensure return
+ * types of {@link Node} are replaced with {@link NodeSPI}.
+ * <p/>
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ * @see NodeSPI
+ * @see Cache
+ * @see org.jboss.cache.loader.CacheLoader
+ * @see org.jboss.cache.interceptors.Interceptor
+ * @since 2.0.0
+ */
+@ThreadSafe
+public interface CacheSPI<K, V> extends Cache<K, V>
+{
+ /**
+ * Overrides {@link org.jboss.cache.Cache#getRoot()} to return a {@link org.jboss.cache.NodeSPI} instead of a {@link org.jboss.cache.Node}.
+ */
+ NodeSPI<K, V> getRoot();
+
+ /**
+ * Retrieves a reference to a running {@link javax.transaction.TransactionManager}, if one is configured.
+ *
+ * @return a TransactionManager
+ */
+ TransactionManager getTransactionManager();
+
+ /**
+ * @return an immutable {@link List} of {@link Interceptor}s configured for this cache, or
+ * <code>null</code> if {@link Cache#create() create()} has not been invoked
+ * and the interceptors thus do not exist.
+ */
+ List<Interceptor> getInterceptorChain();
+
+ /**
+ * Adds a custom interceptor to the interceptor chain, at specified position, where the first interceptor in the chain
+ * is at position 0 and the last one at getInterceptorChain().size() - 1.
+ *
+ * @param i the interceptor to add
+ * @param position the position to add the interceptor
+ */
+ void addInterceptor(Interceptor i, int position);
+
+ /**
+ * Removes the interceptor at a specified position, where the first interceptor in the chain
+ * is at position 0 and the last one at getInterceptorChain().size() - 1.
+ *
+ * @param position the position at which to remove an interceptor
+ */
+ void removeInterceptor(int position);
+
+ /**
+ * @return Retrieves a reference to the currently configured {@link org.jboss.cache.loader.CacheLoaderManager} if one or more cache loaders are configured, null otherwise.
+ */
+ CacheLoaderManager getCacheLoaderManager();
+
+ /**
+ * @return an instance of {@link BuddyManager} if buddy replication is enabled, null otherwise.
+ */
+ BuddyManager getBuddyManager();
+
+ /**
+ * @return the current {@link TransactionTable}
+ */
+ TransactionTable getTransactionTable();
+
+ /**
+ * Gets a handle of the RPC manager.
+ *
+ * @return the {@link org.jboss.cache.RPCManager} configured.
+ */
+ RPCManager getRPCManager();
+
+ /**
+ * @return the current {@link org.jboss.cache.statetransfer.StateTransferManager}
+ */
+ StateTransferManager getStateTransferManager();
+
+ /**
+ * @return the name of the cluster. Null if running in local mode.
+ */
+ String getClusterName();
+
+ /**
+ * @return the number of attributes in the cache.
+ */
+ int getNumberOfAttributes();
+
+ /**
+ * @return the number of nodes in the cache.
+ */
+ int getNumberOfNodes();
+
+ /**
+ * Retrieves the current table of locks.
+ *
+ * @return lock table.
+ */
+ Map<Thread, List<NodeLock>> getLockTable();
+
+ /**
+ * @return the {@link org.jboss.cache.RegionManager}
+ */
+ RegionManager getRegionManager();
+
+ /**
+ * Returns the global transaction for this local transaction.
+ * Optionally creates a new global transaction if it does not exist.
+ *
+ * @param tx the current transaction
+ * @param createIfNotExists if true creates a new transaction if none exists
+ * @return a GlobalTransaction
+ */
+ GlobalTransaction getCurrentTransaction(Transaction tx, boolean createIfNotExists);
+
+ /**
+ * @return the notifier attached with this instance of the cache. See {@link Notifier}, a class
+ * that is responsible for emitting notifications to registered CacheListeners.
+ */
+ Notifier getNotifier();
+
+ /**
+ * Returns a node without accessing the interceptor chain.
+ *
+ * @param fqn the Fqn to look up.
+ * @param includeDeletedNodes if you intend to see nodes marked as deleted within the current tx, set this to true
+ * @return a node if one exists or null
+ */
+ NodeSPI<K, V> peek(Fqn<?> fqn, boolean includeDeletedNodes);
+
+ /**
+ * Used with buddy replication's data gravitation interceptor. If marshalling is necessary, ensure that the cache is
+ * configured to use {@link org.jboss.cache.config.Configuration#useRegionBasedMarshalling} and the {@link org.jboss.cache.Region}
+ * pertaining to the Fqn passed in is activated, and has an appropriate ClassLoader.
+ *
+ * @param fqn the fqn to gravitate
+ * @param searchBuddyBackupSubtrees if true, buddy backup subtrees are searched and if false, they are not.
+ * @return a GravitateResult which contains the data for the gravitation
+ */
+ GravitateResult gravitateData(Fqn<?> fqn, boolean searchBuddyBackupSubtrees);
+
+ /**
+ * Retrieves an instance of a {@link Marshaller}, which is capable of
+ * converting Java objects to bytestreams and back in an efficient manner, which is
+ * also interoperable with bytestreams produced/consumed by other versions of JBoss
+ * Cache.
+ * <p/>
+ * The use of this marshaller is the <b>recommended</b> way of creating efficient,
+ * compatible, byte streams from objects.
+ *
+ * @return an instance of {@link Marshaller}
+ */
+ Marshaller getMarshaller();
+}
Copied: core/trunk/src/main/java/org/jboss/cache/CacheStatus.java (from rev 4250, core/trunk/src-old/org/jboss/cache/CacheStatus.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/CacheStatus.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/CacheStatus.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,224 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.cache;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Various states that an object that has a four stage lifecycle
+ * (i.e. <code>create()</code>, <code>start()</code>, <code>stop()</code>
+ * and <code>destroy()</code>) might be in.
+ *
+ * @author <a href="brian.stansberry(a)jboss.com">Brian Stansberry</a>
+ * @version $Revision$
+ */
+public enum CacheStatus
+{
+ /**
+ * Object has been instantiated, but create() has not been called.
+ */
+ INSTANTIATED,
+ /**
+ * The <code>create()</code> method has been called but not yet completed.
+ */
+ CREATING,
+ /**
+ * The <code>create()</code> method has been completed but
+ * <code>start()</code> has not been called.
+ */
+ CREATED,
+ /**
+ * The <code>start()</code> method has been called but has not yet completed.
+ */
+ STARTING,
+ /**
+ * The <code>start()</code> method has completed.
+ */
+ STARTED,
+ /**
+ * The <code>stop()</code> method has been called but has not yet completed.
+ */
+ STOPPING,
+ /**
+ * The <code>stop()</code> method has completed but <code>destroy()</code>
+ * has not yet been called. Conceptually equivalent to {@link #CREATED}.
+ */
+ STOPPED,
+ /**
+ * The <code>destroy()</code> method has been called but has not yet completed.
+ */
+ DESTROYING,
+ /**
+ * The <code>destroy()</code> method has completed.
+ * Conceptually equivalent to {@link #INSTANTIATED}.
+ */
+ DESTROYED,
+ /**
+ * A failure occurred during the execution of <code>create()</code>,
+ * <code>start()</code>, <code>stop()</code> or <code>destroy()</code>.
+ * The next logical transition is to call <code>destroy()</code>.
+ */
+ FAILED;
+
+ private static final Log log = LogFactory.getLog(CacheStatus.class);
+
+ public boolean createAllowed()
+ {
+ switch (this)
+ {
+ case CREATING:
+ case CREATED:
+ case STARTING:
+ case STARTED:
+ case STOPPED:
+ log.debug("Ignoring call to create() as current state is " + this);
+ // fall through
+ case FAILED:
+ return false;
+ case STOPPING:
+ case DESTROYING:
+ log.warn("Ignoring call to create() while cache is " + this);
+ return false;
+ case INSTANTIATED:
+ case DESTROYED:
+ default:
+ return true;
+ }
+ }
+
+ public boolean needToDestroyFailedCache()
+ {
+ if (this == CacheStatus.FAILED)
+ {
+ log.debug("need to call destroy() since current state is " +
+ this);
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean startAllowed()
+ {
+ switch (this)
+ {
+ case INSTANTIATED:
+ case DESTROYED:
+ case STARTING:
+ case STARTED:
+ log.debug("Ignoring call to start() as current state is " + this);
+ // fall through
+ case FAILED:
+ return false;
+ case STOPPING:
+ case DESTROYING:
+ log.warn("Ignoring call to start() as current state is " + this);
+ return false;
+ case CREATED:
+ case STOPPED:
+ default:
+ return true;
+ }
+ }
+
+ public boolean needCreateBeforeStart()
+ {
+ switch (this)
+ {
+ case INSTANTIATED:
+ case DESTROYED:
+ log.debug("start() called while current state is " +
+ this + " -- call create() first");
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public boolean stopAllowed()
+ {
+ switch (this)
+ {
+ case INSTANTIATED:
+ case CREATED:
+ case STOPPED:
+ case DESTROYED:
+ log.debug("Ignoring call to stop() as current state is " + this);
+ return false;
+ case CREATING:
+ case STARTING:
+ case STOPPING:
+ case DESTROYING:
+ log.warn("Ignoring call to stop() as current state is " + this);
+ return false;
+ case FAILED:
+ case STARTED:
+ default:
+ return true;
+ }
+
+ }
+
+ public boolean destroyAllowed()
+ {
+ switch (this)
+ {
+ case INSTANTIATED:
+ case DESTROYED:
+ log.debug("Ignoring call to destroy() as current state is " + this);
+ return false;
+ case CREATING:
+ case STARTING:
+ case STOPPING:
+ case DESTROYING:
+ log.warn("Ignoring call to destroy() as current state iswhile cache is " + this);
+ return false;
+ case STARTED:
+ // stop first
+ return false;
+ case CREATED:
+ case STOPPED:
+ case FAILED:
+ default:
+ return true;
+ }
+ }
+
+ public boolean needStopBeforeDestroy()
+ {
+ if (this == CacheStatus.STARTED)
+ {
+ log.warn("destroy() called while current state is " +
+ this + " -- call stop() first");
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean allowInvocations()
+ {
+ return (this == CacheStatus.STARTED);
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/ConsoleListener.java (from rev 4250, core/trunk/src-old/org/jboss/cache/ConsoleListener.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/ConsoleListener.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/ConsoleListener.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,230 @@
+package org.jboss.cache;
+
+import org.jboss.cache.notifications.annotation.CacheListener;
+import org.jboss.cache.notifications.annotation.CacheStarted;
+import org.jboss.cache.notifications.annotation.CacheStopped;
+import org.jboss.cache.notifications.annotation.NodeActivated;
+import org.jboss.cache.notifications.annotation.NodeCreated;
+import org.jboss.cache.notifications.annotation.NodeEvicted;
+import org.jboss.cache.notifications.annotation.NodeLoaded;
+import org.jboss.cache.notifications.annotation.NodeModified;
+import org.jboss.cache.notifications.annotation.NodeMoved;
+import org.jboss.cache.notifications.annotation.NodePassivated;
+import org.jboss.cache.notifications.annotation.NodeRemoved;
+import org.jboss.cache.notifications.annotation.NodeVisited;
+import org.jboss.cache.notifications.annotation.ViewChanged;
+import org.jboss.cache.notifications.event.Event;
+import org.jboss.cache.notifications.event.NodeEvent;
+import org.jboss.cache.notifications.event.ViewChangedEvent;
+
+/**
+ * This class provides a non-graphical view of <em>JBossCache</em> replication
+ * events for a replicated cache.
+ * <p/>
+ * It can be utilized as a standalone application or as a component in other
+ * applications.
+ * <p/>
+ * <strong>WARNING</strong>: take care when using this class in conjunction with
+ * transactionally replicated cache's as it can cause deadlock situations due to
+ * the reading of values for nodes in the cache.
+ *
+ * @author Jimmy Wilson 12-2004
+ */
+@CacheListener
+public class ConsoleListener
+{
+ private CacheImpl _cache;
+ private boolean _startCache;
+
+ /**
+ * Constructor.
+ * <p/>
+ * When using this constructor, this class with attempt to start and stop
+ * the specified cache.
+ *
+ * @param cache the cache to monitor for replication events.
+ */
+ public ConsoleListener(CacheImpl cache)
+ throws Exception
+ {
+ this(cache, true, true);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param cache the cache to monitor for replication events.
+ * @param startCache indicates whether or not the cache should be started by
+ * this class.
+ * @param stopCache indicates whether or not the cache should be stopped by
+ * this class.
+ */
+ public ConsoleListener(CacheImpl cache,
+ boolean startCache, boolean stopCache)
+ throws Exception
+ {
+ _cache = cache;
+ _startCache = startCache;
+
+ if (stopCache)
+ {
+ new ListenerShutdownHook().register();
+ }
+ }
+
+ /**
+ * Instructs this class to listen for cache replication events.
+ * <p/>
+ * This method waits indefinately. Use the notify method of this class
+ * (using traditional Java thread notification semantics) to cause this
+ * method to return.
+ */
+ public void listen()
+ throws Exception
+ {
+ listen(true);
+ }
+
+ /**
+ * Instructs this class to listen for cache replication events.
+ *
+ * @param wait whether or not this method should wait indefinately.
+ * <p/>
+ * If this parameter is set to <code>true</code>, using the
+ * notify method of this class (using traditional Java thread
+ * notification semantics) will cause this method to return.
+ */
+ public void listen(boolean wait)
+ throws Exception
+ {
+ _cache.getNotifier().addCacheListener(this);
+
+ if (_startCache)
+ {
+ _cache.start();
+ }
+
+ synchronized (this)
+ {
+ while (wait)
+ {
+ wait();
+ }
+ }
+ }
+
+
+ @CacheStarted
+ @CacheStopped
+ public void printDetails(Event e)
+ {
+ printEvent("Cache started.");
+ }
+
+
+ @NodeCreated
+ @NodeLoaded
+ @NodeModified
+ @NodeRemoved
+ @NodeVisited
+ @NodeMoved
+ @NodeEvicted
+ @NodeActivated
+ @NodePassivated
+ public void printDetailsWithFqn(NodeEvent e)
+ {
+ if (e.isPre())
+ {
+ printEvent("Event " + e.getType() + " on node [" + e.getFqn() + "] about to be invoked");
+ }
+ else
+ {
+ printEvent("Event " + e.getType() + " on node [" + e.getFqn() + "] invoked");
+ }
+ }
+
+ @ViewChanged
+ public void printNewView(ViewChangedEvent e)
+ {
+ printEvent("View change: " + e.getNewView());
+ }
+
+ /**
+ * Prints an event message.
+ *
+ * @param eventSuffix the suffix of the event message.
+ */
+ private void printEvent(String eventSuffix)
+ {
+ System.out.print("EVENT");
+ System.out.print(' ');
+
+ System.out.println(eventSuffix);
+ }
+
+ /**
+ * This class provides a shutdown hook for shutting down the cache.
+ */
+ private class ListenerShutdownHook extends Thread
+ {
+ /**
+ * Registers this hook for invocation during shutdown.
+ */
+ public void register()
+ {
+ Runtime.getRuntime().addShutdownHook(this);
+ }
+
+ /*
+ * Thread overrides.
+ */
+
+ public void run()
+ {
+ _cache.stop();
+ }
+ }
+
+ /**
+ * The main method.
+ *
+ * @param args command line arguments dictated by convention.
+ * <p/>
+ * The first command line argument is the name of the
+ * <code>JBossCache</code> configuration file to be utilized
+ * for configuration of the cache. Only the name of the
+ * configuration file is necessary as it is read off of the
+ * classpath.
+ * <p/>
+ * If a configuration file is not specified on the command line,
+ * <code>jboss-cache.xml</code> will be the assumed file name.
+ * <p/>
+ * All command line arguments after the first are ignored.
+ */
+ public static void main(String[] args)
+ {
+ final String DEFAULT_CONFIG_FILE_NAME = "jboss-cache.xml";
+
+ try
+ {
+ String configFileName = DEFAULT_CONFIG_FILE_NAME;
+
+ if (args.length >= 1)
+ {
+ configFileName = args[0];
+ }
+ else
+ {
+ System.out.print("No xml config file argument is supplied. Will use jboss-cache.xml from classpath");
+ }
+
+ CacheImpl cache = (CacheImpl) DefaultCacheFactory.getInstance().createCache(configFileName);
+ ConsoleListener listener = new ConsoleListener(cache);
+ listener.listen();
+ }
+ catch (Throwable throwable)
+ {
+ throwable.printStackTrace();
+ }
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/DefaultCacheFactory.java (from rev 4250, core/trunk/src-old/org/jboss/cache/DefaultCacheFactory.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/DefaultCacheFactory.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/DefaultCacheFactory.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,95 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.ConfigurationException;
+import org.jboss.cache.factories.XmlConfigurationParser;
+
+/**
+ * Default (singleton) implementation of the {@link org.jboss.cache.CacheFactory} interface.
+ * Use {@link #getInstance()} to obtain an instance.
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ */
+public class DefaultCacheFactory<K, V> implements CacheFactory<K, V>
+{
+ private static CacheFactory singleton = new DefaultCacheFactory();
+
+ /**
+ * @return a singleton instance of this class.
+ */
+ public static <K, V> CacheFactory<K, V> getInstance()
+ {
+ return singleton;
+ }
+
+ public Cache<K, V> createCache() throws ConfigurationException
+ {
+ return createCache(true);
+ }
+
+ public Cache<K, V> createCache(boolean start) throws ConfigurationException
+ {
+ return createCache(new Configuration(), start);
+ }
+
+ public Cache<K, V> createCache(String configFileName) throws ConfigurationException
+ {
+ return createCache(configFileName, true);
+ }
+
+ public Cache<K, V> createCache(String configFileName, boolean start) throws ConfigurationException
+ {
+ XmlConfigurationParser parser = new XmlConfigurationParser();
+ Configuration c = parser.parseFile(configFileName);
+ return createCache(c, start);
+ }
+
+ /**
+ * This implementation clones the configuration passed in before using it.
+ *
+ * @param configuration to use
+ * @return a cache
+ * @throws ConfigurationException if there are problems with the cfg
+ */
+ public Cache<K, V> createCache(Configuration configuration) throws ConfigurationException
+ {
+ return createCache(configuration, true);
+ }
+
+ /**
+ * This implementation clones the configuration passed in before using it.
+ *
+ * @param configuration to use
+ * @param start whether to start the cache
+ * @return a cache
+ * @throws ConfigurationException if there are problems with the cfg
+ */
+ public Cache<K, V> createCache(Configuration configuration, boolean start) throws ConfigurationException
+ {
+ try
+ {
+ CacheImpl<K, V> cache = new CacheImpl<K, V>();
+ cache.setConfiguration(configuration);
+ if (start) cache.start();
+ return cache;
+ }
+ catch (ConfigurationException ce)
+ {
+ throw ce;
+ }
+ catch (RuntimeException re)
+ {
+ throw re;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/Fqn.java (from rev 4250, core/trunk/src-old/org/jboss/cache/Fqn.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Fqn.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/Fqn.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,518 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+
+import net.jcip.annotations.Immutable;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * A Fully Qualified Name (Fqn) is a list of names (typically Strings but can be any Object),
+ * which represent a path to a particular {@link Node} or sometimes a {@link Region} in a {@link Cache}.
+ * <p/>
+ * This name can be absolute (i.e., relative from the root node - {@link #ROOT}), or relative to any node in the cache. Reading the
+ * documentation on each API call that makes use of {@link org.jboss.cache.Fqn}s will tell you whether the API expects a
+ * relative or absolute Fqn.
+ * <p/>
+ * For instance, using this class to fetch a particular node might look like
+ * this. (Here data on "Joe" is kept under the "Smith" surname node, under
+ * the "people" tree.)
+ * <pre>
+ * Fqn<String> abc = Fqn.fromString("/people/Smith/Joe/");
+ * Node joesmith = Cache.getRoot().getChild(abc);
+ * </pre>
+ * Alternatively, the same Fqn could be constructed using an array:
+ * <pre>
+ * Fqn<String> abc = new Fqn<String>(new String[] { "people", "Smith", "Joe" });
+ * </pre>
+ * This is a bit more efficient to construct.
+ * <p/>
+ * <p/>
+ * Note that<br>
+ * <p/>
+ * <code>Fqn<String> f = new Fqn<String>("/a/b/c");</code>
+ * <p/>
+ * is <b>not</b> the same as
+ * <p/>
+ * <code>Fqn<String> f = Fqn.fromString("/a/b/c");</code>
+ * <p/>
+ * The former will result in a single Fqn, called "/a/b/c" which hangs directly under Fqn.ROOT.
+ * <p/>
+ * The latter will result in 3 Fqns, called "a", "b" and "c", where "c" is a child of "b", "b" is a child of "a", and "a" hangs off Fqn.ROOT.
+ * <p/>
+ * Another way to look at it is that the "/" separarator is only parsed when it forms
+ * part of a String passed in to Fqn.fromString() and not otherwise.
+ *
+ * @version $Revision$
+ */
+@Immutable
+public class Fqn<E> implements Cloneable, Externalizable, Comparable<Fqn>
+{
+
+ /**
+ * Separator between FQN elements.
+ */
+ public static final String SEPARATOR = "/";
+ private static final long serialVersionUID = -5351930616956603651L;
+ private List<E> elements;
+ private transient int hash_code = 0;
+
+ /**
+ * Immutable root FQN.
+ */
+ public static final Fqn ROOT = new Fqn();
+ private static Log log = LogFactory.getLog(Fqn.class);
+ // a cached string representation of this Fqn, used by toString to it isn't calculated again every time.
+ private String cachedStringRep;
+
+ /**
+ * Constructs a root Fqn
+ */
+ public Fqn()
+ {
+ elements = Collections.emptyList();
+ }
+
+ /**
+ * Constructs a FQN from a list of names.
+ *
+ * @param names List of names
+ */
+ public Fqn(List<E> names)
+ {
+ // the list is unsafe - may be referenced externally
+ this(names, false);
+ }
+
+ /**
+ * If safe is false, Collections.unmodifiableList() is used to wrap the list passed in. This is an optimisation so
+ * Fqn.fromString(), probably the most frequently used factory method, doesn't end up needing to use the unmodifiableList()
+ * since it creates the list internally.
+ *
+ * @param names List of names
+ * @param safe whether this list is referenced externally (safe = false) or not (safe = true).
+ */
+ protected Fqn(List<E> names, boolean safe)
+ {
+ if (names != null)
+ {
+ // if not safe make a defensive copy
+ elements = safe ? names : new ArrayList<E>(names);
+ }
+ else
+ {
+ elements = Collections.emptyList();
+ }
+ }
+
+
+ /**
+ * Constructs a Fqn from an array of names.
+ *
+ * @param names Names that comprose this Fqn
+ */
+ public Fqn(E... names)
+ {
+ // safe - the list is created here.
+ this(Arrays.asList(names), true);
+ }
+
+ /**
+ * Constructs a Fqn from a base and relative Fqn.
+ *
+ * @param base parent Fqn
+ * @param relative Sub-Fqn relative to the parent
+ */
+ public Fqn(Fqn<E> base, Fqn<E> relative)
+ {
+ this(base, relative.elements);
+ }
+
+ /**
+ * Constructs a Fqn from a base and a list of relative names.
+ *
+ * @param base parent Fqn
+ * @param relative List of elements that identify the child Fqn, relative to the parent
+ */
+ public Fqn(Fqn<E> base, List<E> relative)
+ {
+ List<E> elements = new ArrayList<E>(base.elements.size() + relative.size());
+ elements.addAll(base.elements);
+ elements.addAll(relative);
+ this.elements = elements;
+ }
+
+ /**
+ * Constructs a Fqn from a base and two relative names.
+ *
+ * @param base parent Fqn
+ * @param childNames elements that denote the path to the Fqn, under the parent
+ */
+ public Fqn(Fqn<E> base, E... childNames)
+ {
+ List<E> elements = new ArrayList<E>(base.elements.size() + childNames.length);
+ elements.addAll(base.elements);
+ elements.addAll(Arrays.asList(childNames));
+ this.elements = elements;
+ }
+
+ /**
+ * Returns a new Fqn from a string, where the elements are deliminated by
+ * one or more separator ({@link #SEPARATOR}) characters.<br><br>
+ * Example use:<br>
+ * <pre>
+ * Fqn.fromString("/a/b/c/");
+ * </pre><br>
+ * is equivalent to:<br>
+ * <pre>
+ * new Fqn("a", "b", "c");
+ * </pre><br>
+ * but not<br>
+ * <pre>
+ * new Fqn("/a/b/c");
+ * </pre>
+ *
+ * @param stringRepresentation String representation of the Fqn
+ * @return an Fqn<String> constructed from the string representation passed in
+ * @see #Fqn(Object[])
+ */
+ public static Fqn<String> fromString(String stringRepresentation)
+ {
+ if (stringRepresentation == null)
+ {
+ return Fqn.ROOT;
+ }
+ List<String> list = new ArrayList<String>();
+ StringTokenizer tok = new StringTokenizer(stringRepresentation, SEPARATOR);
+ while (tok.hasMoreTokens()) list.add(tok.nextToken());
+ return new Fqn<String>(list, true);
+ }
+
+ /**
+ * Obtains an ancestor of the current Fqn. Literally performs <code>elements.subList(0, generation)</code>
+ * such that if
+ * <code>
+ * generation == Fqn.size()
+ * </code>
+ * then the return value is the Fqn itself (current generation), and if
+ * <code>
+ * generation == Fqn.size() - 1
+ * </code>
+ * then the return value is the same as
+ * <code>
+ * Fqn.getParent()
+ * </code>
+ * i.e., just one generation behind the current generation.
+ * <code>
+ * generation == 0
+ * </code>
+ * would return Fqn.ROOT.
+ *
+ * @param generation the generation of the ancestor to retrieve
+ * @return an ancestor of the current Fqn
+ */
+ public Fqn<E> getAncestor(int generation)
+ {
+ if (generation == 0) return Fqn.ROOT;
+ return getSubFqn(0, generation);
+ }
+
+ /**
+ * Obtains a sub-Fqn from the given Fqn. Literally performs <code>elements.subList(startIndex, endIndex)</code>
+ */
+ public Fqn<E> getSubFqn(int startIndex, int endIndex)
+ {
+ return new Fqn<E>(elements.subList(startIndex, endIndex));
+ }
+
+ /**
+ * @return the number of elements in the Fqn. The root node contains zero.
+ */
+ public int size()
+ {
+ return elements.size();
+ }
+
+ /**
+ * @param n index of the element to return
+ * @return Returns the nth element in the Fqn.
+ */
+ public E get(int n)
+ {
+ return elements.get(n);
+ }
+
+ /**
+ * @return the last element in the Fqn.
+ * @see #getLastElementAsString
+ */
+ public E getLastElement()
+ {
+ if (isRoot()) return null;
+ return elements.get(elements.size() - 1);
+ }
+
+ /**
+ * @param element element to find
+ * @return true if the Fqn contains this element, false otherwise.
+ */
+ public boolean hasElement(E element)
+ {
+ return elements.lastIndexOf(element) != -1;
+ }
+
+ /**
+ * Clones the Fqn.
+ */
+ public Fqn<E> clone() throws CloneNotSupportedException
+ {
+ try
+ {
+ return (Fqn<E>) super.clone();
+ }
+ catch (CloneNotSupportedException e)
+ {
+ log.error("Unable to clone Fqn " + this, e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns true if obj is a Fqn with the same elements.
+ */
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (!(obj instanceof Fqn))
+ {
+ return false;
+ }
+ Fqn other = (Fqn) obj;
+ return elements.equals(other.elements);
+ }
+
+ /**
+ * Returns a hash code with Fqn elements.
+ */
+ public int hashCode()
+ {
+ if (hash_code == 0)
+ {
+ hash_code = _hashCode();
+ }
+ return hash_code;
+ }
+
+ /**
+ * Returns this Fqn as a string, prefixing the first element with a {@link Fqn#SEPARATOR} and
+ * joining each subsequent element with a {@link Fqn#SEPARATOR}.
+ * If this is the root Fqn, returns {@link Fqn#SEPARATOR}.
+ * Example:
+ * <pre>
+ * new Fqn(new Object[] { "a", "b", "c" }).toString(); // "/a/b/c"
+ * Fqn.ROOT.toString(); // "/"
+ * </pre>
+ */
+ public String toString()
+ {
+ if (cachedStringRep == null)
+ {
+ if (isRoot())
+ {
+ cachedStringRep = SEPARATOR;
+ }
+ else
+ {
+ StringBuffer sb = new StringBuffer();
+ for (E element : elements)
+ {
+ sb.append(SEPARATOR).append(element);
+ }
+ cachedStringRep = sb.toString();
+ }
+ }
+ return cachedStringRep;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ out.writeShort(elements.size());
+ for (E element : elements)
+ {
+ out.writeObject(element);
+ }
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+ {
+ short length = in.readShort();
+ this.elements = new ArrayList<E>(length);
+ for (int i = 0; i < length; i++)
+ {
+ elements.add((E) in.readObject());
+ }
+ }
+
+
+ /**
+ * Returns true if this Fqn is child of parentFqn.
+ * Example usage:
+ * <pre>
+ * Fqn<String> f1 = Fqn.fromString("/a/b");
+ * Fqn<String> f2 = Fqn.fromString("/a/b/c");
+ * assertTrue(f1.isChildOf(f2));
+ * assertFalse(f1.isChildOf(f1));
+ * assertFalse(f2.isChildOf(f1));
+ * </pre>
+ *
+ * @param parentFqn candidate parent to test against
+ * @return true if the target is a child of parentFqn
+ */
+ public boolean isChildOf(Fqn<E> parentFqn)
+ {
+ return parentFqn.elements.size() != elements.size() && isChildOrEquals(parentFqn);
+ }
+
+ /**
+ * Returns true if this Fqn is equals or the child of parentFqn.
+ * Example usage:
+ * <pre>
+ * Fqn<String> f1 = Fqn.fromString("/a/b");
+ * Fqn<String> f2 = Fqn.fromString("/a/b/c");
+ * assertTrue(f1.isChildOrEquals(f2));
+ * assertTrue(f1.isChildOrEquals(f1));
+ * assertFalse(f2.isChildOrEquals(f1));
+ * </pre>
+ *
+ * @param parentFqn candidate parent to test against
+ * @return true if this Fqn is equals or the child of parentFqn.
+ */
+ public boolean isChildOrEquals(Fqn<E> parentFqn)
+ {
+ List<E> parentList = parentFqn.elements;
+ if (parentList.size() > elements.size())
+ {
+ return false;
+ }
+ for (int i = parentList.size() - 1; i >= 0; i--)
+ {
+ if (!parentList.get(i).equals(elements.get(i)))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Calculates a hash code by summing the hash code of all elements.
+ *
+ * @return a cached hashcode
+ */
+ private int _hashCode()
+ {
+ int hashCode = 0;
+ int count = 1;
+ Object o;
+ for (E element : elements)
+ {
+ o = element;
+ hashCode += (o == null) ? 0 : o.hashCode() * count++;
+ }
+ if (hashCode == 0)// fix degenerate case
+ {
+ hashCode = 0xFEED;
+ }
+ return hashCode;
+ }
+
+ /**
+ * Returns the parent of this Fqn.
+ * The parent of the root node is {@link #ROOT}.
+ * Examples:
+ * <pre>
+ * Fqn<String> f1 = Fqn.fromString("/a");
+ * Fqn<String> f2 = Fqn.fromString("/a/b");
+ * assertEquals(f1, f2.getParent());
+ * assertEquals(Fqn.ROOT, f1.getParent().getParent());
+ * assertEquals(Fqn.ROOT, Fqn.ROOT.getParent());
+ * </pre>
+ *
+ * @return the parent Fqn
+ */
+ public Fqn<E> getParent()
+ {
+ switch (elements.size())
+ {
+ case 0:
+ case 1:
+ return ROOT;
+ default:
+ return new Fqn<E>(elements.subList(0, elements.size() - 1));
+ }
+ }
+
+ /**
+ * Returns true if this is a root Fqn.
+ *
+ * @return true if the Fqn is Fqn.ROOT.
+ */
+ public boolean isRoot()
+ {
+ return elements.isEmpty();
+ }
+
+ /**
+ * If this is the root, returns {@link Fqn#SEPARATOR}.
+ *
+ * @return a String representation of the last element that makes up this Fqn.
+ */
+ public String getLastElementAsString()
+ {
+ if (isRoot())
+ {
+ return SEPARATOR;
+ }
+ else
+ {
+ return String.valueOf(getLastElement());
+ }
+ }
+
+ /**
+ * Peeks into the elements that build up this Fqn. The list returned is
+ * read-only, to maintain the immutable nature of Fqn.
+ *
+ * @return an unmodifiable list
+ */
+ public List<E> peekElements()
+ {
+ return elements;
+ }
+
+ /**
+ * Compares this Fqn to another using {@link FqnComparator}.
+ */
+ public int compareTo(Fqn Fqn)
+ {
+ return FqnComparator.INSTANCE.compare(this, Fqn);
+ }
+}
\ No newline at end of file
Copied: core/trunk/src/main/java/org/jboss/cache/FqnComparator.java (from rev 4250, core/trunk/src-old/org/jboss/cache/FqnComparator.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/FqnComparator.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/FqnComparator.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,106 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import net.jcip.annotations.Immutable;
+
+import java.util.Comparator;
+
+/**
+ * Compares the order of two FQN.
+ * Sorts by name, then by depth, e.g.
+ * <pre>
+ * aaa/bbb
+ * xxx
+ * xxx/ccc
+ * </pre>
+ *
+ * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
+ * @author Steve Woodcock (<a href="mailto:stevew@jofti.com">stevew(a)jofti.com</a>)
+ */
+@Immutable
+public class FqnComparator implements Comparator<Fqn>
+{
+ public static final FqnComparator INSTANCE = new FqnComparator();
+
+ /**
+ * Sorts by name, then depth.
+ */
+ public FqnComparator()
+ {
+ }
+
+ /**
+ * Returns -1 if the first comes before; 0 if they are the same; 1 if the
+ * second Fqn comes before. <code>null</code> always comes first.
+ */
+ public int compare(Fqn fqn1, Fqn fqn2)
+ {
+ int s1 = fqn1.size();
+ int s2 = fqn2.size();
+
+ if (s1 == 0)
+ {
+ return (s2 == 0) ? 0 : -1;
+ }
+
+ if (s2 == 0)
+ {
+ return 1;
+ }
+
+ int size = Math.min(s1, s2);
+
+ for (int i = 0; i < size; i++)
+ {
+ Object e1 = fqn1.get(i);
+ Object e2 = fqn2.get(i);
+ if (e1 == e2)
+ {
+ continue;
+ }
+ if (e1 == null)
+ {
+ return 0;
+ }
+ if (e2 == null)
+ {
+ return 1;
+ }
+ if (!e1.equals(e2))
+ {
+ int c = compareElements(e1, e2);
+ if (c != 0)
+ {
+ return c;
+ }
+ }
+ }
+
+ return s1 - s2;
+ }
+
+ /**
+ * Compares two Fqn elements.
+ * If e1 and e2 are the same class and e1 implements Comparable,
+ * returns e1.compareTo(e2).
+ * Otherwise, returns e1.toString().compareTo(e2.toString()).
+ */
+ private int compareElements(Object e1, Object e2)
+ {
+ if (e1.getClass() == e2.getClass() && e1 instanceof Comparable)
+ {
+ return ((Comparable) e1).compareTo(e2);
+ }
+ else
+ {
+ return e1.toString().compareTo(e2.toString());
+ }
+ }
+
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/InvocationContext.java (from rev 4250, core/trunk/src-old/org/jboss/cache/InvocationContext.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/InvocationContext.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/InvocationContext.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,257 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.config.Option;
+import org.jboss.cache.marshall.MethodCall;
+import org.jboss.cache.transaction.GlobalTransaction;
+
+import javax.transaction.Transaction;
+
+/**
+ * This context holds information specific to a method invocation.
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ */
+public class InvocationContext implements Cloneable
+{
+ private Transaction transaction;
+ private GlobalTransaction globalTransaction;
+ private Option optionOverrides;
+ // defaults to true.
+ private boolean originLocal = true;
+ private boolean txHasMods;
+ private boolean localRollbackOnly;
+ private MethodCall methodCall;
+
+ InvocationContext()
+ {
+ }
+
+ public void setLocalRollbackOnly(boolean localRollbackOnly)
+ {
+ this.localRollbackOnly = localRollbackOnly;
+ }
+
+
+ /**
+ * Retrieves the transaction associated with this invocation
+ *
+ * @return The transaction associated with this invocation
+ */
+ public Transaction getTransaction()
+ {
+ return transaction;
+ }
+
+ /**
+ * Sets the transaction associated with this invocation
+ *
+ * @param transaction
+ */
+ public void setTransaction(Transaction transaction)
+ {
+ this.transaction = transaction;
+ }
+
+ /**
+ * Retrieves the global transaction associated with this invocation
+ *
+ * @return the global transaction associated with this invocation
+ */
+ public GlobalTransaction getGlobalTransaction()
+ {
+ return globalTransaction;
+ }
+
+ /**
+ * Sets the global transaction associated with this invocation
+ *
+ * @param globalTransaction
+ */
+ public void setGlobalTransaction(GlobalTransaction globalTransaction)
+ {
+ this.globalTransaction = globalTransaction;
+ }
+
+ /**
+ * Retrieves the option overrides associated with this invocation
+ *
+ * @return the option overrides associated with this invocation
+ */
+ public Option getOptionOverrides()
+ {
+ if (optionOverrides == null)
+ {
+ optionOverrides = new Option();
+ }
+ return optionOverrides;
+ }
+
+ /**
+ * Sets the option overrides associated with this invocation
+ *
+ * @param optionOverrides
+ */
+ public void setOptionOverrides(Option optionOverrides)
+ {
+ this.optionOverrides = optionOverrides;
+ }
+
+ /**
+ * Tests if this invocation originated locally or from a remote cache.
+ *
+ * @return true if the invocation originated locally.
+ */
+ public boolean isOriginLocal()
+ {
+ return originLocal;
+ }
+
+ /**
+ * If set to true, the invocation is assumed to have originated locally. If set to false,
+ * assumed to have originated from a remote cache.
+ *
+ * @param originLocal
+ */
+ public void setOriginLocal(boolean originLocal)
+ {
+ this.originLocal = originLocal;
+ }
+
+ public String toString()
+ {
+ return "InvocationContext{" +
+ "methodCall=" + methodCall +
+ "transaction=" + transaction +
+ ", globalTransaction=" + globalTransaction +
+ ", optionOverrides=" + optionOverrides +
+ ", originLocal=" + originLocal +
+ ", txHasMods=" + txHasMods +
+ '}';
+ }
+
+ public boolean isTxHasMods()
+ {
+ return txHasMods;
+ }
+
+ public void setTxHasMods(boolean b)
+ {
+ txHasMods = b;
+ }
+
+ public boolean isLocalRollbackOnly()
+ {
+ return localRollbackOnly;
+ }
+
+ /**
+ * Resets this to the defaults used when constructing an invocation context object
+ */
+ public void reset()
+ {
+ transaction = null;
+ globalTransaction = null;
+ optionOverrides = null;
+ originLocal = true;
+ txHasMods = false;
+ }
+
+ public InvocationContext clone() throws CloneNotSupportedException
+ {
+ InvocationContext clone = (InvocationContext) super.clone();
+ clone.setOptionOverrides(getOptionOverrides().clone());
+ return clone;
+ }
+
+ /**
+ * Sets the state of the InvocationContext based on the template context passed in
+ *
+ * @param template
+ */
+ public void setState(InvocationContext template)
+ {
+ if (template == null)
+ {
+ throw new NullPointerException("Template InvocationContext passed in to InvocationContext.setState() passed in is null");
+ }
+
+ this.setGlobalTransaction(template.getGlobalTransaction());
+ this.setLocalRollbackOnly(template.isLocalRollbackOnly());
+ this.setOptionOverrides(template.getOptionOverrides());
+ this.setOriginLocal(template.isOriginLocal());
+ this.setTransaction(template.getTransaction());
+ this.setTxHasMods(template.isTxHasMods());
+ }
+
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final InvocationContext that = (InvocationContext) o;
+
+ if (localRollbackOnly != that.localRollbackOnly) return false;
+ if (originLocal != that.originLocal) return false;
+ if (txHasMods != that.txHasMods) return false;
+ if (globalTransaction != null ? !globalTransaction.equals(that.globalTransaction) : that.globalTransaction != null)
+ {
+ return false;
+ }
+ if (optionOverrides != null ? !optionOverrides.equals(that.optionOverrides) : that.optionOverrides != null)
+ {
+ return false;
+ }
+ if (transaction != null ? !transaction.equals(that.transaction) : that.transaction != null) return false;
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ int result;
+ result = (transaction != null ? transaction.hashCode() : 0);
+ result = 29 * result + (globalTransaction != null ? globalTransaction.hashCode() : 0);
+ result = 29 * result + (optionOverrides != null ? optionOverrides.hashCode() : 0);
+ result = 29 * result + (originLocal ? 1 : 0);
+ result = 29 * result + (txHasMods ? 1 : 0);
+ result = 29 * result + (localRollbackOnly ? 1 : 0);
+ return result;
+ }
+
+ /**
+ * @return the method call associated with this invocation
+ */
+ public MethodCall getMethodCall()
+ {
+ return methodCall;
+ }
+
+ /**
+ * Sets the method call associated with this invocation.
+ *
+ * @param methodCall methodcall to set
+ */
+ public void setMethodCall(MethodCall methodCall)
+ {
+ this.methodCall = methodCall;
+ }
+
+ /**
+ * Factory method that creates a context with a given method call.
+ *
+ * @param methodCall methodcall to use
+ * @return invocation context
+ */
+ public static InvocationContext fromMethodCall(MethodCall methodCall)
+ {
+ InvocationContext ctx = new InvocationContext();
+ ctx.methodCall = methodCall;
+ return ctx;
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/Modification.java (from rev 4250, core/trunk/src-old/org/jboss/cache/Modification.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Modification.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/Modification.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,290 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Map;
+
+
+/**
+ * Represents a modification in the cache. Contains the nature of the modification
+ * (e.g. PUT, REMOVE), the fqn of the node, the new value and the previous value.
+ * A list of modifications will be sent to all nodes in a cluster when a transaction
+ * has been committed (PREPARE phase). A Modification is also used to roll back changes,
+ * e.g. since we know the previous value, we can reconstruct the previous state by
+ * applying the changes in a modification listin reverse order.
+ *
+ * @author <a href="mailto:bela@jboss.org">Bela Ban</a> Apr 12, 2003
+ * @version $Revision$
+ */
+public class Modification implements Externalizable
+{
+
+ private static final long serialVersionUID = 7463314130283897197L;
+
+ public enum ModificationType
+ {
+ PUT_KEY_VALUE,
+ PUT_DATA,
+ PUT_DATA_ERASE,
+ REMOVE_NODE,
+ REMOVE_KEY_VALUE,
+ REMOVE_DATA,
+ MOVE,
+ UNKNOWN
+ }
+
+ private ModificationType type = ModificationType.UNKNOWN;
+ private Fqn fqn = null;
+ private Fqn fqn2 = null;
+ private Object key = null;
+ private Object value = null;
+ private Object old_value = null;
+ private Map data = null;
+
+ /**
+ * Constructs a new modification.
+ */
+ public Modification()
+ {
+ }
+
+ /**
+ * Constructs a new modification with details.
+ */
+ public Modification(ModificationType type, Fqn fqn, Object key, Object value)
+ {
+ this.type = type;
+ this.fqn = fqn;
+ this.key = key;
+ this.value = value;
+ }
+
+ /**
+ * Constructs a new modification with key.
+ */
+ public Modification(ModificationType type, Fqn fqn, Object key)
+ {
+ this.type = type;
+ this.fqn = fqn;
+ this.key = key;
+ }
+
+ /**
+ * Constructs a new modification with data map.
+ */
+ public Modification(ModificationType type, Fqn fqn, Map data)
+ {
+ this.type = type;
+ this.fqn = fqn;
+ this.data = data;
+ }
+
+ /**
+ * Constructs a new modification with fqn only.
+ */
+ public Modification(ModificationType type, Fqn fqn)
+ {
+ this.type = type;
+ this.fqn = fqn;
+ }
+
+ /**
+ * Constructs a new modification with fqn only.
+ */
+ public Modification(ModificationType type, Fqn fqn1, Fqn fqn2)
+ {
+ this.type = type;
+ this.fqn = fqn1;
+ this.fqn2 = fqn2;
+ }
+
+
+ /**
+ * Returns the type of modification.
+ */
+ public ModificationType getType()
+ {
+ return type;
+ }
+
+ /**
+ * Sets the type of modification.
+ */
+ public void setType(ModificationType type)
+ {
+ this.type = type;
+ }
+
+ /**
+ * Returns the modification fqn.
+ */
+ public Fqn getFqn()
+ {
+ return fqn;
+ }
+
+ /**
+ * Sets the modification fqn.
+ */
+ public void setFqn(Fqn fqn)
+ {
+ this.fqn = fqn;
+ }
+
+ public void setFqn2(Fqn fqn2)
+ {
+ this.fqn2 = fqn2;
+ }
+
+ public Fqn getFqn2()
+ {
+ return fqn2;
+ }
+
+ /**
+ * Returns the modification key.
+ */
+ public Object getKey()
+ {
+ return key;
+ }
+
+ /**
+ * Sets the modification key.
+ */
+ public void setKey(Object key)
+ {
+ this.key = key;
+ }
+
+ /**
+ * Returns the modification value.
+ */
+ public Object getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Sets the modification value.
+ */
+ public void setValue(Object value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Returns the <i>post</i> modification old value.
+ */
+ public Object getOldValue()
+ {
+ return old_value;
+ }
+
+ /**
+ * Sets the <i>post</i> modification old value.
+ */
+ public void setOldValue(Object old_value)
+ {
+ this.old_value = old_value;
+ }
+
+ /**
+ * Returns the modification Map set.
+ */
+ public Map getData()
+ {
+ return data;
+ }
+
+ /**
+ * Sets the modification Map set.
+ */
+ public void setData(Map data)
+ {
+ this.data = data;
+ }
+
+ /**
+ * Writes data to an external stream.
+ */
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ out.writeObject(type);
+
+ out.writeBoolean(fqn != null);
+ if (fqn != null)
+ {
+ fqn.writeExternal(out);
+ }
+
+ out.writeObject(key);
+ out.writeObject(value);
+ out.writeObject(old_value);
+
+ out.writeBoolean(data != null);
+ if (data != null)
+ {
+ out.writeObject(data);
+ }
+ }
+
+ /**
+ * Reads data from an external stream.
+ */
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+ {
+ type = (ModificationType) in.readObject();
+
+ if (in.readBoolean())
+ {
+ fqn = new Fqn();
+ fqn.readExternal(in);
+ }
+
+ key = in.readObject();
+ value = in.readObject();
+ old_value = in.readObject();
+
+ if (in.readBoolean())
+ {
+ data = (Map) in.readObject();
+ }
+ }
+
+ /**
+ * Returns debug information about this modification.
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append(type.toString()).append(": ").append(fqn);
+ if (key != null)
+ {
+ sb.append("\nkey=").append(key);
+ }
+ if (value != null)
+ {
+ sb.append("\nvalue=").append(value);
+ }
+ if (old_value != null)
+ {
+ sb.append("\nold_value=").append(old_value);
+ }
+ if (data != null)
+ {
+ sb.append("\ndata=").append(data);
+ }
+ return sb.toString();
+ }
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/Node.java (from rev 4250, core/trunk/src-old/org/jboss/cache/Node.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Node.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/Node.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,280 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import net.jcip.annotations.ThreadSafe;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A Node is a {@link Fqn named} logical grouping of data in the JBoss {@link Cache}.
+ * A node should be used to contain data for a single data record, for example
+ * information about a particular person or account.
+ * <p/>
+ * One purpose of grouping cache data into separate nodes is to minimize transaction
+ * locking interference, and increase concurrency. So for example, when multiple threads or
+ * possibly distributed caches are acccessing different accounts simultaneously.
+ * <p/>
+ * Another is that when making changes to this node, its data might be kept in a single
+ * database row or file on disk. (Persisted via the use of a {@link org.jboss.cache.loader.CacheLoader}.)
+ * <p/>
+ * A node has references to its children, parent (each node except the root - defined by {@link Fqn#ROOT} - has
+ * a single parent) and data contained within the node (as key/value pairs). The
+ * data access methods are similar to the collections {@link Map} interface,
+ * but some are read-only or return copies of the underlying the data.
+ * <p/>
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ * @see Cache
+ * @since 2.0.0
+ */
+@ThreadSafe
+public interface Node<K, V>
+{
+ /**
+ * Returns the parent node.
+ * If this is the root node, this method returns <code>null</code>.
+ *
+ * @return the parent node, or null if this is the root node
+ */
+ Node<K, V> getParent();
+
+ /**
+ * Returns an immutable set of children nodes.
+ *
+ * @return an immutable {@link Set} of child nodes. Empty {@link Set} if there aren't any children.
+ */
+ Set<Node<K, V>> getChildren();
+
+ /**
+ * Returns an immutable set of children node names.
+ *
+ * @return an immutable {@link Set} of child node names. Empty {@link Set} if there aren't any children.
+ */
+ Set<Object> getChildrenNames();
+
+ /**
+ * Returns a map containing the data in this {@link Node}.
+ *
+ * @return a {@link Map} containing the data in this {@link Node}. If there is no data, an empty {@link Map} is returned. The {@link Map} returned is always immutable.
+ */
+ Map<K, V> getData();
+
+ /**
+ * Returns a {@link Set} containing the data in this {@link Node}.
+ *
+ * @return a {@link Set} containing the data in this {@link Node}. If there is no data, an empty {@link Set} is returned. The {@link Set} returned is always immutable.
+ */
+ Set<K> getKeys();
+
+ /**
+ * Returns the {@link Fqn} which represents the location of this {@link Node} in the cache structure. The {@link Fqn} returned is absolute.
+ *
+ * @return The {@link Fqn} which represents the location of this {@link Node} in the cache structure. The {@link Fqn} returned is absolute.
+ */
+ Fqn getFqn();
+
+ /**
+ * Adds a child node with the given {@link Fqn} under the current node. Returns the newly created node.
+ * <p/>
+ * If the child exists returns the child node anyway. Guaranteed to return a non-null node.
+ * <p/>
+ * The {@link Fqn} passed in is relative to the current node. The new child node will have an absolute fqn
+ * calculated as follows: <pre>new Fqn(getFqn(), f)</pre>. See {@link Fqn} for the operation of this constructor.
+ *
+ * @param f {@link Fqn} of the child node, relative to the current node.
+ * @return the newly created node, or the existing node if one already exists.
+ */
+ Node<K, V> addChild(Fqn<?> f);
+
+ /**
+ * Removes a child node specified by the given relative {@link Fqn}.
+ * <p/>
+ * If you wish to remove children based on absolute {@link Fqn}s, use the {@link Cache} interface instead.
+ *
+ * @param f {@link Fqn} of the child node, relative to the current node.
+ * @return true if the node was found and removed, false otherwise
+ */
+ boolean removeChild(Fqn<?> f);
+
+ /**
+ * Removes a child node specified by the given name.
+ *
+ * @param childName name of the child node, directly under the current node.
+ * @return true if the node was found and removed, false otherwise
+ */
+ boolean removeChild(Object childName);
+
+
+ /**
+ * Returns the child node
+ *
+ * @param f {@link Fqn} of the child node
+ * @return null if the child does not exist.
+ */
+ Node<K, V> getChild(Fqn<?> f);
+
+ /**
+ * @param name name of the child
+ * @return a direct child of the current node.
+ */
+ Node<K, V> getChild(Object name);
+
+ /**
+ * Associates the specified value with the specified key for this node.
+ * If this node previously contained a mapping for this key, the old value is replaced by the specified value.
+ *
+ * @param key key with which the specified value is to be associated.
+ * @param value value to be associated with the specified key.
+ * @return Returns the old value contained under this key. Null if key doesn't exist.
+ */
+ V put(K key, V value);
+
+ /**
+ * If the specified key is not already associated with a value, associate it with the given value, and returns the
+ * Object (if any) that occupied the space, or null.
+ * <p/>
+ * Equivalent to calling
+ * <pre>
+ * if (!node.getKeys().contains(key))
+ * return node.put(key, value);
+ * else
+ * return node.get(key);
+ * </pre>
+ * <p/>
+ * except that this is atomic.
+ *
+ * @param key key with which the specified value is to be associated.
+ * @param value value to be associated with the specified key.
+ * @return previous value associated with specified key, or null if there was no mapping for key.
+ */
+ V putIfAbsent(K key, V value);
+
+ /**
+ * Replace entry for key only if currently mapped to some value.
+ * Acts as
+ * <pre>
+ * if ((node.getKeys().contains(key))
+ * {
+ * return node.put(key, value);
+ * }
+ * else
+ * return null;
+ * </pre>
+ * <p/>
+ * except that this is atomic.
+ *
+ * @param key key with which the specified value is associated.
+ * @param value value to be associated with the specified key.
+ * @return previous value associated with specified key, or <tt>null</tt>
+ * if there was no mapping for key.
+ */
+ V replace(K key, V value);
+
+ /**
+ * Replace entry for key only if currently mapped to given value.
+ * Acts as
+ * <pre>
+ * if (node.get(key).equals(oldValue))
+ * {
+ * node.putAll(key, newValue);
+ * return true;
+ * }
+ * else
+ * return false;
+ * </pre>
+ * <p/>
+ * except that this is atomic.
+ *
+ * @param key key with which the specified value is associated.
+ * @param oldValue value expected to be associated with the specified key.
+ * @param newValue value to be associated with the specified key.
+ * @return true if the value was replaced
+ */
+ boolean replace(K key, V oldValue, V newValue);
+
+
+ /**
+ * Copies all of the mappings from the specified map to this node's map.
+ * If any data exists, existing keys are overwritten with the keys in the new map.
+ * The behavior is equivalent to:
+ * <pre>
+ * Node node;
+ * for (Map.Entry me : map.entrySet())
+ * node.put(me.getKey(), me.getValue());
+ * </pre>
+ *
+ * @param map map to copy from
+ */
+ void putAll(Map<K, V> map);
+
+ /**
+ * Similar to {@link #putAll(java.util.Map)} except that it removes any entries that exists in
+ * the data map first. Note that this happens atomically, under a single lock. This is the analogous
+ * to doing a {@link #clearData()} followed by a {@link #putAll(java.util.Map)} in the same transaction.
+ *
+ * @param map map to copy from
+ */
+ void replaceAll(Map<K, V> map);
+
+
+ /**
+ * Returns the value to which this node maps the specified key.
+ * Returns <code>null</code> if the node contains no mapping for this key.
+ *
+ * @param key key of the data to return
+ * @return the value to which this node maps the specified key, or <code>null</code> if the map contains no mapping for this key
+ */
+ V get(K key);
+
+ /**
+ * Removes the mapping for this key from this node if it is present.
+ * Returns the value to which the node previously associated the key,
+ * or <code>null</code> if the node contained no mapping for this key
+ *
+ * @param key key whose mapping is to be removed
+ * @return previous value associated with specified key, or <code>null</code>
+ * if there was no mapping for key
+ */
+ V remove(K key);
+
+ /**
+ * Removes all mappings from the node's data map.
+ */
+ void clearData();
+
+ /**
+ * @return the number of elements (key/value pairs) in the node's data map.
+ */
+ int dataSize();
+
+ /**
+ * Returns true if the child node denoted by the relative {@link Fqn} passed in exists.
+ *
+ * @param f {@link Fqn} relative to the current node of the child you are testing the existence of.
+ * @return true if the child node denoted by the relative {@link Fqn} passed in exists.
+ */
+ boolean hasChild(Fqn<?> f);
+
+ /**
+ * Returns true if the child node denoted by the Object name passed in exists.
+ *
+ * @param o name of the child, relative to the current node
+ * @return true if the child node denoted by the name passed in exists.
+ */
+ boolean hasChild(Object o);
+
+ /**
+ * Tests if a node reference is still valid. A node reference may become invalid if it has been evicted, for example,
+ * in which case it should be looked up again from the cache.
+ *
+ * @return true if the node is valid.
+ */
+ boolean isValid();
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/NodeFactory.java (from rev 4250, core/trunk/src-old/org/jboss/cache/NodeFactory.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/NodeFactory.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/NodeFactory.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,97 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.optimistic.TransactionWorkspace;
+import org.jboss.cache.optimistic.WorkspaceNode;
+import org.jboss.cache.optimistic.WorkspaceNodeImpl;
+
+import java.util.Map;
+
+/**
+ * Generates new nodes based on the {@link CacheSPI} configuration.
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ */
+public class NodeFactory<K, V>
+{
+ public enum NodeType
+ {
+ UNVERSIONED_NODE, VERSIONED_NODE, WORKSPACE_NODE
+ }
+
+ private CacheSPI<K, V> cache;
+ private boolean optimistic;
+
+ /**
+ * Constructs an instance of the factory
+ */
+ public NodeFactory(CacheSPI<K, V> cache)
+ {
+ this.cache = cache;
+ init();
+ }
+
+ /**
+ * Initialises the node factory with the configuration from the cache.
+ */
+ public void init()
+ {
+ optimistic = cache.getConfiguration().isNodeLockingOptimistic();
+ }
+
+
+ /**
+ * Creates a new {@link Node} instance.
+ *
+ * @param childName the new node's name
+ * @param fqn the new node's Fqn
+ * @param parent the new node's parent
+ * @param data the new node's attribute map
+ * @param mapSafe <code>true</code> if param <code>data</code> can safely
+ * be directly assigned to the new node's data field;
+ * <code>false</code> if param <code>data</code>'s contents
+ * should be copied into the new node's data field.
+ * @return the new node
+ */
+ public NodeSPI<K, V> createDataNode(Object childName, Fqn fqn, NodeSPI<K, V> parent, Map<K, V> data, boolean mapSafe)
+ {
+ NodeSPI<K, V> n = optimistic ? new VersionedNode<K, V>(fqn, parent, data, cache) : new UnversionedNode<K, V>(childName, fqn, data, mapSafe, cache);
+ // always assume that new nodes do not have data loaded
+ n.setDataLoaded(false);
+ return n;
+ }
+
+ public Node<K, V> createNode(Object childName, Node<K, V> parent, Map<K, V> data)
+ {
+ return createNodeOfType(parent, childName, parent, data);
+ }
+
+ public Node<K, V> createNodeOfType(Node<K, V> template, Object childName, Node<K, V> parent, Map<K, V> data)
+ {
+ if (template instanceof WorkspaceNode)
+ {
+ NodeSPI<K, V> dataNodeParent = ((WorkspaceNode<K, V>) parent).getNode();
+ TransactionWorkspace workspace = ((WorkspaceNode) template).getTransactionWorkspace();
+ return createWorkspaceNode(dataNodeParent, workspace);
+ }
+
+ // not a workspace node.
+ return createDataNode(childName, new Fqn(parent.getFqn(), childName), (NodeSPI<K, V>) parent, data, false);
+ }
+
+ public WorkspaceNode<K, V> createWorkspaceNode(NodeSPI<K, V> dataNode, TransactionWorkspace workspace)
+ {
+ return new WorkspaceNodeImpl<K, V>(dataNode, workspace);
+ }
+
+ public NodeSPI<K, V> createRootDataNode()
+ {
+ return createDataNode(null, Fqn.ROOT, null, null, false);
+ }
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/NodeNotExistsException.java (from rev 4250, core/trunk/src-old/org/jboss/cache/NodeNotExistsException.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/NodeNotExistsException.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/NodeNotExistsException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,42 @@
+// $Id$
+
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.cache;
+
+
+
+
+/**
+ * Thrown when an operation is attempted on a non-existing node in the cache
+ *
+ * @author <a href="mailto:bela@jboss.com">Bela Ban</a>.
+ * @version $Id$
+ */
+
+public class NodeNotExistsException extends CacheException {
+
+ private static final long serialVersionUID = 779376138690777440L;
+
+ public NodeNotExistsException() {
+ super();
+ }
+
+
+ public NodeNotExistsException(String msg) {
+ super(msg);
+ }
+
+
+ public NodeNotExistsException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/NodeSPI.java (from rev 4250, core/trunk/src-old/org/jboss/cache/NodeSPI.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/NodeSPI.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/NodeSPI.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,440 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.cache.lock.NodeLock;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.transaction.GlobalTransaction;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A more detailed interface to {@link Node}, which is used when writing plugins for or extending JBoss Cache. References are usually
+ * obtained by calling methods on {@link org.jboss.cache.CacheSPI}.
+ * <p/>
+ * <B><I>You should NEVER attempt to directly cast a {@link Node} instance to this interface. In future, the implementation may not allow it.</I></B>
+ * <p/>
+ * This interface contains overridden method signatures of some methods from {@link Node}, overridden to ensure return
+ * types of {@link Node} are replaced with {@link NodeSPI}.
+ * <p/>
+ * <b><i>An important note</i></b> on the xxxDirect() methods below. These methods are counterparts to similarly named
+ * methods in {@link Node} - e.g., {@link NodeSPI#getDirect(Object)} is a direct access counterpart to {@link Node#get(Object)},
+ * the difference being that:
+ * <p/>
+ * <ul>
+ * <li>{@link Node#get(Object)} - Passes the call up the interceptor stack, applies all aspects including node locking, cache loading, passivation, etc etc.</li>
+ * <li>{@link NodeSPI#getDirect(Object)} - directly works on the underlying data in the node.</li>
+ * </ul>
+ * <p/>
+ * The big difference with the direct access methods are that it is the onus of the caller to ensure proper locks are obtained
+ * prior to the call. A proper call should have gone through a locking-capable interceptor first and based on the cache
+ * configuration's locking policy, an appropriate lock should be obtained prior to the call. These direct access methods will
+ * throw {@link org.jboss.cache.lock.LockingException}s if appropriate locks haven't been obtained by the caller.
+ * <p/>
+ * It is important to node that the direct <b>read</b> methods, such as getDataDirect(), return unmodifiable collections.
+ * In addition to being unmodifiable, they are also defensively copied from the underlying data map to ensure view consistency.
+ * <p/>
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ * @see Node
+ * @see org.jboss.cache.CacheSPI
+ * @since 2.0.0
+ */
+@NotThreadSafe
+public interface NodeSPI<K, V> extends Node<K, V>
+{
+ /**
+ * Returns true if the children of this node were loaded from a cache loader.
+ *
+ * @return true if the children of this node were loaded from a cache loader.
+ */
+ boolean isChildrenLoaded();
+
+ /**
+ * Sets if the children of this node were loaded from a cache loader.
+ *
+ * @param loaded true if loaded, false otherwise
+ */
+ void setChildrenLoaded(boolean loaded);
+
+ /**
+ * Returns true if the data was loaded from the cache loader.
+ *
+ * @return true if the data was loaded from the cache loader.
+ */
+ public boolean isDataLoaded();
+
+ /**
+ * Sets if the data was loaded from the cache loader.
+ *
+ * @param dataLoaded true if loaded, false otherwise
+ */
+ public void setDataLoaded(boolean dataLoaded);
+
+ /**
+ * Returns a map to access the raw children.
+ * This method may return a null if the node does not have any children. It is important to note that this method
+ * returns a direct reference to the underlying child map and is intended for internal use only. Incorrect use
+ * may result in very inconsistent state of the cache.
+ *
+ * @return Map, keyed by child name, values Nodes.
+ */
+ Map<Object, Node<K, V>> getChildrenMapDirect();
+
+ /**
+ * Sets the node's children explictly.
+ * This method will remove all children currently associated with this node and add all the children passed in.
+ *
+ * @param children cannot be null
+ */
+ void setChildrenMapDirect(Map<Object, Node<K, V>> children);
+
+ /**
+ * Returns an existing child or creates a new one using a global transaction.
+ *
+ * @param name name of child to create
+ * @param tx transaction under which to create child
+ * @return newly created node
+ */
+ NodeSPI<K, V> getOrCreateChild(Object name, GlobalTransaction tx);
+
+ /**
+ * Returns a lock for this node.
+ *
+ * @return node lock
+ */
+ NodeLock getLock();
+
+ /**
+ * Sets the FQN of this node and resets the names of all children as well.
+ *
+ * @param f fqn to set
+ */
+ void setFqn(Fqn<?> f);
+
+ /**
+ * Returns true if the instance has been deleted in the current transaction.
+ *
+ * @return true if the instance has been deleted in the current transaction.
+ */
+ boolean isDeleted();
+
+ /**
+ * Marks the node as being deleted (or not) in the current transaction. This is not recursive, child nodes are not affected.
+ *
+ * @param marker true if the node has been deleted, false if not.
+ */
+ void markAsDeleted(boolean marker);
+
+ /**
+ * Same as {@link #markAsDeleted(boolean)} except that the option to recurse into children is provided.
+ *
+ * @param marker true if the node has been deleted, false if not.
+ * @param recursive if true, child nodes (and their children) are marked as well.
+ */
+ void markAsDeleted(boolean marker, boolean recursive);
+
+ /**
+ * Adds or replaces a child by name.
+ *
+ * @param nodeName child node name (not an FQN)
+ * @param nodeToAdd child node
+ */
+ void addChild(Object nodeName, Node<K, V> nodeToAdd);
+
+ /**
+ * Prints details of this node to the StringBuffer passed in.
+ *
+ * @param sb StringBuffer to print to
+ * @param indent depth of this node in the tree. Used to indent details by prepending spaces.
+ */
+ void printDetails(StringBuffer sb, int indent);
+
+ /**
+ * Prints basic information of this node to the StringBuffer passed in.
+ *
+ * @param sb StringBuffer to print to
+ * @param indent depth of this node in the tree. Used to indent details by prepending spaces.
+ */
+
+ void print(StringBuffer sb, int indent);
+
+ // versioning
+ /**
+ * Sets the data version of this node if versioning is supported.
+ *
+ * @param version data version to apply
+ * @throws UnsupportedOperationException if versioning is not supported
+ */
+ void setVersion(DataVersion version);
+
+ /**
+ * Returns the data version of this node if versioning is supported.
+ *
+ * @return data version
+ * @throws UnsupportedOperationException if versioning is not supported
+ */
+ DataVersion getVersion();
+
+
+ // ------- these XXXDirect() methods work directly on the node and bypass the interceptor chain.
+ /**
+ * Functionally the same as {@link #getChildren()} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @return set of child nodes.
+ * @see #getChildren()
+ */
+ Set<NodeSPI<K, V>> getChildrenDirect();
+
+ /**
+ * Directly removes all children for this node.
+ * The only direct method that does not have a non-direct counterpart.
+ */
+ void removeChildrenDirect();
+
+ /**
+ * Retrieves children (directly), optionally including any marked as deleted nodes.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method.
+ *
+ * @param includeMarkedAsDeleted if true, the returned set will include nodes marked as deleted
+ * @return a set of nodes
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ */
+ Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedAsDeleted);
+
+ /**
+ * Retrives a child directly by name.
+ * Functionally the same as {@link #getChild(Object)} except that it bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method.
+ *
+ * @param childName name of child
+ * @return child node
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ * @see #getChild(Object)
+ */
+ NodeSPI<K, V> getChildDirect(Object childName);
+
+ /**
+ * Adds a child directly to a Node.
+ * Functionally the same as {@link #addChild(Fqn)} except that it bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method.
+ *
+ * @param childName name of child
+ * @return child node
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ * @see #addChild(Fqn)
+ */
+ NodeSPI<K, V> addChildDirect(Fqn childName);
+
+ /**
+ * Directly adds the node passed in to the children map of the current node. Will throw a CacheException if
+ * <tt>child.getFqn().getParent().equals(getFqn())</tt> returns false.
+ *
+ * @param child child to add
+ */
+ void addChildDirect(NodeSPI<K, V> child);
+
+ /**
+ * Retrives a child directly by fully qualified name.
+ * Functionally the same as {@link #getChild(Fqn)} except that it bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method.
+ *
+ * @param childName name of child
+ * @return child node
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ * @see #getChild(Fqn)
+ */
+ NodeSPI<K, V> getChildDirect(Fqn childName);
+
+ /**
+ * Removes a child directly from a node.
+ * Functionally the same as {@link #removeChild(Fqn)} except that it bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ *
+ * @param fqn of child.
+ * @return true if the node was found, false otherwise
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ * @see #removeChild(Fqn)
+ */
+ boolean removeChildDirect(Fqn fqn);
+
+ /**
+ * Removes a child directly from a node.
+ * Functionally the same as {@link #removeChild(Object)} except that bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method.
+ *
+ * @param childName of child.
+ * @return true if the node was found, false otherwise
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ * @see #removeChild(Object)
+ */
+ boolean removeChildDirect(Object childName);
+
+
+ /**
+ * Removes a data key directly from a node.
+ * Functionally the same as {@link #remove(Object)} except that it bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method.
+ *
+ * @param key to remove
+ * @return the old data contained under the key
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ * @see #remove(Object)
+ */
+ V removeDirect(K key);
+
+ /**
+ * Functionally the same as {@link #put(Object,Object)} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @param key of data
+ * @param value of data
+ * @return the previous value under the key passed in, or <tt>null</tt>
+ * @see #put(Object,Object)
+ */
+ V putDirect(K key, V value);
+
+ /**
+ * Functionally the same as {@link #putAll(Map)} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @param data to put
+ * @see #putAll(Map)
+ */
+ void putAllDirect(Map<K, V> data);
+
+ /**
+ * Functionally the same as {@link #getData()} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * Note that this returns a reference to access the node's data.
+ * This data should only be modified by the cache itself.
+ * This method should never return null.
+ * <p/>
+ * Also note that this method returns an unmodifiable reference to the underlying data map.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @return map containing data
+ * @see #getData()
+ */
+ Map<K, V> getDataDirect();
+
+ /**
+ * Functionally the same as {@link #get(Object)} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @param key data to get
+ * @return value under key
+ * @see #get(Object)
+ */
+ V getDirect(K key);
+
+
+ /**
+ * Functionally the same as {@link #clearData()} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @see #clearData()
+ */
+ void clearDataDirect();
+
+
+ /**
+ * Functionally the same as {@link #getKeys()} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @return set of keys
+ * @see #getKeys()
+ */
+ Set<K> getKeysDirect();
+
+ /**
+ * Functionally the same as {@link #getChildrenNames()} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @return set of children names
+ * @see #getChildrenNames()
+ */
+ Set<Object> getChildrenNamesDirect();
+
+ /**
+ * Retrieves a reference to the cache in which this Node resides.
+ *
+ * @return a cache
+ */
+ CacheSPI<K, V> getCache();
+
+ // ----------- these methods override their corresponding methods in Node, so that the return types are NodeSPI rather than Node.
+
+ /**
+ * Returns the parent node as a {@link NodeSPI}, instead
+ * of {@link Node} from {@link Node#getParent()}, and is otherwise identical.
+ *
+ * @return parent node
+ * @see Node#getParent()
+ */
+ NodeSPI<K, V> getParent();
+
+ /**
+ * @return true if the node has one or more child nodes; false otherwise.
+ */
+ boolean hasChildrenDirect();
+}
Copied: core/trunk/src/main/java/org/jboss/cache/RPCManager.java (from rev 4250, core/trunk/src-old/org/jboss/cache/RPCManager.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RPCManager.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/RPCManager.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,27 @@
+package org.jboss.cache;
+
+import org.jboss.cache.marshall.MethodCall;
+import org.jgroups.Address;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+public interface RPCManager
+{
+ public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, int mode, boolean excludeSelf, long timeout) throws Exception;
+
+ public boolean isCoordinator();
+
+ public Address getCoordinator();
+
+ public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, boolean synchronous, boolean excludeSelf, int timeout) throws Exception;
+
+ public List callRemoteMethods(List<Address> recipients, Method method, Object[] arguments, boolean synchronous, boolean excludeSelf, long timeout) throws Exception;
+
+ public void setCache(CacheSPI c);
+
+ /**
+ * @return Returns the replication queue (if one is used), null otherwise.
+ */
+ public ReplicationQueue getReplicationQueue();
+}
Copied: core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java (from rev 4250, core/trunk/src-old/org/jboss/cache/RPCManagerImpl.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,75 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.marshall.MethodCall;
+import org.jgroups.Address;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+/**
+ * Manager that handles all RPC calls between JBoss Cache instances
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ */
+public class RPCManagerImpl implements RPCManager
+{
+ private CacheImpl c;
+
+ /**
+ * Empty ctor for mock object creation/unit testing
+ */
+ public RPCManagerImpl()
+ {
+ }
+
+ public RPCManagerImpl(CacheSPI c)
+ {
+ this.c = (CacheImpl) c;
+ }
+
+ // for now, we delegate RPC calls to deprecated methods in CacheImpl.
+
+ public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, int mode, boolean excludeSelf, long timeout) throws Exception
+ {
+ return c.callRemoteMethods(recipients, methodCall, mode, excludeSelf, timeout);
+ }
+
+ public boolean isCoordinator()
+ {
+ return c.isCoordinator();
+ }
+
+ public Address getCoordinator()
+ {
+ return c.getCoordinator();
+ }
+
+ public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, boolean synchronous, boolean excludeSelf, int timeout) throws Exception
+ {
+ return c.callRemoteMethods(recipients, methodCall, synchronous, excludeSelf, timeout);
+ }
+
+ public List callRemoteMethods(List<Address> recipients, Method method, Object[] arguments, boolean synchronous, boolean excludeSelf, long timeout) throws Exception
+ {
+ return c.callRemoteMethods(recipients, method, arguments, synchronous, excludeSelf, timeout);
+ }
+
+ public void setCache(CacheSPI c)
+ {
+ this.c = (CacheImpl) c;
+ }
+
+ /**
+ * @return Returns the replication queue (if one is used), null otherwise.
+ */
+ public ReplicationQueue getReplicationQueue()
+ {
+ return c.getReplicationQueue();
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/Region.java (from rev 4250, core/trunk/src-old/org/jboss/cache/Region.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Region.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/Region.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,189 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.config.EvictionPolicyConfig;
+import org.jboss.cache.config.EvictionRegionConfig;
+import org.jboss.cache.eviction.EvictedEventNode;
+import org.jboss.cache.eviction.EvictionPolicy;
+import org.jboss.cache.eviction.LRUPolicy;
+
+/**
+ * Defines characteristics such as class loading and eviction of {@link org.jboss.cache.Node}s belonging to a Region in a {@link Cache}.
+ * A Region is described by an {@link #getFqn() Fqn} relative to the root of the cache.
+ * All nodes and child nodes of this Fqn belong to this region.
+ * <p/>
+ * If a region is to be recognised as an eviction region (region of type {@link Type#EVICTION} then
+ * it <b>must</b> have an {@link org.jboss.cache.config.EvictionPolicyConfig} set using {@link #setEvictionPolicy(org.jboss.cache.config.EvictionPolicyConfig)}.
+ * <p/>
+ * Similarly, to be recognised as a marshalling region (region of type {@link Type#MARSHALLING} then it <b>must</b> have a
+ * {@link ClassLoader} registered using {@link #registerContextClassLoader(ClassLoader)}.
+ * <p/>
+ * Note that a single region can be both an eviction and marshalling region at the same time.
+ * <p/>
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ * @see org.jboss.cache.RegionManager
+ * @since 2.0.0
+ */
+public interface Region extends Comparable<Region>
+{
+
+ /**
+ * Types of regions.
+ */
+ public enum Type
+ {
+ EVICTION, MARSHALLING, ANY
+ }
+
+ /**
+ * Registers a specific {@link ClassLoader} for this region,
+ * overridding the default cache class loader.
+ *
+ * @param classLoader specific class loader
+ */
+ void registerContextClassLoader(ClassLoader classLoader);
+
+ /**
+ * Unregisters a registered {@link ClassLoader}s for this region.
+ */
+ void unregisterContextClassLoader();
+
+ /**
+ * Activates this region for replication.
+ * By default, the entire cache is activated for replication at start-up.
+ *
+ * @throws RegionNotEmptyException if the {@link Fqn} that represents this region already exists and contains data or children.
+ */
+ void activate() throws RegionNotEmptyException;
+
+ /**
+ * Activates this region for replication, but if the {@link Fqn} that represents this region already exists and
+ * either contains data or children, no state transfers take place. The region is simply marked as active in this
+ * case.
+ */
+ public void activateIfEmpty();
+
+ /**
+ * Deactivates this region from being replicated.
+ */
+ void deactivate();
+
+ /**
+ * Sets this region as active - this only marks a flag
+ * and does not actually activates or
+ * deactivates this region. Use {@link #activate()}
+ * and {@link #deactivate()} for the full process.
+ *
+ * @param b
+ */
+ void setActive(boolean b);
+
+ /**
+ * Returns true if this region has been activated.
+ *
+ * @return true if this region has been activated.
+ */
+ boolean isActive();
+
+ /**
+ * Returns the configured {@link ClassLoader} for this region.
+ *
+ * @return a ClassLoader
+ */
+ ClassLoader getClassLoader();
+
+ /**
+ * Configures an eviction policy for this region.
+ *
+ * @param evictionPolicyConfig configuration to set
+ */
+ void setEvictionPolicy(EvictionPolicyConfig evictionPolicyConfig);
+
+ /**
+ * Returns an eviction policy configuration.
+ *
+ * @return an eviction policy configuration
+ */
+ EvictionPolicyConfig getEvictionPolicyConfig();
+
+ /**
+ * Returns an eviction policy.
+ *
+ * @return an eviction policy
+ */
+ EvictionPolicy getEvictionPolicy();
+
+ /**
+ * Returns an eviction region configuration for this region.
+ *
+ * @return an eviction region configuration
+ */
+ EvictionRegionConfig getEvictionRegionConfig();
+
+ /**
+ * Clears the node event queue used for processing eviction.
+ *
+ * @see #nodeEventQueueSize()
+ */
+ void resetEvictionQueues();
+
+ /**
+ * Returns the size of the node event queue, used by the eviction thread.
+ *
+ * @return number of events
+ */
+ int nodeEventQueueSize();
+
+ /**
+ * Returns the most recent {@link org.jboss.cache.eviction.EvictedEventNode} added to the event queue by
+ * {@link #putNodeEvent(EvictedEventNode)}.
+ *
+ * @return the last {@link org.jboss.cache.eviction.EvictedEventNode}, or null if no more events exist
+ */
+ EvictedEventNode takeLastEventNode();
+
+ /**
+ * Adds an {@link org.jboss.cache.eviction.EvictedEventNode} to the internal queue for processing
+ * by the eviction thread.
+ *
+ * @param event event to add
+ */
+ void putNodeEvent(EvictedEventNode event);
+
+ /**
+ * Marks a {@link org.jboss.cache.Node} as currently in use, by adding an event to the eviction queue.
+ * If there is an {@link EvictionPolicy} associated with this region, and
+ * it respects this event (e.g., {@link LRUPolicy} does), then the {@link org.jboss.cache.Node} will not
+ * be evicted until {@link #unmarkNodeCurrentlyInUse(Fqn)} is invoked.
+ * <p/>
+ * This mechanism can be used to prevent eviction of data that the application
+ * is currently using, in the absence of any locks on the {@link org.jboss.cache.Node} where the
+ * data is stored.
+ *
+ * @param fqn Fqn of the node.
+ * @see #unmarkNodeCurrentlyInUse(Fqn)
+ */
+ void markNodeCurrentlyInUse(Fqn fqn, long timeout);
+
+ /**
+ * Adds an event to the eviction queue indicating that a node is no longer in use.
+ *
+ * @param fqn Fqn of the node.
+ * @see #markNodeCurrentlyInUse(Fqn,long)
+ */
+ void unmarkNodeCurrentlyInUse(Fqn fqn);
+
+ /**
+ * Returns the {@link org.jboss.cache.Fqn} of this region.
+ *
+ * @return the Fqn
+ */
+ Fqn getFqn();
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/RegionImpl.java (from rev 4250, core/trunk/src-old/org/jboss/cache/RegionImpl.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RegionImpl.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/RegionImpl.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,243 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.config.EvictionPolicyConfig;
+import org.jboss.cache.config.EvictionRegionConfig;
+import org.jboss.cache.eviction.EvictedEventNode;
+import org.jboss.cache.eviction.EvictionPolicy;
+import org.jboss.cache.eviction.NodeEventType;
+import org.jboss.cache.util.Util;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Default implementation of a {@link Region}
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ */
+public class RegionImpl implements Region
+{
+ private static final Log log = LogFactory.getLog(RegionImpl.class);
+
+ private RegionManager regionManager;
+ private Fqn fqn;
+ private boolean active;
+ private ClassLoader classLoader;
+ private BlockingQueue<EvictedEventNode> nodeEventQueue = null;
+ private int capacityWarnThreshold = 0;
+ private EvictionRegionConfig configuration = new EvictionRegionConfig();
+ private EvictionPolicy policy;
+
+ /**
+ * Constructs a marshalling region from an fqn and region manager.
+ */
+ public RegionImpl(Fqn fqn, RegionManager regionManager)
+ {
+ this.fqn = fqn;
+ this.regionManager = regionManager;
+ this.active = !regionManager.isDefaultInactive();
+ }
+
+ /**
+ * Constructs an eviction region from a policy and configuration, defined by an fqn and region manager.
+ */
+ public RegionImpl(EvictionPolicy policy, EvictionRegionConfig config, Fqn fqn, RegionManager regionManager)
+ {
+ this(fqn, regionManager);
+ this.configuration = config;
+ this.policy = policy;
+ createQueue();
+ }
+
+ public void registerContextClassLoader(ClassLoader classLoader)
+ {
+ this.classLoader = classLoader;
+ }
+
+ public void unregisterContextClassLoader()
+ {
+ this.classLoader = null;
+ }
+
+ public void activate()
+ {
+ regionManager.activate(fqn);
+ active = true;
+ }
+
+ public void activateIfEmpty()
+ {
+ regionManager.activateIfEmpty(fqn);
+ active = true;
+ }
+
+ public void deactivate()
+ {
+ regionManager.deactivate(fqn);
+ active = false;
+ }
+
+ public boolean isActive()
+ {
+ return active;
+ }
+
+ public ClassLoader getClassLoader()
+ {
+ return classLoader;
+ }
+
+ public Fqn getFqn()
+ {
+ return fqn;
+ }
+
+ public void setActive(boolean b)
+ {
+ active = b;
+ }
+
+ // -------- eviction stuff -----
+
+ public void markNodeCurrentlyInUse(Fqn fqn, long timeout)
+ {
+ EvictedEventNode markUse = new EvictedEventNode(fqn, NodeEventType.MARK_IN_USE_EVENT);
+ markUse.setInUseTimeout(timeout);
+ putNodeEvent(markUse);
+ }
+
+ public void unmarkNodeCurrentlyInUse(Fqn fqn)
+ {
+ EvictedEventNode markNoUse = new EvictedEventNode(fqn, NodeEventType.UNMARK_USE_EVENT);
+ putNodeEvent(markNoUse);
+ }
+
+ public String toString()
+ {
+ return "RegionImpl{" +
+ "fqn=" + fqn +
+ "; classloader="+ classLoader +
+ "; active=" + active +
+ "; eviction=" + (getEvictionPolicy() != null) +
+ "; timerThreadRegistered=" + (getEvictionPolicy() != null && regionManager.getEvictionTimerTask().isRegionRegisteredForProcessing(this)) +
+ '}';
+ }
+
+ public int compareTo(Region other)
+ {
+ return getFqn().compareTo(other.getFqn());
+ }
+
+ public void putNodeEvent(EvictedEventNode event)
+ {
+ try
+ {
+ if (nodeEventQueue == null) createQueue();// in case the queue does not exist yet.
+ if (nodeEventQueue.size() > capacityWarnThreshold)
+ {
+ log.warn("putNodeEvent(): eviction node event queue size is at 98% threshold value of capacity: " + configuration.getEventQueueSize() +
+ " Region: " + fqn +
+ " You will need to reduce the wakeUpIntervalSeconds parameter.");
+ }
+
+ nodeEventQueue.put(event);
+ }
+ catch (InterruptedException e)
+ {
+ log.debug("give up put", e);
+ }
+ }
+
+ public EvictedEventNode takeLastEventNode()
+ {
+ try
+ {
+ return nodeEventQueue.poll(0, TimeUnit.SECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ log.debug("trace", e);
+ }
+ return null;
+ }
+
+ public int nodeEventQueueSize()
+ {
+ return nodeEventQueue.size();
+ }
+
+ public void resetEvictionQueues()
+ {
+ nodeEventQueue.clear();
+ }
+
+ private synchronized void createQueue()
+ {
+ if (nodeEventQueue == null)
+ {
+ if (configuration == null)
+ {
+ throw new IllegalArgumentException("null eviction configuration");
+ }
+ int size = configuration.getEventQueueSize();
+ capacityWarnThreshold = (98 * size) / 100 - 100;
+ if (capacityWarnThreshold <= 0)
+ {
+ throw new RuntimeException("Capacity warn threshold used in eviction is smaller than 1.");
+ }
+ nodeEventQueue = new LinkedBlockingQueue<EvictedEventNode>(size);
+ }
+ }
+
+ public EvictionRegionConfig getEvictionRegionConfig()
+ {
+ return this.configuration;
+ }
+
+ public EvictionPolicyConfig getEvictionPolicyConfig()
+ {
+ return configuration == null ? null : configuration.getEvictionPolicyConfig();
+ }
+
+ public EvictionPolicy getEvictionPolicy()
+ {
+ return policy;
+ }
+
+ public void setEvictionPolicy(EvictionPolicyConfig evictionPolicyConfig)
+ {
+ configuration.setEvictionPolicyConfig(evictionPolicyConfig);
+ policy = createPolicy(evictionPolicyConfig.getEvictionPolicyClass());
+ regionManager.getEvictionTimerTask().addRegionToProcess(this);
+ if (nodeEventQueue == null) createQueue();
+ }
+
+ private EvictionPolicy createPolicy(String className)
+ {
+ if (className == null)
+ {
+ throw new IllegalArgumentException("null className");
+ }
+ try
+ {
+ if (log.isTraceEnabled()) log.trace("Instantiating " + className);
+ EvictionPolicy ep = (EvictionPolicy) Util.loadClass(className).newInstance();
+ ep.setCache(regionManager.getCache());
+ return ep;
+ }
+ catch (Exception e)
+ {
+ log.fatal("Unable to instantiate eviction policy class " + className, e);
+ return null;
+ }
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/RegionManager.java (from rev 4250, core/trunk/src-old/org/jboss/cache/RegionManager.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RegionManager.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/RegionManager.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,819 @@
+package org.jboss.cache;
+
+import net.jcip.annotations.ThreadSafe;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.cache.config.ConfigurationException;
+import org.jboss.cache.config.EvictionConfig;
+import org.jboss.cache.config.EvictionRegionConfig;
+import org.jboss.cache.eviction.EvictionTimerTask;
+import org.jboss.cache.eviction.RegionNameConflictException;
+import org.jboss.cache.lock.NodeLock;
+import org.jgroups.Address;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Manages multiple {@link Region}s for a Cache instance.
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
+ * @since 2.0.0
+ */
+@ThreadSafe
+public class RegionManager
+{
+ /**
+ * The default region used in XML configuration files when defining eviction policies. Any
+ * eviction settings bound under this 'default' Fqn is appplied to {@link org.jboss.cache.Fqn#ROOT} internally so
+ * any region that is not explicitly defined comes under the settings defined for this default.
+ */
+ public static final Fqn DEFAULT_REGION = new Fqn("_default_");
+
+ /**
+ * A registry of regions that have been defined.
+ */
+ private Map<Fqn, Region> regionsRegistry = new ConcurrentHashMap<Fqn, Region>();
+ private boolean defaultInactive;
+ private Log log = LogFactory.getLog(RegionManager.class);
+ private CacheImpl cache;
+ private boolean usingEvictions;
+ private EvictionConfig evictionConfig;
+ private EvictionTimerTask evictionTimerTask = new EvictionTimerTask();
+
+ protected final Set<Fqn> activationChangeNodes = Collections.synchronizedSet(new HashSet<Fqn>());
+
+ /**
+ * Constructs a new instance not attached to a cache.
+ */
+ public RegionManager()
+ {
+ }
+
+ /**
+ * Constructs a new instance attached to a cache.
+ */
+ public RegionManager(CacheImpl cache)
+ {
+ this.cache = cache;
+ }
+
+ /**
+ * Returns true if evictions are being processed.
+ */
+ public boolean isUsingEvictions()
+ {
+ return usingEvictions;
+ }
+
+ /**
+ * Returns true if replication is by default inactive for new {@link Region}s.
+ */
+ public boolean isDefaultInactive()
+ {
+ return defaultInactive;
+ }
+
+ /**
+ * Sets if replication for new {@link Region}s is by default inactive.
+ */
+ public void setDefaultInactive(boolean defaultInactive)
+ {
+ this.defaultInactive = defaultInactive;
+ }
+
+ /**
+ * Helper utility that checks for a {@link ClassLoader} registered for the
+ * given {@link Fqn}, and if found sets it as the TCCL. If the given Fqn is
+ * under the _BUDDY_BACKUP_ region, the equivalent region in the main
+ * cache is used to find the {@link ClassLoader}.
+ *
+ * @param fqn Fqn pointing to a region for which a special classloader
+ * may have been registered.
+ */
+ public void setContextClassLoaderAsCurrent(Fqn fqn)
+ {
+ if (fqn.isChildOf(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN))
+ {
+ if (fqn.size() <= 2)
+ {
+ fqn = Fqn.ROOT;
+ }
+ else
+ {
+ fqn = fqn.getSubFqn(2, fqn.size());
+ }
+ }
+ Region region = getRegion(fqn, false);
+ ClassLoader regionCL = (region == null) ? null : region.getClassLoader();
+ if (regionCL != null)
+ {
+ Thread.currentThread().setContextClassLoader(regionCL);
+ }
+
+ }
+
+ /**
+ * Returns a region by {@link Fqn}, creating it optionally if absent. If the region does not exist and <tt>createIfAbsent</tt>
+ * is <tt>false</tt>, a parent region which may apply to the {@link Fqn} is sought.
+ */
+ public Region getRegion(Fqn fqn, boolean createIfAbsent)
+ {
+ return getRegion(fqn, Region.Type.ANY, createIfAbsent);
+ }
+
+ /**
+ * An overloaded form of {@link #getRegion(Fqn,boolean)} that takes an additional {@link org.jboss.cache.Region.Type}
+ * parameter to force regions of a specific type.
+ *
+ * @see org.jboss.cache.Region.Type
+ */
+ public Region getRegion(Fqn fqn, Region.Type type, boolean createIfAbsent)
+ {
+ Fqn fqnToUse = fqn;
+ if (DEFAULT_REGION.equals(fqnToUse)) fqnToUse = Fqn.ROOT;
+ // first see if a region for this specific Fqn exists
+ if (regionsRegistry.containsKey(fqnToUse))
+ {
+ Region r = regionsRegistry.get(fqnToUse);
+
+ // this is a very poor way of telling whether a region is a marshalling one or an eviction one. :-(
+ // mandates that class loaders be registered for marshalling regions.
+ if (type == Region.Type.ANY
+ || (type == Region.Type.MARSHALLING && r.getClassLoader() != null)
+ || (type == Region.Type.EVICTION && r.getEvictionPolicyConfig() != null))
+ {
+ return r;
+ }
+ }
+
+ // if not, attempt to create one ...
+ if (createIfAbsent)
+ {
+ Region r = new RegionImpl(fqnToUse, this);
+ regionsRegistry.put(fqnToUse, r);
+ if (type == Region.Type.MARSHALLING)
+ {
+ // insert current class loader into region so at least it is recognised as a marshalling region
+ r.registerContextClassLoader(getClass().getClassLoader());
+ }
+ return r;
+ }
+ else
+ {
+ // first test if the default region has been defined. If not, and if eviction regions
+ // are in use, throw an exception since it is required.
+ if (isUsingEvictions() && !regionsRegistry.containsKey(Fqn.ROOT))
+ {
+ throw new RuntimeException("No default eviction region defined!");
+ }
+ }
+
+ // else try and find a parent which has a defined region, may return null if nothing is defined.
+ Region nextBestThing = null;
+ Fqn nextFqn = fqnToUse;
+
+ while (nextBestThing == null)
+ {
+ nextFqn = nextFqn.getParent();
+ if (regionsRegistry.containsKey(nextFqn))
+ {
+ Region r = regionsRegistry.get(nextFqn);
+
+ // this is a very poor way of telling whether a region is a marshalling one or an eviction one. :-(
+ // mandates that class loaders be registered for marshalling regions.
+ if (type == Region.Type.ANY
+ || (type == Region.Type.MARSHALLING && r.getClassLoader() != null)
+ || (type == Region.Type.EVICTION && r.getEvictionPolicyConfig() != null))
+ {
+ nextBestThing = r;
+ }
+ }
+ if (nextFqn.isRoot()) break;
+ }
+
+ return nextBestThing;
+ }
+
+ /**
+ * Returns a region using Fqn.fromString(fqn), calling {@link #getRegion(Fqn,boolean)}
+ *
+ * @param fqn
+ * @param createIfAbsent
+ * @see #getRegion(Fqn,boolean)
+ */
+ public Region getRegion(String fqn, boolean createIfAbsent)
+ {
+ return getRegion(Fqn.fromString(fqn), createIfAbsent);
+ }
+
+ /**
+ * Removes a {@link org.jboss.cache.Region} identified by the given fqn.
+ *
+ * @param fqn fqn of the region to remove
+ * @return true if such a region existed and was removed.
+ */
+ public boolean removeRegion(Fqn fqn)
+ {
+ Region r = regionsRegistry.remove(fqn);
+ if (r == null) return false;
+
+ if (isUsingEvictions() && r.getEvictionPolicy() != null)
+ {
+ evictionTimerTask.removeRegionToProcess(r);
+ }
+ return true;
+ }
+
+ /**
+ * @return the eviction timer task object associated with this Region Manager.
+ */
+ protected EvictionTimerTask getEvictionTimerTask()
+ {
+ return evictionTimerTask;
+ }
+
+ /**
+ * Activates unmarshalling of replication messages for the region
+ * rooted in the given Fqn.
+ * <p/>
+ * <strong>NOTE:</strong> This method will cause the creation of a node
+ * in the local cache at <code>subtreeFqn</code> whether or not that
+ * node exists anywhere else in the cluster. If the node does not exist
+ * elsewhere, the local node will be empty. The creation of this node will
+ * not be replicated.
+ * <p/>
+ *
+ * @param fqn representing the region to be activated.
+ * @throws RegionNotEmptyException if the node <code>fqn</code>
+ * exists and already has either data or children
+ */
+ public void activate(Fqn fqn) throws RegionNotEmptyException
+ {
+ activate(fqn, false);
+ }
+
+ /**
+ * Attempts to activate a given region rooted at a given Fqn, similar to {@link #activate(Fqn)} except
+ * that if the fqn is currently already in use (probably already been activated) this method is a no-op.
+ *
+ * @param fqn which represents the region to activate
+ */
+ public void activateIfEmpty(Fqn fqn)
+ {
+ activate(fqn, true);
+ }
+
+ private void activate(Fqn fqn, boolean suppressRegionNotEmptyException)
+ {
+ try
+ {
+ if (log.isTraceEnabled()) log.trace("Activating region " + fqn);
+ Region r = getRegion(fqn, false);
+ if (r != null)
+ {
+ if (!defaultInactive && r.getClassLoader() == null)
+ {
+ // This region's state will no match that of a non-existent one
+ // So, there is no reason to keep this region any more
+
+ // (Brian) We shouldn't do this anymore; now outside code
+ // can have a ref to the region!!
+ removeRegion(fqn);
+ }
+ else
+ {
+ //r.activate();
+ r.setActive(true);
+ // FIXME - persistent state transfer counts too!
+ if (cache.getConfiguration().isFetchInMemoryState())
+ {
+ activateRegion(r.getFqn(), suppressRegionNotEmptyException);
+ }
+ }
+ }
+ else if (defaultInactive)
+ {
+ // "Active" region is not the default, so create a region
+ r = getRegion(fqn, true);
+ r.setActive(true);
+ // FIXME - persistent state transfer counts too!
+ if (cache.getConfiguration().isFetchInMemoryState())
+ {
+ activateRegion(r.getFqn(), suppressRegionNotEmptyException);
+ }
+ }
+ }
+ catch (RuntimeException re)
+ {
+ throw re;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Causes the cache to transfer state for the subtree rooted at
+ * <code>subtreeFqn</code> and to begin accepting replication messages
+ * for that subtree.
+ * <p/>
+ * <strong>NOTE:</strong> This method will cause the creation of a node
+ * in the local cache at <code>subtreeFqn</code> whether or not that
+ * node exists anywhere else in the cluster. If the node does not exist
+ * elsewhere, the local node will be empty. The creation of this node will
+ * not be replicated.
+ *
+ * @param fqn Fqn string indicating the uppermost node in the
+ * portion of the cache that should be activated.
+ * @throws RegionNotEmptyException if the node <code>subtreeFqn</code>
+ * exists and has either data or children
+ */
+ private void activateRegion(Fqn fqn, boolean suppressRegionNotEmptyException)
+ {
+ // Check whether the node already exists and has data
+ Node subtreeRoot = cache.findNode(fqn);
+
+ /*
+ * Commented out on Nov 16,2006 Manik&Vladimir
+ *
+ * if (!(cache.isNodeEmpty(subtreeRoot)))
+ {
+ throw new RegionNotEmptyException("Node " + subtreeRoot.getFqn() + " already exists and is not empty");
+ }*/
+
+ if (isActivatingDeactivating(fqn))
+ {
+ throw new CacheException("Region " + subtreeRoot.getFqn() + " is already being activated/deactivated");
+ }
+
+ if (log.isDebugEnabled())
+ {
+ log.debug("activating " + fqn);
+ }
+
+ try
+ {
+
+ // Add this fqn to the set of those we are activating
+ // so calls to _getState for the fqn can return quickly
+ activationChangeNodes.add(fqn);
+
+ Region region = getRegion(fqn, true);
+
+ BuddyManager buddyManager = cache.getBuddyManager();
+ // Request partial state from the cluster and integrate it
+ if (buddyManager == null)
+ {
+ // Get the state from any node that has it and put it
+ // in the main cache
+ if (subtreeRoot == null)
+ {
+ // We'll update this node with the state we receive
+ subtreeRoot = cache.createSubtreeRootNode(fqn);
+ }
+
+ List<Address> members = cache.getMembers();
+ cache.fetchPartialState(members, subtreeRoot.getFqn());
+ }
+ else
+ {
+ // Get the state from each DataOwner and integrate in their
+ // respective buddy backup cache
+ List<Address> buddies = buddyManager.getBuddyAddresses();
+ for (Address buddy : buddies)
+ {
+ List<Address> sources = new ArrayList<Address>(1);
+ sources.add(buddy);
+ Fqn base = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, BuddyManager.getGroupNameFromAddress(buddy));
+ Fqn buddyRoot = new Fqn(base, fqn);
+ subtreeRoot = cache.findNode(buddyRoot);
+ if (subtreeRoot == null)
+ {
+ // We'll update this node with the state we receive
+ subtreeRoot = cache.createSubtreeRootNode(buddyRoot);
+ }
+ cache.fetchPartialState(sources, fqn, subtreeRoot.getFqn());
+ }
+ }
+ }
+ catch (Throwable t)
+ {
+ log.error("failed to activate " + fqn, t);
+
+ // "Re-deactivate" the region
+ try
+ {
+ inactivateRegion(fqn);
+ }
+ catch (Exception e)
+ {
+ log.error("failed inactivating " + fqn, e);
+ // just swallow this one and throw the first one
+ }
+
+ // Throw the exception on, wrapping if necessary
+ if (t instanceof RegionNotEmptyException)
+ {
+ if (!suppressRegionNotEmptyException) throw (RegionNotEmptyException) t;
+ }
+ else if (t instanceof CacheException)
+ {
+ throw (CacheException) t;
+ }
+ else
+ {
+ throw new CacheException(t.getClass().getName() + " " +
+ t.getLocalizedMessage(), t);
+ }
+ }
+ finally
+ {
+ activationChangeNodes.remove(fqn);
+ }
+ }
+
+ /**
+ * Convenienve method. If the region defined by fqn does not exist, {@link #isDefaultInactive()} is returned, otherwise
+ * !{@link Region#isActive()} is returned.
+ *
+ * @param fqn fqn to test
+ * @return true if inactive
+ */
+ public boolean isInactive(Fqn fqn)
+ {
+ Region region = getRegion(fqn, false);
+ return region == null ? defaultInactive : !region.isActive();
+ }
+
+
+ /**
+ * Causes the cache to stop accepting replication events for the subtree
+ * rooted at <code>subtreeFqn</code> and evict all nodes in that subtree.
+ * <p/>
+ * This is legacy code and should not be called directly. This is a private method for now and will be refactored out.
+ * You should be using {@link #activate(Fqn)} and {@link #deactivate(Fqn)}
+ * <p/>
+ *
+ * @param fqn Fqn string indicating the uppermost node in the
+ * portion of the cache that should be activated.
+ * @throws RegionNameConflictException if <code>subtreeFqn</code> indicates
+ * a node that is part of another
+ * subtree that is being specially
+ * managed (either by activate/inactiveRegion()
+ * or by registerClassLoader())
+ * @throws CacheException if there is a problem evicting nodes
+ * @throws IllegalStateException if {@link org.jboss.cache.config.Configuration#isUseRegionBasedMarshalling()} is <code>false</code>
+ */
+ private void inactivateRegion(Fqn fqn) throws CacheException
+ {
+ if (isActivatingDeactivating(fqn))
+ {
+ throw new CacheException("Region " + fqn + " is already being activated/deactivated");
+ }
+
+ NodeSPI parent = null;
+ NodeSPI subtreeRoot = null;
+ boolean parentLocked = false;
+ boolean subtreeLocked = false;
+ NodeLock parentLock = null;
+ NodeLock subtreeLock = null;
+
+ try
+ {
+ // Record that this fqn is in status change, so can't provide state
+ activationChangeNodes.add(fqn);
+
+ if (!isInactive(fqn))
+ {
+ deactivate(fqn);
+ }
+
+ // Create a list with the Fqn in the main cache and any buddy backup trees
+ BuddyManager buddyManager = cache.getBuddyManager();
+ ArrayList<Fqn> list = new ArrayList<Fqn>();
+ list.add(fqn);
+
+ if (buddyManager != null)
+ {
+ Set buddies = cache.getChildrenNames(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
+ if (buddies != null)
+ {
+ for (Iterator it = buddies.iterator(); it.hasNext();)
+ {
+ Fqn base = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, it.next());
+ list.add(new Fqn(base, fqn));
+ }
+ }
+ }
+
+ long stateFetchTimeout = cache.getConfiguration().getLockAcquisitionTimeout() + 5000;
+ // Remove the subtree from the main cache and any buddy backup trees
+ for (Iterator<Fqn> it = list.iterator(); it.hasNext();)
+ {
+ Fqn subtree = it.next();
+ subtreeRoot = cache.findNode(subtree);
+ if (subtreeRoot != null)
+ {
+ // Acquire locks
+ Object owner = cache.getOwnerForLock();
+ subtreeLock = subtreeRoot.getLock();
+ subtreeLock.acquireAll(owner, stateFetchTimeout, NodeLock.LockType.WRITE);
+ subtreeLocked = true;
+
+ // Lock the parent, as we're about to write to it
+ parent = subtreeRoot.getParent();
+ if (parent != null)
+ {
+ parentLock = parent.getLock();
+ parentLock.acquire(owner, stateFetchTimeout, NodeLock.LockType.WRITE);
+ parentLocked = true;
+ }
+
+ // Remove the subtree
+ cache._evictSubtree(subtree);
+
+ // Release locks
+ if (parent != null)
+ {
+ log.debug("forcing release of locks in parent");
+ parentLock.releaseAll();
+ }
+
+ parentLocked = false;
+
+ log.debug("forcing release of all locks in subtree");
+ subtreeLock.releaseAll();
+ subtreeLocked = false;
+ }
+ }
+ }
+ catch (InterruptedException ie)
+ {
+ throw new CacheException("Interrupted while acquiring lock", ie);
+ }
+ finally
+ {
+ // If we didn't succeed, undo the marshalling change
+ // NO. Since we inactivated, we may have missed changes
+ //if (!success && !inactive)
+ // marshaller_.activate(subtreeFqn);
+
+ // If necessary, release locks
+ if (parentLocked)
+ {
+ log.debug("forcing release of locks in parent");
+ try
+ {
+ parentLock.releaseAll();
+ }
+ catch (Throwable t)
+ {
+ log.error("failed releasing locks", t);
+ }
+ }
+ if (subtreeLocked)
+ {
+ log.debug("forcing release of all locks in subtree");
+ try
+ {
+ subtreeLock.releaseAll();
+ }
+ catch (Throwable t)
+ {
+ log.error("failed releasing locks", t);
+ }
+ }
+
+ activationChangeNodes.remove(fqn);
+ }
+ }
+
+ /**
+ * <p/>
+ * This is legacy code and should not be called directly. This is a private method for now and will be refactored out.
+ * You should be using {@link #activate(Fqn)} and {@link #deactivate(Fqn)}
+ * <p/>
+ *
+ * @param fqn fqn of the region
+ * @return true if the region defined by the fqn is in the process of activating/deactivating
+ */
+ private boolean isActivatingDeactivating(Fqn fqn)
+ {
+ return activationChangeNodes.contains(fqn);
+ }
+
+ /**
+ * Returns true if the region exists
+ *
+ * @param fqn FQN of the region
+ * @param type type of region to search for
+ * @return true if the region exists
+ */
+ public boolean hasRegion(Fqn fqn, Region.Type type)
+ {
+ Region r = regionsRegistry.get(fqn);
+ if (r == null) return false;
+ switch (type)
+ {
+ case ANY:
+ return true;
+ case EVICTION:
+ return r.getEvictionPolicy() != null && evictionTimerTask.isRegionRegisteredForProcessing(r);
+ case MARSHALLING:
+ return r.isActive() && r.getClassLoader() != null;
+ }
+ // should never reach here?
+ return false;
+ }
+
+ /**
+ * Disables unmarshalling of replication messages for the region
+ * rooted in the given Fqn.
+ *
+ * @param fqn
+ */
+ public void deactivate(Fqn fqn)
+ {
+ try
+ {
+ Region region = getRegion(fqn, false);
+
+ if (region != null)
+ {
+ if (defaultInactive && region.getClassLoader() == null)
+ {
+ // This region's state will no match that of a non-existent one
+ // So, there is no reason to keep this region any more
+
+ // FIXME (Brian) We shouldn't do this anymore; now outside code
+ // can have a ref to the region!!
+ removeRegion(fqn);
+ }
+ else
+ {
+ //region.deactivate();
+ region.setActive(false);
+ // FIXME - we should always clean up; otherwise stale data
+ // is in memory!
+ if (cache.getConfiguration().isFetchInMemoryState())
+ {
+ inactivateRegion(fqn);
+ }
+ }
+ }
+ else if (!defaultInactive)
+ {
+ region = getRegion(fqn, true);
+ region.setActive(false);
+ // FIXME - we should always clean up; otherwise stale data
+ // is in memory!
+ if (cache.getConfiguration().isFetchInMemoryState())
+ {
+ inactivateRegion(fqn);
+ }
+ }
+ }
+ catch (RuntimeException re)
+ {
+ throw re;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Resets the region manager's regions registry
+ */
+ public void reset()
+ {
+ regionsRegistry.clear();
+ }
+
+ /**
+ * Returns an ordered list of all regions.
+ * Note that the ordered list returned is sorted according to the natural order defined in the {@link Comparable} interface, which {@link org.jboss.cache.Region} extends.
+ *
+ * @param type Type of region to return
+ * @return an ordered list of all regions, based on the type requested.
+ */
+ public List<Region> getAllRegions(Region.Type type)
+ {
+ List<Region> regions;
+
+ if (type != Region.Type.ANY)
+ {
+ regions = new ArrayList<Region>();
+ // we need to loop thru the regions and only select specific regions to rtn.
+ for (Region r : regionsRegistry.values())
+ {
+ if ((type == Region.Type.EVICTION && r.getEvictionPolicy() != null && evictionTimerTask.isRegionRegisteredForProcessing(r)) ||
+ (type == Region.Type.MARSHALLING && r.isActive() && r.getClassLoader() != null))
+ regions.add(r);
+ }
+ }
+ else
+ {
+ // put all regions
+ regions = new ArrayList<Region>(regionsRegistry.values());
+ }
+
+ Collections.sort(regions);
+
+ return regions;
+ }
+
+ /**
+ * Sets if evictions are processed.
+ */
+ public void setUsingEvictions(boolean usingEvictions)
+ {
+ this.usingEvictions = usingEvictions;
+ }
+
+ /**
+ * Sets the eviction configuration.
+ */
+ public void setEvictionConfig(EvictionConfig evictionConfig)
+ {
+ this.evictionConfig = evictionConfig;
+ boolean setDefault = false;
+ // create regions for the regions defined in the evictionConfig.
+ for (EvictionRegionConfig erc : evictionConfig.getEvictionRegionConfigs())
+ {
+ Fqn fqn = erc.getRegionFqn();
+ if (log.isTraceEnabled()) log.trace("Creating eviction region " + fqn);
+
+ if (fqn.equals(DEFAULT_REGION))
+ {
+ if (setDefault)
+ {
+ throw new ConfigurationException("A default region for evictions has already been set for this cache");
+ }
+ if (log.isTraceEnabled()) log.trace("Applying settings for " + DEFAULT_REGION + " to Fqn.ROOT");
+ fqn = Fqn.ROOT;
+ setDefault = true;
+ }
+ Region r = getRegion(fqn, true);
+ r.setEvictionPolicy(erc.getEvictionPolicyConfig());
+ }
+ }
+
+ /**
+ * Starts the eviction processing thread.
+ */
+ public void startEvictionThread()
+ {
+ evictionTimerTask.init(evictionConfig.getWakeupIntervalSeconds());
+ }
+
+ /**
+ * Stops the eviction processing thread
+ */
+ public void stopEvictionThread()
+ {
+ evictionTimerTask.stop();
+ }
+
+
+ /**
+ * Returns a string containing debug information on every region.
+ */
+ public String dumpRegions()
+ {
+ StringBuilder sb = new StringBuilder();
+ for (Region r : regionsRegistry.values())
+ {
+ sb.append("\tRegion " + r);
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns a string containing debug information on every region.
+ */
+ public String toString()
+ {
+ return "RegionManager " + dumpRegions();
+ }
+
+ /**
+ * Returns the cache for this region manager
+ */
+ public CacheImpl getCache()
+ {
+ return this.cache;
+ }
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/RegionNotEmptyException.java (from rev 4250, core/trunk/src-old/org/jboss/cache/RegionNotEmptyException.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RegionNotEmptyException.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/RegionNotEmptyException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,39 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.cache;
+
+/**
+ * Thrown when an attempt is made to {@link RegionManager#activate(Fqn)} activate a subtree}
+ * root in Fqn that already has an existing node in the cache.
+ *
+ * @author <a href="mailto://brian.stansberry@jboss.com">Brian Stansberry</a>
+ */
+public class RegionNotEmptyException extends CacheException
+{
+
+ /**
+ * The serialVersionUID
+ */
+ private static final long serialVersionUID = 1L;
+
+ public RegionNotEmptyException()
+ {
+ super();
+ }
+
+ public RegionNotEmptyException(String msg)
+ {
+ super(msg);
+ }
+
+ public RegionNotEmptyException(String msg, Throwable cause)
+ {
+ super(msg, cause);
+ }
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/ReplicationException.java (from rev 4250, core/trunk/src-old/org/jboss/cache/ReplicationException.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/ReplicationException.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/ReplicationException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,44 @@
+// $Id$
+
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.cache;
+
+/**
+ * Thrown when a replication problem occurred
+ */
+public class ReplicationException extends CacheException
+{
+
+ private static final long serialVersionUID = 33172388691879866L;
+
+ public ReplicationException()
+ {
+ super();
+ }
+
+ public ReplicationException(Throwable cause)
+ {
+ super(cause);
+ }
+
+ public ReplicationException(String msg)
+ {
+ super(msg);
+ }
+
+ public ReplicationException(String msg, Throwable cause)
+ {
+ super(msg, cause);
+ }
+
+ public String toString()
+ {
+ return super.toString();
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/ReplicationQueue.java (from rev 4250, core/trunk/src-old/org/jboss/cache/ReplicationQueue.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/ReplicationQueue.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/ReplicationQueue.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,197 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.marshall.MethodCall;
+import org.jboss.cache.marshall.MethodDeclarations;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+
+/**
+ * Periodically (or when certain size is exceeded) takes elements and replicates them.
+ *
+ * @author <a href="mailto:bela@jboss.org">Bela Ban</a> May 24, 2003
+ * @version $Revision$
+ */
+public class ReplicationQueue
+{
+
+ private static Log log = LogFactory.getLog(ReplicationQueue.class);
+
+ private CacheImpl cache = null;
+
+ /**
+ * We flush every 5 seconds. Inactive if -1 or 0
+ */
+ private long interval = 5000;
+
+ /**
+ * Max elements before we flush
+ */
+ private long max_elements = 500;
+
+ /**
+ * Holds the replication jobs: LinkedList<MethodCall>
+ */
+ private final List<MethodCall> elements = new LinkedList<MethodCall>();
+
+ /**
+ * For periodical replication
+ */
+ private Timer timer = null;
+
+ /**
+ * The timer task, only calls flush() when executed by Timer
+ */
+ private MyTask task = null;
+
+ public ReplicationQueue()
+ {
+ }
+
+ /**
+ * Constructs a new ReplicationQueue.
+ */
+ public ReplicationQueue(CacheImpl cache, long interval, long max_elements)
+ {
+ this.cache = cache;
+ this.interval = interval;
+ this.max_elements = max_elements;
+ }
+
+ /**
+ * Returns the flush interval in milliseconds.
+ */
+ public long getInterval()
+ {
+ return interval;
+ }
+
+ /**
+ * Sets the flush interval in milliseconds.
+ */
+ public void setInterval(long interval)
+ {
+ this.interval = interval;
+ stop();
+ start();
+ }
+
+ /**
+ * Returns the maximum number of elements to hold.
+ * If the maximum number is reached, flushes in the calling thread.
+ */
+ public long getMax_elements()
+ {
+ return max_elements;
+ }
+
+ /**
+ * Sets the maximum number of elements to hold.
+ */
+ public void setMax_elements(long max_elements)
+ {
+ this.max_elements = max_elements;
+ }
+
+ /**
+ * Starts the asynchronous flush queue.
+ */
+ public synchronized void start()
+ {
+ if (interval > 0)
+ {
+ if (task == null)
+ task = new MyTask();
+ if (timer == null)
+ {
+ timer = new Timer(true);
+ timer.schedule(task,
+ 500, // delay before initial flush
+ interval); // interval between flushes
+ }
+ }
+ }
+
+ /**
+ * Stops the asynchronous flush queue.
+ */
+ public synchronized void stop()
+ {
+ if (task != null)
+ {
+ task.cancel();
+ task = null;
+ }
+ if (timer != null)
+ {
+ timer.cancel();
+ timer = null;
+ }
+ }
+
+
+ /**
+ * Adds a new method call.
+ */
+ public void add(MethodCall job)
+ {
+ if (job == null)
+ throw new NullPointerException("job is null");
+ synchronized (elements)
+ {
+ elements.add(job);
+ if (elements.size() >= max_elements)
+ flush();
+ }
+ }
+
+ /**
+ * Flushes existing method calls.
+ */
+ public void flush()
+ {
+ List<MethodCall> l;
+ synchronized (elements)
+ {
+ if (log.isTraceEnabled())
+ log.trace("flush(): flushing repl queue (num elements=" + elements.size() + ")");
+ l = new ArrayList<MethodCall>(elements);
+ elements.clear();
+ }
+
+ if (l.size() > 0)
+ {
+ try
+ {
+ // send to all live nodes in the cluster
+ cache.getRPCManager().callRemoteMethods(null, MethodDeclarations.replicateAllMethod, new Object[]{l}, false, true, 5000);
+ }
+ catch (Throwable t)
+ {
+ log.error("failed replicating " + l.size() + " elements in replication queue", t);
+ }
+ }
+ }
+
+ class MyTask extends TimerTask
+ {
+ public void run()
+ {
+ flush();
+ }
+ }
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/SuspectException.java (from rev 4250, core/trunk/src-old/org/jboss/cache/SuspectException.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/SuspectException.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/SuspectException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,28 @@
+package org.jboss.cache;
+
+/**
+ * Thrown when a member is suspected during remote method invocation
+ * @author Bela Ban
+ * @version $Id$
+ */
+public class SuspectException extends CacheException
+{
+
+ private static final long serialVersionUID = -2965599037371850141L;
+
+ public SuspectException() {
+ super();
+ }
+
+ public SuspectException(String msg) {
+ super(msg);
+ }
+
+ public SuspectException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ public String toString() {
+ return super.toString();
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/TreeCacheViewMBean.java (from rev 4250, core/trunk/src-old/org/jboss/cache/TreeCacheViewMBean.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/TreeCacheViewMBean.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/TreeCacheViewMBean.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,34 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.jmx.CacheJmxWrapperMBean;
+
+
+/**
+ * MBean interface.
+ *
+ * @author <a href="mailto:bela@jboss.org">Bela Ban</a> March 27 2003
+ */
+public interface TreeCacheViewMBean
+{
+ void create() throws Exception;
+
+ void start() throws Exception;
+
+ void stop() ;
+
+ void destroy() ;
+
+ Cache getCache();
+
+ void setCache(Cache cache);
+
+ CacheJmxWrapperMBean getCacheService();
+
+ void setCacheService(CacheJmxWrapperMBean cache_service);
+}
Copied: core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java (from rev 4250, core/trunk/src-old/org/jboss/cache/UnversionedNode.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,745 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.lock.IdentityLock;
+import org.jboss.cache.marshall.MethodCall;
+import org.jboss.cache.marshall.MethodCallFactory;
+import org.jboss.cache.marshall.MethodDeclarations;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.transaction.GlobalTransaction;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Basic data node class. Throws {@link UnsupportedOperationException} for version-specific methods like {@link #getVersion()} and
+ * {@link #setVersion(org.jboss.cache.optimistic.DataVersion)}, defined in {@link org.jboss.cache.NodeSPI}.
+ *
+ * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
+ * @since 2.0.0
+ */
+public class UnversionedNode<K, V> extends AbstractNode<K, V> implements NodeSPI<K, V>
+{
+
+ /**
+ * Default output indent for printing.
+ */
+ private static final int INDENT = 4;
+
+ /**
+ * Debug log.
+ */
+ private static Log log = LogFactory.getLog(UnversionedNode.class);
+
+ /**
+ * True if all children have been loaded. This is set when CacheImpl.getChildrenNames() is called.
+ */
+ private boolean childrenLoaded = false;
+
+ /**
+ * True if data has been loaded from the cache loader.
+ */
+ private boolean dataLoaded = true;
+
+ /**
+ * Lock manager that manages locks to be acquired when accessing the node inside a transaction. Lazy set just in case
+ * locking is not needed.
+ */
+ private transient IdentityLock lock_ = null;
+
+ /**
+ * A reference of the CacheImpl instance.
+ */
+ private transient CacheImpl<K, V> cache;
+
+ /**
+ * Map of general data keys to values.
+ */
+ private final Map<K, V> data = new HashMap<K, V>();
+
+ /**
+ * Constructs a new node with an FQN of Root.
+ */
+ public UnversionedNode()
+ {
+ this.fqn = Fqn.ROOT;
+ }
+
+ /**
+ * Constructs a new node with a name, etc.
+ *
+ * @param mapSafe <code>true</code> if param <code>data</code> can safely be directly assigned to this object's
+ * {@link #data} field; <code>false</code> if param <code>data</code>'s contents should be copied into
+ * this object's {@link #data} field.
+ */
+ protected UnversionedNode(Object child_name, Fqn fqn, Map<K, V> data, boolean mapSafe, CacheSPI<K, V> cache)
+ {
+ init(child_name, fqn, cache);
+ if (data != null)
+ {
+ this.data.putAll(data);// ? is this safe
+ }
+ }
+
+ /**
+ * Initializes with a name and FQN and cache.
+ */
+ private void init(Object child_name, Fqn fqn, CacheSPI<K, V> cache)
+ {
+ if (cache == null)
+ {
+ throw new IllegalArgumentException("no cache init for " + fqn);
+ }
+ this.cache = (CacheImpl) cache;
+ this.fqn = fqn;
+ if (!fqn.isRoot() && !child_name.equals(fqn.getLastElement()))
+ {
+ throw new IllegalArgumentException("Child " + child_name + " must be last part of " + fqn);
+ }
+ }
+
+ /**
+ * Returns a parent by checking the TreeMap by name.
+ */
+ public NodeSPI<K, V> getParent()
+ {
+ if (fqn.isRoot())
+ {
+ return null;
+ }
+ return cache.peek(fqn.getParent(), true);
+ }
+
+ private synchronized void initLock()
+ {
+ if (lock_ == null)
+ {
+ lock_ = new IdentityLock(cache.getConfiguration().getIsolationLevel(), this);
+ }
+ }
+
+ private synchronized Map<Object, Node<K, V>> children()
+ {
+ if (children == null)
+ {
+ if (getFqn().isRoot())
+ {
+ children = new ConcurrentHashMap<Object, Node<K, V>>(64, .5f, 16);
+ }
+ else
+ {
+ // Less segments to save memory
+ children = new ConcurrentHashMap<Object, Node<K, V>>(4, .75f, 4);
+ }
+ }
+ return children;
+ }
+
+ public CacheSPI<K, V> getCache()
+ {
+ return cache;
+ }
+
+ public boolean isChildrenLoaded()
+ {
+ return childrenLoaded;
+ }
+
+ public void setChildrenLoaded(boolean flag)
+ {
+ childrenLoaded = flag;
+ }
+
+ public V get(K key)
+ {
+ return cache.get(getFqn(), key);
+ }
+
+ public V getDirect(K key)
+ {
+ return data == null ? null : data.get(key);
+ }
+
+
+ private boolean isReadLocked()
+ {
+ return lock_ != null && lock_.isReadLocked();
+ }
+
+ private boolean isWriteLocked()
+ {
+ return lock_ != null && lock_.isWriteLocked();
+ }
+
+ public IdentityLock getLock()
+ {
+ initLock();
+ return lock_;
+ }
+
+ public Map<K, V> getData()
+ {
+ if (cache == null) return Collections.emptyMap();
+ return cache.getData(getFqn());
+
+/*
+ Map<K, V> dMap = new HashMap<K, V>();
+ for (K k : cache.getKeys(getFqn()))
+ {
+ dMap.put(k, cache.get(fqn, k));
+ }
+ return Collections.unmodifiableMap(dMap);
+*/
+ }
+
+ public Map<K, V> getDataDirect()
+ {
+ if (data == null) return Collections.emptyMap();
+ return Collections.unmodifiableMap(data);
+ }
+
+ public V put(K key, V value)
+ {
+ return cache.put(getFqn(), key, value);
+ }
+
+ public V putDirect(K key, V value)
+ {
+ return data.put(key, value);
+ }
+
+ public NodeSPI getOrCreateChild(Object child_name, GlobalTransaction gtx)
+ {
+ return getOrCreateChild(child_name, gtx, true);
+ }
+
+ private NodeSPI getOrCreateChild(Object child_name, GlobalTransaction gtx, boolean createIfNotExists)
+ {
+
+ NodeSPI child;
+ if (child_name == null)
+ {
+ throw new IllegalArgumentException("null child name");
+ }
+
+ child = (NodeSPI) children().get(child_name);
+ InvocationContext ctx = cache.getInvocationContext();
+ if (createIfNotExists && child == null)
+ {
+ // construct the new child outside the synchronized block to avoid
+ // spending any more time than necessary in the synchronized section
+ Fqn child_fqn = new Fqn(this.fqn, child_name);
+ NodeSPI newChild = (NodeSPI) cache.getConfiguration().getRuntimeConfig().getNodeFactory().createNode(child_name, this, null);
+ if (newChild == null)
+ {
+ throw new IllegalStateException();
+ }
+ synchronized (this)
+ {
+ // check again to see if the child exists
+ // after acquiring exclusive lock
+ child = (NodeSPI) children().get(child_name);
+ if (child == null)
+ {
+ cache.getNotifier().notifyNodeCreated(child_fqn, true, ctx);
+ child = newChild;
+ children.put(child_name, child);
+ if (gtx != null)
+ {
+ MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, gtx,
+ child_fqn, false);
+ cache.addUndoOperation(gtx, undo_op);
+ // add the node name to the list maintained for the current tx
+ // (needed for abort/rollback of transaction)
+ // cache.addNode(gtx, child.getFqn());
+ }
+ }
+ }
+
+ // notify if we actually created a new child
+ if (newChild == child)
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("created child: fqn=" + child_fqn);
+ }
+ cache.getNotifier().notifyNodeCreated(child_fqn, false, ctx);
+ }
+ }
+ return child;
+
+ }
+
+ public V remove(K key)
+ {
+ return cache.remove(getFqn(), key);
+ }
+
+ public V removeDirect(K key)
+ {
+ if (data == null) return null;
+ return data.remove(key);
+ }
+
+ public void printDetails(StringBuffer sb, int indent)
+ {
+ printDetailsInMap(sb, indent);
+ }
+
+ /**
+ * Returns a debug string.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append(getClass().getSimpleName());
+ if (deleted)
+ {
+ sb.append(" (deleted) [ ").append(fqn);
+ }
+ else
+ {
+ sb.append("[ ").append(fqn);
+ }
+ if (data != null)
+ {
+ synchronized (data)
+ {
+ sb.append(" data=").append(data.keySet());
+ }
+ }
+ if (children != null && !children.isEmpty())
+ {
+ sb.append(" child=").append(getChildrenNamesDirect());
+ }
+ if (lock_ != null)
+ {
+ if (isReadLocked())
+ {
+ sb.append(" RL");
+ }
+ if (isWriteLocked())
+ {
+ sb.append(" WL");
+ }
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ public Node<K, V> addChild(Fqn f)
+ {
+ Fqn nf = new Fqn(getFqn(), f);
+ cache.put(nf, null);
+ return getChild(f);
+ }
+
+ public void addChildDirect(NodeSPI<K, V> child)
+ {
+ if (child.getFqn().getParent().equals(getFqn()))
+ {
+ synchronized (this)
+ {
+ children().put(child.getFqn().getLastElement(), child);
+ }
+ }
+ else
+ throw new CacheException("Attempting to add a child [" + child.getFqn() + "] to [" + getFqn() + "]. Can only add direct children.");
+ }
+
+ public NodeSPI<K, V> addChildDirect(Fqn f)
+ {
+ if (f.size() == 1)
+ {
+ GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
+ return getOrCreateChild(f.getLastElement(), gtx);
+ }
+ else
+ {
+ throw new UnsupportedOperationException("Cannot directly create children which aren't directly under the current node.");
+ }
+
+ }
+
+ public void clearData()
+ {
+ cache.removeData(getFqn());
+ }
+
+ public void clearDataDirect()
+ {
+ if (data != null) data.clear();
+ }
+
+ public Node<K, V> getChild(Fqn fqn)
+ {
+ return cache.get(new Fqn(getFqn(), fqn));
+ }
+
+ public NodeSPI<K, V> getChildDirect(Fqn fqn)
+ {
+ if (fqn.size() == 1)
+ {
+ return getChildDirect(fqn.getLastElement());
+ }
+ else
+ {
+ NodeSPI currentNode = this;
+ for (int i = 0; i < fqn.size(); i++)
+ {
+ Object nextChildName = fqn.get(i);
+ currentNode = currentNode.getChildDirect(nextChildName);
+ if (currentNode == null) return null;
+ }
+ return currentNode;
+ }
+ }
+
+ public Set<Object> getChildrenNames()
+ {
+ return cache.getChildrenNames(getFqn());
+ }
+
+ public Set<Object> getChildrenNamesDirect()
+ {
+ return children == null ? Collections.emptySet() : new HashSet(children.keySet());
+ //return childrenNames();
+ }
+
+ public Set<K> getKeys()
+ {
+ Set<K> keys = cache.getKeys(getFqn());
+ return (Set<K>) (keys == null ? Collections.emptySet() : Collections.unmodifiableSet(keys));
+ }
+
+ public Set<K> getKeysDirect()
+ {
+ if (data == null)
+ {
+ return Collections.emptySet();
+ }
+ return Collections.unmodifiableSet(new HashSet<K>(data.keySet()));
+ }
+
+ public boolean hasChild(Fqn f)
+ {
+ return getChild(f) != null;
+ }
+
+ public boolean hasChild(Object o)
+ {
+ return getChild(o) != null;
+ }
+
+ public V putIfAbsent(K k, V v)
+ {
+ // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
+ synchronized (this)
+ {
+ if (!getKeys().contains(k))
+ return put(k, v);
+ else
+ return get(k);
+ }
+ }
+
+ public V replace(K key, V value)
+ {
+ // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
+ synchronized (this)
+ {
+ if (getKeys().contains(key))
+ {
+ return put(key, value);
+ }
+ else
+ return null;
+ }
+ }
+
+ public boolean replace(K key, V oldValue, V newValue)
+ {
+ // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
+ synchronized (this)
+ {
+ if (oldValue.equals(get(key)))
+ {
+ put(key, newValue);
+ return true;
+ }
+ else
+ return false;
+ }
+ }
+
+ public boolean removeChild(Fqn fqn)
+ {
+ return cache.removeNode(new Fqn(getFqn(), fqn));
+ }
+
+ public int dataSize()
+ {
+ return cache.getKeys(getFqn()).size();
+ }
+
+ public boolean removeChild(Object childName)
+ {
+ return removeChild(new Fqn(getFqn(), childName));
+ }
+
+ public boolean removeChildDirect(Object childName)
+ {
+ return children != null && children.remove(childName) != null;
+ }
+
+ public boolean removeChildDirect(Fqn f)
+ {
+ if (f.size() == 1)
+ {
+ return removeChildDirect(f.getLastElement());
+ }
+ else
+ {
+ NodeSPI child = getChildDirect(f);
+ return child != null && child.getParent().removeChildDirect(f.getLastElement());
+ }
+ }
+
+ public Map<Object, Node<K, V>> getChildrenMapDirect()
+ {
+ return children;
+ }
+
+ public void setChildrenMapDirect(Map<Object, Node<K, V>> children)
+ {
+ this.children().clear();
+ this.children.putAll(children);
+ }
+
+ public void putAll(Map data)
+ {
+ cache.put(fqn, data);
+ }
+
+ public void replaceAll(Map data)
+ {
+ cache.put(fqn, data, true);
+ }
+
+ public void putAllDirect(Map<K, V> data)
+ {
+ if (data == null) return;
+ this.data.putAll(data);
+ }
+
+ public void removeChildrenDirect()
+ {
+ if (children != null)
+ {
+ children.clear();
+ }
+ children = null;
+ }
+
+ public void print(StringBuffer sb, int indent)
+ {
+ printIndent(sb, indent);
+ sb.append(Fqn.SEPARATOR).append(getName()).append(" ").append(getDataDirect().size());
+ if (children != null)
+ {
+ for (Node node : children.values())
+ {
+ sb.append("\n");
+ ((NodeSPI) node).print(sb, indent + INDENT);
+ }
+ }
+ }
+
+ // versioning
+
+ public void setVersion(DataVersion version)
+ {
+ throw new UnsupportedOperationException("Versioning not supported");
+ }
+
+ public DataVersion getVersion()
+ {
+ throw new UnsupportedOperationException("Versioning not supported");
+ }
+
+ private void printIndent(StringBuffer sb, int indent)
+ {
+ if (sb != null)
+ {
+ for (int i = 0; i < indent; i++)
+ {
+ sb.append(" ");
+ }
+ }
+ }
+
+ public void addChild(Object child_name, Node<K, V> n)
+ {
+ if (child_name != null)
+ {
+ children().put(child_name, n);
+ }
+ }
+
+ /**
+ * Returns the name of this node.
+ */
+ private Object getName()
+ {
+ return fqn.getLastElement();
+ }
+
+ /**
+ * Returns the name of this node.
+ */
+ public Fqn getFqn()
+ {
+ return fqn;
+ }
+
+ public void setFqn(Fqn fqn)
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace(getFqn() + " set FQN " + fqn);
+ }
+ this.fqn = fqn;
+
+ if (children == null)
+ {
+ return;
+ }
+
+ // process children
+ for (Map.Entry<Object, ? extends Node> me : children.entrySet())
+ {
+ NodeSPI n = (NodeSPI) me.getValue();
+ Fqn cfqn = new Fqn(fqn, me.getKey());
+ n.setFqn(cfqn);
+ }
+ }
+
+ public Node<K, V> getChild(Object childName)
+ {
+ return cache.get(new Fqn(getFqn(), childName));
+ }
+
+ public NodeSPI<K, V> getChildDirect(Object childName)
+ {
+ if (childName == null) return null;
+ return (NodeSPI<K, V>) (children == null ? null : children.get(childName));
+ }
+
+ public Set<Node<K, V>> getChildren()
+ {
+ if (cache == null) return Collections.emptySet();
+ Set<Node<K, V>> children = new HashSet<Node<K, V>>();
+ for (Object c : cache.getChildrenNames(getFqn()))
+ {
+ Node n = cache.get(new Fqn(getFqn(), c));
+ if (n != null) children.add(n);
+ }
+ return Collections.unmodifiableSet(children);
+ }
+
+ public Set<NodeSPI<K, V>> getChildrenDirect()
+ {
+ // strip out deleted child nodes...
+ if (children == null || children.size() == 0) return Collections.emptySet();
+
+ Set<NodeSPI<K, V>> exclDeleted = new HashSet<NodeSPI<K, V>>();
+ for (Node n : children.values())
+ {
+ NodeSPI spi = (NodeSPI) n;
+ if (!spi.isDeleted()) exclDeleted.add(spi);
+ }
+ return Collections.unmodifiableSet(exclDeleted);
+ }
+
+ public boolean hasChildrenDirect()
+ {
+ return children != null && children.size() != 0;
+ }
+
+ public Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedForRemoval)
+ {
+ if (includeMarkedForRemoval)
+ {
+ if (children != null && !children.isEmpty())
+ {
+ return Collections.unmodifiableSet(new HashSet(children.values()));
+ }
+ else
+ {
+ return Collections.emptySet();
+ }
+ }
+ else
+ {
+ return getChildrenDirect();
+ }
+ }
+
+ /**
+ * Adds details of the node into a map as strings.
+ */
+ private void printDetailsInMap(StringBuffer sb, int indent)
+ {
+ printIndent(sb, indent);
+ indent += 2;// increse it
+ if (!(getFqn()).isRoot())
+ {
+ sb.append(Fqn.SEPARATOR);
+ }
+ sb.append(getName());
+ sb.append(" ");
+ sb.append(data);
+ if (children != null)
+ {
+ for (Node n : children.values())
+ {
+ sb.append("\n");
+ ((NodeSPI) n).printDetails(sb, indent);
+ }
+ }
+ }
+
+ /**
+ * Returns true if the data was loaded from the cache loader.
+ */
+ public boolean isDataLoaded()
+ {
+ return dataLoaded;
+ }
+
+ /**
+ * Sets if the data was loaded from the cache loader.
+ */
+ public void setDataLoaded(boolean dataLoaded)
+ {
+ this.dataLoaded = dataLoaded;
+ }
+
+ public boolean isValid()
+ {
+ // TODO; implement this property, to detect if it has been evicted, removed by another thread, etc. Method added for now as a dummy so it exists in the API
+ return true;
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/Version.java (from rev 4250, core/trunk/src-old/org/jboss/cache/Version.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Version.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/Version.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,172 @@
+package org.jboss.cache;
+
+import java.util.StringTokenizer;
+
+/**
+ * Contains version information about this release of JBoss Cache.
+ *
+ * @author Bela Ban
+ * @version $Id$
+ */
+public class Version
+{
+ public static final String version = "2.0.0.GA";
+ public static final String codename = "Habanero";
+ public static byte[] version_id = {'0', '2', '0', '0'};
+ public static final String cvs = "$Id$";
+
+ private static final int MAJOR_SHIFT = 11;
+ private static final int MINOR_SHIFT = 6;
+ private static final int MAJOR_MASK = 0x00f800;
+ private static final int MINOR_MASK = 0x0007c0;
+ private static final int PATCH_MASK = 0x00003f;
+
+ private static final short SHORT_1_2_3 = encodeVersion(1, 2, 3);
+ private static final short SHORT_1_2_4_SP2 = encodeVersion(1, 2, 4);
+
+ /**
+ * Prints version information.
+ */
+ public static void main(String[] args)
+ {
+ System.out.println("\nVersion: \t" + version);
+ System.out.println("Codename: \t" + codename);
+ System.out.println("CVS: \t" + cvs);
+ System.out.println("History: \t(see http://jira.jboss.com/jira/browse/JBCACHE for details)\n");
+ }
+
+ /**
+ * Returns version information as a string.
+ */
+ public static String printVersion()
+ {
+ return "JBossCache '" + codename + "' " + version + "[ " + cvs + "]";
+ }
+
+ public static String printVersionId(byte[] v, int len)
+ {
+ StringBuffer sb = new StringBuffer();
+ if (v != null)
+ {
+ if (len <= 0)
+ len = v.length;
+ for (int i = 0; i < len; i++)
+ sb.append((char) v[i]);
+ }
+ return sb.toString();
+ }
+
+ public static String printVersionId(byte[] v)
+ {
+ StringBuffer sb = new StringBuffer();
+ if (v != null)
+ {
+ for (byte aV : v) sb.append((char) aV);
+ }
+ return sb.toString();
+ }
+
+
+ public static boolean compareTo(byte[] v)
+ {
+ if (v == null)
+ return false;
+ if (v.length < version_id.length)
+ return false;
+ for (int i = 0; i < version_id.length; i++)
+ {
+ if (version_id[i] != v[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static int getLength()
+ {
+ return version_id.length;
+ }
+
+ public static short getVersionShort()
+ {
+ return getVersionShort(version);
+ }
+
+ public static short getVersionShort(String versionString)
+ {
+ if (versionString == null)
+ throw new IllegalArgumentException("versionString is null");
+
+ // Special cases for version prior to 1.2.4.SP2
+ if ("1.2.4".equals(versionString))
+ return 124;
+ else if ("1.2.4.SP1".equals(versionString))
+ return 1241;
+
+ StringTokenizer tokenizer = new StringTokenizer(versionString, ".");
+
+ int major = 0;
+ int minor = 0;
+ int patch = 0;
+
+ if (tokenizer.hasMoreTokens())
+ major = Integer.parseInt(tokenizer.nextToken());
+ if (tokenizer.hasMoreTokens())
+ minor = Integer.parseInt(tokenizer.nextToken());
+ if (tokenizer.hasMoreTokens())
+ patch = Integer.parseInt(tokenizer.nextToken());
+
+ return encodeVersion(major, minor, patch);
+ }
+
+ public static String getVersionString(short versionShort)
+ {
+ if (versionShort == SHORT_1_2_4_SP2)
+ return "1.2.4.SP2";
+
+ switch (versionShort)
+ {
+ case 124:
+ return "1.2.4";
+ case 1241:
+ return "1.2.4.SP1";
+ default:
+ return decodeVersion(versionShort);
+ }
+ }
+
+ public static short encodeVersion(int major, int minor, int patch)
+ {
+ short version = (short) ((major << MAJOR_SHIFT)
+ + (minor << MINOR_SHIFT)
+ + patch);
+ return version;
+ }
+
+ public static String decodeVersion(short version)
+ {
+ int major = (version & MAJOR_MASK) >> MAJOR_SHIFT;
+ int minor = (version & MINOR_MASK) >> MINOR_SHIFT;
+ int patch = (version & PATCH_MASK);
+ String versionString = major + "." + minor + "." + patch;
+ return versionString;
+ }
+
+ public static boolean isBefore124(short version)
+ {
+ return (version > 1241 && version <= SHORT_1_2_3);
+ }
+
+ /**
+ * Retroweaver version info.
+ */
+ public static class Retro
+ {
+ public static void main(String[] args)
+ {
+ System.out.println("\nVersion: \t" + version + " (Retroweaved for JDK 1.4.x compatibility)");
+ System.out.println("Codename: \t" + codename);
+ System.out.println("CVS: \t" + cvs);
+ System.out.println("History: \t(see http://jira.jboss.com/jira/browse/JBCACHE for details)\n");
+ }
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/VersionedNode.java (from rev 4250, core/trunk/src-old/org/jboss/cache/VersionedNode.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/VersionedNode.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/VersionedNode.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,73 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.optimistic.DefaultDataVersion;
+
+import java.util.Map;
+
+/**
+ * VersionedNode extends the {@link org.jboss.cache.UnversionedNode} by adding a {@link org.jboss.cache.optimistic.DataVersion} property.
+ * <p/>
+ * Unlike {@link org.jboss.cache.UnversionedNode}, this node supports {@link #getVersion} and {@link #setVersion(org.jboss.cache.optimistic.DataVersion)}
+ * defined in {@link org.jboss.cache.NodeSPI}
+ * <p/>
+ * Typically used when the cache mode configured is {@link org.jboss.cache.config.Configuration.NodeLockingScheme#OPTIMISTIC}
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
+ * @since 2.0.0
+ */
+public class VersionedNode<K, V> extends UnversionedNode<K, V>
+{
+ private DataVersion version;
+ /**
+ * Although this object has a reference to the CacheImpl, the optimistic
+ * node is actually disconnected from the CacheImpl itself.
+ * The parent could be looked up from the TransactionWorkspace.
+ */
+ private NodeSPI<K, V> parent;
+
+ protected VersionedNode(Fqn fqn, NodeSPI<K, V> parent, Map<K, V> data, CacheSPI<K, V> cache)
+ {
+ super(fqn.getLastElement(), fqn, data, false, cache);
+ if (parent == null && !fqn.isRoot()) throw new NullPointerException("parent");
+ this.parent = parent;
+ this.version = DefaultDataVersion.ZERO;
+ }
+
+ /**
+ * Returns the version id of this node.
+ *
+ * @return the version
+ */
+ @Override
+ public DataVersion getVersion()
+ {
+ return version;
+ }
+
+ /**
+ * Returns the parent.
+ */
+ @Override
+ public NodeSPI<K, V> getParent()
+ {
+ return parent;
+ }
+
+ /**
+ * Sets the version id of this node.
+ *
+ * @param version
+ */
+ @Override
+ public void setVersion(DataVersion version)
+ {
+ this.version = version;
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/buddyreplication (from rev 4250, core/trunk/src-old/org/jboss/cache/buddyreplication)
Copied: core/trunk/src/main/java/org/jboss/cache/config (from rev 4250, core/trunk/src-old/org/jboss/cache/config)
Copied: core/trunk/src/main/java/org/jboss/cache/demo (from rev 4250, core/trunk/src-old/org/jboss/cache/demo)
Copied: core/trunk/src/main/java/org/jboss/cache/eviction (from rev 4250, core/trunk/src-old/org/jboss/cache/eviction)
Copied: core/trunk/src/main/java/org/jboss/cache/factories (from rev 4250, core/trunk/src-old/org/jboss/cache/factories)
Copied: core/trunk/src/main/java/org/jboss/cache/interceptors (from rev 4250, core/trunk/src-old/org/jboss/cache/interceptors)
Copied: core/trunk/src/main/java/org/jboss/cache/jmx (from rev 4250, core/trunk/src-old/org/jboss/cache/jmx)
Copied: core/trunk/src/main/java/org/jboss/cache/loader (from rev 4250, core/trunk/src-old/org/jboss/cache/loader)
Copied: core/trunk/src/main/java/org/jboss/cache/lock (from rev 4250, core/trunk/src-old/org/jboss/cache/lock)
Copied: core/trunk/src/main/java/org/jboss/cache/marshall (from rev 4250, core/trunk/src-old/org/jboss/cache/marshall)
Copied: core/trunk/src/main/java/org/jboss/cache/notifications (from rev 4250, core/trunk/src-old/org/jboss/cache/notifications)
Copied: core/trunk/src/main/java/org/jboss/cache/optimistic (from rev 4250, core/trunk/src-old/org/jboss/cache/optimistic)
Copied: core/trunk/src/main/java/org/jboss/cache/statetransfer (from rev 4250, core/trunk/src-old/org/jboss/cache/statetransfer)
Copied: core/trunk/src/main/java/org/jboss/cache/transaction (from rev 4250, core/trunk/src-old/org/jboss/cache/transaction)
Copied: core/trunk/src/main/java/org/jboss/cache/util (from rev 4250, core/trunk/src-old/org/jboss/cache/util)
Copied: core/trunk/src/main/java/org/jboss/cache/xml (from rev 4250, core/trunk/src-old/org/jboss/cache/xml)
Deleted: core/trunk/src-old/org/jboss/cache/AbstractNode.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/AbstractNode.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/AbstractNode.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,58 +0,0 @@
-/**
- *
- */
-package org.jboss.cache;
-
-import java.util.Map;
-
-/**
- * Base class for {@link UnversionedNode}.
- *
- * @author manik
- */
-public abstract class AbstractNode<K, V> implements Node<K, V>
-{
- protected boolean deleted;
- protected Map<Object, Node<K, V>> children;
- protected Fqn fqn;
-
- public boolean isDeleted()
- {
- return deleted;
- }
-
- public void markAsDeleted(boolean marker)
- {
- markAsDeleted(marker, false);
- }
-
- public void markAsDeleted(boolean marker, boolean recursive)
- {
- deleted = marker;
- if (recursive && children != null)
- {
- synchronized (this)
- {
- for (Node child : children.values())
- {
- ((AbstractNode) child).markAsDeleted(marker, true);
- }
- }
- }
- }
-
- public boolean equals(Object another)
- {
- if (another instanceof AbstractNode)
- {
- AbstractNode anotherNode = (AbstractNode) another;
- return fqn == null && anotherNode.fqn == null || !(fqn == null || anotherNode.fqn == null) && fqn.equals(anotherNode.fqn);
- }
- return false;
- }
-
- public int hashCode()
- {
- return fqn.hashCode();
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/Cache.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/Cache.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/Cache.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,373 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.cache.config.Configuration;
-import org.jgroups.Address;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Interface for a Cache where data mappings are grouped and stored in a tree data
- * structure consisting of {@link Node}s.
- * <p/>
- * This is the central construct and basic client API of JBoss Cache and is used for
- * cache-wide operations.
- * <p/>
- * The cache is constructed using a {@link CacheFactory} and is started
- * using {@link #start}, if not already started by the CacheFactory.
- * <p/>
- * Once constructed, the Cache interface can be used to create or access {@link Node}s, which contain data. Once references
- * to {@link Node}s are obtained, data can be stored in them,
- * <p/>
- * As a convenience (and mainly to provide a familiar API to the older JBoss Cache 1.x.x releases) methods are provided that
- * operate directly on nodes.
- * <ul>
- * <li>{@link #put(Fqn,Object,Object)} </li>
- * <li>{@link #put(Fqn,java.util.Map)} </li>
- * <li>{@link #get(Fqn,Object)} </li>
- * <li>{@link #remove(Fqn,Object)} </li>
- * <li>{@link #removeNode(Fqn)} </li>
- * </ul>
- * <p/>
- * A simple example of usage:
- * <pre>
- * // creates with default settings and starts the cache
- * Cache cache = DefaultCacheFactory.getInstance().createCache();
- * Fqn personRecords = Fqn.fromString("/org/mycompany/personRecords");
- * <p/>
- * Node rootNode = cache.getRoot();
- * Node personRecordsNode = rootNode.addChild(personRecords);
- * <p/>
- * // now add some person records.
- * Fqn peterGriffin = Fqn.fromString("/peterGriffin");
- * Fqn stewieGriffin = Fqn.fromString("/stewieGriffin");
- * <p/>
- * // the addChild() API uses relative Fqns
- * Node peter = personRecordsNode.addChild(peterGriffin);
- * Node stewie = personRecordsNode.addChild(stewieGriffin);
- * <p/>
- * peter.put("name", "Peter Griffin");
- * peter.put("ageGroup", "MidLifeCrisis");
- * peter.put("homicidal", Boolean.FALSE);
- * <p/>
- * stewie.put("name", "Stewie Griffin");
- * stewie.put("ageGroup", "Infant");
- * stewie.put("homicidal", Boolean.TRUE);
- * <p/>
- * peter.getFqn().toString(); // will print out /org/mycompany/personRecords/peterGriffin
- * stewie.getFqn().toString(); // will print out /org/mycompany/personRecords/stewieGriffin
- * <p/>
- * peter.getFqn().getParent().equals(stewie.getFqn().getParent()); // will return true
- * <p/>
- * </pre>
- * <p/>
- * For more information, please read the JBoss Cache user guide and tutorial, available on <a href="http://labs.jboss.com/portal/jbosscache/docs/index.html" target="_BLANK">the JBoss Cache documentation site</a>,
- * and look through the examples <a href="http://labs.jboss.com/portal/jbosscache/download/index.html" target="_BLANK">shipped with the JBoss Cache distribution</a>.
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- * @see Node
- * @see CacheFactory
- * @since 2.0.0
- */
-@ThreadSafe
-public interface Cache<K, V>
-{
- /**
- * Retrieves the configuration of this cache.
- *
- * @return the configuration.
- */
- Configuration getConfiguration();
-
- /**
- * Returns the root node of this cache.
- *
- * @return the root node
- */
- Node<K, V> getRoot();
-
- /**
- * Adds a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object to the entire cache. The object passed in needs to be properly annotated with the
- * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
- *
- * @param listener listener to add
- */
- void addCacheListener(Object listener);
-
- /**
- * Adds a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object to a given region. The object passed in needs to be properly annotated with the
- * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
- *
- * @param region region to add listener to
- * @param listener listener to add
- */
- void addCacheListener(Fqn<?> region, Object listener);
-
- /**
- * Removes a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object from the cache. The object passed in needs to be properly annotated with the
- * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
- *
- * @param listener listener to remove
- */
- void removeCacheListener(Object listener);
-
- /**
- * Removes a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object from a given region. The object passed in needs to be properly annotated with the
- * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
- *
- * @param region region from which to remove listener
- * @param listener listener to remove
- */
- void removeCacheListener(Fqn<?> region, Object listener);
-
- /**
- * Retrieves an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to the cache.
- *
- * @return an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to the cache.
- */
- Set<Object> getCacheListeners();
-
- /**
- * Retrieves an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to a specific region.
- *
- * @return an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to a specific region.
- */
- Set<Object> getCacheListeners(Fqn<?> region);
-
- /**
- * Associates the specified value with the specified key for a {@link Node} in this cache.
- * If the {@link Node} previously contained a mapping for this key, the old value is replaced by the specified value.
- *
- * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
- * @param key key with which the specified value is to be associated.
- * @param value value to be associated with the specified key.
- * @return previous value associated with specified key, or <code>null</code> if there was no mapping for key.
- * A <code>null</code> return can also indicate that the Node previously associated <code>null</code> with the specified key, if the implementation supports null values.
- */
- V put(Fqn<?> fqn, K key, V value);
-
- /**
- * Under special operating behavior, associates the value with the specified key for a node identified by the Fqn passed in.
- * <ul>
- * <li> Only goes through if the node specified does not exist; no-op otherwise.</i>
- * <li> Force asynchronous mode for replication or invalidation to prevent any blocking.</li>
- * <li> 0ms lock timeout to prevent any blocking here either. If the lock is not acquired, this method is a no-op, and swallows the timeout exception.</li>
- * <li> Ongoing transactions are suspended before this call, so failures here will not affect any ongoing transactions.</li>
- * <li> Errors and exceptions are 'silent' - logged at a much lower level than normal, and this method does not throw exceptions</li>
- * </ul>
- * This method is for caching data that has an external representation in storage, where, concurrent modification and
- * transactions are not a consideration, and failure to put the data in the cache should be treated as a 'suboptimal outcome'
- * rather than a 'failing outcome'.
- * <p/>
- * An example of when this method is useful is when data is read from, for example, a legacy datastore, and is cached before
- * returning the data to the caller. Subsequent calls would prefer to get the data from the cache and if the data doesn't exist
- * in the cache, fetch again from the legacy datastore.
- * <p/>
- * See <a href="http://jira.jboss.com/jira/browse/JBCACHE-848">JBCACHE-848</a> for details around this feature.
- * <p/>
- *
- * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
- * @param key key with which the specified value is to be associated.
- * @param value value to be associated with the specified key.
- */
- void putForExternalRead(Fqn<?> fqn, K key, V value);
-
- /**
- * Copies all of the mappings from the specified map to a {@link Node}.
- *
- * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to copy the data to
- * @param data mappings to copy
- */
- void put(Fqn<?> fqn, Map<K, V> data);
-
- /**
- * Removes the mapping for this key from a Node.
- * Returns the value to which the Node previously associated the key, or
- * <code>null</code> if the Node contained no mapping for this key.
- *
- * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
- * @param key key whose mapping is to be removed from the Node
- * @return previous value associated with specified Node's key
- */
- V remove(Fqn<?> fqn, K key);
-
- /**
- * Removes a {@link Node} indicated by absolute {@link Fqn}.
- *
- * @param fqn {@link Node} to remove
- * @return true if the node was removed, false if the node was not found
- */
- boolean removeNode(Fqn<?> fqn);
-
- /**
- * Convenience method that allows for direct access to the data in a {@link Node}.
- *
- * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
- * @param key key under which value is to be retrieved.
- * @return returns data held under specified key in {@link Node} denoted by specified Fqn.
- */
- V get(Fqn<?> fqn, K key);
-
- /**
- * Eviction call that evicts the specified {@link Node} from memory.
- *
- * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be evicted.
- * @param recursive evicts children as well
- */
- void evict(Fqn<?> fqn, boolean recursive);
-
- /**
- * Retrieves a {@link Region} for a given {@link Fqn}. If the region does not exist,
- * and <li>createIfAbsent</li> is true, then one is created.
- * <p/>
- * If not, parent Fqns will be consulted in turn for registered regions, gradually working up to
- * Fqn.ROOT. If no regions are defined in any of the parents either, a null is returned.
- *
- * @param fqn Fqn that is contained in a region.
- * @param createIfAbsent If true, will create a new associated region if not found.
- * @return a MarshRegion. Null if none is found.
- * @throws UnsupportedOperationException if the region cannot be defined.
- * @see Region
- */
- Region getRegion(Fqn<?> fqn, boolean createIfAbsent);
-
- /**
- * Removes a region denoted by the Fqn passed in.
- *
- * @param fqn of the region to remove
- * @return true if a region did exist and was removed; false otherwise.
- */
- boolean removeRegion(Fqn<?> fqn);
-
- /**
- * Lifecycle method that initializes configuration state, the root node, etc.
- *
- * @throws CacheException if there are creation problems
- */
- void create() throws CacheException;
-
- /**
- * Lifecycle method that starts the cache loader,
- * starts cache replication, starts the region manager, etc., and (if configured) warms the cache using a
- * state transfer or cache loader preload.
- *
- * @throws CacheException if there are startup problems
- */
- void start() throws CacheException;
-
- /**
- * Lifecycle method that stops the cache, including replication,
- * clustering, cache loading, notifications, etc., and clears all cache in-memory state.
- * <p/>
- * State can be reconstituted by using either a cache loader or state transfer when the cache starts again.
- */
- void stop();
-
- /**
- * Lifecycle method that destroys the cache and removes any interceptors/configuration elements.
- * Cache can then be restarted (potentially after reconfiguring) using {@link #create()} and {@link #start()}.
- */
- void destroy();
-
- /**
- * Gets where the cache currently is its lifecycle transitions.
- *
- * @return the CacheStatus. Will not return <code>null</code>.
- */
- CacheStatus getCacheStatus();
-
- /**
- * @return the current invocation context for the current invocation and cache instance.
- * @see org.jboss.cache.InvocationContext
- */
- InvocationContext getInvocationContext();
-
- /**
- * Sets the passed in {@link org.jboss.cache.InvocationContext} as current.
- *
- * @param ctx invocation context to use
- */
- void setInvocationContext(InvocationContext ctx);
-
- /**
- * Returns the local address of this cache in a cluster, or <code>null</code>
- * if running in local mode.
- *
- * @return the local address of this cache in a cluster, or <code>null</code>
- * if running in local mode.
- */
- Address getLocalAddress();
-
- /**
- * Returns a list of members in the cluster, or <code>null</code>
- * if running in local mode.
- *
- * @return a {@link List} of members in the cluster, or <code>null</code>
- * if running in local mode.
- */
- List<Address> getMembers();
-
- /**
- * Moves a part of the cache to a different subtree.
- * <p/>
- * E.g.:
- * <p/>
- * assume a cache structure such as:
- * <p/>
- * <pre>
- * /a/b/c
- * /a/b/d
- * /a/b/e
- * <p/>
- * <p/>
- * Fqn f1 = Fqn.fromString("/a/b/c");
- * Fqn f2 = Fqn.fromString("/a/b/d");
- * <p/>
- * cache.move(f1, f2);
- * </pre>
- * <p/>
- * Will result in:
- * <pre>
- * <p/>
- * /a/b/d/c
- * /a/b/e
- * <p/>
- * </pre>
- * <p/>
- * and now
- * <p/>
- * <pre>
- * Fqn f3 = Fqn.fromString("/a/b/e");
- * Fqn f4 = Fqn.fromString("/a");
- * cache.move(f3, f4);
- * </pre>
- * <p/>
- * will result in:
- * <pre>
- * /a/b/d/c
- * /a/e
- * </pre>
- * No-op if the node to be moved is the root node.
- *
- * @param nodeToMove the Fqn of the node to move.
- * @param newParent new location under which to attach the node being moved.
- * @throws NodeNotExistsException may throw one of these if the target node does not exist or if a different thread has moved this node elsewhere already.
- */
- void move(Fqn<?> nodeToMove, Fqn<?> newParent) throws NodeNotExistsException;
-
- /**
- * Returns the version of the cache as a string.
- *
- * @return the version string of the cache.
- * @see Version#printVersion
- */
- String getVersion();
-}
Deleted: core/trunk/src-old/org/jboss/cache/CacheException.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/CacheException.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/CacheException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,45 +0,0 @@
-// $Id$
-
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-
-package org.jboss.cache;
-
-/**
- * Thrown when operations on {@link org.jboss.cache.Cache} or {@link org.jboss.cache.Node} fail unexpectedly.
- * <p/>
- * Specific subclasses such as {@link org.jboss.cache.lock.TimeoutException}, {@link org.jboss.cache.config.ConfigurationException} and {@link org.jboss.cache.lock.LockingException}
- * have more specific uses.
- *
- * @author <a href="mailto:bela@jboss.org">Bela Ban</a>
- * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
- */
-public class CacheException extends RuntimeException
-{
-
- private static final long serialVersionUID = -4386393072593859164L;
-
- public CacheException()
- {
- super();
- }
-
- public CacheException(Throwable cause)
- {
- super(cause);
- }
-
- public CacheException(String msg)
- {
- super(msg);
- }
-
- public CacheException(String msg, Throwable cause)
- {
- super(msg, cause);
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/CacheFactory.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/CacheFactory.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/CacheFactory.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,112 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.cache.config.Configuration;
-import org.jboss.cache.config.ConfigurationException;
-
-/**
- * This factory constructs a cache from a given or default configuration set.
- * <p/>
- * Typical usage would be:
- * <p/>
- * <pre>
- * CacheFactory factory = DefaultCacheFactory.getInstance();
- * Cache cache = factory.createCache("replSync-service.xml"); // expects this file to be in classpath
- * cache.stop();
- * </pre>
- * Factory methods provide options for creating a cache using
- * <ul>
- * <li>default configuration settings</li>
- * <li>an XML file containing the configuration</li>
- * <li>a constructed and populated {@link org.jboss.cache.config.Configuration} object</li>
- * </ul>
- * In addition, methods provide anadditional option to create and return a cache without starting it.
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- * @see org.jboss.cache.Cache
- * @see org.jboss.cache.DefaultCacheFactory
- * @see org.jboss.cache.pojo.PojoCacheFactory
- * @since 2.0.0
- */
-@ThreadSafe
-public interface CacheFactory<K, V>
-{
- /**
- * Creates and starts a {@link Cache} instance using default configuration settings. See {@link Configuration} for default values.
- *
- * @return a cache
- * @throws ConfigurationException if there are problems with the default configuration
- */
- Cache<K, V> createCache() throws ConfigurationException;
-
- /**
- * Creates and optionally starts a {@link Cache} instance using default configuration settings. See {@link Configuration} for default values.
- *
- * @param start if true, starts the cache
- * @return a cache
- * @throws ConfigurationException if there are problems with the default configuration
- */
- Cache<K, V> createCache(boolean start) throws ConfigurationException;
-
- /**
- * Creates and starts a {@link org.jboss.cache.Cache} instance. The following are all valid calls:
- * <pre>
- * factory.createCache("myCacheService.xml"); // file is in class path
- * factory.createCache("etc/myCacheService.xml"); // file is in etc/ relative to the directory you started the JVM
- * factory.createCache("/home/jbosscache/myCacheService.xml"); // file is in the /home/jbosscache directory
- * </pre>
- *
- * @param configFileName the named XML file should exist in the classpath or should be a fully qualified or relative (to your JVM working directory) path to a file on the local file system. Note that the classpath is checked first for the existence of this file.
- * @return a running {@link org.jboss.cache.Cache} instance
- * @throws org.jboss.cache.config.ConfigurationException
- * if there are problems with the configuration
- */
- Cache<K, V> createCache(String configFileName) throws ConfigurationException;
-
- /**
- * Creates {@link Cache} instance, and optionally starts it.
- *
- * @param configFileName the named XML file should exist in the classpath or should be a fully qualified or relative (to your JVM working directory) path to a file on the local file system. Note that the classpath is checked first for the existence of this file.
- * @param start if true, the cache is started before returning.
- * @return an optionally running {@link Cache} instance
- * @throws org.jboss.cache.config.ConfigurationException
- * if there are problems with the configuration
- * @see #createCache(String) for examples on valid config file names.
- */
- Cache<K, V> createCache(String configFileName, boolean start) throws ConfigurationException;
-
- /**
- * Creates a {@link Cache} instance based on a {@link org.jboss.cache.config.Configuration} passed in.
- * <p/>
- * Ensure that the Configuration you pass in is not used by another cache instance in the same JVM,
- * as it may be concurrently modified. Clone the configuration, if shared, using
- * {@link org.jboss.cache.config.Configuration#clone()}.
- *
- * @param configuration the {@link Configuration} object that is passed in to setCache the {@link Cache}.
- * @return a running {@link Cache} instance
- * @throws org.jboss.cache.config.ConfigurationException
- * if there are problems with the configuration
- */
- Cache<K, V> createCache(Configuration configuration) throws ConfigurationException;
-
- /**
- * Creates {@link Cache} instance, and optionally starts it, based on a {@link org.jboss.cache.config.Configuration} passed in.
- * <p/>
- * Ensure that the Configuration you pass in is not used by another cache instance in the same JVM,
- * as it may be concurrently modified. Clone the configuration, if shared, using
- * {@link org.jboss.cache.config.Configuration#clone()}.
- *
- * @param configuration the {@link Configuration} object that is passed in to setCache the {@link Cache}.
- * @param start if true, the cache is started before returning.
- * @return an optionally running {@link Cache} instance
- * @throws org.jboss.cache.config.ConfigurationException
- * if there are problems with the configuration
- */
- Cache<K, V> createCache(Configuration configuration, boolean start) throws ConfigurationException;
-}
Deleted: core/trunk/src-old/org/jboss/cache/CacheImpl.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/CacheImpl.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/CacheImpl.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,4411 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.buddyreplication.BuddyGroup;
-import org.jboss.cache.buddyreplication.BuddyManager;
-import org.jboss.cache.buddyreplication.BuddyNotInitException;
-import org.jboss.cache.buddyreplication.GravitateResult;
-import org.jboss.cache.config.BuddyReplicationConfig;
-import org.jboss.cache.config.Configuration;
-import org.jboss.cache.config.Configuration.NodeLockingScheme;
-import org.jboss.cache.config.Option;
-import org.jboss.cache.config.RuntimeConfig;
-import org.jboss.cache.factories.InterceptorChainFactory;
-import org.jboss.cache.interceptors.Interceptor;
-import org.jboss.cache.loader.CacheLoader;
-import org.jboss.cache.loader.CacheLoaderManager;
-import org.jboss.cache.lock.IsolationLevel;
-import org.jboss.cache.lock.LockStrategyFactory;
-import org.jboss.cache.lock.LockUtil;
-import org.jboss.cache.lock.LockingException;
-import org.jboss.cache.lock.NodeLock;
-import org.jboss.cache.lock.TimeoutException;
-import org.jboss.cache.marshall.InactiveRegionAwareRpcDispatcher;
-import org.jboss.cache.marshall.Marshaller;
-import org.jboss.cache.marshall.MethodCall;
-import org.jboss.cache.marshall.MethodCallFactory;
-import org.jboss.cache.marshall.MethodDeclarations;
-import org.jboss.cache.marshall.NodeData;
-import org.jboss.cache.marshall.VersionAwareMarshaller;
-import org.jboss.cache.notifications.Notifier;
-import org.jboss.cache.notifications.event.NodeModifiedEvent;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.statetransfer.StateTransferManager;
-import org.jboss.cache.transaction.GlobalTransaction;
-import org.jboss.cache.transaction.OptimisticTransactionEntry;
-import org.jboss.cache.transaction.TransactionEntry;
-import org.jboss.cache.transaction.TransactionManagerLookup;
-import org.jboss.cache.transaction.TransactionTable;
-import org.jboss.cache.util.ExposedByteArrayOutputStream;
-import org.jboss.cache.util.ThreadGate;
-import org.jboss.cache.util.concurrent.ConcurrentHashSet;
-import org.jboss.util.stream.MarshalledValueInputStream;
-import org.jboss.util.stream.MarshalledValueOutputStream;
-import org.jgroups.Address;
-import org.jgroups.Channel;
-import org.jgroups.ChannelClosedException;
-import org.jgroups.ChannelException;
-import org.jgroups.ChannelFactory;
-import org.jgroups.ChannelNotConnectedException;
-import org.jgroups.ExtendedMembershipListener;
-import org.jgroups.ExtendedMessageListener;
-import org.jgroups.JChannel;
-import org.jgroups.Message;
-import org.jgroups.View;
-import org.jgroups.blocks.GroupRequest;
-import org.jgroups.blocks.RpcDispatcher;
-import org.jgroups.util.Rsp;
-import org.jgroups.util.RspList;
-import org.jgroups.util.Util;
-
-import javax.transaction.Status;
-import javax.transaction.SystemException;
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.io.NotSerializableException;
-import java.io.OutputStream;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Vector;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * The default implementation class of {@link org.jboss.cache.Cache} and {@link org.jboss.cache.CacheSPI}. This class
- * has its roots in the legacy (JBoss Cache 1.x.x) org.jboss.cache.TreeCache class.
- * <p/>
- * You should not use this class directly, or attempt to cast {@link org.jboss.cache.Cache} or {@link org.jboss.cache.CacheSPI}
- * interfaces directly to this class.
- *
- * @author Bela Ban
- * @author Ben Wang
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- * @author Brian Stansberry
- * @author Daniel Huang (dhuang(a)jboss.org)
- * @see org.jboss.cache.Cache
- */
-public class CacheImpl<K, V> implements CacheSPI<K, V>
-{
-
- /**
- * CacheImpl log.
- */
- private Log log = LogFactory.getLog(CacheImpl.class);
-
- /**
- * Thread gate used to block Dispatcher during JGroups FLUSH protocol
- */
- private final ThreadGate flushBlockGate = new ThreadGate();
-
- /**
- * Root node.
- */
- private NodeSPI<K, V> root;
-
- /**
- * Cache's region manager.
- */
- private RegionManager regionManager = null;
-
- /**
- * The JGroups JChannel in use.
- */
- protected Channel channel = null;
-
- /**
- * True if this CacheImpl is the coordinator.
- */
- private boolean coordinator = false;
-
- /**
- * List of cluster group members.
- */
- private final Vector<Address> members = new Vector<Address>();
-
- /**
- * JGroups RpcDispatcher in use.
- */
- private RpcDispatcher disp = null;
-
- /**
- * JGroups message listener.
- */
- private MessageListenerAdaptor ml = new MessageListenerAdaptor();
-
- /**
- * Maintains mapping of transactions (keys) and Modifications/Undo-Operations
- */
- private final TransactionTable tx_table = new TransactionTable();
-
- /**
- * HashMap<Thread, List<Lock>, maintains locks acquired by threads (used when no TXs are used)
- */
- private Map<Thread, List<NodeLock>> lock_table;
-
- /**
- * Set<Fqn> of Fqns of the topmost node of internal regions that should
- * not included in standard state transfers.
- */
- private Set<Fqn> internalFqns = new ConcurrentHashSet<Fqn>();
-
- /**
- * True if state was initialized during start-up.
- */
- private volatile boolean isStateSet = false;
-
- /**
- * Class name used to handle evictions.
- */
- private String evictionInterceptorClass = "org.jboss.cache.interceptors.EvictionInterceptor";
-
- /**
- * Marshaller if register to handle marshalling
- */
- private Marshaller marshaller_ = null;
-
- /**
- * {@link #invokeMethod(org.jboss.cache.marshall.MethodCall,boolean)} will dispatch to this chain of interceptors.
- * In the future, this will be replaced with JBossAop. This is a first step towards refactoring JBossCache.
- */
- private Interceptor interceptor_chain = null;
-
- /**
- * Method to acquire a TransactionManager. By default we use JBossTransactionManagerLookup. Has
- * to be set before calling {@link #start()}
- */
- private TransactionManagerLookup tm_lookup = null;
-
- /**
- * Used to get the Transaction associated with the current thread
- */
- private TransactionManager tm = null;
-
- /**
- * Cache loader manager.
- */
- private CacheLoaderManager cacheLoaderManager;
-
- /**
- * Queue used to replicate updates when mode is repl-async
- */
- private ReplicationQueue repl_queue = null;
-
- /**
- * The current lifecycle state.
- */
- CacheStatus cacheStatus;
-
- /**
- * Buddy Manager
- */
- private BuddyManager buddyManager;
-
- /**
- * State transfer manager. Do not access this field directly -- use the getter
- */
- private StateTransferManager stateTransferManager;
-
- /**
- * Cache notifier handler class.
- */
- private Notifier notifier;
-
- private ThreadLocal<InvocationContext> invocationContextContainer = new ThreadLocal<InvocationContext>()
- {
- @Override
- protected InvocationContext initialValue()
- {
- return new InvocationContext();
- }
- };
-
- private Configuration configuration;
-
- /**
- * Constructs an uninitialized CacheImpl.
- */
- protected CacheImpl() throws Exception
- {
- configuration = new Configuration(this);
- notifier = new Notifier(this);
- regionManager = new RegionManager(this);
- cacheStatus = CacheStatus.INSTANTIATED;
- }
-
- public StateTransferManager getStateTransferManager()
- {
- if (stateTransferManager == null)
- {
- stateTransferManager = new StateTransferManager(this);
- }
- return stateTransferManager;
- }
-
- public void setStateTransferManager(StateTransferManager manager)
- {
- this.stateTransferManager = manager;
- }
-
- public Configuration getConfiguration()
- {
- return configuration;
- }
-
- /**
- * Returns the CacheImpl implementation version.
- */
- public String getVersion()
- {
- return Version.printVersion();
- }
-
- /**
- * Returns the root node.
- */
- public NodeSPI<K, V> getRoot()
- {
- return root;
- }
-
- /**
- * Returns the local channel address.
- */
- public Address getLocalAddress()
- {
- return channel != null ? channel.getLocalAddress() : null;
- }
-
- /**
- * Returns the members as a List.
- * This list may be concurrently modified.
- */
- public List<Address> getMembers()
- {
- synchronized (members)
- {
- return new ArrayList<Address>(members);
- }
- }
-
- /**
- * Returns <code>true</code> if this node is the group coordinator.
- */
- public boolean isCoordinator()
- {
- return coordinator;
- }
-
- /**
- * Returns the transaction table.
- */
- public TransactionTable getTransactionTable()
- {
- return tx_table;
- }
-
- /**
- * Returns the lock table.
- */
- public Map<Thread, List<NodeLock>> getLockTable()
- {
- if (lock_table == null)
- {
- lock_table = new ConcurrentHashMap<Thread, List<NodeLock>>();
- }
- return lock_table;
- }
-
- /**
- * Returns the contents of the TransactionTable as a string.
- */
- public String dumpTransactionTable()
- {
- return tx_table.toString(true);
- }
-
- /**
- * Used for testing only - sets the interceptor chain.
- */
- public void setInterceptorChain(Interceptor i)
- {
- interceptor_chain = i;
- }
-
- /**
- * @return the list of interceptors.
- */
- public List<Interceptor> getInterceptors()
- {
- return InterceptorChainFactory.getInstance().asList(interceptor_chain);
- }
-
- /**
- * Returns the underlying cache loader in use.
- */
- public CacheLoader getCacheLoader()
- {
- if (cacheLoaderManager == null)
- return null;
- return cacheLoaderManager.getCacheLoader();
- }
-
- public String getEvictionInterceptorClass()
- {
- return this.evictionInterceptorClass;
- }
-
- private void setUseReplQueue(boolean flag)
- {
- if (flag)
- {
- if (repl_queue == null)
- {
- repl_queue = new ReplicationQueue(this, configuration.getReplQueueInterval(), configuration.getReplQueueMaxElements());
- if (configuration.getReplQueueInterval() >= 0)
- {
- repl_queue.start();
- }
- }
- }
- else
- {
- if (repl_queue != null)
- {
- repl_queue.stop();
- repl_queue = null;
- }
- }
- }
-
-
- /**
- * Returns the replication queue.
- */
- public ReplicationQueue getReplicationQueue()
- {
- return repl_queue;
- }
-
- /**
- * Sets the cache locking isolation level.
- */
- private void setIsolationLevel(IsolationLevel level)
- {
- LockStrategyFactory.setIsolationLevel(level);
- }
-
- /**
- * Sets the TransactionManagerLookup object
- */
- public void setTransactionManagerLookup(TransactionManagerLookup l)
- {
- this.tm_lookup = l;
- }
-
- /**
- * Returns the transaction manager in use.
- */
- public TransactionManager getTransactionManager()
- {
- return tm;
- }
-
- /**
- * Fetches the group state from the current coordinator. If successful, this
- * will trigger JChannel setState() call.
- */
- public void fetchState(long timeout) throws ChannelClosedException, ChannelNotConnectedException
- {
- if (channel == null)
- {
- throw new ChannelNotConnectedException();
- }
- boolean rc = channel.getState(null, timeout);
- if (rc)
- {
- log.debug("fetchState(): state was retrieved successfully");
- }
- else
- {
- log.debug("fetchState(): state could not be retrieved (first member)");
- }
- }
-
- void fetchPartialState(List<Address> sources, Fqn sourceTarget, Fqn integrationTarget) throws Exception
- {
- String encodedStateId = sourceTarget + StateTransferManager.PARTIAL_STATE_DELIMITER + integrationTarget;
- fetchPartialState(sources, encodedStateId);
- }
-
- void fetchPartialState(List<Address> sources, Fqn subtree) throws Exception
- {
- if (subtree == null)
- {
- throw new IllegalArgumentException("Cannot fetch partial state. Null subtree.");
- }
- fetchPartialState(sources, subtree.toString());
- }
-
- private void fetchPartialState(List<Address> sources, String stateId) throws Exception
- {
- if (sources == null || sources.isEmpty() || stateId == null)
- {
- // should this really be throwing an exception? Are there valid use cases where partial state may not be available? - Manik
- // Yes -- cache is configured LOCAL but app doesn't know it -- Brian
- //throw new IllegalArgumentException("Cannot fetch partial state, targets are " + sources + " and stateId is " + stateId);
- if (log.isWarnEnabled())
- {
- log.warn("Cannot fetch partial state, targets are " + sources +
- " and stateId is " + stateId);
- }
- return;
- }
-
- List<Address> targets = new LinkedList<Address>(sources);
-
- //skip *this* node as a target
- targets.remove(getLocalAddress());
-
- if (targets.isEmpty())
- {
- // Definitely no exception here -- this happens every time the 1st node in the
- // cluster activates a region!! -- Brian
- log.debug("Cannot fetch partial state. There are no target members specified");
- return;
- }
-
- log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from members " + targets);
- boolean successfulTransfer = false;
- for (Address target : targets)
- {
- log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from member " + target);
- isStateSet = false;
- successfulTransfer = channel.getState(target, stateId, configuration.getStateRetrievalTimeout());
- if (successfulTransfer)
- {
- try
- {
- ml.waitForState();
- }
- catch (Exception transferFailed)
- {
- successfulTransfer = false;
- }
- }
- log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from member " + target + (successfulTransfer ? " successful" : " failed"));
- if (successfulTransfer)
- break;
- }
-
- if (!successfulTransfer)
- {
- log.debug("Node " + getLocalAddress() + " could not fetch partial state " + stateId + " from any member " + targets);
- }
- }
-
- /**
- * Lifecycle method. This is like initialize.
- *
- * @throws Exception
- */
- public void create() throws CacheException
- {
- if (!cacheStatus.createAllowed())
- {
- if (cacheStatus.needToDestroyFailedCache())
- destroy();
- else
- return;
- }
-
- try
- {
- internalCreate();
- }
- catch (Throwable t)
- {
- handleLifecycleTransitionFailure(t);
- }
- }
-
- /**
- * Sets the cacheStatus to FAILED and rethrows the problem as one
- * of the declared types. Converts any non-RuntimeException Exception
- * to CacheException.
- *
- * @param t
- * @throws CacheException
- * @throws RuntimeException
- * @throws Error
- */
- private void handleLifecycleTransitionFailure(Throwable t)
- throws CacheException, RuntimeException, Error
- {
- cacheStatus = CacheStatus.FAILED;
- if (t instanceof CacheException)
- throw (CacheException) t;
- else if (t instanceof RuntimeException)
- throw (RuntimeException) t;
- else if (t instanceof Error)
- throw (Error) t;
- else
- throw new CacheException(t);
- }
-
- /**
- * The actual create implementation.
- *
- * @throws CacheException
- */
- private void internalCreate() throws CacheException
- {
- // Include our clusterName in our log category
- configureLogCategory();
-
- // initialise the node factory and set this in the runtime.
- NodeFactory<K, V> nf;
- if ((nf = configuration.getRuntimeConfig().getNodeFactory()) == null)
- {
- nf = new NodeFactory<K, V>(this);
- configuration.getRuntimeConfig().setNodeFactory(nf);
- }
- else
- {
- // don't create a new one each and every time. After stopping and starting the cache, the old NodeFactory may still be valid.
- nf.init();
- }
-
- if (notifier == null)
- notifier = new Notifier(this);
-
- // create a new root temporarily.
- NodeSPI<K, V> tempRoot = nf.createRootDataNode();
- // if we don't already have a root or the new (temp) root is of a different class (optimistic vs pessimistic) to
- // the current root, then we use the new one. Helps preserve data between cache restarts.
- if (root == null || !root.getClass().equals(tempRoot.getClass()))
- root = tempRoot;
-
- if (configuration.getCacheLoaderConfig() != null && cacheLoaderManager == null)
- {
- initialiseCacheLoaderManager();
- }
- // first set up the Buddy Manager and an RPCManager
- if (configuration.getCacheMode() != Configuration.CacheMode.LOCAL)
- {
- getConfiguration().getRuntimeConfig().setRPCManager(new RPCManagerImpl(this));
- setBuddyReplicationConfig(configuration.getBuddyReplicationConfig());
- }
- // build interceptor chain
- try
- {
- interceptor_chain = InterceptorChainFactory.getInstance().buildInterceptorChain(this);
- }
- catch (Exception e)
- {
- throw new CacheException("Unable to build interceptor chain", e);
- }
-
-
- setUseReplQueue(configuration.isUseReplQueue());
- setIsolationLevel(configuration.getIsolationLevel());
-
- getRegionManager();// make sure we create one
- createEvictionPolicy();
-
- getRegionManager().setDefaultInactive(configuration.isInactiveOnStartup());
-
- cacheStatus = CacheStatus.CREATED;
- }
-
- private void createTransactionManager()
- {
- // See if we had a TransactionManager injected into our config
- this.tm = configuration.getRuntimeConfig().getTransactionManager();
- if (tm == null)
- {
- // Nope. See if we can look it up from JNDI
- if (this.tm_lookup == null && configuration.getTransactionManagerLookupClass() != null)
- {
- try
- {
- Class clazz = Thread.currentThread().getContextClassLoader().loadClass(configuration.getTransactionManagerLookupClass());
- this.tm_lookup = (TransactionManagerLookup) clazz.newInstance();
- }
- catch (Exception e)
- {
- throw new CacheException("Problems creating the cache", e);
- }
- }
-
- try
- {
- if (tm_lookup != null)
- {
- tm = tm_lookup.getTransactionManager();
- configuration.getRuntimeConfig().setTransactionManager(tm);
- }
- else
- {
- if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC)
- {
- log.fatal("No transaction manager lookup class has been defined. Transactions cannot be used and thus OPTIMISTIC locking cannot be used");
- }
- else
- {
- log.info("No transaction manager lookup class has been defined. Transactions cannot be used");
- }
- }
- }
- catch (Exception e)
- {
- log.debug("failed looking up TransactionManager, will not use transactions", e);
- }
- }
- }
-
- protected boolean shouldFetchStateOnStartup()
- {
- boolean loaderFetch = cacheLoaderManager != null && cacheLoaderManager.isFetchPersistentState();
- return !configuration.isInactiveOnStartup() && buddyManager == null && (configuration.isFetchInMemoryState() || loaderFetch);
- }
-
- /**
- * Lifecyle method.
- *
- * @throws CacheException
- */
- public void start() throws CacheException
- {
- if (!cacheStatus.startAllowed())
- {
- if (cacheStatus.needToDestroyFailedCache())
- destroy(); // this will take us back to DESTROYED
-
- if (cacheStatus.needCreateBeforeStart())
- create();
- else
- return;
- }
-
- try
- {
- internalStart();
- }
- catch (Throwable t)
- {
- handleLifecycleTransitionFailure(t);
- }
- }
-
- /**
- * The actual start implementation.
- *
- * @throws CacheException
- * @throws IllegalArgumentException
- */
- private void internalStart() throws CacheException, IllegalArgumentException
- {
- cacheStatus = CacheStatus.STARTING;
-
- createTransactionManager();
-
- // cache loaders should be initialised *before* any state transfers take place to prevent
- // exceptions involving cache loaders not being started. - Manik
- // create cache loader
- if (cacheLoaderManager != null)
- {
- cacheLoaderManager.startCacheLoader();
- }
- // now that we have a TM we can init the interceptor chain
- InterceptorChainFactory.getInstance().initialiseInterceptors(interceptor_chain, this);
-
- switch (configuration.getCacheMode())
- {
- case LOCAL:
- log.debug("cache mode is local, will not create the channel");
- break;
- case REPL_SYNC:
- case REPL_ASYNC:
- case INVALIDATION_ASYNC:
- case INVALIDATION_SYNC:
- if (log.isDebugEnabled()) log.debug("cache mode is " + configuration.getCacheMode());
- initialiseChannelAndRpcDispatcher();
-
- try
- {
- channel.connect(configuration.getClusterName());
- }
- catch (ChannelException e)
- {
- throw new CacheException("Unable to connect to JGroups channel", e);
- }
-
- if (log.isInfoEnabled())
- {
- log.info("CacheImpl local address is " + channel.getLocalAddress());
- }
- if (shouldFetchStateOnStartup())
- {
- try
- {
- fetchStateOnStartup();
- }
- catch (Exception e)
- {
- // make sure we disconnect from the channel before we throw this exception!
- // JBCACHE-761
- channel.disconnect();
- channel.close();
- throw new CacheException("Unable to fetch state on startup", e);
- }
- }
- if (buddyManager != null)
- {
- buddyManager.init(this);
- if (configuration.isUseReplQueue())
- {
- log.warn("Replication queue not supported when using buddy replication. Disabling repliction queue.");
- configuration.setUseReplQueue(false);
- repl_queue = null;
- }
- }
- break;
- default:
- throw new IllegalArgumentException("cache mode " + configuration.getCacheMode() + " is invalid");
- }
-
- //now attempt to preload the cache from the loader - Manik
- if (cacheLoaderManager != null)
- {
- cacheLoaderManager.preloadCache();
- }
-
- // Find out if we are coordinator (blocks until view is received)
- determineCoordinator();
-
- // start any eviction threads.
- if (regionManager.isUsingEvictions())
- {
- regionManager.startEvictionThread();
- }
-
- notifier.notifyCacheStarted(this, getInvocationContext());
-
- // install a VM shutdown hook
- Thread shutdownHook = new Thread()
- {
- public void run()
- {
- CacheImpl.this.stop();
- }
- };
-
- Runtime.getRuntime().addShutdownHook(shutdownHook);
-
- log.info("JBoss Cache version: " + getVersion());
-
- cacheStatus = CacheStatus.STARTED;
- }
-
- /**
- * Lifecycle method.
- */
- public void destroy()
- {
- if (!cacheStatus.destroyAllowed())
- {
- if (cacheStatus.needStopBeforeDestroy())
- {
- try
- {
- stop();
- }
- catch (CacheException e)
- {
- log.warn("Needed to call stop() before destroying but stop() " +
- "threw exception. Proceeding to destroy", e);
- }
- }
- else
- return;
- }
-
- try
- {
- internalDestroy();
- }
- finally
- {
- // We always progress to destroyed
- cacheStatus = CacheStatus.DESTROYED;
- }
- }
-
- /**
- * The actual destroy implementation.
- */
- private void internalDestroy()
- {
- cacheStatus = CacheStatus.DESTROYING;
- regionManager = null;
- notifier = null;
-
- // The rest of these should have already been taken care of in stop,
- // but we do it here as well in case stop failed.
-
- if (channel != null)
- {
- if (channel.isOpen())
- {
- try
- {
- channel.close();
- channel.disconnect();
- }
- catch (Exception toLog)
- {
- log.error("Problem closing channel; setting it to null", toLog);
- }
- }
- channel = null;
- configuration.getRuntimeConfig().setChannel(null);
- }
- disp = null;
- tm = null;
- }
-
- /**
- * Lifecycle method.
- */
- public void stop()
- {
- if (!cacheStatus.stopAllowed())
- {
- return;
- }
-
- // Trying to stop() from FAILED is valid, but may not work
- boolean failed = cacheStatus == CacheStatus.FAILED;
-
- try
- {
- internalStop();
- }
- catch (Throwable t)
- {
- if (failed)
- {
- log.warn("Attempted to stop() from FAILED state, " +
- "but caught exception; try calling destroy()", t);
- }
- handleLifecycleTransitionFailure(t);
- }
- }
-
- /**
- * The actual stop implementation.
- */
- private void internalStop()
- {
- cacheStatus = CacheStatus.STOPPING;
-
- // before closing the channel stop the buddy manager
- if (buddyManager != null && buddyManager.isEnabled())
- {
- log.debug("stop(): stopping buddy manager");
- buddyManager.stop();
- }
-
- if (channel != null)
- {
- log.info("stop(): closing the channel");
- killChannel();
- channel = null;
- configuration.getRuntimeConfig().setChannel(null);
- }
-
- if (disp != null)
- {
- log.info("stop(): stopping the dispatcher");
- disp.stop();
- disp = null;
- }
- if (members != null)
- {
- synchronized (members)
- {
- members.clear();
- }
- }
-
- coordinator = false;
-
- if (repl_queue != null)
- {
- repl_queue.stop();
- }
-
- if (cacheLoaderManager != null)
- {
- log.debug("stop(): stopping cache loader manager");
- cacheLoaderManager.stopCacheLoader();
- }
-
- if (regionManager.isUsingEvictions()) regionManager.stopEvictionThread();
-
- if (notifier != null)
- {
- notifier.notifyCacheStopped(this, getInvocationContext());
- notifier.removeAllCacheListeners();
- }
-
- // unset transaction manager reference
- tm = null;
-
- cacheStatus = CacheStatus.STOPPED;
-
- // empty in-memory state
- root.clearDataDirect();
- root.removeChildrenDirect();
- }
-
- public CacheStatus getCacheStatus()
- {
- return cacheStatus;
- }
-
- /* ----------------------- End of MBeanSupport ----------------------- */
-
- /* ----------------------- Start of buddy replication specific methods ------------*/
-
- /**
- * Sets the buddy replication configuration element
- *
- * @param config
- */
- private void setBuddyReplicationConfig(BuddyReplicationConfig config)
- {
- if (config != null)
- {
- buddyManager = new BuddyManager(config);
- if (!buddyManager.isEnabled())
- {
- buddyManager = null;
- }
- else
- {
- internalFqns.add(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
- }
- }
- }
-
- /**
- * Retrieves the Buddy Manager configured.
- *
- * @return null if buddy replication is not enabled.
- */
- public BuddyManager getBuddyManager()
- {
- return buddyManager;
- }
-
- /**
- * Returns a Set<Fqn> of Fqns of the topmost node of internal regions that
- * should not included in standard state transfers. Will include
- * {@link BuddyManager#BUDDY_BACKUP_SUBTREE} if buddy replication is
- * enabled.
- *
- * @return an unmodifiable Set<Fqn>. Will not return <code>null</code>.
- */
- public Set<Fqn> getInternalFqns()
- {
- return Collections.unmodifiableSet(internalFqns);
- }
-
- /* ----------------------- End of buddy replication specific methods ------------*/
-
- protected void createEvictionPolicy()
- {
- if (configuration.getEvictionConfig() != null
- && configuration.getEvictionConfig().isValidConfig())
- {
- regionManager.setEvictionConfig(configuration.getEvictionConfig());
- regionManager.setUsingEvictions(true);
- }
- else
- {
- regionManager.setUsingEvictions(false);
- log.debug("Not using an EvictionPolicy");
- }
- }
-
- /**
- * Loads the indicated Fqn, plus all parents recursively from the
- * CacheLoader. If no CacheLoader is present, this is a no-op
- *
- * @param fqn
- * @throws Exception
- */
- public void load(String fqn) throws Exception
- {
- if (cacheLoaderManager != null)
- {
- cacheLoaderManager.preload(Fqn.fromString(fqn), true, true);
- }
- }
-
- private void determineCoordinator()
- {
- // Synchronize on members to make the answer atomic for the current view
- synchronized (members)
- {
- Address coord = getCoordinator();
- coordinator = (coord == null ? false : coord.equals(getLocalAddress()));
- }
- }
-
- /**
- * Returns the address of the coordinator or null if there is no
- * coordinator.
- * Waits until the membership view is updated.
- */
- public Address getCoordinator()
- {
- if (channel == null)
- {
- return null;
- }
-
- synchronized (members)
- {
- while (members.isEmpty())
- {
- log.debug("getCoordinator(): waiting on viewAccepted()");
- try
- {
- members.wait();
- }
- catch (InterruptedException e)
- {
- log.error("getCoordinator(): Interrupted while waiting for members to be set", e);
- break;
- }
- }
- return members.size() > 0 ? members.get(0) : null;
- }
- }
-
- // ----------- Marshalling and State Transfer -----------------------
-
- /**
- * Creates a subtree in the local cache.
- * Returns the DataNode created.
- */
- protected Node createSubtreeRootNode(Fqn<?> subtree) throws CacheException
- {
- NodeSPI<K, V> parent = root;
- NodeSPI<K, V> child = null;
- Object owner = getOwnerForLock();
- Object name;
- NodeFactory<K, V> factory = configuration.getRuntimeConfig().getNodeFactory();
-
- for (int i = 0; i < subtree.size(); i++)
- {
- name = subtree.get(i);
- child = parent.getChildDirect(name);
- if (child == null)
- {
- // Lock the parent, create and add the child
- try
- {
- parent.getLock().acquire(owner, configuration.getSyncReplTimeout(), NodeLock.LockType.WRITE);
- }
- catch (InterruptedException e)
- {
- log.error("Interrupted while locking" + parent.getFqn(), e);
- throw new CacheException(e.getLocalizedMessage(), e);
- }
-
- try
- {
- child = factory.createDataNode(name,
- subtree.getAncestor(i + 1),
- parent, null, true);
- parent.addChild(name, child);
- }
- finally
- {
- if (log.isDebugEnabled())
- {
- log.debug("forcing release of locks in " + parent.getFqn());
- }
- try
- {
- parent.getLock().releaseAll();
- }
- catch (Throwable t)
- {
- log.error("failed releasing locks", t);
- }
- }
- }
-
- parent = child;
- }
-
- return child;
- }
-
- /**
- * Evicts the node at <code>subtree</code> along with all descendant nodes.
- *
- * @param subtree Fqn indicating the uppermost node in the
- * portion of the cache that should be evicted.
- * @throws CacheException
- */
- protected void _evictSubtree(Fqn subtree) throws CacheException
- {
-
- if (!exists(subtree))
- {
- return;// node does not exist. Maybe it has been recursively removed.
- }
-
- if (log.isTraceEnabled())
- {
- log.trace("_evictSubtree(" + subtree + ")");
- }
-
- // Recursively remove any children
- Set children = getChildrenNames(subtree);
- if (children != null)
- {
- for (Object s : children)
- {
-
- Fqn<Object> tmp = new Fqn<Object>(subtree, s);
- _remove(null, // no tx
- tmp,
- false, // no undo ops
- false, // no nodeEvent
- true);// is an eviction
- }
- }
-
- // Remove the root node of the subtree
- _remove(null, subtree, false, false, true);
-
- }
-
- private void removeLocksForDeadMembers(NodeSPI<K, V> node, List deadMembers)
- {
- Set<GlobalTransaction> deadOwners = new HashSet<GlobalTransaction>();
- NodeLock lock = node.getLock();
- Object owner = lock.getWriterOwner();
-
- if (isLockOwnerDead(owner, deadMembers))
- {
- deadOwners.add((GlobalTransaction) owner);
- }
-
- for (Object readOwner : lock.getReaderOwners())
- {
- if (isLockOwnerDead(readOwner, deadMembers))
- {
- deadOwners.add((GlobalTransaction) readOwner);
- }
- }
-
- for (GlobalTransaction deadOwner : deadOwners)
- {
- boolean localTx = deadOwner.getAddress().equals(getLocalAddress());
- boolean broken = LockUtil.breakTransactionLock(lock, deadOwner, localTx, this);
-
- if (broken && log.isTraceEnabled())
- {
- log.trace("Broke lock for node " + node.getFqn() +
- " held by " + deadOwner);
- }
- }
-
- // Recursively unlock children
- for (NodeSPI<K, V> child : node.getChildrenDirect())
- {
- removeLocksForDeadMembers(child, deadMembers);
- }
- }
-
- private boolean isLockOwnerDead(Object owner, List deadMembers)
- {
- boolean result = false;
- if (owner != null && owner instanceof GlobalTransaction)
- {
- Object addr = ((GlobalTransaction) owner).getAddress();
- result = deadMembers.contains(addr);
- }
- return result;
- }
-
- protected void fetchStateOnStartup() throws Exception
- {
- long start, stop;
- isStateSet = false;
- start = System.currentTimeMillis();
- boolean rc = channel.getState(null, configuration.getStateRetrievalTimeout());
- if (rc)
- {
- ml.waitForState();
- stop = System.currentTimeMillis();
- if (log.isDebugEnabled())
- {
- log.debug("state was retrieved successfully (in " + (stop - start) + " milliseconds)");
- }
- }
- else
- {
- // No one provided us with state. We need to find out if that's because
- // we are the coordinator. But we don't know if the viewAccepted() callback
- // has been invoked, so call determineCoordinator(), which will block until
- // viewAccepted() is called at least once
- determineCoordinator();
-
- if (isCoordinator())
- {
- log.debug("State could not be retrieved (we are the first member in group)");
- }
- else
- {
- throw new CacheException("Initial state transfer failed: " +
- "Channel.getState() returned false");
- }
- }
- }
-
- // ----------- End Marshalling and State Transfer -----------------------
-
- /**
- * @param fqn fqn String name to retrieve from cache
- * @return DataNode corresponding to the fqn. Null if does not exist. No guarantees wrt replication,
- * cache loading are given if the underlying node is modified
- */
- public Node get(String fqn) throws CacheException
- {
- return get(Fqn.fromString(fqn));
- }
-
- /**
- * Returns a DataNode corresponding to the fully qualified name or null if
- * does not exist.
- * No guarantees wrt replication, cache loading are given if the underlying node is modified
- *
- * @param fqn name of the DataNode to retreive
- */
- public Node<K, V> get(Fqn<?> fqn) throws CacheException
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.getNodeMethodLocal, fqn);
- return (Node<K, V>) invokeMethod(m, true);
- }
-
- /**
- * Returns the raw data of the node; called externally internally.
- */
- public Node<K, V> _get(Fqn<?> fqn) throws CacheException
- {
- return findNode(fqn);
- }
-
- /**
- * Returns the raw data of the node; called externally internally.
- */
- public Map _getData(Fqn<?> fqn)
- {
- NodeSPI n = findNode(fqn);
- if (n == null) return null;
- return n.getDataDirect();
- }
-
- /**
- * Returns a set of attribute keys for the Fqn.
- * Returns null if the node is not found, otherwise a Set.
- * The set is a copy of the actual keys for this node.
- *
- * @param fqn name of the node
- */
- public Set getKeys(String fqn) throws CacheException
- {
- return getKeys(Fqn.fromString(fqn));
- }
-
- /**
- * Returns a set of attribute keys for the Fqn.
- * Returns null if the node is not found, otherwise a Set.
- * The set is a copy of the actual keys for this node.
- *
- * @param fqn name of the node
- */
- public Set<K> getKeys(Fqn<?> fqn) throws CacheException
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.getKeysMethodLocal, fqn);
- return (Set<K>) invokeMethod(m, true);
- }
-
-
- /**
- * Retrieves a defensively copied data map of the underlying node.
- *
- * @param fqn
- * @return map of data, or an empty map
- * @throws CacheException
- */
- public Map<K, V> getData(Fqn<?> fqn) throws CacheException
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.getDataMapMethodLocal, fqn);
- return (Map<K, V>) invokeMethod(m, true);
- }
-
- public Set _getKeys(Fqn<?> fqn) throws CacheException
- {
- NodeSPI<K, V> n = findNode(fqn);
- if (n == null)
- {
- return null;
- }
- Set<K> keys = n.getKeysDirect();
- return new HashSet<K>(keys);
- }
-
- /**
- * Finds a node given its name and returns the value associated with a given key in its <code>data</code>
- * map. Returns null if the node was not found in the cache or the key was not found in the hashmap.
- *
- * @param fqn The fully qualified name of the node.
- * @param key The key.
- */
- public V get(String fqn, K key) throws CacheException
- {
- return get(Fqn.fromString(fqn), key);
- }
-
-
- /**
- * Finds a node given its name and returns the value associated with a given key in its <code>data</code>
- * map. Returns null if the node was not found in the cache or the key was not found in the hashmap.
- *
- * @param fqn The fully qualified name of the node.
- * @param key The key.
- */
- public V get(Fqn<?> fqn, K key) throws CacheException
- {
- return get(fqn, key, true);
- }
-
- public V _get(Fqn<?> fqn, K key, boolean sendNodeEvent) throws CacheException
- {
- InvocationContext ctx = getInvocationContext();
- if (log.isTraceEnabled())
- {
- log.trace(new StringBuffer("_get(").append("\"").append(fqn).append("\", \"").append(key).append("\", \"").
- append(sendNodeEvent).append("\")"));
- }
- if (sendNodeEvent) notifier.notifyNodeVisited(fqn, true, ctx);
- NodeSPI<K, V> n = findNode(fqn);
- if (n == null)
- {
- log.trace("node not found");
- return null;
- }
- if (sendNodeEvent) notifier.notifyNodeVisited(fqn, false, ctx);
- return n.getDirect(key);
- }
-
-
- protected V get(Fqn<?> fqn, K key, boolean sendNodeEvent) throws CacheException
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.getKeyValueMethodLocal, fqn, key, sendNodeEvent);
- return (V) invokeMethod(m, true);
- }
-
- /**
- * Checks whether a given node exists in current in-memory state of the cache.
- * Does not acquire any locks in doing so (result may be dirty read). Does
- * not attempt to load nodes from a cache loader (may return false if a
- * node has been evicted).
- *
- * @param fqn The fully qualified name of the node
- * @return boolean Whether or not the node exists
- */
- public boolean exists(String fqn)
- {
- return exists(Fqn.fromString(fqn));
- }
-
-
- /**
- * Checks whether a given node exists in current in-memory state of the cache.
- * Does not acquire any locks in doing so (result may be dirty read). Does
- * not attempt to load nodes from a cache loader (may return false if a
- * node has been evicted).
- *
- * @param fqn The fully qualified name of the node
- * @return boolean Whether or not the node exists
- */
- public boolean exists(Fqn<?> fqn)
- {
- Node n = peek(fqn, false);
- return n != null;
- }
-
- /**
- * Gets node without attempt to load it from CacheLoader if not present
- *
- * @param fqn
- */
- public NodeSPI<K, V> peek(Fqn<?> fqn, boolean includeDeletedNodes)
- {
- if (fqn == null || fqn.size() == 0) return root;
- NodeSPI<K, V> n = root;
- int fqnSize = fqn.size();
- for (int i = 0; i < fqnSize; i++)
- {
- Object obj = fqn.get(i);
- n = n.getChildDirect(obj);
- if (n == null)
- {
- return null;
- }
- else if (!includeDeletedNodes && n.isDeleted())
- {
- return null;
- }
- }
- return n;
- }
-
-
- /**
- * @param fqn
- * @param key
- */
- public boolean exists(String fqn, Object key)
- {
- return exists(Fqn.fromString(fqn), key);
- }
-
-
- /**
- * Checks whether a given key exists in the given node. Does not interact with CacheLoader, so the behavior is
- * different from {@link #get(Fqn,Object)}
- *
- * @param fqn The fully qualified name of the node
- * @param key
- * @return boolean Whether or not the node exists
- */
- public boolean exists(Fqn<?> fqn, Object key)
- {
- NodeSPI n = peek(fqn, false);
- return n != null && n.getKeysDirect().contains(key);
- }
-
-
- /**
- * Adds a new node to the cache and sets its data. If the node doesn not yet exist, it will be created.
- * Also, parent nodes will be created if not existent. If the node already has data, then the new data
- * will override the old one. If the node already existed, a nodeModified() notification will be generated.
- * Otherwise a nodeCreated() motification will be emitted.
- *
- * @param fqn The fully qualified name of the new node
- * @param data The new data. May be null if no data should be set in the node.
- */
- public void put(String fqn, Map data) throws CacheException
- {
- put(Fqn.fromString(fqn), data);
- }
-
- /**
- * Sets a node's data. If the node does not yet exist, it will be created.
- * Also, parent nodes will be created if not existent. If the node already has data, then the new data
- * will override the old one. If the node already existed, a nodeModified() notification will be generated.
- * Otherwise a nodeCreated() motification will be emitted.
- *
- * @param fqn The fully qualified name of the new node
- * @param data The new data. May be null if no data should be set in the node.
- */
- public void put(Fqn<?> fqn, Map<K, V> data) throws CacheException
- {
- put(fqn, data, false);
- }
-
- public void put(Fqn<?> fqn, Map<K, V> data, boolean erase) throws CacheException
- {
- GlobalTransaction tx = getCurrentTransaction();
- MethodCall m;
- if (erase)
- {
- m = MethodCallFactory.create(MethodDeclarations.putDataEraseMethodLocal, tx, fqn, data, true, true);
- }
- else
- {
- m = MethodCallFactory.create(MethodDeclarations.putDataMethodLocal, tx, fqn, data, true);
- }
- invokeMethod(m, true);
- }
-
- /**
- * Adds a key and value to a given node. If the node doesn't exist, it will be created. If the node
- * already existed, a nodeModified() notification will be generated. Otherwise a
- * nodeCreated() motification will be emitted.
- *
- * @param fqn The fully qualified name of the node
- * @param key The key
- * @param value The value
- * @return Object The previous value (if any), if node was present
- */
- public V put(String fqn, K key, V value) throws CacheException
- {
- return put(Fqn.fromString(fqn), key, value);
- }
-
- /**
- * Adds a key and value to a given node. If the node doesn't exist, it will be created. If the node
- * already existed, a nodeModified() notification will be generated. Otherwise a
- * nodeCreated() motification will be emitted.
- *
- * @param fqn The fully qualified name of the node
- * @param key The key
- * @param value The value
- * @return Object The previous value (if any), if node was present
- */
- public V put(Fqn<?> fqn, K key, V value) throws CacheException
- {
- GlobalTransaction tx = getCurrentTransaction();
- MethodCall m = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, value, true);
- return (V) invokeMethod(m, true);
- }
-
- /**
- * Removes the node from the cache.
- *
- * @param fqn The fully qualified name of the node.
- */
- public void remove(String fqn) throws CacheException
- {
- remove(Fqn.fromString(fqn));
- }
-
- /**
- * Removes the node from the cache.
- *
- * @param fqn The fully qualified name of the node.
- */
- public boolean remove(Fqn fqn) throws CacheException
- {
- GlobalTransaction tx = getCurrentTransaction();
- // special case if we are removing the root. Remove all children instead.
- if (fqn.isRoot())
- {
- boolean result = true;
- // we need to preserve options
- InvocationContext ctx = getInvocationContext();
- Option o = ctx.getOptionOverrides();
- for (Object childName : _getChildrenNames(fqn))
- {
- ctx.setOptionOverrides(o);
- result = remove(new Fqn<Object>(fqn, childName)) && result;
- }
-
- return result;
- }
- else
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, tx, fqn, true);
- Object retval = invokeMethod(m, true);
- return retval != null && (Boolean) retval;
- }
- }
-
- /**
- * Called by eviction policy provider. Note that eviction is done only in
- * local mode, that is, it doesn't replicate the node removal. This will
- * cause the replication nodes to not be synchronizing, which is fine since
- * the value will be fetched again when {@link #get} returns null. After
- * that, the contents will be in sync.
- *
- * @param fqn Will remove everythign assoicated with this fqn.
- * @throws CacheException
- */
- public void evict(Fqn fqn) throws CacheException
- {
- if (fqn.isRoot())
- {
- // special treatment for root eviction
- // we need to preserve options
- InvocationContext ctx = getInvocationContext();
- Option o = ctx.getOptionOverrides();
- for (Object childName : _getChildrenNames(fqn))
- {
- ctx.setOptionOverrides(o);
- evict(new Fqn<Object>(fqn, childName));
- }
- }
- else
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, fqn);
- invokeMethod(m, true);
- }
- }
-
- /**
- * Removes <code>key</code> from the node's hashmap
- *
- * @param fqn The fullly qualified name of the node
- * @param key The key to be removed
- * @return The previous value, or null if none was associated with the given key
- */
- public V remove(String fqn, K key) throws CacheException
- {
- return remove(Fqn.fromString(fqn), key);
- }
-
- /**
- * Removes <code>key</code> from the node's hashmap
- *
- * @param fqn The fullly qualified name of the node
- * @param key The key to be removed
- * @return The previous value, or null if none was associated with the given key
- */
- public V remove(Fqn<?> fqn, K key) throws CacheException
- {
- GlobalTransaction tx = getCurrentTransaction();
- MethodCall m = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal, tx, fqn, key, true);
- return (V) invokeMethod(m, true);
- }
-
- /**
- * Removes the keys and properties from a node.
- */
- public void removeData(String fqn) throws CacheException
- {
- removeData(Fqn.fromString(fqn));
- }
-
- /**
- * Removes the keys and properties from a named node.
- */
- public void removeData(Fqn fqn) throws CacheException
- {
- GlobalTransaction tx = getCurrentTransaction();
- MethodCall m = MethodCallFactory.create(MethodDeclarations.removeDataMethodLocal, tx, fqn, true);
- invokeMethod(m, true);
- }
-
- /**
- * Lock a given node (or the entire subtree starting at this node)
- * @param fqn The FQN of the node
- * @param owner The owner. This is simply a key into a hashtable, and can be anything, e.g.
- * a GlobalTransaction, the current thread, or a special object. If null, it is set to Thread.currentThread()
- * @param lock_type The type of lock (RO, RW). Needs to be of type DataNode.LOCK_TYPE_READ or DataNode.LOCK_TYPE_WRITE
- * @param lock_recursive If true, the entire subtree is locked, else only the given node
- * @throws CacheException If node doesn't exist, a NodeNotExistsException is throw. Other exceptions are
- * LockingException, TimeoutException and UpgradeException
- */
- // public void lock(Fqn fqn, Object owner, int lock_type, boolean lock_recursive) throws CacheException {
- //
- // }
-
- /**
- * Unlock a given node (or the entire subtree starting at this node)
- * @param fqn The FQN of the node
- * @param owner The owner. This is simply a key into a hashtable, and can be anything, e.g.
- * a GlobalTransaction, the current thread, or a special object. If null, it is set to Thread.currentThread()
- * @param unlock_recursive If true, the entire subtree is unlocked, else only the given node
- * @param force Release the lock even if we're not the owner
- */
- // public void unlock(Fqn fqn, Object owner, boolean unlock_recursive, boolean force) {
- //
- // }
-
- /**
- * Releases all locks for this node and the entire node subtree.
- */
- public void releaseAllLocks(String fqn)
- {
- releaseAllLocks(Fqn.fromString(fqn));
- }
-
- /**
- * Releases all locks for this node and the entire node subtree.
- */
- public void releaseAllLocks(Fqn fqn)
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.releaseAllLocksMethodLocal, fqn);
- try
- {
- invokeMethod(m, true);
- }
- catch (CacheException e)
- {
- log.error("failed releasing all locks for " + fqn, e);
- }
- }
-
- /**
- * Prints a representation of the node defined by <code>fqn</code>.
- * Output includes name, fqn and data.
- */
- public String print(String fqn)
- {
- return print(Fqn.fromString(fqn));
- }
-
- /**
- * Prints a representation of the node defined by <code>fqn</code>.
- * Output includes name, fqn and data.
- */
- public String print(Fqn fqn)
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.printMethodLocal, fqn);
- Object retval = null;
- try
- {
- retval = invokeMethod(m, true);
- }
- catch (Throwable e)
- {
- retval = e;
- }
- if (retval != null)
- {
- return retval.toString();
- }
- else
- {
- return "";
- }
- }
-
-
- /**
- * Returns all children of a given node.
- * Returns null of the parent node was not found, or if there are no
- * children.
- * The set is unmodifiable.
- *
- * @param fqn The fully qualified name of the node
- * @return Set A list of child names (as Strings)
- * @see #getChildrenNames(Fqn)
- */
- public Set getChildrenNames(String fqn) throws CacheException
- {
- return getChildrenNames(Fqn.fromString(fqn));
- }
-
- /**
- * Returns all children of a given node. Returns an empty set if there are no children.
- * The set is unmodifiable.
- *
- * @param fqn The fully qualified name of the node
- * @return Set an unmodifiable set of children names, Object.
- */
- public <E> Set<E> getChildrenNames(Fqn<E> fqn) throws CacheException
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.getChildrenNamesMethodLocal, fqn);
- Set<E> retval = null;
- retval = (Set<E>) invokeMethod(m, true);
- if (retval != null)
- retval = Collections.unmodifiableSet(new HashSet<E>(retval));
- else
- retval = Collections.emptySet();
- return retval;
- }
-
- public <E> Set<E> _getChildrenNames(Fqn<E> fqn) throws CacheException
- {
- NodeSPI<K, V> n = findNode(fqn);
- if (n == null) return null;
- Set childNames = new HashSet();
- Map childrenMap = n.getChildrenMapDirect();
- if (childrenMap == null || childrenMap.isEmpty()) return Collections.emptySet();
- Collection s = childrenMap.values();
- // prune deleted children - JBCACHE-1136
- for (Object c : s)
- {
- NodeSPI child = (NodeSPI) c;
- if (!child.isDeleted()) childNames.add(child.getFqn().getLastElement());
- }
- return childNames;
- }
-
- /**
- * Returns true if the FQN exists and the node has children.
- */
- public boolean hasChild(Fqn fqn)
- {
- if (fqn == null) return false;
-
- NodeSPI n = findNode(fqn);
- return n != null && n.hasChildrenDirect();
- }
-
- /**
- * Returns a debug string with few details.
- */
- public String toString()
- {
- return toString(true);
- }
-
-
- /**
- * Returns a debug string with optional details of contents.
- */
- public String toString(boolean details)
- {
- StringBuffer sb = new StringBuffer();
- int indent = 0;
-
- if (!details)
- {
- sb.append(getClass().getName()).append(" [").append(getNumberOfNodes()).append(" nodes, ");
- sb.append(getNumberOfLocksHeld()).append(" locks]");
- }
- else
- {
- if (root == null)
- return sb.toString();
- for (NodeSPI n : root.getChildrenDirect())
- {
- n.print(sb, indent);
- sb.append("\n");
- }
- }
- return sb.toString();
- }
-
-
- /**
- * Prints information about the contents of the nodes in the cache's current
- * in-memory state. Does not load any previously evicted nodes from a
- * cache loader, so evicted nodes will not be included.
- */
- public String printDetails()
- {
- StringBuffer sb = new StringBuffer();
- root.printDetails(sb, 0);
- sb.append("\n");
- return sb.toString();
- }
-
- /**
- * Returns lock information.
- */
- public String printLockInfo()
- {
- StringBuffer sb = new StringBuffer("\n");
- int indent = 0;
-
- for (NodeSPI n : root.getChildrenDirect())
- {
- n.getLock().printLockInfo(sb, indent);
- sb.append("\n");
- }
- return sb.toString();
- }
-
- /**
- * Returns the number of read or write locks held across the entire cache.
- */
- public int getNumberOfLocksHeld()
- {
- return numLocks(root);
- }
-
- private int numLocks(NodeSPI<K, V> n)
- {
- int num = 0;
- if (n.getLock().isLocked())
- {
- num++;
- }
- for (NodeSPI<K, V> cn : n.getChildrenDirect(true))
- {
- num += numLocks(cn);
- }
- return num;
- }
-
- /**
- * Returns an <em>approximation</em> of the total number of nodes in the
- * cache. Since this method doesn't acquire any locks, the number might be
- * incorrect, or the method might even throw a
- * ConcurrentModificationException
- */
- public int getNumberOfNodes()
- {
- return numNodes(root) - 1;
- }
-
- private int numNodes(NodeSPI<K, V> n)
- {
- int count = 1;// for n
- for (NodeSPI<K, V> child : n.getChildrenDirect())
- {
- count += numNodes(child);
- }
- return count;
- }
-
- /**
- * Returns an <em>approximation</em> of the total number of attributes in
- * the cache. Since this method doesn't acquire any locks, the number might
- * be incorrect, or the method might even throw a
- * ConcurrentModificationException
- */
- public int getNumberOfAttributes()
- {
- return numAttributes(root);
- }
-
- /**
- * Returns an <em>approximation</em> of the total number of attributes in
- * this sub cache.
- *
- * @see #getNumberOfAttributes
- */
- public int getNumberOfAttributes(Fqn fqn)
- {
- return numAttributes(findNode(fqn));
- }
-
- private int numAttributes(NodeSPI<K, V> n)
- {
- int count = 0;
- for (NodeSPI<K, V> child : n.getChildrenDirect())
- {
- count += numAttributes(child);
- }
- count += n.getDataDirect().size();
- return count;
- }
-
- /* ---------------------- Remote method calls -------------------- */
-
- /**
- * @param mbrs
- * @param method_call
- * @param synchronous
- * @param exclude_self
- * @param timeout
- * @return
- * @throws Exception
- * @deprecated Note this is due to be moved to an interceptor.
- */
- @Deprecated
- public List callRemoteMethods(List<Address> mbrs, MethodCall method_call,
- boolean synchronous, boolean exclude_self, long timeout)
- throws Exception
- {
- return callRemoteMethods(mbrs, method_call, synchronous ? GroupRequest.GET_ALL : GroupRequest.GET_NONE, exclude_self, timeout);
- }
-
-
- /**
- * Overloaded to allow a finer grained control over JGroups mode
- *
- * @param mbrs
- * @param method_call
- * @param mode
- * @param exclude_self
- * @param timeout
- * @return
- * @throws Exception
- * @deprecated Note this is due to be moved to an interceptor.
- */
- @Deprecated
- public List callRemoteMethods(List<Address> mbrs, MethodCall method_call, int mode, boolean exclude_self, long timeout)
- throws Exception
- {
- RspList rsps = null;
- Rsp rsp;
- List retval;
- Vector<Address> validMembers;
-
- if (disp == null)
- {
- return null;
- }
-
- validMembers = null;
- if (mbrs != null)
- validMembers = new Vector<Address>(mbrs);
- else
- {
- synchronized (members)
- {
- validMembers = new Vector<Address>(this.members);
- }
- }
-
- if (exclude_self && !validMembers.isEmpty())
- {
- Object local_addr = getLocalAddress();
- if (local_addr != null)
- {
- validMembers.remove(local_addr);
- }
- }
- if (validMembers.isEmpty())
- {
- if (log.isTraceEnabled())
- {
- log.trace("destination list is empty, discarding call");
- }
- return null;
- }
-
- if (log.isTraceEnabled())
- {
- log.trace("callRemoteMethods(): valid members are " + validMembers + " methods: " + method_call.getArgs()[0]);
- }
-
- if (channel.flushSupported())
- {
- flushBlockGate.await(configuration.getStateRetrievalTimeout());
- rsps = disp.callRemoteMethods(validMembers, method_call, mode, timeout, buddyManager != null && buddyManager.isEnabled());
- }
- else
- {
- rsps = disp.callRemoteMethods(validMembers, method_call, mode, timeout, buddyManager != null && buddyManager.isEnabled());
- }
-
- // a null response is 99% likely to be due to a marshalling problem - we throw a NSE, this needs to be changed when
- // JGroups supports http://jira.jboss.com/jira/browse/JGRP-193
- if (rsps == null)
- {
- // return null;
- throw new NotSerializableException("RpcDispatcher returned a null. This is most often caused by args for " + method_call + " not being serializable.");
- }
- if (mode == GroupRequest.GET_NONE)
- {
- return Collections.EMPTY_LIST;// async case
- }
-
- if (log.isTraceEnabled())
- {
- log.trace("(" + getLocalAddress() + "): responses for method " + method_call.getName() + ":\n" + rsps);
- }
-
- retval = new ArrayList(rsps.size());
- for (int i = 0; i < rsps.size(); i++)
- {
- rsp = (Rsp) rsps.elementAt(i);
- if (rsp.wasSuspected() || !rsp.wasReceived())
- {
- CacheException ex;
- if (rsp.wasSuspected())
- {
- ex = new SuspectException("Suspected member: " + rsp.getSender());
- }
- else
- {
- ex = new TimeoutException("Replication timeout for " + rsp.getSender());
- }
- retval.add(new ReplicationException("rsp=" + rsp, ex));
- }
- else
- {
- retval.add(rsp.getValue());
- }
- }
- return retval;
- }
-
- /**
- * @param members
- * @param method
- * @param args
- * @param synchronous
- * @param exclude_self
- * @param timeout
- * @return
- * @throws Exception
- * @deprecated Note this is due to be moved to an interceptor.
- */
- @Deprecated
- public List callRemoteMethods(List<Address> members, Method method, Object[] args,
- boolean synchronous, boolean exclude_self, long timeout)
- throws Exception
- {
- return callRemoteMethods(members, MethodCallFactory.create(method, args), synchronous, exclude_self, timeout);
- }
-
- /**
- * @param members
- * @param method_name
- * @param types
- * @param args
- * @param synchronous
- * @param exclude_self
- * @param timeout
- * @return
- * @throws Exception
- * @deprecated Note this is due to be moved to an interceptor.
- */
- @Deprecated
- public List callRemoteMethods(Vector<Address> members, String method_name,
- Class[] types, Object[] args,
- boolean synchronous, boolean exclude_self, long timeout)
- throws Exception
- {
- Method method = getClass().getDeclaredMethod(method_name, types);
- return callRemoteMethods(members, method, args, synchronous, exclude_self, timeout);
- }
-
- /* -------------------- End Remote method calls ------------------ */
-
- /* --------------------- Callbacks -------------------------- */
-
- /* ----- These are VERSIONED callbacks to facilitate JBCACHE-843. Also see docs/design/DataVersion.txt --- */
-
- public void _putForExternalRead(GlobalTransaction gtx, Fqn fqn, K key, V value, DataVersion dv) throws CacheException
- {
- _putForExternalRead(gtx, fqn, key, value);
- }
-
- public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, DataVersion dv) throws CacheException
- {
- _put(tx, fqn, data, create_undo_ops, false, dv);
- }
-
- public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, boolean erase_contents, DataVersion dv) throws CacheException
- {
- _put(tx, fqn, data, create_undo_ops, erase_contents);
- }
-
- public Object _put(GlobalTransaction tx, Fqn fqn, K key, V value, boolean create_undo_ops, DataVersion dv) throws CacheException
- {
- return _put(tx, fqn, key, value, create_undo_ops);
- }
-
- public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, DataVersion dv) throws CacheException
- {
- return _remove(tx, fqn, create_undo_ops, true);
- }
-
- public Object _remove(GlobalTransaction tx, Fqn fqn, K key, boolean create_undo_ops, DataVersion dv) throws CacheException
- {
- return _remove(tx, fqn, key, create_undo_ops);
- }
-
- public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, DataVersion dv) throws CacheException
- {
-
- _removeData(tx, fqn, create_undo_ops, true);
- }
-
- /* ----- End VERSIONED callbacks - Now for the NORMAL callbacks. -------- */
-
- /**
- * Internal put method.
- * Does the real work. Needs to acquire locks if accessing nodes, depending on
- * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
- * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
- * that were created to {@link TransactionEntry}'s node list and (c) create
- * {@link Modification}s and add them to {@link TransactionEntry}'s modification
- * list and (d) create compensating modifications to undo the changes in case
- * of a rollback
- *
- * @param fqn
- * @param data
- * @param create_undo_ops If true, undo operations will be created (default is true).
- * Otherwise they will not be created (used by rollback()).
- */
- public void _put(GlobalTransaction tx, String fqn, Map<K, V> data, boolean create_undo_ops)
- throws CacheException
- {
- _put(tx, Fqn.fromString(fqn), data, create_undo_ops);
- }
-
-
- /**
- * Internal put method.
- * Does the real work. Needs to acquire locks if accessing nodes, depending on
- * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
- * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
- * that were created to {@link TransactionEntry}'s node list and (c) create
- * {@link Modification}s and add them to {@link TransactionEntry}'s modification
- * list and (d) create compensating modifications to undo the changes in case
- * of a rollback
- *
- * @param fqn
- * @param data
- * @param create_undo_ops If true, undo operations will be created (default is true).
- * Otherwise they will not be created (used by rollback()).
- */
- public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops)
- throws CacheException
- {
- _put(tx, fqn, data, create_undo_ops, false);
- }
-
- /**
- * Internal put method.
- * Does the real work. Needs to acquire locks if accessing nodes, depending on
- * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
- * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
- * that were created to {@link TransactionEntry}'s node list and (c) create
- * {@link Modification}s and add them to {@link TransactionEntry}'s modification
- * list and (d) create compensating modifications to undo the changes in case
- * of a rollback
- *
- * @param fqn
- * @param data
- * @param create_undo_ops If true, undo operations will be created (default is true).
- * @param erase_contents Clear the existing hashmap before putting the new data into it
- * Otherwise they will not be created (used by rollback()).
- */
- public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, boolean erase_contents)
- throws CacheException
- {
- if (log.isTraceEnabled())
- {
- log.trace("_put(" + tx + ", \"" + fqn + "\", " + data + " undo=" + create_undo_ops + " erase=" + erase_contents + ")");
- }
- InvocationContext ctx = getInvocationContext();
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
- NodeSPI<K, V> n = findNodeCheck(tx, fqn);
- Map<K, V> rawData = n.getDataDirect();
- if (!isRollback) notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_MAP, rawData, ctx);
-
- // create a compensating method call (reverting the effect of
- // this modification) and put it into the TX's undo list.
- if (tx != null && create_undo_ops)
- {
- // erase and set to previous hashmap contents
- MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.putDataEraseMethodLocal, tx, fqn, new HashMap(rawData), false, true);
- tx_table.addUndoOperation(tx, undo_op);
- }
-
- if (erase_contents)
- n.clearDataDirect();
- n.putAllDirect(data);
-
- if (!isRollback)
- notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.PUT_MAP, n.getDataDirect(), ctx);
- }
-
- /**
- * Internal put method.
- *
- * @return Previous value (if any)
- */
- public Object _put(GlobalTransaction tx, String fqn, K key, V value, boolean create_undo_ops)
- throws CacheException
- {
- return _put(tx, Fqn.fromString(fqn), key, value, create_undo_ops);
- }
-
- private boolean checkIsRollingBack(Transaction tx)
- {
- try
- {
- return tx != null && (
- tx.getStatus() == javax.transaction.Status.STATUS_ROLLEDBACK ||
- tx.getStatus() == javax.transaction.Status.STATUS_ROLLING_BACK ||
- tx.getStatus() == javax.transaction.Status.STATUS_MARKED_ROLLBACK);
- }
- catch (Exception e)
- {
- // can't get a hold of a transaction - probably no tx rolling back
- return false;
- }
- }
-
- /**
- * Internal put method.
- *
- * @return Previous value (if any)
- */
- public Object _put(GlobalTransaction tx, Fqn fqn, K key, V value, boolean create_undo_ops)
- throws CacheException
- {
- if (log.isTraceEnabled())
- {
- log.trace(new StringBuffer("_put(").append(tx).append(", \"").
- append(fqn).append("\", k=").append(key).append(", v=").append(value).append(")"));
- }
-
-
- InvocationContext ctx = getInvocationContext();
- // if this is a rollback then don't fire notifications.
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
-
- NodeSPI<K, V> n = findNodeCheck(tx, fqn);
- Map<K, V> rawData = n.getDataDirect();
- if (!isRollback)
- notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_DATA, rawData, ctx);
-
- V old_value = n.putDirect(key, value);
-
- // create a compensating method call (reverting the effect of
- // this modification) and put it into the TX's undo list.
- if (tx != null && create_undo_ops)
- {
- MethodCall undo_op;
- if (old_value == null)
- {
- undo_op = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal, tx, fqn, key, false);
- }
- else
- {
- undo_op = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, old_value, false);
- }
- // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
- tx_table.addUndoOperation(tx, undo_op);
- }
-
- Map<K, V> newData = Collections.singletonMap(key, value);
- if (!isRollback)
- notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.PUT_DATA, newData, ctx);
- return old_value;
- }
-
- /**
- * Internal remove method.
- */
- public void _remove(GlobalTransaction tx, String fqn, boolean create_undo_ops) throws CacheException
- {
- _remove(tx, Fqn.fromString(fqn), create_undo_ops);
- }
-
- /**
- * Internal remove method.
- */
- public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops) throws CacheException
- {
- return _remove(tx, fqn, create_undo_ops, true);
- }
-
- public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent)
- throws CacheException
- {
- return _remove(tx, fqn, create_undo_ops, sendNodeEvent, false);
- }
-
- /**
- * Internal method to remove a node.
- *
- * @param tx
- * @param fqn
- * @param create_undo_ops
- * @param sendNodeEvent
- */
- public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction)
- throws CacheException
- {
- return _remove(tx, fqn, create_undo_ops, sendNodeEvent, eviction, null);
- }
-
- /**
- * Internal method to remove a node.
- * Performs a remove on a node, passing in a {@link DataVersion} which is used with optimistically locked nodes. Pass
- * in a null if optimistic locking is not used.
- *
- * @param tx
- * @param fqn
- * @param create_undo_ops
- * @param sendNodeEvent
- * @param eviction
- * @param version
- * @return true if the node was removed, false if not found
- * @throws CacheException
- */
- public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction, DataVersion version)
- throws CacheException
- {
-
- NodeSPI<K, V> n;
- NodeSPI<K, V> parent_node;
- MethodCall undo_op = null;
-
- if (log.isTraceEnabled())
- {
- log.trace("_remove(" + tx + ", \"" + fqn + "\", undo=" + create_undo_ops + ")");
- }
- InvocationContext ctx = getInvocationContext();
- // check if this is triggered by a rollback operation ...
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
- if (tx != null)
- {
- try
- {
- if (isRollback)
- {
- log.trace("This remove call is triggered by a transaction rollback, as a compensation operation. Do a realRemove() instead.");
- return realRemove(fqn, true);
- }
- }
- catch (Exception e)
- {
- // what do we do here?
- log.warn("Unable to get a hold of the transaction for a supposedly transactional call! This *may* result in stale locks!", e);
- }
- }
-
- // Find the node. This will add the temporarily created parent nodes to the TX's node list if tx != null)
- n = findNode(fqn, version);
- if (n == null)
- {
- if (log.isTraceEnabled())
- {
- log.trace("node " + fqn + " not found");
- }
- return false;
- }
-
- if (!isRollback)
- {
- if (eviction)
- {
- notifier.notifyNodeEvicted(fqn, true, ctx);
- }
- else
- {
- notifier.notifyNodeRemoved(fqn, true, n.getDataDirect(), ctx);
- }
- }
-
- parent_node = n.getParent();
- boolean found;
-
- // remove subtree from parent
- if (eviction || configuration.isNodeLockingOptimistic())
- {
- // if there is no parent node and the fqn is root, found == true otherwise found == false.
- found = parent_node == null ? fqn.isRoot() : parent_node.removeChildDirect(n.getFqn().getLastElement());
- }
- else
- {
- found = !n.isDeleted();
- n.markAsDeleted(true);
- }
-
- if (eviction && parent_node != null)
- {
- parent_node.setChildrenLoaded(false);
- }
-
- // release all locks for the entire subtree
- // n.getNodeSPI().getLock().releaseAll(tx != null ? tx : (Object) Thread.currentThread());
-
- // create a compensating method call (reverting the effect of
- // this modification) and put it into the TX's undo list.
- if (tx != null && create_undo_ops && !eviction)
- {
- undo_op = MethodCallFactory.create(MethodDeclarations.addChildMethodLocal, tx, parent_node.getFqn(), n.getFqn().getLastElement(), n, false);
-
- // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
- tx_table.addUndoOperation(tx, undo_op);
- }
-
- if (!isRollback)
- {
- if (eviction)
- {
- notifier.notifyNodeEvicted(fqn, false, ctx);
- }
- else
- {
- notifier.notifyNodeRemoved(fqn, false, null, ctx);
- }
- }
-
- return found;
- }
-
- /**
- * Internal method to remove a key.
- *
- * @param fqn
- * @param key
- * @return Object
- */
- public V _remove(GlobalTransaction tx, String fqn, K key, boolean create_undo_ops)
- throws CacheException
- {
- return _remove(tx, Fqn.fromString(fqn), key, create_undo_ops);
- }
-
- /**
- * Internal method to remove a key.
- *
- * @param fqn
- * @param key
- * @return Object
- */
- public V _remove(GlobalTransaction tx, Fqn fqn, K key, boolean create_undo_ops)
- throws CacheException
- {
- MethodCall undo_op = null;
- V old_value = null;
-
- if (log.isTraceEnabled())
- {
- log.trace("_remove(" + tx + ", \"" + fqn + "\", key=" + key + ")");
- }
-
- // Find the node. This will lock it (if <tt>locking</tt> is true) and
- // add the temporarily created parent nodes to the TX's node list if tx != null)
- NodeSPI<K, V> n = findNode(fqn);
- if (n == null)
- {
- log.warn("node " + fqn + " not found");
- return null;
- }
- InvocationContext ctx = getInvocationContext();
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
- if (!isRollback)
- notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, n.getDataDirect(), ctx);
-
- old_value = n.removeDirect(key);
-
- // create a compensating method call (reverting the effect of
- // this modification) and put it into the TX's undo list.
- if (tx != null && create_undo_ops && old_value != null)
- {
- undo_op = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, old_value, false);
- // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
- tx_table.addUndoOperation(tx, undo_op);
- }
-
- Map<K, V> removedData = Collections.singletonMap(key, old_value);
- if (!isRollback)
- notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, removedData, ctx);
-
- return old_value;
- }
-
- /**
- * Internal method to remove data from a node.
- */
- public void _removeData(GlobalTransaction tx, String fqn, boolean create_undo_ops)
- throws CacheException
- {
- _removeData(tx, Fqn.fromString(fqn), create_undo_ops);
- }
-
- /**
- * Internal method to remove data from a node.
- */
- public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops)
- throws CacheException
- {
- _removeData(tx, fqn, create_undo_ops, true);
- }
-
- /**
- * Internal method to remove data from a node.
- */
- public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent)
- throws CacheException
- {
- _removeData(tx, fqn, create_undo_ops, sendNodeEvent, false);
- }
-
- /**
- * Internal method to remove data from a node.
- */
- public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction)
- throws CacheException
- {
- _removeData(tx, fqn, create_undo_ops, sendNodeEvent, eviction, null);
- }
-
- /**
- * Internal method to remove data from a node.
- */
- public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction, DataVersion version)
- throws CacheException
- {
- MethodCall undo_op = null;
-
- if (log.isTraceEnabled())
- {
- log.trace("_removeData(" + tx + ", \"" + fqn + "\")");
- }
-
- // Find the node. This will lock it (if <tt>locking</tt> is true) and
- // add the temporarily created parent nodes to the TX's node list if tx != null)
- NodeSPI n = findNode(fqn, version);
- if (n == null)
- {
- log.warn("node " + fqn + " not found");
- return;
- }
-
- Map<K, V> data = n.getDataDirect();
- InvocationContext ctx = getInvocationContext();
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
- // create a compensating method call (reverting the effect of
- // this modification) and put it into the TX's undo list.
- if (tx != null && create_undo_ops && !eviction)
- {
- if (!data.isEmpty())
- {
- undo_op = MethodCallFactory.create(MethodDeclarations.putDataMethodLocal,
- tx, fqn, new HashMap<K,V>(data), false);
- }
- }
-
- if (!isRollback)
- {
- if (eviction)
- {
- notifier.notifyNodeEvicted(fqn, true, ctx);
- }
- else
- {
- notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
- }
- }
-
- n.clearDataDirect();
- if (eviction)
- {
- n.setDataLoaded(false);
- }
-
- if (!isRollback)
- {
- if (sendNodeEvent)
- {
- notifier.notifyNodeVisited(fqn, false, ctx);
- }
- else
- {// FIXME Bela did this so GUI view can refresh the view after node is evicted. But this breaks eviction policy, especially AOP!!!!
- if (eviction)
- {
- notifier.notifyNodeEvicted(fqn, false, ctx);
- }
- else
- {
- notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
- }
- }
- }
-
- // put undo-op in TX' undo-operations list (needed to rollback TX)
- if (tx != null && create_undo_ops)
- {
- tx_table.addUndoOperation(tx, undo_op);
- }
- }
-
-
- /**
- * Internal evict method called by eviction policy provider.
- *
- * @param fqn removes everything assoicated with this FQN
- * @return <code>true</code> if the node has been completely removed,
- * <code>false</code> if only the data map was removed, due
- * to the presence of children
- * @throws CacheException
- */
- public boolean _evict(Fqn fqn) throws CacheException
- {
- if (!exists(fqn))
- return true;// node does not exist. Maybe it has been recursively removed.
- // use remove method now if there is a child node. Otherwise, it is removed
- boolean create_undo_ops = false;
- boolean sendNodeEvent = false;
- boolean eviction = true;
- if (log.isTraceEnabled())
- {
- log.trace("_evict(" + fqn + ")");
- }
- if (hasChild(fqn))
- {
- _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction);
- return false;
- }
- else
- {
- _remove(null, fqn, create_undo_ops, sendNodeEvent, eviction);
- return true;
- }
- }
-
- /**
- * Internal evict method called by eviction policy provider.
- *
- * @param fqn
- * @param version
- * @return <code>true</code> if the node has been completely removed,
- * <code>false</code> if only the data map was removed, due
- * to the presence of children
- * @throws CacheException
- */
- public boolean _evict(Fqn fqn, DataVersion version) throws CacheException
- {
- if (!exists(fqn))
- return true;// node does not exist
-
- boolean create_undo_ops = false;
- boolean sendNodeEvent = false;
- boolean eviction = true;
- if (log.isTraceEnabled())
- {
- log.trace("_evict(" + fqn + ", " + version + ")");
- }
- if (hasChild(fqn))
- {
- _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction, version);
- return false;
- }
- else
- {
- _remove(null, fqn, create_undo_ops, sendNodeEvent, eviction, version);
- return true;
- }
- }
-
- /**
- * Evicts a key/value pair from a node's attributes. Note that this is <em>local</em>, will not be replicated.
- * @param fqn
- * @param key
- * @throws CacheException
- */
- // public void _evict(Fqn fqn, Object key) throws CacheException {
- // if(!exists(fqn)) return;
- // boolean create_undo_ops = false;
- // boolean sendNodeEvent = false;
- // boolean eviction=true;
- // _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction);
- // }
-
-
- /**
- * Compensating method to {@link #_remove(GlobalTransaction,Fqn,boolean)}.
- */
- public void _addChild(GlobalTransaction gtx, Fqn parent_fqn, Object child_name, Node cn, boolean undoOps)
- throws CacheException
- {
- NodeSPI childNode = (NodeSPI) cn;
- if (log.isTraceEnabled())
- {
- log.trace("_addChild(\"" + parent_fqn + "\", \"" + child_name + "\", node=" + childNode + ")");
- }
-
- if (parent_fqn == null || child_name == null || childNode == null)
- {
- log.error("parent_fqn or child_name or childNode was null");
- return;
- }
- NodeSPI parentNode = findNode(parent_fqn);
- if (parentNode == null)
- {
- log.warn("node " + parent_fqn + " not found");
- return;
- }
- InvocationContext ctx = getInvocationContext();
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
- Fqn fqn = new Fqn(parent_fqn, child_name);
- if (!isRollback) notifier.notifyNodeCreated(fqn, true, ctx);
- parentNode.addChild(child_name, childNode);
-
- childNode.markAsDeleted(false, true);
-
- if (gtx != null && undoOps)
- {
- // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
- tx_table.addUndoOperation(gtx, MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, gtx, fqn, false));
- }
-
- if (!isRollback) notifier.notifyNodeCreated(fqn, false, ctx);
- }
-
-
- /**
- * Replicates changes across to other nodes in the cluster. Invoked by the
- * ReplicationInterceptor. Calls need to be forwarded to the
- * ReplicationInterceptor in this interceptor chain. This method will later
- * be moved entirely into the ReplicationInterceptor.
- */
- public Object _replicate(MethodCall method_call) throws Throwable
- {
- try
- {
- Object retVal = invokeMethod(method_call, false);
- // we only need to return values for a set of remote calls; not every call.
- if (MethodDeclarations.returnValueForRemoteCall(method_call.getMethodId()))
- {
- return retVal;
- }
- else
- {
- return null;
- }
- }
- catch (Throwable ex)
- {
- log.warn("replication failure with method_call " + method_call + " exception", ex);
- throw ex;
- }
- }
-
- /**
- * Replicates a list of method calls.
- */
- public void _replicate(List<MethodCall> methodCalls) throws Throwable
- {
- for (MethodCall methodCall : methodCalls) _replicate(methodCall);
- }
-
- /**
- * A 'clustered get' call, called from a remote ClusteredCacheLoader.
- *
- * @return a List containing 2 elements: (true or false) and a value (Object). If buddy replication
- * is used one further element is added - an Fqn of the backup subtree in which this node may be found.
- */
- public List _clusteredGet(MethodCall methodCall, Boolean searchBackupSubtrees)
- {
- MethodCall call = methodCall;
- if (log.isTraceEnabled()) log.trace("Clustered Get called with params: " + call + ", " + searchBackupSubtrees);
- Method m = call.getMethod();
- Object[] args = call.getArgs();
-
- Object callResults = null;
-
- try
- {
- Fqn fqn = (Fqn) args[0];
-
- if (log.isTraceEnabled()) log.trace("Clustered get: invoking call " + m + " with Fqn " + fqn);
- callResults = m.invoke(this, args);
- boolean found = validResult(callResults, call, fqn);
- if (log.isTraceEnabled()) log.trace("Got result " + callResults + ", found=" + found);
- if (found && callResults == null) callResults = createEmptyResults(call);
- }
- catch (Exception e)
- {
- log.warn("Problems processing clusteredGet call", e);
- }
-
- List<Object> results = new ArrayList<Object>(2);
- if (callResults != null)
- {
- results.add(true);
- results.add(callResults);
- }
- else
- {
- results.add(false);
- results.add(null);
- }
- return results;
- }
-
- /**
- * Used with buddy replication's data gravitation interceptor. If marshalling is necessary, ensure that the cache is
- * configured to use {@link org.jboss.cache.config.Configuration#useRegionBasedMarshalling} and the {@link org.jboss.cache.Region}
- * pertaining to the Fqn passed in is activated, and has an appropriate ClassLoader.
- *
- * @param fqn the fqn to gravitate
- * @param searchSubtrees if true, buddy backup subtrees are searched and if false, they are not.
- * @return a GravitateResult which contains the data for the gravitation
- */
- public GravitateResult gravitateData(Fqn fqn, boolean searchSubtrees)
- throws CacheException
- {
- // we need to get the state for this Fqn and its sub-nodes.
-
- // for now, perform a very simple series of getData calls.
- InvocationContext ctx = getInvocationContext();
-
- log.debug("*****************>>>>> " + printLockInfo());
-
- try
- {
- ctx.setOriginLocal(false);
-
- NodeSPI<K, V> actualNode = findNode(fqn);
- Fqn backupNodeFqn = null;
- if (actualNode == null && searchSubtrees)
- {
- NodeSPI backupSubtree = findNode(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
- if (backupSubtree != null)
- {
- // need to loop through backupSubtree's children
- Set childNames = backupSubtree.getChildrenNamesDirect();
- if (childNames != null)
- {
- for (Object childName : childNames)
- {
- // childName is the name of a buddy group since all child names in this
- // collection are direct children of BUDDY_BACKUP_SUBTREE_FQN
- backupNodeFqn = BuddyManager.getBackupFqn(childName.toString(), fqn);
- actualNode = findNode(backupNodeFqn);
- if (actualNode != null) break;
- }
- }
- /*Map children = backupSubtree.getChildrenMapDirect();
- if (children != null)
- {
- Iterator childNames = children.keySet().iterator();
- while (childNames.hasNext() && actualNode == null)
- {
- backupNodeFqn = BuddyManager.getBackupFqn(childNames.next().toString(), fqn);
- actualNode = findNode(backupNodeFqn);
- }
- }*/
- }
- }
-
- if (actualNode == null)
- {
- return GravitateResult.noDataFound();
- }
-
- if (backupNodeFqn == null && searchSubtrees)
- {
- backupNodeFqn = BuddyManager.getBackupFqn(BuddyManager.getGroupNameFromAddress(getLocalAddress()), fqn);
- }
-
- List<NodeData> list = getNodeData(new LinkedList<NodeData>(), actualNode);
-
- return GravitateResult.subtreeResult(list, backupNodeFqn);
- }
- finally
- {
- ctx.setOriginLocal(true);
- }
- }
-
- private List<NodeData> getNodeData(List<NodeData> list, NodeSPI<K, V> node)
- {
- NodeData data = new NodeData(BuddyManager.getActualFqn(node.getFqn()), node.getDataDirect());
- list.add(data);
- for (NodeSPI<K, V> childNode : node.getChildrenDirect())
- {
- getNodeData(list, childNode);
- }
- return list;
- }
-
- // ------------- start: buddy replication specific 'lifecycle' method calls
-
- public void _remoteAssignToBuddyGroup(BuddyGroup group, Map<Fqn, byte[]> state) throws Exception
- {
- if (buddyManager != null)
- buddyManager.handleAssignToBuddyGroup(group, state);
- else if (log.isWarnEnabled())
- log.warn("Received assignToBuddyGroup call from group owner [" + group.getDataOwner() + "] but buddy replication is not enabled on this node!");
- }
-
- public void _remoteRemoveFromBuddyGroup(String groupName) throws BuddyNotInitException
- {
- if (buddyManager != null)
- buddyManager.handleRemoveFromBuddyGroup(groupName);
- else if (log.isWarnEnabled())
- log.warn("Received removeFromBuddyGroup call for group name [" + groupName + "] but buddy replication is not enabled on this node!");
-
- }
-
- public void _remoteAnnounceBuddyPoolName(Address address, String buddyPoolName)
- {
- if (buddyManager != null)
- buddyManager.handlePoolNameBroadcast(address, buddyPoolName);
- else if (log.isWarnEnabled())
- log.warn("Received annouceBuddyPoolName call from [" + address + "] but buddy replication is not enabled on this node!");
- }
-
- public void _dataGravitationCleanup(GlobalTransaction gtx, Fqn primary, Fqn backup) throws Exception
- {
- MethodCall primaryDataCleanup, backupDataCleanup;
- if (buddyManager.isDataGravitationRemoveOnFind())
- {
- if (log.isTraceEnabled())
- log.trace("DataGravitationCleanup: Removing primary (" + primary + ") and backup (" + backup + ")");
- primaryDataCleanup = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, null, primary, false);
- backupDataCleanup = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, null, backup, false);
- }
- else
- {
- if (log.isTraceEnabled())
- log.trace("DataGravitationCleanup: Evicting primary (" + primary + ") and backup (" + backup + ")");
- primaryDataCleanup = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, primary);
- backupDataCleanup = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, backup);
- }
-
- invokeMethod(primaryDataCleanup, true);
- invokeMethod(backupDataCleanup, true);
- }
-
- // ------------- end: buddy replication specific 'lifecycle' method calls
-
-
- /**
- * Returns true if the call results returned a valid result.
- */
- private boolean validResult(Object callResults, MethodCall mc, Fqn fqn)
- {
- switch (mc.getMethodId())
- {
- case MethodDeclarations.getDataMapMethodLocal_id:
- case MethodDeclarations.getChildrenNamesMethodLocal_id:
- return callResults != null || exists(fqn);
- case MethodDeclarations.existsMethod_id:
- return (Boolean) callResults;
- default:
- return false;
- }
- }
-
- /**
- * Creates an empty Collection class based on the return type of the method called.
- */
- private Object createEmptyResults(MethodCall mc)
- {
- switch (mc.getMethodId())
- {
- case MethodDeclarations.getDataMapMethodLocal_id:
- case MethodDeclarations.getChildrenNamesMethodLocal_id:
- return Collections.emptyMap();
- default:
- return null;
- }
- }
-
- /**
- * Releases all locks for a FQN.
- */
- public void _releaseAllLocks(Fqn fqn)
- {
- NodeSPI<K, V> n;
-
- try
- {
- n = findNode(fqn);
- if (n == null)
- {
- log.error("releaseAllLocks(): node " + fqn + " not found");
- return;
- }
- releaseAll(n);
- }
- catch (Throwable t)
- {
- log.error("releaseAllLocks(): failed", t);
- }
- }
-
- private void releaseAll(NodeSPI<K, V> n)
- {
- for (NodeSPI<K, V> child : n.getChildrenDirect())
- {
- releaseAll(child);
- }
- n.getLock().releaseAll();
- }
-
-
- /**
- * Finds and returns the string value for the Fqn.
- * Returns null if not found or upon error.
- */
- public String _print(Fqn fqn)
- {
- try
- {
- Node n = findNode(fqn);
- if (n == null) return null;
- return n.toString();
- }
- catch (Throwable t)
- {
- return null;
- }
- }
-
- /**
- * Should not be called.
- */
- public void _lock(Fqn fqn, NodeLock.LockType lock_type, boolean recursive)
- throws TimeoutException, LockingException
- {
- throw new UnsupportedOperationException("method _lock() should not be invoked on CacheImpl");
- }
-
- /**
- * Throws UnsupportedOperationException.
- */
- public void optimisticPrepare(GlobalTransaction gtx, List modifications, Map data, Address address, boolean onePhaseCommit)
- {
- throw new UnsupportedOperationException("optimisticPrepare() should not be called on CacheImpl directly");
- }
-
- /**
- * Throws UnsupportedOperationException.
- */
- public void prepare(GlobalTransaction global_tx, List modifications, Address coord, boolean onePhaseCommit)
- {
- throw new UnsupportedOperationException("prepare() should not be called on CacheImpl directly");
- }
-
- /**
- * Throws UnsupportedOperationException.
- */
- public void commit(GlobalTransaction tx)
- {
- throw new UnsupportedOperationException("commit() should not be called on CacheImpl directly");
- }
-
- /**
- * Throws UnsupportedOperationException.
- */
- public void rollback(GlobalTransaction tx)//, Boolean hasMods)
- {
- throw new UnsupportedOperationException("rollback() should not be called on CacheImpl directly");
- }
-
- /* ----------------- End of Callbacks ---------------------- */
-
- /**
- * Adds an undo operatoin to the transaction table.
- */
- public void addUndoOperation(GlobalTransaction gtx, MethodCall undo_op)
- {
- tx_table.addUndoOperation(gtx, undo_op);
- }
-
- /**
- * Returns the CacheLoaderManager.
- */
- public CacheLoaderManager getCacheLoaderManager()
- {
- return cacheLoaderManager;
- }
-
- /**
- * Sets the CacheLoaderManager.
- */
- public void setCacheLoaderManager(CacheLoaderManager cacheLoaderManager)
- {
- this.cacheLoaderManager = cacheLoaderManager;
- }
-
- public void setConfiguration(Configuration configuration)
- {
- this.configuration = configuration;
- configuration.setCacheImpl(this);
- }
-
- /**
- * @return an instance of {@link Notifier} which has been configured with this instance of CacheImpl.
- */
- public Notifier getNotifier()
- {
- return notifier;
- }
-
- public InvocationContext getInvocationContext()
- {
- InvocationContext ctx = invocationContextContainer.get();
- if (ctx == null)
- {
- ctx = new InvocationContext();
- invocationContextContainer.set(ctx);
- }
- return ctx;
- }
-
- public void setInvocationContext(InvocationContext ctx)
- {
- invocationContextContainer.set(ctx);
- }
-
- /**
- * New API to efficiently relocate a node
- *
- * @since 2.0.0
- */
- public void move(Fqn<?> nodeToMove, Fqn<?> newParent)
- {
- // this needs to be passed up the interceptor chain
- MethodCall m = MethodCallFactory.create(MethodDeclarations.moveMethodLocal, nodeToMove, newParent);
- invokeMethod(m, true);
- }
-
- /**
- * Called by reflection
- *
- * @param newParentFqn
- * @param nodeToMoveFqn
- */
- public void _move(Fqn nodeToMoveFqn, Fqn newParentFqn)
- {
- // the actual move algorithm.
- NodeSPI<K, V> newParent = findNode(newParentFqn);
-
- if (newParent == null)
- {
- throw new NodeNotExistsException("New parent node " + newParentFqn + " does not exist when attempting to move node!!");
- }
-
- NodeSPI<K, V> node = findNode(nodeToMoveFqn);
-
- if (node == null)
- {
- throw new NodeNotExistsException("Node " + nodeToMoveFqn + " does not exist when attempting to move node!!");
- }
-
- NodeSPI oldParent = node.getParent();
- Object nodeName = nodeToMoveFqn.getLastElement();
-
- // now that we have the parent and target nodes:
- // first correct the pointers at the pruning point
- oldParent.removeChildDirect(nodeName);
- newParent.addChild(nodeName, node);
- InvocationContext ctx = getInvocationContext();
- // parent pointer is calculated on the fly using Fqns.
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
-
- // notify
- if (!isRollback)
- notifier.notifyNodeMoved(nodeToMoveFqn, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), true, ctx);
-
- // now adjust Fqns of node and all children.
- moveFqns(node, newParent.getFqn());
-
- if (!isRollback)
- notifier.notifyNodeMoved(nodeToMoveFqn, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), false, ctx);
-
- // now register an undo op
- if (ctx.getTransaction() != null)
- {
- MethodCall undo = MethodCallFactory.create(MethodDeclarations.moveMethodLocal, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), oldParent.getFqn());
- tx_table.addUndoOperation(ctx.getGlobalTransaction(), undo);
- }
- }
-
- public void _block()
- {
- //intentionally empty, used only for reflection in MethodDeclarations.blockChannelLocal
- }
-
- public void _unblock()
- {
- //intentionally empty, used only for reflection in MethodDeclarations.unblockChannelLocal
- }
-
- private void moveFqns(NodeSPI node, Fqn newBase)
- {
- Fqn newFqn = new Fqn(newBase, node.getFqn().getLastElement());
- node.setFqn(newFqn);
- }
-
- /**
- * Set our log category to include our clusterName, if we have one.
- */
- private void configureLogCategory()
- {
- StringBuffer category = new StringBuffer(getClass().getName());
- if (configuration != null)
- {
- String clusterName = configuration.getClusterName();
- if (clusterName != null)
- {
- category.append('.');
- category.append(clusterName);
- }
- }
-
- log = LogFactory.getLog(category.toString());
- }
-
- /**
- * Kills the JGroups channel; an unclean channel disconnect
- */
- public void killChannel()
- {
- if (channel != null)
- {
- channel.close();
- channel.disconnect();
- }
- }
-
- protected class MessageListenerAdaptor implements ExtendedMessageListener
- {
- /**
- * Reference to an exception that was raised during
- * state installation on this node.
- */
- protected volatile Exception setStateException;
- private final Object stateLock = new Object();
-
- protected MessageListenerAdaptor()
- {
- }
-
- public void waitForState() throws Exception
- {
- synchronized (stateLock)
- {
- while (!isStateSet)
- {
- if (setStateException != null)
- {
- throw setStateException;
- }
-
- try
- {
- stateLock.wait();
- }
- catch (InterruptedException iex)
- {
- }
- }
- }
- }
-
- protected void stateReceivedSuccess()
- {
- isStateSet = true;
- setStateException = null;
- }
-
- protected void stateReceivingFailed(Throwable t)
- {
- if (t instanceof CacheException)
- {
- log.debug(t);
- }
- else
- {
- log.error("failed setting state", t);
- }
- if (t instanceof Exception)
- {
- setStateException = (Exception) t;
- }
- else
- {
- setStateException = new Exception(t);
- }
- }
-
- protected void stateProducingFailed(Throwable t)
- {
- if (t instanceof CacheException)
- {
- log.debug(t);
- }
- else
- {
- log.error("Caught " + t.getClass().getName()
- + " while responding to state transfer request", t);
- }
- }
-
- /**
- * Callback, does nothing.
- */
- public void receive(Message msg)
- {
- }
-
- public byte[] getState()
- {
- MarshalledValueOutputStream out = null;
- byte[] result = null;
- ExposedByteArrayOutputStream baos = new ExposedByteArrayOutputStream(16 * 1024);
- try
- {
- out = new MarshalledValueOutputStream(baos);
-
- getStateTransferManager().getState(out, Fqn.ROOT, configuration.getStateRetrievalTimeout(), true, true);
- }
- catch (Throwable t)
- {
- stateProducingFailed(t);
- }
- finally
- {
- result = baos.getRawBuffer();
- Util.close(out);
- }
- return result;
- }
-
- public void setState(byte[] new_state)
- {
- if (new_state == null)
- {
- log.debug("transferred state is null (may be first member in cluster)");
- return;
- }
- ByteArrayInputStream bais = new ByteArrayInputStream(new_state);
- MarshalledValueInputStream in = null;
- try
- {
- in = new MarshalledValueInputStream(bais);
- getStateTransferManager().setState(in, Fqn.ROOT);
- stateReceivedSuccess();
- }
- catch (Throwable t)
- {
- stateReceivingFailed(t);
- }
- finally
- {
- Util.close(in);
- synchronized (stateLock)
- {
- // Notify wait that state has been set.
- stateLock.notifyAll();
- }
- }
- }
-
- public byte[] getState(String state_id)
- {
- MarshalledValueOutputStream out = null;
- String sourceRoot = state_id;
- byte[] result = null;
-
- boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
- if (hasDifferentSourceAndIntegrationRoots)
- {
- sourceRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[0];
- }
-
- ExposedByteArrayOutputStream baos = new ExposedByteArrayOutputStream(16 * 1024);
- try
- {
- out = new MarshalledValueOutputStream(baos);
-
- getStateTransferManager().getState(out, Fqn.fromString(sourceRoot),
- configuration.getStateRetrievalTimeout(), true, true);
- }
- catch (Throwable t)
- {
- stateProducingFailed(t);
- }
- finally
- {
- result = baos.getRawBuffer();
- Util.close(out);
- }
- return result;
- }
-
- public void getState(OutputStream ostream)
- {
- MarshalledValueOutputStream out = null;
- try
- {
- out = new MarshalledValueOutputStream(ostream);
- getStateTransferManager().getState(out, Fqn.ROOT, configuration.getStateRetrievalTimeout(), true, true);
- }
- catch (Throwable t)
- {
- stateProducingFailed(t);
- }
- finally
- {
- Util.close(out);
- }
- }
-
- public void getState(String state_id, OutputStream ostream)
- {
- String sourceRoot = state_id;
- MarshalledValueOutputStream out = null;
- boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
- if (hasDifferentSourceAndIntegrationRoots)
- {
- sourceRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[0];
- }
- try
- {
- out = new MarshalledValueOutputStream(ostream);
- getStateTransferManager().getState(out, Fqn.fromString(sourceRoot), configuration.getStateRetrievalTimeout(), true, true);
- }
- catch (Throwable t)
- {
- stateProducingFailed(t);
- }
- finally
- {
- Util.close(out);
- }
- }
-
- public void setState(InputStream istream)
- {
- if (istream == null)
- {
- log.debug("stream is null (may be first member in cluster)");
- return;
- }
- MarshalledValueInputStream in = null;
- try
- {
- in = new MarshalledValueInputStream(istream);
- getStateTransferManager().setState(in, Fqn.ROOT);
- stateReceivedSuccess();
- }
- catch (Throwable t)
- {
- stateReceivingFailed(t);
- }
- finally
- {
- Util.close(in);
- synchronized (stateLock)
- {
- // Notify wait that state has been set.
- stateLock.notifyAll();
- }
- }
- }
-
- public void setState(String state_id, byte[] state)
- {
- if (state == null)
- {
- log.debug("partial transferred state is null");
- return;
- }
-
- MarshalledValueInputStream in = null;
- String targetRoot = state_id;
- boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
- if (hasDifferentSourceAndIntegrationRoots)
- {
- targetRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[1];
- }
- try
- {
- log.debug("Setting received partial state for subroot " + state_id);
- Fqn subroot = Fqn.fromString(targetRoot);
-// Region region = regionManager.getRegion(subroot, false);
-// ClassLoader cl = null;
-// if (region != null)
-// {
-// // If a classloader is registered for the node's region, use it
-// cl = region.getClassLoader();
-// }
- ByteArrayInputStream bais = new ByteArrayInputStream(state);
- in = new MarshalledValueInputStream(bais);
- //getStateTransferManager().setState(in, subroot, cl);
- getStateTransferManager().setState(in, subroot);
- stateReceivedSuccess();
- }
- catch (Throwable t)
- {
- stateReceivingFailed(t);
- }
- finally
- {
- Util.close(in);
- synchronized (stateLock)
- {
- // Notify wait that state has been set.
- stateLock.notifyAll();
- }
- }
- }
-
- public void setState(String state_id, InputStream istream)
- {
- String targetRoot = state_id;
- MarshalledValueInputStream in = null;
- boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
- if (hasDifferentSourceAndIntegrationRoots)
- {
- targetRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[1];
- }
- if (istream == null)
- {
- log.debug("stream is null (may be first member in cluster). State is not set");
- return;
- }
-
- try
- {
- log.debug("Setting received partial state for subroot " + state_id);
- in = new MarshalledValueInputStream(istream);
- Fqn subroot = Fqn.fromString(targetRoot);
-// Region region = regionManager.getRegion(subroot, false);
-// ClassLoader cl = null;
-// if (region != null)
-// {
-// // If a classloader is registered for the node's region, use it
-// cl = region.getClassLoader();
-// }
- //getStateTransferManager().setState(in, subroot, cl);
- getStateTransferManager().setState(in, subroot);
- stateReceivedSuccess();
- }
- catch (Throwable t)
- {
- stateReceivingFailed(t);
- }
- finally
- {
- Util.close(in);
- synchronized (stateLock)
- {
- // Notify wait that state has been set.
- stateLock.notifyAll();
- }
- }
- }
- }
-
- /*-------------------- End of MessageListener ----------------------*/
-
- /*----------------------- MembershipListener ------------------------*/
-
- protected class MembershipListenerAdaptor implements ExtendedMembershipListener
- {
-
- public void viewAccepted(View new_view)
- {
- Vector<Address> new_mbrs = new_view.getMembers();
- if (log.isInfoEnabled()) log.info("viewAccepted(): " + new_view);
- synchronized (members)
- {
- boolean needNotification = false;
- if (new_mbrs != null)
- {
- // Determine what members have been removed
- // and roll back any tx and break any locks
- Vector<Address> removed = new Vector<Address>(members);
- removed.removeAll(new_mbrs);
- removeLocksForDeadMembers(root, removed);
-
- members.removeAllElements();
- members.addAll(new_mbrs);
-
- needNotification = true;
- }
-
- // Now that we have a view, figure out if we are the coordinator
- coordinator = (members.size() != 0 && members.get(0).equals(getLocalAddress()));
-
- // now notify listeners - *after* updating the coordinator. - JBCACHE-662
- if (needNotification && notifier != null)
- {
- InvocationContext ctx = getInvocationContext();
- notifier.notifyViewChange(new_view, ctx);
- }
-
- // Wake up any threads that are waiting to know who the members
- // are so they can figure out who the coordinator is
- members.notifyAll();
- }
- }
-
- /**
- * Called when a member is suspected.
- */
- public void suspect(Address suspected_mbr)
- {
- }
-
- /**
- * Indicates that a channel has received a BLOCK event from FLUSH protocol.
- */
- public void block()
- {
- flushBlockGate.close();
- if (log.isDebugEnabled())
- {
- log.debug("Block received at " + getLocalAddress());
- }
- MethodCall m = MethodCallFactory.create(MethodDeclarations.blockChannelLocal);
- getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
- invokeMethod(m, true);
- if (log.isDebugEnabled())
- {
- log.debug("Block processed at " + getLocalAddress());
- }
- }
-
- /**
- * Indicates that a channel has received a UNBLOCK event from FLUSH protocol.
- */
- public void unblock()
- {
- if (log.isDebugEnabled())
- {
- log.debug("UnBlock received at " + getLocalAddress());
- }
- MethodCall m = MethodCallFactory.create(MethodDeclarations.unblockChannelLocal);
- getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
- invokeMethod(m, true);
- if (log.isDebugEnabled())
- {
- log.debug("UnBlock processed at " + getLocalAddress());
- }
- flushBlockGate.open();
- }
-
- }
-
- /*------------------- End of MembershipListener ----------------------*/
-
- /* ------------------------------ Private methods --------------------------- */
-
- /**
- * Returns the transaction associated with the current thread. We get the
- * initial context and a reference to the TransactionManager to get the
- * transaction. This method is used by {@link #getCurrentTransaction()}
- */
- protected Transaction getLocalTransaction()
- {
- if (tm == null)
- {
- return null;
- }
- try
- {
- return tm.getTransaction();
- }
- catch (Throwable t)
- {
- return null;
- }
- }
-
-
- /**
- * Returns true if transaction is ACTIVE or PREPARING, false otherwise.
- */
- private boolean isValid(Transaction tx)
- {
- if (tx == null) return false;
- int status = -1;
- try
- {
- status = tx.getStatus();
- return status == Status.STATUS_ACTIVE || status == Status.STATUS_PREPARING;
- }
- catch (SystemException e)
- {
- log.error("failed getting transaction status", e);
- return false;
- }
- }
-
-
- /**
- * Returns the transaction associated with the current thread.
- * If a local transaction exists, but doesn't yet have a mapping to a
- * GlobalTransaction, a new GlobalTransaction will be created and mapped to
- * the local transaction. Note that if a local transaction exists, but is
- * not ACTIVE or PREPARING, null is returned.
- *
- * @return A GlobalTransaction, or null if no (local) transaction was associated with the current thread
- */
- public GlobalTransaction getCurrentTransaction()
- {
- return getCurrentTransaction(true);
- }
-
- /**
- * Returns the transaction associated with the thread; optionally creating
- * it if is does not exist.
- */
- public GlobalTransaction getCurrentTransaction(boolean createIfNotExists)
- {
- Transaction tx;
-
- if ((tx = getLocalTransaction()) == null)
- {// no transaction is associated with the current thread
- return null;
- }
-
- if (!isValid(tx))
- {// we got a non-null transaction, but it is not active anymore
- int status = -1;
- try
- {
- status = tx.getStatus();
- }
- catch (SystemException e)
- {
- }
-
- // JBCACHE-982 -- don't complain if COMMITTED
- if (status != Status.STATUS_COMMITTED)
- {
- log.warn("status is " + status + " (not ACTIVE or PREPARING); returning null)", new Throwable());
- }
- else
- {
- log.trace("status is COMMITTED; returning null");
- }
-
- return null;
- }
-
- return getCurrentTransaction(tx, createIfNotExists);
- }
-
- /**
- * Returns the global transaction for this local transaction.
- */
- public GlobalTransaction getCurrentTransaction(Transaction tx)
- {
- return getCurrentTransaction(tx, true);
- }
-
- /**
- * Returns the global transaction for this local transaction.
- *
- * @param createIfNotExists if true, if a global transaction is not found; one is created
- */
- public GlobalTransaction getCurrentTransaction(Transaction tx, boolean createIfNotExists)
- {
- // removed synchronization on tx_table because underlying implementation is thread safe
- // and JTA spec (section 3.4.3 Thread of Control, par 2) says that only one thread may
- // operate on the transaction at one time so no concern about 2 threads trying to call
- // this method for the same Transaction instance at the same time
- //
- GlobalTransaction gtx = tx_table.get(tx);
- if (gtx == null && createIfNotExists)
- {
- Address addr = getLocalAddress();
- gtx = GlobalTransaction.create(addr);
- tx_table.put(tx, gtx);
- TransactionEntry ent = configuration.isNodeLockingOptimistic() ? new OptimisticTransactionEntry() : new TransactionEntry();
- ent.setTransaction(tx);
- tx_table.put(gtx, ent);
- if (log.isTraceEnabled())
- {
- log.trace("created new GTX: " + gtx + ", local TX=" + tx);
- }
- }
- return gtx;
- }
-
-
- /**
- * Invokes a method against this object. Contains the logger_ic for handling
- * the various use cases, e.g. mode (local, repl_async, repl_sync),
- * transaction (yes or no) and locking (yes or no).
- * <p/>
- * Only sets originLocal on the invocation context IF this is explicitly passed in as <tt>false</tt>
- * If passed in as <tt>true</tt> then it is not set; but whatever default exists in the invocation
- * context is used. For example, it may be set prior to calling invokeMethod()
- */
- protected Object invokeMethod(MethodCall m, boolean originLocal) throws CacheException
- {
- // don't create a new one; get it from ThreadLocal just this once, in case a user has added any overrides.
- InvocationContext ctx = getInvocationContext();
-
- // BR methods should NOT block on the cache being started, since the cache depends on these completing to start.
- if (!MethodDeclarations.isBuddyGroupOrganisationMethod(m.getMethodId()) && !cacheStatus.allowInvocations() && !ctx.getOptionOverrides().isSkipCacheStatusCheck())
- throw new IllegalStateException("Cache not in STARTED state!");
-
- MethodCall oldCall = null;
- try
- {
- // check if we had a method call lurking around
- oldCall = ctx.getMethodCall();
- ctx.setMethodCall(m);
- // only set this if originLocal is EXPLICITLY passed in as FALSE. Otherwise leave it as a default.
- if (!originLocal) ctx.setOriginLocal(false);
- return interceptor_chain.invoke(ctx);
- }
- catch (CacheException e)
- {
- throw e;
- }
- catch (RuntimeException e)
- {
- throw e;
- }
- catch (Throwable t)
- {
- throw new RuntimeException(t);
- }
- finally
- {
- if (!originLocal) ctx.setOriginLocal(true);
- // reset old method call
- ctx.setMethodCall(oldCall);
- }
- }
-
- /**
- * Returns an object suitable for use in node locking, either the current
- * transaction or the current thread if there is no transaction.
- */
- protected Object getOwnerForLock()
- {
- Object owner = getCurrentTransaction();
- if (owner == null)
- {
- owner = Thread.currentThread();
- }
-
- return owner;
- }
-
- /**
- * Finds a node given a fully qualified name.
- * Whenever nodes are created, and the global transaction is not null, the created
- * nodes have to be added to the transaction's {@link TransactionEntry}
- * field.<br>
- * When a lock is acquired on a node, a reference to the lock has to be
- * {@link TransactionEntry#addLock(org.jboss.cache.lock.NodeLock) added to the list of locked nodes}
- * in the {@link TransactionEntry}.
- * <p>This operation will also apply different locking to the cache nodes, depending on
- * <tt>operation_type</tt>. If it is <tt>read</tt> type, all nodes will be acquired with
- * read lock. Otherwise, the operation is <tt>write</tt> type, all parent nodes will be acquired
- * with read lock while the destination node acquires write lock.</p>
- *
- * @param fqn Fully qualified name for the corresponding node.
- * @return DataNode
- */
- public NodeSPI<K, V> findNode(Fqn fqn)
- {
- try
- {
- return findNode(fqn, null);
- }
- catch (CacheException e)
- {
- log.warn("Unexpected error", e);
- return null;
- }
- }
-
- private NodeSPI<K, V> findNodeCheck(GlobalTransaction tx, Fqn fqn)
- {
- NodeSPI<K, V> n = findNode(fqn);
- if (n == null)
- {
- String errStr = "node " + fqn + " not found (gtx=" + tx + ", caller=" + Thread.currentThread() + ")";
- if (log.isTraceEnabled())
- {
- log.trace(errStr);
- }
- throw new NodeNotExistsException(errStr);
- }
- return n;
- }
-
- /**
- * Internal method; not to be used externally.
- * Returns true if the node was found, false if not.
- *
- * @param f
- */
- public boolean realRemove(Fqn f, boolean skipMarkerCheck)
- {
- NodeSPI n = peek(f, true);
- if (n == null)
- {
- return false;
- }
-
- if (log.isTraceEnabled()) log.trace("Performing a real remove for node " + f + ", marked for removal.");
- if (skipMarkerCheck || n.isDeleted())
- {
- if (n.getFqn().isRoot())
- {
- // do not actually delete; just remove deletion marker
- n.markAsDeleted(true);
- // but now remove all children, since the call has been to remove("/")
- n.removeChildrenDirect();
- return true;
- }
- else
- {
- return n.getParent().removeChildDirect(n.getFqn().getLastElement());
- }
- }
- else
- {
- if (log.isDebugEnabled()) log.debug("Node " + f + " NOT marked for removal as expected, not removing!");
- return false;
- }
- }
-
- /**
- * Finds a node given a fully qualified name and DataVersion.
- */
- private NodeSPI<K, V> findNode(Fqn fqn, DataVersion version) throws CacheException
- {
- if (fqn == null) return null;
-
- NodeSPI<K, V> toReturn = peek(fqn, false);
-
- if (version != null && configuration.isNodeLockingOptimistic())
- {
- // we need to check the version of the data node...
- DataVersion nodeVersion = toReturn.getVersion();
- if (log.isTraceEnabled())
- {
- log.trace("looking for optimistic node [" + fqn + "] with version [" + version + "]. My version is [" + nodeVersion + "]");
- }
- if (nodeVersion.newerThan(version))
- {
- // we have a versioning problem; throw an exception!
- throw new CacheException("Unable to validate versions.");
- }
- }
- return toReturn;
- }
-
- public synchronized RegionManager getRegionManager()
- {
- if (regionManager == null)
- {
- regionManager = new RegionManager(this);
- }
- return regionManager;
- }
-
-
- public Marshaller getMarshaller()
- {
- if (marshaller_ == null)
- {
- synchronized (this)
- {
- if (marshaller_ == null)
- {
- if (configuration.getMarshallerClass() == null || configuration.getMarshallerClass().equals(VersionAwareMarshaller.class.getName()))
- {
- marshaller_ = new VersionAwareMarshaller(getRegionManager(), configuration);
- }
- else
- {
- try
- {
- marshaller_ = (Marshaller) org.jboss.cache.util.Util.loadClass(configuration.getMarshallerClass()).newInstance();
- }
- catch (Exception e)
- {
- log.error("Unable to load marshaller " + configuration.getMarshallerClass() + ". Falling back to default (" + VersionAwareMarshaller.class.getName() + ")");
- marshaller_ = new VersionAwareMarshaller(getRegionManager(), configuration);
- }
- }
- if (log.isTraceEnabled()) log.trace("Using marshaller " + marshaller_.getClass().getName());
- }
- }
- }
- return marshaller_;
- }
-
- /**
- * Returns the default JGroup properties.
- * Subclasses may wish to override this method.
- */
- protected String getDefaultProperties()
- {
- return "UDP(mcast_addr=224.0.0.36;mcast_port=55566;ip_ttl=32;" +
- "mcast_send_buf_size=150000;mcast_recv_buf_size=80000):" +
- "PING(timeout=1000;num_initial_members=2):" +
- "MERGE2(min_interval=5000;max_interval=10000):" +
- "FD_SOCK:" +
- "VERIFY_SUSPECT(timeout=1500):" +
- "pbcast.NAKACK(gc_lag=50;max_xmit_size=8192;retransmit_timeout=600,1200,2400,4800):" +
- "UNICAST(timeout=600,1200,2400,4800):" +
- "pbcast.STABLE(desired_avg_gossip=20000):" +
- "FRAG(frag_size=8192;down_thread=false;up_thread=false):" +
- "pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;" +
- "shun=false;print_local_addr=true):" +
- "pbcast.STATE_TRANSFER";
- }
-
- private void initialiseCacheLoaderManager() throws CacheException
- {
- if (cacheLoaderManager == null)
- {
- cacheLoaderManager = new CacheLoaderManager();
- }
- cacheLoaderManager.setConfig(configuration.getCacheLoaderConfig(), this);
- }
-
- /**
- * Sets the CacheLoader to use.
- * Provided for backwards compatibility.
- *
- * @param loader
- * @deprecated only provided for backward compat
- */
- @Deprecated
- public void setCacheLoader(CacheLoader loader)
- {
- log.warn("Using deprecated config method setCacheLoader. This element will be removed in future, please use CacheLoaderConfiguration instead.");
-
- try
- {
- if (cacheLoaderManager == null) initialiseCacheLoaderManager();
- }
- catch (Exception e)
- {
- log.warn("Problem setting cache loader. Perhaps your cache loader config has not been set yet?");
- }
- cacheLoaderManager.setCacheLoader(loader);
- }
-
- /**
- * Purges the contents of all configured {@link CacheLoader}s
- */
- public void purgeCacheLoaders() throws Exception
- {
- if (cacheLoaderManager != null) cacheLoaderManager.purgeLoaders(true);
- }
-
- // ---------------------------------------------------------------
- // END: Methods to provide backward compatibility with older cache loader config settings
- // ---------------------------------------------------------------
-
- private void initialiseChannelAndRpcDispatcher() throws CacheException
- {
- channel = configuration.getRuntimeConfig().getChannel();
- if (channel == null)
- {
- // Try to create a multiplexer channel
- channel = getMultiplexerChannel();
-
- if (channel != null)
- {
- configuration.setUsingMultiplexer(true);
- if (log.isDebugEnabled())
- {
- log.debug("Created Multiplexer Channel for cache cluster " + configuration.getClusterName() +
- " using stack " + configuration.getMultiplexerStack());
- }
- }
- else
- {
- if (configuration.getClusterConfig() == null)
- {
- log.debug("setting cluster properties to default value");
- configuration.setClusterConfig(getDefaultProperties());
- }
- try
- {
- channel = new JChannel(configuration.getClusterConfig());
- }
- catch (Exception e)
- {
- throw new CacheException("Unable to create JGroups channel", e);
- }
- if (log.isTraceEnabled())
- {
- log.trace("cache properties: " + configuration.getClusterConfig());
- }
- }
-
- configuration.getRuntimeConfig().setChannel(channel);
- }
-
- channel.setOpt(Channel.AUTO_RECONNECT, true);
- channel.setOpt(Channel.AUTO_GETSTATE, true);
- channel.setOpt(Channel.BLOCK, true);
-
- // always use the InactiveRegionAwareRpcDispatcher - exceptions due to regions not being active should not propagate to remote
- // nodes as errors. - Manik
- disp = new InactiveRegionAwareRpcDispatcher(channel, ml, new MembershipListenerAdaptor(), this);
- // disp = new RpcDispatcher(channel, ml, this, this);
-
- disp.setRequestMarshaller(getMarshaller());
- disp.setResponseMarshaller(getMarshaller());
- }
-
- private JChannel getMultiplexerChannel() throws CacheException
- {
- String stackName = configuration.getMultiplexerStack();
-
- RuntimeConfig rtc = configuration.getRuntimeConfig();
- ChannelFactory channelFactory = rtc.getMuxChannelFactory();
- JChannel muxchannel = null;
-
- if (channelFactory != null)
- {
- try
- {
- muxchannel = (JChannel) channelFactory.createMultiplexerChannel(stackName, configuration.getClusterName());
- }
- catch (Exception e)
- {
- throw new CacheException("Failed to create multiplexed channel using stack " + stackName, e);
- }
- }
-
- return muxchannel;
- }
-
- // ================== methods to implement Cache and CacheSPI interfaces ============================
-
- public List<Interceptor> getInterceptorChain()
- {
- List<Interceptor> modifiable = getInterceptors();
- return modifiable == null ? null : Collections.unmodifiableList(modifiable);
- }
-
- public void addCacheListener(Object listener)
- {
- getNotifier().addCacheListener(listener);
- }
-
- public void addCacheListener(Fqn<?> region, Object listener)
- {
- throw new UnsupportedOperationException("Not implemented in this release");
- }
-
- public void removeCacheListener(Object listener)
- {
- // BES 2007/5/23 workaround to avoid NPE while we decide whether
- // to remove notifier in destroy()
- Notifier n = getNotifier();
- if (n != null)
- n.removeCacheListener(listener);
- }
-
- public void removeCacheListener(Fqn<?> region, Object listener)
- {
- throw new UnsupportedOperationException("Not implemented in this release");
- }
-
- public Set<Object> getCacheListeners()
- {
- return getNotifier().getCacheListeners();
- }
-
- public Set<Object> getCacheListeners(Fqn<?> region)
- {
- throw new UnsupportedOperationException("Not implemented in this release");
- }
-
- public synchronized void addInterceptor(Interceptor i, int position)
- {
- List<Interceptor> interceptors = getInterceptors();
-
- i.setCache(this);
-
- interceptors.add(position, i);
-
- // now correct the chaining of interceptors...
- Interceptor linkedChain = InterceptorChainFactory.getInstance().correctInterceptorChaining(interceptors);
-
- setInterceptorChain(linkedChain);
- }
-
- public synchronized void removeInterceptor(int position)
- {
- List<Interceptor> i = getInterceptors();
- i.remove(position);
- setInterceptorChain(InterceptorChainFactory.getInstance().correctInterceptorChaining(i));
- }
-
- public RPCManager getRPCManager()
- {
- return configuration.getRuntimeConfig().getRPCManager();
- }
-
- public String getClusterName()
- {
- return getConfiguration().getClusterName();
- }
-
- public void evict(Fqn<?> fqn, boolean recursive)
- {
- if (recursive)
- {
- Node<K, V> n = get(fqn);
- if (n != null)
- {
- evictChildren((NodeSPI<K, V>) n);
- }
- }
- else
- {
- evict(fqn);
- }
- }
-
- private void evictChildren(NodeSPI<K, V> n)
- {
- for (NodeSPI<K, V> child : n.getChildrenDirect())
- {
- evictChildren(child);
- }
- evict(n.getFqn());
- }
-
- public Region getRegion(Fqn<?> fqn, boolean createIfAbsent)
- {
- return getRegionManager().getRegion(fqn, createIfAbsent);
- }
-
- public boolean removeRegion(Fqn<?> fqn)
- {
- return getRegionManager().removeRegion(fqn);
- }
-
- public boolean removeNode(Fqn<?> fqn)
- {
- return remove(fqn);
- }
-
- public void putForExternalRead(Fqn<?> fqn, K key, V value)
- {
- // if the node exists then this should be a no-op.
- if (!exists(fqn))
- {
- getInvocationContext().getOptionOverrides().setFailSilently(true);
- GlobalTransaction tx = getCurrentTransaction();
- MethodCall m = MethodCallFactory.create(MethodDeclarations.putForExternalReadMethodLocal, tx, fqn, key, value);
- invokeMethod(m, true);
- }
- else
- {
- if (log.isDebugEnabled())
- log.debug("putForExternalRead() called with Fqn " + fqn + " and this node already exists. This method is hence a no op.");
- }
- }
-
- public void _putForExternalRead(GlobalTransaction gtx, Fqn fqn, K key, V value)
- {
- _put(gtx, fqn, key, value, true);
- }
-
- public boolean isStarted()
- {
- return getCacheStatus() == CacheStatus.STARTED;
- }
-
- protected void setMessageListener(MessageListenerAdaptor ml)
- {
- this.ml = ml;
- }
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/CacheSPI.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/CacheSPI.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/CacheSPI.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,186 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.cache.buddyreplication.BuddyManager;
-import org.jboss.cache.buddyreplication.GravitateResult;
-import org.jboss.cache.interceptors.Interceptor;
-import org.jboss.cache.loader.CacheLoader;
-import org.jboss.cache.loader.CacheLoaderManager;
-import org.jboss.cache.lock.NodeLock;
-import org.jboss.cache.marshall.Marshaller;
-import org.jboss.cache.notifications.Notifier;
-import org.jboss.cache.statetransfer.StateTransferManager;
-import org.jboss.cache.transaction.GlobalTransaction;
-import org.jboss.cache.transaction.TransactionTable;
-
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A more detailed interface to {@link Cache}, which is used when writing plugins for or extending JBoss Cache. A reference
- * to this interface should only be obtained when it is passed in to your code, for example when you write an
- * {@link Interceptor} or {@link CacheLoader}.
- * <p/>
- * <B><I>You should NEVER attempt to directly cast a {@link Cache} instance to this interface. In future, the implementation may not allow it.</I></B>
- * <p/>
- * This interface contains overridden method signatures of some methods from {@link Cache}, overridden to ensure return
- * types of {@link Node} are replaced with {@link NodeSPI}.
- * <p/>
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- * @see NodeSPI
- * @see Cache
- * @see org.jboss.cache.loader.CacheLoader
- * @see org.jboss.cache.interceptors.Interceptor
- * @since 2.0.0
- */
-@ThreadSafe
-public interface CacheSPI<K, V> extends Cache<K, V>
-{
- /**
- * Overrides {@link org.jboss.cache.Cache#getRoot()} to return a {@link org.jboss.cache.NodeSPI} instead of a {@link org.jboss.cache.Node}.
- */
- NodeSPI<K, V> getRoot();
-
- /**
- * Retrieves a reference to a running {@link javax.transaction.TransactionManager}, if one is configured.
- *
- * @return a TransactionManager
- */
- TransactionManager getTransactionManager();
-
- /**
- * @return an immutable {@link List} of {@link Interceptor}s configured for this cache, or
- * <code>null</code> if {@link Cache#create() create()} has not been invoked
- * and the interceptors thus do not exist.
- */
- List<Interceptor> getInterceptorChain();
-
- /**
- * Adds a custom interceptor to the interceptor chain, at specified position, where the first interceptor in the chain
- * is at position 0 and the last one at getInterceptorChain().size() - 1.
- *
- * @param i the interceptor to add
- * @param position the position to add the interceptor
- */
- void addInterceptor(Interceptor i, int position);
-
- /**
- * Removes the interceptor at a specified position, where the first interceptor in the chain
- * is at position 0 and the last one at getInterceptorChain().size() - 1.
- *
- * @param position the position at which to remove an interceptor
- */
- void removeInterceptor(int position);
-
- /**
- * @return Retrieves a reference to the currently configured {@link org.jboss.cache.loader.CacheLoaderManager} if one or more cache loaders are configured, null otherwise.
- */
- CacheLoaderManager getCacheLoaderManager();
-
- /**
- * @return an instance of {@link BuddyManager} if buddy replication is enabled, null otherwise.
- */
- BuddyManager getBuddyManager();
-
- /**
- * @return the current {@link TransactionTable}
- */
- TransactionTable getTransactionTable();
-
- /**
- * Gets a handle of the RPC manager.
- *
- * @return the {@link org.jboss.cache.RPCManager} configured.
- */
- RPCManager getRPCManager();
-
- /**
- * @return the current {@link org.jboss.cache.statetransfer.StateTransferManager}
- */
- StateTransferManager getStateTransferManager();
-
- /**
- * @return the name of the cluster. Null if running in local mode.
- */
- String getClusterName();
-
- /**
- * @return the number of attributes in the cache.
- */
- int getNumberOfAttributes();
-
- /**
- * @return the number of nodes in the cache.
- */
- int getNumberOfNodes();
-
- /**
- * Retrieves the current table of locks.
- *
- * @return lock table.
- */
- Map<Thread, List<NodeLock>> getLockTable();
-
- /**
- * @return the {@link org.jboss.cache.RegionManager}
- */
- RegionManager getRegionManager();
-
- /**
- * Returns the global transaction for this local transaction.
- * Optionally creates a new global transaction if it does not exist.
- *
- * @param tx the current transaction
- * @param createIfNotExists if true creates a new transaction if none exists
- * @return a GlobalTransaction
- */
- GlobalTransaction getCurrentTransaction(Transaction tx, boolean createIfNotExists);
-
- /**
- * @return the notifier attached with this instance of the cache. See {@link Notifier}, a class
- * that is responsible for emitting notifications to registered CacheListeners.
- */
- Notifier getNotifier();
-
- /**
- * Returns a node without accessing the interceptor chain.
- *
- * @param fqn the Fqn to look up.
- * @param includeDeletedNodes if you intend to see nodes marked as deleted within the current tx, set this to true
- * @return a node if one exists or null
- */
- NodeSPI<K, V> peek(Fqn<?> fqn, boolean includeDeletedNodes);
-
- /**
- * Used with buddy replication's data gravitation interceptor. If marshalling is necessary, ensure that the cache is
- * configured to use {@link org.jboss.cache.config.Configuration#useRegionBasedMarshalling} and the {@link org.jboss.cache.Region}
- * pertaining to the Fqn passed in is activated, and has an appropriate ClassLoader.
- *
- * @param fqn the fqn to gravitate
- * @param searchBuddyBackupSubtrees if true, buddy backup subtrees are searched and if false, they are not.
- * @return a GravitateResult which contains the data for the gravitation
- */
- GravitateResult gravitateData(Fqn<?> fqn, boolean searchBuddyBackupSubtrees);
-
- /**
- * Retrieves an instance of a {@link Marshaller}, which is capable of
- * converting Java objects to bytestreams and back in an efficient manner, which is
- * also interoperable with bytestreams produced/consumed by other versions of JBoss
- * Cache.
- * <p/>
- * The use of this marshaller is the <b>recommended</b> way of creating efficient,
- * compatible, byte streams from objects.
- *
- * @return an instance of {@link Marshaller}
- */
- Marshaller getMarshaller();
-}
Deleted: core/trunk/src-old/org/jboss/cache/CacheStatus.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/CacheStatus.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/CacheStatus.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,224 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2006, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-
-package org.jboss.cache;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Various states that an object that has a four stage lifecycle
- * (i.e. <code>create()</code>, <code>start()</code>, <code>stop()</code>
- * and <code>destroy()</code>) might be in.
- *
- * @author <a href="brian.stansberry(a)jboss.com">Brian Stansberry</a>
- * @version $Revision$
- */
-public enum CacheStatus
-{
- /**
- * Object has been instantiated, but create() has not been called.
- */
- INSTANTIATED,
- /**
- * The <code>create()</code> method has been called but not yet completed.
- */
- CREATING,
- /**
- * The <code>create()</code> method has been completed but
- * <code>start()</code> has not been called.
- */
- CREATED,
- /**
- * The <code>start()</code> method has been called but has not yet completed.
- */
- STARTING,
- /**
- * The <code>start()</code> method has completed.
- */
- STARTED,
- /**
- * The <code>stop()</code> method has been called but has not yet completed.
- */
- STOPPING,
- /**
- * The <code>stop()</code> method has completed but <code>destroy()</code>
- * has not yet been called. Conceptually equivalent to {@link #CREATED}.
- */
- STOPPED,
- /**
- * The <code>destroy()</code> method has been called but has not yet completed.
- */
- DESTROYING,
- /**
- * The <code>destroy()</code> method has completed.
- * Conceptually equivalent to {@link #INSTANTIATED}.
- */
- DESTROYED,
- /**
- * A failure occurred during the execution of <code>create()</code>,
- * <code>start()</code>, <code>stop()</code> or <code>destroy()</code>.
- * The next logical transition is to call <code>destroy()</code>.
- */
- FAILED;
-
- private static final Log log = LogFactory.getLog(CacheStatus.class);
-
- public boolean createAllowed()
- {
- switch (this)
- {
- case CREATING:
- case CREATED:
- case STARTING:
- case STARTED:
- case STOPPED:
- log.debug("Ignoring call to create() as current state is " + this);
- // fall through
- case FAILED:
- return false;
- case STOPPING:
- case DESTROYING:
- log.warn("Ignoring call to create() while cache is " + this);
- return false;
- case INSTANTIATED:
- case DESTROYED:
- default:
- return true;
- }
- }
-
- public boolean needToDestroyFailedCache()
- {
- if (this == CacheStatus.FAILED)
- {
- log.debug("need to call destroy() since current state is " +
- this);
- return true;
- }
-
- return false;
- }
-
- public boolean startAllowed()
- {
- switch (this)
- {
- case INSTANTIATED:
- case DESTROYED:
- case STARTING:
- case STARTED:
- log.debug("Ignoring call to start() as current state is " + this);
- // fall through
- case FAILED:
- return false;
- case STOPPING:
- case DESTROYING:
- log.warn("Ignoring call to start() as current state is " + this);
- return false;
- case CREATED:
- case STOPPED:
- default:
- return true;
- }
- }
-
- public boolean needCreateBeforeStart()
- {
- switch (this)
- {
- case INSTANTIATED:
- case DESTROYED:
- log.debug("start() called while current state is " +
- this + " -- call create() first");
- return true;
- default:
- return false;
- }
- }
-
- public boolean stopAllowed()
- {
- switch (this)
- {
- case INSTANTIATED:
- case CREATED:
- case STOPPED:
- case DESTROYED:
- log.debug("Ignoring call to stop() as current state is " + this);
- return false;
- case CREATING:
- case STARTING:
- case STOPPING:
- case DESTROYING:
- log.warn("Ignoring call to stop() as current state is " + this);
- return false;
- case FAILED:
- case STARTED:
- default:
- return true;
- }
-
- }
-
- public boolean destroyAllowed()
- {
- switch (this)
- {
- case INSTANTIATED:
- case DESTROYED:
- log.debug("Ignoring call to destroy() as current state is " + this);
- return false;
- case CREATING:
- case STARTING:
- case STOPPING:
- case DESTROYING:
- log.warn("Ignoring call to destroy() as current state iswhile cache is " + this);
- return false;
- case STARTED:
- // stop first
- return false;
- case CREATED:
- case STOPPED:
- case FAILED:
- default:
- return true;
- }
- }
-
- public boolean needStopBeforeDestroy()
- {
- if (this == CacheStatus.STARTED)
- {
- log.warn("destroy() called while current state is " +
- this + " -- call stop() first");
- return true;
- }
-
- return false;
- }
-
- public boolean allowInvocations()
- {
- return (this == CacheStatus.STARTED);
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/ConsoleListener.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/ConsoleListener.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/ConsoleListener.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,230 +0,0 @@
-package org.jboss.cache;
-
-import org.jboss.cache.notifications.annotation.CacheListener;
-import org.jboss.cache.notifications.annotation.CacheStarted;
-import org.jboss.cache.notifications.annotation.CacheStopped;
-import org.jboss.cache.notifications.annotation.NodeActivated;
-import org.jboss.cache.notifications.annotation.NodeCreated;
-import org.jboss.cache.notifications.annotation.NodeEvicted;
-import org.jboss.cache.notifications.annotation.NodeLoaded;
-import org.jboss.cache.notifications.annotation.NodeModified;
-import org.jboss.cache.notifications.annotation.NodeMoved;
-import org.jboss.cache.notifications.annotation.NodePassivated;
-import org.jboss.cache.notifications.annotation.NodeRemoved;
-import org.jboss.cache.notifications.annotation.NodeVisited;
-import org.jboss.cache.notifications.annotation.ViewChanged;
-import org.jboss.cache.notifications.event.Event;
-import org.jboss.cache.notifications.event.NodeEvent;
-import org.jboss.cache.notifications.event.ViewChangedEvent;
-
-/**
- * This class provides a non-graphical view of <em>JBossCache</em> replication
- * events for a replicated cache.
- * <p/>
- * It can be utilized as a standalone application or as a component in other
- * applications.
- * <p/>
- * <strong>WARNING</strong>: take care when using this class in conjunction with
- * transactionally replicated cache's as it can cause deadlock situations due to
- * the reading of values for nodes in the cache.
- *
- * @author Jimmy Wilson 12-2004
- */
-@CacheListener
-public class ConsoleListener
-{
- private CacheImpl _cache;
- private boolean _startCache;
-
- /**
- * Constructor.
- * <p/>
- * When using this constructor, this class with attempt to start and stop
- * the specified cache.
- *
- * @param cache the cache to monitor for replication events.
- */
- public ConsoleListener(CacheImpl cache)
- throws Exception
- {
- this(cache, true, true);
- }
-
- /**
- * Constructor.
- *
- * @param cache the cache to monitor for replication events.
- * @param startCache indicates whether or not the cache should be started by
- * this class.
- * @param stopCache indicates whether or not the cache should be stopped by
- * this class.
- */
- public ConsoleListener(CacheImpl cache,
- boolean startCache, boolean stopCache)
- throws Exception
- {
- _cache = cache;
- _startCache = startCache;
-
- if (stopCache)
- {
- new ListenerShutdownHook().register();
- }
- }
-
- /**
- * Instructs this class to listen for cache replication events.
- * <p/>
- * This method waits indefinately. Use the notify method of this class
- * (using traditional Java thread notification semantics) to cause this
- * method to return.
- */
- public void listen()
- throws Exception
- {
- listen(true);
- }
-
- /**
- * Instructs this class to listen for cache replication events.
- *
- * @param wait whether or not this method should wait indefinately.
- * <p/>
- * If this parameter is set to <code>true</code>, using the
- * notify method of this class (using traditional Java thread
- * notification semantics) will cause this method to return.
- */
- public void listen(boolean wait)
- throws Exception
- {
- _cache.getNotifier().addCacheListener(this);
-
- if (_startCache)
- {
- _cache.start();
- }
-
- synchronized (this)
- {
- while (wait)
- {
- wait();
- }
- }
- }
-
-
- @CacheStarted
- @CacheStopped
- public void printDetails(Event e)
- {
- printEvent("Cache started.");
- }
-
-
- @NodeCreated
- @NodeLoaded
- @NodeModified
- @NodeRemoved
- @NodeVisited
- @NodeMoved
- @NodeEvicted
- @NodeActivated
- @NodePassivated
- public void printDetailsWithFqn(NodeEvent e)
- {
- if (e.isPre())
- {
- printEvent("Event " + e.getType() + " on node [" + e.getFqn() + "] about to be invoked");
- }
- else
- {
- printEvent("Event " + e.getType() + " on node [" + e.getFqn() + "] invoked");
- }
- }
-
- @ViewChanged
- public void printNewView(ViewChangedEvent e)
- {
- printEvent("View change: " + e.getNewView());
- }
-
- /**
- * Prints an event message.
- *
- * @param eventSuffix the suffix of the event message.
- */
- private void printEvent(String eventSuffix)
- {
- System.out.print("EVENT");
- System.out.print(' ');
-
- System.out.println(eventSuffix);
- }
-
- /**
- * This class provides a shutdown hook for shutting down the cache.
- */
- private class ListenerShutdownHook extends Thread
- {
- /**
- * Registers this hook for invocation during shutdown.
- */
- public void register()
- {
- Runtime.getRuntime().addShutdownHook(this);
- }
-
- /*
- * Thread overrides.
- */
-
- public void run()
- {
- _cache.stop();
- }
- }
-
- /**
- * The main method.
- *
- * @param args command line arguments dictated by convention.
- * <p/>
- * The first command line argument is the name of the
- * <code>JBossCache</code> configuration file to be utilized
- * for configuration of the cache. Only the name of the
- * configuration file is necessary as it is read off of the
- * classpath.
- * <p/>
- * If a configuration file is not specified on the command line,
- * <code>jboss-cache.xml</code> will be the assumed file name.
- * <p/>
- * All command line arguments after the first are ignored.
- */
- public static void main(String[] args)
- {
- final String DEFAULT_CONFIG_FILE_NAME = "jboss-cache.xml";
-
- try
- {
- String configFileName = DEFAULT_CONFIG_FILE_NAME;
-
- if (args.length >= 1)
- {
- configFileName = args[0];
- }
- else
- {
- System.out.print("No xml config file argument is supplied. Will use jboss-cache.xml from classpath");
- }
-
- CacheImpl cache = (CacheImpl) DefaultCacheFactory.getInstance().createCache(configFileName);
- ConsoleListener listener = new ConsoleListener(cache);
- listener.listen();
- }
- catch (Throwable throwable)
- {
- throwable.printStackTrace();
- }
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/DefaultCacheFactory.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/DefaultCacheFactory.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/DefaultCacheFactory.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,95 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.config.Configuration;
-import org.jboss.cache.config.ConfigurationException;
-import org.jboss.cache.factories.XmlConfigurationParser;
-
-/**
- * Default (singleton) implementation of the {@link org.jboss.cache.CacheFactory} interface.
- * Use {@link #getInstance()} to obtain an instance.
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- */
-public class DefaultCacheFactory<K, V> implements CacheFactory<K, V>
-{
- private static CacheFactory singleton = new DefaultCacheFactory();
-
- /**
- * @return a singleton instance of this class.
- */
- public static <K, V> CacheFactory<K, V> getInstance()
- {
- return singleton;
- }
-
- public Cache<K, V> createCache() throws ConfigurationException
- {
- return createCache(true);
- }
-
- public Cache<K, V> createCache(boolean start) throws ConfigurationException
- {
- return createCache(new Configuration(), start);
- }
-
- public Cache<K, V> createCache(String configFileName) throws ConfigurationException
- {
- return createCache(configFileName, true);
- }
-
- public Cache<K, V> createCache(String configFileName, boolean start) throws ConfigurationException
- {
- XmlConfigurationParser parser = new XmlConfigurationParser();
- Configuration c = parser.parseFile(configFileName);
- return createCache(c, start);
- }
-
- /**
- * This implementation clones the configuration passed in before using it.
- *
- * @param configuration to use
- * @return a cache
- * @throws ConfigurationException if there are problems with the cfg
- */
- public Cache<K, V> createCache(Configuration configuration) throws ConfigurationException
- {
- return createCache(configuration, true);
- }
-
- /**
- * This implementation clones the configuration passed in before using it.
- *
- * @param configuration to use
- * @param start whether to start the cache
- * @return a cache
- * @throws ConfigurationException if there are problems with the cfg
- */
- public Cache<K, V> createCache(Configuration configuration, boolean start) throws ConfigurationException
- {
- try
- {
- CacheImpl<K, V> cache = new CacheImpl<K, V>();
- cache.setConfiguration(configuration);
- if (start) cache.start();
- return cache;
- }
- catch (ConfigurationException ce)
- {
- throw ce;
- }
- catch (RuntimeException re)
- {
- throw re;
- }
- catch (Exception e)
- {
- throw new RuntimeException(e);
- }
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/Fqn.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/Fqn.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/Fqn.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,518 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-
-import net.jcip.annotations.Immutable;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.StringTokenizer;
-
-/**
- * A Fully Qualified Name (Fqn) is a list of names (typically Strings but can be any Object),
- * which represent a path to a particular {@link Node} or sometimes a {@link Region} in a {@link Cache}.
- * <p/>
- * This name can be absolute (i.e., relative from the root node - {@link #ROOT}), or relative to any node in the cache. Reading the
- * documentation on each API call that makes use of {@link org.jboss.cache.Fqn}s will tell you whether the API expects a
- * relative or absolute Fqn.
- * <p/>
- * For instance, using this class to fetch a particular node might look like
- * this. (Here data on "Joe" is kept under the "Smith" surname node, under
- * the "people" tree.)
- * <pre>
- * Fqn<String> abc = Fqn.fromString("/people/Smith/Joe/");
- * Node joesmith = Cache.getRoot().getChild(abc);
- * </pre>
- * Alternatively, the same Fqn could be constructed using an array:
- * <pre>
- * Fqn<String> abc = new Fqn<String>(new String[] { "people", "Smith", "Joe" });
- * </pre>
- * This is a bit more efficient to construct.
- * <p/>
- * <p/>
- * Note that<br>
- * <p/>
- * <code>Fqn<String> f = new Fqn<String>("/a/b/c");</code>
- * <p/>
- * is <b>not</b> the same as
- * <p/>
- * <code>Fqn<String> f = Fqn.fromString("/a/b/c");</code>
- * <p/>
- * The former will result in a single Fqn, called "/a/b/c" which hangs directly under Fqn.ROOT.
- * <p/>
- * The latter will result in 3 Fqns, called "a", "b" and "c", where "c" is a child of "b", "b" is a child of "a", and "a" hangs off Fqn.ROOT.
- * <p/>
- * Another way to look at it is that the "/" separarator is only parsed when it forms
- * part of a String passed in to Fqn.fromString() and not otherwise.
- *
- * @version $Revision$
- */
-@Immutable
-public class Fqn<E> implements Cloneable, Externalizable, Comparable<Fqn>
-{
-
- /**
- * Separator between FQN elements.
- */
- public static final String SEPARATOR = "/";
- private static final long serialVersionUID = -5351930616956603651L;
- private List<E> elements;
- private transient int hash_code = 0;
-
- /**
- * Immutable root FQN.
- */
- public static final Fqn ROOT = new Fqn();
- private static Log log = LogFactory.getLog(Fqn.class);
- // a cached string representation of this Fqn, used by toString to it isn't calculated again every time.
- private String cachedStringRep;
-
- /**
- * Constructs a root Fqn
- */
- public Fqn()
- {
- elements = Collections.emptyList();
- }
-
- /**
- * Constructs a FQN from a list of names.
- *
- * @param names List of names
- */
- public Fqn(List<E> names)
- {
- // the list is unsafe - may be referenced externally
- this(names, false);
- }
-
- /**
- * If safe is false, Collections.unmodifiableList() is used to wrap the list passed in. This is an optimisation so
- * Fqn.fromString(), probably the most frequently used factory method, doesn't end up needing to use the unmodifiableList()
- * since it creates the list internally.
- *
- * @param names List of names
- * @param safe whether this list is referenced externally (safe = false) or not (safe = true).
- */
- protected Fqn(List<E> names, boolean safe)
- {
- if (names != null)
- {
- // if not safe make a defensive copy
- elements = safe ? names : new ArrayList<E>(names);
- }
- else
- {
- elements = Collections.emptyList();
- }
- }
-
-
- /**
- * Constructs a Fqn from an array of names.
- *
- * @param names Names that comprose this Fqn
- */
- public Fqn(E... names)
- {
- // safe - the list is created here.
- this(Arrays.asList(names), true);
- }
-
- /**
- * Constructs a Fqn from a base and relative Fqn.
- *
- * @param base parent Fqn
- * @param relative Sub-Fqn relative to the parent
- */
- public Fqn(Fqn<E> base, Fqn<E> relative)
- {
- this(base, relative.elements);
- }
-
- /**
- * Constructs a Fqn from a base and a list of relative names.
- *
- * @param base parent Fqn
- * @param relative List of elements that identify the child Fqn, relative to the parent
- */
- public Fqn(Fqn<E> base, List<E> relative)
- {
- List<E> elements = new ArrayList<E>(base.elements.size() + relative.size());
- elements.addAll(base.elements);
- elements.addAll(relative);
- this.elements = elements;
- }
-
- /**
- * Constructs a Fqn from a base and two relative names.
- *
- * @param base parent Fqn
- * @param childNames elements that denote the path to the Fqn, under the parent
- */
- public Fqn(Fqn<E> base, E... childNames)
- {
- List<E> elements = new ArrayList<E>(base.elements.size() + childNames.length);
- elements.addAll(base.elements);
- elements.addAll(Arrays.asList(childNames));
- this.elements = elements;
- }
-
- /**
- * Returns a new Fqn from a string, where the elements are deliminated by
- * one or more separator ({@link #SEPARATOR}) characters.<br><br>
- * Example use:<br>
- * <pre>
- * Fqn.fromString("/a/b/c/");
- * </pre><br>
- * is equivalent to:<br>
- * <pre>
- * new Fqn("a", "b", "c");
- * </pre><br>
- * but not<br>
- * <pre>
- * new Fqn("/a/b/c");
- * </pre>
- *
- * @param stringRepresentation String representation of the Fqn
- * @return an Fqn<String> constructed from the string representation passed in
- * @see #Fqn(Object[])
- */
- public static Fqn<String> fromString(String stringRepresentation)
- {
- if (stringRepresentation == null)
- {
- return Fqn.ROOT;
- }
- List<String> list = new ArrayList<String>();
- StringTokenizer tok = new StringTokenizer(stringRepresentation, SEPARATOR);
- while (tok.hasMoreTokens()) list.add(tok.nextToken());
- return new Fqn<String>(list, true);
- }
-
- /**
- * Obtains an ancestor of the current Fqn. Literally performs <code>elements.subList(0, generation)</code>
- * such that if
- * <code>
- * generation == Fqn.size()
- * </code>
- * then the return value is the Fqn itself (current generation), and if
- * <code>
- * generation == Fqn.size() - 1
- * </code>
- * then the return value is the same as
- * <code>
- * Fqn.getParent()
- * </code>
- * i.e., just one generation behind the current generation.
- * <code>
- * generation == 0
- * </code>
- * would return Fqn.ROOT.
- *
- * @param generation the generation of the ancestor to retrieve
- * @return an ancestor of the current Fqn
- */
- public Fqn<E> getAncestor(int generation)
- {
- if (generation == 0) return Fqn.ROOT;
- return getSubFqn(0, generation);
- }
-
- /**
- * Obtains a sub-Fqn from the given Fqn. Literally performs <code>elements.subList(startIndex, endIndex)</code>
- */
- public Fqn<E> getSubFqn(int startIndex, int endIndex)
- {
- return new Fqn<E>(elements.subList(startIndex, endIndex));
- }
-
- /**
- * @return the number of elements in the Fqn. The root node contains zero.
- */
- public int size()
- {
- return elements.size();
- }
-
- /**
- * @param n index of the element to return
- * @return Returns the nth element in the Fqn.
- */
- public E get(int n)
- {
- return elements.get(n);
- }
-
- /**
- * @return the last element in the Fqn.
- * @see #getLastElementAsString
- */
- public E getLastElement()
- {
- if (isRoot()) return null;
- return elements.get(elements.size() - 1);
- }
-
- /**
- * @param element element to find
- * @return true if the Fqn contains this element, false otherwise.
- */
- public boolean hasElement(E element)
- {
- return elements.lastIndexOf(element) != -1;
- }
-
- /**
- * Clones the Fqn.
- */
- public Fqn<E> clone() throws CloneNotSupportedException
- {
- try
- {
- return (Fqn<E>) super.clone();
- }
- catch (CloneNotSupportedException e)
- {
- log.error("Unable to clone Fqn " + this, e);
- return null;
- }
- }
-
- /**
- * Returns true if obj is a Fqn with the same elements.
- */
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (!(obj instanceof Fqn))
- {
- return false;
- }
- Fqn other = (Fqn) obj;
- return elements.equals(other.elements);
- }
-
- /**
- * Returns a hash code with Fqn elements.
- */
- public int hashCode()
- {
- if (hash_code == 0)
- {
- hash_code = _hashCode();
- }
- return hash_code;
- }
-
- /**
- * Returns this Fqn as a string, prefixing the first element with a {@link Fqn#SEPARATOR} and
- * joining each subsequent element with a {@link Fqn#SEPARATOR}.
- * If this is the root Fqn, returns {@link Fqn#SEPARATOR}.
- * Example:
- * <pre>
- * new Fqn(new Object[] { "a", "b", "c" }).toString(); // "/a/b/c"
- * Fqn.ROOT.toString(); // "/"
- * </pre>
- */
- public String toString()
- {
- if (cachedStringRep == null)
- {
- if (isRoot())
- {
- cachedStringRep = SEPARATOR;
- }
- else
- {
- StringBuffer sb = new StringBuffer();
- for (E element : elements)
- {
- sb.append(SEPARATOR).append(element);
- }
- cachedStringRep = sb.toString();
- }
- }
- return cachedStringRep;
- }
-
- public void writeExternal(ObjectOutput out) throws IOException
- {
- out.writeShort(elements.size());
- for (E element : elements)
- {
- out.writeObject(element);
- }
- }
-
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
- {
- short length = in.readShort();
- this.elements = new ArrayList<E>(length);
- for (int i = 0; i < length; i++)
- {
- elements.add((E) in.readObject());
- }
- }
-
-
- /**
- * Returns true if this Fqn is child of parentFqn.
- * Example usage:
- * <pre>
- * Fqn<String> f1 = Fqn.fromString("/a/b");
- * Fqn<String> f2 = Fqn.fromString("/a/b/c");
- * assertTrue(f1.isChildOf(f2));
- * assertFalse(f1.isChildOf(f1));
- * assertFalse(f2.isChildOf(f1));
- * </pre>
- *
- * @param parentFqn candidate parent to test against
- * @return true if the target is a child of parentFqn
- */
- public boolean isChildOf(Fqn<E> parentFqn)
- {
- return parentFqn.elements.size() != elements.size() && isChildOrEquals(parentFqn);
- }
-
- /**
- * Returns true if this Fqn is equals or the child of parentFqn.
- * Example usage:
- * <pre>
- * Fqn<String> f1 = Fqn.fromString("/a/b");
- * Fqn<String> f2 = Fqn.fromString("/a/b/c");
- * assertTrue(f1.isChildOrEquals(f2));
- * assertTrue(f1.isChildOrEquals(f1));
- * assertFalse(f2.isChildOrEquals(f1));
- * </pre>
- *
- * @param parentFqn candidate parent to test against
- * @return true if this Fqn is equals or the child of parentFqn.
- */
- public boolean isChildOrEquals(Fqn<E> parentFqn)
- {
- List<E> parentList = parentFqn.elements;
- if (parentList.size() > elements.size())
- {
- return false;
- }
- for (int i = parentList.size() - 1; i >= 0; i--)
- {
- if (!parentList.get(i).equals(elements.get(i)))
- {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Calculates a hash code by summing the hash code of all elements.
- *
- * @return a cached hashcode
- */
- private int _hashCode()
- {
- int hashCode = 0;
- int count = 1;
- Object o;
- for (E element : elements)
- {
- o = element;
- hashCode += (o == null) ? 0 : o.hashCode() * count++;
- }
- if (hashCode == 0)// fix degenerate case
- {
- hashCode = 0xFEED;
- }
- return hashCode;
- }
-
- /**
- * Returns the parent of this Fqn.
- * The parent of the root node is {@link #ROOT}.
- * Examples:
- * <pre>
- * Fqn<String> f1 = Fqn.fromString("/a");
- * Fqn<String> f2 = Fqn.fromString("/a/b");
- * assertEquals(f1, f2.getParent());
- * assertEquals(Fqn.ROOT, f1.getParent().getParent());
- * assertEquals(Fqn.ROOT, Fqn.ROOT.getParent());
- * </pre>
- *
- * @return the parent Fqn
- */
- public Fqn<E> getParent()
- {
- switch (elements.size())
- {
- case 0:
- case 1:
- return ROOT;
- default:
- return new Fqn<E>(elements.subList(0, elements.size() - 1));
- }
- }
-
- /**
- * Returns true if this is a root Fqn.
- *
- * @return true if the Fqn is Fqn.ROOT.
- */
- public boolean isRoot()
- {
- return elements.isEmpty();
- }
-
- /**
- * If this is the root, returns {@link Fqn#SEPARATOR}.
- *
- * @return a String representation of the last element that makes up this Fqn.
- */
- public String getLastElementAsString()
- {
- if (isRoot())
- {
- return SEPARATOR;
- }
- else
- {
- return String.valueOf(getLastElement());
- }
- }
-
- /**
- * Peeks into the elements that build up this Fqn. The list returned is
- * read-only, to maintain the immutable nature of Fqn.
- *
- * @return an unmodifiable list
- */
- public List<E> peekElements()
- {
- return elements;
- }
-
- /**
- * Compares this Fqn to another using {@link FqnComparator}.
- */
- public int compareTo(Fqn Fqn)
- {
- return FqnComparator.INSTANCE.compare(this, Fqn);
- }
-}
\ No newline at end of file
Deleted: core/trunk/src-old/org/jboss/cache/FqnComparator.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/FqnComparator.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/FqnComparator.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,106 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import net.jcip.annotations.Immutable;
-
-import java.util.Comparator;
-
-/**
- * Compares the order of two FQN.
- * Sorts by name, then by depth, e.g.
- * <pre>
- * aaa/bbb
- * xxx
- * xxx/ccc
- * </pre>
- *
- * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
- * @author Steve Woodcock (<a href="mailto:stevew@jofti.com">stevew(a)jofti.com</a>)
- */
-@Immutable
-public class FqnComparator implements Comparator<Fqn>
-{
- public static final FqnComparator INSTANCE = new FqnComparator();
-
- /**
- * Sorts by name, then depth.
- */
- public FqnComparator()
- {
- }
-
- /**
- * Returns -1 if the first comes before; 0 if they are the same; 1 if the
- * second Fqn comes before. <code>null</code> always comes first.
- */
- public int compare(Fqn fqn1, Fqn fqn2)
- {
- int s1 = fqn1.size();
- int s2 = fqn2.size();
-
- if (s1 == 0)
- {
- return (s2 == 0) ? 0 : -1;
- }
-
- if (s2 == 0)
- {
- return 1;
- }
-
- int size = Math.min(s1, s2);
-
- for (int i = 0; i < size; i++)
- {
- Object e1 = fqn1.get(i);
- Object e2 = fqn2.get(i);
- if (e1 == e2)
- {
- continue;
- }
- if (e1 == null)
- {
- return 0;
- }
- if (e2 == null)
- {
- return 1;
- }
- if (!e1.equals(e2))
- {
- int c = compareElements(e1, e2);
- if (c != 0)
- {
- return c;
- }
- }
- }
-
- return s1 - s2;
- }
-
- /**
- * Compares two Fqn elements.
- * If e1 and e2 are the same class and e1 implements Comparable,
- * returns e1.compareTo(e2).
- * Otherwise, returns e1.toString().compareTo(e2.toString()).
- */
- private int compareElements(Object e1, Object e2)
- {
- if (e1.getClass() == e2.getClass() && e1 instanceof Comparable)
- {
- return ((Comparable) e1).compareTo(e2);
- }
- else
- {
- return e1.toString().compareTo(e2.toString());
- }
- }
-
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/InvocationContext.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/InvocationContext.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/InvocationContext.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,257 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.config.Option;
-import org.jboss.cache.marshall.MethodCall;
-import org.jboss.cache.transaction.GlobalTransaction;
-
-import javax.transaction.Transaction;
-
-/**
- * This context holds information specific to a method invocation.
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- */
-public class InvocationContext implements Cloneable
-{
- private Transaction transaction;
- private GlobalTransaction globalTransaction;
- private Option optionOverrides;
- // defaults to true.
- private boolean originLocal = true;
- private boolean txHasMods;
- private boolean localRollbackOnly;
- private MethodCall methodCall;
-
- InvocationContext()
- {
- }
-
- public void setLocalRollbackOnly(boolean localRollbackOnly)
- {
- this.localRollbackOnly = localRollbackOnly;
- }
-
-
- /**
- * Retrieves the transaction associated with this invocation
- *
- * @return The transaction associated with this invocation
- */
- public Transaction getTransaction()
- {
- return transaction;
- }
-
- /**
- * Sets the transaction associated with this invocation
- *
- * @param transaction
- */
- public void setTransaction(Transaction transaction)
- {
- this.transaction = transaction;
- }
-
- /**
- * Retrieves the global transaction associated with this invocation
- *
- * @return the global transaction associated with this invocation
- */
- public GlobalTransaction getGlobalTransaction()
- {
- return globalTransaction;
- }
-
- /**
- * Sets the global transaction associated with this invocation
- *
- * @param globalTransaction
- */
- public void setGlobalTransaction(GlobalTransaction globalTransaction)
- {
- this.globalTransaction = globalTransaction;
- }
-
- /**
- * Retrieves the option overrides associated with this invocation
- *
- * @return the option overrides associated with this invocation
- */
- public Option getOptionOverrides()
- {
- if (optionOverrides == null)
- {
- optionOverrides = new Option();
- }
- return optionOverrides;
- }
-
- /**
- * Sets the option overrides associated with this invocation
- *
- * @param optionOverrides
- */
- public void setOptionOverrides(Option optionOverrides)
- {
- this.optionOverrides = optionOverrides;
- }
-
- /**
- * Tests if this invocation originated locally or from a remote cache.
- *
- * @return true if the invocation originated locally.
- */
- public boolean isOriginLocal()
- {
- return originLocal;
- }
-
- /**
- * If set to true, the invocation is assumed to have originated locally. If set to false,
- * assumed to have originated from a remote cache.
- *
- * @param originLocal
- */
- public void setOriginLocal(boolean originLocal)
- {
- this.originLocal = originLocal;
- }
-
- public String toString()
- {
- return "InvocationContext{" +
- "methodCall=" + methodCall +
- "transaction=" + transaction +
- ", globalTransaction=" + globalTransaction +
- ", optionOverrides=" + optionOverrides +
- ", originLocal=" + originLocal +
- ", txHasMods=" + txHasMods +
- '}';
- }
-
- public boolean isTxHasMods()
- {
- return txHasMods;
- }
-
- public void setTxHasMods(boolean b)
- {
- txHasMods = b;
- }
-
- public boolean isLocalRollbackOnly()
- {
- return localRollbackOnly;
- }
-
- /**
- * Resets this to the defaults used when constructing an invocation context object
- */
- public void reset()
- {
- transaction = null;
- globalTransaction = null;
- optionOverrides = null;
- originLocal = true;
- txHasMods = false;
- }
-
- public InvocationContext clone() throws CloneNotSupportedException
- {
- InvocationContext clone = (InvocationContext) super.clone();
- clone.setOptionOverrides(getOptionOverrides().clone());
- return clone;
- }
-
- /**
- * Sets the state of the InvocationContext based on the template context passed in
- *
- * @param template
- */
- public void setState(InvocationContext template)
- {
- if (template == null)
- {
- throw new NullPointerException("Template InvocationContext passed in to InvocationContext.setState() passed in is null");
- }
-
- this.setGlobalTransaction(template.getGlobalTransaction());
- this.setLocalRollbackOnly(template.isLocalRollbackOnly());
- this.setOptionOverrides(template.getOptionOverrides());
- this.setOriginLocal(template.isOriginLocal());
- this.setTransaction(template.getTransaction());
- this.setTxHasMods(template.isTxHasMods());
- }
-
- public boolean equals(Object o)
- {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- final InvocationContext that = (InvocationContext) o;
-
- if (localRollbackOnly != that.localRollbackOnly) return false;
- if (originLocal != that.originLocal) return false;
- if (txHasMods != that.txHasMods) return false;
- if (globalTransaction != null ? !globalTransaction.equals(that.globalTransaction) : that.globalTransaction != null)
- {
- return false;
- }
- if (optionOverrides != null ? !optionOverrides.equals(that.optionOverrides) : that.optionOverrides != null)
- {
- return false;
- }
- if (transaction != null ? !transaction.equals(that.transaction) : that.transaction != null) return false;
-
- return true;
- }
-
- public int hashCode()
- {
- int result;
- result = (transaction != null ? transaction.hashCode() : 0);
- result = 29 * result + (globalTransaction != null ? globalTransaction.hashCode() : 0);
- result = 29 * result + (optionOverrides != null ? optionOverrides.hashCode() : 0);
- result = 29 * result + (originLocal ? 1 : 0);
- result = 29 * result + (txHasMods ? 1 : 0);
- result = 29 * result + (localRollbackOnly ? 1 : 0);
- return result;
- }
-
- /**
- * @return the method call associated with this invocation
- */
- public MethodCall getMethodCall()
- {
- return methodCall;
- }
-
- /**
- * Sets the method call associated with this invocation.
- *
- * @param methodCall methodcall to set
- */
- public void setMethodCall(MethodCall methodCall)
- {
- this.methodCall = methodCall;
- }
-
- /**
- * Factory method that creates a context with a given method call.
- *
- * @param methodCall methodcall to use
- * @return invocation context
- */
- public static InvocationContext fromMethodCall(MethodCall methodCall)
- {
- InvocationContext ctx = new InvocationContext();
- ctx.methodCall = methodCall;
- return ctx;
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/Modification.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/Modification.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/Modification.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,290 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.util.Map;
-
-
-/**
- * Represents a modification in the cache. Contains the nature of the modification
- * (e.g. PUT, REMOVE), the fqn of the node, the new value and the previous value.
- * A list of modifications will be sent to all nodes in a cluster when a transaction
- * has been committed (PREPARE phase). A Modification is also used to roll back changes,
- * e.g. since we know the previous value, we can reconstruct the previous state by
- * applying the changes in a modification listin reverse order.
- *
- * @author <a href="mailto:bela@jboss.org">Bela Ban</a> Apr 12, 2003
- * @version $Revision$
- */
-public class Modification implements Externalizable
-{
-
- private static final long serialVersionUID = 7463314130283897197L;
-
- public enum ModificationType
- {
- PUT_KEY_VALUE,
- PUT_DATA,
- PUT_DATA_ERASE,
- REMOVE_NODE,
- REMOVE_KEY_VALUE,
- REMOVE_DATA,
- MOVE,
- UNKNOWN
- }
-
- private ModificationType type = ModificationType.UNKNOWN;
- private Fqn fqn = null;
- private Fqn fqn2 = null;
- private Object key = null;
- private Object value = null;
- private Object old_value = null;
- private Map data = null;
-
- /**
- * Constructs a new modification.
- */
- public Modification()
- {
- }
-
- /**
- * Constructs a new modification with details.
- */
- public Modification(ModificationType type, Fqn fqn, Object key, Object value)
- {
- this.type = type;
- this.fqn = fqn;
- this.key = key;
- this.value = value;
- }
-
- /**
- * Constructs a new modification with key.
- */
- public Modification(ModificationType type, Fqn fqn, Object key)
- {
- this.type = type;
- this.fqn = fqn;
- this.key = key;
- }
-
- /**
- * Constructs a new modification with data map.
- */
- public Modification(ModificationType type, Fqn fqn, Map data)
- {
- this.type = type;
- this.fqn = fqn;
- this.data = data;
- }
-
- /**
- * Constructs a new modification with fqn only.
- */
- public Modification(ModificationType type, Fqn fqn)
- {
- this.type = type;
- this.fqn = fqn;
- }
-
- /**
- * Constructs a new modification with fqn only.
- */
- public Modification(ModificationType type, Fqn fqn1, Fqn fqn2)
- {
- this.type = type;
- this.fqn = fqn1;
- this.fqn2 = fqn2;
- }
-
-
- /**
- * Returns the type of modification.
- */
- public ModificationType getType()
- {
- return type;
- }
-
- /**
- * Sets the type of modification.
- */
- public void setType(ModificationType type)
- {
- this.type = type;
- }
-
- /**
- * Returns the modification fqn.
- */
- public Fqn getFqn()
- {
- return fqn;
- }
-
- /**
- * Sets the modification fqn.
- */
- public void setFqn(Fqn fqn)
- {
- this.fqn = fqn;
- }
-
- public void setFqn2(Fqn fqn2)
- {
- this.fqn2 = fqn2;
- }
-
- public Fqn getFqn2()
- {
- return fqn2;
- }
-
- /**
- * Returns the modification key.
- */
- public Object getKey()
- {
- return key;
- }
-
- /**
- * Sets the modification key.
- */
- public void setKey(Object key)
- {
- this.key = key;
- }
-
- /**
- * Returns the modification value.
- */
- public Object getValue()
- {
- return value;
- }
-
- /**
- * Sets the modification value.
- */
- public void setValue(Object value)
- {
- this.value = value;
- }
-
- /**
- * Returns the <i>post</i> modification old value.
- */
- public Object getOldValue()
- {
- return old_value;
- }
-
- /**
- * Sets the <i>post</i> modification old value.
- */
- public void setOldValue(Object old_value)
- {
- this.old_value = old_value;
- }
-
- /**
- * Returns the modification Map set.
- */
- public Map getData()
- {
- return data;
- }
-
- /**
- * Sets the modification Map set.
- */
- public void setData(Map data)
- {
- this.data = data;
- }
-
- /**
- * Writes data to an external stream.
- */
- public void writeExternal(ObjectOutput out) throws IOException
- {
- out.writeObject(type);
-
- out.writeBoolean(fqn != null);
- if (fqn != null)
- {
- fqn.writeExternal(out);
- }
-
- out.writeObject(key);
- out.writeObject(value);
- out.writeObject(old_value);
-
- out.writeBoolean(data != null);
- if (data != null)
- {
- out.writeObject(data);
- }
- }
-
- /**
- * Reads data from an external stream.
- */
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
- {
- type = (ModificationType) in.readObject();
-
- if (in.readBoolean())
- {
- fqn = new Fqn();
- fqn.readExternal(in);
- }
-
- key = in.readObject();
- value = in.readObject();
- old_value = in.readObject();
-
- if (in.readBoolean())
- {
- data = (Map) in.readObject();
- }
- }
-
- /**
- * Returns debug information about this modification.
- */
- public String toString()
- {
- StringBuffer sb = new StringBuffer();
- sb.append(type.toString()).append(": ").append(fqn);
- if (key != null)
- {
- sb.append("\nkey=").append(key);
- }
- if (value != null)
- {
- sb.append("\nvalue=").append(value);
- }
- if (old_value != null)
- {
- sb.append("\nold_value=").append(old_value);
- }
- if (data != null)
- {
- sb.append("\ndata=").append(data);
- }
- return sb.toString();
- }
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/Node.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/Node.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/Node.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,280 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import net.jcip.annotations.ThreadSafe;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A Node is a {@link Fqn named} logical grouping of data in the JBoss {@link Cache}.
- * A node should be used to contain data for a single data record, for example
- * information about a particular person or account.
- * <p/>
- * One purpose of grouping cache data into separate nodes is to minimize transaction
- * locking interference, and increase concurrency. So for example, when multiple threads or
- * possibly distributed caches are acccessing different accounts simultaneously.
- * <p/>
- * Another is that when making changes to this node, its data might be kept in a single
- * database row or file on disk. (Persisted via the use of a {@link org.jboss.cache.loader.CacheLoader}.)
- * <p/>
- * A node has references to its children, parent (each node except the root - defined by {@link Fqn#ROOT} - has
- * a single parent) and data contained within the node (as key/value pairs). The
- * data access methods are similar to the collections {@link Map} interface,
- * but some are read-only or return copies of the underlying the data.
- * <p/>
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- * @see Cache
- * @since 2.0.0
- */
-@ThreadSafe
-public interface Node<K, V>
-{
- /**
- * Returns the parent node.
- * If this is the root node, this method returns <code>null</code>.
- *
- * @return the parent node, or null if this is the root node
- */
- Node<K, V> getParent();
-
- /**
- * Returns an immutable set of children nodes.
- *
- * @return an immutable {@link Set} of child nodes. Empty {@link Set} if there aren't any children.
- */
- Set<Node<K, V>> getChildren();
-
- /**
- * Returns an immutable set of children node names.
- *
- * @return an immutable {@link Set} of child node names. Empty {@link Set} if there aren't any children.
- */
- Set<Object> getChildrenNames();
-
- /**
- * Returns a map containing the data in this {@link Node}.
- *
- * @return a {@link Map} containing the data in this {@link Node}. If there is no data, an empty {@link Map} is returned. The {@link Map} returned is always immutable.
- */
- Map<K, V> getData();
-
- /**
- * Returns a {@link Set} containing the data in this {@link Node}.
- *
- * @return a {@link Set} containing the data in this {@link Node}. If there is no data, an empty {@link Set} is returned. The {@link Set} returned is always immutable.
- */
- Set<K> getKeys();
-
- /**
- * Returns the {@link Fqn} which represents the location of this {@link Node} in the cache structure. The {@link Fqn} returned is absolute.
- *
- * @return The {@link Fqn} which represents the location of this {@link Node} in the cache structure. The {@link Fqn} returned is absolute.
- */
- Fqn getFqn();
-
- /**
- * Adds a child node with the given {@link Fqn} under the current node. Returns the newly created node.
- * <p/>
- * If the child exists returns the child node anyway. Guaranteed to return a non-null node.
- * <p/>
- * The {@link Fqn} passed in is relative to the current node. The new child node will have an absolute fqn
- * calculated as follows: <pre>new Fqn(getFqn(), f)</pre>. See {@link Fqn} for the operation of this constructor.
- *
- * @param f {@link Fqn} of the child node, relative to the current node.
- * @return the newly created node, or the existing node if one already exists.
- */
- Node<K, V> addChild(Fqn<?> f);
-
- /**
- * Removes a child node specified by the given relative {@link Fqn}.
- * <p/>
- * If you wish to remove children based on absolute {@link Fqn}s, use the {@link Cache} interface instead.
- *
- * @param f {@link Fqn} of the child node, relative to the current node.
- * @return true if the node was found and removed, false otherwise
- */
- boolean removeChild(Fqn<?> f);
-
- /**
- * Removes a child node specified by the given name.
- *
- * @param childName name of the child node, directly under the current node.
- * @return true if the node was found and removed, false otherwise
- */
- boolean removeChild(Object childName);
-
-
- /**
- * Returns the child node
- *
- * @param f {@link Fqn} of the child node
- * @return null if the child does not exist.
- */
- Node<K, V> getChild(Fqn<?> f);
-
- /**
- * @param name name of the child
- * @return a direct child of the current node.
- */
- Node<K, V> getChild(Object name);
-
- /**
- * Associates the specified value with the specified key for this node.
- * If this node previously contained a mapping for this key, the old value is replaced by the specified value.
- *
- * @param key key with which the specified value is to be associated.
- * @param value value to be associated with the specified key.
- * @return Returns the old value contained under this key. Null if key doesn't exist.
- */
- V put(K key, V value);
-
- /**
- * If the specified key is not already associated with a value, associate it with the given value, and returns the
- * Object (if any) that occupied the space, or null.
- * <p/>
- * Equivalent to calling
- * <pre>
- * if (!node.getKeys().contains(key))
- * return node.put(key, value);
- * else
- * return node.get(key);
- * </pre>
- * <p/>
- * except that this is atomic.
- *
- * @param key key with which the specified value is to be associated.
- * @param value value to be associated with the specified key.
- * @return previous value associated with specified key, or null if there was no mapping for key.
- */
- V putIfAbsent(K key, V value);
-
- /**
- * Replace entry for key only if currently mapped to some value.
- * Acts as
- * <pre>
- * if ((node.getKeys().contains(key))
- * {
- * return node.put(key, value);
- * }
- * else
- * return null;
- * </pre>
- * <p/>
- * except that this is atomic.
- *
- * @param key key with which the specified value is associated.
- * @param value value to be associated with the specified key.
- * @return previous value associated with specified key, or <tt>null</tt>
- * if there was no mapping for key.
- */
- V replace(K key, V value);
-
- /**
- * Replace entry for key only if currently mapped to given value.
- * Acts as
- * <pre>
- * if (node.get(key).equals(oldValue))
- * {
- * node.putAll(key, newValue);
- * return true;
- * }
- * else
- * return false;
- * </pre>
- * <p/>
- * except that this is atomic.
- *
- * @param key key with which the specified value is associated.
- * @param oldValue value expected to be associated with the specified key.
- * @param newValue value to be associated with the specified key.
- * @return true if the value was replaced
- */
- boolean replace(K key, V oldValue, V newValue);
-
-
- /**
- * Copies all of the mappings from the specified map to this node's map.
- * If any data exists, existing keys are overwritten with the keys in the new map.
- * The behavior is equivalent to:
- * <pre>
- * Node node;
- * for (Map.Entry me : map.entrySet())
- * node.put(me.getKey(), me.getValue());
- * </pre>
- *
- * @param map map to copy from
- */
- void putAll(Map<K, V> map);
-
- /**
- * Similar to {@link #putAll(java.util.Map)} except that it removes any entries that exists in
- * the data map first. Note that this happens atomically, under a single lock. This is the analogous
- * to doing a {@link #clearData()} followed by a {@link #putAll(java.util.Map)} in the same transaction.
- *
- * @param map map to copy from
- */
- void replaceAll(Map<K, V> map);
-
-
- /**
- * Returns the value to which this node maps the specified key.
- * Returns <code>null</code> if the node contains no mapping for this key.
- *
- * @param key key of the data to return
- * @return the value to which this node maps the specified key, or <code>null</code> if the map contains no mapping for this key
- */
- V get(K key);
-
- /**
- * Removes the mapping for this key from this node if it is present.
- * Returns the value to which the node previously associated the key,
- * or <code>null</code> if the node contained no mapping for this key
- *
- * @param key key whose mapping is to be removed
- * @return previous value associated with specified key, or <code>null</code>
- * if there was no mapping for key
- */
- V remove(K key);
-
- /**
- * Removes all mappings from the node's data map.
- */
- void clearData();
-
- /**
- * @return the number of elements (key/value pairs) in the node's data map.
- */
- int dataSize();
-
- /**
- * Returns true if the child node denoted by the relative {@link Fqn} passed in exists.
- *
- * @param f {@link Fqn} relative to the current node of the child you are testing the existence of.
- * @return true if the child node denoted by the relative {@link Fqn} passed in exists.
- */
- boolean hasChild(Fqn<?> f);
-
- /**
- * Returns true if the child node denoted by the Object name passed in exists.
- *
- * @param o name of the child, relative to the current node
- * @return true if the child node denoted by the name passed in exists.
- */
- boolean hasChild(Object o);
-
- /**
- * Tests if a node reference is still valid. A node reference may become invalid if it has been evicted, for example,
- * in which case it should be looked up again from the cache.
- *
- * @return true if the node is valid.
- */
- boolean isValid();
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/NodeFactory.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/NodeFactory.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/NodeFactory.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,97 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.optimistic.TransactionWorkspace;
-import org.jboss.cache.optimistic.WorkspaceNode;
-import org.jboss.cache.optimistic.WorkspaceNodeImpl;
-
-import java.util.Map;
-
-/**
- * Generates new nodes based on the {@link CacheSPI} configuration.
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- */
-public class NodeFactory<K, V>
-{
- public enum NodeType
- {
- UNVERSIONED_NODE, VERSIONED_NODE, WORKSPACE_NODE
- }
-
- private CacheSPI<K, V> cache;
- private boolean optimistic;
-
- /**
- * Constructs an instance of the factory
- */
- public NodeFactory(CacheSPI<K, V> cache)
- {
- this.cache = cache;
- init();
- }
-
- /**
- * Initialises the node factory with the configuration from the cache.
- */
- public void init()
- {
- optimistic = cache.getConfiguration().isNodeLockingOptimistic();
- }
-
-
- /**
- * Creates a new {@link Node} instance.
- *
- * @param childName the new node's name
- * @param fqn the new node's Fqn
- * @param parent the new node's parent
- * @param data the new node's attribute map
- * @param mapSafe <code>true</code> if param <code>data</code> can safely
- * be directly assigned to the new node's data field;
- * <code>false</code> if param <code>data</code>'s contents
- * should be copied into the new node's data field.
- * @return the new node
- */
- public NodeSPI<K, V> createDataNode(Object childName, Fqn fqn, NodeSPI<K, V> parent, Map<K, V> data, boolean mapSafe)
- {
- NodeSPI<K, V> n = optimistic ? new VersionedNode<K, V>(fqn, parent, data, cache) : new UnversionedNode<K, V>(childName, fqn, data, mapSafe, cache);
- // always assume that new nodes do not have data loaded
- n.setDataLoaded(false);
- return n;
- }
-
- public Node<K, V> createNode(Object childName, Node<K, V> parent, Map<K, V> data)
- {
- return createNodeOfType(parent, childName, parent, data);
- }
-
- public Node<K, V> createNodeOfType(Node<K, V> template, Object childName, Node<K, V> parent, Map<K, V> data)
- {
- if (template instanceof WorkspaceNode)
- {
- NodeSPI<K, V> dataNodeParent = ((WorkspaceNode<K, V>) parent).getNode();
- TransactionWorkspace workspace = ((WorkspaceNode) template).getTransactionWorkspace();
- return createWorkspaceNode(dataNodeParent, workspace);
- }
-
- // not a workspace node.
- return createDataNode(childName, new Fqn(parent.getFqn(), childName), (NodeSPI<K, V>) parent, data, false);
- }
-
- public WorkspaceNode<K, V> createWorkspaceNode(NodeSPI<K, V> dataNode, TransactionWorkspace workspace)
- {
- return new WorkspaceNodeImpl<K, V>(dataNode, workspace);
- }
-
- public NodeSPI<K, V> createRootDataNode()
- {
- return createDataNode(null, Fqn.ROOT, null, null, false);
- }
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/NodeNotExistsException.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/NodeNotExistsException.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/NodeNotExistsException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,42 +0,0 @@
-// $Id$
-
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-
-package org.jboss.cache;
-
-
-
-
-/**
- * Thrown when an operation is attempted on a non-existing node in the cache
- *
- * @author <a href="mailto:bela@jboss.com">Bela Ban</a>.
- * @version $Id$
- */
-
-public class NodeNotExistsException extends CacheException {
-
- private static final long serialVersionUID = 779376138690777440L;
-
- public NodeNotExistsException() {
- super();
- }
-
-
- public NodeNotExistsException(String msg) {
- super(msg);
- }
-
-
- public NodeNotExistsException(String msg, Throwable cause) {
- super(msg, cause);
- }
-
-
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/NodeSPI.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/NodeSPI.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/NodeSPI.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,440 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import net.jcip.annotations.NotThreadSafe;
-import org.jboss.cache.lock.NodeLock;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.transaction.GlobalTransaction;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A more detailed interface to {@link Node}, which is used when writing plugins for or extending JBoss Cache. References are usually
- * obtained by calling methods on {@link org.jboss.cache.CacheSPI}.
- * <p/>
- * <B><I>You should NEVER attempt to directly cast a {@link Node} instance to this interface. In future, the implementation may not allow it.</I></B>
- * <p/>
- * This interface contains overridden method signatures of some methods from {@link Node}, overridden to ensure return
- * types of {@link Node} are replaced with {@link NodeSPI}.
- * <p/>
- * <b><i>An important note</i></b> on the xxxDirect() methods below. These methods are counterparts to similarly named
- * methods in {@link Node} - e.g., {@link NodeSPI#getDirect(Object)} is a direct access counterpart to {@link Node#get(Object)},
- * the difference being that:
- * <p/>
- * <ul>
- * <li>{@link Node#get(Object)} - Passes the call up the interceptor stack, applies all aspects including node locking, cache loading, passivation, etc etc.</li>
- * <li>{@link NodeSPI#getDirect(Object)} - directly works on the underlying data in the node.</li>
- * </ul>
- * <p/>
- * The big difference with the direct access methods are that it is the onus of the caller to ensure proper locks are obtained
- * prior to the call. A proper call should have gone through a locking-capable interceptor first and based on the cache
- * configuration's locking policy, an appropriate lock should be obtained prior to the call. These direct access methods will
- * throw {@link org.jboss.cache.lock.LockingException}s if appropriate locks haven't been obtained by the caller.
- * <p/>
- * It is important to node that the direct <b>read</b> methods, such as getDataDirect(), return unmodifiable collections.
- * In addition to being unmodifiable, they are also defensively copied from the underlying data map to ensure view consistency.
- * <p/>
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- * @see Node
- * @see org.jboss.cache.CacheSPI
- * @since 2.0.0
- */
-@NotThreadSafe
-public interface NodeSPI<K, V> extends Node<K, V>
-{
- /**
- * Returns true if the children of this node were loaded from a cache loader.
- *
- * @return true if the children of this node were loaded from a cache loader.
- */
- boolean isChildrenLoaded();
-
- /**
- * Sets if the children of this node were loaded from a cache loader.
- *
- * @param loaded true if loaded, false otherwise
- */
- void setChildrenLoaded(boolean loaded);
-
- /**
- * Returns true if the data was loaded from the cache loader.
- *
- * @return true if the data was loaded from the cache loader.
- */
- public boolean isDataLoaded();
-
- /**
- * Sets if the data was loaded from the cache loader.
- *
- * @param dataLoaded true if loaded, false otherwise
- */
- public void setDataLoaded(boolean dataLoaded);
-
- /**
- * Returns a map to access the raw children.
- * This method may return a null if the node does not have any children. It is important to note that this method
- * returns a direct reference to the underlying child map and is intended for internal use only. Incorrect use
- * may result in very inconsistent state of the cache.
- *
- * @return Map, keyed by child name, values Nodes.
- */
- Map<Object, Node<K, V>> getChildrenMapDirect();
-
- /**
- * Sets the node's children explictly.
- * This method will remove all children currently associated with this node and add all the children passed in.
- *
- * @param children cannot be null
- */
- void setChildrenMapDirect(Map<Object, Node<K, V>> children);
-
- /**
- * Returns an existing child or creates a new one using a global transaction.
- *
- * @param name name of child to create
- * @param tx transaction under which to create child
- * @return newly created node
- */
- NodeSPI<K, V> getOrCreateChild(Object name, GlobalTransaction tx);
-
- /**
- * Returns a lock for this node.
- *
- * @return node lock
- */
- NodeLock getLock();
-
- /**
- * Sets the FQN of this node and resets the names of all children as well.
- *
- * @param f fqn to set
- */
- void setFqn(Fqn<?> f);
-
- /**
- * Returns true if the instance has been deleted in the current transaction.
- *
- * @return true if the instance has been deleted in the current transaction.
- */
- boolean isDeleted();
-
- /**
- * Marks the node as being deleted (or not) in the current transaction. This is not recursive, child nodes are not affected.
- *
- * @param marker true if the node has been deleted, false if not.
- */
- void markAsDeleted(boolean marker);
-
- /**
- * Same as {@link #markAsDeleted(boolean)} except that the option to recurse into children is provided.
- *
- * @param marker true if the node has been deleted, false if not.
- * @param recursive if true, child nodes (and their children) are marked as well.
- */
- void markAsDeleted(boolean marker, boolean recursive);
-
- /**
- * Adds or replaces a child by name.
- *
- * @param nodeName child node name (not an FQN)
- * @param nodeToAdd child node
- */
- void addChild(Object nodeName, Node<K, V> nodeToAdd);
-
- /**
- * Prints details of this node to the StringBuffer passed in.
- *
- * @param sb StringBuffer to print to
- * @param indent depth of this node in the tree. Used to indent details by prepending spaces.
- */
- void printDetails(StringBuffer sb, int indent);
-
- /**
- * Prints basic information of this node to the StringBuffer passed in.
- *
- * @param sb StringBuffer to print to
- * @param indent depth of this node in the tree. Used to indent details by prepending spaces.
- */
-
- void print(StringBuffer sb, int indent);
-
- // versioning
- /**
- * Sets the data version of this node if versioning is supported.
- *
- * @param version data version to apply
- * @throws UnsupportedOperationException if versioning is not supported
- */
- void setVersion(DataVersion version);
-
- /**
- * Returns the data version of this node if versioning is supported.
- *
- * @return data version
- * @throws UnsupportedOperationException if versioning is not supported
- */
- DataVersion getVersion();
-
-
- // ------- these XXXDirect() methods work directly on the node and bypass the interceptor chain.
- /**
- * Functionally the same as {@link #getChildren()} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @return set of child nodes.
- * @see #getChildren()
- */
- Set<NodeSPI<K, V>> getChildrenDirect();
-
- /**
- * Directly removes all children for this node.
- * The only direct method that does not have a non-direct counterpart.
- */
- void removeChildrenDirect();
-
- /**
- * Retrieves children (directly), optionally including any marked as deleted nodes.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method.
- *
- * @param includeMarkedAsDeleted if true, the returned set will include nodes marked as deleted
- * @return a set of nodes
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- */
- Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedAsDeleted);
-
- /**
- * Retrives a child directly by name.
- * Functionally the same as {@link #getChild(Object)} except that it bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method.
- *
- * @param childName name of child
- * @return child node
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- * @see #getChild(Object)
- */
- NodeSPI<K, V> getChildDirect(Object childName);
-
- /**
- * Adds a child directly to a Node.
- * Functionally the same as {@link #addChild(Fqn)} except that it bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method.
- *
- * @param childName name of child
- * @return child node
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- * @see #addChild(Fqn)
- */
- NodeSPI<K, V> addChildDirect(Fqn childName);
-
- /**
- * Directly adds the node passed in to the children map of the current node. Will throw a CacheException if
- * <tt>child.getFqn().getParent().equals(getFqn())</tt> returns false.
- *
- * @param child child to add
- */
- void addChildDirect(NodeSPI<K, V> child);
-
- /**
- * Retrives a child directly by fully qualified name.
- * Functionally the same as {@link #getChild(Fqn)} except that it bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method.
- *
- * @param childName name of child
- * @return child node
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- * @see #getChild(Fqn)
- */
- NodeSPI<K, V> getChildDirect(Fqn childName);
-
- /**
- * Removes a child directly from a node.
- * Functionally the same as {@link #removeChild(Fqn)} except that it bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- *
- * @param fqn of child.
- * @return true if the node was found, false otherwise
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- * @see #removeChild(Fqn)
- */
- boolean removeChildDirect(Fqn fqn);
-
- /**
- * Removes a child directly from a node.
- * Functionally the same as {@link #removeChild(Object)} except that bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method.
- *
- * @param childName of child.
- * @return true if the node was found, false otherwise
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- * @see #removeChild(Object)
- */
- boolean removeChildDirect(Object childName);
-
-
- /**
- * Removes a data key directly from a node.
- * Functionally the same as {@link #remove(Object)} except that it bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method.
- *
- * @param key to remove
- * @return the old data contained under the key
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- * @see #remove(Object)
- */
- V removeDirect(K key);
-
- /**
- * Functionally the same as {@link #put(Object,Object)} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @param key of data
- * @param value of data
- * @return the previous value under the key passed in, or <tt>null</tt>
- * @see #put(Object,Object)
- */
- V putDirect(K key, V value);
-
- /**
- * Functionally the same as {@link #putAll(Map)} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @param data to put
- * @see #putAll(Map)
- */
- void putAllDirect(Map<K, V> data);
-
- /**
- * Functionally the same as {@link #getData()} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * Note that this returns a reference to access the node's data.
- * This data should only be modified by the cache itself.
- * This method should never return null.
- * <p/>
- * Also note that this method returns an unmodifiable reference to the underlying data map.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @return map containing data
- * @see #getData()
- */
- Map<K, V> getDataDirect();
-
- /**
- * Functionally the same as {@link #get(Object)} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @param key data to get
- * @return value under key
- * @see #get(Object)
- */
- V getDirect(K key);
-
-
- /**
- * Functionally the same as {@link #clearData()} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @see #clearData()
- */
- void clearDataDirect();
-
-
- /**
- * Functionally the same as {@link #getKeys()} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @return set of keys
- * @see #getKeys()
- */
- Set<K> getKeysDirect();
-
- /**
- * Functionally the same as {@link #getChildrenNames()} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @return set of children names
- * @see #getChildrenNames()
- */
- Set<Object> getChildrenNamesDirect();
-
- /**
- * Retrieves a reference to the cache in which this Node resides.
- *
- * @return a cache
- */
- CacheSPI<K, V> getCache();
-
- // ----------- these methods override their corresponding methods in Node, so that the return types are NodeSPI rather than Node.
-
- /**
- * Returns the parent node as a {@link NodeSPI}, instead
- * of {@link Node} from {@link Node#getParent()}, and is otherwise identical.
- *
- * @return parent node
- * @see Node#getParent()
- */
- NodeSPI<K, V> getParent();
-
- /**
- * @return true if the node has one or more child nodes; false otherwise.
- */
- boolean hasChildrenDirect();
-}
Deleted: core/trunk/src-old/org/jboss/cache/RPCManager.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/RPCManager.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/RPCManager.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,27 +0,0 @@
-package org.jboss.cache;
-
-import org.jboss.cache.marshall.MethodCall;
-import org.jgroups.Address;
-
-import java.lang.reflect.Method;
-import java.util.List;
-
-public interface RPCManager
-{
- public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, int mode, boolean excludeSelf, long timeout) throws Exception;
-
- public boolean isCoordinator();
-
- public Address getCoordinator();
-
- public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, boolean synchronous, boolean excludeSelf, int timeout) throws Exception;
-
- public List callRemoteMethods(List<Address> recipients, Method method, Object[] arguments, boolean synchronous, boolean excludeSelf, long timeout) throws Exception;
-
- public void setCache(CacheSPI c);
-
- /**
- * @return Returns the replication queue (if one is used), null otherwise.
- */
- public ReplicationQueue getReplicationQueue();
-}
Deleted: core/trunk/src-old/org/jboss/cache/RPCManagerImpl.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/RPCManagerImpl.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/RPCManagerImpl.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,75 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.marshall.MethodCall;
-import org.jgroups.Address;
-
-import java.lang.reflect.Method;
-import java.util.List;
-
-/**
- * Manager that handles all RPC calls between JBoss Cache instances
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- */
-public class RPCManagerImpl implements RPCManager
-{
- private CacheImpl c;
-
- /**
- * Empty ctor for mock object creation/unit testing
- */
- public RPCManagerImpl()
- {
- }
-
- public RPCManagerImpl(CacheSPI c)
- {
- this.c = (CacheImpl) c;
- }
-
- // for now, we delegate RPC calls to deprecated methods in CacheImpl.
-
- public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, int mode, boolean excludeSelf, long timeout) throws Exception
- {
- return c.callRemoteMethods(recipients, methodCall, mode, excludeSelf, timeout);
- }
-
- public boolean isCoordinator()
- {
- return c.isCoordinator();
- }
-
- public Address getCoordinator()
- {
- return c.getCoordinator();
- }
-
- public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, boolean synchronous, boolean excludeSelf, int timeout) throws Exception
- {
- return c.callRemoteMethods(recipients, methodCall, synchronous, excludeSelf, timeout);
- }
-
- public List callRemoteMethods(List<Address> recipients, Method method, Object[] arguments, boolean synchronous, boolean excludeSelf, long timeout) throws Exception
- {
- return c.callRemoteMethods(recipients, method, arguments, synchronous, excludeSelf, timeout);
- }
-
- public void setCache(CacheSPI c)
- {
- this.c = (CacheImpl) c;
- }
-
- /**
- * @return Returns the replication queue (if one is used), null otherwise.
- */
- public ReplicationQueue getReplicationQueue()
- {
- return c.getReplicationQueue();
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/Region.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/Region.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/Region.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,189 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.config.EvictionPolicyConfig;
-import org.jboss.cache.config.EvictionRegionConfig;
-import org.jboss.cache.eviction.EvictedEventNode;
-import org.jboss.cache.eviction.EvictionPolicy;
-import org.jboss.cache.eviction.LRUPolicy;
-
-/**
- * Defines characteristics such as class loading and eviction of {@link org.jboss.cache.Node}s belonging to a Region in a {@link Cache}.
- * A Region is described by an {@link #getFqn() Fqn} relative to the root of the cache.
- * All nodes and child nodes of this Fqn belong to this region.
- * <p/>
- * If a region is to be recognised as an eviction region (region of type {@link Type#EVICTION} then
- * it <b>must</b> have an {@link org.jboss.cache.config.EvictionPolicyConfig} set using {@link #setEvictionPolicy(org.jboss.cache.config.EvictionPolicyConfig)}.
- * <p/>
- * Similarly, to be recognised as a marshalling region (region of type {@link Type#MARSHALLING} then it <b>must</b> have a
- * {@link ClassLoader} registered using {@link #registerContextClassLoader(ClassLoader)}.
- * <p/>
- * Note that a single region can be both an eviction and marshalling region at the same time.
- * <p/>
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- * @see org.jboss.cache.RegionManager
- * @since 2.0.0
- */
-public interface Region extends Comparable<Region>
-{
-
- /**
- * Types of regions.
- */
- public enum Type
- {
- EVICTION, MARSHALLING, ANY
- }
-
- /**
- * Registers a specific {@link ClassLoader} for this region,
- * overridding the default cache class loader.
- *
- * @param classLoader specific class loader
- */
- void registerContextClassLoader(ClassLoader classLoader);
-
- /**
- * Unregisters a registered {@link ClassLoader}s for this region.
- */
- void unregisterContextClassLoader();
-
- /**
- * Activates this region for replication.
- * By default, the entire cache is activated for replication at start-up.
- *
- * @throws RegionNotEmptyException if the {@link Fqn} that represents this region already exists and contains data or children.
- */
- void activate() throws RegionNotEmptyException;
-
- /**
- * Activates this region for replication, but if the {@link Fqn} that represents this region already exists and
- * either contains data or children, no state transfers take place. The region is simply marked as active in this
- * case.
- */
- public void activateIfEmpty();
-
- /**
- * Deactivates this region from being replicated.
- */
- void deactivate();
-
- /**
- * Sets this region as active - this only marks a flag
- * and does not actually activates or
- * deactivates this region. Use {@link #activate()}
- * and {@link #deactivate()} for the full process.
- *
- * @param b
- */
- void setActive(boolean b);
-
- /**
- * Returns true if this region has been activated.
- *
- * @return true if this region has been activated.
- */
- boolean isActive();
-
- /**
- * Returns the configured {@link ClassLoader} for this region.
- *
- * @return a ClassLoader
- */
- ClassLoader getClassLoader();
-
- /**
- * Configures an eviction policy for this region.
- *
- * @param evictionPolicyConfig configuration to set
- */
- void setEvictionPolicy(EvictionPolicyConfig evictionPolicyConfig);
-
- /**
- * Returns an eviction policy configuration.
- *
- * @return an eviction policy configuration
- */
- EvictionPolicyConfig getEvictionPolicyConfig();
-
- /**
- * Returns an eviction policy.
- *
- * @return an eviction policy
- */
- EvictionPolicy getEvictionPolicy();
-
- /**
- * Returns an eviction region configuration for this region.
- *
- * @return an eviction region configuration
- */
- EvictionRegionConfig getEvictionRegionConfig();
-
- /**
- * Clears the node event queue used for processing eviction.
- *
- * @see #nodeEventQueueSize()
- */
- void resetEvictionQueues();
-
- /**
- * Returns the size of the node event queue, used by the eviction thread.
- *
- * @return number of events
- */
- int nodeEventQueueSize();
-
- /**
- * Returns the most recent {@link org.jboss.cache.eviction.EvictedEventNode} added to the event queue by
- * {@link #putNodeEvent(EvictedEventNode)}.
- *
- * @return the last {@link org.jboss.cache.eviction.EvictedEventNode}, or null if no more events exist
- */
- EvictedEventNode takeLastEventNode();
-
- /**
- * Adds an {@link org.jboss.cache.eviction.EvictedEventNode} to the internal queue for processing
- * by the eviction thread.
- *
- * @param event event to add
- */
- void putNodeEvent(EvictedEventNode event);
-
- /**
- * Marks a {@link org.jboss.cache.Node} as currently in use, by adding an event to the eviction queue.
- * If there is an {@link EvictionPolicy} associated with this region, and
- * it respects this event (e.g., {@link LRUPolicy} does), then the {@link org.jboss.cache.Node} will not
- * be evicted until {@link #unmarkNodeCurrentlyInUse(Fqn)} is invoked.
- * <p/>
- * This mechanism can be used to prevent eviction of data that the application
- * is currently using, in the absence of any locks on the {@link org.jboss.cache.Node} where the
- * data is stored.
- *
- * @param fqn Fqn of the node.
- * @see #unmarkNodeCurrentlyInUse(Fqn)
- */
- void markNodeCurrentlyInUse(Fqn fqn, long timeout);
-
- /**
- * Adds an event to the eviction queue indicating that a node is no longer in use.
- *
- * @param fqn Fqn of the node.
- * @see #markNodeCurrentlyInUse(Fqn,long)
- */
- void unmarkNodeCurrentlyInUse(Fqn fqn);
-
- /**
- * Returns the {@link org.jboss.cache.Fqn} of this region.
- *
- * @return the Fqn
- */
- Fqn getFqn();
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/RegionImpl.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/RegionImpl.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/RegionImpl.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,243 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.config.EvictionPolicyConfig;
-import org.jboss.cache.config.EvictionRegionConfig;
-import org.jboss.cache.eviction.EvictedEventNode;
-import org.jboss.cache.eviction.EvictionPolicy;
-import org.jboss.cache.eviction.NodeEventType;
-import org.jboss.cache.util.Util;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Default implementation of a {@link Region}
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- */
-public class RegionImpl implements Region
-{
- private static final Log log = LogFactory.getLog(RegionImpl.class);
-
- private RegionManager regionManager;
- private Fqn fqn;
- private boolean active;
- private ClassLoader classLoader;
- private BlockingQueue<EvictedEventNode> nodeEventQueue = null;
- private int capacityWarnThreshold = 0;
- private EvictionRegionConfig configuration = new EvictionRegionConfig();
- private EvictionPolicy policy;
-
- /**
- * Constructs a marshalling region from an fqn and region manager.
- */
- public RegionImpl(Fqn fqn, RegionManager regionManager)
- {
- this.fqn = fqn;
- this.regionManager = regionManager;
- this.active = !regionManager.isDefaultInactive();
- }
-
- /**
- * Constructs an eviction region from a policy and configuration, defined by an fqn and region manager.
- */
- public RegionImpl(EvictionPolicy policy, EvictionRegionConfig config, Fqn fqn, RegionManager regionManager)
- {
- this(fqn, regionManager);
- this.configuration = config;
- this.policy = policy;
- createQueue();
- }
-
- public void registerContextClassLoader(ClassLoader classLoader)
- {
- this.classLoader = classLoader;
- }
-
- public void unregisterContextClassLoader()
- {
- this.classLoader = null;
- }
-
- public void activate()
- {
- regionManager.activate(fqn);
- active = true;
- }
-
- public void activateIfEmpty()
- {
- regionManager.activateIfEmpty(fqn);
- active = true;
- }
-
- public void deactivate()
- {
- regionManager.deactivate(fqn);
- active = false;
- }
-
- public boolean isActive()
- {
- return active;
- }
-
- public ClassLoader getClassLoader()
- {
- return classLoader;
- }
-
- public Fqn getFqn()
- {
- return fqn;
- }
-
- public void setActive(boolean b)
- {
- active = b;
- }
-
- // -------- eviction stuff -----
-
- public void markNodeCurrentlyInUse(Fqn fqn, long timeout)
- {
- EvictedEventNode markUse = new EvictedEventNode(fqn, NodeEventType.MARK_IN_USE_EVENT);
- markUse.setInUseTimeout(timeout);
- putNodeEvent(markUse);
- }
-
- public void unmarkNodeCurrentlyInUse(Fqn fqn)
- {
- EvictedEventNode markNoUse = new EvictedEventNode(fqn, NodeEventType.UNMARK_USE_EVENT);
- putNodeEvent(markNoUse);
- }
-
- public String toString()
- {
- return "RegionImpl{" +
- "fqn=" + fqn +
- "; classloader="+ classLoader +
- "; active=" + active +
- "; eviction=" + (getEvictionPolicy() != null) +
- "; timerThreadRegistered=" + (getEvictionPolicy() != null && regionManager.getEvictionTimerTask().isRegionRegisteredForProcessing(this)) +
- '}';
- }
-
- public int compareTo(Region other)
- {
- return getFqn().compareTo(other.getFqn());
- }
-
- public void putNodeEvent(EvictedEventNode event)
- {
- try
- {
- if (nodeEventQueue == null) createQueue();// in case the queue does not exist yet.
- if (nodeEventQueue.size() > capacityWarnThreshold)
- {
- log.warn("putNodeEvent(): eviction node event queue size is at 98% threshold value of capacity: " + configuration.getEventQueueSize() +
- " Region: " + fqn +
- " You will need to reduce the wakeUpIntervalSeconds parameter.");
- }
-
- nodeEventQueue.put(event);
- }
- catch (InterruptedException e)
- {
- log.debug("give up put", e);
- }
- }
-
- public EvictedEventNode takeLastEventNode()
- {
- try
- {
- return nodeEventQueue.poll(0, TimeUnit.SECONDS);
- }
- catch (InterruptedException e)
- {
- log.debug("trace", e);
- }
- return null;
- }
-
- public int nodeEventQueueSize()
- {
- return nodeEventQueue.size();
- }
-
- public void resetEvictionQueues()
- {
- nodeEventQueue.clear();
- }
-
- private synchronized void createQueue()
- {
- if (nodeEventQueue == null)
- {
- if (configuration == null)
- {
- throw new IllegalArgumentException("null eviction configuration");
- }
- int size = configuration.getEventQueueSize();
- capacityWarnThreshold = (98 * size) / 100 - 100;
- if (capacityWarnThreshold <= 0)
- {
- throw new RuntimeException("Capacity warn threshold used in eviction is smaller than 1.");
- }
- nodeEventQueue = new LinkedBlockingQueue<EvictedEventNode>(size);
- }
- }
-
- public EvictionRegionConfig getEvictionRegionConfig()
- {
- return this.configuration;
- }
-
- public EvictionPolicyConfig getEvictionPolicyConfig()
- {
- return configuration == null ? null : configuration.getEvictionPolicyConfig();
- }
-
- public EvictionPolicy getEvictionPolicy()
- {
- return policy;
- }
-
- public void setEvictionPolicy(EvictionPolicyConfig evictionPolicyConfig)
- {
- configuration.setEvictionPolicyConfig(evictionPolicyConfig);
- policy = createPolicy(evictionPolicyConfig.getEvictionPolicyClass());
- regionManager.getEvictionTimerTask().addRegionToProcess(this);
- if (nodeEventQueue == null) createQueue();
- }
-
- private EvictionPolicy createPolicy(String className)
- {
- if (className == null)
- {
- throw new IllegalArgumentException("null className");
- }
- try
- {
- if (log.isTraceEnabled()) log.trace("Instantiating " + className);
- EvictionPolicy ep = (EvictionPolicy) Util.loadClass(className).newInstance();
- ep.setCache(regionManager.getCache());
- return ep;
- }
- catch (Exception e)
- {
- log.fatal("Unable to instantiate eviction policy class " + className, e);
- return null;
- }
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/RegionManager.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/RegionManager.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/RegionManager.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,819 +0,0 @@
-package org.jboss.cache;
-
-import net.jcip.annotations.ThreadSafe;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.buddyreplication.BuddyManager;
-import org.jboss.cache.config.ConfigurationException;
-import org.jboss.cache.config.EvictionConfig;
-import org.jboss.cache.config.EvictionRegionConfig;
-import org.jboss.cache.eviction.EvictionTimerTask;
-import org.jboss.cache.eviction.RegionNameConflictException;
-import org.jboss.cache.lock.NodeLock;
-import org.jgroups.Address;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Manages multiple {@link Region}s for a Cache instance.
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
- * @since 2.0.0
- */
-@ThreadSafe
-public class RegionManager
-{
- /**
- * The default region used in XML configuration files when defining eviction policies. Any
- * eviction settings bound under this 'default' Fqn is appplied to {@link org.jboss.cache.Fqn#ROOT} internally so
- * any region that is not explicitly defined comes under the settings defined for this default.
- */
- public static final Fqn DEFAULT_REGION = new Fqn("_default_");
-
- /**
- * A registry of regions that have been defined.
- */
- private Map<Fqn, Region> regionsRegistry = new ConcurrentHashMap<Fqn, Region>();
- private boolean defaultInactive;
- private Log log = LogFactory.getLog(RegionManager.class);
- private CacheImpl cache;
- private boolean usingEvictions;
- private EvictionConfig evictionConfig;
- private EvictionTimerTask evictionTimerTask = new EvictionTimerTask();
-
- protected final Set<Fqn> activationChangeNodes = Collections.synchronizedSet(new HashSet<Fqn>());
-
- /**
- * Constructs a new instance not attached to a cache.
- */
- public RegionManager()
- {
- }
-
- /**
- * Constructs a new instance attached to a cache.
- */
- public RegionManager(CacheImpl cache)
- {
- this.cache = cache;
- }
-
- /**
- * Returns true if evictions are being processed.
- */
- public boolean isUsingEvictions()
- {
- return usingEvictions;
- }
-
- /**
- * Returns true if replication is by default inactive for new {@link Region}s.
- */
- public boolean isDefaultInactive()
- {
- return defaultInactive;
- }
-
- /**
- * Sets if replication for new {@link Region}s is by default inactive.
- */
- public void setDefaultInactive(boolean defaultInactive)
- {
- this.defaultInactive = defaultInactive;
- }
-
- /**
- * Helper utility that checks for a {@link ClassLoader} registered for the
- * given {@link Fqn}, and if found sets it as the TCCL. If the given Fqn is
- * under the _BUDDY_BACKUP_ region, the equivalent region in the main
- * cache is used to find the {@link ClassLoader}.
- *
- * @param fqn Fqn pointing to a region for which a special classloader
- * may have been registered.
- */
- public void setContextClassLoaderAsCurrent(Fqn fqn)
- {
- if (fqn.isChildOf(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN))
- {
- if (fqn.size() <= 2)
- {
- fqn = Fqn.ROOT;
- }
- else
- {
- fqn = fqn.getSubFqn(2, fqn.size());
- }
- }
- Region region = getRegion(fqn, false);
- ClassLoader regionCL = (region == null) ? null : region.getClassLoader();
- if (regionCL != null)
- {
- Thread.currentThread().setContextClassLoader(regionCL);
- }
-
- }
-
- /**
- * Returns a region by {@link Fqn}, creating it optionally if absent. If the region does not exist and <tt>createIfAbsent</tt>
- * is <tt>false</tt>, a parent region which may apply to the {@link Fqn} is sought.
- */
- public Region getRegion(Fqn fqn, boolean createIfAbsent)
- {
- return getRegion(fqn, Region.Type.ANY, createIfAbsent);
- }
-
- /**
- * An overloaded form of {@link #getRegion(Fqn,boolean)} that takes an additional {@link org.jboss.cache.Region.Type}
- * parameter to force regions of a specific type.
- *
- * @see org.jboss.cache.Region.Type
- */
- public Region getRegion(Fqn fqn, Region.Type type, boolean createIfAbsent)
- {
- Fqn fqnToUse = fqn;
- if (DEFAULT_REGION.equals(fqnToUse)) fqnToUse = Fqn.ROOT;
- // first see if a region for this specific Fqn exists
- if (regionsRegistry.containsKey(fqnToUse))
- {
- Region r = regionsRegistry.get(fqnToUse);
-
- // this is a very poor way of telling whether a region is a marshalling one or an eviction one. :-(
- // mandates that class loaders be registered for marshalling regions.
- if (type == Region.Type.ANY
- || (type == Region.Type.MARSHALLING && r.getClassLoader() != null)
- || (type == Region.Type.EVICTION && r.getEvictionPolicyConfig() != null))
- {
- return r;
- }
- }
-
- // if not, attempt to create one ...
- if (createIfAbsent)
- {
- Region r = new RegionImpl(fqnToUse, this);
- regionsRegistry.put(fqnToUse, r);
- if (type == Region.Type.MARSHALLING)
- {
- // insert current class loader into region so at least it is recognised as a marshalling region
- r.registerContextClassLoader(getClass().getClassLoader());
- }
- return r;
- }
- else
- {
- // first test if the default region has been defined. If not, and if eviction regions
- // are in use, throw an exception since it is required.
- if (isUsingEvictions() && !regionsRegistry.containsKey(Fqn.ROOT))
- {
- throw new RuntimeException("No default eviction region defined!");
- }
- }
-
- // else try and find a parent which has a defined region, may return null if nothing is defined.
- Region nextBestThing = null;
- Fqn nextFqn = fqnToUse;
-
- while (nextBestThing == null)
- {
- nextFqn = nextFqn.getParent();
- if (regionsRegistry.containsKey(nextFqn))
- {
- Region r = regionsRegistry.get(nextFqn);
-
- // this is a very poor way of telling whether a region is a marshalling one or an eviction one. :-(
- // mandates that class loaders be registered for marshalling regions.
- if (type == Region.Type.ANY
- || (type == Region.Type.MARSHALLING && r.getClassLoader() != null)
- || (type == Region.Type.EVICTION && r.getEvictionPolicyConfig() != null))
- {
- nextBestThing = r;
- }
- }
- if (nextFqn.isRoot()) break;
- }
-
- return nextBestThing;
- }
-
- /**
- * Returns a region using Fqn.fromString(fqn), calling {@link #getRegion(Fqn,boolean)}
- *
- * @param fqn
- * @param createIfAbsent
- * @see #getRegion(Fqn,boolean)
- */
- public Region getRegion(String fqn, boolean createIfAbsent)
- {
- return getRegion(Fqn.fromString(fqn), createIfAbsent);
- }
-
- /**
- * Removes a {@link org.jboss.cache.Region} identified by the given fqn.
- *
- * @param fqn fqn of the region to remove
- * @return true if such a region existed and was removed.
- */
- public boolean removeRegion(Fqn fqn)
- {
- Region r = regionsRegistry.remove(fqn);
- if (r == null) return false;
-
- if (isUsingEvictions() && r.getEvictionPolicy() != null)
- {
- evictionTimerTask.removeRegionToProcess(r);
- }
- return true;
- }
-
- /**
- * @return the eviction timer task object associated with this Region Manager.
- */
- protected EvictionTimerTask getEvictionTimerTask()
- {
- return evictionTimerTask;
- }
-
- /**
- * Activates unmarshalling of replication messages for the region
- * rooted in the given Fqn.
- * <p/>
- * <strong>NOTE:</strong> This method will cause the creation of a node
- * in the local cache at <code>subtreeFqn</code> whether or not that
- * node exists anywhere else in the cluster. If the node does not exist
- * elsewhere, the local node will be empty. The creation of this node will
- * not be replicated.
- * <p/>
- *
- * @param fqn representing the region to be activated.
- * @throws RegionNotEmptyException if the node <code>fqn</code>
- * exists and already has either data or children
- */
- public void activate(Fqn fqn) throws RegionNotEmptyException
- {
- activate(fqn, false);
- }
-
- /**
- * Attempts to activate a given region rooted at a given Fqn, similar to {@link #activate(Fqn)} except
- * that if the fqn is currently already in use (probably already been activated) this method is a no-op.
- *
- * @param fqn which represents the region to activate
- */
- public void activateIfEmpty(Fqn fqn)
- {
- activate(fqn, true);
- }
-
- private void activate(Fqn fqn, boolean suppressRegionNotEmptyException)
- {
- try
- {
- if (log.isTraceEnabled()) log.trace("Activating region " + fqn);
- Region r = getRegion(fqn, false);
- if (r != null)
- {
- if (!defaultInactive && r.getClassLoader() == null)
- {
- // This region's state will no match that of a non-existent one
- // So, there is no reason to keep this region any more
-
- // (Brian) We shouldn't do this anymore; now outside code
- // can have a ref to the region!!
- removeRegion(fqn);
- }
- else
- {
- //r.activate();
- r.setActive(true);
- // FIXME - persistent state transfer counts too!
- if (cache.getConfiguration().isFetchInMemoryState())
- {
- activateRegion(r.getFqn(), suppressRegionNotEmptyException);
- }
- }
- }
- else if (defaultInactive)
- {
- // "Active" region is not the default, so create a region
- r = getRegion(fqn, true);
- r.setActive(true);
- // FIXME - persistent state transfer counts too!
- if (cache.getConfiguration().isFetchInMemoryState())
- {
- activateRegion(r.getFqn(), suppressRegionNotEmptyException);
- }
- }
- }
- catch (RuntimeException re)
- {
- throw re;
- }
- catch (Exception e)
- {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Causes the cache to transfer state for the subtree rooted at
- * <code>subtreeFqn</code> and to begin accepting replication messages
- * for that subtree.
- * <p/>
- * <strong>NOTE:</strong> This method will cause the creation of a node
- * in the local cache at <code>subtreeFqn</code> whether or not that
- * node exists anywhere else in the cluster. If the node does not exist
- * elsewhere, the local node will be empty. The creation of this node will
- * not be replicated.
- *
- * @param fqn Fqn string indicating the uppermost node in the
- * portion of the cache that should be activated.
- * @throws RegionNotEmptyException if the node <code>subtreeFqn</code>
- * exists and has either data or children
- */
- private void activateRegion(Fqn fqn, boolean suppressRegionNotEmptyException)
- {
- // Check whether the node already exists and has data
- Node subtreeRoot = cache.findNode(fqn);
-
- /*
- * Commented out on Nov 16,2006 Manik&Vladimir
- *
- * if (!(cache.isNodeEmpty(subtreeRoot)))
- {
- throw new RegionNotEmptyException("Node " + subtreeRoot.getFqn() + " already exists and is not empty");
- }*/
-
- if (isActivatingDeactivating(fqn))
- {
- throw new CacheException("Region " + subtreeRoot.getFqn() + " is already being activated/deactivated");
- }
-
- if (log.isDebugEnabled())
- {
- log.debug("activating " + fqn);
- }
-
- try
- {
-
- // Add this fqn to the set of those we are activating
- // so calls to _getState for the fqn can return quickly
- activationChangeNodes.add(fqn);
-
- Region region = getRegion(fqn, true);
-
- BuddyManager buddyManager = cache.getBuddyManager();
- // Request partial state from the cluster and integrate it
- if (buddyManager == null)
- {
- // Get the state from any node that has it and put it
- // in the main cache
- if (subtreeRoot == null)
- {
- // We'll update this node with the state we receive
- subtreeRoot = cache.createSubtreeRootNode(fqn);
- }
-
- List<Address> members = cache.getMembers();
- cache.fetchPartialState(members, subtreeRoot.getFqn());
- }
- else
- {
- // Get the state from each DataOwner and integrate in their
- // respective buddy backup cache
- List<Address> buddies = buddyManager.getBuddyAddresses();
- for (Address buddy : buddies)
- {
- List<Address> sources = new ArrayList<Address>(1);
- sources.add(buddy);
- Fqn base = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, BuddyManager.getGroupNameFromAddress(buddy));
- Fqn buddyRoot = new Fqn(base, fqn);
- subtreeRoot = cache.findNode(buddyRoot);
- if (subtreeRoot == null)
- {
- // We'll update this node with the state we receive
- subtreeRoot = cache.createSubtreeRootNode(buddyRoot);
- }
- cache.fetchPartialState(sources, fqn, subtreeRoot.getFqn());
- }
- }
- }
- catch (Throwable t)
- {
- log.error("failed to activate " + fqn, t);
-
- // "Re-deactivate" the region
- try
- {
- inactivateRegion(fqn);
- }
- catch (Exception e)
- {
- log.error("failed inactivating " + fqn, e);
- // just swallow this one and throw the first one
- }
-
- // Throw the exception on, wrapping if necessary
- if (t instanceof RegionNotEmptyException)
- {
- if (!suppressRegionNotEmptyException) throw (RegionNotEmptyException) t;
- }
- else if (t instanceof CacheException)
- {
- throw (CacheException) t;
- }
- else
- {
- throw new CacheException(t.getClass().getName() + " " +
- t.getLocalizedMessage(), t);
- }
- }
- finally
- {
- activationChangeNodes.remove(fqn);
- }
- }
-
- /**
- * Convenienve method. If the region defined by fqn does not exist, {@link #isDefaultInactive()} is returned, otherwise
- * !{@link Region#isActive()} is returned.
- *
- * @param fqn fqn to test
- * @return true if inactive
- */
- public boolean isInactive(Fqn fqn)
- {
- Region region = getRegion(fqn, false);
- return region == null ? defaultInactive : !region.isActive();
- }
-
-
- /**
- * Causes the cache to stop accepting replication events for the subtree
- * rooted at <code>subtreeFqn</code> and evict all nodes in that subtree.
- * <p/>
- * This is legacy code and should not be called directly. This is a private method for now and will be refactored out.
- * You should be using {@link #activate(Fqn)} and {@link #deactivate(Fqn)}
- * <p/>
- *
- * @param fqn Fqn string indicating the uppermost node in the
- * portion of the cache that should be activated.
- * @throws RegionNameConflictException if <code>subtreeFqn</code> indicates
- * a node that is part of another
- * subtree that is being specially
- * managed (either by activate/inactiveRegion()
- * or by registerClassLoader())
- * @throws CacheException if there is a problem evicting nodes
- * @throws IllegalStateException if {@link org.jboss.cache.config.Configuration#isUseRegionBasedMarshalling()} is <code>false</code>
- */
- private void inactivateRegion(Fqn fqn) throws CacheException
- {
- if (isActivatingDeactivating(fqn))
- {
- throw new CacheException("Region " + fqn + " is already being activated/deactivated");
- }
-
- NodeSPI parent = null;
- NodeSPI subtreeRoot = null;
- boolean parentLocked = false;
- boolean subtreeLocked = false;
- NodeLock parentLock = null;
- NodeLock subtreeLock = null;
-
- try
- {
- // Record that this fqn is in status change, so can't provide state
- activationChangeNodes.add(fqn);
-
- if (!isInactive(fqn))
- {
- deactivate(fqn);
- }
-
- // Create a list with the Fqn in the main cache and any buddy backup trees
- BuddyManager buddyManager = cache.getBuddyManager();
- ArrayList<Fqn> list = new ArrayList<Fqn>();
- list.add(fqn);
-
- if (buddyManager != null)
- {
- Set buddies = cache.getChildrenNames(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
- if (buddies != null)
- {
- for (Iterator it = buddies.iterator(); it.hasNext();)
- {
- Fqn base = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, it.next());
- list.add(new Fqn(base, fqn));
- }
- }
- }
-
- long stateFetchTimeout = cache.getConfiguration().getLockAcquisitionTimeout() + 5000;
- // Remove the subtree from the main cache and any buddy backup trees
- for (Iterator<Fqn> it = list.iterator(); it.hasNext();)
- {
- Fqn subtree = it.next();
- subtreeRoot = cache.findNode(subtree);
- if (subtreeRoot != null)
- {
- // Acquire locks
- Object owner = cache.getOwnerForLock();
- subtreeLock = subtreeRoot.getLock();
- subtreeLock.acquireAll(owner, stateFetchTimeout, NodeLock.LockType.WRITE);
- subtreeLocked = true;
-
- // Lock the parent, as we're about to write to it
- parent = subtreeRoot.getParent();
- if (parent != null)
- {
- parentLock = parent.getLock();
- parentLock.acquire(owner, stateFetchTimeout, NodeLock.LockType.WRITE);
- parentLocked = true;
- }
-
- // Remove the subtree
- cache._evictSubtree(subtree);
-
- // Release locks
- if (parent != null)
- {
- log.debug("forcing release of locks in parent");
- parentLock.releaseAll();
- }
-
- parentLocked = false;
-
- log.debug("forcing release of all locks in subtree");
- subtreeLock.releaseAll();
- subtreeLocked = false;
- }
- }
- }
- catch (InterruptedException ie)
- {
- throw new CacheException("Interrupted while acquiring lock", ie);
- }
- finally
- {
- // If we didn't succeed, undo the marshalling change
- // NO. Since we inactivated, we may have missed changes
- //if (!success && !inactive)
- // marshaller_.activate(subtreeFqn);
-
- // If necessary, release locks
- if (parentLocked)
- {
- log.debug("forcing release of locks in parent");
- try
- {
- parentLock.releaseAll();
- }
- catch (Throwable t)
- {
- log.error("failed releasing locks", t);
- }
- }
- if (subtreeLocked)
- {
- log.debug("forcing release of all locks in subtree");
- try
- {
- subtreeLock.releaseAll();
- }
- catch (Throwable t)
- {
- log.error("failed releasing locks", t);
- }
- }
-
- activationChangeNodes.remove(fqn);
- }
- }
-
- /**
- * <p/>
- * This is legacy code and should not be called directly. This is a private method for now and will be refactored out.
- * You should be using {@link #activate(Fqn)} and {@link #deactivate(Fqn)}
- * <p/>
- *
- * @param fqn fqn of the region
- * @return true if the region defined by the fqn is in the process of activating/deactivating
- */
- private boolean isActivatingDeactivating(Fqn fqn)
- {
- return activationChangeNodes.contains(fqn);
- }
-
- /**
- * Returns true if the region exists
- *
- * @param fqn FQN of the region
- * @param type type of region to search for
- * @return true if the region exists
- */
- public boolean hasRegion(Fqn fqn, Region.Type type)
- {
- Region r = regionsRegistry.get(fqn);
- if (r == null) return false;
- switch (type)
- {
- case ANY:
- return true;
- case EVICTION:
- return r.getEvictionPolicy() != null && evictionTimerTask.isRegionRegisteredForProcessing(r);
- case MARSHALLING:
- return r.isActive() && r.getClassLoader() != null;
- }
- // should never reach here?
- return false;
- }
-
- /**
- * Disables unmarshalling of replication messages for the region
- * rooted in the given Fqn.
- *
- * @param fqn
- */
- public void deactivate(Fqn fqn)
- {
- try
- {
- Region region = getRegion(fqn, false);
-
- if (region != null)
- {
- if (defaultInactive && region.getClassLoader() == null)
- {
- // This region's state will no match that of a non-existent one
- // So, there is no reason to keep this region any more
-
- // FIXME (Brian) We shouldn't do this anymore; now outside code
- // can have a ref to the region!!
- removeRegion(fqn);
- }
- else
- {
- //region.deactivate();
- region.setActive(false);
- // FIXME - we should always clean up; otherwise stale data
- // is in memory!
- if (cache.getConfiguration().isFetchInMemoryState())
- {
- inactivateRegion(fqn);
- }
- }
- }
- else if (!defaultInactive)
- {
- region = getRegion(fqn, true);
- region.setActive(false);
- // FIXME - we should always clean up; otherwise stale data
- // is in memory!
- if (cache.getConfiguration().isFetchInMemoryState())
- {
- inactivateRegion(fqn);
- }
- }
- }
- catch (RuntimeException re)
- {
- throw re;
- }
- catch (Exception e)
- {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Resets the region manager's regions registry
- */
- public void reset()
- {
- regionsRegistry.clear();
- }
-
- /**
- * Returns an ordered list of all regions.
- * Note that the ordered list returned is sorted according to the natural order defined in the {@link Comparable} interface, which {@link org.jboss.cache.Region} extends.
- *
- * @param type Type of region to return
- * @return an ordered list of all regions, based on the type requested.
- */
- public List<Region> getAllRegions(Region.Type type)
- {
- List<Region> regions;
-
- if (type != Region.Type.ANY)
- {
- regions = new ArrayList<Region>();
- // we need to loop thru the regions and only select specific regions to rtn.
- for (Region r : regionsRegistry.values())
- {
- if ((type == Region.Type.EVICTION && r.getEvictionPolicy() != null && evictionTimerTask.isRegionRegisteredForProcessing(r)) ||
- (type == Region.Type.MARSHALLING && r.isActive() && r.getClassLoader() != null))
- regions.add(r);
- }
- }
- else
- {
- // put all regions
- regions = new ArrayList<Region>(regionsRegistry.values());
- }
-
- Collections.sort(regions);
-
- return regions;
- }
-
- /**
- * Sets if evictions are processed.
- */
- public void setUsingEvictions(boolean usingEvictions)
- {
- this.usingEvictions = usingEvictions;
- }
-
- /**
- * Sets the eviction configuration.
- */
- public void setEvictionConfig(EvictionConfig evictionConfig)
- {
- this.evictionConfig = evictionConfig;
- boolean setDefault = false;
- // create regions for the regions defined in the evictionConfig.
- for (EvictionRegionConfig erc : evictionConfig.getEvictionRegionConfigs())
- {
- Fqn fqn = erc.getRegionFqn();
- if (log.isTraceEnabled()) log.trace("Creating eviction region " + fqn);
-
- if (fqn.equals(DEFAULT_REGION))
- {
- if (setDefault)
- {
- throw new ConfigurationException("A default region for evictions has already been set for this cache");
- }
- if (log.isTraceEnabled()) log.trace("Applying settings for " + DEFAULT_REGION + " to Fqn.ROOT");
- fqn = Fqn.ROOT;
- setDefault = true;
- }
- Region r = getRegion(fqn, true);
- r.setEvictionPolicy(erc.getEvictionPolicyConfig());
- }
- }
-
- /**
- * Starts the eviction processing thread.
- */
- public void startEvictionThread()
- {
- evictionTimerTask.init(evictionConfig.getWakeupIntervalSeconds());
- }
-
- /**
- * Stops the eviction processing thread
- */
- public void stopEvictionThread()
- {
- evictionTimerTask.stop();
- }
-
-
- /**
- * Returns a string containing debug information on every region.
- */
- public String dumpRegions()
- {
- StringBuilder sb = new StringBuilder();
- for (Region r : regionsRegistry.values())
- {
- sb.append("\tRegion " + r);
- sb.append("\n");
- }
- return sb.toString();
- }
-
- /**
- * Returns a string containing debug information on every region.
- */
- public String toString()
- {
- return "RegionManager " + dumpRegions();
- }
-
- /**
- * Returns the cache for this region manager
- */
- public CacheImpl getCache()
- {
- return this.cache;
- }
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/RegionNotEmptyException.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/RegionNotEmptyException.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/RegionNotEmptyException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,39 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-
-package org.jboss.cache;
-
-/**
- * Thrown when an attempt is made to {@link RegionManager#activate(Fqn)} activate a subtree}
- * root in Fqn that already has an existing node in the cache.
- *
- * @author <a href="mailto://brian.stansberry@jboss.com">Brian Stansberry</a>
- */
-public class RegionNotEmptyException extends CacheException
-{
-
- /**
- * The serialVersionUID
- */
- private static final long serialVersionUID = 1L;
-
- public RegionNotEmptyException()
- {
- super();
- }
-
- public RegionNotEmptyException(String msg)
- {
- super(msg);
- }
-
- public RegionNotEmptyException(String msg, Throwable cause)
- {
- super(msg, cause);
- }
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/ReplicationException.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/ReplicationException.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/ReplicationException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,44 +0,0 @@
-// $Id$
-
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-
-package org.jboss.cache;
-
-/**
- * Thrown when a replication problem occurred
- */
-public class ReplicationException extends CacheException
-{
-
- private static final long serialVersionUID = 33172388691879866L;
-
- public ReplicationException()
- {
- super();
- }
-
- public ReplicationException(Throwable cause)
- {
- super(cause);
- }
-
- public ReplicationException(String msg)
- {
- super(msg);
- }
-
- public ReplicationException(String msg, Throwable cause)
- {
- super(msg, cause);
- }
-
- public String toString()
- {
- return super.toString();
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/ReplicationQueue.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/ReplicationQueue.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/ReplicationQueue.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,197 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.marshall.MethodCall;
-import org.jboss.cache.marshall.MethodDeclarations;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
-
-
-/**
- * Periodically (or when certain size is exceeded) takes elements and replicates them.
- *
- * @author <a href="mailto:bela@jboss.org">Bela Ban</a> May 24, 2003
- * @version $Revision$
- */
-public class ReplicationQueue
-{
-
- private static Log log = LogFactory.getLog(ReplicationQueue.class);
-
- private CacheImpl cache = null;
-
- /**
- * We flush every 5 seconds. Inactive if -1 or 0
- */
- private long interval = 5000;
-
- /**
- * Max elements before we flush
- */
- private long max_elements = 500;
-
- /**
- * Holds the replication jobs: LinkedList<MethodCall>
- */
- private final List<MethodCall> elements = new LinkedList<MethodCall>();
-
- /**
- * For periodical replication
- */
- private Timer timer = null;
-
- /**
- * The timer task, only calls flush() when executed by Timer
- */
- private MyTask task = null;
-
- public ReplicationQueue()
- {
- }
-
- /**
- * Constructs a new ReplicationQueue.
- */
- public ReplicationQueue(CacheImpl cache, long interval, long max_elements)
- {
- this.cache = cache;
- this.interval = interval;
- this.max_elements = max_elements;
- }
-
- /**
- * Returns the flush interval in milliseconds.
- */
- public long getInterval()
- {
- return interval;
- }
-
- /**
- * Sets the flush interval in milliseconds.
- */
- public void setInterval(long interval)
- {
- this.interval = interval;
- stop();
- start();
- }
-
- /**
- * Returns the maximum number of elements to hold.
- * If the maximum number is reached, flushes in the calling thread.
- */
- public long getMax_elements()
- {
- return max_elements;
- }
-
- /**
- * Sets the maximum number of elements to hold.
- */
- public void setMax_elements(long max_elements)
- {
- this.max_elements = max_elements;
- }
-
- /**
- * Starts the asynchronous flush queue.
- */
- public synchronized void start()
- {
- if (interval > 0)
- {
- if (task == null)
- task = new MyTask();
- if (timer == null)
- {
- timer = new Timer(true);
- timer.schedule(task,
- 500, // delay before initial flush
- interval); // interval between flushes
- }
- }
- }
-
- /**
- * Stops the asynchronous flush queue.
- */
- public synchronized void stop()
- {
- if (task != null)
- {
- task.cancel();
- task = null;
- }
- if (timer != null)
- {
- timer.cancel();
- timer = null;
- }
- }
-
-
- /**
- * Adds a new method call.
- */
- public void add(MethodCall job)
- {
- if (job == null)
- throw new NullPointerException("job is null");
- synchronized (elements)
- {
- elements.add(job);
- if (elements.size() >= max_elements)
- flush();
- }
- }
-
- /**
- * Flushes existing method calls.
- */
- public void flush()
- {
- List<MethodCall> l;
- synchronized (elements)
- {
- if (log.isTraceEnabled())
- log.trace("flush(): flushing repl queue (num elements=" + elements.size() + ")");
- l = new ArrayList<MethodCall>(elements);
- elements.clear();
- }
-
- if (l.size() > 0)
- {
- try
- {
- // send to all live nodes in the cluster
- cache.getRPCManager().callRemoteMethods(null, MethodDeclarations.replicateAllMethod, new Object[]{l}, false, true, 5000);
- }
- catch (Throwable t)
- {
- log.error("failed replicating " + l.size() + " elements in replication queue", t);
- }
- }
- }
-
- class MyTask extends TimerTask
- {
- public void run()
- {
- flush();
- }
- }
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/SuspectException.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/SuspectException.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/SuspectException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,28 +0,0 @@
-package org.jboss.cache;
-
-/**
- * Thrown when a member is suspected during remote method invocation
- * @author Bela Ban
- * @version $Id$
- */
-public class SuspectException extends CacheException
-{
-
- private static final long serialVersionUID = -2965599037371850141L;
-
- public SuspectException() {
- super();
- }
-
- public SuspectException(String msg) {
- super(msg);
- }
-
- public SuspectException(String msg, Throwable cause) {
- super(msg, cause);
- }
-
- public String toString() {
- return super.toString();
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/TreeCacheViewMBean.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/TreeCacheViewMBean.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/TreeCacheViewMBean.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,34 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.jmx.CacheJmxWrapperMBean;
-
-
-/**
- * MBean interface.
- *
- * @author <a href="mailto:bela@jboss.org">Bela Ban</a> March 27 2003
- */
-public interface TreeCacheViewMBean
-{
- void create() throws Exception;
-
- void start() throws Exception;
-
- void stop() ;
-
- void destroy() ;
-
- Cache getCache();
-
- void setCache(Cache cache);
-
- CacheJmxWrapperMBean getCacheService();
-
- void setCacheService(CacheJmxWrapperMBean cache_service);
-}
Deleted: core/trunk/src-old/org/jboss/cache/UnversionedNode.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/UnversionedNode.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/UnversionedNode.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,745 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.lock.IdentityLock;
-import org.jboss.cache.marshall.MethodCall;
-import org.jboss.cache.marshall.MethodCallFactory;
-import org.jboss.cache.marshall.MethodDeclarations;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.transaction.GlobalTransaction;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Basic data node class. Throws {@link UnsupportedOperationException} for version-specific methods like {@link #getVersion()} and
- * {@link #setVersion(org.jboss.cache.optimistic.DataVersion)}, defined in {@link org.jboss.cache.NodeSPI}.
- *
- * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
- * @since 2.0.0
- */
-public class UnversionedNode<K, V> extends AbstractNode<K, V> implements NodeSPI<K, V>
-{
-
- /**
- * Default output indent for printing.
- */
- private static final int INDENT = 4;
-
- /**
- * Debug log.
- */
- private static Log log = LogFactory.getLog(UnversionedNode.class);
-
- /**
- * True if all children have been loaded. This is set when CacheImpl.getChildrenNames() is called.
- */
- private boolean childrenLoaded = false;
-
- /**
- * True if data has been loaded from the cache loader.
- */
- private boolean dataLoaded = true;
-
- /**
- * Lock manager that manages locks to be acquired when accessing the node inside a transaction. Lazy set just in case
- * locking is not needed.
- */
- private transient IdentityLock lock_ = null;
-
- /**
- * A reference of the CacheImpl instance.
- */
- private transient CacheImpl<K, V> cache;
-
- /**
- * Map of general data keys to values.
- */
- private final Map<K, V> data = new HashMap<K, V>();
-
- /**
- * Constructs a new node with an FQN of Root.
- */
- public UnversionedNode()
- {
- this.fqn = Fqn.ROOT;
- }
-
- /**
- * Constructs a new node with a name, etc.
- *
- * @param mapSafe <code>true</code> if param <code>data</code> can safely be directly assigned to this object's
- * {@link #data} field; <code>false</code> if param <code>data</code>'s contents should be copied into
- * this object's {@link #data} field.
- */
- protected UnversionedNode(Object child_name, Fqn fqn, Map<K, V> data, boolean mapSafe, CacheSPI<K, V> cache)
- {
- init(child_name, fqn, cache);
- if (data != null)
- {
- this.data.putAll(data);// ? is this safe
- }
- }
-
- /**
- * Initializes with a name and FQN and cache.
- */
- private void init(Object child_name, Fqn fqn, CacheSPI<K, V> cache)
- {
- if (cache == null)
- {
- throw new IllegalArgumentException("no cache init for " + fqn);
- }
- this.cache = (CacheImpl) cache;
- this.fqn = fqn;
- if (!fqn.isRoot() && !child_name.equals(fqn.getLastElement()))
- {
- throw new IllegalArgumentException("Child " + child_name + " must be last part of " + fqn);
- }
- }
-
- /**
- * Returns a parent by checking the TreeMap by name.
- */
- public NodeSPI<K, V> getParent()
- {
- if (fqn.isRoot())
- {
- return null;
- }
- return cache.peek(fqn.getParent(), true);
- }
-
- private synchronized void initLock()
- {
- if (lock_ == null)
- {
- lock_ = new IdentityLock(cache.getConfiguration().getIsolationLevel(), this);
- }
- }
-
- private synchronized Map<Object, Node<K, V>> children()
- {
- if (children == null)
- {
- if (getFqn().isRoot())
- {
- children = new ConcurrentHashMap<Object, Node<K, V>>(64, .5f, 16);
- }
- else
- {
- // Less segments to save memory
- children = new ConcurrentHashMap<Object, Node<K, V>>(4, .75f, 4);
- }
- }
- return children;
- }
-
- public CacheSPI<K, V> getCache()
- {
- return cache;
- }
-
- public boolean isChildrenLoaded()
- {
- return childrenLoaded;
- }
-
- public void setChildrenLoaded(boolean flag)
- {
- childrenLoaded = flag;
- }
-
- public V get(K key)
- {
- return cache.get(getFqn(), key);
- }
-
- public V getDirect(K key)
- {
- return data == null ? null : data.get(key);
- }
-
-
- private boolean isReadLocked()
- {
- return lock_ != null && lock_.isReadLocked();
- }
-
- private boolean isWriteLocked()
- {
- return lock_ != null && lock_.isWriteLocked();
- }
-
- public IdentityLock getLock()
- {
- initLock();
- return lock_;
- }
-
- public Map<K, V> getData()
- {
- if (cache == null) return Collections.emptyMap();
- return cache.getData(getFqn());
-
-/*
- Map<K, V> dMap = new HashMap<K, V>();
- for (K k : cache.getKeys(getFqn()))
- {
- dMap.put(k, cache.get(fqn, k));
- }
- return Collections.unmodifiableMap(dMap);
-*/
- }
-
- public Map<K, V> getDataDirect()
- {
- if (data == null) return Collections.emptyMap();
- return Collections.unmodifiableMap(data);
- }
-
- public V put(K key, V value)
- {
- return cache.put(getFqn(), key, value);
- }
-
- public V putDirect(K key, V value)
- {
- return data.put(key, value);
- }
-
- public NodeSPI getOrCreateChild(Object child_name, GlobalTransaction gtx)
- {
- return getOrCreateChild(child_name, gtx, true);
- }
-
- private NodeSPI getOrCreateChild(Object child_name, GlobalTransaction gtx, boolean createIfNotExists)
- {
-
- NodeSPI child;
- if (child_name == null)
- {
- throw new IllegalArgumentException("null child name");
- }
-
- child = (NodeSPI) children().get(child_name);
- InvocationContext ctx = cache.getInvocationContext();
- if (createIfNotExists && child == null)
- {
- // construct the new child outside the synchronized block to avoid
- // spending any more time than necessary in the synchronized section
- Fqn child_fqn = new Fqn(this.fqn, child_name);
- NodeSPI newChild = (NodeSPI) cache.getConfiguration().getRuntimeConfig().getNodeFactory().createNode(child_name, this, null);
- if (newChild == null)
- {
- throw new IllegalStateException();
- }
- synchronized (this)
- {
- // check again to see if the child exists
- // after acquiring exclusive lock
- child = (NodeSPI) children().get(child_name);
- if (child == null)
- {
- cache.getNotifier().notifyNodeCreated(child_fqn, true, ctx);
- child = newChild;
- children.put(child_name, child);
- if (gtx != null)
- {
- MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, gtx,
- child_fqn, false);
- cache.addUndoOperation(gtx, undo_op);
- // add the node name to the list maintained for the current tx
- // (needed for abort/rollback of transaction)
- // cache.addNode(gtx, child.getFqn());
- }
- }
- }
-
- // notify if we actually created a new child
- if (newChild == child)
- {
- if (log.isTraceEnabled())
- {
- log.trace("created child: fqn=" + child_fqn);
- }
- cache.getNotifier().notifyNodeCreated(child_fqn, false, ctx);
- }
- }
- return child;
-
- }
-
- public V remove(K key)
- {
- return cache.remove(getFqn(), key);
- }
-
- public V removeDirect(K key)
- {
- if (data == null) return null;
- return data.remove(key);
- }
-
- public void printDetails(StringBuffer sb, int indent)
- {
- printDetailsInMap(sb, indent);
- }
-
- /**
- * Returns a debug string.
- */
- @Override
- public String toString()
- {
- StringBuffer sb = new StringBuffer();
- sb.append(getClass().getSimpleName());
- if (deleted)
- {
- sb.append(" (deleted) [ ").append(fqn);
- }
- else
- {
- sb.append("[ ").append(fqn);
- }
- if (data != null)
- {
- synchronized (data)
- {
- sb.append(" data=").append(data.keySet());
- }
- }
- if (children != null && !children.isEmpty())
- {
- sb.append(" child=").append(getChildrenNamesDirect());
- }
- if (lock_ != null)
- {
- if (isReadLocked())
- {
- sb.append(" RL");
- }
- if (isWriteLocked())
- {
- sb.append(" WL");
- }
- }
- sb.append("]");
- return sb.toString();
- }
-
- public Node<K, V> addChild(Fqn f)
- {
- Fqn nf = new Fqn(getFqn(), f);
- cache.put(nf, null);
- return getChild(f);
- }
-
- public void addChildDirect(NodeSPI<K, V> child)
- {
- if (child.getFqn().getParent().equals(getFqn()))
- {
- synchronized (this)
- {
- children().put(child.getFqn().getLastElement(), child);
- }
- }
- else
- throw new CacheException("Attempting to add a child [" + child.getFqn() + "] to [" + getFqn() + "]. Can only add direct children.");
- }
-
- public NodeSPI<K, V> addChildDirect(Fqn f)
- {
- if (f.size() == 1)
- {
- GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
- return getOrCreateChild(f.getLastElement(), gtx);
- }
- else
- {
- throw new UnsupportedOperationException("Cannot directly create children which aren't directly under the current node.");
- }
-
- }
-
- public void clearData()
- {
- cache.removeData(getFqn());
- }
-
- public void clearDataDirect()
- {
- if (data != null) data.clear();
- }
-
- public Node<K, V> getChild(Fqn fqn)
- {
- return cache.get(new Fqn(getFqn(), fqn));
- }
-
- public NodeSPI<K, V> getChildDirect(Fqn fqn)
- {
- if (fqn.size() == 1)
- {
- return getChildDirect(fqn.getLastElement());
- }
- else
- {
- NodeSPI currentNode = this;
- for (int i = 0; i < fqn.size(); i++)
- {
- Object nextChildName = fqn.get(i);
- currentNode = currentNode.getChildDirect(nextChildName);
- if (currentNode == null) return null;
- }
- return currentNode;
- }
- }
-
- public Set<Object> getChildrenNames()
- {
- return cache.getChildrenNames(getFqn());
- }
-
- public Set<Object> getChildrenNamesDirect()
- {
- return children == null ? Collections.emptySet() : new HashSet(children.keySet());
- //return childrenNames();
- }
-
- public Set<K> getKeys()
- {
- Set<K> keys = cache.getKeys(getFqn());
- return (Set<K>) (keys == null ? Collections.emptySet() : Collections.unmodifiableSet(keys));
- }
-
- public Set<K> getKeysDirect()
- {
- if (data == null)
- {
- return Collections.emptySet();
- }
- return Collections.unmodifiableSet(new HashSet<K>(data.keySet()));
- }
-
- public boolean hasChild(Fqn f)
- {
- return getChild(f) != null;
- }
-
- public boolean hasChild(Object o)
- {
- return getChild(o) != null;
- }
-
- public V putIfAbsent(K k, V v)
- {
- // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
- synchronized (this)
- {
- if (!getKeys().contains(k))
- return put(k, v);
- else
- return get(k);
- }
- }
-
- public V replace(K key, V value)
- {
- // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
- synchronized (this)
- {
- if (getKeys().contains(key))
- {
- return put(key, value);
- }
- else
- return null;
- }
- }
-
- public boolean replace(K key, V oldValue, V newValue)
- {
- // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
- synchronized (this)
- {
- if (oldValue.equals(get(key)))
- {
- put(key, newValue);
- return true;
- }
- else
- return false;
- }
- }
-
- public boolean removeChild(Fqn fqn)
- {
- return cache.removeNode(new Fqn(getFqn(), fqn));
- }
-
- public int dataSize()
- {
- return cache.getKeys(getFqn()).size();
- }
-
- public boolean removeChild(Object childName)
- {
- return removeChild(new Fqn(getFqn(), childName));
- }
-
- public boolean removeChildDirect(Object childName)
- {
- return children != null && children.remove(childName) != null;
- }
-
- public boolean removeChildDirect(Fqn f)
- {
- if (f.size() == 1)
- {
- return removeChildDirect(f.getLastElement());
- }
- else
- {
- NodeSPI child = getChildDirect(f);
- return child != null && child.getParent().removeChildDirect(f.getLastElement());
- }
- }
-
- public Map<Object, Node<K, V>> getChildrenMapDirect()
- {
- return children;
- }
-
- public void setChildrenMapDirect(Map<Object, Node<K, V>> children)
- {
- this.children().clear();
- this.children.putAll(children);
- }
-
- public void putAll(Map data)
- {
- cache.put(fqn, data);
- }
-
- public void replaceAll(Map data)
- {
- cache.put(fqn, data, true);
- }
-
- public void putAllDirect(Map<K, V> data)
- {
- if (data == null) return;
- this.data.putAll(data);
- }
-
- public void removeChildrenDirect()
- {
- if (children != null)
- {
- children.clear();
- }
- children = null;
- }
-
- public void print(StringBuffer sb, int indent)
- {
- printIndent(sb, indent);
- sb.append(Fqn.SEPARATOR).append(getName()).append(" ").append(getDataDirect().size());
- if (children != null)
- {
- for (Node node : children.values())
- {
- sb.append("\n");
- ((NodeSPI) node).print(sb, indent + INDENT);
- }
- }
- }
-
- // versioning
-
- public void setVersion(DataVersion version)
- {
- throw new UnsupportedOperationException("Versioning not supported");
- }
-
- public DataVersion getVersion()
- {
- throw new UnsupportedOperationException("Versioning not supported");
- }
-
- private void printIndent(StringBuffer sb, int indent)
- {
- if (sb != null)
- {
- for (int i = 0; i < indent; i++)
- {
- sb.append(" ");
- }
- }
- }
-
- public void addChild(Object child_name, Node<K, V> n)
- {
- if (child_name != null)
- {
- children().put(child_name, n);
- }
- }
-
- /**
- * Returns the name of this node.
- */
- private Object getName()
- {
- return fqn.getLastElement();
- }
-
- /**
- * Returns the name of this node.
- */
- public Fqn getFqn()
- {
- return fqn;
- }
-
- public void setFqn(Fqn fqn)
- {
- if (log.isTraceEnabled())
- {
- log.trace(getFqn() + " set FQN " + fqn);
- }
- this.fqn = fqn;
-
- if (children == null)
- {
- return;
- }
-
- // process children
- for (Map.Entry<Object, ? extends Node> me : children.entrySet())
- {
- NodeSPI n = (NodeSPI) me.getValue();
- Fqn cfqn = new Fqn(fqn, me.getKey());
- n.setFqn(cfqn);
- }
- }
-
- public Node<K, V> getChild(Object childName)
- {
- return cache.get(new Fqn(getFqn(), childName));
- }
-
- public NodeSPI<K, V> getChildDirect(Object childName)
- {
- if (childName == null) return null;
- return (NodeSPI<K, V>) (children == null ? null : children.get(childName));
- }
-
- public Set<Node<K, V>> getChildren()
- {
- if (cache == null) return Collections.emptySet();
- Set<Node<K, V>> children = new HashSet<Node<K, V>>();
- for (Object c : cache.getChildrenNames(getFqn()))
- {
- Node n = cache.get(new Fqn(getFqn(), c));
- if (n != null) children.add(n);
- }
- return Collections.unmodifiableSet(children);
- }
-
- public Set<NodeSPI<K, V>> getChildrenDirect()
- {
- // strip out deleted child nodes...
- if (children == null || children.size() == 0) return Collections.emptySet();
-
- Set<NodeSPI<K, V>> exclDeleted = new HashSet<NodeSPI<K, V>>();
- for (Node n : children.values())
- {
- NodeSPI spi = (NodeSPI) n;
- if (!spi.isDeleted()) exclDeleted.add(spi);
- }
- return Collections.unmodifiableSet(exclDeleted);
- }
-
- public boolean hasChildrenDirect()
- {
- return children != null && children.size() != 0;
- }
-
- public Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedForRemoval)
- {
- if (includeMarkedForRemoval)
- {
- if (children != null && !children.isEmpty())
- {
- return Collections.unmodifiableSet(new HashSet(children.values()));
- }
- else
- {
- return Collections.emptySet();
- }
- }
- else
- {
- return getChildrenDirect();
- }
- }
-
- /**
- * Adds details of the node into a map as strings.
- */
- private void printDetailsInMap(StringBuffer sb, int indent)
- {
- printIndent(sb, indent);
- indent += 2;// increse it
- if (!(getFqn()).isRoot())
- {
- sb.append(Fqn.SEPARATOR);
- }
- sb.append(getName());
- sb.append(" ");
- sb.append(data);
- if (children != null)
- {
- for (Node n : children.values())
- {
- sb.append("\n");
- ((NodeSPI) n).printDetails(sb, indent);
- }
- }
- }
-
- /**
- * Returns true if the data was loaded from the cache loader.
- */
- public boolean isDataLoaded()
- {
- return dataLoaded;
- }
-
- /**
- * Sets if the data was loaded from the cache loader.
- */
- public void setDataLoaded(boolean dataLoaded)
- {
- this.dataLoaded = dataLoaded;
- }
-
- public boolean isValid()
- {
- // TODO; implement this property, to detect if it has been evicted, removed by another thread, etc. Method added for now as a dummy so it exists in the API
- return true;
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/Version.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/Version.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/Version.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,172 +0,0 @@
-package org.jboss.cache;
-
-import java.util.StringTokenizer;
-
-/**
- * Contains version information about this release of JBoss Cache.
- *
- * @author Bela Ban
- * @version $Id$
- */
-public class Version
-{
- public static final String version = "2.0.0.GA";
- public static final String codename = "Habanero";
- public static byte[] version_id = {'0', '2', '0', '0'};
- public static final String cvs = "$Id$";
-
- private static final int MAJOR_SHIFT = 11;
- private static final int MINOR_SHIFT = 6;
- private static final int MAJOR_MASK = 0x00f800;
- private static final int MINOR_MASK = 0x0007c0;
- private static final int PATCH_MASK = 0x00003f;
-
- private static final short SHORT_1_2_3 = encodeVersion(1, 2, 3);
- private static final short SHORT_1_2_4_SP2 = encodeVersion(1, 2, 4);
-
- /**
- * Prints version information.
- */
- public static void main(String[] args)
- {
- System.out.println("\nVersion: \t" + version);
- System.out.println("Codename: \t" + codename);
- System.out.println("CVS: \t" + cvs);
- System.out.println("History: \t(see http://jira.jboss.com/jira/browse/JBCACHE for details)\n");
- }
-
- /**
- * Returns version information as a string.
- */
- public static String printVersion()
- {
- return "JBossCache '" + codename + "' " + version + "[ " + cvs + "]";
- }
-
- public static String printVersionId(byte[] v, int len)
- {
- StringBuffer sb = new StringBuffer();
- if (v != null)
- {
- if (len <= 0)
- len = v.length;
- for (int i = 0; i < len; i++)
- sb.append((char) v[i]);
- }
- return sb.toString();
- }
-
- public static String printVersionId(byte[] v)
- {
- StringBuffer sb = new StringBuffer();
- if (v != null)
- {
- for (byte aV : v) sb.append((char) aV);
- }
- return sb.toString();
- }
-
-
- public static boolean compareTo(byte[] v)
- {
- if (v == null)
- return false;
- if (v.length < version_id.length)
- return false;
- for (int i = 0; i < version_id.length; i++)
- {
- if (version_id[i] != v[i])
- return false;
- }
- return true;
- }
-
- public static int getLength()
- {
- return version_id.length;
- }
-
- public static short getVersionShort()
- {
- return getVersionShort(version);
- }
-
- public static short getVersionShort(String versionString)
- {
- if (versionString == null)
- throw new IllegalArgumentException("versionString is null");
-
- // Special cases for version prior to 1.2.4.SP2
- if ("1.2.4".equals(versionString))
- return 124;
- else if ("1.2.4.SP1".equals(versionString))
- return 1241;
-
- StringTokenizer tokenizer = new StringTokenizer(versionString, ".");
-
- int major = 0;
- int minor = 0;
- int patch = 0;
-
- if (tokenizer.hasMoreTokens())
- major = Integer.parseInt(tokenizer.nextToken());
- if (tokenizer.hasMoreTokens())
- minor = Integer.parseInt(tokenizer.nextToken());
- if (tokenizer.hasMoreTokens())
- patch = Integer.parseInt(tokenizer.nextToken());
-
- return encodeVersion(major, minor, patch);
- }
-
- public static String getVersionString(short versionShort)
- {
- if (versionShort == SHORT_1_2_4_SP2)
- return "1.2.4.SP2";
-
- switch (versionShort)
- {
- case 124:
- return "1.2.4";
- case 1241:
- return "1.2.4.SP1";
- default:
- return decodeVersion(versionShort);
- }
- }
-
- public static short encodeVersion(int major, int minor, int patch)
- {
- short version = (short) ((major << MAJOR_SHIFT)
- + (minor << MINOR_SHIFT)
- + patch);
- return version;
- }
-
- public static String decodeVersion(short version)
- {
- int major = (version & MAJOR_MASK) >> MAJOR_SHIFT;
- int minor = (version & MINOR_MASK) >> MINOR_SHIFT;
- int patch = (version & PATCH_MASK);
- String versionString = major + "." + minor + "." + patch;
- return versionString;
- }
-
- public static boolean isBefore124(short version)
- {
- return (version > 1241 && version <= SHORT_1_2_3);
- }
-
- /**
- * Retroweaver version info.
- */
- public static class Retro
- {
- public static void main(String[] args)
- {
- System.out.println("\nVersion: \t" + version + " (Retroweaved for JDK 1.4.x compatibility)");
- System.out.println("Codename: \t" + codename);
- System.out.println("CVS: \t" + cvs);
- System.out.println("History: \t(see http://jira.jboss.com/jira/browse/JBCACHE for details)\n");
- }
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/VersionedNode.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/VersionedNode.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/VersionedNode.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,73 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.optimistic.DefaultDataVersion;
-
-import java.util.Map;
-
-/**
- * VersionedNode extends the {@link org.jboss.cache.UnversionedNode} by adding a {@link org.jboss.cache.optimistic.DataVersion} property.
- * <p/>
- * Unlike {@link org.jboss.cache.UnversionedNode}, this node supports {@link #getVersion} and {@link #setVersion(org.jboss.cache.optimistic.DataVersion)}
- * defined in {@link org.jboss.cache.NodeSPI}
- * <p/>
- * Typically used when the cache mode configured is {@link org.jboss.cache.config.Configuration.NodeLockingScheme#OPTIMISTIC}
- *
- * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
- * @since 2.0.0
- */
-public class VersionedNode<K, V> extends UnversionedNode<K, V>
-{
- private DataVersion version;
- /**
- * Although this object has a reference to the CacheImpl, the optimistic
- * node is actually disconnected from the CacheImpl itself.
- * The parent could be looked up from the TransactionWorkspace.
- */
- private NodeSPI<K, V> parent;
-
- protected VersionedNode(Fqn fqn, NodeSPI<K, V> parent, Map<K, V> data, CacheSPI<K, V> cache)
- {
- super(fqn.getLastElement(), fqn, data, false, cache);
- if (parent == null && !fqn.isRoot()) throw new NullPointerException("parent");
- this.parent = parent;
- this.version = DefaultDataVersion.ZERO;
- }
-
- /**
- * Returns the version id of this node.
- *
- * @return the version
- */
- @Override
- public DataVersion getVersion()
- {
- return version;
- }
-
- /**
- * Returns the parent.
- */
- @Override
- public NodeSPI<K, V> getParent()
- {
- return parent;
- }
-
- /**
- * Sets the version id of this node.
- *
- * @param version
- */
- @Override
- public void setVersion(DataVersion version)
- {
- this.version = version;
- }
-}
17 years, 4 months
JBoss Cache SVN: r4251 - pojo/trunk/src/main/docbook/userguide/en/modules.
by jbosscache-commits@lists.jboss.org
Author: jason.greene(a)jboss.com
Date: 2007-08-14 15:09:32 -0400 (Tue, 14 Aug 2007)
New Revision: 4251
Added:
pojo/trunk/src/main/docbook/userguide/en/modules/api.xml
pojo/trunk/src/main/docbook/userguide/en/modules/appendix.xml
pojo/trunk/src/main/docbook/userguide/en/modules/architecture.xml
pojo/trunk/src/main/docbook/userguide/en/modules/configuration.xml
pojo/trunk/src/main/docbook/userguide/en/modules/example.xml
pojo/trunk/src/main/docbook/userguide/en/modules/instrumentation.xml
pojo/trunk/src/main/docbook/userguide/en/modules/introduction.xml
pojo/trunk/src/main/docbook/userguide/en/modules/term.xml
pojo/trunk/src/main/docbook/userguide/en/modules/troubleshooting.xml
Removed:
pojo/trunk/src/main/docbook/userguide/en/modules/architecture.xml
pojo/trunk/src/main/docbook/userguide/en/modules/basic_api.xml
pojo/trunk/src/main/docbook/userguide/en/modules/cache_loaders.xml
pojo/trunk/src/main/docbook/userguide/en/modules/compatibility.xml
pojo/trunk/src/main/docbook/userguide/en/modules/configuration.xml
pojo/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml
pojo/trunk/src/main/docbook/userguide/en/modules/deployment.xml
pojo/trunk/src/main/docbook/userguide/en/modules/eviction_policies.xml
pojo/trunk/src/main/docbook/userguide/en/modules/introduction.xml
pojo/trunk/src/main/docbook/userguide/en/modules/jmx_reference.xml
pojo/trunk/src/main/docbook/userguide/en/modules/preface.xml
pojo/trunk/src/main/docbook/userguide/en/modules/replication.xml
pojo/trunk/src/main/docbook/userguide/en/modules/transactions.xml
Log:
Use pojo cache docs
Added: pojo/trunk/src/main/docbook/userguide/en/modules/api.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/api.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/api.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -0,0 +1,184 @@
+<chapter id="api">
+
+ <title>API Overview</title>
+ <para>This section provides a brief overview of the POJO Cache APIs. Please consult the javadoc for the full API.</para>
+
+ <sect1>
+ <title>PojoCacheFactory Class</title>
+ <para>PojoCacheFactory provides a couple of static methods to instantiate and obtain a PojoCache instance.</para>
+<programlisting>
+ /**
+ * Create a PojoCache instance. Note that this will start the cache life cycle automatically.
+ * @param config A configuration string that represents the file name that is used to
+ * configure the underlying Cache instance.
+ * @return PojoCache
+ */
+ public static PojoCache createInstance(String config);
+
+ /**
+ * Create a PojoCache instance.
+ * @param config A configuration string that represents the file name that is used to
+ * configure the underlying Cache instance.
+ * @param start If true, it will start the cache life cycle.
+ * @return PojoCache
+ */
+ public static PojoCache createInstance(String config, boolean start);
+
+ /**
+ * Create a PojoCache instance.
+ * @param config A configuration object that is used to configure the underlying Cache instance.
+ * @param start If true, it will start the cache life cycle.
+ * @return PojoCache
+ */
+ public static PojoCache createInstance(Configuration config, boolean start);
+</programlisting>
+ <para>For example, to obtain a PojoCache instance and start the cache lifestyle automatically,
+ we can do:
+<programlisting>
+ String configFile = "META-INF/replSync-service.xml";
+ PojoCache cache = PojoCacheFactory.createInstance(configFile);
+</programlisting>
+ </para>
+ </sect1>
+
+
+ <sect1>
+ <title>PojoCache Interface</title>
+ <para>
+ <literal>PojoCache</literal> is the main interface for POJO Cache operations.
+ Since most of the cache interaction is performed against the application domain model,
+ there are only a few methods on this interface.
+ </para>
+
+ <sect2>
+ <title>Attachment</title>
+
+<programlisting>
+ /**
+ * Attach a POJO into PojoCache. It will also recursively put any sub-POJO into
+ * the cache system. A POJO can be the following and have the consequences when attached:
+ *
+ * It is PojoCacheable, that is, it has been annotated with
+ * {@see org.jboss.cache.aop.annotation.PojoCacheable} annotation (or via XML), and has
+ * been "instrumented" either compile- or load-time. The POJO will be mapped recursively to
+ * the system and fine-grained replication will be performed.
+ *
+ * It is Serializable. The POJO will still be stored in the cache system. However, it is
+ * treated as an "opaque" object per se. That is, the POJO will neither be intercepted
+ * (for fine-grained operation) or object relationship will be maintained.
+ *
+ * Neither of above. In this case, a user can specify whether it wants this POJO to be
+ * stored (e.g., replicated or persistent). If not, a PojoCacheException will be thrown.
+ *
+ * @param id An id String to identify the object in the cache. To promote concurrency, we
+ * recommend the use of hierarchical String separating by a designated separator. Default
+ * is "/" but it can be set differently via a System property, jbosscache.separator
+ * in the future release. E.g., "ben", or "student/joe", etc.
+ * @param pojo object to be inserted into the cache. If null, it will nullify the fqn node.
+ * @return Existing POJO or null if there is none.
+ * @throws PojoCacheException Throws if there is an error related to the cache operation.
+ */
+ Object attach(String id, Object pojo) throws PojoCacheException;
+</programlisting>
+ <para>
+ As described in the above javadoc, this method "attaches" the passed object to the cache
+ at the specified location (<literal>id</literal>).
+ The passed in object (<literal>pojo</literal>) must have been instrumented (using the <literal>@Replicable</literal> annotation)
+ or implement the <literal>Serializable</literal> interface.
+ </para>
+
+ <para>
+ If the object is not instrumented, but serializable, POJO Cache will simply treat it as an opaque "primitive" type. That is,
+ it will simply store it without mapping the object's fields into the cache. Replication is done on the object wide
+ level and therefore it will not be fine-grained.
+ </para>
+
+ <para>If the object has references to other objects, this call will issue
+ <literal>attach()</literal> calls
+ recursively until the entire object graph is
+ traversed. In addition, object identity and object references are preserved. So both circular and multiply referenced objects
+ are mapped as expected.
+ </para>
+
+ <para>The return value after the call is the previous object under <literal>id</literal>, if any. As a result, a successful call i
+ will replace that old value with the new instance. Note that a user will only need to
+ issue this call once for each top-level object. Further calls can be made directly on the graph, and they will be mapped as
+ expected.
+ </para>
+</sect2>
+ <sect2>
+ <title>Detachment</title>
+
+<programlisting>
+ /**
+ * Remove POJO object from the cache.
+ *
+ * @param id Is string that associates with this node.
+ * @return Original value object from this node.
+ * @throws PojoCacheException Throws if there is an error related to the cache operation.
+ */
+ Object detach(String id) throws PojoCacheException;
+</programlisting>
+
+ <para>
+ This call will detach the POJO from the cache by removing the contents under <literal>id</literal>
+ and return the POJO instance stored there (null if it doesn't exist). If successful, further operations against
+ this object will not affect the cache.
+ Note this call will also remove everything stored under <literal>id</literal> even if you have put
+ other plain cache data there.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Query</title>
+<programlisting>
+
+ /**
+ * Retrieve POJO from the cache system. Return null if object does not exist in the cache.
+ * Note that this operation is fast if there is already a POJO instance attached to the cache.
+ *
+ * @param id that associates with this node.
+ * @return Current content value. Null if does not exist.
+ * @throws PojoCacheException Throws if there is an error related to the cache operation.
+ */
+ Object find(String id) throws PojoCacheException;
+</programlisting>
+ <para>
+This call will
+ return the current object content located under
+ <literal>id</literal>. This method call is useful when you don't have the exact POJO reference.
+ For example, when you fail over to the
+ replicated node, you want to get the object reference from the replicated cache instance.
+ In this case, PojoCache will create a new Java object if it does not exist and
+ then add the cache interceptor such that every future access will be
+ in sync with the underlying cache store.
+ </para>
+
+<programlisting>
+ /**
+ * Query all managed POJO objects under the id recursively. Note that this will not return
+ * the sub-object POJOs, e.g., if Person has a sub-object of Address, it
+ * won't return Address pojo. Also note also that this operation is not thread-safe
+ * now. In addition, it assumes that once a POJO is found with a id, no more POJO is stored
+ * under the children of the id. That is, we don't mix the id with different POJOs.
+ *
+ * @param id The starting place to find all POJOs.
+ * @return Map of all POJOs found with (id, POJO) pair. Return size of 0, if not found.
+ * @throws PojoCacheException Throws if there is an error related to the cache operation.
+ */
+ Map findAll(String id) throws PojoCacheException;
+</programlisting>
+
+ <para>
+This call will return all the managed POJOs under cache with a base Fqn name. It is recursive, meaning that
+ it will traverse all the sub-trees to find the POJOs under that base. For example, if you specify
+ the fqn to be root, e.g.,
+ <code>"/"</code>
+ , then it will return all the
+ managed POJOs under the cache.
+ </para>
+ </sect2>
+
+</sect1>
+
+</chapter>
Property changes on: pojo/trunk/src/main/docbook/userguide/en/modules/api.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: pojo/trunk/src/main/docbook/userguide/en/modules/appendix.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/appendix.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/appendix.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -0,0 +1,309 @@
+<chapter id="appendix">
+
+ <title>Appendix</title>
+ <sect1>
+ <title id="examplePOJO">Example POJO</title>
+
+ <para>The example POJO classes used for
+ are:
+ <literal>Person,</literal> <literal>Student,</literal>
+ and
+ <literal>Address</literal>. Below are their definition
+ (note that
+ neither class implements
+ <literal>Serializable</literal>
+ ) along with the annotation.
+ </para>
+
+ <programlisting>
+(a)org.jboss.cache.pojo.annotation.Replicable
+public class Person {
+ String name=null;
+ int age=0;
+ Map hobbies=null;
+ Address address=null;
+ Set skills;
+ List languages;
+
+ public String getName() { return name; }
+ public void setName(String name) { this.name=name; }
+
+ public int getAge() { return age; }
+ public void setAge(int age) { this.age = age; }
+
+ public Map getHobbies() { return hobbies; }
+ public void setHobbies(Map hobbies) { this.hobbies = hobbies; }
+
+ public Address getAddress() { return address; }
+ public void setAddress(Address address) { this.address = address; }
+
+ public Set getSkills() { return skills; }
+ public void setSkills(Set skills) { this.skills = skills; }
+
+ public List getLanguages() { return languages; }
+ public void setLanguages(List languages) { this.languages = languages; }
+}</programlisting>
+
+ <programlisting>public class Student extends Person {
+ String year=null;
+
+ public String getYear() { return year; }
+ public void setYear(String year) { this.year=year; }
+}</programlisting>
+
+ <programlisting>
+ @org.jboss.cache.pojo.annotation.Replicable
+ public class Address {
+ String street=null;
+ String city=null;
+ int zip=0;
+
+ public String getStreet() { return street; }
+ public void setStreet(String street) { this.street=street; }
+ ...
+}</programlisting>
+ </sect1>
+
+ <sect1 id="xml" revision="1">
+ <title>Sample Cache configuration xml</title>
+
+ <para>
+ Below is a sample xml configuration for Cache that you can use for PojoCache creation.
+ </para>
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<server>
+ <mbean code="org.jboss.cache.pojo.jmx.PojoCacheJmxWrapper"
+ name="jboss.cache:service=PojoCache">
+
+ <depends>jboss:service=TransactionManager</depends>
+
+ <!-- Configure the TransactionManager -->
+ <attribute name="TransactionManagerLookupClass">
+ org.jboss.cache.transaction.DummyTransactionManagerLookup
+ </attribute>
+
+ <!-- Isolation level : SERIALIZABLE
+ REPEATABLE_READ (default)
+ READ_COMMITTED
+ READ_UNCOMMITTED
+ NONE
+ -->
+ <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
+
+ <!-- Valid modes are LOCAL, REPL_ASYNC and REPL_SYNC -->
+ <attribute name="CacheMode">REPL_SYNC</attribute>
+
+ <!-- Name of cluster. Needs to be the same for all caches,
+ in order for them to find each other
+ -->
+ <attribute name="ClusterName">PojoCacheCluster</attribute>
+
+ <!-- JGroups protocol stack properties. -->
+ <attribute name="ClusterConfig">
+ <config>
+ <!-- UDP: if you have a multihomed machine, set the bind_addr
+ attribute to the appropriate NIC IP address -->
+ <!-- UDP: On Windows machines, because of the media sense feature
+ being broken with multicast (even after disabling media sense)
+ set the loopback attribute to true -->
+ <UDP mcast_addr="228.1.2.3" mcast_port="48866"
+ ip_ttl="64" ip_mcast="true"
+ mcast_send_buf_size="150000" mcast_recv_buf_size="80000"
+ ucast_send_buf_size="150000" ucast_recv_buf_size="80000"
+ loopback="false"/>
+ <PING timeout="2000" num_initial_members="3"/>
+ <MERGE2 min_interval="10000" max_interval="20000"/>
+ <FD shun="true"/>
+ <FD_SOCK/>
+ <VERIFY_SUSPECT timeout="1500"/>
+ <pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
+ max_xmit_size="8192"/>
+ <UNICAST timeout="600,1200,2400",4800/>
+ <pbcast.STABLE desired_avg_gossip="400000"/>
+ <FC max_credits="2000000" min_threshold="0.10"/>
+ <FRAG2 frag_size="8192"/>
+ <pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
+ shun="true" print_local_addr="true"/>
+ <pbcast.STATE_TRANSFER/>
+ </config>
+ </attribute>
+
+ <!-- Whether or not to fetch state on joining a cluster -->
+ <attribute name="FetchInMemoryState">true</attribute>
+
+ <!-- The max amount of time (in milliseconds) we wait until the
+ initial state (ie. the contents of the cache) are retrieved from
+ existing members in a clustered environment
+ -->
+ <attribute name="InitialStateRetrievalTimeout">15000</attribute>
+
+ <!-- Number of milliseconds to wait until all responses for a
+ synchronous call have been received.
+ -->
+ <attribute name="SyncReplTimeout">15000</attribute>
+
+ <!-- Max number of milliseconds to wait for a lock acquisition -->
+ <attribute name="LockAcquisitionTimeout">10000</attribute>
+
+ </mbean>
+</server>
+]]>
+ </programlisting>
+
+ </sect1>
+
+
+ <sect1 id="xml-pojo" revision="1">
+ <title>PojoCache configuration xml</title>
+ <para>Attached is a full listing for <literal>pojocache-aop.xml</literal>.</para>
+<programlisting>
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!--
+ This is the PojoCache configuration file that specifies:
+ 1. Interceptor stack for API
+ 2. Annotation binding for POJO (via "prepare" element)
+
+ Basically, this is a variant of jboss-aop.xml. Note that
+ except for the customization of interceptor stack, you should
+ not need to modify this file.
+
+ To run PojoCache, you will need to define a system property:
+ jboss.aop.path that contains the path to this file such that JBoss Aop
+ can locate it.
+ -->
+ <aop>
+
+ <!--
+ This defines the PojoCache 2.0 interceptor stack. Unless necessary, don't modify the stack here!
+ -->
+
+ <!-- Check id range validity -->
+ <interceptor name="CheckId" class="org.jboss.cache.pojo.interceptors.CheckIdInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Track Tx undo operation -->
+ <interceptor name="Undo" class="org.jboss.cache.pojo.interceptors.PojoTxUndoInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Begining of interceptor chain -->
+ <interceptor name="Start" class="org.jboss.cache.pojo.interceptors.PojoBeginInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Check if we need a local tx for batch processing -->
+ <interceptor name="Tx" class="org.jboss.cache.pojo.interceptors.PojoTxInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!--
+ Mockup failed tx for testing. You will need to set PojoFailedTxMockupInterceptor.setRollback(true)
+ to activate it.
+ -->
+ <interceptor name="MockupTx" class="org.jboss.cache.pojo.interceptors.PojoFailedTxMockupInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Perform parent level node locking -->
+ <interceptor name="TxLock" class="org.jboss.cache.pojo.interceptors.PojoTxLockInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Interceptor to perform Pojo level rollback -->
+ <interceptor name="TxUndo" class="org.jboss.cache.pojo.interceptors.PojoTxUndoSynchronizationInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Interceptor to used to check recursive field interception. -->
+ <interceptor name="Reentrant" class="org.jboss.cache.pojo.interceptors.MethodReentrancyStopperInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Whether to allow non-serializable pojo. Default is false. -->
+ <interceptor name="MarshallNonSerializable"
+ class="org.jboss.cache.pojo.interceptors.CheckNonSerializableInterceptor"
+ scope="PER_INSTANCE">
+ <attribute name="marshallNonSerializable">false</attribute>
+ </interceptor>
+
+ <!-- This defines the stack macro -->
+ <stack name="Attach">
+ <interceptor-ref name="Start"/>
+ <interceptor-ref name="CheckId"/>
+ <interceptor-ref name="MarshallNonSerializable"/>
+ <interceptor-ref name="Tx"/>
+ <!-- NOTE: You can comment this out during production although leaving it here is OK. -->
+ <interceptor-ref name="MockupTx"/>
+ <interceptor-ref name="TxLock"/>
+ <interceptor-ref name="TxUndo"/>
+ </stack>
+
+ <stack name="Detach">
+ <interceptor-ref name="Start"/>
+ <interceptor-ref name="CheckId"/>
+ <interceptor-ref name="Tx"/>
+ <!-- NOTE: You can comment this out during production although leaving it here is OK. -->
+ <interceptor-ref name="MockupTx"/>
+ <interceptor-ref name="TxLock"/>
+ <interceptor-ref name="TxUndo"/>
+ </stack>
+
+ <stack name="Find">
+ <interceptor-ref name="Start"/>
+ <interceptor-ref name="CheckId"/>
+ </stack>
+
+ <!--
+ The following section should be READ-ONLY!! It defines the annotation binding to the stack.
+ -->
+
+ <!-- This binds the jointpoint to specific in-memory operations. Currently in PojoUtil. -->
+ <bind pointcut="execution(*
+ @org.jboss.cache.pojo.annotation.Reentrant->toString())">
+ <interceptor-ref name="Reentrant"/>
+ </bind>
+
+ <bind pointcut="execution(*
+ org.jboss.cache.pojo.PojoUtil->@org.jboss.cache.pojo.annotation.TxUndo(..))">
+ <interceptor-ref name="Undo"/>
+ </bind>
+
+ <bind pointcut="execution(* org.jboss.cache.pojo.impl.PojoCacheImpl->@org.jboss.cache.pojo.annotation.Attach(..))">
+ <stack-ref name="Attach"/>
+ </bind>
+
+ <bind pointcut="execution(* org.jboss.cache.pojo.impl.PojoCacheImpl->@org.jboss.cache.pojo.annotation.Detach(..))">
+ <stack-ref name="Detach"/>
+ </bind>
+
+ <bind pointcut="execution(* org.jboss.cache.pojo.impl.PojoCacheImpl->@org.jboss.cache.pojo.annotation.Find(..))">
+ <stack-ref name="Find"/>
+ </bind>
+
+
+ <!--
+ Following is declaration for JDK50 annotation. You use the specific annotation on your
+ POJO such that it can be instrumented. Idea is user will then need only to annotate like:
+ @org.jboss.cache.pojo.annotation.Replicable
+ in his POJO. There will be no need of jboss-aop.xml from user's side.
+ -->
+
+ <!-- If a POJO has PojoCachable annotation, it will be asepctized. -->
+ <prepare expr="field(* $instanceof{(a)org.jboss.cache.pojo.annotation.Replicable}->*)" />
+
+ <!-- Observer and Observable to monitor field modification -->
+ <bind pointcut="
+ set(* $instanceof{(a)org.jboss.cache.pojo.annotation.Replicable}->*)
+ ">
+ <interceptor class="org.jboss.cache.pojo.observable.SubjectInterceptor"/>
+ </bind>
+
+ <introduction class="$instanceof{(a)org.jboss.cache.pojo.annotation.Replicable}">
+ <mixin>
+ <interfaces>org.jboss.cache.pojo.observable.Subject</interfaces>
+ <class>org.jboss.cache.pojo.observable.SubjectImpl</class>
+ <construction>new org.jboss.cache.pojo.observable.SubjectImpl(this)</construction>
+ </mixin>
+ </introduction>
+ </aop>
+
+</programlisting>
+ </sect1>
+</chapter>
+
Property changes on: pojo/trunk/src/main/docbook/userguide/en/modules/appendix.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: pojo/trunk/src/main/docbook/userguide/en/modules/architecture.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/architecture.xml 2007-08-14 16:34:22 UTC (rev 4250)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/architecture.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -1,498 +0,0 @@
-<chapter id="architecture">
- <title>Architecture</title>
- <section id="architecture.tree_structure">
- <title>Data Structures Within The Cache</title>
-
-
- <para>
- A
- <literal>Cache</literal>
- consists of a collection of
- <literal>Node</literal>
- instances, organised in a tree
- structure. Each
- <literal>Node</literal>
- contains a
- <literal>Map</literal>
- which holds the data
- objects to be cached. It is important to note that the structure is a mathematical tree, and not a graph; each
- <literal>Node</literal>
- has one and only one parent, and the root node is denoted by the constant fully qualitied name,
- <literal>Fqn.ROOT</literal>
- .
- </para>
- <para>
- The reason for organising nodes as such is to improve concurrent access to data and make replication and
- persistence
- more fine-grained.
- </para>
- <para>
- <figure>
- <title>Data structured as a tree</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="TreeCacheArchitecture.png"/>
- </imageobject>
- </mediaobject>
- </figure>
-
- In the diagram above, each box represents a JVM. You see 2 caches in separate JVMs, replicating data to each
- other.
- These VMs can be located on the same physical machine, or on 2 different machines connected by a network link.
- The
- underlying group communication between networked nodes is done using
- <ulink url="http://www.jgroups.org">JGroups</ulink>
- .
- </para>
-
- <para>Any modifications (see
- <link linkend="api">API chapter</link>
- ) in one cache instance will be replicated to
- the other cache. Naturally, you can have more than 2 caches in a cluster.
- Depending on the transactional settings, this replication will occur either after each modification or at the
- end of a transaction, at commit time. When a new cache is created, it can optionally acquire the contents
- from one of the existing caches on startup.
- </para>
- </section>
-
- <section id="architecture.SPI_interfaces">
- <title>SPI Interfaces</title>
- <para>
- In addition to
- <literal>Cache</literal>
- and
- <literal>Node</literal>
- interfaces, JBoss Cache exposes more powerful
- <literal>CacheSPI</literal>
- and
- <literal>NodeSPI</literal>
- interfaces, which offer more control over the internals
- of JBoss Cache. These interfaces are not intended for general use, but are designed for people who wish to
- extend and enhance JBoss Cache, or write custom
- <literal>Interceptor</literal>
- or
- <literal>CacheLoader</literal>
- instances.
- </para>
- <figure>
- <title>SPI Interfaces</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="SPI.png"/>
- </imageobject>
- </mediaobject>
- </figure>
- <para>
- The
- <literal>CacheSPI</literal>
- interface cannot be created, but is injected into
- <literal>Interceptor</literal>
- and
- <literal>CacheLoader</literal>
- implementations by the
- <literal>setCache(CacheSPI cache)</literal>
- methods on these interfaces.
- <literal>CacheSPI</literal>
- extends
- <literal>Cache</literal>
- so all the functionality of the basic API is made available.
- </para>
- <para>
- Similarly, a
- <literal>NodeSPI</literal>
- interface cannot be created. Instead, one is obtained by performing operations on
- <literal>CacheSPI</literal>
- ,
- obtained as above. For example,
- <literal>Cache.getRoot() : Node</literal>
- is overridden as
- <literal>CacheSPI.getRoot() : NodeSPI</literal>
- .
- </para>
- <para>
- It is important to note that directly casting a
- <literal>Cache</literal>
- or
- <literal>Node</literal>
- to it's SPI
- counterpart is not recommended and is bad practice, since the inheritace of interfaces it is not a contract
- that is guaranteed to be upheld moving forward. The exposed public APIs, on the other hand, is guaranteed to
- be upheld.
- </para>
- </section>
-
- <section id="architecture.invocations">
- <title>Method Invocations On Nodes</title>
- <para>
- Since the cache is essentially a collection of nodes, aspects such as clustering, persistence, eviction, etc.
- need to be applied to these nodes when operations are invoked on the cache as a whole or on individual nodes.
- To achieve this in a clean, modular and extensible manner, an interceptor chain is used. The chain is built
- up of a series of interceptors, each one adding an aspect or particular functionality. The chain is built
- when the cache is created, based on the configuration used.
- </para>
- <para>
- It is important to note that the
- <literal>NodeSPI</literal>
- offers some methods (such as the
- <literal>xxxDirect()</literal>
- method
- family) that operate on a node directly without passing through the interceptor stack. Plugin authors should
- note
- that using such methods will affect the aspects of the cache that may need to be applied, such as locking,
- replication, etc. Basically, don't use such methods unless you
- <emphasis>really</emphasis>
- know what you're doing!
- </para>
- <section id="architecture.interceptors">
- <title>Interceptors</title>
- <para>
- An
- <literal>Interceptor</literal>
- is an abstract class, several of which comprise an interceptor chain. It
- exposes an
- <literal>invoke()</literal>
- method, which must be overridden by implementing classes to add behaviour
- to a call before passing the call down the chain by calling
- <literal>super.invoke()</literal>
- .
- </para>
- <figure>
- <title>SPI Interfaces</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="Interceptor.png"/>
- </imageobject>
- </mediaobject>
- </figure>
- <para>
- JBoss Cache ships with several interceptors, representing different configuration options, some of which
- are:
- <itemizedlist>
- <listitem>
- <literal>TxInterceptor</literal>
- - looks for ongoing transactions and registers with transaction managers to participate in
- synchronization events
- </listitem>
- <listitem>
- <literal>ReplicationInterceptor</literal>
- - replicates state across a cluster using a JGroups channel
- </listitem>
- <listitem>
- <literal>CacheLoaderInterceptor</literal>
- - loads data from a persistent store if the data requested is not available in memory
- </listitem>
- </itemizedlist>
- The interceptor chain configured for your cache instance can be obtained and inspected by calling
- <literal>CacheSPI.getInterceptorChain()</literal>
- ,
- which returns an ordered
- <literal>List</literal>
- of interceptors.
- </para>
- <section id="architecture.custom_interceptors">
- <title>Writing Custom Interceptors</title>
- <para>
- Custom interceptors to add specific aspects or features can be written by extending
- <literal>Interceptor</literal>
- and overriding
- <literal>invoke()</literal>
- . The custom interceptor will need to be added to the interceptor chain by using the
- <literal>CacheSPI.addInterceptor()</literal>
- method.
- </para>
- <para>
- Adding custom interceptors via XML is not supported at this time.
- </para>
- </section>
- </section>
-
- <section id="architecture.methodcalls">
- <title>MethodCalls</title>
- <para>
- <literal>org.jboss.cache.marshall.MethodCall</literal>
- is a class that encapsulates a
- <literal>java.lang.reflection.Method</literal>
- and an
- <literal>Object[]</literal>
- representing the method's arguments. It is an extension of the
- <literal>org.jgroups.blocks.MethodCall</literal>
- class, that adds a mechanism for identifying known methods using magic numbers and method ids,
- which makes marshalling and unmarshalling more efficient and performant.
- </para>
- <para>
- This is central to the
- <literal>Interceptor</literal>
- architecture, and is the only parameter passed in to
- <literal>Interceptor.invoke()</literal>
- .
- </para>
- </section>
-
- <section id="architecture.invocationcontext">
- <title>InvocationContexts</title>
- <para>
- <literal>InvocationContext</literal>
- holds intermediate state for the duration of a single invocation, and is set up and
- destroyed by the
- <literal>InvocationContextInterceptor</literal>
- which sits at the start of the chain.
- </para>
- <para>
- <literal>InvocationContext</literal>
- , as its name implies, holds contextual information associated with a single cache
- method invocation. Contextual information includes associated
- <literal>javax.transaction.Transaction</literal>
- or
- <literal>org.jboss.cache.transaction.GlobalTransaction</literal>
- ,
- method invocation origin (
- <literal>InvocationContext.isOriginLocal()</literal>
- ) as well as
- <link
- linkend="configuration.options">
- <literal>Option</literal>
- overrides
- </link>
- .
- </para>
- <para>
- The
- <literal>InvocationContext</literal>
- can be obtained by calling
- <literal>Cache.getInvocationContext()</literal>
- .
- </para>
- </section>
- </section>
-
- <section id="architecture.managers">
- <title>Managers For Subsystems</title>
- <para>
- Some aspects and functionality is shared by more than a single interceptor. Some of these have been
- encapsulated
- into managers, for use by various interceptors, and are made available by the
- <literal>CacheSPI</literal>
- interface.
- </para>
-
- <section id="architecture.rpcmanager">
- <title>RpcManager</title>
- <para>
- This class is responsible for calls made via the JGroups channel for all RPC calls to remote caches, and
- encapsulates the JGroups channel used.
- </para>
- </section>
-
- <section id="architecture.buddymanager">
- <title>BuddyManager</title>
- <para>
- This class manages buddy groups and invokes group organisation remote calls to organise a cluster of
- caches into smaller sub-groups.
- </para>
- </section>
-
- <section id="architecture.cacheloadermanager">
- <title>CacheLoaderManager</title>
- <para>
- Sets up and configures cache loaders. This class wraps individual
- <literal>CacheLoader</literal>
- instances
- in delegating classes, such as
- <literal>SingletonStoreCacheLoader</literal>
- or
- <literal>AsyncCacheLoader</literal>
- ,
- or may add the
- <literal>CacheLoader</literal>
- to a chain using the
- <literal>ChainingCacheLoader</literal>
- .
- </para>
- </section>
-
- </section>
-
- <section id="architecture.marshalling">
- <title>Marshalling And Wire Formats</title>
- <para>
- Early versions of JBoss Cache simply wrote cached data to the network by writing to an
- <literal>ObjectOutputStream</literal>
- during replication. Over various releases in the JBoss Cache 1.x.x series this approach was gradually
- deprecated
- in favour of a more mature marshalling framework. In the JBoss Cache 2.x.x series, this is the only officially
- supported and recommended mechanism for writing objects to datastreams.
- </para>
- <figure>
- <title>The Marshaller interface</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="Marshaller.png"/>
- </imageobject>
- </mediaobject>
- </figure>
- <section>
- <title>The Marshaller Interface</title>
- <para>
- The
- <literal>Marshaller</literal>
- interface extends
- <literal>RpcDispatcher.Marshaller</literal>
- from JGroups.
- This interface has two main implementations - a delegating
- <literal>VersionAwareMarshaller</literal>
- and a
- concrete
- <literal>CacheMarshaller200</literal>
- .
- </para>
- <para>
- The marshaller can be obtained by calling
- <literal>CacheSPI.getMarshaller()</literal>
- , and defaults to the
- <literal>VersionAwareMarshaller</literal>
- .
- Users may also write their own marshallers by implementing the
- <literal>Marshaller</literal>
- interface and
- adding it to their configuration, by using the
- <literal>MarshallerClass</literal>
- configuration attribute.
- </para>
- </section>
-
- <section>
- <title>VersionAwareMarshaller</title>
- <para>
- As the name suggests, this marshaller adds a version
- <literal>short</literal>
- to the start of any stream when
- writing, enabling similar
- <literal>VersionAwareMarshaller</literal>
- instances to read the version short and
- know which specific marshaller implementation to delegate the call to.
- For example,
- <literal>CacheMarshaller200</literal>
- , is the marshaller for JBoss Cache 2.0.x.
- JBoss Cache 2.1.x, say, may ship with
- <literal>CacheMarshaller210</literal>
- with an improved wire protocol.
- Using a
- <literal>VersionAwareMarshaller</literal>
- helps achieve wire protocol compatibility between minor
- releases but still affords us the flexibility to tweak and improve the wire protocol between minor or micro
- releases.
- </para>
-
- <section>
- <title>CacheLoaders</title>
- <para>
- Some of the existing cache loaders, such as the
- <literal>JDBCCacheLoader</literal>
- and the
- <literal>FileCacheLoader</literal>
- relied on persisting data using
- <literal>ObjectOutputStream</literal>
- as well, but now, they are using the
- <literal>VersionAwareMarshaller</literal>
- to marshall the persisted
- data to their cache stores.
- </para>
- </section>
-
- </section>
-
- <section>
- <title>CacheMarshaller200</title>
- <para>
- This marshaller treats well-known objects that need marshalling - such as
- <literal>MethodCall</literal>
- ,
- <literal>Fqn</literal>
- ,
- <literal>DataVersion</literal>
- , and even some JDK objects such as
- <literal>String</literal>
- ,
- <literal>List</literal>
- ,
- <literal>Boolean</literal>
- and others as types that do not need complete class definitions.
- Instead, each of these well-known types are represented by a
- <literal>short</literal>
- , which is a lot more efficient.
- </para>
- <para>
- In addition, reference counting is done to reduce duplication of writing certain objects multiple times, to
- help
- keep the streams small and efficient.
- </para>
- <para>
- Also, if
- <literal>UseRegionBasedMarshalling</literal>
- is enabled (disabled by default) the marshaller adds region
- information to the stream before writing any data. This region information is in the form of a
- <literal>String</literal>
- representation of an
- <literal>Fqn</literal>
- . When unmarshalling, the
- <literal>RegionManager</literal>
- can be used to
- find the relevant
- <literal>Region</literal>
- , and use a region-specific
- <literal>ClassLoader</literal>
- to unmarshall
- the stream. This is specifically useful when used to cluster state for application servers, where each
- deployment has
- it's own
- <literal>ClassLoader</literal>
- . See the section below on
- <link linkend="architecture.regions">regions</link>
- for more information.
- </para>
- </section>
-
- </section>
- <section id="architecture.regions">
- <title>Class Loading and Regions</title>
- <para>
- When used to cluster state of application servers, applications deployed in the application tend to put
- instances
- of objects specific to their application in the cache (or in an
- <literal>HttpSession</literal>
- object) which
- would require replication. It is common for application servers to assign separate
- <literal>ClassLoader</literal>
- instances to each application deployed, but have JBoss Cache libraries referenced by the application server's
- <literal>ClassLoader</literal>
- .
- </para>
- <para>
- To enable us to successfully marshall and unmarshall objects from such class loaders, we use a concept called
- regions. A region is a portion of the cache which share a common class loader (a region also has other uses -
- see
- <link linkend="eviction_policies">eviction policies</link>
- ).
- </para>
- <para>
- A region is created by using the
- <literal>Cache.getRegion(Fqn fqn, boolean createIfNotExists)</literal>
- method,
- and returns an implementation of the
- <literal>Region</literal>
- interface. Once a region is obtained, a
- class loader for the region can be set or unset, and the region can be activated/deactivated. By default,
- regions
- are active unless the
- <literal>InactiveOnStartup</literal>
- configuration attribute is set to
- <literal>true</literal>
- .
- </para>
- </section>
-
-</chapter>
Added: pojo/trunk/src/main/docbook/userguide/en/modules/architecture.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/architecture.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/architecture.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -0,0 +1,488 @@
+<chapter id="architecture">
+
+ <title>Architecture</title>
+
+ <para>POJO Cache internally uses the JBoss Aop framework to both intercept object field access, and
+ to provide an internal interceptor stack for centralizing common behavior (e.g. locking, transactions). </para>
+
+ <para>The following figure is a simple overview of the POJO Cache architecture. From the top, it can be can seen that
+ when a call comes in (e.g., <literal>attach</literal> or <literal>detach</literal>), it will go through
+ the POJO Cache interceptor stack first. After that, it will store the object's fields into the underlying Core Cache,
+ which will be replicated (if enabled) using JGroups.</para>
+ <figure>
+ <title>POJO Cache architecture overview</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/pojocache_architecture.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <sect1>
+ <title>POJO Cache interceptor stack</title>
+
+ <para>As mentioned, the JBoss Aop framework is used to provide a configurable interceptor stack.
+ In the current implementation, the main POJO Cache methods have their own independant stack. These are specified in <literal>META-INF/pojocache-aop.xml</literal>
+ In most cases, this file should be left alone, although advanced users may wish to add their own interceptors.
+ The Following is the default configuration:</para>
+<programlisting>
+ <!-- Check id range validity -->
+ <interceptor name="CheckId" class="org.jboss.cache.pojo.interceptors.CheckIdInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Track Tx undo operation -->
+ <interceptor name="Undo" class="org.jboss.cache.pojo.interceptors.PojoTxUndoInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Begining of interceptor chain -->
+ <interceptor name="Start" class="org.jboss.cache.pojo.interceptors.PojoBeginInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Check if we need a local tx for batch processing -->
+ <interceptor name="Tx" class="org.jboss.cache.pojo.interceptors.PojoTxInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!--
+ Mockup failed tx for testing. You will need to set PojoFailedTxMockupInterceptor.setRollback(true)
+ to activate it.
+ -->
+ <interceptor name="MockupTx" class="org.jboss.cache.pojo.interceptors.PojoFailedTxMockupInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Perform parent level node locking -->
+ <interceptor name="TxLock" class="org.jboss.cache.pojo.interceptors.PojoTxLockInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Interceptor to perform Pojo level rollback -->
+ <interceptor name="TxUndo" class="org.jboss.cache.pojo.interceptors.PojoTxUndoSynchronizationInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Interceptor to used to check recursive field interception. -->
+ <interceptor name="Reentrant" class="org.jboss.cache.pojo.interceptors.MethodReentrancyStopperInterceptor"
+ scope="PER_INSTANCE"/>
+
+ <!-- Whether to allow non-serializable pojo. Default is false. -->
+ <interceptor name="MarshallNonSerializable" class="org.jboss.cache.pojo.interceptors.CheckNonSerializableInterceptor"
+ scope="PER_INSTANCE">
+ <attribute name="marshallNonSerializable">false</attribute>
+ </interceptor>
+
+ <stack name="Attach">
+ <interceptor-ref name="Start"/>
+ <interceptor-ref name="CheckId"/>
+ <interceptor-ref name="Tx"/>
+ <interceptor-ref name="TxLock"/>
+ <interceptor-ref name="TxUndo"/>
+ </stack>
+
+ <stack name="Detach">
+ <interceptor-ref name="Start"/>
+ <interceptor-ref name="CheckId"/>
+ <interceptor-ref name="Tx"/>
+ <interceptor-ref name="TxLock"/>
+ <interceptor-ref name="TxUndo"/>
+ </stack>
+
+ <stack name="Find">
+ <interceptor-ref name="Start"/>
+ <interceptor-ref name="CheckId"/>
+ </stack>
+</programlisting>
+<para>
+ The stack should be self-explanatory. For example, for the <literal>Attach</literal> stack,
+ we currently have <literal>Start, CheckId, Tx, TxLock</literal>, and
+ <literal>TxUndo</literal> interceptors. The stack always starts with a
+ <literal>Start</literal> interceptor such that initialization can be done properly.
+ <literal>CheckId</literal> is to ensure the validity of the Id (e.g., it didn't use any internal
+ Id string). Finally, <literal>Tx, TxLock</literal>, and <literal>TxUndo</literal> are handling the
+ the proper transaction locking and rollback behavior (if needed).
+</para>
+ </sect1>
+ <sect1>
+ <title>Field interception</title>
+
+ <para>POJO Cache currently uses JBoss AOP to intercept field operations. If a class has been properly instrumented (by either
+ using the <literal>@Replicable</literal> annotation, or if the object has already been advised by JBoss AOP), then a cache
+ interceptor is added during an <literal>attach()</literal> call.
+ Afterward, any field modification will invoke the corresponding <literal>CacheFieldInterceptor</literal>
+ instance. Below is a schematic illustration of this process.
+ </para>
+
+ <para>Only fields, and not methods are intercepted, since this is the most efficient and accurate way to gaurantee the same data is visible on all nodes in the cluster. Further, this allows for objects that do not conform to the JavaBean specficiation to be replicable.
+ There are two important aspects of field interception:
+ <itemizedlist>
+ <listitem>
+ All access qualifiers are intercepted. In other words, all <literal>private</literal>, all <literal>protected</literal>, all default, and all <literal>public</literal> fields will be intercepted.
+ </listitem>
+ <listitem>
+ Any field with <literal>final</literal>, <literal>static</literal>, and/or <literal>transient</literal> qualifiers, <emphasis role="bold">will be skipped</emphasis>. Therefore, they will not be replicated, passivated, or manipulated in any way by POJO Cache.
+ </listitem>
+ </itemizedlist>
+ </para>
+<para>The figure below illustrates both field read and write operations.
+ Once an POJO is managed by POJO Cache (i.e., after an
+ <literal>attach()</literal>
+ method has been called), JBoss Aop will invoke the
+ <literal>CacheFieldInterceptor</literal> every time a class operates on a field. The cache is always consulted, since it is in control
+ of the mapped data (i.e. it gaurantess the state changes made by other nodes in the cluster are visible). Afterwords, the in-memmory copy is
+ updated. This is mainly to allow transaction rollbacks to restore the previous state of the object.
+ </para>
+
+ <figure>
+ <title>POJO Cache field interception</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/set.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ </sect1>
+
+
+ <sect1>
+ <title>Object relationship management</title>
+
+ <para>As previously mentioned, unlike a traditional cache system, POJO Cache preserves object identity. This allows
+ for any type of object relationship available in the Java language to be transparently handled. </para>
+
+ <para>During the mapping process, all object references are checked to see if they are already stored in the cache. If already stored, instead of duplicating the data, a reference to the original object is written in the cache. All referenced objects are reference counted, so they will be removed once they are no longer referenced.
+ </para>
+
+ <para>To look at one example, let's say that multiple
+ <literal>Person</literal>s ("joe" and "mary")
+ objects can own the same
+ <literal>Address</literal>
+ (e.g., a household). The following diagram is a graphical representation of the pysical cache data.
+ As can be seen, the "San Jose" address is only stored once.
+ </para>
+
+ <figure>
+ <title>Schematic illustration of object relationship mapping</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/reference.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>In the following code snippet, we show programmatically the object sharing example.
+ </para>
+
+<programlisting>
+import org.jboss.cache.pojo.PojoCache;
+import org.jboss.cache.pojo.PojoCacheFactory;
+import org.jboss.test.cache.test.standAloneAop.Person;
+import org.jboss.test.cache.test.standAloneAop.Address;
+
+String configFile = "META-INF/replSync-service.xml";
+PojoCache cache = PojoCacheFactory.createCache(configFile); // This will start PojoCache automatically
+
+Person joe = new Person(); // instantiate a Person object named joe
+joe.setName("Joe Black");
+joe.setAge(41);
+
+Person mary = new Person(); // instantiate a Person object named mary
+mary.setName("Mary White");
+mary.setAge(30);
+
+Address addr = new Address(); // instantiate a Address object named addr
+addr.setCity("Sunnyvale");
+addr.setStreet("123 Albert Ave");
+addr.setZip(94086);
+
+joe.setAddress(addr); // set the address reference
+mary.setAddress(addr); // set the address reference
+
+cache.attach("pojo/joe", joe); // add aop sanctioned object (and sub-objects) into cache.
+cache.attach("pojo/mary", mary); // add aop sanctioned object (and sub-objects) into cache.
+
+Address joeAddr = joe.getAddress();
+Address maryAddr = mary.getAddress(); // joeAddr and maryAddr should be the same instance
+
+cache.detach("pojo/joe");
+maryAddr = mary.getAddress(); // Should still have the address.
+</programlisting>
+
+ <para>If
+ <literal>joe</literal>
+ is removed from
+ the cache,
+ <literal>mary</literal>
+ should still have reference the same
+ <literal>Address</literal>
+ object in the cache store.
+ </para>
+
+ <para>To further illustrate this relationship management, let's examine the Java code under a replicated
+ environment. Imagine two separate cache instances in the cluster now (<literal>cache1</literal>
+ and <literal>cache2</literal>). On the first cache instance, both <literal>joe</literal>
+ and <literal>mary</literal> are attached as above. Then, the application fails over to <literal>cache2.</literal>
+ Here is the code
+ snippet for <literal>cache2</literal> (assume the objects were already attached):
+ </para>
+<programlisting>
+/**
+ * Code snippet on cache2 during fail-over
+ */
+import org.jboss.cache.PropertyConfigurator;
+import org.jboss.cache.pojo.PojoCache;
+import org.jboss.test.cache.test.standAloneAop.Person;
+import org.jboss.test.cache.test.standAloneAop.Address;
+
+String configFile = "META-INF/replSync-service.xml";
+PojoCache cache2 = PojoCacheFactory.createCache(configFile); // This will start PojoCache automatically
+
+Person joe = cache2.find("pojo/joe"); // retrieve the POJO reference.
+Person mary = cache2.find("pojo/mary"); // retrieve the POJO reference.
+
+Address joeAddr = joe.getAddress();
+Address maryAddr = mary.getAddress(); // joeAddr and maryAddr should be the same instance!!!
+
+maryAddr = mary.getAddress().setZip(95123);
+int zip = joeAddr.getAddress().getZip(); // Should be 95123 as well instead of 94086!
+</programlisting>
+ </sect1>
+
+ <sect1>
+ <title>Object Inheritance</title>
+
+ <para>POJO Cache preserves the inheritance hierarchy of all attached objects.
+ For example, if a
+ <literal>Student</literal>
+ extends
+ <literal>Person</literal>
+ with an additional field
+ <literal>year</literal>,
+ then once
+ <literal>Student</literal>
+ is put into the cache, all the class
+ attributes of
+ <literal>Person</literal>
+ are mapped to the cache as well.
+ </para>
+
+ <para>Following is a code snippet that illustrates how the inheritance
+ behavior of a POJO is maintained. Again, no special configuration is
+ needed.</para>
+
+<programlisting>
+import org.jboss.test.cache.test.standAloneAop.Student;
+
+Student joe = new Student(); // Student extends Person class
+joe.setName("Joe Black"); // This is base class attributes
+joe.setAge(22); // This is also base class attributes
+joe.setYear("Senior"); // This is Student class attribute
+
+cache.attach("pojo/student/joe", joe);
+
+//...
+
+joe = (Student)cache.attach("pojo/student/joe");
+Person person = (Person)joe; // it will be correct here
+joe.setYear("Junior"); // will be intercepted by the cache
+joe.setName("Joe Black II"); // also intercepted by the cache
+</programlisting>
+ </sect1>
+
+ <sect1>
+ <title>Physical object cache mapping model</title>
+ <para>The previous sections describe the logical object mapping model. In this section, we will explain
+ the physical mapping model, that is, how do we map the POJO into Core Cache
+ for transactional state replication. However, it should be noted that the physical structure of the cache
+ is purely an internal implementation detail, it should not be treated as an API as it may change in future
+ releases. This information is provided solely to aid in better understanding the mapping process in POJO Cache.</para>
+
+ <para>When an object is first attached in POJO Cache, the Core Cache node representation is created in a special internal
+ area. The <literal>Id</literal> fqn that is passed to <literal>attach()</literal> is used to create an empty node that
+ references the internal node. Future references to the same object will point to the same internal node location, and that
+ node will remain until all such references have been removed (detached).
+ </para>
+
+ <para>The example below demonstrates the mapping of the <literal>Person</literal> object under id "pojo/joe" and
+ "pojo/mary" as metioned in previous sections. It is created from a two node replication group where
+ one node is a Beanshell window and the other node is a Swing Gui window (shown here).
+ For clarity, multiple snapshots were taken to highlight the mapping process.</para><para>
+ The first figure illustrates the first step of the mapping approach. From the bottom of the figure,
+ it can be seen that
+ the <literal>PojoReference</literal> field under <literal>pojo/joe</literal> is pointing to an
+ internal location,
+ <literal>/__JBossInternal__/5c4o12-lpaf5g-esl49n5e-1-esl49n5o-2</literal>. That is, under the user-specified
+ Id string, we store only an indirect reference to the internal area. Please note that
+ <literal>Mary</literal> has a similar reference.</para>
+ <figure>
+ <title>Object cache mapping for <literal>Joe</literal></title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/guiJoe.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <figure>
+ <title>Object cache mapping for <literal>Mary</literal></title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/guiMary.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Then by clicking on the referenced internal node (from the following figure), it can seen that the
+ primitive fields for <literal>Joe</literal> are stored there. E.g., <literal>Age</literal> is
+ <literal>41</literal> and
+ <literal>Name</literal> is <literal>Joe Black</literal>. And similarly for <literal>Mary</literal> as
+ well.
+ </para>
+ <figure>
+ <title>Object cache mapping for internal node <literal>Joe</literal></title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/guiJoeInternal.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ <figure>
+ <title>Object cache mapping for internal node <literal>Mary</literal></title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/guiMaryInternal.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Under the <literal>/__JBossInternal__/5c4o12-lpaf5g-esl49n5e-1-esl49n5o-2</literal>, it can be seen that
+ there is an <literal>Address</literal> node. Clicking
+ on the <literal>Address</literal> node shows that it references another internal location:
+ <literal>/__JBossInternal__/5c4o12-lpaf5g-esl49n5e-1-esl49ngs-3</literal> as shown in the following figure.
+ Then by the same token, the <literal>Address</literal> node under
+ <literal>/__JBossInternal__/5c4o12-lpaf5g-esl49n5e-1-esl49na0-4</literal> points to the same
+ address reference. That is, both <literal>Joe</literal> and <literal>Mary</literal> share the same
+ <literal>Address</literal> reference.</para>
+ <figure>
+ <title>Object cache mapping: Joe's internal address</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/guiJoeAddress.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <figure>
+ <title>Object cache mapping: Mary's internal address</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/guiMaryAddress.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Finally, the <literal>/__JBossInternal__/5c4o12-lpaf5g-esl49n5e-1-esl49ngs-3</literal> node
+ contains the various various primitive fields of <literal>Address</literal>, e.g., <literal>Street</literal>,
+ <literal>Zip</literal>, and <literal>City</literal>. This is illustrated in the following figure.</para>
+ <figure>
+ <title>Object cache mapping: Address fields</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/guiAddress.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ </sect1>
+ <sect1>
+ <title>Collection Mapping</title>
+
+ <para>Due to current Java limitations, Collection classes that implement
+ <literal>Set</literal>, <literal>List</literal>, and <literal>Map</literal>
+ are substituted with a Java proxy. That is, whenever POJO Cache encounters
+ any Collection instance, it will:
+ <itemizedlist>
+ <listitem>
+ Create a Collection proxy instance and place it in the cache (instead of the original reference).
+ The mapping of the Collection elements will still be carried out recursively as expected.
+ </listitem>
+ <listitem>
+ If the Collection instance is referenced from another object, POJO Cache will swap out the original reference
+ with the new proxy, so that operations performed by the refering object will be picked up by the cache.
+ </listitem>
+ </itemizedlist>
+
+ The drawback to this approach is that the calling application must re-get any collection references that were attached. Otherwise,
+ the cache will not be aware of future changes. If the collection is referenced from another object, then the calling app can obtain
+ the proxy by using the publishing mechanism provided by the object (e.g. Person.getHobbies()).
+
+ If, however, the collection is directly attached to the cache, then a subsequent <literal>find()</literal> call will need to be made
+ to retrieve the proxy.
+ </para>
+
+ <para>The following code snippet illustrates obtaining a direct Collection proxy reference:
+ </para>
+<programlisting>
+List list = new ArrayList();
+list.add("ONE");
+list.add("TWO");
+
+cache.attach("pojo/list", list);
+list.add("THREE"); // This won't be intercepted by the cache!
+
+List proxyList = cache.find("pojo/list"; // Note that list is a proxy reference
+proxyList.add("FOUR"); // This will be intercepted by the cache
+</programlisting>
+
+ <para>
+ This snippet illustrates obtaining the proxy reference from a refering object:
+ </para>
+<programlisting>
+Person joe = new Person();
+joe.setName("Joe Black"); // This is base class attributes
+List lang = new ArrayList();
+lang.add("English");
+lang.add("Mandarin");
+joe.setLanguages(lang);
+// This will map the languages List automatically and swap it out with the proxy reference.
+cache.attach("pojo/student/joe", joe);
+lang = joe.getLanguages(); // Note that lang is now a proxy reference
+lang.add("French"); // This will be intercepted by the cache
+</programlisting>
+
+ <para>
+ Finally, when a Collection is removed from the cache (e.g., via <literal>detach</literal>),
+ you still can use the proxy reference. POJO Cache will just redirect the call back to the in-memory copy. See below:
+ </para>
+<programlisting>
+List list = new ArrayList();
+list.add("ONE");
+list.add("TWO");
+
+cache.attach("pojo/list", list);
+List proxyList = cache.find("pojo/list"); // Note that list is a proxy reference
+proxyList.add("THREE"); // This will be intercepted by the cache
+
+cache.detach("pojo/list"); // detach from the cache
+proxyList.add("FOUR"); // proxyList has 4 elements still.
+</programlisting>
+ <sect2>
+ <title>Limitations</title>
+ <para>The current implementation has the following
+ limitations with collections:</para>
+ <itemizedlist>
+ <listitem>Only List, Set and Map are supported. Also it should be noted that the Java Collection API does not
+ fully describe the behavior of implementations, so the cache versions may differ slightly from the common Java implementations (e.g. handling of NULL)
+ </listitem>
+ <listitem>As of PojoCache 2.0, HashMap keys must be serializable.
+ Prior to PojoCache 2.0, HashMap keys were converted to String.
+ This was fixed as you couldn't get the key back in its original form. See issue JBCACHE-399 for more details.
+ </listitem>
+ </itemizedlist>
+ </sect2>
+ </sect1>
+</chapter>
Property changes on: pojo/trunk/src/main/docbook/userguide/en/modules/architecture.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: pojo/trunk/src/main/docbook/userguide/en/modules/basic_api.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/basic_api.xml 2007-08-14 16:34:22 UTC (rev 4250)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/basic_api.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -1,719 +0,0 @@
-<chapter id="api">
- <title>User API</title>
- <section>
- <title>API Classes</title>
- <para>
- The
- <literal>Cache</literal>
- interface is the primary mechanism for interacting with JBoss Cache. It is
- constructed and optionally started using the
- <literal>CacheFactory</literal>
- . The
- <literal>CacheFactory</literal>
- allows you to create a
- <literal>Cache</literal>
- either from a
- <literal>Configuration</literal>
- object
- or an XML file. Once you have a reference to a
- <literal>Cache</literal>
- , you can use it to look up
- <literal>Node</literal>
- objects in the tree structure, and store data in the tree.
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="PublicAPI.png" format="PNG"/>
- </imageobject>
- </mediaobject>
-
- </para>
-
- <para>
- Reviewing the javadoc for the above interfaces is the best way
- to learn the API. Below we cover some of the main points.
- </para>
- </section>
-
- <section id="api.create_start">
- <title>Instantiating and Starting the Cache</title>
- <para>
- An instance of the
- <literal>Cache</literal>
- interface can only be created
- via a
- <literal>CacheFactory</literal>
- . (This is unlike JBoss Cache 1.x,
- where an instance of the old
- <literal>TreeCache</literal>
- class could
- be directly instantiated.)
- </para>
- <para>
- <literal>CacheFactory</literal>
- provides a number of overloaded methods
- for creating a
- <literal>Cache</literal>
- , but they all do the same thing:
- <itemizedlist>
- <listitem>Gain access to a
- <literal>Configuration</literal>
- , either
- by having one passed in as a method parameter, or by parsing XML
- content and constructing one. The XML content can come from a
- provided input stream or from a classpath or filesystem location.
- See the
- <link linkend="configuration">chapter on Configuration</link>
- for
- more on obtaining a
- <literal>Configuration</literal>
- .
- </listitem>
- <listitem>Instantiate the
- <literal>Cache</literal>
- and provide
- it with a reference to the
- <literal>Configuration</literal>
- .
- </listitem>
- <listitem>Optionally invoke the cache's
- <literal>create()</literal>
- and
- <literal>start()</literal>
- methods.
- </listitem>
- </itemizedlist>
- </para>
-
- <para>
- An example of the simplest mechanism for creating and starting
- a cache, using the default configuration values:
- </para>
-
- <programlisting>
- CacheFactory factory = DefaultCacheFactory.getInstance();
- Cache cache = factory.createCache();
- </programlisting>
-
- <para>Here we tell the
- <literal>CacheFactory</literal>
- to find and
- parse a configuration file on the classpath:
- </para>
-
- <programlisting>
- CacheFactory factory = DefaultCacheFactory.getInstance();
- Cache cache = factory.createCache("cache-configuration.xml");
- </programlisting>
-
- <para>Here we configure the cache from a file, but want to programatically
- change a configuration element. So, we tell the factory not to start
- the cache, and instead do it ourselves:
- </para>
-
- <programlisting>
- CacheFactory factory = DefaultCacheFactory.getInstance();
- Cache cache = factory.createCache("cache-configuration.xml", false);
- Configuration config = cache.getConfiguration();
- config.setClusterName(this.getClusterName());
-
- // Have to create and start cache before using it
- cache.create();
- cache.start();
- </programlisting>
-
- </section>
-
- <section>
- <title>Caching and Retrieving Data</title>
-
- <para>Next, let's use the
- <literal>Cache</literal>
- API to access
- a
- <literal>Node</literal>
- in the cache and then do some
- simple reads and writes to that node.
- </para>
- <programlisting>
- // Let's get ahold of the root node.
- Node rootNode = cache.getRoot();
-
- // Remember, JBoss Cache stores data in a tree structure.
- // All nodes in the tree structure are identified by Fqn objects.
- Fqn peterGriffinFqn = Fqn.fromString("/griffin/peter");
-
- // Create a new Node
- Node peterGriffin = rootNode.addChild(peterGriffinFqn);
-
- // let's store some data in the node
- peterGriffin.put("isCartoonCharacter", Boolean.TRUE);
- peterGriffin.put("favouriteDrink", new Beer());
-
- // some tests (just assume this code is in a JUnit test case)
- assertTrue(peterGriffin.get("isCartoonCharacter"));
- assertEquals(peterGriffinFqn, peterGriffin.getFqn());
- assertTrue(rootNode.hasChild(peterGriffinFqn));
-
- Set keys = new HashSet();
- keys.add("isCartoonCharacter");
- keys.add("favouriteDrink");
-
- assertEquals(keys, peterGriffin.getKeys());
-
- // let's remove some data from the node
- peterGriffin.remove("favouriteDrink");
-
- assertNull(peterGriffin.get("favouriteDrink");
-
- // let's remove the node altogether
- rootNode.removeChild(peterGriffinFqn);
-
- assertFalse(rootNode.hasChild(peterGriffinFqn));
- </programlisting>
-
- <para>
- The
- <literal>Cache</literal>
- interface also exposes put/get/remove
- operations that take an
- <link linkend="basic_api.fqn">Fqn</link>
- as an argument:
- </para>
-
- <programlisting>
- Fqn peterGriffinFqn = Fqn.fromString("/griffin/peter");
-
- cache.put(peterGriffinFqn, "isCartoonCharacter", Boolean.TRUE);
- cache.put(peterGriffinFqn, "favouriteDrink", new Beer());
-
- assertTrue(peterGriffin.get(peterGriffinFqn, "isCartoonCharacter"));
- assertTrue(cache.getRootNode().hasChild(peterGriffinFqn));
-
- cache.remove(peterGriffinFqn, "favouriteDrink");
-
- assertNull(cache.get(peterGriffinFqn, "favouriteDrink");
-
- cache.removeNode(peterGriffinFqn);
-
- assertFalse(cache.getRootNode().hasChild(peterGriffinFqn));
- </programlisting>
- </section>
-
- <section id="basic_api.fqn">
- <title>The
- <literal>Fqn</literal>
- Class
- </title>
-
- <para>
- The previous section used the
- <literal>Fqn</literal>
- class in its
- examples; now let's learn a bit more about that class.
- </para>
-
- <para>
- A Fully Qualified Name (Fqn) encapsulates a list of names which represent
- a path to a particular location in the cache's tree structure. The
- elements in the list are typically
- <literal>String</literal>
- s but can be
- any
- <literal>Object</literal>
- or a mix of different types.
- </para>
-
- <para>
- This path can be absolute (i.e., relative to the root node), or relative
- to any node in the cache. Reading the documentation on each API call that
- makes use of
- <literal>Fqn</literal>
- will tell you whether the API expects
- a relative or absolute
- <literal>Fqn</literal>
- .
- </para>
-
- <para>
- The
- <literal>Fqn</literal>
- class provides are variety of constructors;
- see the javadoc for all the possibilities. The following illustrates the
- most commonly used approaches to creating an Fqn:
- </para>
-
- <programlisting>
- <![CDATA[
- // Create an Fqn pointing to node 'Joe' under parent node 'Smith'
- // under the 'people' section of the tree
-
- // Parse it from a String
- Fqn<String> abc = Fqn.fromString("/people/Smith/Joe/");
-
- // Build it directly. A bit more efficient to construct than parsing
- String[] strings = new String[] { "people", "Smith", "Joe" };
- Fqn<String> abc = new Fqn<String>(strings);
-
- // Here we want to use types other than String
- Object[] objs = new Object[]{ "accounts", "NY", new Integer(12345) };
- Fqn<Object> acctFqn = new Fqn<Object>(objs);
- ]]>
- </programlisting>
-
- <para>Note that</para>
- <para>
- <programlisting><![CDATA[Fqn<String> f = new Fqn<String>("/a/b/c");]]></programlisting>
- </para>
- <para>is
- <emphasis>not</emphasis>
- the same as
- </para>
- <para>
- <programlisting><![CDATA[Fqn<String> f = Fqn.fromString("/a/b/c");]]></programlisting>
- </para>
-
- <para>
- The former will result in an Fqn with a single element, called "/a/b/c"
- which hangs directly under the cache root. The latter will result
- in a 3 element Fqn, where "c" idicates a child of "b", which is a child
- of "a", and "a" hangs off the cache root. Another way to
- look at it is that the "/" separarator is only parsed when it forms
- part of a String passed in to
- <literal>Fqn.fromString()</literal>
- and not
- otherwise.
- </para>
-
- <para>
- The JBoss Cache API in the 1.x releases included many overloaded
- convenience methods that took a string in the "/a/b/c" format in place
- of an
- <literal>Fqn</literal>
- . In the interests of API simplicity, no
- such convenience methods are available in the JBC 2.x API.
- </para>
-
- </section>
-
- <section>
- <title>Stopping and Destroying the Cache</title>
- <para>
- It is good practice to stop and destroy your cache when you are done
- using it, particularly if it is a clustered cache and has thus
- used a JGroups channel. Stopping and destroying a cache ensures
- resources like the JGroups channel are properly cleaned up.
- </para>
-
- <programlisting>
- cache.stop();
- cache.destroy();
- </programlisting>
-
- <para>
- Not also that a cache that has had
- <literal>stop()</literal>
- invoked
- on it can be started again with a new call to
- <literal>start()</literal>
- .
- Similarly, a cache that has had
- <literal>destroy()</literal>
- invoked
- on it can be created again with a new call to
- <literal>create()</literal>
- (and then started again with a
- <literal>start()</literal>
- call).
- </para>
- </section>
-
- <section>
- <title>Cache Modes</title>
- <para>
- Although technically not part of the API, the
- <emphasis>mode</emphasis>
- in which the cache is configured to operate affects the cluster-wide
- behavior of any
- <literal>put</literal>
- or
- <literal>remove</literal>
- operation, so we'll briefly mention the various modes here.
- </para>
- <para>
- JBoss Cache modes are denoted by the
- <literal>org.jboss.cache.config.Configuration.CacheMode</literal>
- enumeration.
- They consist of:
- <itemizedlist>
- <listitem>
- <emphasis>LOCAL</emphasis>
- - local, non-clustered cache. Local caches don't join a cluster and don't
- communicate with other caches in a cluster. Therefore their contents don't need to be Serializable;
- however, we recommend making them Serializable, allowing you the flexibility to change the cache mode at
- any time.
- </listitem>
- <listitem>
- <emphasis>REPL_SYNC</emphasis>
- - synchronous replication. Replicated caches replicate all changes to the other
- caches in the cluster. Synchronous replication means that changes are replicated and the caller blocks
- until replication acknowledgements are received.
- </listitem>
- <listitem>
- <emphasis>REPL_ASYNC</emphasis>
- - asynchronous replication. Similar to REPL_SYNC above, replicated caches replicate
- all changes to the other caches in the cluster. Being asynchronous, the caller does not block until
- replication acknowledgements are received.
- </listitem>
- <listitem>
- <emphasis>INVALIDATION_SYNC</emphasis>
- - if a cache is configured for invalidation rather than replication,
- every time data is changed in a cache other caches in the cluster
- receive a message informing them that their data is now stale and should
- be evicted from memory. This reduces replication overhead while still being able to invalidate stale data
- on remote caches.
- </listitem>
- <listitem>
- <emphasis>INVALIDATION_ASYNC</emphasis>
- - as above, except this invalidation mode causes invalidation messages
- to be broadcast asynchronously.
- </listitem>
- </itemizedlist>
- </para>
- <para>See the
- <link linkend="clustering">chapter on Clustering</link>
- for
- more details on how the cache's mode affects behavior. See the
- <link linkend="configuration">chapter on Configuration</link>
- for info
- on how to configure things like the cache's mode.
- </para>
- </section>
-
- <section id="api.listener">
- <title>
- Adding a CacheListener
- </title>
- <para>
- The
- <literal>@org.jboss.cache.notifications.annotation.CacheListener</literal>
- annotation is a convenient
- mechanism for receiving notifications from a cache about events that happen in the cache. Classes annotated
- with
- <literal>@CacheListener</literal>
- need to be public classes. In addition, the class needs to have one or
- more methods annotated with one of the method-level annotations (in the
- <literal>org.jboss.cache.notifications.annotation</literal>
- package). Methods annotated as such need to be public, have a void return type, and accept a single parameter
- of
- type
- <literal>org.jboss.cache.notifications.event.Event</literal>
- or one of it's subtypes.
-
- <itemizedlist>
- <listitem>
- <para>
- <literal>@CacheStarted</literal>
- - methods annotated such receive a notification when the cache is
- started. Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.CacheStartedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@CacheStopped</literal>
- - methods annotated such receive a notification when the cache is
- stopped. Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.CacheStoppedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@NodeCreated</literal>
- - methods annotated such receive a notification when a node is
- created. Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.NodeCreatedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@NodeRemoved</literal>
- - methods annotated such receive a notification when a node is
- removed. Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.NodeRemovedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@NodeModified</literal>
- - methods annotated such receive a notification when a node is
- modified. Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.NodeModifiedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@NodeMoved</literal>
- - methods annotated such receive a notification when a node is
- moved. Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.NodeMovedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@NodeVisited</literal>
- - methods annotated such receive a notification when a node is
- started. Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.NodeVisitedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@NodeLoaded</literal>
- - methods annotated such receive a notification when a node is
- loaded from a
- <literal>CacheLoader</literal>
- . Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.NodeLoadedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@NodeEvicted</literal>
- - methods annotated such receive a notification when a node is
- evicted from memory. Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.NodeEvictedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@NodeActivated</literal>
- - methods annotated such receive a notification when a node is
- activated. Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.NodeActivatedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@NodePassivated</literal>
- - methods annotated such receive a notification when a node is
- passivated. Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.NodePassivatedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@TransactionRegistered</literal>
- - methods annotated such receive a notification when the cache
- registers a
- <literal>javax.transaction.Synchronization</literal>
- with a registered transaction manager.
- Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.TransactionRegisteredEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@TransactionCompleted</literal>
- - methods annotated such receive a notification when the cache
- receives a commit or rollback call from a registered transaction manager.
- Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.TransactionCompletedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@ViewChanged</literal>
- - methods annotated such receive a notification when the group structure
- of the cluster changes. Methods need to accept a parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.ViewChangedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@CacheBlocked</literal>
- - methods annotated such receive a notification when the cluster
- requests that cache operations are blocked for a state transfer event. Methods need to accept a
- parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.CacheBlockedEvent</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>@CacheUnblocked</literal>
- - methods annotated such receive a notification when the cluster
- requests that cache operations are unblocked after a state transfer event. Methods need to accept a
- parameter type which is assignable from
- <literal>org.jboss.cache.notifications.event.CacheUnblockedEvent</literal>
- .
- </para>
- </listitem>
-
- </itemizedlist>
- </para>
- <para>
- Refer to the javadocs on the annotations as well as the
- <literal>Event</literal>
- subtypes
- for details of what is passed in to your method, and when.
- </para>
- <para>
- Example:
- <programlisting><![CDATA[
-
- @CacheListener
- public class MyListener
- {
-
- @CacheStarted
- @CacheStopped
- public void cacheStartStopEvent(Event e)
- {
- switch (e.getType())
- {
- case Event.Type.CACHE_STARTED:
- System.out.println("Cache has started");
- break;
- case Event.Type.CACHE_STOPPED:
- System.out.println("Cache has stopped");
- break;
- }
- }
-
- @NodeCreated
- @NodeRemoved
- @NodeVisited
- @NodeModified
- @NodeMoved
- public void logNodeEvent(NodeEvent ne)
- {
- log("An event on node " + ne.getFqn() + " has occured");
- }
- }
-
- ]]></programlisting>
- </para>
- </section>
-
- <section>
- <title>Using Cache Loaders</title>
- <para>
- Cache loaders are an important part of JBoss Cache. They allow persistence of nodes to disk or to remote cache
- clusters, and allow for passivation when caches run out of memory. In addition, cache loaders allow JBoss Cache
- to perform 'warm starts', where in-memory state can be preloaded from persistent storage. JBoss Cache ships
- with a number of cache loader implementations.
- <itemizedlist>
- <listitem>
- <literal>org.jboss.cache.loader.FileCacheLoader</literal>
- - a basic, filesystem based cache loader that persists data to disk. Non-transactional and not very
- performant, but a very simple solution. Used mainly for testing and not recommended for production use.
- </listitem>
- <listitem>
- <literal>org.jboss.cache.loader.JDBCCacheLoader</literal>
- - uses a JDBC connection to store data. Connections could be created and maintained in an internal pool
- (uses the c3p0 pooling library)
- or from a configured DataSource. The database this CacheLoader connects to could be local or remotely
- located.
- </listitem>
- <listitem>
- <literal>org.jboss.cache.loader.BdbjeCacheLoader</literal>
- - uses Oracle's BerkeleyDB file-based transactional database to persist data. Transactional and very
- performant, but potentially restrictive license.
- </listitem>
- <listitem>
- <literal>org.jboss.cache.loader.JdbmCacheLoader</literal>
- - an upcoming open source alternative to the BerkeleyDB.
- </listitem>
- <listitem>
- <literal>org.jboss.cache.loader.tcp.TcpCacheLoader</literal>
- - uses a TCP socket to "persist" data to a remote cluster, using a "far cache" pattern.
- <footnote>
- <para>http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossClusteringPatternFarCache</para>
- </footnote>
- </listitem>
- <listitem>
- <literal>org.jboss.cache.loader.ClusteredCacheLoader</literal>
- - used as a "read-only" CacheLoader, where other nodes in the cluster are queried for state.
- </listitem>
- </itemizedlist>
- These CacheLoaders, along with advanced aspects and tuning issues, are discussed in the
- <link linkend="cache_loaders">chapter dedicated to CacheLoaders</link>
- .
- </para>
- </section>
-
- <section>
- <title>Using Eviction Policies</title>
- <para>
- Eviction policies are the counterpart to CacheLoaders. They are necessary to make sure the cache does not run
- out of memory and when the cache starts to fill,
- the eviction algorithm running in a separate thread offloads in-memory state to the CacheLoader and frees up
- memory. Eviction policies can be configured
- on a per-region basis, so different subtrees in the cache could have different eviction preferences.
-
- JBoss Cache ships with several eviction policies:
- <itemizedlist>
- <listitem>
- <literal>org.jboss.cache.eviction.LRUPolicy</literal>
- - an eviction policy that evicts the least recently used nodes when thresholds are hit.
- </listitem>
- <listitem>
- <literal>org.jboss.cache.eviction.LFUPolicy</literal>
- - an eviction policy that evicts the least frequently used nodes when thresholds are hit.
- </listitem>
- <listitem>
- <literal>org.jboss.cache.eviction.MRUPolicy</literal>
- - an eviction policy that evicts the most recently used nodes when thresholds are hit.
- </listitem>
- <listitem>
- <literal>org.jboss.cache.eviction.FIFOPolicy</literal>
- - an eviction policy that creates a first-in-first-out queue and evicts the oldest nodes when thresholds
- are hit.
- </listitem>
- <listitem>
- <literal>org.jboss.cache.eviction.ExpirationPolicy</literal>
- - an eviction policy that selects nodes for eviction based on an expiry time each node is configured
- with.
- </listitem>
- <listitem>
- <literal>org.jboss.cache.eviction.ElementSizePolicy</literal>
- - an eviction policy that selects nodes for eviction based on the number of key/value pairs held in the
- node.
- </listitem>
- </itemizedlist>
- Detailed configuration and implementing custom eviction policies are discussed in the
- <link linkend="eviction_policies">chapter dedicated to eviction policies.</link>
- .
- </para>
- </section>
-</chapter>
Deleted: pojo/trunk/src/main/docbook/userguide/en/modules/cache_loaders.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/cache_loaders.xml 2007-08-14 16:34:22 UTC (rev 4250)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/cache_loaders.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -1,1325 +0,0 @@
-<chapter id="cache_loaders">
- <title>Cache Loaders</title>
- <para>JBoss Cache can use a
- <literal>CacheLoader</literal>
- to back up the in-memory cache to a backend datastore.
- If JBoss Cache is configured with a cache loader, then the following features are provided:
- <itemizedlist>
- <listitem>Whenever a cache element is accessed, and that element is not in
- the cache (e.g. due to eviction or due to server restart), then the cache loader transparently
- loads the element into the cache if found in the backend
- store.
- </listitem>
-
- <listitem>Whenever an element is modified, added or removed, then that
- modification is persisted in the backend store via the cache loader. If
- transactions are used, all modifications created within a transaction
- are persisted. To this end, the
- <literal>CacheLoader</literal>
- takes part in the two
- phase commit protocol run by the transaction manager, although it does not do so explicitly.
- </listitem>
- </itemizedlist>
- </para>
-
- <section>
- <title>The CacheLoader Interface and Lifecycle</title>
-
- <figure>
- <title>The CacheLoader interface</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="CacheLoader.png"/>
- </imageobject>
- </mediaobject>
- </figure>
-
-
- <para>The interaction between JBoss Cache and a
- <literal>CacheLoader</literal>
- implementation is as follows. When
- <literal>CacheLoaderConfiguration</literal>
- (see below) is non-null, an
- instance of each configured
- <literal>CacheLoader</literal>
- is created when the cache is created, and started when the cache is started.
- </para>
-
- <para>
- <literal>CacheLoader.create()</literal>
- and
- <literal>CacheLoader.start()</literal>
- are called when the cache is
- started. Correspondingly,
- <literal>stop()</literal>
- and
- <literal>destroy()</literal>
- are called when the cache is
- stopped.
- </para>
-
- <para>Next,
- <literal>setConfig()</literal>
- and
- <literal>setCache()</literal>
- are called. The latter can be used to
- store a reference to the cache, the former is used to configure this
- instance of the
- <literal>CacheLoader</literal>
- . For example, here a database cache loader
- could establish a connection to the database.
- </para>
-
- <para>The
- <literal>CacheLoader</literal>
- interface has a set of methods that are called
- when no transactions are used:
- <literal>get()</literal>
- ,
- <literal>put()</literal>
- ,
- <literal>remove()</literal>
- and
- <literal>removeData()</literal>
- : they get/set/remove the value
- immediately. These methods are described as javadoc comments in the
- interface.
- </para>
-
- <para>Then there are three methods that are used with transactions:
- <literal>prepare()</literal>
- ,
- <literal>commit()</literal>
- and
- <literal>rollback()</literal>
- . The
- <literal>prepare()</literal>
- method
- is called when a transaction is to be committed. It has a transaction
- object and a list of modfications as argument. The transaction object
- can be used as a key into a hashmap of transactions, where the values
- are the lists of modifications. Each modification list has a number of
- <literal>Modification</literal>
- elements, which represent the changes
- made to a cache for a given transaction. When
- <literal>prepare()</literal>
- returns successfully, then the cache loader
- <emphasis>must</emphasis>
- be able to commit (or rollback) the
- transaction successfully.
- </para>
-
- <para>
- JBoss Cache takes care of calling prepare(), commit()
- and rollback() on the cache loaders at the right time.
- </para>
-
- <para>The
- <literal>commit()</literal>
- method tells the cache loader to
- commit the transaction, and the
- <literal>rollback()</literal>
- method
- tells the cache loader to discard the changes associated with that
- transaction.
- </para>
-
- <para>See the javadocs on this interface for a detailed explanation on each method and the contract
- implementations
- would need to fulfil.
- </para>
-
- </section>
-
- <section>
- <title>Configuration</title>
-
- <para>Cache loaders are configured as follows in the JBoss Cache XML
- file. Note that you can define several cache loaders, in
- a chain. The impact is that the cache will look at all of the cache
- loaders in the order they've been configured, until it finds a valid,
- non-null element of data. When performing writes, all cache loaders are
- written to (except if the
- <literal>ignoreModifications</literal>
- element has been set to
- <literal>true</literal>
- for a specific cache loader. See the configuration section below for
- details.
- </para>
-
- <programlisting>
- <![CDATA[
-
-...
-
-<!-- Cache loader config block -->
-<attribute name="CacheLoaderConfiguration">
- <config>
- <!-- if passivation is true, only the first cache loader is used; the rest are ignored -->
- <passivation>false</passivation>
- <!-- comma delimited FQNs to preload -->
- <preload>/</preload>
- <!-- are the cache loaders shared in a cluster? -->
- <shared>false</shared>
-
- <!-- we can now have multiple cache loaders, which get chained -->
- <!-- the 'cacheloader' element may be repeated -->
- <cacheloader>
-
- <class>org.jboss.cache.loader.JDBCCacheLoader</class>
-
- <!-- properties to pass in to the cache loader -->
- <properties>
- cache.jdbc.driver=com.mysql.jdbc.Driver
- cache.jdbc.url=jdbc:mysql://localhost:3306/jbossdb
- cache.jdbc.user=root
- cache.jdbc.password=
- cache.jdbc.sql-concat=concat(1,2)
- </properties>
-
- <!-- whether the cache loader writes are asynchronous -->
- <async>false</async>
-
- <!-- only one cache loader in the chain may set fetchPersistentState to true.
- An exception is thrown if more than one cache loader sets this to true. -->
- <fetchPersistentState>true</fetchPersistentState>
-
- <!-- determines whether this cache loader ignores writes - defaults to false. -->
- <ignoreModifications>false</ignoreModifications>
-
- <!-- if set to true, purges the contents of this cache loader when the cache starts up.
- Defaults to false. -->
- <purgeOnStartup>false</purgeOnStartup>
-
- <!-- defines the cache loader as a singleton store where only the coordinator of the
- cluster will store modifications. -->
- <singletonStore>
- <!-- if true, singleton store functionality is enabled, defaults to false -->
- <enabled>false</enabled>
-
- <!-- implementation class for singleton store functionality which must extend
- org.jboss.cache.loader.AbstractDelegatingCacheLoader. Default implementation
- is org.jboss.cache.loader.SingletonStoreCacheLoader -->
- <class>org.jboss.cache.loader.SingletonStoreCacheLoader</class>
-
- <!-- properties and default values for the default singleton store functionality
- implementation -->
- <properties>
- pushStateWhenCoordinator=true
- pushStateWhenCoordinatorTimeout=20000
- </properties>
- </singletonStore>
- </cacheloader>
-
- </config>
-</attribute>
-]]>
- </programlisting>
-
- <para>The
- <literal>class</literal>
- element defines the
- class of the cache loader implementation. (Note that, because of a bug in
- the properties editor in JBoss AS, backslashes in variables for Windows
- filenames might not get expanded correctly, so replace="false" may be
- necessary). Note that an implementation of cache loader has to have an empty
- constructor.
- </para>
-
- <para>The
- <literal>properties</literal>
- element defines a configuration
- specific to the given implementation. The filesystem-based
- implementation for example defines the root directory to be used,
- whereas a database implementation might define the database URL, name
- and password to establish a database connection. This configuration is
- passed to the cache loader implementation via
- <literal>CacheLoader.setConfig(Properties)</literal>
- . Note that
- backspaces may have to be escaped.
- </para>
-
- <para>
- <literal>preload</literal>
- allows us to define a list of nodes, or
- even entire subtrees, that are visited by the cache on startup, in order
- to preload the data associated with those nodes. The default ("/") loads
- the entire data available in the backend store into the cache, which is
- probably not a good idea given that the data in the backend store might
- be large. As an example,
- <literal>/a,
- /product/catalogue
- </literal>
- loads the subtrees
- <literal>/a</literal>
- and
- <literal>/product/catalogue</literal>
- into the cache, but nothing
- else. Anything else is loaded lazily when accessed. Preloading makes
- sense when one anticipates using elements under a given subtree
- frequently.
- .
- </para>
-
- <para>
- <literal>fetchPersistentState</literal>
- determines whether or not
- to fetch the persistent state of a cache when joining a cluster. Only
- one configured cache loader may set this property to true; if more than
- one cache loader does so, a configuration exception will be thrown when
- starting your cache service.
- </para>
-
- <para>
- <literal>async</literal>
- determines whether writes to the cache
- loader block until completed, or are run on a separate thread so writes
- return immediately. If this is set to true, an instance of
- <literal>org.jboss.cache.loader.AsyncCacheLoader</literal>
- is
- constructed with an instance of the actual cache loader to be used. The
- <literal>AsyncCacheLoader</literal>
- then delegates all requests to the
- underlying cache loader, using a separate thread if necessary. See the
- Javadocs on
- <literal>AsyncCacheLoader</literal>
- for more details. If unspecified, the
- <literal>async</literal>
- element
- defaults to
- <literal>false</literal>
- .
- </para>
-
- <para>
- <emphasis role="bold">Note on using the
- <literal>async</literal>
- element:
- </emphasis>
- there is always the possibility of dirty reads since
- all writes are performed asynchronously, and it is thus impossible to
- guarantee when (and even if) a write succeeds. This needs to be kept in
- mind when setting the
- <literal>async</literal>
- element to true.
- </para>
-
- <para>
- <literal>ignoreModifications</literal>
- determines whether write
- methods are pushed down to the specific cache loader. Situations may
- arise where transient application data should only reside in a file
- based cache loader on the same server as the in-memory cache, for
- example, with a further shared
- <literal>JDBCCacheLoader</literal>
- used by all servers in
- the network. This feature allows you to write to the 'local' file cache
- loader but not the shared
- <literal>JDBCCacheLoader</literal>
- . This property defaults to
- <literal>false</literal>
- , so writes are propagated to all cache loaders
- configured.
- </para>
-
- <para>
- <literal>purgeOnStatup</literal>
- empties the specified cache loader
- (if
- <literal>ignoreModifications</literal>
- is
- <literal>false</literal>
- )
- when the cache loader starts up.
- </para>
-
- <para>
- <literal>shared</literal>
- indicates that the cache loader is shared among different cache instances, for example where all instances in a
- cluster use the same JDBC settings t talk to the same remote, shared database. Setting this to
- <literal>true</literal>
- prevents repeated and unnecessary writes of the same data to the cache loader by different cache instances.
- Default value is
- <literal>false</literal>
- .
- </para>
-
- <section>
- <title>Singleton Store Configuration</title>
-
- <para>
- <literal>singletonStore</literal>
- element enables modifications to be stored by only one node in the cluster,
- the coordinator. Essentially, whenever any data comes in to some node
- it is always replicated so as to keep the caches' in-memory states in
- sync; the coordinator, though, has the sole responsibility of pushing
- that state to disk. This functionality can be activated setting the
- <literal>enabled</literal>
- subelement to true in all nodes, but
- again only the coordinator of the cluster will store the modifications
- in the underlying cache loader as defined in
- <literal>cacheloader</literal>
- element. You cannot define a cache loader as
- <literal>shared</literal>
- and with
- <literal>singletonStore</literal>
- enabled at the same time.
- Default value for
- <literal>enabled</literal>
- is
- <literal>false</literal>
- .
- </para>
-
- <para>
- Optionally, within the
- <literal>singletonStore</literal>
- element, you can define a
- <literal>class</literal>
- element that specifies the implementation class that provides the
- singleton store functionality. This class must extend
- <literal>org.jboss.cache.loader.AbstractDelegatingCacheLoader</literal>
- , and if absent, it defaults to
- <literal>org.jboss.cache.loader.SingletonStoreCacheLoader</literal>
- .
- </para>
-
- <para>
- The
- <literal>properties</literal>
- subelement defines properties that allow changing the behaivour of the
- class providing the singleton store functionality. By default,
- <literal>pushStateWhenCoordinator</literal>
- and
- <literal>pushStateWhenCoordinatorTimeout</literal>
- properties have been defined, but more could be added as
- required by the user-defined class providing singleton store
- functionality.
- </para>
-
- <para>
- <literal>pushStateWhenCoordinator</literal>
- allows the in-memory
- state to be pushed to the cache store when a node becomes the
- coordinator, as a result of the new election of coordinator due to a
- cluster topology change. This can be very useful in situations where the
- coordinator crashes and there's a gap in time until the new coordinator
- is elected. During this time, if this property was set to
- <literal>false</literal>
- and the
- cache was updated, these changes would never be persisted. Setting this
- property to
- <literal>true</literal>
- would ensure that any changes during this process also
- get stored in the cache loader. You would also want to set this property
- to
- <literal>true</literal>
- if each node's cache loader is configured with a different
- location. Default value is
- <literal>true</literal>
- .
- </para>
-
- <para>
- <literal>pushStateWhenCoordinatorTimeout</literal>
- is only relevant if
- <literal>pushStateWhenCoordinator</literal>
- is
- <literal>true</literal>
- in which case, sets the maximum number of milliseconds that the process
- of pushing the in-memory state to the underlying cache loader should take,
- reporting a
- <literal>PushStateException</literal>
- if exceeded. Default value is 20000.
- </para>
-
- <para>
- <emphasis role="bold">Note on using the
- <literal>singletonStore</literal>
- element:
- </emphasis>
- setting
- up a cache loader as a singleton and using cache passivation (via
- evictions) can lead to undesired effects. If a node is to be passivated
- as a result of an eviction, while the cluster is in the process of
- electing a new coordinator, the data will be lost. This is because no
- coordinator is active at that time and therefore, none of the nodes in
- the cluster will store the passivated node. A new coordinator is elected
- in the cluster when either, the coordinator leaves the cluster, the
- coordinator crashes or stops responding.
- </para>
- </section>
- </section>
-
- <section id="cl.impls">
-
- <title>Shipped Implementations</title>
-
- <para>The currently available implementations shipped with JBoss Cache are as follows.</para>
-
- <section>
- <title>File system based cache loaders</title>
- <para>
- JBoss Cache ships with several cache loaders that utilise the file system as a data store. They all require
- that the
- <literal><![CDATA[<cacheloader><properties>]]></literal>
- configuration element
- contains a
- <literal>location</literal>
- property, which maps to a directory to be used as a persistent store.
- (e.g.,
- <literal>location=/tmp/myDataStore</literal>
- ). Used mainly for testing and not recommended for production use.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <literal>FileCacheLoader</literal>
- , which is a simple filesystem-based implementation. By default, this cache
- loader checks for any potential character portability issues in the
- location or tree node names, for example invalid characters, producing
- warning messages. These checks can be disabled adding
- <literal>check.character.portability</literal>
- property to the
- <literal><![CDATA[<properties>]]></literal>
- element and setting it to
- <literal>false</literal>
- (e.g.,
- <literal>check.character.portability=false</literal>
- ).
- </para>
- <para>
- The FileCacheLoader has some severe limitations which restrict it's use in a production
- environment, or if used in such an environment, it should be used with due care and sufficient
- understanding of these limitations.
- <itemizedlist>
- <listitem>Due to the way the FileCacheLoader represents a tree structure on disk (directories and
- files) traversal is inefficient for deep trees.
- </listitem>
- <listitem>Usage on shared filesystems like NFS, Windows shares, etc. should be avoided as these do
- not implement proper file locking and can cause data corruption.
- </listitem>
- <listitem>Usage with an isolation level of NONE can cause corrupt writes as multiple threads
- attempt to write to the same file.
- </listitem>
- <listitem>File systems are inherently not transactional, so when attempting to use your cache in a
- transactional context, failures when writing to the file (which happens during the commit phase)
- cannot be recovered.
- </listitem>
- </itemizedlist>
-
- As a rule of thumb, it is recommended that the FileCacheLoader not be used in a highly concurrent,
- transactional or stressful environment, and it's use is restricted to testing.
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>BdbjeCacheLoader</literal>
- , which is a cache loader implementation based on the Oracle/Sleepycat's
- <ulink url="http://www.oracle.com/database/berkeley-db/index.html">BerkeleyDB Java Edition</ulink>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>JdbmCacheLoader</literal>
- , which is a cache loader
- implementation based on the
- <ulink url="http://jdbm.sourceforge.net/">JDBM engine</ulink>
- , a fast and free alternative to
- BerkeleyDB.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>Note that the BerkeleyDB implementation is much more efficient than
- the filesystem-based implementation, and provides transactional
- guarantees, but requires a commercial license if distributed with an
- application (see http://www.oracle.com/database/berkeley-db/index.html for
- details).
- </para>
-
- </section>
-
- <section>
- <title>Cache loaders that delegate to other caches</title>
- <itemizedlist>
- <listitem>
- <para>
- <literal>LocalDelegatingCacheLoader</literal>
- , which enables
- loading from and storing to another local (same JVM) cache.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>ClusteredCacheLoader</literal>
- , which allows querying
- of other caches in the same cluster for in-memory data via the same
- clustering protocols used to replicate data. Writes are
- <emphasis>not</emphasis>
- 'stored' though, as replication would
- take care of any updates needed. You need to specify a property
- called
- <literal>timeout</literal>
- , a long value telling the cache
- loader how many milliseconds to wait for responses from the cluster
- before assuming a null value. For example,
- <literal>timeout = 3000</literal>
- would use a timeout value of 3 seconds.
- </para>
- </listitem>
- </itemizedlist>
- </section>
-
-
- <section id="cl.jdbc">
- <title>JDBCCacheLoader</title>
-
- <para>JBossCache is distributed with a JDBC-based cache loader
- implementation that stores/loads nodes' state into a relational database.
- The implementing class is
- <literal>org.jboss.cache.loader.JDBCCacheLoader</literal>
- .
- </para>
-
- <para>The current implementation uses just one table. Each row in the table
- represents one node and contains three columns:
- <itemizedlist>
- <listitem>column for
- <literal>Fqn</literal>
- (which is also a primary key
- column)
- </listitem>
-
- <listitem>column for node contents (attribute/value
- pairs)
- </listitem>
-
- <listitem>column for parent
- <literal>Fqn</literal>
- </listitem>
- </itemizedlist>
- </para>
-
- <para>
- <literal>Fqn</literal>
- 's are stored as strings. Node content is stored
- as a BLOB.
- <emphasis>WARNING:</emphasis>
- JBoss Cache does not impose any
- limitations on the types of objects used in
- <literal>Fqn</literal>
- but this implementation of
- cache loader requires
- <literal>Fqn</literal>
- to contain only objects of type
- <literal>java.lang.String</literal>
- . Another limitation for
- <literal>Fqn</literal>
- is its
- length. Since
- <literal>Fqn</literal>
- is a primary key, its default column type is
- <literal>VARCHAR</literal>
- which can store text values up to some
- maximum length determined by the database in use.
- </para>
-
- <para>See
- <ulink
- url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JDBCCacheLoader">
- http://wiki.jboss.org/wiki/Wiki.jsp?page=JDBCCacheLoader
- </ulink>
- for configuration tips with specific database systems.
- </para>
-
- <section>
- <title>JDBCCacheLoader configuration</title>
-
- <section>
- <title>Table configuration</title>
-
- <para>Table and column names as well as column types are
- configurable with the following properties.
- <itemizedlist>
- <listitem>
- <emphasis>cache.jdbc.table.name</emphasis>
- - the name
- of the table. The default value is 'jbosscache'.
- </listitem>
-
- <listitem>
- <emphasis>cache.jdbc.table.primarykey</emphasis>
- - the
- name of the primary key for the table. The default value is
- 'jbosscache_pk'.
- </listitem>
-
- <listitem>
- <emphasis>cache.jdbc.table.create</emphasis>
- - can be
- true or false. Indicates whether to create the table during startup.
- If true, the table is created if it doesn't already exist. The
- default value is true.
- </listitem>
-
- <listitem>
- <emphasis>cache.jdbc.table.drop</emphasis>
- - can be
- true or false. Indicates whether to drop the table during shutdown. The
- default value is true.
- </listitem>
-
- <listitem>
- <emphasis>cache.jdbc.fqn.column</emphasis>
- - FQN
- column name. The default value is 'fqn'.
- </listitem>
-
- <listitem>
- <emphasis>cache.jdbc.fqn.type</emphasis>
- - FQN column
- type. The default value is 'varchar(255)'.
- </listitem>
-
- <listitem>
- <emphasis>cache.jdbc.node.column</emphasis>
- - node
- contents column name. The default value is 'node'.
- </listitem>
-
- <listitem>
- <emphasis>cache.jdbc.node.type</emphasis>
- - node
- contents column type. The default value is 'blob'. This type must specify
- a valid binary data type for the database being used.
- </listitem>
- </itemizedlist>
- </para>
- </section>
-
- <section>
- <title>DataSource</title>
-
- <para>If you are using JBossCache in a managed environment (e.g., an
- application server) you can specify the JNDI name of the DataSource
- you want to use.
- <itemizedlist>
- <listitem>
- <emphasis>cache.jdbc.datasource</emphasis>
- - JNDI name
- of the DataSource. The default value is
- <literal>java:/DefaultDS</literal>
- .
- </listitem>
- </itemizedlist>
- </para>
- </section>
-
- <section>
- <title>JDBC driver</title>
-
- <para>If you are
- <emphasis>not</emphasis>
- using DataSource you have
- the following properties to configure database access using a JDBC
- driver.
- <itemizedlist>
- <listitem>
- <emphasis>cache.jdbc.driver</emphasis>
- - fully
- qualified JDBC driver name.
- </listitem>
-
- <listitem>
- <emphasis>cache.jdbc.url</emphasis>
- - URL to connect
- to the database.
- </listitem>
-
- <listitem>
- <emphasis>cache.jdbc.user</emphasis>
- - user name to
- connect to the database.
- </listitem>
-
- <listitem>
- <emphasis>cache.jdbc.password</emphasis>
- - password to
- connect to the database.
- </listitem>
- </itemizedlist>
- </para>
- </section>
-
- <section>
- <title>c3p0 connection pooling</title>
-
- <para>JBoss Cache implements JDBC connection pooling when running outside of an application server
- standalone using
- the c3p0:JDBC DataSources/Resource Pools library. In order to enable it, just edit the following
- property:
- <itemizedlist>
- <listitem>
- <emphasis>cache.jdbc.connection.factory</emphasis>
- - Connection factory class name.
- If not set, it defaults to standard non-pooled implementation. To enable c3p0 pooling, just set
- the
- connection factory class for c3p0. See example below.
- </listitem>
- </itemizedlist>
- </para>
-
- <para>You can also set any c3p0 parameters in the same cache loader properties section but don't forget
- to
- start the property name with 'c3p0.'. To find a list of available properties, please check the
- c3p0 documentation for the c3p0 library version distributed in
- <ulink url="http://sourceforge.net/projects/c3p0">c3p0:JDBC DataSources/Resource Pools</ulink>
- .
- Also, in order to provide quick and easy way to try out different pooling
- parameters, any of these properties can be set via a System property overriding any values these
- properties might have in the JBoss Cache XML configuration file, for example:
- <literal>-Dc3p0.maxPoolSize=20</literal>
- .
- If a c3p0 property is not defined in either the configuration file or as a System property, default
- value, as indicated in the c3p0 documentation, will apply.
- </para>
- </section>
-
- <section>
- <title>Configuration example</title>
-
- <para>Below is an example of a JDBCCacheLoader using Oracle as
- database. The CacheLoaderConfiguration XML element contains an
- arbitrary set of properties which define the database-related
- configuration.
- </para>
-
- <para>
- <programlisting>
- <![CDATA[
-<attribute name="CacheLoaderConfiguration">
-<config>
- <passivation>false</passivation>
- <preload>/some/stuff</preload>
- <cacheloader>
- <class>org.jboss.cache.loader.JDBCCacheLoader</class>
-
- <properties>
- cache.jdbc.table.name=jbosscache
- cache.jdbc.table.create=true
- cache.jdbc.table.drop=true
- cache.jdbc.table.primarykey=jbosscache_pk
- cache.jdbc.fqn.column=fqn
- cache.jdbc.fqn.type=varchar(255)
- cache.jdbc.node.column=node
- cache.jdbc.node.type=blob
- cache.jdbc.parent.column=parent
- cache.jdbc.driver=oracle.jdbc.OracleDriver
- cache.jdbc.url=jdbc:oracle:thin:@localhost:1521:JBOSSDB
- cache.jdbc.user=SCOTT
- cache.jdbc.password=TIGER
- cache.jdbc.sql-concat=concat(1,2)
- </properties>
-
- <async>false</async>
- <fetchPersistentState>true</fetchPersistentState>
- <ignoreModifications>false</ignoreModifications>
- <purgeOnStartup>false</purgeOnStartup>
- </cacheloader>
-</config>
-</attribute>
-]]>
- </programlisting>
- </para>
-
- <para>As an alternative to configuring the entire JDBC connection,
- the name of an existing data source can be given:
- </para>
-
- <programlisting>
- <![CDATA[
-<attribute name="CacheLoaderConfiguration">
-<config>
- <passivation>false</passivation>
- <preload>/some/stuff</preload>
- <cacheloader>
- <class>org.jboss.cache.loader.JDBCCacheLoader</class>
-
- <properties>
- cache.jdbc.datasource=java:/DefaultDS
- </properties>
-
- <async>false</async>
- <fetchPersistentState>true</fetchPersistentState>
- <ignoreModifications>false</ignoreModifications>
- <purgeOnStartup>false</purgeOnStartup>
- </cacheloader>
-</config>
-</attribute>
-]]>
- </programlisting>
-
- <para>Cconfiguration example for a cache loader using c3p0 JDBC connection pooling:</para>
-
- <programlisting>
- <![CDATA[
-<attribute name="CacheLoaderConfiguration">
-<config>
- <passivation>false</passivation>
- <preload>/some/stuff</preload>
- <cacheloader>
- <class>org.jboss.cache.loader.JDBCCacheLoader</class>
-
- <properties>
- cache.jdbc.table.name=jbosscache
- cache.jdbc.table.create=true
- cache.jdbc.table.drop=true
- cache.jdbc.table.primarykey=jbosscache_pk
- cache.jdbc.fqn.column=fqn
- cache.jdbc.fqn.type=varchar(255)
- cache.jdbc.node.column=node
- cache.jdbc.node.type=blob
- cache.jdbc.parent.column=parent
- cache.jdbc.driver=oracle.jdbc.OracleDriver
- cache.jdbc.url=jdbc:oracle:thin:@localhost:1521:JBOSSDB
- cache.jdbc.user=SCOTT
- cache.jdbc.password=TIGER
- cache.jdbc.sql-concat=concat(1,2)
- cache.jdbc.connection.factory=org.jboss.cache.loader.C3p0ConnectionFactory
- c3p0.maxPoolSize=20
- c3p0.checkoutTimeout=5000
- </properties>
-
- <async>false</async>
- <fetchPersistentState>true</fetchPersistentState>
- <ignoreModifications>false</ignoreModifications>
- <purgeOnStartup>false</purgeOnStartup>
- </cacheloader>
-</config>
-</attribute>
-]]>
- </programlisting>
-
- </section>
- </section>
- </section>
-
- <section id="cl.tcp">
- <title>TcpDelegatingCacheLoader</title>
-
- <para>This cache loader allows to delegate loads and stores to another
- instance of JBoss Cache, which could reside (a) in the same address
- space, (b) in a different process on the same host, or (c) in a
- different process on a different host.
- </para>
-
- <para>A TcpDelegatingCacheLoader talks to a remote
- <literal>org.jboss.cache.loader.tcp.TcpCacheServer</literal>
- ,
- which can be a standalone process started on the command line, or embedded as an MBean inside
- JBoss AS. The
- <literal>TcpCacheServer</literal>
- has a reference to another JBoss Cache instance, which
- it can create itself, or which is given to it (e.g. by JBoss, using
- dependency injection).
- </para>
-
- <para>The TcpDelegatingCacheLoader is configured with the host and
- port of the remote TcpCacheServer, and uses this to communicate to
- it.
- </para>
-
- <para>The configuration looks as follows:</para>
-
- <programlisting>
- <![CDATA[
-<attribute name="CacheLoaderConfiguration">
-<config>
- <cacheloader>
- <class>org.jboss.cache.loader.TcpDelegatingCacheLoader</class>
- <properties>
- host=myRemoteServer
- port=7500
- </properties>
- </cacheloader>
-</config>
-</attribute>
-]]>
- </programlisting>
-
- <para>This means this instance of JBoss Cache will delegate all load
- and store requests to the remote TcpCacheServer running on
- <literal>myRemoteServer:7500</literal>
- .
- </para>
-
- <para>A typical use case could be multiple replicated instances of
- JBoss Cache in the same cluster, all delegating to the same
- TcpCacheServer instance. The TcpCacheServer might itself delegate to a
- database via JDBCCacheLoader, but the point here is that - if we have
- 5 nodes all accessing the same dataset - they will load the data from
- the TcpCacheServer, which has do execute one SQL statement per
- unloaded data set. If the nodes went directly to the database, then
- we'd have the same SQL executed multiple times. So TcpCacheServer
- serves as a natural cache in front of the DB (assuming that a network
- round trip is faster than a DB access (which usually also include a
- network round trip)).
- </para>
-
- <para>To alleviate single point of failure, we could configure several cache loaders.
- The first cache loader is a ClusteredCacheLoader, the second a TcpDelegatingCacheLoader, and the
- last a JDBCacheLoader, effectively defining our cost of access to a
- cache in increasing order.
- </para>
-
- </section>
-
- <section id="cl.transforming">
- <title>Transforming Cache Loaders</title>
-
- <para>The way cached data is written to
- <literal>FileCacheLoader</literal>
- and
- <literal>JDBCCacheLoader</literal>
- based cache stores has changed in JBoss Cache 2.0 in such way that
- these cache loaders now write and read data using the same marhalling framework used to replicate data
- accross the network. Such change is trivial for replication purpouses as it just requires the rest of the
- nodes to understand this format. However, changing the format of the data in cache stores brings up a new
- problem: how do users, which have their data stored in JBoss Cache 1.x.x format, migrate their stores to
- JBoss Cache 2.0 format?
- </para>
-
- <para>With this in mind, JBoss Cache 2.0 comes with two cache loader implementations called
- <literal>org.jboss.cache.loader.TransformingFileCacheLoader</literal>
- and
- <literal>org.jboss.cache.loader.TransformingJDBCCacheLoader</literal>
- located within the optional
- jbosscache-cacheloader-migration.jar file. These are one-off cache loaders that read data from the
- cache store in JBoss Cache 1.x.x format and write data to cache stores in JBoss Cache 2.0 format.
- </para>
-
- <para>The idea is for users to modify their existing cache configuration file(s) momentarily to use these
- cache loaders and for them to create a small Java application that creates an instance of this cache,
- recursively reads the entire cache and writes the data read back into the cache. Once the data is
- transformed, users can revert back to their original cache configuration file(s). In order to help the users
- with this task, a cache loader migration example has been constructed which can be located under the
- <literal>examples/cacheloader-migration</literal>
- directory within the JBoss Cache distribution. This
- example, called
- <literal>examples.TransformStore</literal>
- , is independent of the actual data stored in
- the cache as it writes back whatever it was read recursively. It is highly recommended that anyone
- interested in porting their data run this example first, which contains a
- <literal>readme.txt</literal>
- file with detailed information about the example itself, and also use it as base for their own application.
- </para>
-
- </section>
-
- </section>
-
-
- <section id="cl.pass">
- <title>Cache Passivation</title>
-
- <para>A cache loader can be used to enforce node passivation and
- activation on eviction in a cache.
- </para>
-
- <para>
- <emphasis>Cache Passivation</emphasis>
- is the process of removing
- an object from in-memory cache and writing it to a secondary data store
- (e.g., file system, database) on eviction.
- <emphasis>Cache
- Activation
- </emphasis>
- is the process of restoring an object from the
- data store into the in-memory cache when it's needed to be used. In both
- cases, the configured cache loader will be used to read from the data
- store and write to the data store.
- </para>
-
- <para>When an eviction policy in effect evicts a node
- from the cache, if passivation is enabled, a notification that the node
- is being passivated will be emitted to the cache listeners and the
- node and its children will be stored in the cache loader store. When a
- user attempts to retrieve a node that was evicted earlier, the node is loaded
- (lazy loaded) from the cache loader store into memory. When
- the node and its children have been loaded, they're removed from the
- cache loader and a notification is emitted to the cache listeners
- that the node has been activated.
- </para>
-
- <para>To enable cache passivation/activation, you can set
- <literal>passivation</literal>
- to true. The default is
- <literal>false</literal>
- .
- When passivation is used, only the first cache loader configured is
- used and all others are ignored.
- </para>
- </section>
-
- <section>
- <title>Strategies</title>
- <para>
- This section discusses different patterns of combining different cache loader types and configuration
- options to achieve specific outcomes.
- </para>
-
- <section>
- <title>Local Cache With Store</title>
-
- <para>This is the simplest case. We have a JBoss Cache instance, whose
- cache mode is
- <literal>LOCAL</literal>
- , therefore no replication is going
- on. The cache loader simply loads non-existing elements from the store
- and stores modifications back to the store. When the cache is started,
- depending on the
- <literal>preload</literal>
- element, certain data can
- be preloaded, so that the cache is partly warmed up.
- </para>
- </section>
-
- <section>
- <title>Replicated Caches With All Caches Sharing The Same Store</title>
-
- <para>The following figure shows 2 JBoss Cache instances sharing the same
- backend store:
- </para>
-
- <figure>
- <title>2 nodes sharing a backend store</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="SharedCacheLoader.png"/>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>Both nodes have a cache loader that accesses a common shared
- backend store. This could for example be a shared filesystem (using
- the FileCacheLoader), or a shared database. Because both nodes access
- the same store, they don't necessarily need state transfer on
- startup.
- <footnote>
- <para>Of course they can enable state transfer, if they want to
- have a warm or hot cache after startup.
- </para>
- </footnote>
- Rather, the
- <literal>FetchInMemoryState</literal>
- attribute could be set to false, resulting in a 'cold' cache, that
- gradually warms up as elements are accessed and loaded for the first
- time. This would mean that individual caches in a cluster might have
- different in-memory state at any given time (largely depending on
- their preloading and eviction strategies).
- </para>
-
- <para>When storing a value, the writer takes care of storing the
- change in the backend store. For example, if node1 made change C1 and
- node2 C2, then node1 would tell its cache loader to store C1, and node2
- would tell its cache loader to store C2.
- </para>
- </section>
-
- <section>
- <title>Replicated Caches With Only One Cache Having A Store</title>
-
- <figure>
- <title>2 nodes but only one accesses the backend store</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="OnlyOneCacheLoader.png"/>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>This is a similar case to the previous one, but here only one
- node in the cluster interacts with a backend store via its
- cache loader. All other nodes perform in-memory replication. The idea
- here is all application state is kept in memory in each node, with
- the existence of multiple caches making the data highly available.
- (This assumes that a client that needs the data is able to somehow
- fail over from one cache to another.) The single persistent backend
- store then provides a backup copy of the data in case all caches in
- the cluster fail or need to be restarted.
- </para>
- <para>
- Note that here it may make sense for the cache loader to store
- changes asynchronously, that is <emphasis>not</emphasis>
- on the caller's thread, in order not to slow
- down the cluster by accessing (for example) a database. This is a
- non-issue when using asynchronous replication.
- </para>
- <para>
- A weakness with this architecture is that the cache with access
- to the cache loader becomes a single point of failure. Furthermore,
- if the cluster is restarted, the cache with the cache loader must
- be started first (easy to forget). A solution to the first problem
- is to configure a cache loader on each node, but set the
- <literal>singletonStore</literal> configuration to
- <literal>true</literal>. With this kind of setup, one but only one
- node will always be writing to a persistent store. However, this
- complicates the restart problem, as before restarting you need
- to determine which cache was writing before the shutdown/failure
- and then start that cache first.
- </para>
- </section>
-
- <section>
- <title>Replicated Caches With Each Cache Having Its Own Store</title>
-
- <figure>
- <title>2 nodes each having its own backend store</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="LocalCacheLoader.png"/>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>Here, each node has its own datastore. Modifications to the
- cache are (a) replicated across the cluster and (b) persisted using
- the cache loader. This means that all datastores have exactly the same
- state. When replicating changes synchronously and in a transaction,
- the two phase commit protocol takes care that all modifications are
- replicated and persisted in each datastore, or none is replicated and
- persisted (atomic updates).
- </para>
-
- <para>Note that JBoss Cache is
- <emphasis>not</emphasis>
- an
- XA Resource, that means it doesn't implement recovery. When used with a
- transaction manager that supports recovery, this functionality is not
- available.
- </para>
-
- <para>The challenge here is state transfer: when a new node starts it
- needs to do the following:
- </para>
-
- <orderedlist>
- <listitem>
- <para>Tell the coordinator (oldest node in a cluster) to send it
- the state. This is always a full state transfer, overwriting
- any state that may already be present.
- </para>
- </listitem>
-
- <listitem>
- <para>The coordinator then needs to wait until all in-flight
- transactions have completed. During this time, it will not allow
- for new transactions to be started.
- </para>
- </listitem>
-
- <listitem>
- <para>Then the coordinator asks its cache loader for the entire
- state using
- <literal>loadEntireState()</literal>
- . It then sends
- back that state to the new node.
- </para>
- </listitem>
-
- <listitem>
- <para>The new node then tells its cache loader to store that state
- in its store, overwriting the old state. This is the
- <literal>CacheLoader.storeEntireState()</literal>
- method
- </para>
- </listitem>
-
- <listitem>
- <para>As an option, the transient (in-memory) state can be
- transferred as well during the state transfer.
- </para>
- </listitem>
-
- <listitem>
- <para>The new node now has the same state in its backend store as
- everyone else in the cluster, and modifications received from
- other nodes will now be persisted using the local
- cache loader.
- </para>
- </listitem>
- </orderedlist>
-
-
- </section>
-
- <section>
- <title>Hierarchical Caches</title>
-
- <para>If you need to set up a hierarchy within a single JVM, you can
- use the
- <literal>LocalDelegatingCacheLoader</literal>
- . This type of
- hierarchy can currently only be set up programmatically.
- </para>
-
- <para>
- Hierarchical caches could also be set up spanning more than one JVM or server, using the
- <literal>TcpDelegatingCacheLoader</literal>
- .
- <figure>
- <title>TCP delegating cache loader</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="DelegatingCacheLoader.png"/>
- </imageobject>
- </mediaobject>
- </figure>
-
- </para>
-
- </section>
-
-
- <section>
- <title>Multiple Cache Loaders</title>
-
- <para>
- You can set up more than one cache loader in a chain. Internally, a delegating
- <literal>ChainingCacheLoader</literal>
- is used, with references to each
- cache loader you have configured. Use cases vary depending on the type of cache loaders used in the chain.
- One example is
- using a filesystem based cache loader, colocated on the same host as the JVM, used as an overflow for
- memory. This ensures
- data is available relatively easily and with low cost. An additional remote cache loader, such as a
- <literal>TcpDelegatingCacheLoader</literal>
- provides resilience between server restarts.
- </para>
-
- <figure>
- <title>Multiple cache loaders in a chain</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="MultipleCacheLoaders.png"/>
- </imageobject>
- </mediaobject>
- </figure>
-
- </section>
-
-
- </section>
-
-
-</chapter>
Deleted: pojo/trunk/src/main/docbook/userguide/en/modules/compatibility.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/compatibility.xml 2007-08-14 16:34:22 UTC (rev 4250)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/compatibility.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -1,37 +0,0 @@
-<chapter id="compatibility">
- <title>Version Compatibility and Interoperability</title>
-
- <para>
- Within a major version, releases of JBoss Cache are meant to be compatible and
- interoperable. Compatible in the sense that it should be possible to
- upgrade an application from one version to another by simply replacing the
- jars. Interoperable in the sense that if two different versions of
- JBoss Cache are used in the same cluster, they should be able to exchange
- replication and state transfer messages. Note however that interoperability
- requires use of the same JGroups version in all nodes in the cluster.
- In most cases, the version of JGroups used by a version of JBoss Cache can
- be upgraded.
- </para>
-
- <para>
- As such, JBoss Cache 2.x.x is not API or binary compatible with prior 1.x.x versions.
- However, JBoss Cache 2.1.x will be API and binary compatible with 2.0.x.
- </para>
-
- <para>
- A configuration attribute, <literal>ReplicationVersion</literal>, is available and is used
- to control the wire format of inter-cache communications. They can be wound back from more
- efficient and newer protocols to "compatible" versions when talking to older releases.
- This mechanism allows us to improve JBoss Cache by using more efficient wire formats while
- still providing a means to preserve interoperability.
- </para>
-
- <section>
- <title>Compatibility Matrix</title>
- <para>
- A <ulink url="http://labs.jboss.com/portal/jbosscache/compatibility/index.html">compatibility matrix</ulink> is maintained on the JBoss Cache website, which contains information on
- different versions of JBoss Cache, JGroups and JBoss AS.
- </para>
- </section>
-
-</chapter>
\ No newline at end of file
Deleted: pojo/trunk/src/main/docbook/userguide/en/modules/configuration.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/configuration.xml 2007-08-14 16:34:22 UTC (rev 4250)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/configuration.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -1,447 +0,0 @@
-<chapter id="configuration">
- <title>Configuration</title>
-
- <section>
- <title>Configuration Overview</title>
-
- <para>
- The
- <literal>org.jboss.cache.config.Configuration</literal>
- class
- (along with its
- <link linkend="configuration.elements">component parts</link>
- )
- is a Java Bean that encapsulates the configuration of the
- <literal>Cache</literal>
- and all of its architectural elements
- (cache loaders, evictions policies, etc.)
- </para>
-
- <para>
- The
- <literal>Configuration</literal>
- exposes numerous properties which
- are summarized in the
- <link linkend="configuration_reference">configuration reference</link>
- section of this book and many of which are discussed in later
- chapters. Any time you see a configuration option
- discussed in this book, you can assume that the
- <literal>Configuration</literal>
- class or one of its component parts exposes a simple property setter/getter for that configuration option.
- </para>
-
- </section>
-
- <section id="configuration.creation">
- <title>Creating a
- <literal>Configuration</literal>
- </title>
-
- <para>
- As discussed in the
- <link linkend="api.create_start">User API section</link>
- ,
- before a
- <literal>Cache</literal>
- can be created, the
- <literal>CacheFactory</literal>
- must be provided with a
- <literal>Configuration</literal>
- object or with a file name or
- input stream to use to parse a
- <literal>Configuration</literal>
- from XML. The following sections describe how to accomplish this.
- </para>
-
- <section>
- <title>Parsing an XML-based Configuration File</title>
- <para>
- The most convenient way to configure JBoss Cache is via an XML file. The JBoss Cache distribution ships
- with a number of configuration files for common use cases. It is recommended that these files be used as
- a starting point, and tweaked to meet specific needs.
- </para>
-
- <para>
- Here is a simple example configuration file:
- </para>
- <programlisting>
- <![CDATA[
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!-- ===================================================================== -->
-<!-- -->
-<!-- Sample JBoss Cache Service Configuration -->
-<!-- -->
-<!-- ===================================================================== -->
-
-<server>
-
- <mbean code="org.jboss.cache.jmx.CacheJmxWrapper" name="jboss.cache:service=Cache">
-
- <!-- Configure the TransactionManager -->
- <attribute name="TransactionManagerLookupClass">
- org.jboss.cache.transaction.GenericTransactionManagerLookup
- </attribute>
-
- <!-- Node locking level : SERIALIZABLE
- REPEATABLE_READ (default)
- READ_COMMITTED
- READ_UNCOMMITTED
- NONE -->
- <attribute name="IsolationLevel">READ_COMMITTED</attribute>
-
- <!-- Lock parent before doing node additions/removes -->
- <attribute name="LockParentForChildInsertRemove">true</attribute>
-
- <!-- Valid modes are LOCAL (default)
- REPL_ASYNC
- REPL_SYNC
- INVALIDATION_ASYNC
- INVALIDATION_SYNC -->
- <attribute name="CacheMode">LOCAL</attribute>
-
- <!-- Max number of milliseconds to wait for a lock acquisition -->
- <attribute name="LockAcquisitionTimeout">15000</attribute>
-
-
- <!-- Specific eviction policy configurations. This is LRU -->
- <attribute name="EvictionConfig">
- <config>
- <attribute name="wakeUpIntervalSeconds">5</attribute>
- <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
-
- <!-- Cache wide default -->
- <region name="/_default_">
- <attribute name="maxNodes">5000</attribute>
- <attribute name="timeToLiveSeconds">1000</attribute>
- </region>
- </config>
- </attribute>
- </mbean>
-</server>
-]]>
- </programlisting>
-
- <para>
- Another, more complete, sample XML file is included in the
- <link linkend="sample_xml_file">configuration reference</link>
- section of this book,
- along with
- <link linkend="configuration_reference">a handy look-up table</link>
- explaining the various options.
- </para>
-
- <para>
- For historical reasons, the format of the JBoss Cache configuraton
- file follows that of a JBoss AS Service Archive (SAR) deployment
- descriptor (and still can be used as such
- <link linkend="deployment.microkernel">inside JBoss AS</link>
- ). Because
- of this dual usage, you may see elements in some configuration files
- (such as
- <literal>depends</literal>
- or
- <literal>classpath</literal>
- ) that are
- not relevant outside JBoss AS. These can safely be ignored.
- </para>
-
- <para>
- Here's how you tell the
- <literal>CacheFactory</literal>
- to create
- and start a cache by finding and parsing a configuration file on the
- classpath:
- </para>
-
- <programlisting>
- CacheFactory factory = DefaultCacheFactory.getInstance();
- Cache cache = factory.createCache("cache-configuration.xml");
- </programlisting>
-
- </section>
-
- <section>
- <title>Programmatic Configuration</title>
- <para>
- In addition to the XML-based configuration above, the
- <literal>Configuration</literal>
- can be built up programatically,
- using the simple property mutators exposed by
- <literal>Configuration</literal>
- and its components. When constructed,
- the
- <literal>Configuration</literal>
- object is preset with JBoss Cache
- defaults and can even be used as-is for a quick start.
- </para>
-
- <para>
- Following is an example of programatically creating a
- <literal>Configuration</literal>
- configured to match the one produced
- by the XML example above, and then using it to create a
- <literal>Cache</literal>
- :
- </para>
-
- <programlisting>
- <![CDATA[
- Configuration config = new Configuration();
- String tmlc = GenericTransactionManagerLookup.class.getName();
- config.setTransactionManagerLookupClass(tmlc);
- config.setIsolationLevel(IsolationLevel.READ_COMMITTED);
- config.setCacheMode(CacheMode.LOCAL);
- config.setLockParentForChildInsertRemove(true);
- config.setLockAcquisitionTimeout(15000);
-
- EvictionConfig ec = new EvictionConfig();
- ec.setWakeupIntervalSeconds(5);
- ec.setDefaultEvictionPolicyClass(LRUPolicy.class.getName());
-
- EvictionRegionConfig erc = new EvictionRegionConfig();
- erc.setRegionName("_default_");
-
- LRUConfiguration lru = new LRUConfiguration();
- lru.setMaxNodes(5000);
- lru.setTimeToLiveSeconds(1000);
-
- erc.setEvictionPolicyConfig(lru);
-
- List<EvictionRegionConfig> ercs = new ArrayList<EvictionRegionConfig>();
- ercs.add(erc);
- ec.setEvictionRegionConfigs(erc);
-
- config.setEvictionConfig(ec);
-
- CacheFactory factory = DefaultCacheFactory.getInstance();
- Cache cache = factory.createCache(config);
-]]>
- </programlisting>
-
- <para>
- Even the above fairly simple configuration is pretty tedious programming;
- hence the preferred use of XML-based configuration. However, if your
- application requires it, there is no reason not to use XML-based
- configuration for most of the attributes, and then access the
- <literal>Configuration</literal>
- object to programatically change
- a few items from the defaults, add an eviction region, etc.
- </para>
-
- <para>
- Note that configuration values may not be changed programmatically when a cache is running,
- except those annotated as
- <literal>@Dynamic</literal>
- . Dynamic properties are also marked as such in the
- <link linkend="configuration_reference">configuration reference</link>
- table. Attempting to change a non-dynamic
- property will result in a
- <literal>ConfigurationException</literal>
- .
- </para>
- </section>
-
- <section>
- <title>Using an IOC Framework</title>
-
- <para>
- The
- <literal>Configuration</literal>
- class and its
- <link linkend="configuration.elements">component parts</link>
- are all Java Beans that expose all config elements via simple setters
- and getters. Therefore, any good IOC framework should be able to
- build up a
- <literal>Configuration</literal>
- from an XML file in
- the framework's own format. See the
- <link linkend="deployment.microcontainer">deployment via the JBoss micrcontainer</link>
- section for an example of this.
- </para>
- </section>
- </section>
-
- <section id="configuration.elements">
- <title>Composition of a
- <literal>Configuration</literal>
- Object
- </title>
-
- <para>
- A
- <literal>Configuration</literal>
- is composed of a number of
- subobjects:
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="Configuration.png"/>
- </imageobject>
- </mediaobject>
- </para>
-
- <para>
- Following is a brief overview of the components of a
- <literal>Configuration</literal>
- . See the javadoc and the linked
- chapters in this book for a more complete explanation of the
- configurations associated with each component.
-
- <itemizedlist>
- <listitem>
- <literal>Configuration</literal>
- : top level object
- in the hierarchy; exposes the configuration properties listed in the
- <link linkend="configuration_reference">configuration reference</link>
- section of this book.
- </listitem>
-
- <listitem>
- <literal>BuddyReplicationConfig</literal>
- : only relevant if
- <link linkend="br">buddy replication</link>
- is used. General
- buddy replication configuration options. Must include a:
- </listitem>
-
- <listitem>
- <literal>BuddyLocatorConfig</literal>
- : implementation-specific
- configuration object for the
- <literal>BuddyLocator</literal>
- implementation
- being used. What configuration elements are exposed depends on
- the needs of the
- <literal>BuddyLocator</literal>
- implementation.
- </listitem>
-
- <listitem>
- <literal>EvictionConfig</literal>
- : only relevant if
- <link linkend="eviction_policies">eviction</link>
- is used. General
- eviction configuration options. Must include at least one:
- </listitem>
-
- <listitem>
- <literal>EvictionRegionConfig</literal>
- : one for each
- eviction region; names the region, etc. Must include a:
- </listitem>
-
- <listitem>
- <literal>EvictionPolicyConfig</literal>
- : implementation-specific
- configuration object for the
- <literal>EvictionPolicy</literal>
- implementation
- being used. What configuration elements are exposed depends on
- the needs of the
- <literal>EvictionPolicy</literal>
- implementation.
- </listitem>
-
- <listitem>
- <literal>CacheLoaderConfig</literal>
- : only relevant if a
- <link linkend="cache_loaders">cache loader</link>
- is used. General
- cache loader configuration options. Must include at least one:
- </listitem>
-
- <listitem>
- <literal>IndividualCacheLoaderConfig</literal>
- : implementation-specific
- configuration object for the
- <literal>CacheLoader</literal>
- implementation
- being used. What configuration elements are exposed depends on
- the needs of the
- <literal>CacheLoader</literal>
- implementation.
- </listitem>
-
- <listitem>
- <literal>RuntimeConfig</literal>
- : exposes to cache clients
- certain information about the cache's runtime environment (e.g. membership
- in buddy replication groups if
- <link linkend="br">buddy replication</link>
- is used.) Also allows
- direct injection into the cache of needed external services like a
- JTA
- <literal>TransactionManager</literal>
- or a JGroups
- <literal>ChannelFactory</literal>
- .
- </listitem>
- </itemizedlist>
- </para>
- </section>
-
- <section>
- <title>Dynamic Reconfiguration</title>
- <para>
- Dynamically changing the configuration of
- <emphasis>some</emphasis>
- options while the cache is running is supported,
- by programmatically obtaining the
- <literal>Configuration</literal>
- object from the running cache and changing values. E.g.,
- <programlisting>
-
- Configuration liveConfig = cache.getConfiguration();
- liveConfig.setLockAcquisitionTimeout(2000);
-
- </programlisting>
- A complete listing of which options may be changed dynamically is in the
- <link linkend="configuration_reference">configuration reference</link>
- section. An
- <literal>org.jboss.cache.config.ConfigurationException</literal>
- will be thrown if you attempt to change a
- setting that is not dynamic.
- </para>
- </section>
-
- <section id="configuration.options">
- <title>Overriding the Configuration Via the Option API</title>
- <para>
- The Option API allows you to override certain behaviours of the cache on a per invocation basis.
- This involves creating an instance of
- <literal>org.jboss.cache.config.Option</literal>
- , setting the options
- you wish to override on the
- <literal>Option</literal>
- object and passing it in the
- <literal>InvocationContext</literal>
- before invoking your method on the cache.
- </para>
- <para>
- E.g., to override the default node versioning used with optimistic locking:
- <programlisting>
-
- DataVersion v = new MyCustomDataVersion();
- cache.getInvocationContext().getOptionOverrides().setDataVersion(v);
- Node ch = cache.getRoot().addChild(Fqn.fromString("/a/b/c"));
-
- </programlisting>
- </para>
- <para>
- E.g., to suppress replication of a put call in a REPL_SYNC cache:
- <programlisting>
-
- Node node = cache.getChild(Fqn.fromString("/a/b/c"));
- cache.getInvocationContext().getOptionOverrides().setLocalOnly(true);
- node.put("localCounter", new Integer(2));
-
- </programlisting>
- </para>
- <para>
- See the javadocs on the
- <literal>Option</literal>
- class for details on the options available.
- </para>
- </section>
-</chapter>
Added: pojo/trunk/src/main/docbook/userguide/en/modules/configuration.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/configuration.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/configuration.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -0,0 +1,502 @@
+<chapter id="configuration">
+
+
+ <title>Configuration and Deployment</title>
+
+ <para>Since POJO Cache uses Core Cache for the underlying node replication, transaction,
+ locking, and passivation behavior, the configuration is mostly the same.</para>
+
+ <section>
+ <title>Cache configuration xml file</title>
+ <para>When a PojoCache instance is obtained from a PojoCacheFactory, it is required that the
+ either a <literal>org.jboss.cache.config.Configuration</literal> object is passed, or more typically
+ a String indicating the location on the classpath or filesystem of an xml configuration file is provided.
+ In the latter case, PojoCacheFactory will parse the xml to create a <literal>Configuration</literal>.
+ PojoCache will simply pass the resulting <literal>Configuration</literal> to the underlying Core Cache
+ implementation.
+
+ For details on the configuration please see the "Configuration" chapter in the
+ the JBoss Cache User Guide.</para>
+ </section>
+
+ <section>
+ <title>Passivation</title>
+ <para>A common use-case is to configure the underlying Core Cache to enable passivation. Passivation is a feature
+ used to reduce cache memory usage by evicting stale data that can later be reloaded.
+ In JBoss Cache, it is done via a combination of an eviction
+ policy and a cache loader. That is, when a node is evicted from the Cache's in-memory store, it will
+ be stored in a persistent store by the cache loader. When the node is requested again, it will be loaded
+ from the persistent store and stored into memory.
+ </para>
+ <para>There is a restriction, however. Since POJO Cache maps object data into an internal area, there are
+ two places that have object information. One is under the regular String ID that the user specifies, and
+ the other is located under <code>/__JBossInternal__</code>. Therefore, to maintain consistentency,
+ when you specify the eviction region, you can only specify one global (i.e., <code>/_default_</code>)
+ region. This way, when the nodes associated with a POJO are passivated, they will do so across the whole
+ region.
+ </para>
+ <para>
+ Below is a snippet from a cache configuration xml
+ illustrating how the eviction policy along with cache loader can be configured. Please note that this is
+ simply an aspect of the underlying Cache. That is, PojoCache layer is agnostic to this behavior.
+<programlisting>
+ <![CDATA[
+<attribute name="EvictionPolicyConfig">
+ <config>
+ <attribute name="wakeUpIntervalSeconds">5</attribute>
+ <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+ <!-- Cache wide default -->
+ <region name="/_default_">
+ <attribute name="maxNodes">5000</attribute>
+ <attribute name="timeToLiveSeconds">3</attribute>
+ </region>
+ </config>
+</attribute>
+
+<attribute name="CacheLoaderConfiguration">
+ <config>
+ <passivation>true</passivation>
+ <preload>/</preload>
+ <shared>false</shared>
+
+ <!-- we can now have multiple cache loaders, which get chained -->
+ <cacheloader>
+ <class>org.jboss.cache.loader.FileCacheLoader</class>
+ <!-- whether the cache loader writes are asynchronous -->
+ <async>false</async>
+ <!-- only one cache loader in the chain may set fetchPersistentState to true.
+ An exception is thrown if more than one cache loader sets this to true. -->
+ <fetchPersistentState>true</fetchPersistentState>
+ <!-- determines whether this cache loader ignores writes - defaults to false. -->
+ <ignoreModifications>false</ignoreModifications>
+ </cacheloader>
+ </config>
+</attribute>
+]]>
+</programlisting>
+ </para>
+ <para>Another way to support multiple regions in eviction is to use region-based marshalling.
+ See the "Architecture" chapter in the JBoss Cache User Guide for more information on region-based marshalling.
+ When the Cache uses region-based marshalling, POJO Cache will store internal node data on the region that is
+ specified. This allows for a more flexible eviction policy. </para>
+ </section>
+
+
+ <section>
+ <title>AOP Configuration</title>
+ <para>POJO Cache supplies a <literal>pojocache-aop.xml</literal> that is required to be set via a
+ system property: <literal>jboss.aop.path</literal> during compile- or load-time, or placed in
+ the user's classpath. The file now consists
+ of the interceptor stack specification, as well as annotations for POJO instrumentation. It is listed fully in the
+ Appendix section. Note that the file should not normally need to be modified. Only an advanced use-case
+ would require changes.</para>
+ </section>
+
+ <section>
+ <title>Deployment Options</title>
+ <para>There are a number of ways to deploy POJO Cache:</para>
+
+ <section>
+ <title>Programatic Deployment</title>
+ <para>Simply instantiate a PojoCacheFactory and invoke one of the
+ overloaded <literal>createCache</literal> methods shown in the
+ <link linkend="api">API Overview</link>.</para>
+ </section>
+
+ <section id="deployment.microkernel">
+ <title>JMX-Based Deployment in JBoss AS (JBoss AS 5.x and 4.x)</title>
+ <para>If PojoCache is run in JBoss AS then your cache can be deployed as an
+ MBean simply by copying a standard cache configuration file to the server's
+ <literal>deploy</literal> directory. The standard format of PojoCache's
+ standard XML configuration file (as shown in the
+ <link linkend="xml">Appendix</link>) is the same
+ as a JBoss AS MBean deployment descriptor, so the AS's SAR Deployer has
+ no trouble handling it. Also, you don't have to place the configuration
+ file directly in <literal>deploy</literal>; you can package it along
+ with other services or JEE components in a SAR or EAR.
+ </para>
+
+ <para>
+ In AS 5, if you're using a server config based on the standard
+ <literal>all</literal> config, then that's all you need to do; all required
+ jars will be on the classpath. Otherwise, you will need to ensure
+ <literal>pojocache.jar</literal>, <literal>jbosscache.jar</literal>
+ and <literal>jgroups-all.jar</literal> are on the classpath. You may
+ need to add other jars if you're using
+ things like <literal>JdbmCacheLoader</literal>. The simplest way to do
+ this is to copy the jars from the PojoCache distribution's
+ <literal>lib</literal> directory to the server config's <literal>lib</literal>
+ directory. You could also package the jars with the configuration file
+ in Service Archive (.sar) file or an EAR.
+ </para>
+
+ <para>
+ It is possible, to deploy a POJO Cache 2.0 instance in JBoss AS 4.x
+ However, the significant API changes between the 2.x and 1.x releases
+ mean none of the standard AS 4.x clustering services (e.g.
+ http session replication) that rely on the 1.x API will work with
+ PojoCache 2.x. Also, be aware that usage of PojoCache 2.x in AS 4.x is not
+ something the cache developers are making any significant effort to test,
+ so be sure to test your application well (which of course you're doing anyway.)
+ </para>
+
+ <para>
+ Note in the <link linkend="xml">example</link>
+ the value of the <literal>mbean</literal> element's
+ <literal>code</literal> attribute:
+ <literal>org.jboss.cache.pojo.jmx.PojoCacheJmxWrapper</literal>. This is the
+ class JBoss Cache uses to handle JMX integration; the
+ PojoCache itself does not expose an MBean
+ interface. See the
+ <link linkend="jmx.mbeans">JBoss Cache MBeans section</link>
+ for more on the PojoCacheJmxWrapper.
+ </para>
+
+ <para>
+ Once your cache is deployed, in order to use it with an in-VM client
+ such as a servlet, a JMX proxy can be used to get a reference to
+ the cache:
+ </para>
+
+ <programlisting>
+ <![CDATA[
+ MBeanServer server = MBeanServerLocator.locateJBoss();
+ ObjectName on = new ObjectName("jboss.cache:service=PojoCache");
+ PojoCacheJmxWrapperMBean cacheWrapper =
+ (PojoCacheJmxWrapperMBean) MBeanServerInvocationHandler.newProxyInstance(server, on,
+ PojoCacheJmxWrapperMBean.class, false);
+ PojoCache cache = cacheWrapper.getPojoCache();
+ ]]>
+ </programlisting>
+
+ <para>The MBeanServerLocator class is a helper to find the (only) JBoss
+ MBean server inside the current JVM. The
+ <literal>javax.management.MBeanServerInvocationHandler</literal> class'
+ <literal>newProxyInstance</literal> method creates a
+ dynamic proxy implementing the given interface and uses JMX to
+ dynamically dispatch methods invoked against the generated interface
+ to the MBean. The name used to look up the MBean is the same as defined
+ in the cache's configuration file.
+ </para>
+
+ <para>
+ Once the proxy to the <literal>PojoCacheJmxWrapper</literal> is obtained,
+ the <literal>getPojoCache()</literal> will return a reference to the
+ PojoCache itself.
+ </para>
+ </section>
+
+ <section id="deployment.microcontainer">
+ <title>Via JBoss Microcontainer (JBoss AS 5.x)</title>
+
+ <para>
+ Beginning with AS 5, JBoss AS also supports deployment of POJO services via
+ deployment of a file whose name ends with <literal>-beans.xml</literal>.
+ A POJO service is one whose implementation is via a "Plain Old Java Object",
+ meaning a simple java bean that isn't required to implement any special
+ interfaces or extend any particular superclass. A PojoCache
+ is a POJO service, and all the components in a <literal>Configuration</literal>
+ are also POJOS, so deploying a cache in this way is a natural step.
+ </para>
+ <para>
+ Deployment of the cache is done using the JBoss Microcontainer that forms the
+ core of JBoss AS. JBoss Microcontainer is a sophisticated IOC framework
+ (similar to Spring). A <literal>-beans.xml</literal> file is basically
+ a descriptor that tells the IOC framework how to assemble the various
+ beans that make up a POJO service.
+ </para>
+ <para>
+ The rules for how to deploy the file, how to package it, how to
+ ensure the required jars are on the classpath, etc. are the same
+ as for a <link linkend="deployment.microkernel">JMX-based deployment</link>.
+ </para>
+
+ <para>
+ Following is an abbreviated example <literal>-beans.xml</literal> file.
+ The details of building up the Configuration are omitted; see the
+ "Deploying JBoss Cache" chapter in the JBoss Cache User Guide for
+ a more complete example. If you look in the
+ <literal>server/all/deploy</literal> directory of an AS 5
+ installation, you can find several more examples.
+ </para>
+
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <!-- First we create a Configuration object for the cache -->
+ <bean name="ExampleCacheConfig"
+ class="org.jboss.cache.config.Configuration">
+
+ ... details omitted
+
+ </bean>
+
+ <!-- The cache itself. -->
+ <bean name="ExampleCache" class="org.jboss.cache.pojo.impl.PojoCacheImpl">
+
+ <constructor factoryClass="org.jboss.cache.pojo.PojoCacheFactory
+ factoryMethod="createCache">
+ <parameter><inject bean="ExampleCacheConfig"/></parameter>
+ <parameter>false</false>
+ </constructor>
+
+ </bean>
+
+</deployment>
+]]>
+ </programlisting>
+
+ <para>
+ An interesting thing to note in the above example is the difference
+ between POJO Cache and a plain Cache in the use of a factory to
+ create the cache. (See the "Deploying JBoss Cache" chapter in the
+ JBoss Cache User Guide for the comparable plain Cache example.) The
+ PojoCacheFactory exposes static methods for creating a PojoCache;
+ as a result there is no need to add a separate <literal>bean</literal>
+ element for the factory. Core Cache's
+ <literal>DefaultCacheFactory</literal> creates caches from a singleton
+ instance, requiring a bit more boilerplate in the config file.
+ </para>
+ </section>
+ </section>
+
+ <section id="jmx.mbeans">
+ <title>POJO Cache MBeans</title>
+ <para>
+ POJO Cache provides an MBean that can be registered with your environment's JMX server to allow access
+ to the cache instance via JMX. This MBean is the <literal>org.jboss.cache.pojo.jmx.PojoCacheJmxWrapper</literal>.
+ It is a StandardMBean, so it's MBean interface is <literal>org.jboss.cache.pojo.jmx.PojoCacheJmxWrapperMBean</literal>.
+ This MBean can be used to:
+ <itemizedlist>
+ <listitem>Get a reference to the underlying PojoCache.</listitem>
+ <listitem>Invoke create/start/stop/destroy lifecycle operations on
+ the underlying PojoCache.</listitem>
+ <listitem>See numerous details about the cache's configuration, and
+ change those configuration items that can be changed when the
+ cache has already been started.</listitem>
+ </itemizedlist>
+ See the <literal>PojoCacheJmxWrapperMBean</literal> javadoc for more details.
+ </para>
+ <para>
+ It is important to note a significant architectural difference between PojoCache 1.x and 2.x. In 1.x,
+ the old <literal>TreeCacheAop</literal> class was itself an MBean, and essentially exposed the cache's entire
+ API via JMX. In 2.x, JMX has been returned to it's fundamental role as a management layer. The
+ PojoCache object itself is completely unaware of JMX; instead JMX functionality is added
+ through a wrapper class designed for that purpose. Furthermore, the interface exposed through JMX
+ has been limited to management functions; the general PojoCache API is no longer exposed
+ through JMX. For example, it is no longer possible to invoke a cache <literal>attach</literal> or
+ <literal>detach</literal> via the JMX interface.
+ </para>
+ <para>
+ If a <literal>PojoCacheJmxWrapper</literal> is registered, the wrapper also registers MBeans
+ for the underlying plain Cache and for each interceptor configured in the cache's interceptor stack.
+ These MBeans are used to capture and expose statistics related to cache operations; see the
+ JBoss Cache User Guide for more. They are hierarchically
+ associated with the <literal>PojoCacheJmxWrapper</literal> MBean and have service names that
+ reflect this relationship. For
+ example, a plain Cache associated with a <literal>jboss.cache:service=PojoCache</literal> will be
+ accessible through an mbean named <literal>jboss.cache:service=PojoCache,cacheType=Cache</literal>.
+ The replication interceptor MBean for that cache will be accessible through the mbean named
+ <literal>jboss.cache:service=PojoCache,cacheType=Cache,cache-interceptor=ReplicationInterceptor</literal>.
+ </para>
+ </section>
+
+ <section id="jmx.registration">
+ <title>Registering the PojoCacheJmxWrapper</title>
+
+ <para>
+ The best way to ensure the <literal>PojoCacheJmxWrapper</literal> is registered
+ in JMX depends on how you are deploying your cache:
+ </para>
+
+ <section id="jmx.registration.programatic">
+ <title>Programatic Registration</title>
+
+ <para>
+ Simplest way to do this is to create your <literal>PojoCache</literal>
+ and pass it to the <literal>PojoCacheJmxWrapper</literal> constructor.
+ </para>
+
+ <programlisting>
+ // Build but don't start the cache
+ // (although it would work OK if we started it)
+ PojoCache cache = PojoCacheFactory.createCache("cache-configuration.xml", false);
+
+ PojoCacheJmxWrapperMBean wrapper = new PojoCacheJmxWrapper(cache);
+ MBeanServer server = getMBeanServer(); // however you do it
+ ObjectName on = new ObjectName("jboss.cache:service=PojoCache");
+ server.registerMBean(wrapper, on);
+
+ // Invoking lifecycle methods on the wrapper results
+ // in a call through to the cache
+ wrapper.create();
+ wrapper.start();
+
+ ... use the cache
+
+ ... on application shutdown
+
+ // Invoking lifecycle methods on the wrapper results
+ // in a call through to the cache
+ wrapper.stop();
+ wrapper.destroy();
+ </programlisting>
+
+ <para>
+ Alternatively, build a <literal>Configuration</literal> object
+ and pass it to the <literal>PojoCacheJmxWrapper</literal>. The wrapper
+ will construct the <literal>PojoCache</literal>:
+ </para>
+
+ <programlisting>
+ Configuration config = buildConfiguration(); // whatever it does
+
+ PojoCacheJmxWrapperMBean wrapper = new PojoCacheJmxWrapper(config);
+ MBeanServer server = getMBeanServer(); // however you do it
+ ObjectName on = new ObjectName("jboss.cache:service=TreeCache");
+ server.registerMBean(wrapper, on);
+
+ // Call to wrapper.create() will build the Cache if one wasn't injected
+ wrapper.create();
+ wrapper.start();
+
+ // Now that it's built, created and started, get the cache from the wrapper
+ PojoCache cache = wrapper.getPojoCache();
+
+ ... use the cache
+
+ ... on application shutdown
+
+ wrapper.stop();
+ wrapper.destroy();
+
+ </programlisting>
+ </section>
+
+ <section>
+ <title>JMX-Based Deployment in JBoss AS (JBoss AS 4.x and 5.x)</title>
+
+ <para>
+ When you
+ <link linkend="deployment.microkernel">deploy your cache in JBoss AS using a -service.xml file</link>,
+ a <literal>PojoCacheJmxWrapper</literal> is automatically registered. There is no need
+ to do anything further. The <literal>PojoCacheJmxWrapper</literal> is accessible
+ through the service name specified in the cache configuration file's <literal>mbean</literal> element.
+ </para>
+ </section>
+
+ <section>
+ <title>Via JBoss Microcontainer (JBoss AS 5.x)</title>
+
+ <para>
+ <literal>PojoCacheJmxWrapper</literal> is a POJO, so the microcontainer
+ has no problem creating one. The trick is
+ getting it to register your bean in JMX. This can be done by
+ specifying the <literal>org.jboss.aop.microcontainer.aspects.jmx.JMX</literal>
+ annotation on the <literal>PojoCacheJmxWrapper</literal> bean:
+ </para>
+
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <!-- First we create a Configuration object for the cache -->
+ <bean name="ExampleCacheConfig"
+ class="org.jboss.cache.config.Configuration">
+
+ ... build up the Configuration
+
+ </bean>
+
+ <!-- The cache itself. -->
+ <bean name="ExampleCache" class="org.jboss.cache.pojo.impl.PojoCacheImpl">
+
+ <constructor factoryClass="org.jboss.cache.pojo.PojoCacheFactory
+ factoryMethod="createCache">
+ <parameter><inject bean="ExampleCacheConfig"/></parameter>
+ <parameter>false</false>
+ </constructor>
+
+ </bean>
+
+ <!-- JMX Management -->
+ <bean name="ExampleCacheJmxWrapper" class="org.jboss.cache.jmx.CacheJmxWrapper">
+
+ <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(
+ name="jboss.cache:service=ExamplePojoCache",
+ exposedInterface=org.jboss.cache.pojo.jmx.PojoCacheJmxWrapperMBean.class,
+ registerDirectly=true)
+ </annotation>
+
+ <constructor>
+ <parameter><inject bean="ExampleCache"/></parameter>
+ </constructor>
+
+ </bean>
+
+</deployment>
+]]>
+ </programlisting>
+
+ <para>
+ As discussed in the <link linkend="jmx.registration.programatic">Programatic Registration</link>
+ section, <literal>PojoCacheJmxWrapper</literal> can do the work of building,
+ creating and starting the PojoCache if it is provided with a <literal>Configuration</literal>:
+ </para>
+
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <!-- First we create a Configuration object for the cache -->
+ <bean name="ExampleCacheConfig"
+ class="org.jboss.cache.config.Configuration">
+
+ ... build up the Configuration
+
+ </bean>
+
+ <bean name="ExampleCache" class="org.jboss.cache.pojo.jmx.PojoCacheJmxWrapper">
+
+ <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(
+ name="jboss.cache:service=ExamplePojoCache",
+ exposedInterface=org.jboss.cache.pojo.jmx.PojoCacheJmxWrapperMBean.class,
+ registerDirectly=true)
+ </annotation>
+
+ <constructor>
+ <parameter><inject bean="ExampleCacheConfig"/></parameter>
+ </constructor>
+
+ </bean>
+
+</deployment>
+]]>
+ </programlisting>
+ </section>
+
+ </section>
+
+ <section>
+ <title>Runtime Statistics and JMX Notifications</title>
+
+ <para>As mentioned above, the cache exposes a variety of statistical
+ information through its MBeans. It also emits JMX notifications when
+ events occur in the cache. See the JBoss Cache User Guide for more
+ on the statistics and notifications that are available.
+ </para>
+ <para>The only PojoCache addition to the plain JBoss Cache behavior
+ described in the User Guide is that you can register with the
+ PojoCacheJmxWrapper to get the notifications. There is no
+ requirement to figure out the ObjectName of the underlying
+ cache's CacheJmxWrapper and register with that.
+ </para>
+ </section>
+</chapter>
Property changes on: pojo/trunk/src/main/docbook/userguide/en/modules/configuration.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: pojo/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml 2007-08-14 16:34:22 UTC (rev 4250)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -1,665 +0,0 @@
-<chapter id="configuration_reference_chapter">
- <title>Configuration References</title>
- <section id="sample_xml_file">
- <title>Sample XML Configuration File</title>
- <para>
- This is what a typical XML configuration file looks like. It is recommended that you use one of the
- configurations
- shipped with the JBoss Cache distribution and tweak according to your needs rather than write one from scratch.
- </para>
- <programlisting>
- <![CDATA[
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!-- ===================================================================== -->
-<!-- -->
-<!-- Sample JBoss Cache Service Configuration -->
-<!-- -->
-<!-- ===================================================================== -->
-
-<server>
-
- <!-- ==================================================================== -->
- <!-- Defines JBoss Cache configuration -->
- <!-- ==================================================================== -->
-
- <!-- Note the value of the 'code' attribute has changed since JBC 1.x -->
- <mbean code="org.jboss.cache.jmx.CacheJmxWrapper" name="jboss.cache:service=Cache">
-
- <!-- Ensure JNDI and the TransactionManager are started before the
- cache. Only works inside JBoss AS; ignored otherwise -->
- <depends>jboss:service=Naming</depends>
- <depends>jboss:service=TransactionManager</depends>
-
- <!-- Configure the TransactionManager -->
- <attribute name="TransactionManagerLookupClass">
- org.jboss.cache.transaction.GenericTransactionManagerLookup
- </attribute>
-
- <!-- Node locking level : SERIALIZABLE
- REPEATABLE_READ (default)
- READ_COMMITTED
- READ_UNCOMMITTED
- NONE -->
- <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
-
- <!-- Lock parent before doing node additions/removes -->
- <attribute name="LockParentForChildInsertRemove">true</attribute>
-
- <!-- Valid modes are LOCAL (default)
- REPL_ASYNC
- REPL_SYNC
- INVALIDATION_ASYNC
- INVALIDATION_SYNC -->
- <attribute name="CacheMode">REPL_ASYNC</attribute>
-
- <!-- Name of cluster. Needs to be the same for all JBoss Cache nodes in a
- cluster in order to find each other.
- -->
- <attribute name="ClusterName">JBossCache-Cluster</attribute>
-
- <!--Uncomment next three statements to use the JGroups multiplexer.
- This configuration is dependent on the JGroups multiplexer being
- registered in an MBean server such as JBossAS. This type of
- dependency injection only works in the AS; outside it's up to
- your code to inject a ChannelFactory if you want to use one.
- -->
- <!--
- <depends optional-attribute-name="MultiplexerService"
- proxy-type="attribute">jgroups.mux:name=Multiplexer</depends>
- <attribute name="MultiplexerStack">tcp</attribute>
- -->
-
- <!-- JGroups protocol stack properties.
- ClusterConfig isn't used if the multiplexer is enabled above.
- -->
- <attribute name="ClusterConfig">
- <config>
- <!-- UDP: if you have a multihomed machine, set the bind_addr
- attribute to the appropriate NIC IP address -->
- <!-- UDP: On Windows machines, because of the media sense feature
- being broken with multicast (even after disabling media sense)
- set the loopback attribute to true -->
- <UDP mcast_addr="228.1.2.3" mcast_port="48866"
- ip_ttl="64" ip_mcast="true"
- mcast_send_buf_size="150000" mcast_recv_buf_size="80000"
- ucast_send_buf_size="150000" ucast_recv_buf_size="80000"
- loopback="false"/>
- <PING timeout="2000" num_initial_members="3"/>
- <MERGE2 min_interval="10000" max_interval="20000"/>
- <FD shun="true"/>
- <FD_SOCK/>
- <VERIFY_SUSPECT timeout="1500"/>
- <pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
- max_xmit_size="8192"/>
- <UNICAST timeout="600,1200,2400",4800/>
- <pbcast.STABLE desired_avg_gossip="400000"/>
- <FC max_credits="2000000" min_threshold="0.10"/>
- <FRAG2 frag_size="8192"/>
- <pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
- shun="true" print_local_addr="true"/>
- <pbcast.STATE_TRANSFER/>
- </config>
- </attribute>
-
- <!--
- The max amount of time (in milliseconds) we wait until the
- initial state (ie. the contents of the cache) are retrieved from
- existing members in a clustered environment
- -->
- <attribute name="StateRetrievalTimeout">20000</attribute>
-
- <!--
- Number of milliseconds to wait until all responses for a
- synchronous call have been received.
- -->
- <attribute name="SyncReplTimeout">20000</attribute>
-
- <!-- Max number of milliseconds to wait for a lock acquisition -->
- <attribute name="LockAcquisitionTimeout">15000</attribute>
-
-
- <!-- Specific eviction policy configurations. This is LRU -->
- <attribute name="EvictionConfig">
- <config>
- <attribute name="wakeUpIntervalSeconds">5</attribute>
- <!-- This defaults to 200000 if not specified -->
- <attribute name="eventQueueSize">200000</attribute>
- <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
-
- <!-- Cache wide default -->
- <region name="/_default_">
- <attribute name="maxNodes">5000</attribute>
- <attribute name="timeToLiveSeconds">1000</attribute>
- </region>
- <region name="/org/jboss/data">
- <attribute name="maxNodes">5000</attribute>
- <attribute name="timeToLiveSeconds">1000</attribute>
- </region>
- <region name="/org/jboss/test/data">
- <attribute name="maxNodes">5</attribute>
- <attribute name="timeToLiveSeconds">4</attribute>
- </region>
- <region name="/test">
- <attribute name="maxNodes">10000</attribute>
- <attribute name="timeToLiveSeconds">4</attribute>
- </region>
- <region name="/maxAgeTest">
- <attribute name="maxNodes">10000</attribute>
- <attribute name="timeToLiveSeconds">8</attribute>
- <attribute name="maxAgeSeconds">10</attribute>
- </region>
- </config>
- </attribute>
- </mbean>
-</server>
-]]>
- </programlisting>
- </section>
-
-
- <section id="configuration_reference">
- <title>
- Reference table of XML attributes
- </title>
- <para>A list of definitions of each of the XML attributes used above. If the
- description of an attribute states that it is
- <emphasis>dynamic</emphasis>
- ,
- that means it can be changed after the cache is created and started.
- </para>
-
- <informaltable frame="all">
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>
- <para>Name</para>
- </entry>
-
- <entry>
- <para>Description</para>
- </entry>
- </row>
- <row>
- <entry>
- <para>BuddyReplicationConfig</para>
- </entry>
-
- <entry>
- <para>An XML element that contains detailed buddy replication
- configuration. See
- <link linkend="br">section on Buddy Replication</link>
- for details.
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>CacheLoaderConfig</para>
- </entry>
-
- <entry>
- <para>An XML element that contains detailed cache loader
- configuration. See
- <link linkend="cache_loaders">chapter on Cache Loaders</link>
- for details.
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>CacheLoaderConfiguration</para>
- </entry>
-
- <entry>
- <para>
- <emphasis>Deprecated</emphasis>
- . Use
- <literal>CacheLoaderConfig</literal>
- .
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>CacheMode</para>
- </entry>
-
- <entry>
- <para>LOCAL, REPL_SYNC, REPL_ASYNC, INVALIDATION_SYNC or
- INVALIDATION_ASYNC. Defaults to LOCAL. See the
- <link linkend="clustering">chapter on Clustering</link>
- for details.
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>ClusterConfig</para>
- </entry>
-
- <entry>
- <para>The configuration of the underlying JGroups stack.
- Ignored if
- <literal>MultiplexerService</literal>
- and
- <literal>MultiplexerStack</literal>
- are used.
- See the various *-service.xml files in the source distribution
- <literal>etc/META-INF</literal>
- folder for examples.
- See the
- <ulink url="http://www.jgroups.org">JGroups documentation</ulink>
- or the
- <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JGroups">JGroups wiki page</ulink>
- for more information.
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>ClusterName</para>
- </entry>
-
- <entry>
- <para>Name of cluster. Needs to be the same for all nodes in a
- cluster in order for them to communicate with each other.
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>EvictionPolicyConfig</para>
- </entry>
-
- <entry>
- <para>Configuration parameter for the specified eviction policy.
- See
- <link linkend="eviction_policies">chapter on eviction policies</link>
- for details. This property is
- <emphasis>dynamic</emphasis>
- .
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>ExposeManagementStatistics</para>
- </entry>
-
- <entry>
- <para>
- Specifies whether interceptors that provide statistics should have statistics
- gathering enabled at startup. Also controls whether a
- <literal>CacheMgmtInterceptor</literal>
- (whose sole purpose is gathering
- statistics) should be added to the interceptor chain. Default value is
- <emphasis>true</emphasis>
- . See the
- <link linkend="jmx.statistics">JBoss Cache Statistics section</link>
- section for more details.
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>FetchInMemoryState
- </para>
- </entry>
-
- <entry>
- <para>Whether or not to acquire the initial in-memory state from
- existing members. Allows for hot caches when enabled. Also
- see the
- <literal>fetchPersistentState</literal>
- element in
- <literal>CacheLoaderConfig</literal>
- . Defaults to
- <literal>true</literal>
- . This property is
- <emphasis>dynamic</emphasis>
- .
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>InactiveOnStartup</para>
- </entry>
-
- <entry>
- <para>Whether or not the entire tree is inactive upon startup,
- only responding to replication messages after
- <literal>activateRegion()</literal>
- is called to activate one or
- more parts of the tree. If true, property
- <literal>FetchInMemoryState</literal>
- is ignored. This property
- should only be set to true if
- <literal>UseRegionBasedMarshalling</literal>
- is also
- <literal>true</literal>
- .
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>StateRetrievalTimeout</para>
- </entry>
-
- <entry>
- <para>Time in milliseconds to wait for state
- retrieval. This should be longer than
- <literal>LockAcquisitionTimeout</literal>
- as the node
- providing state may need to wait that long to acquire
- necessary read locks on the cache. This property is
- <emphasis>dynamic</emphasis>
- .
- </para>
- </entry>
- </row>
-
-
- <row>
- <entry>
- <para>IsolationLevel</para>
- </entry>
-
- <entry>
- <para>Node locking isolation level : SERIALIZABLE, REPEATABLE_READ
- (default), READ_COMMITTED, READ_UNCOMMITTED, and NONE. Note that this is ignored if
- NodeLockingScheme is OPTIMISTIC. Case doesn't matter. See documentation on Transactions and
- Concurrency for more details.
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>LockAcquisitionTimeout</para>
- </entry>
-
- <entry>
- <para>Time in milliseconds to wait for a lock to be acquired. If
- a lock cannot be acquired an exception will be thrown. This property is
- <emphasis>dynamic</emphasis>
- .
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>LockParentForChildInsertRemove</para>
- </entry>
-
- <entry>
- <para>Controls whether inserting or removing a node requires a write
- lock on the node's parent (when pessimistic locking is used) or whether
- it results in an update of the parent node's version (when optimistic
- locking is used). The default value is
- <code>false</code>
- .
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>MarshallerClass</para>
- </entry>
-
- <entry>
- <para>An instance of
- <literal>org.jboss.cache.marshall.Marshaller</literal>
- used to serialize data to byte streams.
- Defaults to
- <literal>org.jboss.cache.marshall.VersionAwareMarshaller</literal>
- if not specified.
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>MultiplexerService</para>
- </entry>
-
- <entry>
- <para>The JMX object name of the service that defines the JGroups multiplexer.
- In JBoss AS 5.0 this service is normally defined in the jgroups-multiplexer.sar.
- This XML attribute can only be handled by the JBoss AS MBean deployment services;
- if it is included in a file passed to a
- <literal>CacheFactory</literal>
- the
- factory's creation of the cache will fail. Inside JBoss AS, the attribute should
- be specified using the "depends optional-attribute-name" syntax shown in
- the example above. Inside the AS if this attribute
- is defined, an instance of
- <literal>org.jgroups.jmx.JChannelFactoryMBean</literal>
- will be injected into the
- <literal>CacheJmxWrapper</literal>
- which will use
- it to obtain a multiplexed JGroups channel. The configuration
- of the channel will be that associated with
- <literal>MultiplexerStack</literal>
- .
- The
- <literal>ClusterConfig</literal>
- attribute will be ignored.
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>MultiplexerStack</para>
- </entry>
-
- <entry>
- <para>The name of the JGroups stack to be used with the cache cluster.
- Stacks are defined in the configuration of the external
- <literal>MultiplexerService</literal>
- discussed above. In JBoss AS 5 this is normally done in the
- jgroups-multiplexer.sar/META-INF/multiplexer-stacks.xml file.
- The default stack is
- <literal>udp</literal>
- . This attribute is used in conjunction with
- <literal>MultiplexerService</literal>
- .
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>NodeLockingScheme</para>
- </entry>
-
- <entry>
- <para>May be PESSIMISTIC (default) or OPTIMISTIC.
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>ReplicationVersion</para>
- </entry>
- <entry>
- <para>Tells the cache to serialize cluster traffic
- in a format consistent with that used by the given release
- of JBoss Cache. Different JBoss Cache versions use different
- wire formats; setting this attribute tells a cache from a later
- release to serialize data using the format from an earlier
- release. This allows caches from different releases to
- interoperate. For example, a 2.1.0 cache could have this
- value set to "2.0.0", allowing it to interoperate with a 2.0.0
- cache. Valid values are a dot-separated release number, with
- any final qualifer also separated by a dot, e.g. "2.0.0" or "2.0.0.GA".
- Values that indicate a 1.x release are not supported in the 2.x series.
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>ReplQueueInterval</para>
- </entry>
-
- <entry>
- <para>Time in milliseconds for elements from the replication
- queue to be replicated. Only used if
- <literal>UseReplQueue</literal>
- is enabled. This property is
- <emphasis>dynamic</emphasis>
- .
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>ReplQueueMaxElements</para>
- </entry>
-
- <entry>
- <para>Max number of elements in the replication queue until
- replication kicks in. Only used if
- <literal>UseReplQueue</literal>
- is enabled. This property is
- <emphasis>dynamic</emphasis>
- .
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>SyncCommitPhase</para>
- </entry>
-
- <entry>
- <para>This option is used to control the behaviour of the commit part of a 2-phase commit protocol,
- when
- using REPL_SYNC (does not apply to other cache modes). By default this is set to
- <literal>false</literal>
- . There is a performance penalty to enabling this, especially when running
- in a large cluster, but the upsides are greater cluster-wide data integrity. See the chapter on
- clustered caches for more information on this. This property is
- <emphasis>dynamic</emphasis>
- .
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>SyncReplTimeout</para>
- </entry>
-
- <entry>
- <para>For synchronous replication: time in milliseconds to wait
- until replication acks have been received from all nodes in the
- cluster. It is usually best that this is greater than
- <literal>LockAcquisitionTimeout</literal>
- .
- This property is
- <emphasis>dynamic</emphasis>
- .
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>SyncRollbackPhase</para>
- </entry>
-
- <entry>
- <para>This option is used to control the behaviour of the rollback part of a 2-phase commit
- protocol, when
- using REPL_SYNC (does not apply to other cache modes). By default this is set to
- <literal>false</literal>
- . There is a performance penalty to enabling this, especially when running
- in a large cluster, but the upsides are greater cluster-wide data integrity. See the chapter on
- clustered caches for more information on this. This property is
- <emphasis>dynamic</emphasis>
- .
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>TransactionManagerLookupClass</para>
- </entry>
-
- <entry>
- <para>The fully qualified name of a class implementing
- TransactionManagerLookup. Default is
- JBossTransactionManagerLookup. There is also an option of
- GenericTransactionManagerLookup for example.
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>UseInterceptorMbeans</para>
- </entry>
-
- <entry>
- <para>
- <emphasis>Deprecated</emphasis>
- . Use
- <literal>ExposeManagementStatistics</literal>
- .
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>UseRegionBasedMarshalling</para>
- </entry>
-
- <entry>
- <para>When unmarshalling replicated data, this option specifies whether or not to
- support use of different classloaders for different cache regions. This defaults to
- <literal>false</literal>
- if unspecified.
- </para>
- </entry>
- </row>
-
- <row>
- <entry>
- <para>UseReplQueue</para>
- </entry>
-
- <entry>
- <para>For asynchronous replication: whether or not to use a
- replication queue. Defaults to
- <literal>false</literal>
- .
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
-</chapter>
\ No newline at end of file
Deleted: pojo/trunk/src/main/docbook/userguide/en/modules/deployment.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/deployment.xml 2007-08-14 16:34:22 UTC (rev 4250)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/deployment.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -1,901 +0,0 @@
-<chapter id="deployment">
- <title>Deploying JBoss Cache</title>
- <section id="deployment.standalone">
- <title>Standalone Use / Programatic Deployment</title>
- <para>
- When used in a standalone Java program, all that needs to be done is to instantiate the cache using the
- <literal>CacheFactory</literal>
- and a
- <literal>Configuration</literal>
- instance or an XML file, as discussed
- in the
- <link linkend="api.create_start">User API</link>
- and
- <link linkend="configuration.creation">Configuration</link>
- chapters.
- </para>
-
- <para>
- The same techniques can be used when an application running in an application
- server wishes to programatically deploy a cache rather than relying on an application server's
- deployment features. An example of this would be
- a webapp deploying a cache via a
- <literal>javax.servlet.ServletContextListener</literal>
- .
- </para>
-
- <para>
- If, after deploying your cache you wish to expose a management interface
- to it in JMX, see the
- <link linkend="jmx.registration.programatic">section on Programatic Registration in JMX</link>
- .
- </para>
- </section>
-
- <section id="deployment.microkernel">
- <title>JMX-Based Deployment in JBoss AS (JBoss AS 5.x and 4.x)</title>
- <para>If JBoss Cache is run in JBoss AS then the cache can be deployed as an
- MBean simply by copying a standard cache configuration file to the server's
- <literal>deploy</literal>
- directory. The standard format of JBoss Cache's
- standard XML configuration file (as shown in the
- <link linkend="sample_xml_file">Configuration Reference</link>
- ) is the same
- as a JBoss AS MBean deployment descriptor, so the AS's SAR Deployer has
- no trouble handling it. Also, you don't have to place the configuration
- file directly in
- <literal>deploy</literal>
- ; you can package it along
- with other services or JEE components in a SAR or EAR.
- </para>
-
- <para>
- In AS 5, if you're using a server config based on the standard
- <literal>all</literal>
- config, then that's all you need to do; all required
- jars will be on the classpath. Otherwise, you will need to ensure
- <literal>jbosscache.jar</literal>
- and
- <literal>jgroups-all.jar</literal>
- are on the classpath. You may need to add other jars if you're using
- things like
- <literal>JdbmCacheLoader</literal>
- . The simplest way to do
- this is to copy the jars from the JBoss Cache distribution's
- <literal>lib</literal>
- directory to the server config's
- <literal>lib</literal>
- directory. You could also package the jars with the configuration file
- in Service Archive (.sar) file or an EAR.
- </para>
-
- <para>
- It is possible to deploy a JBoss Cache 2.0 instance in JBoss AS 4.x
- (at least in 4.2.0.GA; other AS releases are completely untested).
- However, the significant API changes between the JBoss Cache 2.x and 1.x releases
- mean none of the standard AS 4.x clustering services (e.g.
- http session replication) that rely on JBoss Cache will work with
- JBoss Cache 2.x. Also, be aware that usage of JBoss Cache 2.x in AS 4.x is not
- something the JBoss Cache developers are making any significant effort to test,
- so be sure to test your application well (which of course you're doing anyway.)
- </para>
-
- <para>
- Note in the
- <link linkend="sample_xml_file">example</link>
- the value of the
- <literal>mbean</literal>
- element's
- <literal>code</literal>
- attribute:
- <literal>org.jboss.cache.jmx.CacheJmxWrapper</literal>
- . This is the
- class JBoss Cache uses to handle JMX integration; the
- <literal>Cache</literal>
- itself does not expose an MBean
- interface. See the
- <link linkend="jmx.mbeans">JBoss Cache MBeans section</link>
- for more on the
- <literal>CacheJmxWrapper</literal>
- .
- </para>
-
- <para>
- Once your cache is deployed, in order to use it with an in-VM client
- such as a servlet, a JMX proxy can be used to get a reference to
- the cache:
- </para>
-
- <programlisting>
- <![CDATA[
- MBeanServer server = MBeanServerLocator.locateJBoss();
- ObjectName on = new ObjectName("jboss.cache:service=Cache");
- CacheJmxWrapperMBean cacheWrapper =
- (CacheJmxWrapperMBean) MBeanServerInvocationHandler.newProxyInstance(server, on,
- CacheJmxWrapperMBean.class, false);
- Cache cache = cacheWrapper.getCache();
- Node root = cache.getRoot(); // etc etc
- ]]>
- </programlisting>
-
- <para>The MBeanServerLocator class is a helper to find the (only) JBoss
- MBean server inside the current JVM. The
- <literal>javax.management.MBeanServerInvocationHandler</literal>
- class'
- <literal>newProxyInstance</literal>
- method creates a
- dynamic proxy implementing the given interface and uses JMX to
- dynamically dispatch methods invoked against the generated interface
- to the MBean. The name used to look up the MBean is the same as defined
- in the cache's configuration file.
- </para>
-
- <para>
- Once the proxy to the
- <literal>CacheJmxWrapper</literal>
- is obtained,
- the
- <literal>getCache()</literal>
- will return a reference to the
- <literal>Cache</literal>
- itself.
- </para>
-
- </section>
-
- <section id="deployment.microcontainer">
- <title>Via JBoss Microcontainer (JBoss AS 5.x)</title>
-
- <para>
- Beginning with AS 5, JBoss AS also supports deployment of POJO services via
- deployment of a file whose name ends with
- <literal>-beans.xml</literal>
- .
- A POJO service is one whose implementation is via a "Plain Old Java Object",
- meaning a simple java bean that isn't required to implement any special
- interfaces or extend any particular superclass. A
- <literal>Cache</literal>
- is a POJO service, and all the components in a
- <literal>Configuration</literal>
- are also POJOS, so deploying a cache in this way is a natural step.
- </para>
- <para>
- Deployment of the cache is done using the JBoss Microcontainer that forms the
- core of JBoss AS. JBoss Microcontainer is a sophisticated IOC framework
- (similar to Spring). A
- <literal>-beans.xml</literal>
- file is basically
- a descriptor that tells the IOC framework how to assemble the various
- beans that make up a POJO service.
- </para>
- <para>
- The rules for how to deploy the file, how to package it, how to
- ensure the required jars are on the classpath, etc. are the same
- as for a
- <link linkend="deployment.microkernel">JMX-based deployment</link>
- .
- </para>
-
- <para>
- Following is an example
- <literal>-beans.xml</literal>
- file. If you
- look in the
- <literal>server/all/deploy</literal>
- directory of an AS 5
- installation, you can find several more examples.
- </para>
-
- <programlisting>
- <![CDATA[
-<?xml version="1.0" encoding="UTF-8"?>
-
-<deployment xmlns="urn:jboss:bean-deployer:2.0">
-
- <!-- First we create a Configuration object for the cache -->
- <bean name="ExampleCacheConfig"
- class="org.jboss.cache.config.Configuration">
-
- <!-- Externally injected services -->
- <property name="runtimeConfig">
- <bean name="ExampleCacheRuntimeConfig" class="org.jboss.cache.config.RuntimeConfig">
- <property name="transactionManager">
- <inject bean="jboss:service=TransactionManager"
- property="TransactionManager"/>
- </property>
- <property name="muxChannelFactory"><inject bean="JChannelFactory"/></property>
- </bean>
- </property>
-
- <property name="multiplexerStack">udp</property>
-
- <property name="clusterName">Example-EntityCache</property>
-
- <!--
- Node locking level : SERIALIZABLE
- REPEATABLE_READ (default)
- READ_COMMITTED
- READ_UNCOMMITTED
- NONE
- -->
- <property name="isolationLevel">REPEATABLE_READ</property>
-
- <!-- Valid modes are LOCAL
- REPL_ASYNC
- REPL_SYNC
- -->
- <property name="cacheMode">REPL_SYNC</property>
-
- <!-- The max amount of time (in milliseconds) we wait until the
- initial state (ie. the contents of the cache) are retrieved from
- existing members in a clustered environment
- -->
- <property name="initialStateRetrievalTimeout">15000</property>
-
- <!-- Number of milliseconds to wait until all responses for a
- synchronous call have been received.
- -->
- <property name="syncReplTimeout">20000</property>
-
- <!-- Max number of milliseconds to wait for a lock acquisition -->
- <property name="lockAcquisitionTimeout">15000</property>
-
- <property name="exposeManagementStatistics">true</property>
-
- <!-- Must be true if any entity deployment uses a scoped classloader -->
- <property name="useRegionBasedMarshalling">true</property>
- <!-- Must match the value of "useRegionBasedMarshalling" -->
- <property name="inactiveOnStartup">true</property>
-
- <!-- Specific eviction policy configurations. This is LRU -->
- <property name="evictionConfig">
- <bean name="ExampleEvictionConfig"
- class="org.jboss.cache.config.EvictionConfig">
- <property name="defaultEvictionPolicyClass">
- org.jboss.cache.eviction.LRUPolicy
- </property>
- <property name="wakeupIntervalSeconds">5</property>
- <property name="evictionRegionConfigs">
- <list>
- <bean name="ExampleDefaultEvictionRegionConfig"
- class="org.jboss.cache.config.EvictionRegionConfig">
- <property name="regionName">/_default_</property>
- <property name="evictionPolicyConfig">
- <bean name="ExampleDefaultLRUConfig"
- class="org.jboss.cache.eviction.LRUConfiguration">
- <property name="maxNodes">5000</property>
- <property name="timeToLiveSeconds">1000</property>
- </bean>
- </property>
- </bean>
- </list>
- </property>
- </bean>
- </property>
-
- </bean>
-
- <!-- Factory to build the Cache. -->
- <bean name="DefaultCacheFactory" class="org.jboss.cache.DefaultCacheFactory">
- <constructor factoryClass="org.jboss.cache.DefaultCacheFactory"
- factoryMethod="getInstance"/>
- </bean>
-
- <!-- The cache itself -->
- <bean name="ExampleCache" class="org.jboss.cache.CacheImpl">
-
- <constructor factoryMethod="createCache">
- <factory bean="DefaultCacheFactory"/>
- <parameter><inject bean="ExampleCacheConfig"/></parameter>
- <parameter>false</false>
- </constructor>
-
- </bean>
-
-</deployment>
-]]>
- </programlisting>
-
- <para>
- See the JBoss Microcontainer documentation
- <footnote>
- <para>http://labs.jboss.com/jbossmc/docs</para>
- </footnote>
- for details on the above syntax. Basically, each
- <literal>bean</literal>
- element represents an object; most going to create a
- <literal>Configuration</literal>
- and its
- <link linkend="configuration.elements">constituent parts</link>
- .
- </para>
- <para>
- An interesting thing to note in the above example is the use of the
- <literal>RuntimeConfig</literal>
- object. External resources like
- a
- <literal>TransactionManager</literal>
- and a JGroups
- <literal>ChannelFactory</literal>
- that are visible to the
- microcontainer are dependency injected into the
- <literal>RuntimeConfig</literal>
- .
- The assumption here is that in some other deployment descriptor in the AS,
- the referenced beans have been described.
- </para>
- </section>
-
- <section>
- <title>Binding to JNDI in JBoss AS</title>
- <para>
- With the 1.x JBoss Cache releases, a proxy to the cache could be bound
- into JBoss AS's JNDI tree using the AS's
- <literal>JRMPProxyFactory</literal>
- service. With JBoss Cache 2.x, this no longer works. An alternative
- way of doing a similar thing with a POJO (i.e. non-JMX-based) service
- like a
- <literal>Cache</literal>
- is under development by the JBoss AS
- team
- <footnote>
- <para>http://jira.jboss.com/jira/browse/JBAS-4456</para>
- </footnote>
- . That feature is not available as of the time of this writing,
- although it will be completed before AS 5.0.0.GA is released.
- We will add a wiki page describing how to use it once it becomes available.
- </para>
- </section>
-
- <section>
- <title>Runtime Management Information</title>
- <para>JBoss Cache includes JMX MBeans to expose cache functionality and provide statistics that can be
- used to analyze cache operations. JBoss Cache can also broadcast cache events as MBean notifications for
- handling
- via JMX monitoring tools.
- </para>
-
- <section id="jmx.mbeans">
- <title>JBoss Cache MBeans</title>
- <para>
- JBoss Cache provides an MBean that can be registered with your environments JMX server to allow access
- to the cache instance via JMX. This MBean is the
- <literal>org.jboss.cache.jmx.CacheJmxWrapper</literal>
- .
- It is a StandardMBean, so it's MBean interface is
- <literal>org.jboss.cache.jmx.CacheJmxWrapperMBean</literal>
- .
- This MBean can be used to:
- <itemizedlist>
- <listitem>Get a reference to the underlying
- <literal>Cache</literal>
- .
- </listitem>
- <listitem>Invoke create/start/stop/destroy lifecycle operations on
- the underlying
- <literal>Cache</literal>
- .
- </listitem>
- <listitem>Inspect various details about the cache's current state (number of nodes, lock information,
- etc.)
- </listitem>
- <listitem>See numerous details about the cache's configuration, and
- change those configuration items that can be changed when the
- cache has already been started.
- </listitem>
- </itemizedlist>
- See the
- <literal>CacheJmxWrapperMBean</literal>
- javadoc for more details.
- </para>
- <para>
- It is important to note a significant architectural difference between JBoss Cache 1.x and 2.x. In 1.x,
- the old
- <literal>TreeCache</literal>
- class was itself an MBean, and essentially exposed the cache's entire
- API via JMX. In 2.x, JMX has been returned to it's fundamental role as a management layer. The
- <literal>Cache</literal>
- object itself is completely unaware of JMX; instead JMX functionality is added
- through a wrapper class designed for that purpose. Furthermore, the interface exposed through JMX
- has been limited to management functions; the general
- <literal>Cache</literal>
- API is no longer exposed
- through JMX. For example, it is no longer possible to invoke a cache
- <literal>put</literal>
- or
- <literal>get</literal>
- via the JMX interface.
- </para>
- <para>
- If a
- <literal>CacheJmxWrapper</literal>
- is registered, JBoss Cache also provides MBeans
- for each interceptor configured in the cache's interceptor stack. These
- MBeans are used to capture and expose statistics related to cache operations. They are hierarchically
- associated with the
- <literal>CacheJmxWrapper</literal>
- MBean and have service names that reflect this relationship. For
- example, a replication interceptor MBean for the
- <literal>jboss.cache:service=TomcatClusteringCache</literal>
- instance will be
- accessible through the service named
- <literal>jboss.cache:service=TomcatClusteringCache,cache-interceptor=ReplicationInterceptor</literal>
- .
- </para>
- </section>
-
- <section id="jmx.registration">
- <title>Registering the CacheJmxWrapper with the MBeanServer</title>
-
- <para>
- The best way to ensure the
- <literal>CacheJmxWrapper</literal>
- is registered
- in JMX depends on how you are deploying your cache:
- </para>
-
- <section id="jmx.registration.programatic">
- <title>Programatic Registration</title>
-
- <para>
- Simplest way to do this is to create your
- <literal>Cache</literal>
- and pass it to the
- <literal>CacheJmxWrapper</literal>
- constructor.
- </para>
-
- <programlisting>
- CacheFactory factory = DefaultCacheFactory.getInstance();
- // Build but don't start the cache
- // (although it would work OK if we started it)
- Cache cache = factory.createCache("cache-configuration.xml", false);
-
- CacheJmxWrapperMBean wrapper = new CacheJmxWrapper(cache);
- MBeanServer server = getMBeanServer(); // however you do it
- ObjectName on = new ObjectName("jboss.cache:service=TreeCache");
- server.registerMBean(wrapper, on);
-
- // Invoking lifecycle methods on the wrapper results
- // in a call through to the cache
- wrapper.create();
- wrapper.start();
-
- ... use the cache
-
- ... on application shutdown
-
- // Invoking lifecycle methods on the wrapper results
- // in a call through to the cache
- wrapper.stop();
- wrapper.destroy();
- </programlisting>
-
- <para>
- Alternatively, build a
- <literal>Configuration</literal>
- object
- and pass it to the
- <literal>CacheJmxWrapper</literal>
- . The wrapper
- will construct the
- <literal>Cache</literal>
- :
- </para>
-
- <programlisting>
- Configuration config = buildConfiguration(); // whatever it does
-
- CacheJmxWrapperMBean wrapper = new CacheJmxWrapper(config);
- MBeanServer server = getMBeanServer(); // however you do it
- ObjectName on = new ObjectName("jboss.cache:service=TreeCache");
- server.registerMBean(wrapper, on);
-
- // Call to wrapper.create() will build the Cache if one wasn't injected
- wrapper.create();
- wrapper.start();
-
- // Now that it's built, created and started, get the cache from the wrapper
- Cache cache = wrapper.getCache();
-
- ... use the cache
-
- ... on application shutdown
-
- wrapper.stop();
- wrapper.destroy();
-
- </programlisting>
- </section>
-
- <section>
- <title>JMX-Based Deployment in JBoss AS (JBoss AS 4.x and 5.x)</title>
-
- <para>
- When you
- <link linkend="deployment.microkernel">deploy your cache in JBoss AS using a -service.xml file</link>
- ,
- a
- <literal>CacheJmxWrapper</literal>
- is automatically registered. There is no need
- to do anything further. The
- <literal>CacheJmxWrapper</literal>
- is accessible from an MBean server
- through the service name specified in the cache configuration file's
- <literal>mbean</literal>
- element.
- </para>
- </section>
-
- <section>
- <title>Via JBoss Microcontainer (JBoss AS 5.x)</title>
-
- <para>
- <literal>CacheJmxWrapper</literal>
- is a POJO, so the microcontainer
- has no problem creating one. The trick is
- getting it to register your bean in JMX. This can be done by
- specifying the
- <literal>org.jboss.aop.microcontainer.aspects.jmx.JMX</literal>
- annotation on the
- <literal>CacheJmxWrapper</literal>
- bean:
- </para>
-
- <programlisting>
- <![CDATA[
-<?xml version="1.0" encoding="UTF-8"?>
-
-<deployment xmlns="urn:jboss:bean-deployer:2.0">
-
- <!-- First we create a Configuration object for the cache -->
- <bean name="ExampleCacheConfig"
- class="org.jboss.cache.config.Configuration">
-
- ... build up the Configuration
-
- </bean>
-
- <!-- Factory to build the Cache. -->
- <bean name="DefaultCacheFactory" class="org.jboss.cache.DefaultCacheFactory">
- <constructor factoryClass="org.jboss.cache.DefaultCacheFactory"
- factoryMethod="getInstance"/>
- </bean>
-
- <!-- The cache itself -->
- <bean name="ExampleCache" class="org.jboss.cache.CacheImpl">
-
- <constructor factoryMethod="createnewInstance">
- <factory bean="DefaultCacheFactory"/>
- <parameter><inject bean="ExampleCacheConfig"/></parameter>
- <parameter>false</false>
- </constructor>
-
- </bean>
-
- <!-- JMX Management -->
- <bean name="ExampleCacheJmxWrapper" class="org.jboss.cache.jmx.CacheJmxWrapper">
-
- <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.cache:service=ExampleTreeCache",
- exposedInterface=org.jboss.cache.jmx.CacheJmxWrapperMBean.class,
- registerDirectly=true)</annotation>
-
- <constructor>
- <parameter><inject bean="ExampleCache"/></parameter>
- </constructor>
-
- </bean>
-
-</deployment>
-]]>
- </programlisting>
-
- <para>
- As discussed in the
- <link linkend="jmx.registration.programatic">Programatic Registration</link>
- section,
- <literal>CacheJmxWrapper</literal>
- can do the work of building,
- creating and starting the
- <literal>Cache</literal>
- if it is provided
- with a
- <literal>Configuration</literal>
- . With the microcontainer,
- this is the preferred approach, as it saves the boilerplate XML
- needed to create the
- <literal>CacheFactory</literal>
- :
- </para>
-
- <programlisting>
- <![CDATA[
-<?xml version="1.0" encoding="UTF-8"?>
-
-<deployment xmlns="urn:jboss:bean-deployer:2.0">
-
- <!-- First we create a Configuration object for the cache -->
- <bean name="ExampleCacheConfig"
- class="org.jboss.cache.config.Configuration">
-
- ... build up the Configuration
-
- </bean>
-
- <bean name="ExampleCache" class="org.jboss.cache.jmx.CacheJmxWrapper">
-
- <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.cache:service=ExampleTreeCache",
- exposedInterface=org.jboss.cache.jmx.CacheJmxWrapperMBean.class,
- registerDirectly=true)</annotation>
-
- <constructor>
- <parameter><inject bean="ExampleCacheConfig"/></parameter>
- </constructor>
-
- </bean>
-
-</deployment>
-]]>
- </programlisting>
- </section>
-
- </section>
-
- <section id="jmx.statistics">
- <title>JBoss Cache Statistics</title>
- <para>
- JBoss Cache captures statistics in its interceptors and exposes the statistics through interceptor
- MBeans. Gathering of statistics is enabled by default; this can be disabled for a specific cache
- instance through the
- <literal>ExposeManagementStatistics</literal>
- configuration attribute. Note that
- the majority of the statistics are provided by the
- <literal>CacheMgmtInterceptor</literal>
- ,
- so this MBean is the most significant in this regard. If you want to disable all statistics for performance
- reasons, you set
- <literal>ExposeManagementStatistics</literal>
- to
- <literal>false</literal>
- as this will
- prevent the
- <literal>CacheMgmtInterceptor</literal>
- from being included in the cache's interceptor stack
- when the cache is started.
- </para>
- <para>
- If a
- <literal>CacheJmxWrapper</literal>
- is registered with JMX, the wrapper also ensures that
- an MBean is registered in JMX for each interceptor that exposes statistics
- <footnote>
- <para>
- Note that if the
- <literal>CacheJmxWrapper</literal>
- is not registered in JMX, the
- interceptor MBeans will not be registered either. The JBoss Cache 1.4 releases
- included code that would try to "discover" an
- <literal>MBeanServer</literal>
- and
- automatically register the interceptor MBeans with it. For JBoss Cache 2.x we decided
- that this sort of "discovery" of the JMX environment was beyond the proper scope of
- a caching library, so we removed this functionality.
- </para>
- </footnote>
- .
- Management tools can then access those MBeans to examine the statistics. See the section in the
- <link linkend="jmx_reference.statistics">JMX Reference chapter</link>
- pertaining to the
- statistics that are made available via JMX.
- </para>
- <para>
- The name under which the interceptor MBeans will be registered is derived by taking the
- <literal>ObjectName</literal>
- under which the
- <literal>CacheJmxWrapper</literal>
- is
- registered and adding a
- <literal>cache-interceptor</literal>
- attribute key whose value
- is the non-qualified name of the interceptor class. So, for example, if the
- <literal>CacheJmxWrapper</literal>
- were registered under
- <literal>jboss.cache:service=TreeCache</literal>
- , the name of the
- <literal>CacheMgmtInterceptor</literal>
- MBean would be
- <literal>jboss.cache:service=TreeCache,cache-interceptor=CacheMgmtInterceptor</literal>
- .
- </para>
- <para>
- Each interceptor's MBean exposes a
- <literal>StatisticsEnabled</literal>
- attribute that can be used to disable maintenance of statistics for
- that interceptor. In addition, each interceptor MBean provides the following common operations and
- attributes.
- <itemizedlist>
- <listitem>
- <literal>dumpStatistics</literal>
- - returns a
- <literal>Map</literal>
- containing the interceptor's attributes and values.
- </listitem>
- <listitem>
- <literal>resetStatistics</literal>
- - resets all statistics maintained by the interceptor.
- </listitem>
- <listitem>
- <literal>setStatisticsEnabled(boolean)</literal>
- - allows statistics to be disabled for a specific interceptor.
- </listitem>
- </itemizedlist>
- </para>
- <para>
- </para>
- </section>
-
- <section>
- <title>Receiving JMX Notifications</title>
- <para>
- JBoss Cache users can register a listener to receive cache events described earlier in the
- <link linkend="api.listener">User API</link>
- chapter. Users can alternatively utilize the cache's management information infrastructure to receive these
- events
- via JMX notifications. Cache events are accessible as notifications by registering a
- <literal>NotificationListener</literal>
- for the
- <literal>CacheJmxWrapper</literal>
- .
- </para>
-
- <para>
- See the section in the
- <link linkend="jmx_reference.notifications">JMX Reference chapter</link>
- pertaining
- to JMX notifications for a list of notifications that can be received through the
- <literal>CacheJmxWrapper</literal>
- .
- </para>
-
-
- <para>
- The following is an example of how to programmatically receive cache notifications when running in a
- JBoss AS environment. In this example, the client uses a filter to specify which events are of interest.
- </para>
-
- <programlisting>
- <![CDATA[
- MyListener listener = new MyListener();
- NotificationFilterSupport filter = null;
-
- // get reference to MBean server
- Context ic = new InitialContext();
- MBeanServerConnection server = (MBeanServerConnection)ic.lookup("jmx/invoker/RMIAdaptor");
-
- // get reference to CacheMgmtInterceptor MBean
- String cache_service = "jboss.cache:service=TomcatClusteringCache";
- ObjectName mgmt_name = new ObjectName(cache_service);
-
- // configure a filter to only receive node created and removed events
- filter = new NotificationFilterSupport();
- filter.disableAllTypes();
- filter.enableType(CacheNotificationBroadcaster.NOTIF_NODE_CREATED);
- filter.enableType(CacheNotificationBroadcaster.NOTIF_NODE_REMOVED);
-
- // register the listener with a filter
- // leave the filter null to receive all cache events
- server.addNotificationListener(mgmt_name, listener, filter, null);
-
- // ...
-
- // on completion of processing, unregister the listener
- server.removeNotificationListener(mgmt_name, listener, filter, null);
- ]]>
- </programlisting>
-
- <para>The following is the simple notification listener implementation used in the previous example.</para>
- <programlisting>
- <![CDATA[
- private class MyListener implements NotificationListener, Serializable
- {
- public void handleNotification(Notification notification, Object handback)
- {
- String message = notification.getMessage();
- String type = notification.getType();
- Object userData = notification.getUserData();
-
- System.out.println(type + ": " + message);
-
- if (userData == null)
- {
- System.out.println("notification data is null");
- }
- else if (userData instanceof String)
- {
- System.out.println("notification data: " + (String) userData);
- }
- else if (userData instanceof Object[])
- {
- Object[] ud = (Object[]) userData;
- for (Object data : ud)
- {
- System.out.println("notification data: " + data.toString());
- }
- }
- else
- {
- System.out.println("notification data class: " + userData.getClass().getName());
- }
- }
- }
- ]]>
- </programlisting>
-
- <para>Note that the JBoss Cache management implementation only listens to cache events after a client registers
- to receive MBean notifications. As soon as no clients are registered for notifications, the MBean will
- remove
- itself as a cache listener.
- </para>
-
- </section>
-
- <section>
- <title>Accessing Cache MBeans in a Standalone Environment</title>
- <para>
- JBoss Cache MBeans are easily accessed when running cache instances in an application server that
- provides an MBean server interface such as JBoss JMX Console. Refer to your server documentation
- for instructions on how to access MBeans running in a server's MBean container.
- </para>
- <para>
- In addition, though, JBoss Cache MBeans are also accessible when running in a non-server environment if the
- JVM is JDK 5.0 or later. When running a standalone cache in a JDK 5.0 environment, you can access the
- cache's MBeans as follows.
- </para>
- <para>
- <orderedlist>
- <listitem>
- Set the system property
- <literal>-Dcom.sun.management.jmxremote</literal>
- when starting the JVM
- where the cache will run.
- </listitem>
- <listitem>
- Once the JVM is running, start the JDK 5.0
- <literal>jconsole</literal>
- utility, located in your JDK's
- <literal>/bin</literal>
- directory.
- </listitem>
- <listitem>When the utility loads, you will be able to select your running JVM and connect to it. The
- JBoss Cache
- MBeans will be available on the MBeans panel.
- </listitem>
- </orderedlist>
- </para>
- <para>Note that the
- <literal>jconsole</literal>
- utility will automatically register as a listener for cache notifications when
- connected to a JVM running JBoss Cache instances.
- </para>
-
- <para>The following figure shows cache interceptor MBeans in
- <literal>jconsole</literal>
- . Cache statistics are displayed
- for the
- <literal>CacheMgmtInterceptor</literal>
- :
- </para>
-
- <figure>
- <title>CacheMgmtInterceptor MBean in jconsole</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="CacheMgmtInterceptor.png"/>
- </imageobject>
- </mediaobject>
- </figure>
-
- </section>
- </section>
-</chapter>
Deleted: pojo/trunk/src/main/docbook/userguide/en/modules/eviction_policies.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/eviction_policies.xml 2007-08-14 16:34:22 UTC (rev 4250)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/eviction_policies.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -1,537 +0,0 @@
-<chapter id="eviction_policies">
- <title>Eviction Policies</title>
-
- <para>
- Eviction policies control JBoss Cache's memory management by managing how many nodes are allowed to be stored in
- memory and their life spans. Memory constraints on servers mean cache cannot grow indefinitely, so policies
- need to be in place to restrict the size of the cache. Eviction policies are most often used alongside
- <link linkend="cache_loaders">cache loaders</link>
- .
- </para>
-
- <section>
- <title>Configuring Eviction Policies</title>
- <section>
- <title>Basic Configuration</title>
- <para>
- The basic eviction policy configuration element looks like:
- <programlisting>
- <![CDATA[
-
- ...
-
- <attribute name="EvictionConfig">
- <config>
- <attribute name="wakeUpIntervalSeconds">3</attribute>
-
- <!-- This defaults to 200000 if not specified -->
- <attribute name="eventQueueSize">100000</attribute>
-
- <!-- Name of the DEFAULT eviction policy class. -->
- <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
-
- <!-- Cache wide default -->
- <region name="/_default_">
- <attribute name="maxNodes">100</attribute>
- </region>
-
- <!-- override policy used for this region -->
- <region name="/org/jboss/data" policyClass="org.jboss.cache.eviction.MRUPolicy">
- <attribute name="maxNodes">250</attribute>
- </region>
-
- <!-- We expect a lot of events for this region,
- so override the default event queue size -->
- <region name="/org/jboss/test/data" eventQueueSize="500000">
- <attribute name="maxNodes">60000</attribute>
- </region>
-
- </config>
- </attribute>
-
- ...
-]]>
- </programlisting>
-
- <itemizedlist>
- <listitem>
- <literal>wakeUpIntervalSeconds</literal>
- - this required parameter defines how often the eviction thread runs
- </listitem>
- <listitem>
- <literal>eventQueueSize</literal>
- - this optional parameter defines the size of the queue which holds eviction events. If your eviction
- thread does not run often enough, you may need to increase this. This can be overridden on a
- per-region basis.
- </listitem>
- <listitem>
- <literal>policyClass</literal>
- - this is required, unless you set individual policyClass attributes on each and every region. This
- defines the eviction policy to use if one is not defined for a region.
- </listitem>
- </itemizedlist>
-
- </para>
- </section>
- <section>
- <title>Eviction Regions</title>
- <para>
- The concept of regions and the
- <literal>Region</literal>
- class were
- <link linkend="architecture.regions">visited earlier</link>
- when talking about marshalling. Regions also have another use, in that they are used to define the eviction
- policy used within the region. In addition to using a region-specific configuration, you can also configure
- a default, cache-wide eviction policy for nodes that do not fall into predefined regions or if you do not
- wish to define specific regions. It is important to note that when defining regions using the configuration
- XML file, all elements of the
- <literal>Fqn</literal>
- that defines the region are
- <literal>java.lang.String</literal>
- objects.
- </para>
- <para>
- Looking at the eviction configuration snippet above, we see that a default region,
- <literal>_default_</literal>
- , holds attributes
- which apply to nodes that do not fall into any of the other regions defined.
- </para>
- <para>
- For each region, you can define parameters which affect how the policy which applies to the region chooses
- to evict nodes.
- In the example above, the
- <literal>LRUPolicy</literal>
- allows a
- <literal>maxNodes</literal>
- parameter which defines
- how many nodes can exist in the region before it chooses to start evicting nodes. See the javadocs for each
- policy for a list of allowed parameters.
- </para>
-
- <section>
- <title>Overlapping Eviction Regions</title>
-
- <para>It's possible to define regions that overlap. In other words, one region can be defined for
- <emphasis>/a/b/c</emphasis>
- , and another
- defined for
- <emphasis>/a/b/c/d</emphasis>
- (which is just the
- <emphasis>d</emphasis>
- subtree of the
- <emphasis>/a/b/c</emphasis>
- sub-tree).
- The algorithm, in order to handle scenarios like this consistently, will always choose the first region
- it encounters.
- In this way, if the algorithm needed to decide how to handle
- <emphasis>/a/b/c/d/e</emphasis>
- , it would start from there and work
- its way up the tree until it hits the first defined region - in this case
- <emphasis>/a/b/c/d</emphasis>
- .
- </para>
- </section>
-
- </section>
- <section>
- <title>Programmatic Configuration</title>
- <para>
- Configuring eviction using the
- <literal>Configuration</literal>
- object entails the use of the
- <literal>org.jboss.cache.config.EvictionConfig</literal>
- bean, which is passed into
- <literal>Configuration.setEvictionConfig()</literal>
- . See the
- <link linkend="configuration">chapter on Configuration</link>
- for more on building a
- <literal>Configuration</literal>
- programatically.
- </para>
-
- <para>
- The use of simple POJO beans to represent all elements in a
- cache's configuration also makes it fairly easy to programatically
- add eviction regions after the cache is started . For example,
- assume we had an existing cache configured via XML with the
- EvictionConfig element shown above. Now at runtime we wished to
- add a new eviction region named "/org/jboss/fifo", using
- <literal>LRUPolicy</literal>
- but a different number of
- <literal>maxNodes</literal>
- :
- </para>
-
- <programlisting>
- Fqn fqn = Fqn.fromString("/org/jboss/fifo");
-
- // Create a configuration for an LRUPolicy
- LRUConfiguration lruc = new LRUConfiguration();
- lruc.setMaxNodes(10000);
-
- // Create the region and set the config
- Region region = cache.getRegion(fqn, true);
- region.setEvictionPolicy(lruc);
- </programlisting>
- </section>
- </section>
-
- <section>
- <title>Shipped Eviction Policies</title>
- <section>
- <title>LRUPolicy - Least Recently Used</title>
-
- <para>
- <literal>org.jboss.cache.eviction.LRUPolicy</literal>
- controls both the node lifetime and age. This policy guarantees a constant order (
- <literal>O (1)</literal>
- ) for
- adds, removals and lookups (visits). It has the following configuration
- parameters:
- </para>
-
- <itemizedlist>
- <listitem>
- <literal>maxNodes</literal>
- - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
- </listitem>
- <listitem>
- <literal>timeToLiveSeconds</literal>
- - The amount of time a node is not written to or read (in seconds) before the node is swept away. 0
- denotes no limit.
- </listitem>
-
- <listitem>
- <literal>maxAgeSeconds</literal>
- - Lifespan of a node (in seconds) regardless of idle time before the node is swept away. 0 denotes no
- limit.
- </listitem>
- </itemizedlist>
- </section>
-
- <section>
- <title>FIFOPolicy - First In, First Out</title>
-
- <para>
- <literal>org.jboss.cache.eviction.FIFOPolicy</literal>
- controls the eviction in a proper first in first out order. This policy
- guarantees a constant order (
- <literal>O (1)</literal>
- ) for adds, removals and lookups (visits). It has the
- following configuration parameters:
- </para>
-
- <itemizedlist>
- <listitem>
- <literal>maxNodes</literal>
- - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
- </listitem>
- </itemizedlist>
- </section>
-
-
- <section>
- <title>MRUPolicy - Most Recently Used</title>
-
- <para>
- <literal>org.jboss.cache.eviction.MRUPolicy</literal>
- controls
- the eviction in based on most recently used algorithm. The most recently
- used nodes will be the first to evict with this policy. This policy
- guarantees a constant order (
- <literal>O (1)</literal>
- ) for adds, removals and lookups (visits). It has the
- following configuration parameters:
- </para>
-
- <itemizedlist>
- <listitem>
- <literal>maxNodes</literal>
- - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
- </listitem>
- </itemizedlist>
- </section>
-
- <section>
- <title>LFUPolicy - Least Frequently Used</title>
-
- <para>
- <literal>org.jboss.cache.eviction.LFUPolicy</literal>
- controls
- the eviction in based on least frequently used algorithm. The least
- frequently used nodes will be the first to evict with this policy. Node
- usage starts at 1 when a node is first added. Each time it is visted,
- the node usage counter increments by 1. This number is used to determine
- which nodes are least frequently used. LFU is also a sorted eviction
- algorithm. The underlying EvictionQueue implementation and algorithm is
- sorted in ascending order of the node visits counter. This class
- guarantees a constant order (
- <literal>O (1)</literal>
- ) for adds, removal and searches. However, when any
- number of nodes are added/visited to the queue for a given processing
- pass, a single quasilinear (
- <literal>O (n * log n)</literal>
- ) operation is used to resort the queue in
- proper LFU order. Similarly if any nodes are removed or evicted, a
- single linear (
- <literal>O (n)</literal>
- ) pruning operation is necessary to clean up the
- EvictionQueue. LFU has the following configuration parameters:
- </para>
-
- <itemizedlist>
- <listitem>
- <literal>maxNodes</literal>
- - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
- </listitem>
- <listitem>
- <literal>minNodes</literal>
- - This is the minimum number of nodes allowed in this region. This value determines what
- the eviction queue should prune down to per pass. e.g. If
- minNodes is 10 and the cache grows to 100 nodes, the cache is
- pruned down to the 10 most frequently used nodes when the
- eviction timer makes a pass through the eviction
- algorithm.
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section>
- <title>ExpirationPolicy</title>
-
- <para>
- <literal>org.jboss.cache.eviction.ExpirationPolicy</literal>
- is a policy
- that evicts nodes based on an absolute expiration time. The
- expiration time is indicated using the
- <literal>org.jboss.cache.Node.put()</literal>
- method, using a String key
- <literal>expiration</literal>
- and the absolute time as a
- <literal>java.lang.Long</literal>
- object, with a value indicated as milliseconds past midnight
- January 1st, 1970 UTC (the same relative time as provided by
- <literal>java.lang.System.currentTimeMillis()</literal>
- ).
- </para>
-
- <para>
- This policy guarantees a constant order (
- <literal>O (1)</literal>
- ) for adds and removals.
- Internally, a sorted set (TreeSet) containing the expiration
- time and Fqn of the nodes is stored, which essentially
- functions as a heap.
- </para>
-
- <para>
- This policy has the following configuration parameters:
- </para>
-
- <itemizedlist>
- <listitem>
- <literal>expirationKeyName</literal>
- - This is the Node key name used
- in the eviction algorithm. The configuration default is
- <literal>expiration</literal>
- .
- </listitem>
- <listitem>
- <literal>maxNodes</literal>
- - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
- </listitem>
-
- </itemizedlist>
-
- <para>
- The following listing shows how the expiration date is indicated and how the
- policy is applied:
- <programlisting>
- <![CDATA[
- Cache cache = DefaultCacheFactory.createCache();
- Fqn fqn1 = Fqn.fromString("/node/1");
- Long future = new Long(System.currentTimeMillis() + 2000);
-
- // sets the expiry time for a node
- cache.getRoot().addChild(fqn1).put(ExpirationConfiguration.EXPIRATION_KEY, future);
-
- assertTrue(cache.getRoot().hasChild(fqn1));
- Thread.sleep(5000);
-
- // after 5 seconds, expiration completes
- assertFalse(cache.getRoot().hasChild(fqn1));
-]]>
- </programlisting>
- Note that the expiration time of nodes is only checked when the
- region manager wakes up every
- <literal>wakeUpIntervalSeconds</literal>
- , so eviction
- may happen a few seconds later than indicated.
- </para>
- </section>
- <section>
- <title>ElementSizePolicy - Eviction based on number of key/value pairs in a node</title>
-
- <para>
- <literal>org.jboss.cache.eviction.ElementSizePolicy</literal>
- controls
- the eviction in based on the number of key/value pairs in the node. Nodes The most recently
- used nodes will be the first to evict with this policy. It has the following configuration parameters:
- </para>
-
- <itemizedlist>
- <listitem>
- <literal>maxNodes</literal>
- - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
- </listitem>
- <listitem>
- <literal>maxElementsPerNode</literal>
- - This is the trigger number of attributes per node for the node to be selected for eviction. 0 denotes
- no limit.
- </listitem>
- </itemizedlist>
- </section>
- </section>
-
- <section>
- <title>Writing Your Own Eviction Policies</title>
- <section>
- <title>Eviction Policy Plugin Design</title>
-
- <para>The design of the JBoss Cache eviction policy framework is based
- on an
- <literal>EvictionInterceptor</literal>
- to handle cache events and relay them back to the eviction
- policies. During the cache start up, an
- <literal>EvictionInterceptor</literal>
- will be added to the cache
- interceptor stack if the eviction policy is specified.
- Then whenever a node is added, removed, evicted, or visited, the
- <literal>EvictionInterceptor</literal>
- will maintain state statistics and
- information will be relayed to each individual eviction region.
- </para>
-
- <para>
- There is a single eviction thread (timer) that will run at a
- configured interval. This thread will make calls into each of the policy
- providers and inform it of any aggregated adds,
- removes and visits (gets) events to the cache during the configured interval.
- The eviction thread is responsible for kicking off the eviction policy
- processing (a single pass) for each configured eviction cache
- region.
- </para>
- </section>
-
- <section>
- <title>Interfaces to implement</title>
- <para>In order to implement an eviction policy, the following interfaces
- must be implemented:
- <itemizedlist>
- <listitem>
- <literal>org.jboss.cache.eviction.EvictionPolicy</literal>
- </listitem>
- <listitem>
- <literal>org.jboss.cache.eviction.EvictionAlgorithm</literal>
- </listitem>
- <listitem>
- <literal>org.jboss.cache.eviction.EvictionQueue</literal>
- </listitem>
- <listitem>
- <literal>org.jboss.cache.config.EvictionPolicyConfig</literal>
- </listitem>
- </itemizedlist>
- When compounded
- together, each of these interface implementations define all the
- underlying mechanics necessary for a complete eviction policy
- implementation.
- </para>
-
- <para>
- <emphasis>Note that:</emphasis>
- </para>
-
- <itemizedlist>
- <listitem>
- <para>The
- <literal>EvictionPolicyConfig</literal>
- implementation
- should maintain
- getter and setter methods for whatever configuration properties
- the policy supports (e.g. for
- <literal>LRUConfiguration</literal>
- among others there is a
- <literal>int getMaxNodes()</literal>
- and a
- <literal>setMaxNodes(int)</literal>
- ). When the "EvictionConfig" section of an XML configuration
- is parsed, these properties will be set by reflection.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>Alternatively, the implementation of a new eviction policy
- provider can be simplified by extending
- <literal>BaseEvictionPolicy</literal>
- and
- <literal>BaseEvictionAlgorithm</literal>
- . Or for properly sorted EvictionAlgorithms (sorted
- in eviction order - see
- <literal>LFUAlgorithm</literal>
- ) extending
- <literal>BaseSortedEvictionAlgorithm</literal>
- and implementing
- <literal>SortedEvictionQueue</literal>
- takes
- care of most of the common functionality available in a set of eviction
- policy provider classes
- </para>
-
-
- <para>
- <emphasis>Note that:</emphasis>
- </para>
-
- <itemizedlist>
- <listitem>
- <para>The
- <literal>BaseEvictionAlgorithm</literal>
- class maintains a processing
- structure. It will process the ADD, REMOVE, and VISIT events queued
- by the region first. It also maintains an collection of
- items that were not properly evicted during the last go around
- because of held locks. That list is pruned. Finally, the
- EvictionQueue itself is pruned for entries that should be evicted
- based upon the configured eviction rules for the region.
- </para>
- </listitem>
- <listitem>
- <para>The
- <literal>BaseSortedEvictionAlgorithm</literal>
- class will maintain a boolean
- through the algorithm processing that will determine if any new
- nodes were added or visited. This allows the Algorithm to determine
- whether to resort the eviction queue items (in first to evict order)
- or to skip the potentially expensive sorting if there have been no
- changes to the cache in this region.
- </para>
- </listitem>
- <listitem>
- <para>The
- <literal>SortedEvictionQueue</literal>
- interface defines the contract used by
- the
- <literal>BaseSortedEvictionAlgorithm</literal>
- abstract class that is used to
- resort the underlying queue. Again, the queue sorting should be
- sorted in first to evict order. The first entry in the list should
- evict before the last entry in the queue. The last entry in the
- queue should be the last entry that will require eviction.
- </para>
- </listitem>
- </itemizedlist>
- </section>
- </section>
-</chapter>
\ No newline at end of file
Added: pojo/trunk/src/main/docbook/userguide/en/modules/example.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/example.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/example.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -0,0 +1,7 @@
+<chapter id="example">
+
+ <title>Example</title>
+
+
+
+</chapter>
\ No newline at end of file
Property changes on: pojo/trunk/src/main/docbook/userguide/en/modules/example.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: pojo/trunk/src/main/docbook/userguide/en/modules/instrumentation.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/instrumentation.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/instrumentation.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -0,0 +1,320 @@
+<chapter id="instrumentation">
+
+ <title>Instrumentation</title>
+
+ <para>In this chapter, we explain how to instrument (or "aspectize") the
+ POJOs via JBoss Aop. There are two steps needed by JBoss Aop: 1) POJO
+ declaration, 2) instrumentation. But depends on the instrumentation
+ mode that you are using, you may not need to pre-process your POJO at all. That is,
+ if you use JDK5.0 (required) and load-time mode, then all you need to do is
+ annotating your POJO (or declare it in a xml file). This makes your PojoCache
+ programming nearly transparent.</para>
+
+ <para>For the first step, since we are using the dynamic Aop feature, a
+ POJO is only required to be declared "prepare". Basically, there are two
+ ways to do this: either via explicit xml or annotation.</para>
+
+ <para>As for the second step, either we can ask JBoss Aop to do load-time
+ (through a special class loader, so-called load-time mode) or compile-time
+ instrumentation (use of an aopc pre-compiler, so-called precompiled
+ mode). Reader can read the JBoss Aop introduction chapter for more details.</para>
+
+ <sect1>
+ <title>XML descriptor</title>
+
+ <para>To declare a POJO via XML configuration file, you will need a
+ <literal>META-INF/jboss-aop.xml</literal> (or in the PojoCache case, it is
+ the equivalent <literal>pojocache-service.xml</literal>
+ file located under the class
+ path or listed in the <literal>jboss.aop.path</literal> system
+ property. JBoss AOP framework will read this file during startup to make
+ necessary byte code manipulation for advice and introduction. Or you
+ can pre-compile it using a pre-compiler called
+ <literal>aopc</literal>
+ such that you won't need the XML file during load time. JBoss Aop
+ provides a so-called
+ <literal>pointcut</literal>
+ language where it
+ consists of a regular expression set to specify the interception
+ points (or
+ <literal>jointpoint</literal>
+ in aop parlance). The
+ jointpoint can be constructor, method call, or field. You will need to
+ declare any of your POJO to be "prepared" so that AOP framework knows
+ to start intercepting either method, field, or constructor invocations
+ using the dynamic Aop.
+ </para>
+
+ <para>For PojoCache, we only allow all the
+ fields (both read and write) to be intercepted. That is, we don't care
+ for the method level interception since it is the state that we are
+ interested in. So you should
+ only need to change your POJO class name. For details of the pointcut
+ language, please refer to JBoss Aop.</para>
+
+ <para>The standalone
+ <literal>JBoss Cache</literal>
+ distribution
+ package provides an example declaration for the tutorial classes,
+ namely,
+ <literal>Person</literal>
+ and
+ <literal>Address</literal>
+ .
+ Detailed class declaration for
+ <literal>Person</literal>
+ and
+ <literal>Address</literal>
+ are provided in the Appendix section. But here
+ is the snippet for
+ <literal>pojocache-aop.xml</literal>
+ :
+ </para>
+
+<programlisting>
+<aop>
+ <prepare expr="field(* $instanceof{(a)org.jboss.cache.pojo.annotation.Replicable}->*)" />
+</aop>
+</programlisting>
+ and then notice the annotation @Replicable used in the <literal>Person</literal> and
+ <literal>Address</literal> POJOs. Also note that @Replicable is now inheritant. For example,
+ sub-class of <literal>Person</literal> such as <literal>Student</literal> will also
+ be aspectized by JBoss Aop as well. If you want to stop this inheritance behavior,
+ you can simply remove the
+ <literal>$instanceof</literal> declaration in the prepare statement, e.g.,
+ <programlisting>
+ <aop>
+ <prepare expr="field(* @org.jboss.cache.pojo.annotation.Replicable->*)" />
+ </aop>
+ </programlisting>
+
+
+ <para>Detailed semantics of
+ <literal>pojocache-aop.xml</literal> (or equivalently <literal>pojocache-aop.xml</literal>)
+ can again
+ be found in JBoss Aop. But above statements basically declare all field
+ read and write operations in classes
+ <code>Address</code>
+ and
+ <code>Person</code>
+ will be "prepared" (or "aspectized"). Note
+ that:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ The wildcard at the end of the expression signifies all fields in the POJO
+ </listitem>
+
+ <listitem>
+ You can potentially replace specific class name with wildcard that includes all the POJOs inside the
+ same package space
+ </listitem>
+
+ <listitem>
+ The
+
+ <code>instanceof</code>
+
+ operator declares any sub-type or sub-class of the specific POJO will also be "aspectized". For
+ example, if a
+ <code>Student</code>
+ class is a subclass of
+ <code>Person</code>
+ , JBossAop will automatically instrument it as well!
+ </listitem>
+
+ <listitem>
+ We intercept the field of all access levels (i.e.,
+ <literal>private</literal>
+ ,
+ <literal>protected</literal>
+ ,
+ <literal>public</literal>
+ , etc.) The main reason being that we consider all fields as stateful data. However, we can relax this
+ requirement in the future if there is a use case for it.
+ </listitem>
+
+ <listitem>
+ We don't intercept field modifiers of
+ <literal>final</literal>
+ and
+ <literal>transient</literal>
+ though. That is, field with these modifiers are not stored in cache and is not replicated either. If
+ you don't want your field to be managed by the cache, you can declare them with these modifiers, e.g.,
+ transient.
+ </listitem>
+ </itemizedlist>
+ </sect1>
+
+ <sect1>
+ <title>Annotation</title>
+ <para>Annotation is a new feature in Java 5.0 that when declared can
+ contain metadata at compile and run time. It is well suited for aop
+ declaration since there will be no need for external metadata xml
+ descriptor.</para>
+
+ <sect2>
+ <title>POJO annotation for instrumentation</title>
+ <para>To support annotation (in order to
+ simplify user's development effort), the JBoss Cache distribution ships with a
+ <literal>pojocache-aop.xml</literal>
+ under the
+ <literal>resources</literal>
+ directory. For
+ reference, here is annotation definition from
+ <literal>pojocache-aop.xml</literal> again
+ :
+<programlisting>
+<aop>
+ <prepare expr="field(* @org.jboss.cache.pojo.annotation.Replicable->*)" />
+</aop>
+</programlisting>
+ Basically, it simply states that any annotation
+ with both marker interfaces will be "aspectized" accordingly.
+ </para>
+
+
+ <para>Here is a code snippet that illustrate the declaration:</para>
+<programlisting>
+(a)org.jboss.cache.pojo.annotation.Replicable
+public class Person {...}
+</programlisting>
+The above declaration will instrument the class <literal>Person</literal> and all of its sub-classes. That is, if
+<literal>Student</literal> sub-class from <literal>Personal</literal>, then it will get instrumented automatically without
+ further annotation declaration.
+ </sect2>
+
+ <sect2>
+ <title>JDK5.0 field level annotations</title>
+ <para>In Release 2.0, we have added two additional field level annotations for customized behavior.
+ The first one is <code>@org.jboss.cache.pojo.annotation.Transient</code>. When applied to a field
+ variable, it has the same effect as the Java language <code>transient</code> keyword. That is, PojoCache
+ won't put this field into cache management (and therefore no replication).
+ </para>
+ <para>
+ The second one is <code>@org.jboss.cache.pojo.annotation.Serializable</code>, when applied to a field
+ variable, PojoCache will treat this variable as <code>Serializable</code>, even when it is
+ <code>Replicable</code>. However, the field will need to implement the <code>Serializable</code>
+ interface such that it can be replicated.
+ </para>
+ <para>Here is a code snippet that illustrates usage of these two annotations.
+ Assuming that you have a Gadget class:
+<programlisting>
+public class Gadget
+{
+ // resource won't be replicated
+ @Transient Resource resource;
+ // specialAddress is treated as a Serializable object but still has object relationship
+ @Serializable SpecialAddress specialAddress;
+ // other state variables
+}
+</programlisting>
+ Then when we do:
+<programlisting>
+ Gadget gadget = new Gadget();
+ Resource resource = new Resource();
+ SepcialAddress specialAddress = new SpecialAddress();
+
+ // setters
+ gadget.setResource(resource);
+ gadget.setSpecialAddress(specialAddress);
+
+ cache1.putObject("/gadget", gadget); // put into PojoCache management
+
+ Gadget g2 = (Gadget)cache2.getObject("/gadget"); // retrieve it from another cache instance
+ g2.getResource(); // This is should be null because of @Transient tag so it is not replicated.
+
+ SepcialAddress d2 = g2.getSpecialAddress();
+ d2.setName("inet"); // This won't get replicated automatically because of @Serializable tag
+ ge.setSpecialAddress(d2); // Now this will.
+</programlisting>
+ </para>
+ </sect2>
+
+ </sect1>
+
+ <sect1>
+ <title>Weaving</title>
+
+ <para>As already mentioned, a user can use the aop precompiler
+ (<literal>aopc</literal>) to precompile the POJO classes such that,
+ during runtime, there is no additional system class loader needed. The
+ precompiler will read in
+ <literal>pojocache-aop.xml</literal>
+ and weave
+ the POJO byte code at compile time. This is a convenient feature to
+ make the aop less intrusive.
+ </para>
+ <para>
+ Below is an Ant snippet that defines the library needed for the various Ant targets that we are
+ listing here. User can refer to the <literal>build.xml</literal> in the distribution for full details.
+<programlisting>
+ <path id="aop.classpath"/>
+ <fileset dir="${lib}"/>
+ <include name="**/*.jar" //>
+ <exclude name="**/jboss-cache.jar" //>
+ <exclude name="**/j*unit.jar" //>
+ <exclude name="**/bsh*.jar" //>
+ </fileset/>
+ </path/>
+</programlisting>
+ </para>
+
+ <sect2>
+ <title>Ant target for running load-time instrumentation using specialized class loader</title>
+ <para>
+ In JDK5.0, you can use the <code>javaagent</code> option that does not require a
+ separate Classloader. Here are the ant snippet from <code>one-test-pojo</code>, for example.
+<programlisting>
+ <target name="one.test.pojo" depends="compile" description="run one junit test case.">
+ <junit printsummary="yes" timeout="${junit.timeout}" fork="yes">
+ <jvmarg value="-Djboss.aop.path=${output}/resources/pojocache-aop.xml"/>
+ <jvmarg value="-javaagent:${lib}/jboss-aop-jdk50.jar"/>
+ <classpath path="${output}/etc" />
+ <sysproperty key="log4j.configuration" value="file:${output}/etc/log4j.xml" />
+ <classpath refid="lib.classpath"/>
+ <classpath refid="build.classpath"/>
+ <formatter type="xml" usefile="true"/>
+ <test name="${test}" todir="${reports}"/>
+ </junit>
+ </target>
+</programlisting>
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Ant target for aopc</title>
+ <para>Below is the code snippet for the <literal>aopc</literal> Ant target. Running this target will do
+ compile-time weaving of the POJO classes specified.</para>
+<programlisting>
+ <taskdef name="aopc" classname="org.jboss.aop.ant.AopC" classpathref="aop.classpath"/>
+ <target name="aopc" depends="compile" description="Precompile aop class">
+ <aopc compilerclasspathref="aop.classpath" verbose="true">
+ <src path="${build}"/>
+ <include name="org/jboss/cache/aop/test/**/*.class"/>
+ <aoppath path="${output}/resources/pojocache-aop.xml"/>
+ <classpath path="${build}"/>
+ <classpath refid="lib.classpath"/>
+ </aopc>
+ </target>
+</programlisting>
+ <para>
+ Below is a snapshot of files that are generated when aopc is applied. Notice that couple extra classes have
+ been generated because of <literal>aopc</literal>.
+ </para>
+ <figure>
+ <title>Classes generated after aopc</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/classes.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ </sect2>
+ </sect1>
+
+
+</chapter>
Property changes on: pojo/trunk/src/main/docbook/userguide/en/modules/instrumentation.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: pojo/trunk/src/main/docbook/userguide/en/modules/introduction.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/introduction.xml 2007-08-14 16:34:22 UTC (rev 4250)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/introduction.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter id="introduction">
- <title>Overview</title>
-
- <section>
- <title>What is JBoss Cache?</title>
-
- <para>
- JBoss Cache is a tree-structured, clustered, transactional cache. It is
- the backbone for many fundamental JBoss Application Server clustering services, including - in certain
- versions - clustering JNDI, HTTP and EJB sessions.
- </para>
- <para>
- JBoss Cache can also be used as a standalone transactional and clustered caching library or even an object
- oriented data store. It can even be embedded in other enterprise Java frameworks and application servers
- such as BEA WebLogic or IBM WebSphere, Tomcat, Spring, Hibernate, and many others. It is also very commonly
- used directly by standalone Java applications that do not run from within an application server, to maintain
- clustered state.
- </para>
- <section>
- <title>And what is Pojo Cache?</title>
- <para>
- Pojo Cache is an extension of the core JBoss Cache API. Pojo Cache offers additional functionality such as:
- <itemizedlist>
- <listitem>maintaining object references even after replication or persistence.</listitem>
- <listitem>fine grained replication, where only modified object fields are replicated.</listitem>
- <listitem>"API-less" clustering model where pojos are simply annotated as being clustered.</listitem>
- </itemizedlist>
- </para>
- <para>
- Pojo Cache has a complete and separate set of documentation, including a user guide, FAQ and tutorial and
- as such, Pojo Cache is not discussed further in this book.
- </para>
- </section>
-
- </section>
-
- <section>
- <title>Summary of Features</title>
-
- <para>
- JBoss Cache offers a simple and straightforward API, where data (simple Java objects) can be placed in the
- cache and, based on configuration options selected, this data may be one or all of:
- <itemizedlist>
- <listitem>replicated to some or all cache instances in a cluster.</listitem>
- <listitem>persisted to disk and/or a remote cluster ("far-cache").</listitem>
- <listitem>garbage collected from memory when memory runs low, and passivated to disk so state isn't lost.
- </listitem>
- </itemizedlist>
- In addition, JBoss Cache offers a rich set of enterprise-class features:
- <itemizedlist>
- <listitem>being able to participate in JTA transactions (works with Java EE compliant TransactionManagers).
- </listitem>
- <listitem>attach to JMX servers and provide runtime statistics on the state of the cache.</listitem>
- <listitem>allow client code to attach listeners and receive notifications on cache events.</listitem>
- </itemizedlist>
- </para>
-
- <para>A cache is organised as a tree, with a single root. Each node in the tree essentially contains a Map,
- which acts as a store for key/value pairs. The only requirement placed on objects that are cached is that
- they implement
- <literal>java.io.Serializable</literal>
- . Note that this requirement does not exist for Pojo Cache.
- </para>
-
- <para>JBoss Cache
- can be either local or replicated. Local trees exist
- only inside the JVM in which they are created, whereas replicated trees
- propagate any changes to some or all other trees in the same cluster. A
- cluster may span different hosts on a network or just different JVMs
- on a single host.
- </para>
-
- <para>When a change is made to an object in the cache and that change is done in
- the context of a transaction, the replication of changes is deferred until the transaction
- commits successfully. All modifications are kept in a list associated with
- the transaction for the caller. When the transaction commits, we replicate the
- changes. Otherwise, (on a rollback) we simply undo the changes locally
- resulting in zero network traffic and overhead. For example, if a caller
- makes 100 modifications and then rolls back the transaction, we will not replicate
- anything, resulting in no network traffic.
- </para>
-
- <para>If a caller has no transaction associated with it (and isolation level is not
- NONE - more about this later), we will replicate right after each modification, e.g. in the above
- case we would send 100 messages, plus an additional message for the
- rollback. In this sense, running without a transaction can be thought of as analogous as running with
- auto-commit switched on in JDBC terminology, where each operation is committed automatically.
- </para>
-
- <para>
- JBoss Cache works out of the box with most popular transaction managers, and even provides an API where
- custom transaction manager lookups can be written.
- </para>
-
- <para>
- The cache is also completely thread-safe. It uses a pessimistic locking scheme for nodes in the tree by
- default, with an optimistic locking scheme as a configurable option. With pessimistic locking, the degree
- of concurrency can be tuned using a number of isolation levels, corresponding to database-style
- transaction isolation levels, i.e., SERIALIZABLE, REPEATABLE_READ, READ_COMMITTED, READ_UNCOMMITTED and NONE.
- Concurrency, locking and isolation levels will be discussed later.
- </para>
- </section>
-
- <section>
- <title>
- Requirements
- </title>
- <para>
- JBoss Cache requires Java 5.0 (or newer).
- </para>
- <para>
- However, there is a way to build JBoss Cache as a Java 1.4.x compatible binary using
- <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossRetro">JBossRetro</ulink>
- to retroweave the Java 5.0 binaries. However, Red Hat Inc. does not offer professional support around the
- retroweaved
- binary at this time and the Java 1.4.x compatible binary is not in the binary distribution. See
- <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossCacheHabaneroJava1.4">this wiki</ulink>
- page for
- details on building the retroweaved binary for yourself.
- </para>
- <para>
- In addition to Java 5.0, at a minimum, JBoss Cache has dependencies on
- <ulink url="http://www.jgroups.org">JGroups</ulink>
- , and Apache's
- <ulink
- url="http://jakarta.apache.org/commons/logging/">commons-logging
- </ulink>
- . JBoss Cache ships with all dependent libraries necessary to run out of the box.
- </para>
- </section>
-
- <section>
- <title>License</title>
- <para>
- JBoss Cache is an open source product, using the business and OEM-friendly
- <ulink url="http://www.opensource.org/">OSI-approved</ulink>
- <ulink url="http://www.gnu.org/copyleft/lesser.html">LGPL license.</ulink>
- Commercial development support, production support and training for JBoss Cache is available through
- <ulink url="http://www.jboss.com">JBoss, a division of Red Hat Inc.</ulink>
- JBoss Cache is a part of JBoss Professional Open Source
- <ulink url="http://www.jboss.comindex">JEMS</ulink>
- (JBoss Enterprise Middleware Suite).
- </para>
- </section>
-</chapter>
Added: pojo/trunk/src/main/docbook/userguide/en/modules/introduction.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/introduction.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/introduction.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -0,0 +1,257 @@
+<chapter id="intro">
+
+ <title>Introduction</title>
+
+ <sect1 id="1" revision="1">
+ <title id="s1">Overview</title>
+
+ <para>
+ JBoss Cache consists of two components, Core Cache, and POJO Cache. Core Cache provides efficient
+ memory storage, transactions, replication, eviction, persistent storage, and many other
+ "core" features you would expect from a distributed cache.
+
+ The Core Cache API is tree based. Data is arranged on the tree using nodes that each offer a map
+ of attributes. This map-like API is intuitive and easy to use for caching data, but just like the
+ Java Collection API, it operates only off of simple and serializable types.
+ Therefore, it has the following constraints:
+ <itemizedlist>
+ <listitem>If replication or persistence is needed, the object will then need to
+ implement the <literal>Serializable</literal> interface. E.g.,
+ <programlisting>public Class Foo implements Serializable</programlisting>
+ </listitem>
+ <listitem>If the object is mutable, any field change will require a successive put operation on the cache:
+<programlisting>value = new Foo();
+cache.put(fqn, key, value);
+value.update(); // update value
+cache.put(fqn, key, value); // Need to repeat this step again to ask cache to persist or replicate the changes</programlisting>
+ </listitem>
+ <listitem>Java serialization always writes the entire object, even if only one field was changed. Therefore, large objects
+ can have significant overhead, especially if they are updated frequently:
+<programlisting>thousand = new ThousandFieldObject();
+cache.put(fqn, key, thousand);
+thousand.setField1("blah"); // Only one field was modified
+cache.put(fqn, key, thousand); // Replicates 1000 fields</programlisting>
+ </listitem>
+ <listitem>The object structure can not have a graph relationship. That is, the object can not have
+ references to objects that are shared (multiple
+ referenced) or to itself (cyclic). Otherwise, the relationship will be broken upon
+ serialization (e.g., when replicate each parent object separately). For example, Figure 1
+ illustrates this problem during replication.
+ If we have two
+ <literal>Person</literal>
+ instances that share the same
+ <literal>Address</literal>
+ ,
+ upon replication, it will be split into two separate
+ <literal>Address</literal>
+ instances (instead of just one). The following is the code snippet using Cache that illustrates this
+ problem:
+<programlisting>joe = new Person("joe");
+mary = new Person("mary");
+addr = new Address("Taipei");
+joe.setAddress(addr);
+mary.setAddress(addr);
+cache.put("/joe", "person", joe);
+cache.put("/mary", "person", mary);
+</programlisting>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <figure>
+ <title>Illustration of shared objects problem during replication</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/object_split.jpg"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>POJO Cache attempts to address these issues by building a layer on top of Core Cache which transparently maps
+ normal Java object model operations to individual Node operations on the cache.
+
+ This offers the following improvements:
+ <itemizedlist>
+ <listitem>Objects do not need to implement <literal>Serializable</literal> interface. Instead they are instrumented,
+ allowing POJO Cache to intercept individual operations.</listitem>
+ <listitem>Replication is fine-grained. Only modified fields are replicated, and they can be optionally batched in a transaction. </listitem>
+ <listitem>Object identity is preserved, so graphs and cyclical references are allowed.</listitem>
+ <listitem>Once attached to the cache, all subsequent object operationis will trigger a cache operation (like replication)
+ automatically:
+<programlisting>POJO pojo = new POJO();
+pojoCache.attach("id", pojo);
+pojo.setName("some pojo"); // This will trigger replication automatically.
+</programlisting>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ In POJO Cache, these are the typical development and programming steps:
+ <itemizedlist>
+ <listitem>Annotate your object with <literal>@Replicable</literal></listitem>
+ <listitem>Use <literal>attach()</literal> to put your POJO under cache management.</listitem>
+ <listitem>Operate on the object directly. The cache will then manage the replication or persistence automatically and
+ transparently.</listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ More details on these steps will be given in later chapters.
+ </para>
+
+ <para>
+ Since POJO Cache is a layer on-top of Core Cache, all features available in Core Cache are also available in POJO Cache. Furthermore, you can obtain an instance to the underlying Core Cache by calling <literal>PojoCache.getCache()</literal>. This is useful for resusing the same cache instance to store custom data, along with the POJO model.
+ </para>
+ </sect1>
+
+ <sect1 id="2" revision="1">
+ <title id="s2">Features</title>
+
+ <para>Here are the current features and benefits of PojoCache:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Fine-grained replication. The replication modes supported are the
+ same as that of Core Cache:
+ <literal>LOCAL</literal>, <literal>REPL_SYNC</literal>, <literal>REPL_ASYNC</literal>,
+ <literal>INVALIDATION_SYNC</literal>, and <literal>INVALIDATION_ASYNC</literal> (see the
+ main JBoss Cache reference documentation for details). The
+ replication level is fine-grained and is performed automatically once the POJO is mapped into the
+ internal cache store. When a POJO field is updated, a replication request
+ will be sent out only to the key
+ corresponding to that modified attribute (instead of the whole
+ object). This can have a potential performance boost during the replication
+ process; e.g., updating a single key in a big HashMap will only
+ replicate the single field instead of the whole map!
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Transactions. All attached objects participate in a user transaction context.
+ If a rollback occurs, the previous internal field state of the object will be restored:
+<programlisting>POJO p = new POJO();
+p.setName("old value");
+pojoCache.attach("id", p);
+tx.begin(); // start a user transaction
+p.setName("some pojo");
+tx.rollback(); // this will cause the rollback
+p.getName(); // is "old value"
+</programlisting></para>
+ <para>In addition, operations under a transaction is batched. That is,
+ the update is not performed until the <literal>commit</literal> phase. Further, if replication is enabled, other nodes will not see the changes until the transaction has completed successfully. </para>
+ </listitem>
+
+ <listitem>
+ <para>Passivation. POJO Cache supports the same passivation provided by Core Cache. When a node mapped by POJO Cache has reached a configured threshold, it is evicted from memory and stored using a cache loader. When the node is accessed again, it will be retrieved from the cache loader and put into memory.
+ The configuration parameters are the same as those of the Cache
+ counterpart. To configure the passivation, you will need to configure both the eviction policy and
+ cache loader.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Object cache by reachability, i.e., recursive object mapping
+ into the cache store. On attach, <literal>POJO Cache</literal>
+ will attach all referenced objects as well. This feature is explained in more detail later.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Natural Object Relationships. Java references are preserved as they were written. That is, a user
+ does not need to declare any object relationship (e.g., one-to-one, or
+ one-to-many) to use the cache.</para>
+ </listitem>
+
+ <listitem>
+ <para>Object Identity. Object identity is preserved. Not only can a cached object be compared
+ using <literal>equals()</literal>, but the comparison operator, <literal>==</literal>, can be
+ used as well. For example, an object such as
+ <literal>Address</literal> may be multiple referenced by two
+ <literal>Person</literal>s (e.g., <literal>joe</literal> and <literal>mary</literal>).
+ The objects retrieved from <literal>joe.getAddress()</literal> and <literal>mary.getAddress()</literal>
+ should be identicali, when when retrieved from a different node in the cluster then that which attached them.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Inheritance. POJO Cache preserves the inheritance hierarchy of any object in the cache.
+ For example, if a <literal>Student</literal> class inherits from a
+ <keycode>Person</keycode> class, once a <literal>Student</literal>
+ object is mapped to POJO Cache (e.g., <literal>attach</literal>
+ call), the fields in the base class <literal>Person</literal>
+ are mapped as well.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Collections. Java Collection types (e.g. List, Set, and Map) are transparently mapped using Java proxies.
+ Details are described later.</para>
+ </listitem>
+
+ <listitem>
+ <para>Annotation based. Starting from release 2.0, JDK 5 annotations are used to indicate that an object should
+ be instrumented for use under POJO Cache (once attached).
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Transparent. Once a POJO is attached to the cache, subsequent object model changes are transparently handled.
+ No further API calls are required.</para>
+ </listitem>
+ </itemizedlist>
+ </sect1>
+
+ <sect1 id="3">
+ <title>Usage</title>
+ <para>
+ To use POJO Cache, you obtain the instance from the PojoCacheFactory by supplying a config file that is used
+ by the delegating Cache implementation. Once the PojoCache instance is obtained, you can call the cache life
+ cycle method to start the cache. Below is a code snippet that creates and starts the cache:
+<programlisting>String configFile = "replSync-service.xml";
+boolean toStart = false;
+PojoCache pcache = PojoCacheFactory.createCache(configFiel, toStart);
+pcache.start(); // if toStart above is true, it will starts the cache automatically.
+pcache.attach(id, pojo);
+...
+pcache.stop(); // stop the cache. This will take PojoCache out of the clustering group, if any, e.g.
+</programlisting>
+ </para>
+ </sect1>
+ <sect1 id="4">
+ <title>Requirements</title>
+
+ <para>
+ <literal>POJO Cache</literal> is currently supported on JDK 5 (since release 2.0).
+ It requires the following libraries (in
+ addition to jboss-cache.jar and the required libraries for Core
+ Cache) to start up:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Library:</para>
+
+ <itemizedlist>
+ <listitem>
+ pojocache.jar. Main POJO Cache library.
+ </listitem>
+
+ <listitem>
+ jboss-aop-jdk50.jar. Main JBoss Aop library.
+ </listitem>
+
+ <listitem>
+ javassist.jar. Java byte code manipulation library.
+ </listitem>
+
+ <listitem>
+ trove.jar. High performance collections for Java.
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </sect1>
+
+</chapter>
Property changes on: pojo/trunk/src/main/docbook/userguide/en/modules/introduction.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: pojo/trunk/src/main/docbook/userguide/en/modules/jmx_reference.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/jmx_reference.xml 2007-08-14 16:34:22 UTC (rev 4250)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/jmx_reference.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -1,308 +0,0 @@
-<chapter id="jmx_reference">
- <title>JMX References</title>
- <section id="jmx_reference.statistics">
- <title>JBoss Cache Statistics</title>
- <para>
- The following table describes the statistics currently available and may be collected via JMX.
- </para>
- <table>
- <title>JBoss Cache Management Statistics</title>
- <tgroup cols="4">
- <colspec colnum="1" colwidth="2*"/>
- <colspec colnum="2" colwidth="2*"/>
- <colspec colnum="3" colwidth="1*"/>
- <colspec colnum="4" colwidth="3*"/>
- <thead>
- <row>
- <entry>MBean Name</entry>
- <entry>Attribute</entry>
- <entry>Type</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>ActivationInterceptor</entry>
- <entry>Activations</entry>
- <entry>long</entry>
- <entry>Number of passivated nodes that have been activated.</entry>
- </row>
- <row>
- <entry>CacheLoaderInterceptor</entry>
- <entry>CacheLoaderLoads</entry>
- <entry>long</entry>
- <entry>Number of nodes loaded through a cache loader.</entry>
- </row>
- <row>
- <entry>CacheLoaderInterceptor</entry>
- <entry>CacheLoaderMisses</entry>
- <entry>long</entry>
- <entry>Number of unsuccessful attempts to load a node through a cache loader.</entry>
- </row>
- <row>
- <entry>CacheMgmtInterceptor</entry>
- <entry>Hits</entry>
- <entry>long</entry>
- <entry>Number of successful attribute retrievals.</entry>
- </row>
- <row>
- <entry>CacheMgmtInterceptor</entry>
- <entry>Misses</entry>
- <entry>long</entry>
- <entry>Number of unsuccessful attribute retrievals.</entry>
- </row>
- <row>
- <entry>CacheMgmtInterceptor</entry>
- <entry>Stores</entry>
- <entry>long</entry>
- <entry>Number of attribute store operations.</entry>
- </row>
- <row>
- <entry>CacheMgmtInterceptor</entry>
- <entry>Evictions</entry>
- <entry>long</entry>
- <entry>Number of node evictions.</entry>
- </row>
- <row>
- <entry>CacheMgmtInterceptor</entry>
- <entry>NumberOfAttributes</entry>
- <entry>int</entry>
- <entry>Number of attributes currently cached.</entry>
- </row>
- <row>
- <entry>CacheMgmtInterceptor</entry>
- <entry>NumberOfNodes</entry>
- <entry>int</entry>
- <entry>Number of nodes currently cached.</entry>
- </row>
- <row>
- <entry>CacheMgmtInterceptor</entry>
- <entry>ElapsedTime</entry>
- <entry>long</entry>
- <entry>Number of seconds that the cache has been running.</entry>
- </row>
- <row>
- <entry>CacheMgmtInterceptor</entry>
- <entry>TimeSinceReset</entry>
- <entry>long</entry>
- <entry>Number of seconds since the cache statistics have been reset.</entry>
- </row>
- <row>
- <entry>CacheMgmtInterceptor</entry>
- <entry>AverageReadTime</entry>
- <entry>long</entry>
- <entry>Average time in milliseconds to retrieve a cache attribute, including unsuccessful
- attribute retrievals.
- </entry>
- </row>
- <row>
- <entry>CacheMgmtInterceptor</entry>
- <entry>AverageWriteTime</entry>
- <entry>long</entry>
- <entry>Average time in milliseconds to write a cache attribute.</entry>
- </row>
- <row>
- <entry>CacheMgmtInterceptor</entry>
- <entry>HitMissRatio</entry>
- <entry>double</entry>
- <entry>Ratio of hits to hits and misses. A hit is a get attribute operation that results in an object
- being
- returned to the client. The retrieval may be from a cache loader if the entry isn't in the local
- cache.
- </entry>
- </row>
- <row>
- <entry>CacheMgmtInterceptor</entry>
- <entry>ReadWriteRatio</entry>
- <entry>double</entry>
- <entry>Ratio of read operations to write operations. This is the ratio of cache hits and misses to
- cache stores.
- </entry>
- </row>
- <row>
- <entry>CacheStoreInterceptor</entry>
- <entry>CacheLoaderStores</entry>
- <entry>long</entry>
- <entry>Number of nodes written to the cache loader.</entry>
- </row>
- <row>
- <entry>InvalidationInterceptor</entry>
- <entry>Invalidations</entry>
- <entry>long</entry>
- <entry>Number of cached nodes that have been invalidated.</entry>
- </row>
- <row>
- <entry>PassivationInterceptor</entry>
- <entry>Passivations</entry>
- <entry>long</entry>
- <entry>Number of cached nodes that have been passivated.</entry>
- </row>
- <row>
- <entry>TxInterceptor</entry>
- <entry>Prepares</entry>
- <entry>long</entry>
- <entry>Number of transaction prepare operations performed by this interceptor.</entry>
- </row>
- <row>
- <entry>TxInterceptor</entry>
- <entry>Commits</entry>
- <entry>long</entry>
- <entry>Number of transaction commit operations performed by this interceptor.</entry>
- </row>
- <row>
- <entry>TxInterceptor</entry>
- <entry>Rollbacks</entry>
- <entry>long</entry>
- <entry>Number of transaction rollbacks operations performed by this interceptor.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </section>
-
- <section id="jmx_reference.notifications">
- <title>JMX MBean Notifications</title>
- <para>The following table depicts the JMX notifications available for JBoss Cache as well as the cache events to
- which they correspond. These are the notifications that can be received through the
- <literal>CacheJmxWrapper</literal>
- MBean.
- Each notification represents a single event published by JBoss Cache and provides user data corresponding to
- the parameters of the event.
- </para>
- <table>
- <title>JBoss Cache MBean Notifications</title>
- <tgroup cols="3">
- <thead>
- <row>
- <entry>Notification Type</entry>
- <entry>Notification Data</entry>
- <entry>CacheListener Event</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>org.jboss.cache.CacheStarted</entry>
- <entry>String : cache service name</entry>
- <entry>cacheStarted</entry>
- </row>
- <row>
- <entry>org.jboss.cache.CacheStopped</entry>
- <entry>String : cache service name</entry>
- <entry>cacheStopped</entry>
- </row>
- <row>
- <entry>org.jboss.cache.NodeCreated</entry>
- <entry>String : fqn</entry>
- <entry>NodeCreated</entry>
- </row>
- <row>
- <entry>org.jboss.cache.NodeEvicted</entry>
- <entry>String : fqn</entry>
- <entry>NodeEvicted</entry>
- </row>
- <row>
- <entry>org.jboss.cache.NodeLoaded</entry>
- <entry>String : fqn</entry>
- <entry>NodeLoaded</entry>
- </row>
- <row>
- <entry>org.jboss.cache.NodeModifed</entry>
- <entry>String : fqn</entry>
- <entry>NodeModifed</entry>
- </row>
- <row>
- <entry>org.jboss.cache.NodeRemoved</entry>
- <entry>String : fqn</entry>
- <entry>NodeRemoved</entry>
- </row>
- <row>
- <entry>org.jboss.cache.NodeVisited</entry>
- <entry>String : fqn</entry>
- <entry>NodeVisited</entry>
- </row>
- <row>
- <entry>org.jboss.cache.ViewChange</entry>
- <entry>String : view</entry>
- <entry>ViewChange</entry>
- </row>
- <row>
- <entry>org.jboss.cache.NodeActivate</entry>
- <entrytbl cols="1">
- <tbody>
- <row>
- <entry rowsep="0">Object[0]=String: fqn</entry>
- </row>
- <row>
- <entry>Object[1]=Boolean: pre</entry>
- </row>
- </tbody>
- </entrytbl>
- <entry>NodeActivate</entry>
- </row>
- <row>
- <entry>org.jboss.cache.NodeEvict</entry>
- <entrytbl cols="1">
- <tbody>
- <row>
- <entry rowsep="0">Object[0]=String: fqn</entry>
- </row>
- <row>
- <entry>Object[1]=Boolean: pre</entry>
- </row>
- </tbody>
- </entrytbl>
- <entry>NodeEvict</entry>
- </row>
- <row>
- <entry>org.jboss.cache.NodeModify</entry>
- <entrytbl cols="1">
- <tbody>
- <row>
- <entry rowsep="0">Object[0]=String: fqn</entry>
- </row>
- <row>
- <entry rowsep="0">Object[1]=Boolean: pre</entry>
- </row>
- <row>
- <entry>Object[2]=Boolean: isLocal</entry>
- </row>
- </tbody>
- </entrytbl>
- <entry>NodeModify</entry>
- </row>
- <row>
- <entry>org.jboss.cache.NodePassivate</entry>
- <entrytbl cols="1">
- <tbody>
- <row>
- <entry rowsep="0">Object[0]=String: fqn</entry>
- </row>
- <row>
- <entry>Object[1]=Boolean: pre</entry>
- </row>
- </tbody>
- </entrytbl>
- <entry>NodePassivate</entry>
- </row>
- <row>
- <entry>org.jboss.cache.NodeRemove</entry>
- <entrytbl cols="1">
- <tbody>
- <row>
- <entry rowsep="0">Object[0]=String: fqn</entry>
- </row>
- <row>
- <entry rowsep="0">Object[1]=Boolean: pre</entry>
- </row>
- <row>
- <entry>Object[2]=Boolean: isLocal</entry>
- </row>
- </tbody>
- </entrytbl>
- <entry>NodeRemove</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </section>
-</chapter>
\ No newline at end of file
Deleted: pojo/trunk/src/main/docbook/userguide/en/modules/preface.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/preface.xml 2007-08-14 16:34:22 UTC (rev 4250)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/preface.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -1,48 +0,0 @@
-<preface id="preface">
- <title>Preface</title>
-
- <para>
- This is the official JBoss Cache user guide. Along with its accompanying documents (an FAQ, a tutorial and a
- whole set of documents on PojoCache), this is freely available on the JBoss Cache <ulink url="http://labs.jboss.com/jbosscache">documentation site.</ulink>
- </para>
- <para>
- When used, JBoss Cache refers to JBoss Cache Core, a tree-structured, clustered, transactional cache.
- Pojo Cache, also a part of the JBoss Cache distribution, is documented separately. (Pojo Cache is a cache that
- deals with Plain Old Java Objects, complete with object relationships, with the ability to cluster such pojos
- while maintaining their relationships. Please see the Pojo Cache documentation for more information about this.)
- </para>
-
- <para>
- This book is targeted at both developers wishing to use JBoss Cache as a clustering and caching library in
- their codebase, as well as people who wish to "OEM" JBoss Cache by building on and extending its features. As
- such,
- this book is split into two major sections - one detailing the "User" API and the other going much deeper into
- specialist topics and the JBoss Cache architecture.
- </para>
-
- <para>
- In general, a good knowledge of the Java programming language along with a strong appreciation and understanding
- of transactions and concurrent threads is necessary. No prior knowledge of JBoss Application Server is expected
- or required.
- </para>
-
- <para>
- For further discussion, use the
- <ulink url="http://www.jboss.com/index.html?module=bb&op=viewforum&f=157">user forum</ulink>
- linked on the JBoss Cache <ulink url="http://labs.jboss.com/jbosscache">website.</ulink> We also provide a mechanism for
- tracking bug reports and feature requests on the JBoss Cache <ulink url="http://jira.jboss.com/jira/browse/JBCACHE">JIRA issue tracker.</ulink>
-
- If you are interested in the development of JBoss Cache or in translating this documentation into other languages,
- we'd love
- to hear from you. Please post a message on the
- <ulink url="http://www.jboss.com/index.html?module=bb&op=viewforum&f=157">user forum</ulink>
- or contact us by using the JBoss Cache <ulink url="https://lists.jboss.org/mailman/listinfo/jbosscache-dev">developer mailing list.</ulink>
- </para>
-
- <para>
- This book is specifically targeted at the JBoss Cache release of the same version number. It may not apply to
- older or newer releases of JBoss Cache. It is important that you use the documentation appropriate to the version
- of JBoss Cache you intend to use.
- </para>
-
-</preface>
\ No newline at end of file
Deleted: pojo/trunk/src/main/docbook/userguide/en/modules/replication.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/replication.xml 2007-08-14 16:34:22 UTC (rev 4250)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/replication.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -1,730 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter id="clustering">
- <title>Clustering</title>
-
- <para>This chapter talks about aspects around clustering JBoss Cache.</para>
-
- <section>
- <title>Cache Replication Modes</title>
-
- <para>JBoss Cache can be configured to be either local (standalone) or
- clustered. If in a cluster, the cache can be configured to replicate
- changes, or to invalidate changes. A detailed discussion on this
- follows.
- </para>
-
- <section>
- <title>Local Mode</title>
-
- <para>Local caches don't join a cluster and don't communicate with other
- caches in a cluster. Therefore their elements don't need to be
- serializable - however, we recommend making them serializable, enabling
- a user to change the cache mode at any time. The dependency on the
- JGroups library is still there, although a JGroups channel is not
- started.
- </para>
- </section>
-
- <section>
- <title>Replicated Caches</title>
-
- <para>Replicated caches replicate all changes to some or all of the other cache
- instances in the cluster. Replication can either happen after each
- modification (no transactions), or at the end of a transaction (commit
- time).
- </para>
-
- <para>Replication can be synchronous or asynchronous . Use of either one
- of the options is application dependent. Synchronous replication blocks
- the caller (e.g. on a
- <literal>put()</literal>
- ) until the modifications
- have been replicated successfully to all nodes in a cluster.
- Asynchronous replication performs replication in the background (the
- <literal>put()</literal>
- returns immediately). JBoss Cache also offers a
- replication queue, where modifications are replicated periodically (i.e.
- interval-based), or when the queue size exceeds a number of elements, or
- a combination thereof.
- </para>
-
- <para>Asynchronous replication is faster (no caller blocking), because
- synchronous replication requires acknowledgments from all nodes in a
- cluster that they received and applied the modification successfully
- (round-trip time). However, when a synchronous replication returns
- successfully, the caller knows for sure that all modifications have been
- applied to all cache instances, whereas this is not be the case with asynchronous
- replication. With asynchronous replication, errors are simply written to
- a log. Even when using transactions, a transaction may succeed but
- replication may not succeed on all cache instances.
- </para>
-
- <section id="replication.tx">
- <title>Replicated Caches and Transactions</title>
-
- <para>When using transactions, replication only occurs at the
- transaction boundary - i.e., when a transaction commits. This results
- in minimising replication traffic since a single modification is
- broadcast rather than a series of individual modifications, and can be
- a lot more efficient than not using transactions. Another effect of
- this is that if a transaction were to roll back, nothing is broadcast
- across a cluster.
- </para>
-
- <para>Depending on whether you are running your cluster in
- asynchronous or synchronous mode, JBoss Cache will use either a single
- phase or
- <ulink
- url="http://en.wikipedia.org/wiki/Two-phase_commit_protocol">two phase
- commit
- </ulink>
- protocol, respectively.
- </para>
-
- <section>
- <title>One Phase Commits</title>
-
- <para>Used when your cache mode is REPL_ASYNC. All modifications are
- replicated in a single call, which instructs remote caches to apply
- the changes to their local in-memory state and commit locally.
- Remote errors/rollbacks are never fed back to the originator of the
- transaction since the communication is asynchronous.
- </para>
- </section>
-
- <section>
- <title>Two Phase Commits</title>
-
- <para>Used when your cache mode is REPL_SYNC. Upon committing your
- transaction, JBoss Cache broadcasts a prepare call, which carries
- all modifications relevant to the transaction. Remote caches then
- acquire local locks on their in-memory state and apply the
- modifications. Once all remote caches respond to the prepare call,
- the originator of the transaction broadcasts a commit. This
- instructs all remote caches to commit their data. If any of the
- caches fail to respond to the prepare phase, the originator
- broadcasts a rollback.
- </para>
-
- <para>Note that although the prepare phase is synchronous, the
- commit and rollback phases are asynchronous. This is because
- <ulink
- url="http://java.sun.com/products/jta/">Sun's JTA
- specification
- </ulink>
- does not specify how transactional resources
- should deal with failures at this stage of a transaction; and other
- resources participating in the transaction may have indeterminate
- state anyway. As such, we do away with the overhead of synchronous
- communication for this phase of the transaction. That said, they can
- be forced to be synchronous using the
- <literal>SyncCommitPhase</literal>
- and
- <literal>SyncRollbackPhase</literal>
- configuration
- attributes.
- </para>
- </section>
- </section>
-
- <section id="br">
- <title>Buddy Replication</title>
-
- <para>Buddy Replication allows you to suppress replicating your data
- to all instances in a cluster. Instead, each instance picks one or
- more 'buddies' in the cluster, and only replicates to these specific
- buddies. This greatly helps scalability as there is no longer a memory
- and network traffic impact every time another instance is added to a
- cluster.
- </para>
-
- <para>One of the most common use cases of Buddy Replication is when a
- replicated cache is used by a servlet container to store HTTP session
- data. One of the pre-requisites to buddy replication working well and
- being a real benefit is the use of
- <emphasis>session
- affinity
- </emphasis>
- , more casually known as
- <emphasis>sticky
- sessions
- </emphasis>
- in HTTP session replication speak. What this means
- is that if certain data is frequently accessed, it is desirable that
- this is always accessed on one instance rather than in a round-robin
- fashion as this helps the cache cluster optimise how it chooses
- buddies, where it stores data, and minimises replication
- traffic.
- </para>
-
- <para>If this is not possible, Buddy Replication may prove to be more
- of an overhead than a benefit.
- </para>
-
- <section>
- <title>Selecting Buddies</title>
-
- <figure>
- <title>BuddyLocator</title>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="BuddyReplication.png"/>
- </imageobject>
- </mediaobject>
- </figure>
-
- <para>Buddy Replication uses an instance of a
- <literal>BuddyLocator</literal>
- which contains the logic used to
- select buddies in a network. JBoss Cache currently ships with a
- single implementation,
- <literal>NextMemberBuddyLocator</literal>
- ,
- which is used as a default if no implementation is provided. The
- <literal>NextMemberBuddyLocator</literal>
- selects the next member in
- the cluster, as the name suggests, and guarantees an even spread of
- buddies for each instance.
- </para>
-
- <para>The
- <literal>NextMemberBuddyLocator</literal>
- takes in 2
- parameters, both optional.
- <itemizedlist>
- <listitem>
-
-
- <literal>numBuddies</literal>
-
- - specifies how many buddies each instance should pick to back its data onto. This defaults to
- 1.
- </listitem>
-
- <listitem>
-
-
- <literal>ignoreColocatedBuddies</literal>
-
- - means that each instance will
-
- <emphasis>try</emphasis>
-
- to select a buddy on a different physical host. If not able to do so though, it will fall back
- to colocated instances. This defaults to
-
- <literal>true</literal>
-
- .
- </listitem>
- </itemizedlist>
- </para>
- </section>
-
- <section>
- <title>BuddyPools</title>
-
- <para>Also known as
- <emphasis>replication groups</emphasis>
- , a buddy
- pool is an optional construct where each instance in a cluster may
- be configured with a buddy pool name. Think of this as an 'exclusive
- club membership' where when selecting buddies,
- <literal>BuddyLocator</literal>
- s that support buddy pools would try
- and select buddies sharing the same buddy pool name. This allows
- system administrators a degree of flexibility and control over how
- buddies are selected. For example, a sysadmin may put two instances
- on two separate physical servers that may be on two separate
- physical racks in the same buddy pool. So rather than picking an
- instance on a different host on the same rack,
- <literal>BuddyLocator</literal>
- s would rather pick the instance in
- the same buddy pool, on a separate rack which may add a degree of
- redundancy.
- </para>
- </section>
-
- <section>
- <title>Failover</title>
-
- <para>In the unfortunate event of an instance crashing, it is
- assumed that the client connecting to the cache (directly or
- indirectly, via some other service such as HTTP session replication)
- is able to redirect the request to any other random cache instance
- in the cluster. This is where a concept of Data Gravitation comes
- in.
- </para>
-
- <para>Data Gravitation is a concept where if a request is made on a
- cache in the cluster and the cache does not contain this
- information, it asks other instances in the cluster for the
- data. In other words, data is lazily transferred, migrating
- <emphasis>only</emphasis>
- when other nodes ask for it. This strategy
- prevents a network storm effect where lots of data is pushed around
- healthy nodes because only one (or a few) of them die.
- </para>
-
- <para>If the data is not found in the primary section of some node,
- it would (optionally) ask other instances to check in the backup
- data they store for other caches.
- This means that even if a cache containing your session dies, other
- instances will still be able to access this data by asking the cluster
- to search through their backups for this data.
- </para>
-
- <para>Once located, this data is transferred to the instance
- which requested it and is added to this instance's data tree.
- The data is then (optionally) removed from all other instances
- (and backups) so that if session affinity is used, the affinity
- should now be to this new cache instance which has just
- <emphasis>taken
- ownership
- </emphasis>
- of this data.
- </para>
-
- <para>Data Gravitation is implemented as an interceptor. The
- following (all optional) configuration properties pertain to data
- gravitation.
- <itemizedlist>
- <listitem>
-
-
- <literal>dataGravitationRemoveOnFind</literal>
-
- - forces all remote caches that own the data or hold backups for the data to remove that data,
- thereby making the requesting cache the new data owner. This removal, of course, only happens
- after the new owner finishes replicating data to its buddy. If set to
-
- <literal>false</literal>
-
- an evict is broadcast instead of a remove, so any state persisted in cache loaders will remain.
- This is useful if you have a shared cache loader configured. Defaults to
-
- <literal>true</literal>
-
- .
- </listitem>
-
- <listitem>
-
-
- <literal>dataGravitationSearchBackupTrees</literal>
-
- - Asks remote instances to search through their backups as well as main data trees. Defaults to
-
- <literal>true</literal>
-
- . The resulting effect is that if this is
-
- <literal>true</literal>
-
- then backup nodes can respond to data gravitation requests in addition to data owners.
- </listitem>
-
- <listitem>
-
-
- <literal>autoDataGravitation</literal>
-
- - Whether data gravitation occurs for every cache miss. By default this is set to
-
- <literal>false</literal>
-
- to prevent unnecessary network calls. Most use cases will know when it may need to gravitate
- data and will pass in an
-
- <literal>Option</literal>
-
- to enable data gravitation on a per-invocation basis. If
-
- <literal>autoDataGravitation</literal>
-
- is
-
- <literal>true</literal>
-
- this
-
- <literal>Option</literal>
-
- is unnecessary.
- </listitem>
- </itemizedlist>
- </para>
- </section>
-
- <section>
- <title>Configuration</title>
-
- <para>
- <programlisting>
- <![CDATA[
-<!-- Buddy Replication config -->
-<attribute name="BuddyReplicationConfig">
- <config>
-
- <!-- Enables buddy replication. This is the ONLY mandatory configuration element here. -->
- <buddyReplicationEnabled>true</buddyReplicationEnabled>
-
- <!-- These are the default values anyway -->
- <buddyLocatorClass>org.jboss.cache.buddyreplication.NextMemberBuddyLocator</buddyLocatorClass>
-
- <!-- numBuddies is the number of backup nodes each node maintains. ignoreColocatedBuddies means
- that each node will *try* to select a buddy on a different physical host. If not able to do so though,
- it will fall back to colocated nodes. -->
- <buddyLocatorProperties>
- numBuddies = 1
- ignoreColocatedBuddies = true
- </buddyLocatorProperties>
-
- <!-- A way to specify a preferred replication group. If specified, we try and pick a buddy which shares
- the same pool name (falling back to other buddies if not available). This allows the sysdmin to
- hint at backup buddies are picked, so for example, nodes may be hinted topick buddies on a different
- physical rack or power supply for added fault tolerance. -->
- <buddyPoolName>myBuddyPoolReplicationGroup</buddyPoolName>
-
- <!-- Communication timeout for inter-buddy group organisation messages (such as assigning to and
- removing from groups, defaults to 1000. -->
- <buddyCommunicationTimeout>2000</buddyCommunicationTimeout>
-
- <!-- Whether data is removed from old owners when gravitated to a new owner. Defaults to true. -->
- <dataGravitationRemoveOnFind>true</dataGravitationRemoveOnFind>
-
- <!-- Whether backup nodes can respond to data gravitation requests, or only the data owner is
- supposed to respond. Defaults to true. -->
- <dataGravitationSearchBackupTrees>true</dataGravitationSearchBackupTrees>
-
- <!-- Whether all cache misses result in a data gravitation request. Defaults to false, requiring
- callers to enable data gravitation on a per-invocation basis using the Options API. -->
- <autoDataGravitation>false</autoDataGravitation>
-
- </config>
-</attribute>
-
-]]>
- </programlisting>
- </para>
- </section>
- </section>
- </section>
- </section>
-
- <section>
- <title>Invalidation</title>
-
- <para>If a cache is configured for invalidation rather than replication,
- every time data is changed in a cache other caches in the cluster receive
- a message informing them that their data is now stale and should be
- evicted from memory. Invalidation, when used with a shared cache loader
- (see chapter on Cache Loaders) would cause remote caches to refer to the
- shared cache loader to retrieve modified data. The benefit of this is
- twofold: network traffic is minimised as invalidation messages are very
- small compared to replicating updated data, and also that other caches in
- the cluster look up modified data in a lazy manner, only when
- needed.
- </para>
-
- <para>Invalidation messages are sent after each modification (no
- transactions), or at the end of a transaction, upon successful commit.
- This is usually more efficient as invalidation messages can be optimised
- for the transaction as a whole rather than on a per-modification
- basis.
- </para>
-
- <para>Invalidation too can be synchronous or asynchronous, and just as in
- the case of replication, synchronous invalidation blocks until all caches
- in the cluster receive invalidation messages and have evicted stale data
- while asynchronous invalidation works in a 'fire-and-forget' mode, where
- invalidation messages are broadcast but doesn't block and wait for
- responses.
- </para>
- </section>
-
- <section>
- <title>State Transfer</title>
-
- <para>
- <emphasis>State Transfer</emphasis>
- refers to the process by which a
- JBoss Cache instance prepares itself to begin providing a service by
- acquiring the current state from another cache instance and integrating
- that state into its own state.
- </para>
-
- <section>
- <title>State Transfer Types</title>
-
- <para>There are three divisions of state transfer types depending on a
- point of view related to state transfer. First, in the context of
- particular state transfer implementation, the underlying plumbing, there
- are two starkly different state transfer types: byte array and streaming
- based state transfer. Second, state transfer can be full or partial
- state transfer depending on a subtree being transferred. Entire cache
- tree transfer represents full transfer while transfer of a particular
- subtree represents partial state transfer. And finally state transfer
- can be "in-memory" and "persistent" transfer depending on a particular
- use of cache.
- </para>
- </section>
-
- <section>
- <title>Byte array and streaming based state transfer</title>
-
- <para>Byte array based transfer was a default and only transfer
- methodology for cache in all previous releases up to 2.0. Byte array
- based transfer loads entire state transferred into a byte array and
- sends it to a state receiving member. Major limitation of this approach
- is that the state transfer that is very large (>1GB) would likely
- result in OutOfMemoryException. Streaming state transfer provides an
- InputStream to a state reader and an OutputStream to a state writer.
- OutputStream and InputStream abstractions enable state transfer in byte
- chunks thus resulting in smaller memory requirements. For example, if
- application state is represented as a tree whose aggregate size is 1GB,
- rather than having to provide a 1GB byte array streaming state transfer
- transfers the state in chunks of N bytes where N is user
- configurable.
- </para>
-
- <para>Byte array and streaming based state transfer are completely API
- transparent, interchangeable, and statically configured through a
- standard cache configuration XML file. Refer to JGroups documentation on
- how to change from one type of transfer to another.
- </para>
- </section>
-
- <section>
- <title>Full and partial state transfer</title>
-
- <para>If either in-memory or persistent state transfer is enabled, a
- full or partial state transfer will be done at various times, depending
- on how the cache is used. "Full" state transfer refers to the transfer
- of the state related to the entire tree -- i.e. the root node and all
- nodes below it. A "partial" state transfer is one where just a portion
- of the tree is transferred -- i.e. a node at a given Fqn and all nodes
- below it.
- </para>
-
- <para>If either in-memory or persistent state transfer is enabled, state
- transfer will occur at the following times:
- </para>
-
- <orderedlist>
- <listitem>
- <para>Initial state transfer. This occurs when the cache is first
- started (as part of the processing of the
- <literal>start()</literal>
- method). This is a full state transfer. The state is retrieved from
- the cache instance that has been operational the longest.
- <footnote>
- <para>The longest operating cache instance is always, in JGroups
- terms, the coordinator.
- </para>
- </footnote>
- If there is any problem receiving or integrating the state, the cache
- will not start.
- </para>
-
- <para>Initial state transfer will occur unless:</para>
-
- <orderedlist>
- <listitem>
- <para>The cache's
- <literal>InactiveOnStartup</literal>
- property
- is
- <literal>true</literal>
- . This property is used in
- conjunction with region-based marshalling.
- </para>
- </listitem>
-
- <listitem>
- <para>Buddy replication is used. See below for more on state
- transfer with buddy replication.
- </para>
- </listitem>
- </orderedlist>
- </listitem>
-
- <listitem>
- <para>Partial state transfer following region activation. When
- region-based marshalling is used, the application needs to register
- a specific class loader with the cache. This class loader is used
- to unmarshall the state for a specific region (subtree) of the cache.
- </para>
-
- <para>After registration, the application calls
- <literal>cache.getRegion(fqn, true).activate()</literal>
- ,
- which initiates a partial state transfer of the relevant subtree's
- state. The request is first made to the oldest cache instance in the
- cluster. However, if that instance responds with no state, it is then
- requested from each instance in turn until one either provides state
- or all instances have been queried.
- </para>
-
- <para>Typically when region-based marshalling is used, the cache's
- <literal>InactiveOnStartup</literal>
- property is set to
- <literal>true</literal>
- . This suppresses initial state transfer,
- which would fail due to the inability to deserialize the transferred
- state.
- </para>
- </listitem>
-
- <listitem>
- <para>Buddy replication. When buddy replication is used, initial
- state transfer is disabled. Instead, when a cache instance joins the
- cluster, it becomes the buddy of one or more other instances, and
- one or more other instances become its buddy. Each time an instance
- determines it has a new buddy providing backup for it, it pushes
- it's current state to the new buddy. This "pushing" of state to the
- new buddy is slightly different from other forms of state transfer,
- which are based on a "pull" approach (i.e. recipient asks for and
- receives state). However, the process of preparing and integrating
- the state is the same.
- </para>
-
- <para>This "push" of state upon buddy group formation only occurs if
- the
- <literal>InactiveOnStartup</literal>
- property is set to
- <literal>false</literal>
- . If it is
- <literal>true</literal>
- , state
- transfer amongst the buddies only occurs when the application
- activates the region on the various members of the group.
- </para>
-
- <para>Partial state transfer following a region activation call is
- slightly different in the buddy replication case as well. Instead of
- requesting the partial state from one cache instance, and trying all
- instances until one responds, with buddy replication the instance
- that is activating a region will request partial state from each
- instance for which it is serving as a backup.
- </para>
- </listitem>
- </orderedlist>
- </section>
-
- <section>
- <title>Transient ("in-memory") and persistent state transfer</title>
-
- <para>The state that is acquired and integrated can consist of two basic
- types:
- </para>
-
- <orderedlist>
- <listitem>
- <para>"Transient" or "in-memory" state. This consists of the actual
- in-memory state of another cache instance - the contents of the
- various in-memory nodes in the cache that is providing state are
- serialized and transferred; the recipient deserializes the data,
- creates corresponding nodes in its own in-memory tree, and populates
- them with the transferred data.
- </para>
-
- <para>"In-memory" state transfer is enabled by setting the cache's
- <literal>FetchInMemoryState</literal>
- configuration attribute to
- <literal>true</literal>
- .
- </para>
- </listitem>
-
- <listitem>
- <para>"Persistent" state. Only applicable if a non-shared cache
- loader is used. The state stored in the state-provider cache's
- persistent store is deserialized and transferred; the recipient
- passes the data to its own cache loader, which persists it to the
- recipient's persistent store.
- </para>
-
- <para>"Persistent" state transfer is enabled by setting a cache
- loader's
- <literal>fetchPersistentState</literal>
- attribute to
- <literal>true</literal>
- . If multiple cache loaders are configured
- in a chain, only one can have this property set to true; otherwise
- you will get an exception at startup.
- </para>
-
- <para>Persistent state transfer with a shared cache loader does not
- make sense, as the same persistent store that provides the data will
- just end up receiving it. Therefore, if a shared cache loader is
- used, the cache will not allow a persistent state transfer even if a
- cache loader has
- <literal>fetchPersistentState</literal>
- set to
- <literal>true</literal>
- .
- </para>
- </listitem>
- </orderedlist>
-
- <para>Which of these types of state transfer is appropriate depends on
- the usage of the cache.
- </para>
-
- <orderedlist>
- <listitem>
- <para>If a write-through cache loader is used, the current cache
- state is fully represented by the persistent state. Data may have
- been evicted from the in-memory state, but it will still be in the
- persistent store. In this case, if the cache loader is not shared,
- persistent state transfer is used to ensure the new cache has the
- correct state. In-memory state can be transferred as well if the
- desire is to have a "hot" cache -- one that has all relevant data in
- memory when the cache begins providing service. (Note that the
- <literal><![CDATA[<cacheloader><preload>]]></literal>
- element in the
- <literal>CacheLoaderConfig</literal>
- configuration parameter can be used as well to
- provide a "warm" or "hot" cache without requiring an in-memory state
- transfer. This approach somewhat reduces the burden on the cache
- instance providing state, but increases the load on the persistent
- store on the recipient side.)
- </para>
- </listitem>
-
- <listitem>
- <para>If a cache loader is used with passivation, the full
- representation of the state can only be obtained by combining the
- in-memory (i.e. non-passivated) and persistent (i.e. passivated)
- states. Therefore an in-memory state transfer is necessary. A
- persistent state transfer is necessary if the cache loader is not
- shared.
- </para>
- </listitem>
-
- <listitem>
- <para>If no cache loader is used and the cache is solely a
- write-aside cache (i.e. one that is used to cache data that can also
- be found in a persistent store, e.g. a database), whether or not
- in-memory state should be transferred depends on whether or not a
- "hot" cache is desired.
- </para>
- </listitem>
- </orderedlist>
- </section>
- <section>
- <title>Configuring State Transfer</title>
- <para>
- To ensure state transfer behaves as expected, it is important that all nodes in the cluster are configured
- with
- the same settings for persistent and transient state. This is because byte array based transfers, when
- requested,
- rely only on the requester's configuration while stream based transfers rely on both the requester and
- sender's
- configuration, and this is expected to be identical.
- </para>
- </section>
- </section>
-</chapter>
Added: pojo/trunk/src/main/docbook/userguide/en/modules/term.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/term.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/term.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -0,0 +1,127 @@
+<chapter id="term">
+
+ <title>Terminology</title>
+
+ <sect1 id="overview" revision="1">
+ <title>Overview</title>
+
+ <para>
+ The section lists some basic terminology that will be used throughout this guide.
+ </para>
+
+ <para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>Aop</term>
+ <listitem>
+ <para>
+ Aspect-Oriented Programming (AOP) is a new paradigm that allows you to organize
+ and layer your software applications in ways that are impossible with traditional
+ object-oriented approaches. Aspects allow you to transparently glue functionality together
+ so that you can have a more layered design. AOP allows you to intercept any event in a Java
+ program and trigger functionality based on those events.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>JBoss Aop</term>
+ <listitem>
+ <para>
+ JBoss Aop is an open-source Aop framework library developed by JBoss. It is 100% Java based and can be run
+ either
+ as a standalone or inside an application server environment. More details can be found at
+ www.jboss.com. PojoCache uses JBoss Aop library in two ways. It uses JBoss Aop firstly for its own
+ interceptor-based architecture and secondly to realize the fine-grained replication aspects.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Dynamic Aop</term>
+ <listitem>
+ <para>
+ Dynamic Aop is a feature of JBoss Aop that provides a hook so that a caller can insert event
+ interception on the POJO at runtime. PojoCache currently uses this feature to perform
+ field level interception.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>JGroups</term>
+ <listitem>
+ <para>
+ JGroups is a reliable Java group messaging library that is open-source and LGPL. In addition to reliable
+ messaging transport, it also performs group membership management. It has been a de facto
+ replication layer used by numerous open-source projects for clustering purposes. It is also used by
+ JBossCache for replication layer.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Core Cache</term>
+ <listitem>
+ <para>
+ Core Cache is a tree-structured, clustered, transactional cache. Simple and Serializable java types
+ are stored as key/value pairs on nodes within the tree using a collection-like API. It also provides
+ a number of configurable aspects such as node locking strategies, data isolation, eviction, and so on.
+ POJO Cache leverages Core Cache as the underlying data-store in order to provide the same capabilities.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>POJO</term>
+ <listitem>
+ <para>
+ Plain old Java object.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Annotation</term>
+ <listitem>
+ <para>
+ Annotation is a new feature in JDK5.0. It introduces metadata along side the Java code that can
+ be accessed at runtime. PojoCache currently uses JDK50 annotation to support POJO
+ instrumentation (JDK1.4 annotation has been deprecated since release 2.0).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Prepare</term>
+ <listitem>
+ <para>
+ Prepare is a keyword in JBoss Aop pointcut language used to specify which POJO needs to be
+ instrumented. It appears in a <literal>pojocache-aop.xml</literal> file. However, if you can
+ use annotation to specify the POJO instrumentation, there is no
+ need for a <literal>pojocache-aop.xml</literal> listing. Note that
+ When a POJO is declared properly either through the xml or annotation, we consider it "aspectized".
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Instrumentation</term>
+ <listitem>
+ <para>
+ Instrumentation is an Aop process that basically pre-processes (e.g., performing byte-code
+ weaving)
+ on the POJO. There are two modes: compile- or load-time. Compile-time weaving can be done with
+ an Aop precompiler (<literal>aopc</literal>) while load-time is done to specify a special classloader
+ in the run script.
+ This step is necessary for an Aop system to intercept events that are interesting to users.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect1>
+
+</chapter>
+
Property changes on: pojo/trunk/src/main/docbook/userguide/en/modules/term.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: pojo/trunk/src/main/docbook/userguide/en/modules/transactions.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/transactions.xml 2007-08-14 16:34:22 UTC (rev 4250)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/transactions.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -1,345 +0,0 @@
-<chapter id="transactions">
- <title>Transactions and Concurrency</title>
- <section>
- <title>Concurrent Access</title>
-
- <para>JBoss Cache is a thread safe caching API, and uses its own efficient mechanisms of controlling concurrent
- access. It uses a pessimistic locking scheme by default for this purpose. Optimistic locking may alternatively
- be used, and is discussed later.
- </para>
-
- <section>
- <title>Locks</title>
- <para>Locking is done internally, on a node-level. For example when we
- want to access "/a/b/c", a lock will be acquired for nodes "a", "b" and
- "c". When the same transaction wants to access "/a/b/c/d", since we
- already hold locks for "a", "b" and "c", we only need to acquire a lock
- for "d".
- </para>
- <para>Lock owners are either transactions (call is made within the scope of an existing transaction)
- or threads (no transaction associated with the call).
- Regardless, a transaction or a thread is internally transformed into
- an instance of
- <literal>GlobalTransaction</literal>
- , which is used as a globally unique identifier
- for modifications across a cluster. E.g. when we run a two-phase commit
- protocol across the cluster, the
- <literal>GlobalTransaction</literal>
- uniquely identifies a unit of work across a cluster.
- </para>
-
- <para>Locks can be read or write locks. Write locks serialize read and
- write access, whereas read-only locks only serialize read access. When a
- write lock is held, no other write or read locks can be acquired. When a
- read lock is held, others can acquire read locks. However, to acquire
- write locks, one has to wait until all read locks have been released. When
- scheduled concurrently, write locks always have precedence over read
- locks. Note that (if enabled) read locks can be upgraded to write
- locks.
- </para>
-
- <para>Using read-write locks helps in the following scenario: consider a
- tree with entries "/a/b/n1" and "/a/b/n2". With write-locks, when Tx1
- accesses "/a/b/n1", Tx2 cannot access "/a/b/n2" until Tx1 has completed
- and released its locks. However, with read-write locks this is possible,
- because Tx1 acquires read-locks for "/a/b" and a read-write lock for
- "/a/b/n1". Tx2 is then able to acquire read-locks for "/a/b" as well, plus
- a read-write lock for "/a/b/n2". This allows for more concurrency in
- accessing the cache.
- </para>
- </section>
-
- <section>
- <title>Pessimistic locking</title>
- <para>By default, JBoss Cache uses pessimistic locking. Locking is not exposed directly to user. Instead, a
- transaction isolation level which provides different locking behaviour is configurable.
- </para>
- <section>
- <title>Isolation levels</title>
- <para>JBoss Cache supports the following transaction isolation levels, analogous to database ACID isolation
- levels. A user can configure an instance-wide isolation level of NONE, READ_UNCOMMITTED, READ_COMMITTED,
- REPEATABLE_READ, or SERIALIZABLE. REPEATABLE_READ is the default isolation level used.
- </para>
-
- <orderedlist>
- <listitem>
- <para>NONE. No transaction support is needed. There is no locking at
- this level, e.g., users will have to manage the data integrity.
- Implementations use no locks.
- </para>
- </listitem>
-
- <listitem>
- <para>READ_UNCOMMITTED. Data can be read anytime while write
- operations are exclusive. Note that this level doesn't prevent the
- so-called "dirty read" where data modified in Tx1 can be read in Tx2
- before Tx1 commits. In other words, if you have the following
- sequence,
- <programlisting>
- <![CDATA[
- Tx1 Tx2
- W
- R
-]]>
- </programlisting>
-
- using this isolation level will not prevent Tx2 read operation.
- Implementations typically use an exclusive lock for writes while reads
- don't need to acquire a lock.
- </para>
- </listitem>
-
- <listitem>
- <para>READ_COMMITTED. Data can be read any time as long as there is no
- write. This level prevents the dirty read. But it doesn’t prevent the
- so-called ‘non-repeatable read’ where one thread reads the data twice
- can produce different results. For example, if you have the following
- sequence,
- <programlisting>
- <![CDATA[
- Tx1 Tx2
- R
- W
- R
-]]>
- </programlisting>
- </para>
-
- <para>where the second read in Tx1 thread will produce different
- result.
- </para>
-
- <para>Implementations usually use a read-write lock; reads succeed
- acquiring the lock when there are only reads, writes have to wait
- until there are no more readers holding the lock, and readers are
- blocked acquiring the lock until there are no more writers holding the
- lock. Reads typically release the read-lock when done, so that a
- subsequent read to the same data has to re-acquire a read-lock; this
- leads to nonrepeatable reads, where 2 reads of the same data might
- return different values. Note that, the write only applies regardless
- of transaction state (whether it has been committed or not).
- </para>
- </listitem>
-
- <listitem>
- <para>REPEATABLE_READ. Data can be read while there is no write and
- vice versa. This level prevents "non-repeatable read" but it does not
- completely prevent the so-called "phantom read" where new data can be
- inserted into the tree from another transaction. Implementations
- typically use a read-write lock. This is the default isolation level used.
- </para>
- </listitem>
-
- <listitem>
- <para>SERIALIZABLE. Data access is synchronized with exclusive locks.
- Only 1 writer or reader can have the lock at any given time. Locks are
- released at the end of the transaction. Regarded as very poor for performance and
- thread/transaction concurrency.
- </para>
- </listitem>
- </orderedlist>
-
- </section>
-
- <section>
- <title>Insertion and Removal of Nodes</title>
-
- <para>
- By default, before inserting a new node into the tree or removing an existing node from the
- tree, JBoss Cache will only attempt to acquire a read lock on the new node's parent node.
- This approach does not treat child nodes as an integral part of a parent node's state.
- This approach allows greater concurrency if nodes are frequently added or removed, but
- at a cost of lesser correctness. For use cases where greater correctness is necessary, JBoss
- Cache provides a configuration option
- <literal>LockParentForChildInsertRemove</literal>
- .
- If this is set to
- <literal>true</literal>
- , insertions and removals of child nodes
- require the acquisition of a
- <emphasis>write lock</emphasis>
- on the parent node.
- </para>
- </section>
- </section>
-
- <section>
- <title>Optimistic Locking</title>
- <para>The motivation for optimistic locking is to improve concurrency. When a lot of threads have a lot of
- contention for access to the data tree, it can be inefficient to lock portions of the tree - for reading or
- writing - for the entire duration of a transaction as we do in pessimistic locking. Optimistic locking
- allows for greater concurrency of threads and transactions by using a technique called data versioning,
- explained here. Note that isolation levels (if configured) are ignored if optimistic locking is enabled.
- </para>
- <section>
- <title>Architecture</title>
- <para>Optimistic locking treats all method calls as transactional
- <footnote>
- <para>Because of this requirement, you must always have a transaction manager configured when using
- optimistic locking.
- </para>
- </footnote>
- . Even if you do not invoke a call within the scope of an ongoing transaction, JBoss Cache creates an
- <emphasis>implicit transaction</emphasis>
- and commits this transaction when the invocation completes. Each transaction
- maintains a transaction workspace, which contains a copy of the data used within the transaction.
- </para>
- <para>For example, if a transaction calls
- <literal>cache.getRoot().getChild( Fqn.fromString("/a/b/c") )</literal>
- ,
- nodes a, b and c are copied from the main data tree
- and into the workspace. The data is versioned and all calls in the transaction work on the copy of the
- data rather than the actual data. When the transaction commits, its workspace is merged back into the
- underlying tree by matching versions. If there is a version mismatch - such as when the actual data tree
- has a higher version than the workspace, perhaps if another transaction were to access the same data,
- change it and commit before the first transaction can finish - the transaction throws a
- <literal>RollbackException</literal>
- when committing and the commit fails.
- </para>
- <para>Optimistic locking uses the same locks we speak of above, but the locks are only held for a very short
- duration - at the start of a transaction to build a workspace, and when the transaction commits and has
- to merge data back into the tree.
- </para>
- <para>
- So while optimistic locking may occasionally fail if version validations fail or may run slightly slower
- than pessimistic locking due to the inevitable overhead and extra processing of maintaining workspaces,
- versioned data and validating on commit, it does buy you a near-SERIALIZABLE degree of data integrity
- while maintaining a very high level of concurrency.
- </para>
- </section>
- <section>
- <title>Data Versioning</title>
- <mediaobject>
- <imageobject>
- <imagedata fileref="DataVersions.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- <para>
- Optimistic locking makes use of the
- <literal>DataVersion</literal>
- interface (and an internal and default
- <literal>DefaultDataVersion</literal>
- implementation to keep a track of node versioning. In certain cases,
- where cached data is an in-memory representation of data from an external source such as a database,
- it makes sense to align the versions used in JBoss Cache with the versions used externally. As such,
- using the
- <link linkend="configuration.options">options API</link>
- , it is possible to set the
- <literal>DataVersion</literal>
- you wish to use on a per-invocation basis, allowing you to implement the
- <literal>DataVersion</literal>
- interface to hold the versioning information obtained externally before putting your data into the
- cache.
- </para>
- </section>
- <section>
- <title>Configuration</title>
- Optimistic locking is enabled by using the NodeLockingScheme XML attribute, and setting it to "OPTIMISTIC":
- <programlisting>
- <![CDATA[
- ...
- <!--
- Node locking scheme:
- OPTIMISTIC
- PESSIMISTIC (default)
- -->
- <attribute name="NodeLockingScheme">OPTIMISTIC</attribute>
- ...
- ]]>
- </programlisting>
- </section>
- </section>
- </section>
-
-
- <section>
- <title>Transactional Support</title>
-
- <para>JBoss Cache can be configured to use and participate in JTA compliant transactions. Alternatively, if
- transaction support is disabled, it is equivalent to setting AutoCommit to
- on where modifications are potentially
- <footnote>
- <para>Depending on whether interval-based asynchronous replication is used</para>
- </footnote>
- replicated after every change (if replication is
- enabled).
- </para>
-
- <para>What JBoss Cache does on every incoming call is:</para>
- <orderedlist>
- <listitem>
- <para>Retrieve the current
- <literal>javax.transaction.Transaction</literal>
- associated with the thread
- </para>
- </listitem>
- <listitem>
- <para>If not already done, register a
- <literal>javax.transaction.Synchronization</literal>
- with the transaction manager to be notified when a transaction commits
- or is rolled back.
- </para>
- </listitem>
- </orderedlist>
- <para>
- In order to do this, the cache has to be provided with a
- reference to environment's
- <literal>javax.transaction.TransactionManager</literal>
- . This is usually done by configuring the cache
- with the class name of an implementation of the
- <literal>TransactionManagerLookup</literal>
- interface. When the cache starts, it will create an instance of this
- class and invoke its <literal>getTransactionManager()</literal>
- method, which returns a reference to the
- <literal>TransactionManager</literal>
- .
- </para>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="TransactionLookup.png" format="PNG"/>
- </imageobject>
- </mediaobject>
-
- <para>JBoss Cache ships with
- <literal>JBossTransactionManagerLookup</literal>
- and
- <literal>GenericTransactionManagerLookup</literal>
- . The
- <literal>JBossTransactionManagerLookup</literal>
- is able to bind to a running JBoss AS instance and retrieve a
- <literal>TransactionManager</literal>
- while the
- <literal>GenericTransactionManagerLookup</literal>
- is able to bind to most popular Java EE application servers and provide the same functionality. A dummy
- implementation -
- <literal>DummyTransactionManagerLookup</literal>
- - is also provided, primarily for unit tests. Being a dummy, this is just for demo and testing purposes and is
- not recommended for production use.
- </para>
-
- <para>
- An alternative to configuring a <literal>TransactionManagerLookup</literal>
- is to programatically inject a reference to the <literal>TransactionManager</literal>
- into the <literal>Configuration</literal> object's <literal>RuntimeConfig</literal> element:
- </para>
-
- <programlisting>
- TransactionManager tm = getTransactionManager(); // magic method
- cache.getConfiguration().getRuntimeConfig().setTransactionManager(tm);
- </programlisting>
-
- <para>
- Injecting the <literal>TransactionManager</literal> is the recommended
- approach when the <literal>Configuration</literal> is built by some sort of
- IOC container that already has a reference to the TM.
- </para>
-
- <para>When the transaction commits, we initiate either a one- two-phase commit
- protocol. See
- <link linkend="replication.tx">replicated caches and transactions</link>
- for details.
- </para>
-
- </section>
-</chapter>
Added: pojo/trunk/src/main/docbook/userguide/en/modules/troubleshooting.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/troubleshooting.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/troubleshooting.xml 2007-08-14 19:09:32 UTC (rev 4251)
@@ -0,0 +1,17 @@
+<chapter id="trouble">
+<title>TroubleShooting</title>
+
+ <para>We have maintained a
+ <ulink
+ url="http://wiki.jboss.org/wiki/Wiki.jsp?page=PojoCacheTroubleshooting">PojoCache wiki troubleshooting page</ulink>.
+ Please refer it first. We will keep adding troubleshooting tips there.
+ </para>
+ <para>All the current outstanding issues are documented in
+ <ulink
+ url="http://jira.jboss.com/jira/secure/BrowseProject.jspa?id=10051">JBossCache
+ Jira page</ulink>
+ . Please check it for details. If you have discovered
+ additional issues, please report it there as well.
+ </para>
+
+</chapter>
\ No newline at end of file
Property changes on: pojo/trunk/src/main/docbook/userguide/en/modules/troubleshooting.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
17 years, 4 months
JBoss Cache SVN: r4250 - core/trunk.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2007-08-14 12:34:22 -0400 (Tue, 14 Aug 2007)
New Revision: 4250
Removed:
core/trunk/ant-dist/
core/trunk/build.bat
core/trunk/build.properties
core/trunk/build.sh
core/trunk/build.xml
core/trunk/build_reports.bat
core/trunk/deploy-maven.sh
Log:
Removed unnecessary ant related files
Deleted: core/trunk/build.bat
===================================================================
--- core/trunk/build.bat 2007-08-14 16:31:29 UTC (rev 4249)
+++ core/trunk/build.bat 2007-08-14 16:34:22 UTC (rev 4250)
@@ -1,4 +0,0 @@
-@echo off
-set ANT_HOME=.\ant-dist
-REM java -cp %ANT_HOME%/lib/ant.jar;%ANT_HOME%/lib/optional.jar;%ANT_HOME%/lib/junit.jar;%JAVA_HOME%/lib/tools.jar org.apache.tools.ant.Main %1 %2 %3 %4 %5
-%ANT_HOME%\bin\ant %1 %2 %3 %4 %5
Deleted: core/trunk/build.properties
===================================================================
--- core/trunk/build.properties 2007-08-14 16:31:29 UTC (rev 4249)
+++ core/trunk/build.properties 2007-08-14 16:34:22 UTC (rev 4250)
@@ -1,2 +0,0 @@
-# add your own properties in here
-bind.address=127.0.0.1
\ No newline at end of file
Deleted: core/trunk/build.sh
===================================================================
--- core/trunk/build.sh 2007-08-14 16:31:29 UTC (rev 4249)
+++ core/trunk/build.sh 2007-08-14 16:34:22 UTC (rev 4250)
@@ -1,27 +0,0 @@
-#!/bin/sh
-
-CACHE_HOME=`dirname $0`
-ANT_HOME=$CACHE_HOME/ant-dist
-
-#CLASSPATH=$ANT_HOME/lib/ant.jar:$ANT_HOME/lib/optional.jar:$ANT_HOME/lib/junit.jar:$JAVA_HOME/lib/tools.jar
-
-# OS specific support (must be 'true' or 'false').
-#cygwin=false;
-#case "`uname`" in
-# CYGWIN*)
-# cygwin=true
-# ;;
-#esac
-
-#if [ $cygwin = "true" ]; then
-# Note that JAVA_HOME evn needs to be set under cygwin explictly,
-# /cygdrive/e:/j2sdkxxx, for this to work correctly. Otherwise,
-# javac can't be located correctly.
-# CP=`cygpath -wp $CLASSPATH`
-#else
-# CP=$CLASSPATH
-#fi
-
-#java -cp $CP org.apache.tools.ant.Main "$@"
-$ANT_HOME/bin/ant "$@"
-
Deleted: core/trunk/build.xml
===================================================================
--- core/trunk/build.xml 2007-08-14 16:31:29 UTC (rev 4249)
+++ core/trunk/build.xml 2007-08-14 16:34:22 UTC (rev 4250)
@@ -1,1652 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!-- $Id$ -->
-
-<project default="compile" name="JBossCache">
-
- <property name="module.name" value="JBossCache"/>
- <!--We now requires version to have no white space since Ant+JBossAop will sometime choke. -->
- <property name="module.version" value="2.0.0.GA"/>
- <property name="implementation.url" value="http://www.jboss.com/products/jbosscache"/>
- <property file="build.properties"/>
- <property name="root.dir" value="${basedir}"/>
- <property name="doc.dir" value="${root.dir}/docs"/>
- <property name="src.dir" value="${root.dir}/src"/>
- <property name="tests.dir" value="${root.dir}/tests"/>
- <property name="examples.dir" value="${root.dir}/examples"/>
- <property name="functional.tests.dir" value="${tests.dir}/functional"/>
- <property name="stress.tests.dir" value="${tests.dir}/stress"/>
- <property name="interop.tests.dir" value="${tests.dir}/interop"/>
- <property name="clover.dir" value="${root.dir}/clover"/>
- <property name="perf.tests.dir" value="${tests.dir}/perf"/>
- <property name="interop.tests.dir" value="${tests.dir}/interop"/>
- <property name="compat.tests.dir" value="${tests.dir}/compat"/>
- <property name="etc.dir" value="${root.dir}/etc"/>
- <property name="dependencies" value="dependencies.xml"/>
- <property name="resources.dir" value="${root.dir}/src/resources"/>
- <property name="tmp.dir" value="${root.dir}/tmp"/>
- <property name="output.dir" value="${root.dir}/output"/>
- <property name="output.etc.dir" value="${output.dir}/etc"/>
- <property name="output.interop.dir" value="${output.dir}/interop"/>
- <property name="compile.dir" value="${output.dir}/classes"/>
- <property name="compiletest.dir" value="${output.dir}/test-classes"/>
- <property name="retro.compile.dir" value="${output.dir}/classes14"/>
- <property name="retro.compiletest.dir" value="${output.dir}/test-classes14"/>
- <property name="lib.dir" value="${root.dir}/lib"/>
- <property name="berkeleydb.lib.dir" value="${lib.dir}/berkeleydb"/>
- <property name="retro.lib.dir" value="${lib.dir}/retro"/>
- <property name="dist.dir" value="${root.dir}/dist"/>
- <property name="dist.lib" value="${dist.dir}/lib"/>
- <property name="build.reports" value="${output.dir}/reports"/>
- <property name="build.reports.html" value="${build.reports}/html"/>
- <property name="build.lib" value="${output.dir}/lib"/>
- <property name="build.api" value="${output.dir}/api"/>
- <property name="build.etc" value="${root.dir}/etc"/>
- <property name="javadoc.packages" value="org.jboss.cache.*"/>
- <property name="junit.timeout" value="500000"/>
- <property name="junit.timeout.stresstest" value="6000000"/>
- <property name="junit.timeout.performance" value="60000"/>
- <property name="junit.timeout.compat" value="300000"/>
- <property name="junit.batchtest.todir" value="${build.reports}"/>
- <property name="junit.jvm.options" value="-Ddummy"/>
- <property name="ant.dir" value="${root.dir}/ant-dist"/>
- <property name="manifest.file" value="${dist.lib}/default.mf"/>
- <property name="migration.dir" value="${root.dir}/migration"/>
- <property name="migration.src.dir" value="${migration.dir}/src"/>
- <property name="migration.lib.dir" value="${migration.dir}/lib"/>
- <property name="migration.output.dir" value="${migration.dir}/output"/>
- <property name="migration.compile.dir" value="${migration.output.dir}/classes"/>
- <property name="migration.compiletest.dir" value="${migration.output.dir}/test-classes"/>
- <property name="migration.examples.dir" value="${migration.dir}/examples"/>
- <property name="migration.jar.name" value="jbosscache-cacheloader-migration.jar"/>
- <property name="migration.manifest.file" value="${dist.lib}/migration.default.mf"/>
- <property name="migration.functional.tests.dir" value="${migration.dir}/tests/functional"/>
- <property name="migration.perf.tests.dir" value="${migration.dir}/tests/perf"/>
- <property name="cache.db.dir" value="${root.dir}/jbossdb"/>
- <property name="cache.db.1x.dir" value="${cache.db.dir}-1x"/>
- <!-- -->
- <condition property="ENABLE_COMPAT_TESTS">
- <or>
- <equals arg1="${ant.java.version}" arg2="1.5"/>
- <equals arg1="${ant.java.version}" arg2="1.4"/>
- </or>
- </condition>
- <property name="src.dir.50" value="${root.dir}/src"/>
- <property name="tests.dir.50" value="${root.dir}/tests"/>
- <property name="output.resources.dir" value="${output.dir}/resources"/>
- <property name="functional.tests.dir.50" value="${tests.dir.50}/functional"/>
- <property name="perf.tests.dir.50" value="${tests.dir.50}/perf"/>
- <property name="resources.dir.50" value="${src.dir.50}/resources"/>
- <property name="deprecation" value="off"/>
-
-
- <!-- Tests that are currently broken - "known failures" to be excluded when running all-unittests-cc -->
- <!--
- Only one test per line. Please add a comment with a reference to a JIRA task about this failure.
- -->
- <patternset id="known.failures">
- <!-- See JBCACHE-858 -->
- <exclude name="org/jboss/cache/pojo/collection/ReplicatedSyncSetTest*"/>
-
- <!-- See JBCACHE-315 -->
- <exclude name="org/jboss/cache/statetransfer/StateTransferUnderLoadTest*"/>
- <!-- See JBCACHE-641 -->
- <exclude name="org/jboss/cache/eviction/ReplicatedLRUPolicyTest*"/>
- <!-- See JBCACHE-407 -->
- <exclude name="org/jboss/cache/transaction/IsolationLevelReadCommittedNodeCreationRollbackTest*"/>
- <!-- See JBCACHE-462 -->
- <exclude name="org/jboss/cache/aop/eviction/AopLRUPolicyUpdateEvictionTest*"/>
- <!-- See JBCACHE-461 -->
- <exclude name="org/jboss/cache/lock/ReentrantWriterPreference2Readers1WriterLockTest*"/>
- <!-- See JBCACHE-479 -->
- <exclude name="org/jboss/cache/aop/loader/FileCacheLoaderAopCollectionsTest*"/>
- <!-- See JBCACHE-477 -->
- <exclude name="org/jboss/cache/aop/collection/CachedListAopTxTest*"/>
- <!-- See JBCACHE-315 -->
- <exclude name="org/jboss/cache/statetransfer/ForcedStateTransferTest*"/>
- <!-- See JBCACHE-654 -->
- <exclude name="org/jboss/cache/aop/memory/ReplicatedAopTest*"/>
- <!-- See JBCACHE-1035 -->
- <exclude name="org/jboss/cache/pojo/statetransfer/StateTransfer200AopTest*"/>
- <!-- manual tests - tests that are not supposed to be run by CC for whatever reason -->
- <exclude name="**/manualtests/**"/>
- </patternset>
-
- <patternset id="junit.excludes">
- <!-- ALWAYS leave this empty - it is populated later on depending on type of test run -->
- </patternset>
-
- <path id="library.classpath">
- <fileset dir="${lib.dir}">
- <include name="*.jar"/>
- </fileset>
- <fileset dir="${berkeleydb.lib.dir}">
- <include name="*.jar"/>
- </fileset>
- <pathelement path="${ant.dir}/lib/clover.jar"/>
- </path>
-
- <path id="retro.library.classpath">
- <fileset dir="${retro.lib.dir}">
- <include name="*.jar"/>
- </fileset>
- <!-- ant libs are needed as well -->
- <fileset dir="${ant.dir}/lib">
- <include name="*.jar"/>
- </fileset>
- </path>
-
- <path id="migration.library.classpath">
- <fileset dir="${retro.lib.dir}">
- <include name="jboss-logging-spi.jar"/>
- </fileset>
- <fileset dir="${migration.lib.dir}">
- <include name="*.jar"/>
- </fileset>
- </path>
-
- <path id="output.classpath">
- <pathelement location="${compile.dir}"/>
- <pathelement location="${output.etc.dir}"/>
- <pathelement location="${compiletest.dir}"/>
- <pathelement location="${output.resources.dir}"/>
- <pathelement location="${functional.tests.dir}"/>
- </path>
-
- <path id="retro.output.classpath">
- <pathelement location="${retro.compile.dir}"/>
- <pathelement location="${output.etc.dir}"/>
- <pathelement location="${retro.compiletest.dir}"/>
- <pathelement location="${output.resources.dir}"/>
- <fileset dir="${retro.lib.dir}">
- <include name="*.jar"/>
- </fileset>
- </path>
-
- <path id="migration.output.classpath">
- <pathelement location="${migration.compile.dir}"/>
- <pathelement location="${migration.compiletest.dir}"/>
- <pathelement location="${output.etc.dir}"/>
- </path>
-
- <path id="previous.version.classpath">
- <pathelement location="${output.etc.dir}"/>
- <pathelement location="${compiletest.dir}"/>
- <fileset dir="${lib.dir}">
- <include name="*.jar"/>
- </fileset>
- <fileset dir="${output.interop.dir}">
- <include name="*.jar"/>
- </fileset>
- </path>
-
- <path id="current.version.classpath">
- <fileset dir="${lib.dir}">
- <include name="*.jar"/>
- </fileset>
- <fileset dir="${berkeleydb.lib.dir}">
- <include name="*.jar"/>
- </fileset>
- <pathelement location="${compile.dir}"/>
- <pathelement location="${output.etc.dir}"/>
- <pathelement location="${compiletest.dir}"/>
- </path>
-
- <path id="migration.classpath">
- <fileset dir="${lib.dir}">
- <include name="*.jar"/>
- </fileset>
- <fileset dir="${migration.lib.dir}">
- <include name="*.jar"/>
- </fileset>
- <pathelement location="${compile.dir}"/>
- <pathelement location="${migration.compile.dir}"/>
- </path>
-
- <!-- ================================================================== -->
- <!-- Compile -->
- <!-- ================================================================== -->
- <target name="compile" depends="compile-cache, compile-pojocache, compile-migration"
- description="Compiles all Java files">
- </target>
-
- <target name="compile-cache" description="Compiles all Java files">
-
- <mkdir dir="${compile.dir}"/>
- <mkdir dir="${compiletest.dir}"/>
-
- <!-- compile JBossCache Java code -->
- <javac destdir="${compile.dir}"
- debug="on"
- deprecation="${deprecation}"
- optimize="off"
- includes="**/*.java"
- target="1.5"
- source="1.5"
- failonerror="true">
- <src path="${src.dir}"/>
- <classpath refid="library.classpath"/>
- <exclude name="**/obsolete/**"/>
- <exclude name="**/*1_4*"/>
- </javac>
-
- <!-- compile test classes -->
- <javac destdir="${compiletest.dir}"
- debug="on"
- deprecation="${deprecation}"
- optimize="off"
- includes="**/*.java"
- target="1.5"
- source="1.5"
- failonerror="true">
- <src path="${functional.tests.dir}"/>
- <src path="${stress.tests.dir}"/>
- <src path="${perf.tests.dir}"/>
- <src path="${interop.tests.dir}"/>
- <src path="${compat.tests.dir}"/>
- <classpath path="${compile.dir}"/>
- <classpath refid="library.classpath"/>
- <exclude name="**/obsolete/**"/>
- <exclude name="**/*1_4*"/>
- <exclude name="**/aop/**"/>
- </javac>
-
- <copy todir="${output.etc.dir}" filtering="no" overwrite="yes">
- <fileset dir="${etc.dir}">
- <include name="META-INF/*.xml"/>
- <include name="log4j.xml"/>
- <!-- The following copies the cache-jdbc.properties file for
- running jdbc cache loader test against different DBMS -->
- <include name="cache-jdbc.properties"/>
- </fileset>
- </copy>
-
- <copy todir="${output.resources.dir}" filtering="no" overwrite="yes">
- <fileset dir="${resources.dir}">
- <include name="*.xml"/>
- </fileset>
- </copy>
- </target>
-
- <target name="compile-pojocache" depends="aopc-pojocache">
- </target>
-
- <target name="aopc-pojocache" depends="compile-pojocache-1"
- description="Precompile aop classes">
- <taskdef name="aopc" classname="org.jboss.aop.ant.AopC" classpathref="library.classpath"/>
- <aopc compilerclasspathref="library.classpath" verbose="false">
- <src path="${compile.dir}"/>
- <include name="org/jboss/cache/pojo/impl/*.class"/>
- <include name="org/jboss/cache/pojo/collection/*.class"/>
- <aoppath path="${output.resources.dir}/pojocache-aop.xml"/>
- <classpath>
- <path refid="output.classpath"/>
- </classpath>
- </aopc>
- </target>
-
- <target name="compile-pojocache-1">
- <mkdir dir="${compile.dir}"/>
- <mkdir dir="${compiletest.dir}"/>
-
- <javac destdir="${compile.dir}"
- optimize="off"
- target="1.5"
- source="1.5"
- debug="on"
- deprecation="${deprecation}"
- failonerror="true">
- <src path="${src.dir.50}"/>
- <classpath refid="library.classpath"/>
- <classpath path="${compile.dir}"/>
- </javac>
- <!-- compile test classes -->
- <javac destdir="${compiletest.dir}"
- debug="on"
- deprecation="${deprecation}"
- optimize="off"
- includes="**/*.java"
- target="1.5"
- source="1.5"
- failonerror="true">
- <src path="${functional.tests.dir.50}"/>
- <!-- src path="${perf.tests.dir.50}"/ -->
- <classpath path="${compile.dir}"/>
- <classpath refid="library.classpath"/>
- <exclude name="**/aop/**"/>
- </javac>
- </target>
-
- <target name="jbossretro" depends="compile-cache"
- description="Weave the classes compiled in the compile-cache target for JDK 1.4.0 compatibility">
-
- <taskdef name="retro" classname="org.jboss.ant.tasks.retro.Retro">
- <classpath refid="retro.library.classpath"/>
- </taskdef>
-
- <mkdir dir="${retro.compile.dir}"/>
-
- <echo>Retroweaving core source code</echo>
- <retro destdir="${retro.compile.dir}">
- <classpath refid="library.classpath"/>
- <classpath refid="retro.library.classpath"/>
- <classpath path="${compile.dir}"/>
- <src path="${compile.dir}"/>
- <exclude name="**/obsolete/**"/>
- <exclude name="**/pojo/**"/>
- </retro>
-
- <!-- now the tests -->
- <echo>Retroweaving test classes</echo>
- <mkdir dir="${retro.compiletest.dir}"/>
- <retro destdir="${retro.compiletest.dir}">
- <classpath refid="library.classpath"/>
- <classpath refid="retro.library.classpath"/>
- <classpath path="${retro.compile.dir}"/>
- <classpath path="${compiletest.dir}"/>
- <src path="${compiletest.dir}"/>
- <exclude name="**/obsolete/**"/>
- <exclude name="**/pojo/**"/>
- </retro>
-
- </target>
-
- <target name="compile-migration" description="Compiles migration Java files">
- <mkdir dir="${migration.compile.dir}"/>
- <mkdir dir="${migration.compiletest.dir}"/>
-
- <!-- compile cache loader migration Java code -->
- <javac destdir="${migration.compile.dir}"
- debug="on"
- deprecation="${deprecation}"
- optimize="off"
- includes="**/*.java"
- target="1.5"
- source="1.5"
- failonerror="true">
- <src path="${migration.src.dir}"/>
- <classpath refid="migration.classpath"/>
- </javac>
-
- <!-- compile cache loader migration test classes -->
- <javac destdir="${migration.compiletest.dir}"
- debug="on"
- deprecation="${deprecation}"
- optimize="off"
- includes="**/*.java"
- target="1.5"
- source="1.5"
- failonerror="true">
- <src path="${migration.functional.tests.dir}"/>
- <classpath refid="migration.classpath"/>
- <classpath refid="library.classpath"/>
- <classpath refid="migration.library.classpath"/>
- <classpath path="${compile.dir}"/>
- <classpath path="${compiletest.dir}"/>
- <classpath path="${migration.compile.dir}"/>
- </javac>
-
- </target>
-
- <!-- ================================================================== -->
- <!-- Create jbosscache.jar -->
- <!-- ================================================================== -->
- <target name="jar" description="Builds jbosscache.jar"
- depends="compile, manifest, jar-cache, jar-pojocache, jar-migration">
- </target>
-
- <target name="jar-retro" description="Builds JDK 1.4.0-compatible jbosscache.jar"
- depends="jbossretro, manifest-retro">
- <mkdir dir="${dist.lib}"/>
- <jar jarfile="${dist.lib}/jbosscache-JDK140.jar" manifest="${manifest.file}">
- <fileset dir="${retro.compile.dir}">
- <include name="org/jboss/cache/**"/>
- <exclude name="org/jboss/cache/aop/**"/>
- <exclude name="org/jboss/cache/pojo/**"/>
- </fileset>
- <fileset dir="${etc.dir}">
- <include name="${dependencies}"/>
- </fileset>
- </jar>
- <delete file="${manifest.file}"/>
- </target>
-
- <target name="jar-cache" depends="compile-cache, manifest" description="Builds core jbosscache.jar">
- <mkdir dir="${dist.lib}"/>
- <jar jarfile="${dist.lib}/jbosscache.jar" manifest="${manifest.file}">
- <fileset dir="${compile.dir}">
- <include name="org/jboss/cache/**"/>
- <exclude name="org/jboss/cache/aop/**"/>
- <exclude name="org/jboss/cache/pojo/**"/>
- </fileset>
- <fileset dir="${etc.dir}">
- <include name="${dependencies}"/>
- </fileset>
- </jar>
- <delete file="${manifest.file}"/>
- </target>
-
- <target name="jar-pojocache" depends="compile-pojocache, manifest-pc" description="Builds pojocache.jar">
- <mkdir dir="${dist.lib}"/>
- <jar jarfile="${dist.lib}/pojocache.jar" manifest="${manifest.file}">
- <fileset dir="${compile.dir}">
- <include name="org/jboss/cache/pojo/**"/>
- </fileset>
- <fileset dir="${etc.dir}">
- <include name="${dependencies}"/>
- </fileset>
- </jar>
- <delete file="${manifest.file}"/>
- </target>
-
- <target name="jar-migration" depends="compile-cache, compile-migration, manifest-migration"
- description="Builds cache loader migration library, ${migration.jar.name}">
- <mkdir dir="${dist.lib}"/>
- <jar jarfile="${dist.lib}/${migration.jar.name}" manifest="${manifest.file}">
- <fileset dir="${migration.compile.dir}">
- <include name="org/jboss/cache/**"/>
- </fileset>
- <fileset dir="${etc.dir}">
- <include name="${dependencies}"/>
- </fileset>
- <zipfileset src="${migration.lib.dir}/jboss-minimal.jar"/>
- <zipfileset src="${retro.lib.dir}/jboss-logging-spi.jar"/>
- </jar>
- <delete file="${manifest.file}"/>
- </target>
-
- <target name="manifest">
- <tstamp/>
- <mkdir dir="${dist.lib}"/>
- <manifest file="${manifest.file}">
- <attribute name="Built-By" value="${user.name}"/>
- <attribute name="Created-On" value="${TODAY}"/>
- <attribute name="Main-Class" value="org.jboss.cache.Version"/>
- <attribute name="Specification-Title" value="JBossCache"/>
- <attribute name="Specification-Version" value="${module.version}"/>
- <attribute name="Specification-Vendor" value="JBoss Inc."/>
- <attribute name="Implementation-Title" value="${module.name}"/>
- <attribute name="Implementation-Version" value="${module.version}"/>
- <attribute name="Implementation-Vendor" value="JBoss Inc."/>
- </manifest>
- </target>
-
- <target name="manifest-retro">
- <tstamp/>
- <mkdir dir="${dist.lib}"/>
- <manifest file="${manifest.file}">
- <attribute name="Built-By" value="${user.name}"/>
- <attribute name="Created-On" value="${TODAY}"/>
- <attribute name="Main-Class" value="org.jboss.cache.Version$Retro"/>
- <attribute name="Specification-Title" value="JBossCache"/>
- <attribute name="Specification-Version" value="${module.version}"/>
- <attribute name="Specification-Vendor" value="JBoss Inc."/>
- <attribute name="Implementation-Title" value="${module.name}"/>
- <attribute name="Implementation-Version" value="${module.version}"/>
- <attribute name="Implementation-Vendor" value="JBoss Inc."/>
- </manifest>
- </target>
-
- <target name="manifest-pc">
- <tstamp/>
- <mkdir dir="${dist.lib}"/>
- <manifest file="${manifest.file}">
- <attribute name="Built-By" value="${user.name}"/>
- <attribute name="Created-On" value="${TODAY}"/>
- <!--attribute name="Main-Class" value="org.jboss.cache.pojo.Version"/-->
- <attribute name="Specification-Title" value="JBossCache-pojo"/>
- <attribute name="Specification-Version" value="${module.version}"/>
- <attribute name="Specification-Vendor" value="JBoss Inc."/>
- <attribute name="Implementation-Title" value="${module.name}"/>
- <attribute name="Implementation-Version" value="${module.version}"/>
- <attribute name="Implementation-Vendor" value="JBoss Inc."/>
- </manifest>
- </target>
-
- <target name="manifest-migration">
- <tstamp/>
- <mkdir dir="${dist.lib}"/>
- <manifest file="${manifest.file}">
- <attribute name="Built-By" value="${user.name}"/>
- <attribute name="Created-On" value="${TODAY}"/>
- <!-- attribute name="Main-Class" value="org.jboss.cache.Version"/ -->
- <attribute name="Specification-Title" value="JBossCache-Cacheloader-Migration"/>
- <attribute name="Specification-Version" value="${module.version}"/>
- <attribute name="Specification-Vendor" value="JBoss Inc."/>
- <attribute name="Implementation-Title" value="${module.name}"/>
- <attribute name="Implementation-Version" value="${module.version}"/>
- <attribute name="Implementation-Vendor" value="JBoss Inc."/>
- <attribute name="Class-Path" value="jboss-minimal.jar"/>
- </manifest>
- </target>
-
- <!-- ================================================================== -->
- <!-- Documentation -->
- <!-- ================================================================== -->
- <target name="javadocs" description="Create Javadoc documentation in the ./doc/javadoc directory">
- <javadoc packagenames="${javadoc.packages}"
- destdir="${build.api}"
- classpathref="library.classpath"
- author="true"
- version="true"
- use="true"
- windowtitle="${module.name} - ${module.version} API"
- useexternalfile="yes">
-
- <doctitle>${module.name} - ${module.version} API</doctitle>
- <bottom>
- <![CDATA[<p align="center><i><b>Copyright © 1998-2007 Red Hat Inc.</b> All Rights Reserved.</i></p>]]></bottom>
- <fileset dir="${src.dir}" defaultexcludes="yes">
- <include name="org/jboss/**"/>
- </fileset>
-
- <fileset dir="${src.dir.50}" defaultexcludes="yes">
- <include name="org/jboss/**"/>
- </fileset>
-
- </javadoc>
- </target>
-
- <target name="version" description="Prints version of JBossCache">
- <java classname="org.jboss.cache.Version" classpath="${compile.dir}"/>
- </target>
-
-
- <!-- ================================================================== -->
- <!-- Cleaning -->
- <!-- ================================================================== -->
- <target name="clean">
- <delete dir="${output.dir}"/>
- <delete dir="${build.lib}"/>
- <delete dir="${build.api}"/>
- <delete dir="${build.reports}"/>
- <delete dir="${dist.dir}"/>
- <delete dir="${tmp.dir}"/>
-
- <delete dir="${migration.output.dir}"/>
- <delete dir="${cache.db.dir}"/>
- <delete dir="${cache.db.1x.dir}"/>
- <delete dir="${root.dir}/clover"/>
- <delete>
- <fileset dir="${basedir}" defaultexcludes="no">
- <include name="**/*~"/>
- <include name="derby.*"/>
- </fileset>
- </delete>
- </target>
-
- <target name="clean-tests">
- <delete dir="${output.dir}/tests-classes"/>
- <delete dir="${output.dir}/tests-classes-50"/>
- <delete dir="${migration.compiletest.dir}"/>
- </target>
-
-
- <!-- ================================================================== -->
- <!-- Tests -->
- <!-- ================================================================== -->
-
- <target name="one-test-retro" depends="unittests-init" description="Runs a single, retroweaved test under JDK 1.4">
- <property name="jgroups.stack" value="udp"/>
- <echo>Running ${test} using ${jgroups.stack} jgroups stack</echo>
- <junit printsummary="yes" timeout="${junit.timeout.stresstest}" fork="yes">
- <sysproperty key="log4j.configuration" value="file:${etc.dir}/log4j.xml"/>
- <classpath refid="library.classpath"/>
- <classpath refid="retro.library.classpath"/>
- <classpath refid="retro.output.classpath"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <test name="${test}" todir="${build.reports}"/>
- <jvmarg value="-Djgroups.stack=${jgroups.stack}"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
- <jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <jvmarg value="-Dlib.dir=${lib.dir}"/>
- </junit>
- </target>
-
- <target name="one-test" depends="compile,unittests-init" description="Runs a single unit test">
- <property name="jgroups.stack" value="udp"/>
- <echo>Running ${test} using ${jgroups.stack} jgroups stack</echo>
- <junit printsummary="yes" timeout="${junit.timeout.stresstest}" fork="yes">
- <sysproperty key="log4j.configuration" value="file:${etc.dir}/log4j.xml"/>
- <classpath refid="library.classpath"/>
- <classpath refid="output.classpath"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <test name="${test}" todir="${build.reports}"/>
- <jvmarg value="-Djgroups.stack=${jgroups.stack}"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
- <jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <jvmarg value="-Dlib.dir=${lib.dir}"/>
- </junit>
- </target>
-
- <target name="one-test-pkg" depends="compile,unittests-init" description="Runs a single unit test package">
-
- <property name="jgroups.stack" value="udp"/>
- <junit printsummary="yes" timeout="${junit.timeout.stresstest}" fork="yes" maxmemory="512m">
- <sysproperty key="log4j.configuration" value="file:${etc.dir}/log4j.xml"/>
- <classpath refid="library.classpath"/>
- <classpath refid="output.classpath"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
- <jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <jvmarg value="-Dtest.jar.dir=${output.dir}"/>
- <jvmarg value="-Dlib.dir=${lib.dir}"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${functional.tests.dir}">
- <include name="${pkg}/*Test.*"/>
- <exclude name="**/aop/**/*"/>
- <exclude name="**/pojo/**/*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- </batchtest>
- </junit>
- </target>
-
- <target name="one-test-aop" description="deprecated">
- <echo>
- This target is deprecated and will be removed in 2.0.0.GA. Please use "one-test-pojocache" instead.
- </echo>
- </target>
-
- <target name="one-test-aop50" description="deprecated">
- <echo>
- This target is deprecated and will be removed in 2.0.0.GA. Please use "one-test-pojocache" instead.
- </echo>
- </target>
-
-
- <target name="one-test-pojocache" depends="compile, unittests-init" description="Runs a single unit test">
- <property name="jgroups.stack" value="udp"/>
- <echo>Running pojo test ${test} using ${jgroups.stack} jgroups stack</echo>
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes">
- <!-- start of Optimizeit support
- sample script
- #!/bin/sh
- # sample opt.sh script
- # usage: ./opt.sh -Dtest=org.jboss.cache.aop.LocalPerfAopTest one-test-aop
- export OPTITDIR=/home/smarlow/optimeit/OptimizeitSuite60
- export PATH=$PATH:/home/smarlow/optimeit/OptimizeitSuite60
- export LD_LIBRARY_PATH=$OPTITDIR/lib:$LD_LIBRARY_PATH
- ./build.sh -Dbootclasspath=$OPTITDIR/lib/oibcp.jar -Doptjar=$OPTITDIR/lib/optit.jar -DOPTITDIR=$OPTITDIR "$@"
- -->
- <!--
- <jvmarg value="-Xrunpri:startAudit=t,noexit=t"/>
- <jvmarg value="-DOPTITDIR=${OPTITDIR}"/>
- <classpath location="${optjar}"/>
-end of optimizeIt support
--->
- <!-- support for JDWP debug
- <jvmarg value="-Xdebug"/>
- <jvmarg value="-Xnoagent"/>
- <jvmarg value="-Djava.compiler=NONE"/>
- <jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=localhost:6555"/>
- -->
- <jvmarg value="-Djgroups.stack=${jgroups.stack}"/>
- <jvmarg value="-Djboss.aop.path=${output.resources.dir}/pojocache-aop.xml"/>
- <!--
- <jvmarg value="-Djboss.aop.verbose=true"/>
- -->
- <jvmarg value="-Dbind.address=${bind.address}"/>
- <jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <!--
- <jvmarg value="-Djava.system.class.loader=org.jboss.aop.standalone.SystemClassLoader"/>
- -->
- <jvmarg value="-javaagent:${lib.dir}/jboss-aop-jdk50.jar"/>
- <classpath refid="output.classpath"/>
- <sysproperty key="log4j.configuration" value="file:${etc.dir}/log4j.xml"/>
- <classpath refid="library.classpath"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <test name="${test}" todir="${build.reports}"/>
- </junit>
- </target>
-
- <target name="one-test-precompiled-pojocache" depends="compile, aopc50, unittests-init"
- description="Runs a single unit test">
- <property name="jgroups.stack" value="udp"/>
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes">
- <classpath refid="output.classpath"/>
- <sysproperty key="log4j.configuration" value="file:${etc.dir}/log4j.xml"/>
- <classpath refid="library.classpath"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <test name="${test}" todir="${build.reports}"/>
- </junit>
- </target>
-
- <target name="unittests-init">
- <mkdir dir="${build.reports}"/>
- </target>
-
- <target name="test-jar" depends="compile">
- <jar jarfile="${output.dir}/testMarshall.jar">
- <fileset dir="${compiletest.dir}">
- <include name="org/jboss/cache/marshall/Address.class"/>
- <include name="org/jboss/cache/marshall/Person.class"/>
- </fileset>
- </jar>
- </target>
-
-
- <!--
- <target name="tcp-cache-service" depends="compile"
- description="Creates the service archive used to deploy a TcpCacheServer as a JBoss MBean">
- <mkdir dir="${dist.dir}"/>
- <jar jarfile="${dist.dir}/TcpCacheServer.sar"
- basedir="${compile.dir}"
- includes="org/jboss/cache/loader/tcp/TcpCacheServer*">
- <metainf dir="${etc.dir}/TcpCacheServer"
- includes="jboss-service.xml"/>
- </jar>
- </target>
- -->
-
-
- <!-- pre-compile directory with annotationc using jdk1.4 -->
- <target name="annoc" depends="compile" description="Annotation precompiler for aop class">
- <taskdef name="annotationc" classname="org.jboss.aop.ant.AnnotationC" classpathref="library.classpath"/>
- <annotationc compilerclasspathref="library.classpath" bytecode="true">
- <classpath path="${compile.dir}"/>
- <classpath path="${compiletest.dir}"/>
- <classpath path="${output.resources.dir}"/>
- <src path="${functional.tests.dir}"/>
- <src path="${perf.tests.dir}"/>
- <include name="org/jboss/cache/aop/test/**/*.java"/>
- <include name="org/jboss/cache/data/*.java"/>
- </annotationc>
- </target>
-
- <!-- pre-compile directory with aopc50 -->
- <target name="aopc50" depends="compile" description="Precompile aop test classes">
- <taskdef name="aopc" classname="org.jboss.aop.ant.AopC" classpathref="library.classpath"/>
- <aopc compilerclasspathref="library.classpath" classpathref="library.classpath" verbose="false">
- <src path="${compiletest.dir}/org/jboss/cache/pojo/test"/>
- <src path="${compiletest.dir}/org/jboss/cache/test/perf"/>
- <!--src path="${compiletest.dir}/org/jboss/cache/data"/-->
- <aoppath path="${output.resources.dir}/pojocache-aop.xml"/>
- <classpath>
- <path refid="output.classpath"/>
- </classpath>
- </aopc>
- </target>
-
- <target name="functionaltests" depends="compile-cache,test-jar,unittests-init"
- description="Runs all core Cache functional tests">
- <property name="jgroups.stack" value="udp"/>
- <echo>Running functional tests using ${jgroups.stack} jgroups stack</echo>
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes" maxmemory="512m">
- <classpath refid="library.classpath"/>
- <classpath refid="output.classpath"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
- <jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djgroups.stack=${jgroups.stack}"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <jvmarg value="-Dtest.jar.dir=${output.dir}"/>
- <jvmarg value="-Dlib.dir=${lib.dir}"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${functional.tests.dir}">
- <include name="**/*Test.*"/>
- <exclude name="**/aop/**/*"/>
- <exclude name="**/pojo/**/*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- </batchtest>
- </junit>
- </target>
-
- <target name="functionaltests-cc" depends="compile-cache,test-jar,unittests-init"
- description="Runs all core Cache functional tests, excluding known failures">
- <antcall target="functionaltests" inheritrefs="false">
- <reference refid="known.failures" torefid="junit.excludes"/>
- </antcall>
- </target>
-
-
- <target name="functionalAop50TestsWithAopC" depends="compile,aopc50,unittests-init"
- description="Runs all AOP functional tests">
- <property name="jgroups.stack" value="udp"/>
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes">
- <classpath refid="library.classpath"/>
- <classpath refid="output.classpath"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <jvmarg value="-Djboss.aop.path=${output.resources.dir}/pojocache-aop.xml"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
- <jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <sysproperty key="log4j.configuration" value="file:${etc.dir}/log4j.xml"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${functional.tests.dir}">
- <include name="**/aop/**/*Test.*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- <fileset dir="${functional.tests.dir.50}">
- <include name="**/aop/**/*Test.*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- </batchtest>
- </junit>
- </target>
-
- <target name="functionalAopTests50" depends="compile, unittests-init" description="Runs all AOP functional tests">
- <property name="jgroups.stack" value="udp"/>
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes">
- <jvmarg value="-Djboss.aop.path=${output.resources.dir}/pojocache-aop.xml"/>
- <jvmarg value="-javaagent:${lib.dir}/jboss-aop-jdk50.jar"/>
- <classpath refid="output.classpath"/>
- <classpath refid="library.classpath"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
- <jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <sysproperty key="log4j.configuration" value="file:${etc.dir}/log4j.xml"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${functional.tests.dir}">
- <include name="**/aop/**/*Test.*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- <fileset dir="${functional.tests.dir.50}">
- <include name="**/aop/**/*Test.*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- </batchtest>
- </junit>
- </target>
-
- <target name="functionalPojoCacheTests" depends="compile, unittests-init"
- description="Runs all PojoCache2.x functional tests">
- <property name="jgroups.stack" value="udp"/>
- <echo>Running functional pojo tests using ${jgroups.stack} jgroups stack</echo>
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes">
- <jvmarg value="-Djgroups.stack=${jgroups.stack}"/>
- <jvmarg value="-Djboss.aop.path=${output.resources.dir}/pojocache-aop.xml"/>
- <jvmarg value="-javaagent:${lib.dir}/jboss-aop-jdk50.jar"/>
- <classpath refid="output.classpath"/>
- <classpath refid="library.classpath"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
- <jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <sysproperty key="log4j.configuration" value="file:${etc.dir}/log4j.xml"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${functional.tests.dir}">
- <include name="**/pojo/**/*Test.*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- </batchtest>
- </junit>
- </target>
-
- <target name="functionaltests-migration" depends="compile-cache,test-jar,unittests-init"
- description="Runs cache loader functional tests">
- <property name="jgroups.stack" value="udp"/>
- <echo>Running functional tests using ${jgroups.stack} jgroups stack</echo>
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes" maxmemory="512m">
- <classpath refid="library.classpath"/>
- <classpath refid="output.classpath"/>
- <classpath refid="migration.library.classpath"/>
- <classpath refid="migration.output.classpath"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
- <jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djgroups.stack=${jgroups.stack}"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <jvmarg value="-Dtest.jar.dir=${output.dir}"/>
- <jvmarg value="-Dlib.dir=${lib.dir}"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${migration.functional.tests.dir}">
- <include name="**/*Test.*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- </batchtest>
- </junit>
- </target>
-
- <!--
- This is new target since 1.2.4. Since the old way using SystemClassLoader ie error prone, it has been replcaed in
- JBossAop 1.3.1 for the new GeneratedInstrumentedClassLoader. But for this to work, we will need this target
- to generate a temporarily ClassLoader under gen-bootclasspath directory
- -->
- <target name="generateClassLoader"
- description="Generate a new modified class loader so we can perform load time instrumentation">
- <property name="build.bootclasspath" value="${output.dir}/gen-bootclasspath"/>
- <java classname="org.jboss.aop.hook.GenerateInstrumentedClassLoader">
- <classpath>
- <path refid="library.classpath"/>
- </classpath>
- <arg value="${build.bootclasspath}"/>
- </java>
- <path id="bootclasspath">
- <pathelement location="${build.bootclasspath}"/>
- <path refid="library.classpath"/>
- </path>
- <property name="bootclasspath" refid="bootclasspath"/>
- </target>
-
- <target name="functionalAopTests" depends="generateClassLoader, compile,unittests-init"
- description="Runs all AOP functional tests">
- <property name="jgroups.stack" value="udp"/>
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes">
- <classpath refid="library.classpath"/>
- <classpath refid="output.classpath"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <jvmarg value="-Djboss.aop.path=${output.resources.dir}/pojocache-aop.xml"/>
- <jvmarg value="-Xbootclasspath/p:${bootclasspath}"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
- <jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${functional.tests.dir}">
- <include name="**/aop/**/*Test.*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- </batchtest>
- </junit>
- </target>
-
- <!--
- <target name="perfAopTests" depends="compile,aopc,unittests-init" description="Runs all AOP performance tests">
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes">
- <classpath refid="library.classpath"/>
- <classpath refid="output.classpath"/>
- <formatter type="xml" usefile="true"/>
- <jvmarg value="-Djboss.aop.path=${output.resources.dir}/pojocache-aop.xml"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
-<jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${perf.tests.dir}">
- <include name="**/aop/**/*AopTest.*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- </batchtest>
- </junit>
- </target>
-
- <target name="stressAopTests" depends="compile,aopc,unittests-init" description="Runs all AOP stress tests">
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes">
- <classpath refid="library.classpath"/>
- <classpath refid="output.classpath"/>
- <formatter type="xml" usefile="true"/>
- <jvmarg value="-Djboss.aop.path=${output.resources.dir}/pojocache-aop.xml"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
-<jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${stress.tests.dir}">
- <include name="**/aop/**/*AopTest.*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- </batchtest>
- </junit>
- </target>
- -->
-
- <target name="all-functionaltests"
- depends="functionaltests, functionalPojoCacheTests, functionaltests-migration"
- description="Runs all functional tests (including AOP tests)">
- </target>
-
- <target name="all-functional-xknown">
- <antcall target="all-functionaltests" inheritrefs="false">
- <reference refid="known.failures" torefid="junit.excludes"/>
- </antcall>
- </target>
-
- <target name="perftests" depends="compile,unittests-init" description="Runs all non-AOP perf tests">
- <property name="jgroups.stack" value="udp"/>
- <echo>Running performance tests using ${jgroups.stack} jgroups stack</echo>
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes">
- <classpath refid="library.classpath"/>
- <classpath refid="output.classpath"/>
- <jvmarg value="-Djgroups.stack=${jgroups.stack}"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
- <jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${perf.tests.dir}">
- <include name="**/*Test.*"/>
- <exclude name="**/aop/**/*"/>
- <exclude name="**/*JRunitTest.*"/>
- <exclude name="**/benchmark/**/*"/>
- <exclude name="**/optimistic/Local*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- </batchtest>
- </junit>
- </target>
-
- <!-- target name="perftests-migration" depends="compile,unittests-init" description="Runs all migration perf tests">
- <property name="jgroups.stack" value="udp"/>
- <echo>Running performance tests using ${jgroups.stack} jgroups stack</echo>
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes">
- <classpath refid="library.classpath"/>
- <classpath refid="output.classpath"/>
- <classpath refid="migration.library.classpath"/>
- <classpath refid="migration.output.classpath"/>
- <jvmarg value="-Djgroups.stack=${jgroups.stack}"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
-<jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${migration.perf.tests.dir}">
- <include name="**/*Test.*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- </batchtest>
- </junit>
- </target -->
-
- <target name="all-perftests" depends="perftests"
- description="Runs all perf tests (including AOP tests)">
- </target>
-
- <target name="stresstests" depends="compile,unittests-init" description="Runs all non-AOP perf tests">
- <echo>Running stress tests using ${jgroups.stack} jgroups stack</echo>
- <property name="jgroups.stack" value="udp"/>
- <junit printsummary="yes" timeout="${junit.timeout.stresstest}" fork="yes">
- <classpath refid="library.classpath"/>
- <classpath refid="output.classpath"/>
- <jvmarg value="-Djgroups.stack=${jgroups.stack}"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
- <jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${stress.tests.dir}">
- <include name="**/*Test.*"/>
- <exclude name="**/aop/**/*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- </batchtest>
- </junit>
- </target>
-
- <!-- Temporarily disable meaningless interop tests by adding an "if" test of a non-existent property
- We'll re-enable for the 1st release after 2.0 where we need to check backward interoperability -->
- <target name="interoptests" depends="compile,test-jar,unittests-init" if="interoptests.enabled">
-
- <!-- Download the cache version against which we check interop -->
- <mkdir dir="${output.interop.dir}"/>
- <get dest="${output.interop.dir}/jbosscache.jar"
- src="http://repository.jboss.com/jboss/cache/1.2.3.1/lib/jboss-cache.jar" verbose="true"/>
-
- <start-interop-target name="previous version" conf="META-INF/interopPrevSync-service.xml"
- classpath="previous.version.classpath"/>
- <sleep seconds="3"/>
- <run-interop-tests name="current version" desc="PrevTargetSync" conf="META-INF/interopCurSync-service.xml"
- classpath="current.version.classpath"/>
- <stop-interop-target/>
-
- <start-interop-target name="current version" conf="META-INF/interopCurSync-service.xml"
- classpath="current.version.classpath"/>
- <sleep seconds="3"/>
- <run-interop-tests name="previous version" desc="CurTargetSync" conf="META-INF/interopPrevSync-service.xml"
- classpath="previous.version.classpath"/>
- <stop-interop-target/>
-
- <start-interop-target name="previous version" conf="META-INF/interopPrevAsync-service.xml"
- classpath="previous.version.classpath"/>
- <sleep seconds="3"/>
- <run-interop-tests name="current version" desc="PrevTargetAsync" conf="META-INF/interopCurAsync-service.xml"
- classpath="current.version.classpath"/>
- <stop-interop-target/>
-
- <start-interop-target name="current version" conf="META-INF/interopCurAsync-service.xml"
- classpath="current.version.classpath"/>
- <sleep seconds="3"/>
- <run-interop-tests name="previous version" desc="CurTargetAsync" conf="META-INF/interopPrevAsync-service.xml"
- classpath="previous.version.classpath"/>
- <stop-interop-target/>
-
- </target>
-
- <macrodef name="start-interop-target">
- <attribute name="name"
- description="The name of the cache"/>
- <attribute name="conf"
- description="The config file name passed to the cache"/>
- <attribute name="classpath"
- description="The config file name passed to the cache"/>
- <sequential>
- <echo message="Will start a @{name} JBossCache instance with @{conf}"/>
- <java classname="org.jboss.cache.interop.Main" fork="true" spawn="true">
- <classpath refid="@{classpath}"/>
- <arg value="@{conf}"/>
- </java>
- </sequential>
- </macrodef>
-
- <macrodef name="stop-interop-target">
- <sequential>
- <echo message="Will stop the JBossCache instance"/>
- <java classname="org.jboss.cache.interop.Shutdown" fork="true">
- <classpath>
- <path refid="library.classpath"/>
- <path refid="output.classpath"/>
- </classpath>
- </java>
- </sequential>
- </macrodef>
-
- <macrodef name="run-interop-tests">
- <attribute name="name"
- description="The name of the cache"/>
- <attribute name="desc"
- description="The summary desc"/>
- <attribute name="conf"
- description="The config file name passed to the cache"/>
- <attribute name="classpath"
- description="The config file name passed to the cache"/>
- <sequential>
- <echo message="Running tests with a @{name} JBossCache instance with @{conf}"/>
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes">
- <classpath refid="@{classpath}"/>
- <sysproperty key="interop.test.config" value="@{conf}"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true" extension="-(a){desc}.xml"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${interop.tests.dir}">
- <include name="**/*Test.*"/>
- <exclude name="**/aop/**/*"/>
- <exclude name="**/*JRunitTest*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
-
- </batchtest>
- </junit>
- </sequential>
- </macrodef>
-
- <target name="compat-tests" depends="jar, unittests-init"
- if="ENABLE_COMPAT_TESTS">
- <condition property="libdir.list" value="lib,lib, dist/lib">
- <equals arg1="${ant.java.version}" arg2="1.5"/>
- </condition>
- <condition property="libdir.list" value="lib, dist/lib">
- <equals arg1="${ant.java.version}" arg2="1.4"/>
- </condition>
-
- <junit printsummary="yes" timeout="${junit.timeout.compat}" fork="yes"
- maxmemory="256m">
- <classpath>
- <pathelement path="${compiletest.dir}"/>
- </classpath>
- <sysproperty key="libdir.list" value="${libdir.list}"/>
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true" extension=".xml"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${compat.tests.dir}">
- <exclude name="**/tools/**/*"/>
- <patternset refid="junit.excludes"/>
- </fileset>
- </batchtest>
- </junit>
- </target>
-
- <target name="unittests"
- depends="functionaltests, functionaltests-migration, perftests, stresstests"
- description="Run all non-AOP unit tests (functional, perf, stress)"/>
-
- <target name="all-unittests"
- depends="all-functionaltests, all-perftests, stresstests, compat-tests"
- description="Run all unit tests, including AOP-based ones (functional, perf, stress)"/>
-
- <target name="all-unittests-cc"
- description="Run all unit tests, including AOP-based ones (functional, perf, stress) for CruiseControl, (excludes 'known failures')">
-
- <antcall target="all-unittests" inheritrefs="false">
- <reference refid="known.failures" torefid="junit.excludes"/>
- <param name="jgroups.stack" value="udp"/>
- </antcall>
-
- <antcall target="all-unittests" inheritrefs="false">
- <reference refid="known.failures" torefid="junit.excludes"/>
- <param name="jgroups.stack" value="tcp"/>
- </antcall>
- </target>
-
- <target name="all-unittests-retro-cc" depends="unittests-init"
- description="Run retroweaved codebase and unit tests, excluding AOP-based ones (functional, perf, stress) for CruiseControl, (excludes 'known failures'). Meant to be run under JDK 1.4.0.">
-
- <antcall target="all-unittests-retro" inheritrefs="false">
- <reference refid="known.failures" torefid="junit.excludes"/>
- <param name="jgroups.stack" value="udp"/>
- </antcall>
-
- <antcall target="all-unittests-retro" inheritrefs="false">
- <reference refid="known.failures" torefid="junit.excludes"/>
- <param name="jgroups.stack" value="tcp"/>
- </antcall>
-
- </target>
-
- <target name="all-unittests-retro">
- <property name="jgroups.stack" value="udp"/>
- <junit printsummary="yes" timeout="${junit.timeout}" fork="yes" maxmemory="512m">
- <classpath refid="library.classpath"/>
- <classpath refid="retro.output.classpath"/>
- <jvmarg value="-Dbind.address=${bind.address}"/>
- <jvmarg value="-Dsun.lang.ClassLoader.allowArraySyntax=true"/>
- <jvmarg value="-Djgroups.stack=${jgroups.stack}"/>
- <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
- <jvmarg value="-Djgroups.stack=${jgroups.stack}"/>
- <!--<jvmarg value="-Dtest.jar.dir=${output.dir}"/>-->
- <formatter classname="org.jboss.cache.util.XMLUnitTestFormatter" usefile="true"
- extension="-${jgroups.stack}.xml"/>
- <batchtest todir="${build.reports}">
- <fileset dir="${retro.compiletest.dir}">
- <include name="**/*Test.*"/>
- <exclude name="**/aop/**/*"/>
- <exclude name="**/pojo/**/*"/>
- <patternset refid="known.failures"/>
- </fileset>
- </batchtest>
- </junit>
- </target>
-
- <target name="findxalan">
- <available property="xalan.available" classname="org.apache.xalan.Version"/>
- <fail unless="xalan.available"
- message="Xalan was not found. Please add the xalan.jar file from the lib directory to the CLASSPATH and retry"/>
- </target>
-
-
- <target name="reports"
- description="Generates HTML from unit tests (target unitests-* must have run before)">
- <delete dir="${build.reports.html}"/>
- <mkdir dir="${build.reports.html}"/>
- <junitreport todir="${build.reports.html}">
- <fileset dir="${build.reports}" includes="**/TEST-*.xml"/>
- <report todir="${build.reports.html}"/>
- </junitreport>
- <echo message="********************************************************************"/>
- <echo message="The unit test report is available in ${build.reports.html}/index.html"/>
- <echo message="********************************************************************"/>
- </target>
-
- <!-- ================================================================== -->
- <!-- Build all html/pdf docs in various sub dirs -->
- <!-- ================================================================== -->
- <target name="docs" description="Build all html and pdf docs">
-
- <echo message="Building docs from docbook ..."/>
- <!-- Bail out if ../docbook-support dir does not exist -->
- <available file="${root.dir}/../docbook-support" type="dir"
- property="docbook.support.present"/>
- <fail message="docbook-support directory does not exist, please check it out from jboss first (module name is 'docbook-support'."
- unless="docbook.support.present"/>
-
- <ant dir="${root.dir}/docs" antfile="build.xml"
- target="all"/>
- </target>
-
- <!-- ================================================================== -->
- <!-- Install & Release -->
- <!-- ================================================================== -->
-
- <target name="dist" description="Creates a full standalone distribution"
- depends="jar, docs, javadocs">
-
- <!-- Now make temp dirs, copy files and create the zip files -->
- <mkdir dir="${tmp.dir}"/>
- <mkdir dir="${tmp.dir}/lib"/>
- <mkdir dir="${tmp.dir}/docs"/>
- <mkdir dir="${tmp.dir}/examples"/>
- <mkdir dir="${tmp.dir}/tests"/>
- <mkdir dir="${tmp.dir}/etc"/>
- <mkdir dir="${tmp.dir}/resources"/>
- <mkdir dir="${tmp.dir}/docs/javadoc"/>
- <mkdir dir="${tmp.dir}/docs/faq"/>
- <mkdir dir="${tmp.dir}/docs/faq-pojo"/>
- <mkdir dir="${tmp.dir}/docs/tutorial"/>
- <mkdir dir="${tmp.dir}/docs/tutorial-pojo"/>
- <mkdir dir="${tmp.dir}/docs/JBossCache-UserGuide"/>
- <mkdir dir="${tmp.dir}/docs/PojoCache"/>
- <mkdir dir="${tmp.dir}/ant-dist"/>
- <mkdir dir="${tmp.dir}/src"/>
-
- <copy todir="${tmp.dir}/ant-dist" filtering="no">
- <fileset dir="${ant.dir}"/>
- </copy>
-
- <chmod dir="${tmp.dir}/ant-dist/bin" perm="+x" includes="*"/>
-
- <copy todir="${tmp.dir}" filtering="no">
- <fileset dir="${etc.dir}">
- <include name="build.xml"/>
- <include name="*.sh"/>
- <include name="*.bat"/>
- <include name="build.properties"/>
- </fileset>
- </copy>
-
- <copy todir="${tmp.dir}/resources" filtering="no">
- <fileset dir="${resources.dir}">
- <include name="pojocache-aop.xml"/>
- </fileset>
- </copy>
-
- <copy todir="${tmp.dir}" filtering="no">
- <fileset dir="${doc.dir}">
- <include name="Changelog.txt"/>
- <include name="Readme.txt"/>
- <include name="ReleaseNotes.txt"/>
- <include name="JBossORG-EULA.txt"/>
- </fileset>
- </copy>
-
- <copy todir="${tmp.dir}/etc" filtering="no">
- <fileset dir="${etc.dir}">
- <exclude name="log4j.xml"/>
- <include name="log4j.release.xml"/>
- <include name="META-INF/*.xml"/>
- <include name="cache-jdbc.properties"/>
- </fileset>
- </copy>
-
- <move file="${tmp.dir}/etc/log4j.release.xml" tofile="${tmp.dir}/etc/log4j.xml"/>
-
- <copy todir="${tmp.dir}/tests" filtering="no">
- <fileset dir="${functional.tests.dir}">
- <include name="**/*.java"/>
- <!-- needed for some classloader tests -->
- <include name="**/*.clazz"/>
- <include name="**/*.notjava"/>
-
- <exclude name="**/*Bdbje*"/>
- </fileset>
- <fileset dir="${compiletest.dir}">
- <exclude name="**/*Bdbje*"/>
- </fileset>
- </copy>
-
- <copy todir="${tmp.dir}/tests" filtering="no">
- <fileset dir="${functional.tests.dir.50}">
- <include name="**/*.java"/>
- <exclude name="**/*Bdbje*"/>
- <exclude name="**/aop/**"/>
- </fileset>
- </copy>
-
- <copy todir="${tmp.dir}/examples" filtering="no">
- <fileset dir="${examples.dir}">
- <!--include name="**/*.java"/-->
- <exclude name="**/CVS/*"/>
- <!-- Need this because of phantom directories -->
- <exclude name="**/aop/**"/>
- <!-- Exclude this for now -->
- <exclude name="**/article/**"/>
- </fileset>
- <fileset dir="${migration.examples.dir}">
- <include name="**"/>
- </fileset>
- </copy>
-
- <copy todir="${tmp.dir}/lib" filtering="no">
- <fileset dir="${lib.dir}">
- <include name="*.jar"/>
- <include name="**/licenses/*"/>
- <include name="README.txt"/>
- </fileset>
- <fileset dir="${dist.lib}">
- <include name="jbosscache.jar"/>
- <include name="pojocache.jar"/>
- <include name="${migration.jar.name}"/>
- </fileset>
- </copy>
-
- <copy todir="${tmp.dir}/docs/javadoc" filtering="no">
- <fileset dir="${build.api}">
- <include name="**/*"/>
- </fileset>
- </copy>
-
- <copy todir="${tmp.dir}/docs/faq" filtering="no">
- <fileset dir="${doc.dir}/faq/build"/>
- </copy>
-
- <copy todir="${tmp.dir}/docs/faq-pojo" filtering="no">
- <fileset dir="${doc.dir}/faq-pojo/build"/>
- </copy>
-
- <copy todir="${tmp.dir}/docs/tutorial" filtering="no">
- <fileset dir="${doc.dir}/tutorial/build"/>
- </copy>
-
- <copy todir="${tmp.dir}/docs/tutorial-pojo" filtering="no">
- <fileset dir="${doc.dir}/tutorial-pojo/build"/>
- </copy>
-
- <copy todir="${tmp.dir}/docs/JBossCache-UserGuide" filtering="no">
- <fileset dir="${doc.dir}/JBossCache-UserGuide/build"/>
- </copy>
-
- <copy todir="${tmp.dir}/docs/PojoCache" filtering="no">
- <fileset dir="${doc.dir}/PojoCache/build"/>
- </copy>
-
- <copy todir="${tmp.dir}/src" filtering="no">
- <fileset dir="${src.dir}">
- <exclude name="**/CVS/*"/>
- </fileset>
- </copy>
-
- <copy todir="${tmp.dir}" filtering="no">
- <fileset dir="${etc.dir}">
- <include name="*.bsh"/>
- </fileset>
- </copy>
-
- <delete file="${dist.dir}/${module.name}-core-${module.version}.zip"/>
- <!--<delete file="${dist.dir}/${module.name}-core-JDK140-${module.version}.zip"/>-->
- <delete file="${dist.dir}/${module.name}-pojo-${module.version}.zip"/>
- <delete file="${dist.dir}/${module.name}-all-${module.version}.zip"/>
- <delete file="${dist.dir}/bdbje-for-${module.name}-${module.version}.zip"/>
-
- <chmod perm="+x">
- <fileset dir="${dist.dir}">
- <include name="**/*.sh"/>
- <include name="**/*.bsh"/>
- <include name="**/*.bat"/>
- </fileset>
- </chmod>
-
- <zip zipfile="${dist.dir}/${module.name}-core-${module.version}.zip">
- <zipfileset dir="${tmp.dir}" prefix="${module.name}-core-${module.version}" filemode="755">
- <include name="**/*"/>
- <include name="org/jboss/cache/**"/>
- <include name="examples/cacheloader-migration/**"/>
- <exclude name="org/jboss/cache/pojo/**"/>
- <exclude name="src/**"/>
- <exclude name="pojocache*"/>
- <exclude name="lib/pojocache.jar"/>
- <exclude name="lib/jboss-aop*.jar"/>
- <exclude name="lib/qdox.jar"/>
- <exclude name="lib/javassist.jar"/>
- <exclude name="examples/PojoCache/**"/>
- <exclude name="resources/**"/>
- <exclude name="docs/javadoc/**"/>
- <exclude name="docs/PojoCache/**"/>
- <exclude name="docs/faq-pojo/**"/>
- <exclude name="docs/tutorial-pojo/**"/>
- <exclude name="tests/org/jboss/cache/pojo/**"/>
- <exclude name="test-classes/org/jboss/cache/pojo/**"/>
- </zipfileset>
- </zip>
-
- <zip zipfile="${dist.dir}/${module.name}-pojo-${module.version}.zip">
- <zipfileset dir="${tmp.dir}" prefix="${module.name}-pojo-${module.version}" filemode="755">
- <exclude name="src/**"/>
- <exclude name="examples/annotated14/**"/>
- <exclude name="examples/cacheloader-migration/**"/>
- </zipfileset>
- </zip>
-
- <zip zipfile="${dist.dir}/bdbje-for-${module.name}-${module.version}.zip">
- <zipfileset dir="${berkeleydb.lib.dir}" prefix="bdbje-for-${module.name}-${module.version}">
- <include name="*"/>
- </zipfileset>
- </zip>
-
- <zip zipfile="${dist.dir}/${module.name}-all-${module.version}.zip">
- <zipfileset dir="${tmp.dir}" prefix="${module.name}-all-${module.version}" filemode="755">
- <include name="**/**"/>
- </zipfileset>
- </zip>
-
- <!-- Retroweaved binary NOT built as a part of the distribution. Manually run the jar-retro target for this. -->
-
- <!--
- <copy todir="${tmp.dir}/tests14" filtering="no">
- <fileset dir="${retro.compiletest.dir}">
- <include name="**/*.class"/>
- <exclude name="**/loader/Bdbje*.class"/>
- <exclude name="**/aop/**"/>
- <exclude name="**/pojo/**"/>
- </fileset>
- </copy>
-
- <copy todir="${tmp.dir}/lib">
- <fileset dir="${retro.lib.dir}"/>
- </copy>
-
-
- <copy todir="${tmp.dir}/lib" filtering="no">
- <fileset dir="${dist.lib}">
- <include name="jbosscache-JDK140.jar"/>
- </fileset>
- </copy>
-
- <zip zipfile="${dist.dir}/${module.name}-core-JDK140-${module.version}.zip">
- <zipfileset dir="${tmp.dir}" prefix="${module.name}-core-JDK140-${module.version}" filemode="755">
- <include name="**/*"/>
- <include name="org/jboss/cache/**"/>
- <exclude name="pojocache*"/>
- <exclude name="org/jboss/cache/pojo/**"/>
- <exclude name="src/**"/>
- <exclude name="lib/pojocache.jar"/>
- <exclude name="lib/jbosscache.jar"/>
- <exclude name="lib/jboss-aop*.jar"/>
- <exclude name="lib/trove.jar"/>
- <exclude name="lib/qdox.jar"/>
- <exclude name="examples/**"/>
- <exclude name="resources/**"/>
- <exclude name="docs/javadoc/**"/>
- <exclude name="docs/PojoCache/**"/>
- <exclude name="docs/faq-pojo/**"/>
- <exclude name="docs/tutorial-pojo/**"/>
- <exclude name="tests"/>
- </zipfileset>
- </zip>
- -->
-
- <!-- Remove temp dirs -->
- <delete dir="${tmp.dir}"/>
-
- <!-- build checksums -->
- <checksum file="${dist.dir}/${module.name}-all-${module.version}.zip"/>
- <checksum file="${dist.dir}/${module.name}-core-${module.version}.zip"/>
- <!-- uncomment after JBCACHE-664 is closed
- <checksum file="${dist.dir}/${module.name}-core-JDK140-${module.version}.zip"/>
- -->
- <checksum file="${dist.dir}/${module.name}-pojo-${module.version}.zip"/>
- <checksum file="${dist.dir}/bdbje-for-${module.name}-${module.version}.zip"/>
- </target>
-
- <target name="perfTestJar" depends="compile-cache, manifest" description="Builds jar file for the perf test">
- <jar jarfile="${output.dir}/perfTest.jar">
- <fileset dir="${compiletest.dir}">
- <include name="org/jboss/cache/data/**"/>
- <include name="org/jboss/cache/Server*.class"/>
- </fileset>
- </jar>
- </target>
-
- <!-- Clover build targets -->
- <taskdef resource="clovertasks"/>
- <typedef resource="clovertypes"/>
-
- <target name="with.clover">
- <mkdir dir="${clover.dir}"/>
- <mkdir dir="${clover.dir}/coverage"/>
- <mkdir dir="${clover.dir}/report"/>
- <clover-setup initString="${clover.dir}/coverage/JBCcoverage.db" relative="yes">
- <fileset dir="${root.dir}">
- <patternset id="sources">
- <include name="**/*.java"/>
- <exclude name="**/obsolete/**"/>
- <exclude name="**/*1_4*"/>
- <exclude name="**/interop/**/*"/>
- <exclude name="**/stress/**/*"/>
- <exclude name="**/perf/**/*"/>
- <exclude name="**/compat/**/*"/>
- <exclude name="**/data/**/*"/>
- <exclude name="**/demo/**/*"/>
- </patternset>
- <patternset refid="junit.excludes"/>
- </fileset>
- </clover-setup>
- </target>
-
- <target name="clover.html" depends="with.clover">
- <mkdir dir="${clover.dir}/report/html"/>
- <clover-report>
- <current outfile="${clover.dir}/report/html/src">
- <fileset dir="${src.dir}"/>
- <format type="html"/>
- </current>
- <current outfile="${clover.dir}/report/html/tests">
- <fileset dir="${tests.dir}"/>
- <format type="html"/>
- </current>
- </clover-report>
- </target>
-
- <target name="clover.xml" depends="with.clover">
- <mkdir dir="${clover.dir}/report/xml"/>
- <clover-report>
- <current outfile="${clover.dir}/report/xml/JBCcoverage_src.xml">
- <fileset dir="${src.dir}"/>
- <format type="xml"/>
- </current>
- <current outfile="${clover.dir}/report/xml/JBCcoverage_tests.xml">
- <fileset dir="${tests.dir}"/>
- <format type="xml"/>
- </current>
- </clover-report>
- </target>
-
- <target name="clover.pdf" depends="with.clover">
- <mkdir dir="${clover.dir}/report/pdf"/>
- <clover-report>
- <current outfile="${clover.dir}/report/pdf/JBCcoverage_src.pdf" summary="true">
- <fileset dir="${src.dir}"/>
- <format type="pdf"/>
- </current>
- <current outfile="${clover.dir}/report/pdf/JBCcoverage_tests.pdf" summary="true">
- <fileset dir="${tests.dir}"/>
- <format type="pdf"/>
- </current>
- </clover-report>
- </target>
-
- <target name="clover.log" depends="with.clover">
- <clover-log/>
- </target>
-</project>
Deleted: core/trunk/build_reports.bat
===================================================================
--- core/trunk/build_reports.bat 2007-08-14 16:31:29 UTC (rev 4249)
+++ core/trunk/build_reports.bat 2007-08-14 16:34:22 UTC (rev 4250)
@@ -1,2 +0,0 @@
-SET CLASSPATH=%CLASSPATH%;lib\xalan.jar
-build reports
\ No newline at end of file
Deleted: core/trunk/deploy-maven.sh
===================================================================
--- core/trunk/deploy-maven.sh 2007-08-14 16:31:29 UTC (rev 4249)
+++ core/trunk/deploy-maven.sh 2007-08-14 16:34:22 UTC (rev 4250)
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-VER=${1}
-
-if [ ! $VER ]
-then
- echo Usage: deploy-maven.sh VERSION_NUMBER
- echo eg: deploy-maven.sh 3.0.0.GA
- exit
-fi
-
-
-echo "Deploying to a LOCAL maven2 repo, located in ../maven2 with version ${VER}"
-
-mvn deploy:deploy-file -Dfile=dist/lib/jbosscache.jar -Durl=file:../maven2 -DrepositoryId=jboss_maven2_repo -DpomFile=pom.xml -DgroupId=jboss -DartifactId=jboss-cache -Dversion=${VER} -DuniqueVersion=true
-
-echo "Done. Now commit the maven2 repo to svn"
-
17 years, 4 months
JBoss Cache SVN: r4249 - in core/trunk: assembly and 23 other directories.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2007-08-14 12:31:29 -0400 (Tue, 14 Aug 2007)
New Revision: 4249
Added:
core/trunk/README-Maven.txt
core/trunk/assembly/
core/trunk/assembly/all.xml
core/trunk/assembly/bin.xml
core/trunk/assembly/doc.xml
core/trunk/src/
core/trunk/src/main/
core/trunk/src/main/docbook/
core/trunk/src/main/docbook/css/
core/trunk/src/main/docbook/css/html.css
core/trunk/src/main/docbook/faq/
core/trunk/src/main/docbook/faq/en/
core/trunk/src/main/docbook/faq/en/master.xml
core/trunk/src/main/docbook/images/
core/trunk/src/main/docbook/images/BuddyReplication.png
core/trunk/src/main/docbook/images/CacheLoader.png
core/trunk/src/main/docbook/images/CacheMgmtInterceptor.png
core/trunk/src/main/docbook/images/Configuration.png
core/trunk/src/main/docbook/images/DataVersions.png
core/trunk/src/main/docbook/images/DelegatingCacheLoader.doc
core/trunk/src/main/docbook/images/DelegatingCacheLoader.png
core/trunk/src/main/docbook/images/Interceptor.png
core/trunk/src/main/docbook/images/Listeners.png
core/trunk/src/main/docbook/images/LocalCacheLoader.doc
core/trunk/src/main/docbook/images/LocalCacheLoader.png
core/trunk/src/main/docbook/images/Marshaller.png
core/trunk/src/main/docbook/images/MultipleCacheLoaders.doc
core/trunk/src/main/docbook/images/MultipleCacheLoaders.png
core/trunk/src/main/docbook/images/OnlyOneCacheLoader.doc
core/trunk/src/main/docbook/images/OnlyOneCacheLoader.png
core/trunk/src/main/docbook/images/PackageOverview-BuddyReplication.png
core/trunk/src/main/docbook/images/PublicAPI.png
core/trunk/src/main/docbook/images/SPI.png
core/trunk/src/main/docbook/images/SharedCacheLoader.doc
core/trunk/src/main/docbook/images/SharedCacheLoader.png
core/trunk/src/main/docbook/images/TransactionLookup.png
core/trunk/src/main/docbook/images/TreeCacheArchitecture.png
core/trunk/src/main/docbook/images/TreeNodeExample.gif
core/trunk/src/main/docbook/tutorial/
core/trunk/src/main/docbook/tutorial/en/
core/trunk/src/main/docbook/tutorial/en/master.xml
core/trunk/src/main/docbook/userguide/
core/trunk/src/main/docbook/userguide/en/
core/trunk/src/main/docbook/userguide/en/master.xml
core/trunk/src/main/docbook/userguide/en/modules/
core/trunk/src/main/docbook/userguide/en/modules/architecture.xml
core/trunk/src/main/docbook/userguide/en/modules/basic_api.xml
core/trunk/src/main/docbook/userguide/en/modules/cache_loaders.xml
core/trunk/src/main/docbook/userguide/en/modules/compatibility.xml
core/trunk/src/main/docbook/userguide/en/modules/configuration.xml
core/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml
core/trunk/src/main/docbook/userguide/en/modules/deployment.xml
core/trunk/src/main/docbook/userguide/en/modules/eviction_policies.xml
core/trunk/src/main/docbook/userguide/en/modules/introduction.xml
core/trunk/src/main/docbook/userguide/en/modules/jmx_reference.xml
core/trunk/src/main/docbook/userguide/en/modules/preface.xml
core/trunk/src/main/docbook/userguide/en/modules/replication.xml
core/trunk/src/main/docbook/userguide/en/modules/transactions.xml
core/trunk/src/main/java/
core/trunk/src/main/java/org/
core/trunk/src/main/java/org/jboss/
core/trunk/src/main/java/org/jboss/cache/
core/trunk/src/main/java/org/jboss/cache/MyClass.java
core/trunk/src/main/resources/
core/trunk/src/main/resources/replSync-service.xml
core/trunk/src/test/
core/trunk/src/test/java/
core/trunk/src/test/java/org/
core/trunk/src/test/java/org/jboss/
core/trunk/src/test/java/org/jboss/cache/
core/trunk/src/test/java/org/jboss/cache/MyClassTest.java
core/trunk/src/test/resources/
core/trunk/src/test/resources/replSync-service-test.xml
Modified:
core/trunk/pom.xml
Log:
Migrating to SVN
Added: core/trunk/README-Maven.txt
===================================================================
--- core/trunk/README-Maven.txt (rev 0)
+++ core/trunk/README-Maven.txt 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,50 @@
+Working with Maven
+------------------
+
+Requirements:
+
+* Java 5.0 and above
+* Maven 2.x
+
+Typical lifecycle phases
+------------------------
+
+Maven will create a target/ directory under the root for the creation of
+output at every stage.
+
+* mvn clean: cleans out any old builds and binaries
+
+* mvn compile: compiles java source code.
+
+* mvn test: runs the TestNG unit test suite on the compiled code. Will also compile the tests.
+
+* mvn package: packages the module as a jar file and builds the javadocs and user documentation from docbook sources.
+
+* mvn install: will install the artifacts in your local repo for use by other projects (such as JBoss Cache POJO edition which depends on JBoss Cache Core). Will also use Maven's assembly plugin to build ZIP files for download (in target/distribution)
+
+* mvn deploy: will build and deploy the project to the JBoss snapshots repository. Note that you should have your WebDAV username and password set up. (Deploys snapshots to http://snapshots.jboss.org/maven2/org/jboss/cache/)
+
+
+Setting up your WebDAV username and password to deploy project snapshots
+------------------------------------------------------------------------
+
+You will also have to configure maven to use your username and password to access this repository. For this, you will have to modify the servers section of maven settings file ($MAVEN_HOME/conf/settings.xml, or ~/.m2/settings.xml). Something similar to the following should be added:
+
+ <servers>
+...
+ <server>
+ <id>snapshots.jboss.org</id>
+ <username>webdav-user</username>
+ <password>webdav-pass</password>
+ </server>
+ </servers>
+
+
+Integration with CruiseControl
+------------------------------
+
+CruiseControl should do the following:
+
+* Go into core/code
+* Run "mvn clean site" - will clean and run tests, and then prepare reports. In addition to unit tests, this project is set up to run FindBugs, PMD, jxr, and a bunch of other code analysis tools and provide a report in target/site/project-reports.html - which should be linked from the CruiseControl summary page.
+
Added: core/trunk/assembly/all.xml
===================================================================
--- core/trunk/assembly/all.xml (rev 0)
+++ core/trunk/assembly/all.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,74 @@
+<assembly>
+ <id>all</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>true</includeBaseDirectory>
+
+ <fileSets>
+
+ <!-- code -->
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory/>
+ <includes>
+ <include>*.jar</include>
+ </includes>
+ </fileSet>
+
+ <!-- resources -->
+ <fileSet>
+ <directory>src/main/resources</directory>
+ <outputDirectory>etc</outputDirectory>
+ </fileSet>
+
+ <!-- srcs -->
+ <fileSet>
+ <directory>src/main/java</directory>
+ <outputDirectory>src</outputDirectory>
+ </fileSet>
+
+ <!-- tests -->
+ <fileSet>
+ <directory>src/test/java</directory>
+ <outputDirectory>test</outputDirectory>
+ </fileSet>
+
+ <!-- test resources -->
+ <fileSet>
+ <directory>src/test/resources</directory>
+ <outputDirectory>test</outputDirectory>
+ </fileSet>
+
+ <!-- EULAs and license files -->
+ <fileSet>
+ <directory>doc</directory>
+ <outputDirectory/>
+ <includes>
+ <include>*.txt</include>
+ </includes>
+ </fileSet>
+
+ <!-- docs -->
+ <fileSet>
+ <directory>target/site/apidocs</directory>
+ <outputDirectory>doc/apidocs</outputDirectory>
+ </fileSet>
+
+ <fileSet>
+ <directory>target/docbook</directory>
+ <outputDirectory>doc/</outputDirectory>
+ </fileSet>
+ </fileSets>
+
+ <dependencySets>
+ <dependencySet>
+ <outputDirectory>lib</outputDirectory>
+ <outputFileNameMapping>${artifactId}.${extension}</outputFileNameMapping>
+ <unpack>false</unpack>
+ <scope>runtime</scope>
+ </dependencySet>
+ </dependencySets>
+</assembly>
Added: core/trunk/assembly/bin.xml
===================================================================
--- core/trunk/assembly/bin.xml (rev 0)
+++ core/trunk/assembly/bin.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,46 @@
+<assembly>
+ <id>bin</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>true</includeBaseDirectory>
+
+ <fileSets>
+ <!-- code -->
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory/>
+ <includes>
+ <include>*.jar</include>
+ </includes>
+ </fileSet>
+
+ <!-- resources -->
+ <fileSet>
+ <directory>src/main/resources</directory>
+ <outputDirectory>etc</outputDirectory>
+ </fileSet>
+
+ <!-- EULAs and license files -->
+ <fileSet>
+ <directory>doc</directory>
+ <outputDirectory/>
+ <includes>
+ <include>*.txt</include>
+ </includes>
+ </fileSet>
+
+ </fileSets>
+
+ <dependencySets>
+ <dependencySet>
+ <outputDirectory>lib</outputDirectory>
+ <outputFileNameMapping>${artifactId}.${extension}</outputFileNameMapping>
+ <unpack>false</unpack>
+ <scope>runtime</scope>
+ </dependencySet>
+ </dependencySets>
+
+</assembly>
Added: core/trunk/assembly/doc.xml
===================================================================
--- core/trunk/assembly/doc.xml (rev 0)
+++ core/trunk/assembly/doc.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,32 @@
+<assembly>
+ <id>doc</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>true</includeBaseDirectory>
+
+ <fileSets>
+ <!-- EULAs and license files -->
+ <fileSet>
+ <directory>doc</directory>
+ <outputDirectory/>
+ <includes>
+ <include>*.txt</include>
+ </includes>
+ </fileSet>
+
+ <!-- docs -->
+ <fileSet>
+ <directory>target/site/apidocs</directory>
+ <outputDirectory>doc/apidocs</outputDirectory>
+ </fileSet>
+
+ <fileSet>
+ <directory>target/docbook</directory>
+ <outputDirectory>doc/</outputDirectory>
+ </fileSet>
+ </fileSets>
+
+</assembly>
Modified: core/trunk/pom.xml
===================================================================
--- core/trunk/pom.xml 2007-08-14 16:29:26 UTC (rev 4248)
+++ core/trunk/pom.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -1,152 +1,218 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <parent>
- <artifactId>jboss-parent</artifactId>
- <groupId>jboss</groupId>
- <version>1</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>jboss-cache</artifactId>
- <name>JBoss Cache</name>
- <version>2.0.0-CR3</version>
- <url>http://labs.jboss.org/jbosscache</url>
- <build>
- <sourceDirectory>src</sourceDirectory>
- <testSourceDirectory>tests</testSourceDirectory>
- <testResources>
- <testResource>
- <directory>etc</directory>
- <includes>
- <include>**/*.xml</include>
- </includes>
- </testResource>
- </testResources>
- <plugins>
- <plugin>
- <artifactId>maven-compiler-plugin</artifactId>
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <properties>
+ <jbosscache-core-version>2.1.0-SNAPSHOT</jbosscache-core-version>
+ </properties>
+ <parent>
+ <groupId>org.jboss.cache</groupId>
+ <artifactId>jbosscache-common-parent</artifactId>
+ <version>1.0</version>
+ </parent>
+ <groupId>org.jboss.cache</groupId>
+ <artifactId>jbosscache-core</artifactId>
+ <version>${jbosscache-core-version}</version>
+ <name>JBoss Cache - Core Edition</name>
+ <description>JBoss Cache - Core Edition</description>
+ <packaging>jar</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>jgroups</groupId>
+ <artifactId>jgroups</artifactId>
+ <version>2.5.0-GA</version>
+ </dependency>
+ <dependency>
+ <groupId>jdbm</groupId>
+ <artifactId>jdbm</artifactId>
+ <version>1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>c3p0</groupId>
+ <artifactId>c3p0</artifactId>
+ <version>0.9.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.0.4</version>
+ </dependency>
+ <dependency>
+ <groupId>sleepycat</groupId>
+ <artifactId>je</artifactId>
+ <version>1.7.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.microcontainer</groupId>
+ <artifactId>jboss-aop-mc-int</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.2-beta-1</version>
+ <executions>
+ <execution>
+ <id>assemble</id>
+ <phase>install</phase>
+ <goals>
+ <goal>attached</goal>
+ </goals>
<configuration>
- <source>1.5</source>
- <target>1.5</target>
- <testIncludes>
- <include>functional/**/*.java</include>
- </testIncludes>
+ <descriptors>
+ <descriptor>assembly/bin.xml</descriptor>
+ <descriptor>assembly/doc.xml</descriptor>
+ <descriptor>assembly/all.xml</descriptor>
+ </descriptors>
+ <finalName>${artifactId}-${jbosscache-core-version}</finalName>
+ <outputDirectory>target/distribution</outputDirectory>
+ <workDirectory>target/assembly/work</workDirectory>
</configuration>
- </plugin>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
+ </execution>
+ </executions>
+ </plugin>
+ <!-- the docbook generation plugin for the user guide -->
+ <plugin>
+ <groupId>org.jboss.maven.plugins</groupId>
+ <artifactId>maven-jdocbook-plugin</artifactId>
+ <version>2.0.0</version>
+ <extensions>true</extensions>
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.cache</groupId>
+ <artifactId>jbosscache-doc-xslt-support</artifactId>
+ <version>1.0</version>
+ </dependency>
+ </dependencies>
+ <executions>
+
+ <!-- The User Guide-->
+ <execution>
+ <id>userguide_en</id>
+ <phase>package</phase>
+ <goals>
+ <goal>resources</goal>
+ <goal>generate</goal>
+ </goals>
<configuration>
- <testFailureIgnore>true</testFailureIgnore>
+ <sourceDocumentName>master.xml</sourceDocumentName>
+ <sourceDirectory>${basedir}/src/main/docbook/userguide/en</sourceDirectory>
+ <imageResource>
+ <directory>${basedir}/src/main/docbook/images</directory>
+ </imageResource>
+ <cssResource>
+ <directory>${basedir}/src/main/docbook/css</directory>
+ </cssResource>
+ <targetDirectory>${basedir}/target/docbook/userguide_en</targetDirectory>
+ <formats>
+ <format>
+ <formatName>pdf</formatName>
+ <stylesheetResource>classpath:/standard/fopdf.xsl</stylesheetResource>
+ <finalName>userguide_en.pdf</finalName>
+ </format>
+ <format>
+ <formatName>html</formatName>
+ <stylesheetResource>classpath:/standard/html_chunk.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ </format>
+ <format>
+ <formatName>html_single</formatName>
+ <stylesheetResource>classpath:/standard/html.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ </format>
+ </formats>
+ <options>
+ <xincludeSupported>false</xincludeSupported>
+ </options>
</configuration>
- </plugin>
- </plugins>
- </build>
- <repositories>
- <repository>
- <id>jboss</id>
- <name>JBoss Inc. Repository</name>
- <url>http://repository.jboss.com/maven2/</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </repository>
- </repositories>
- <dependencies>
- <dependency>
- <groupId>ant</groupId>
- <artifactId>ant</artifactId>
- <version>1.6.5</version>
- </dependency>
- <dependency>
- <groupId>ant</groupId>
- <artifactId>ant-junit</artifactId>
- <version>1.6.5</version>
- </dependency>
- <dependency>
- <groupId>c3p0</groupId>
- <artifactId>c3p0</artifactId>
- <version>0.9.0.4</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- <version>1.1</version>
- </dependency>
- <dependency>
- <groupId>concurrent</groupId>
- <artifactId>concurrent</artifactId>
- <version>1.3.4</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>findbugs</groupId>
- <artifactId>annotations</artifactId>
- <version>1.0.0</version>
- </dependency>
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-common-core</artifactId>
- <version>2.0.3.GA</version>
- </dependency>
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-j2ee</artifactId>
- <version>4.0.2</version>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.14</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>jdbm</groupId>
- <artifactId>jdbm</artifactId>
- <version>1.0</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.beanshell</groupId>
- <artifactId>bsh</artifactId>
- <version>2.0b4</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-aop</artifactId>
- <version>2.0.0.alpha2</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>jgroups</groupId>
- <artifactId>jgroups</artifactId>
- <version>2.5.0-BETA2</version>
- <exclusions>
- <exclusion>
- <groupId>bsh</groupId>
- <artifactId>bsh</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.apache.derby</groupId>
- <artifactId>derby</artifactId>
- <version>10.2.1.6</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>sleepycat</groupId>
- <artifactId>je</artifactId>
- <version>1.7.0</version>
- <optional>true</optional>
- </dependency>
- </dependencies>
+ </execution>
+
+ <!-- The Tutorial -->
+ <execution>
+ <id>tutorial_en</id>
+ <phase>package</phase>
+ <goals>
+ <goal>resources</goal>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <sourceDocumentName>master.xml</sourceDocumentName>
+ <sourceDirectory>${basedir}/src/main/docbook/tutorial/en</sourceDirectory>
+ <imageResource>
+ <directory>${basedir}/src/main/docbook/images</directory>
+ </imageResource>
+ <cssResource>
+ <directory>${basedir}/src/main/docbook/css</directory>
+ </cssResource>
+ <targetDirectory>${basedir}/target/docbook/tutorial_en</targetDirectory>
+ <formats>
+ <format>
+ <formatName>pdf</formatName>
+ <stylesheetResource>classpath:/standard/fopdf.xsl</stylesheetResource>
+ <finalName>tutorial_en.pdf</finalName>
+ </format>
+ <format>
+ <formatName>html</formatName>
+ <stylesheetResource>classpath:/standard/html_chunk.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ </format>
+ <format>
+ <formatName>html_single</formatName>
+ <stylesheetResource>classpath:/standard/html.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ </format>
+ </formats>
+ <options>
+ <xincludeSupported>false</xincludeSupported>
+ </options>
+ </configuration>
+ </execution>
+
+ <!-- the FAQs -->
+ <execution>
+ <id>faq_en</id>
+ <phase>package</phase>
+ <goals>
+ <goal>resources</goal>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <sourceDocumentName>master.xml</sourceDocumentName>
+ <sourceDirectory>${basedir}/src/main/docbook/faq/en</sourceDirectory>
+ <imageResource>
+ <directory>${basedir}/src/main/docbook/images</directory>
+ </imageResource>
+ <cssResource>
+ <directory>${basedir}/src/main/docbook/css</directory>
+ </cssResource>
+ <targetDirectory>${basedir}/target/docbook/faq_en</targetDirectory>
+ <formats>
+ <format>
+ <formatName>pdf</formatName>
+ <stylesheetResource>classpath:/standard/fopdf.xsl</stylesheetResource>
+ <finalName>faq_en.pdf</finalName>
+ </format>
+ <format>
+ <formatName>html</formatName>
+ <stylesheetResource>classpath:/standard/html_chunk.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ </format>
+ <format>
+ <formatName>html_single</formatName>
+ <stylesheetResource>classpath:/standard/html.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ </format>
+ </formats>
+ <options>
+ <xincludeSupported>false</xincludeSupported>
+ </options>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
</project>
Added: core/trunk/src/main/docbook/css/html.css
===================================================================
--- core/trunk/src/main/docbook/css/html.css (rev 0)
+++ core/trunk/src/main/docbook/css/html.css 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,168 @@
+* {
+ font-family: sans-serif;
+ font-size: 14px;
+}
+
+A {
+ color: #0000CC;
+}
+
+A:active {
+ color: #0000CC;
+}
+
+A:visited {
+ color: #0000CC;
+}
+
+P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
+ color: #000000;
+}
+
+TD, TH, SPAN {
+ color: #000000;
+}
+
+BLOCKQUOTE {
+ margin-right: 0px;
+}
+
+H1, H2, H3, H4, H5, H6 {
+ color: #003399; /*font-weight: 500;*/
+/*margin-top: 10px;*/
+/*padding-top: 5px;*/
+}
+
+.title {
+ margin-top: 10px;
+ padding-top: 5px;
+ font-weight: bold;
+}
+
+.subtitle {
+ margin-top: 10px;
+ padding-top: 5px;
+ font-style: italic;
+ font-weight: normal;
+}
+
+H1 {
+ font-size: 180%;
+}
+
+H2 {
+ font-size: 140%;
+}
+
+H3 {
+ font-size: 120%;
+}
+
+H4 {
+ font-size: 100%;
+}
+
+H5 {
+ font-size: 100%;
+}
+
+H6 {
+ font-size: 100%;
+}
+
+TABLE {
+ border-collapse: collapse;
+ border-spacing: 0; /*border: 1px dashed #CCCCCC;*/
+ empty-cells: hide;
+ width: 100%
+}
+
+TD {
+ padding: 4pt;
+}
+
+TT {
+ font-size: 100%;
+ color: #111111;
+ font-family: monospace;
+}
+
+PRE {
+ font-size: 100%;
+ padding: 5px;
+ border-style: solid;
+ border-width: 1px;
+ border-color: #CCCCCC;
+ background-color: #F4F4F4;
+ font-family: monospace;
+ width: auto;
+}
+
+HR {
+ width: 100%;
+ height: 1px;
+ background-color: #CCCCCC;
+ border-width: 0px;
+ padding: 0px;
+ color: #CCCCCC;
+}
+
+.term {
+ font-weight: bold;
+}
+
+.note {
+ padding-bottom: 5px;
+ padding-left: 5px;
+ padding-right: 5px;
+ background-color: #FFFFCC;
+}
+
+.warning {
+ padding-bottom: 5px;
+ padding-left: 5px;
+ padding-right: 5px;
+ background-color: #FBDADA;
+}
+
+.releaseinfo {
+ font-size: 100%;
+ font-weight: bold;
+}
+
+.pubdate, .copyright {
+ font-size: 80%;
+ font-style: italic;
+}
+
+.email {
+ font-family: sans-serif;
+ padding-left: 40px;
+ padding-right: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+ font-size: 10pt;
+ margin: 0 0 0 0;
+
+}
+
+.firstname {
+ font-weight: bold;
+ margin: 0 0 0 0;
+ padding: 0 0 0 0;
+ padding-left: 20px;
+ font-size: 10pt;
+}
+
+.surname {
+ font-weight: bold;
+ margin: 0 0 0 0;
+ padding: 0 0 0 0;
+ font-size: 10pt;
+}
+
+.author {
+ padding: 0 0 0 0;
+ margin: 0 0 0 0;
+}
+
Added: core/trunk/src/main/docbook/faq/en/master.xml
===================================================================
--- core/trunk/src/main/docbook/faq/en/master.xml (rev 0)
+++ core/trunk/src/main/docbook/faq/en/master.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,1582 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "../../../../docbook-support/support/docbook-dtd/docbookx.dtd"
+ >
+<book lang="en">
+ <bookinfo>
+ <title>Frequently Asked Questions about JBoss Cache</title>
+ <releaseinfo>Release 2.0.0</releaseinfo>
+ <pubdate>June 2007</pubdate>
+
+ <author>
+ <firstname>Manik</firstname>
+ <surname>Surtani</surname>
+ <email>manik(a)jboss.org</email>
+ </author>
+
+ <author>
+ <firstname>Ben</firstname>
+ <surname>Wang</surname>
+ <email>ben.wang(a)jboss.com</email>
+ </author>
+
+ <author>
+ <firstname>Bela</firstname>
+ <surname>Ban</surname>
+ <email>bela(a)jboss.com</email>
+ </author>
+
+ <author>
+ <firstname>Scott</firstname>
+ <surname>Marlow</surname>
+ <email>smarlow(a)novell.com</email>
+ </author>
+
+ <author>
+ <firstname>Galder</firstname>
+ <surname>Zamarreño</surname>
+ <email>galder.zamarreno(a)jboss.com</email>
+ </author>
+
+ <abstract>
+ <para>This is a compilation of the most frequently asked
+ questions about JBoss Cache. Please report any bugs,
+ inconsistencies, or omissions you find in this FAQ on the
+ <ulink url="http://www.jboss.org/index.html?module=bb&op=viewforum&f=157">JBoss Cache User Form
+ </ulink>
+ .
+ </para>
+ <para>
+ This FAQ is divided into specific sections, all pertaining to the core JBoss Cache library. PojoCache has a
+ separate FAQ
+ document pertaining to PojoCache specifics.
+ </para>
+ </abstract>
+ </bookinfo>
+
+
+ <chapter id="general">
+ <title>General Information</title>
+ <qandaset>
+
+ <qandaentry>
+ <question>
+ <para>What is JBoss Cache?</para>
+ </question>
+
+ <answer>
+ <para>JBoss Cache is a replicated and transactional cache. It is
+ replicated since multiple JBoss Cache instances can be distributed
+ (either within the same JVM or across several JVMs whether they reside on
+ the same machine or on different machines on a network) and data is
+ replicated across the whole group. It is transactional because a
+ user can configure a
+ <ulink url="http://java.sun.com/products/jta/">JTA</ulink>
+ compliant transaction
+ manager and make any cache
+ interaction transactional. Note that the cache can also be run without
+ any replication; this is the local mode.
+ </para>
+
+ <para>JBoss Cache comes in two flavours: Core and Pojo versions. The core library
+ (using the
+ <literal>org.jboss.cache.Cache</literal>
+ interface
+ ) is the underlying library that organises data in a tree-like structure and handles all locking,
+ passivation,
+ eviction and replication characteristics of data in the cache. The pojo library (using the
+ <literal>org.jboss.cache.pojo.PojoCache</literal>
+ interface) is built atop the core library and allows introspection
+ of objects in the cache providing transparent coherence by using JBoss AOP. Note that the Pojo version
+ of JBoss Cache
+ (referred to as PojoCache) comes with a separate set of documentation (user guide, FAQ, etc.)
+ available on the
+ <ulink url="http://labs.jboss.com/portal/jbosscache/docs/index.html">JBoss Cache documentation site
+ </ulink>
+ .
+ </para>
+
+ <para>
+ JBoss Cache is made available in one of four different packages:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>jboss-cache-core</literal>
+ </para>
+ contains the core Cache library for users who do not wish to use the additional functionality
+ offered by PojoCache.
+ </listitem>
+ <listitem>
+ <para>
+ <literal>jboss-cache-pojo</literal>
+ </para>
+ contains the core Cache library as well as the PojoCache extensions and dependencies.
+ </listitem>
+ <listitem>
+ <para>
+ <literal>jboss-cache-all</literal>
+ </para>
+ contains all of the above, including unit tests and source code.
+ </listitem>
+ <listitem>
+ <para>
+ <literal>jboss-cache-core-JDK140</literal>
+ </para>
+ contains a JDK 1.4 compatible version of the core Cache library. Note that PojoCache is only
+ available for JDK 5.0.
+ </listitem>
+ </itemizedlist>
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Who are the JBoss Cache developers?</para>
+ </question>
+
+ <answer>
+ <para>
+ JBoss Cache has an active community of developers and contributors. The project was founded by Bela
+ Ban
+ and is currently led by Manik Surtani. Jason Greene is the lead for the PojoCache subsystem, and other
+ contributors both past and present include Ben Wang, Harald Gliebe, Brian Stansberry, Galder Zamarreno
+ and Elias Ross.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>What is the license for JBoss Cache?</para>
+ </question>
+
+ <answer>
+ <para>JBoss Cache is licensed under
+ <ulink url="http://www.gnu.org/licenses/lgpl.html">LGPL</ulink>
+ .
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Where can I download JBoss Cache?</para>
+ </question>
+
+ <answer>
+ <para>The JBoss Cache
+ <ulink url="http://www.jboss.com/products/jbosscache/downloads">product download page</ulink>
+ has prebuilt binaries as well as source distributions. You can also grab snapshots from the JBoss CVS
+ repository (see
+ <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=CVSRepository">this wiki page</ulink>
+ ) - the module name is
+ <emphasis role="bold">JBossCache</emphasis>
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>How do I build JBoss Cache from CVS sources?</para>
+ </question>
+
+ <answer>
+ <para>To build, do
+ <literal>sh build.sh
+ jar
+ </literal>
+ . This will produce
+ <literal>jboss-cache.jar</literal>
+ and
+ <literal>pojocache.jar</literal>
+ in the
+ <literal>dist/lib</literal>
+ directory. Note that you will need to
+ use JDK 5 to build the distribution.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Which versions of the JDK are supported by JBoss Cache?</para>
+ </question>
+
+ <answer>
+ <para>
+ JBoss Cache is baselined on Java 5.0 and this is the platform on which JBoss Cache is most thoroughly
+ tested.
+ If, for whatever reason you have to use Java 1.4, you could build a retroweaved version of the core
+ cache
+ library that is Java 1.4 compatible, using the simple instructions on this wiki page
+ <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossCacheHabaneroJava1.4">on building and
+ running JBoss Cache on Java 1.4.
+ </ulink>
+ . Note that Red Hat Inc. does not offer commercial support for retroweaved binaries at this stage.
+ </para>
+ <para>
+ Java 6 should work as well, and we haven't heard of any specific problems of JBoss Cache run under
+ Java 6.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>How do I know the version of JBoss Cache that I am using?</para>
+ </question>
+
+ <answer>
+ <para>
+ <code>java -jar jbosscache.jar</code>
+ will spit out version details.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Can I run JBoss Cache outside of JBoss Application
+ Server?
+ </para>
+ </question>
+
+ <answer>
+ <para>
+ Of course! Even though JBoss Cache comes integrated with JBoss Application Server as an MBean service,
+ it
+ can also be run standalone, in any Java EE server such as BEA WebLogic, IBM Websphere or Tomcat. It
+ can also run in
+ a standalone Java process, completely outside of an application server. See the user guide for more
+ details.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>How can I migrate my application and configuration from using JBoss Cache 1.x to 2.x?</para>
+ </question>
+ <answer>
+ <para>Look at <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossCache200Migration">this wiki page</ulink> for help.</para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Where can I report bugs or problems?</para>
+ </question>
+
+ <answer>
+ <para>Please report any bugs or problems to
+ <ulink
+ url="http://www.jboss.org/index.html?module=bb&op=viewforum&f=157">JBoss Cache
+ User Forum
+ </ulink>
+ .
+ </para>
+ </answer>
+ </qandaentry>
+ </qandaset>
+ </chapter>
+
+ <chapter id="TreeCache">
+ <title>JBoss Cache - Core</title>
+
+ <qandaset>
+
+ <qandaentry>
+ <question>
+ <para>How do I deploy JBoss Cache as a MBean service?</para>
+ </question>
+
+ <answer>
+ <para>To deploy JBoss Cache as an MBean inside JBoss, you can copy the
+ configuration xml file over to the
+ <literal>deploy</literal>
+ directory (from
+ <literal>all</literal>
+ configuration whereby the
+ necessary jars are present). Under the standalone package
+ <literal>etc/META-INF</literal>
+ directory , there are example
+ configuration files for different cache modes that can be used to
+ deploy JBoss Cache as well.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>How do I know if my JBoss Cache MBean has been deployed?</para>
+ </question>
+
+ <answer>
+ <para>To verify that your JBoss Cache MBean is deployed correctly,
+ you can first check the log output under the command console. Next
+ you can verify it from JBoss JMX console. Look for
+ <literal>jboss.cache</literal>
+ domain.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>How do I access the JBoss Cache MBean?</para>
+ </question>
+
+ <answer>
+ <para>Accessing the JBoss Cache MBean is just like accessing any
+ JBoss MBean. Here is a code snippet:
+ </para>
+
+ <programlisting>
+ import org.jboss.mx.util.MBeanServerLocator;
+ import org.jboss.mx.util.MBeanProxyExt;
+ import org.jboss.cache.TreeCacheMBean;
+ import javax.management.MBeanServer;
+ ...
+
+ MBeanServer server;
+ TreeCacheMBean cache;
+
+ public init() throws Exception
+ {
+ try
+ {
+ server = MBeanServerLocator.locateJBoss();
+ cache = (TreeCacheMBean) MBeanProxyExt.create(TreeCacheMBean.class, "jboss.cache:service=TreeCache",
+ server);
+ }
+ catch (Exception ex)
+ {
+ // handle exception
+ }
+ }
+
+ public void myBusinessMethod()
+ {
+ Object value = cache.get("/my/node", "myKey");
+
+ HashMap stuff = new HashMap();
+ stuff.put("key1", "value1");
+ stuff.put("key2", "value2");
+ stuff.put("key3", "value3");
+
+ cache.put("/my/new/node", stuff);
+
+ cache.remove("/my/node");
+
+ ...
+ }
+
+ </programlisting>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Can I run multiple JBoss Cache instances on the same VM?</para>
+ </question>
+
+ <answer>
+ <para>Yes. There are some scenarios where you may want to run
+ multiple instances of JBoss Cache. For example, you want to run
+ multiple local cache instances with each instance having its own
+ configuration (e.g., different cache policy). In this case, you will
+ need multiple xml configuration files.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Can JBoss Cache run as a second level cache inside
+ Hibernate?
+ </para>
+ </question>
+
+ <answer>
+ <para>Yes. Since Hibernate 3.0 release, you can configure it to use
+ JBoss Cache as a second level cache. For details,
+ see Hibernate documentation, and also see
+ <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossCacheHibernate">
+ http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossCacheHibernate
+ </ulink>
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>What about using Pojo Cache as a Hibernate cache?</para>
+ </question>
+
+ <answer>
+ <para>It is not necessary to use PojoCache for second level
+ cache inside Hibernate because Hibernate
+ manages fine-grained fields in Java objects. Using PojoCache won't
+ provide any advantage.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>How can I configure JBoss Cache?</para>
+ </question>
+
+ <answer>
+ <para>You can configure the JBoss Cache through a configuration xml
+ file or programmatically using a
+ <literal>org.jboss.cache.config.Configuration</literal>
+ object, passed in to the
+ <literal>org.jboss.cache.CacheFactory</literal>
+ instance.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>In the configuration xml file, there are tags such as
+ <literal>class</literal>
+ ,
+ <literal>MBean</literal>
+ , etc. What are
+ these?
+ </para>
+ </question>
+
+ <answer>
+ <para>These are tags for deploying JBoss Cache as a JBoss MBean
+ service. For consistency, we have kept them in the
+ standalone package as well, specifically, the
+ <literal>MBean</literal>
+ tag. If you run in standalone mode,
+ JBoss Cache will ignore these elements.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>What is the difference between the different cache
+ modes?
+ </para>
+ </question>
+
+ <answer>
+ <para>JBossCache has five different cache modes, i.e.,
+ <literal>LOCAL</literal>
+ ,
+ <literal>REPL_SYNC</literal>
+ ,
+ <literal>REPL_ASYNC</literal>
+ ,
+ <literal>INVALIDATION_SYNC</literal>
+ and
+ <literal>INVALIDATION_ASYNC</literal>
+ . If you want to run JBoss Cache as a
+ single instance, then you should set the cache mode to
+ <literal>LOCAL</literal>
+ so that it won't attempt to replicate anything.
+ If you want to have synchronous replication among different
+ JBoss Cache instances, you set it to
+ <literal>REPL_SYNC</literal>
+ .
+ For asynchronous replication, use
+ <literal>AYSNC_REPL</literal>
+ . If you do not wish to replicate cached data but simply inform other caches in a cluster that data
+ under
+ specific addresses are now stale and should be evicted from memory, use
+ <literal>INVALIDATION_SYNC</literal>
+ or
+ <literal>INVALIDTAION_ASYNC</literal>
+ . Synchronous and asynchronous behavior applies to invalidation as well as replication.
+ </para>
+
+ <para>Note that
+ <literal>ASYNC_REPL</literal>
+ and
+ <literal>INVALIDATION_ASYNC</literal>
+ are non-blocking. This
+ can be useful when you want to have another JBoss Cache serving as a
+ mirror or backup and you don't want to wait for confirmation that this mirror has received your
+ messages.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>How does JBoss Cache's replication mechanism work?</para>
+ </question>
+
+ <answer>
+ <para>JBoss Cache leverages
+ <ulink url="http://www.jgroups.org">JGroups</ulink>
+ as a replication layer. A user
+ can configure the cluster of JBoss Cache instances by sharing the
+ same cluster name (
+ <literal>cluster name</literal>
+ ). There is also
+ an option of whether to populate the cache data upon starting a new
+ instance in the
+ <literal>ClusterConfig</literal>
+ attribute.
+ </para>
+
+ <para>Note that once all instances join the same replication group,
+ every replication change is propagated to all participating members.
+ There is no mechanism for sub-partitioning where some replication
+ can be done within only a subset of members, unless you use the Buddy Replication features. See the
+ user guide for more details on this.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>I run a 2 node cluster. If the network dies, do the caches continue to run?</para>
+ </question>
+
+ <answer>
+ <para>Yes, both will continue to run, but depending on your replication mode, all transactions or
+ operations may not complete. If
+ <literal>REPL_SYNC</literal>
+ is used, operations will fail while if
+ <literal>REPL_ASYNC</literal>
+ is used they will succeed. Even if they succeed though, caches will be out of sync.
+ </para>
+ </answer>
+ </qandaentry>
+
+
+ <qandaentry>
+ <question>
+ <para>Can I plug in library X instead of JGroups to handle remote calls and group communications?</para>
+ </question>
+
+ <answer>
+ <para>At this stage the answer is no. We do have an abstraction layer between the
+ communication suite and JBoss Cache in the pipelines, and this may appear as a feature at some stage
+ in
+ the future.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Does the cache need to replicate to every other instance in the cluster? Isn't this slow if the
+ cluster is large?
+ </para>
+ </question>
+
+ <answer>
+ <para>Replication need not occur to every node in the cluster. This feature -
+ called Buddy Replication -
+ allows each node to pick one or more 'buddies' in the cluster and only replicate to its buddies. This
+ allows a cluster to scale
+ very easily with no extra impact on memory or network traffic with each node added.
+ </para>
+ <para>
+ See the User Guide for more information on Buddy Replication, and how it can be used to achieve very
+ high
+ scalability.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>If I have the need for different configuration properties (e.g.,
+ <literal>CacheMode</literal>
+ and
+ <literal>IsolationLevel</literal>
+ ), do I simply need to create multiple
+ <literal>org.jboss.cache.Cache</literal>
+ instances with the appropriate configuration?
+ </para>
+ </question>
+
+ <answer>
+ <para>Yes. All the above mentioned properties are per cache
+ instance. Therefore you will need separate
+ <literal>org.jboss.cache.Cache</literal>
+ instances.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Isn't this expensive from a networking standpoint, i.e., needing to create sockets for each
+ <literal>org.jboss.cache.Cache</literal>
+ instance?
+ </para>
+ </question>
+
+ <answer>
+ <para>
+ Yes, it can be. For such cases it is recommended that you configure your cache using the JGroups
+ Multiplexer, which allows several caches to share
+ a single JGroups channel. Please see the User Guide for details on how to configure the JGroups
+ Multiplexer.
+ </para>
+ </answer>
+ </qandaentry>
+
+
+ <qandaentry>
+ <question>
+ <para>Does the
+ <literal>ClusterName</literal>
+ configuration element have
+ any relation to the JBoss AS cluster
+ <literal>PartitionName</literal>
+ ?
+ </para>
+ </question>
+
+ <answer>
+ <para>Yes. They are both JGroups group names. Besides the notion of
+ a channel in JGroups, it also can partition the channel into different
+ group names.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>When using multiple JGroups based components
+ [cluster-service.xml, cache (multiple instances)], what is the
+ correct/valid way to configure those components to make sure my
+ multicast addresses don't conflict?
+ </para>
+ </question>
+
+ <answer>
+ <para>There are two parameters to consider: multicast address (plus
+ port) and the group name. At minimum, you will have to run
+ components using a different group name. But whether to run them on
+ the same channel depends upon whether the communication performance
+ is critical for you or not. If it is, then it'd be best to run them
+ on different channels.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Does JBoss Cache support cache persistence
+ storage?
+ </para>
+ </question>
+
+ <answer>
+ <para>Yes. JBoss Cache has a cache loader
+ interface that supports cache persistence. See below for more FAQs on cache loaders.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Does JBoss Cache support cache passivation/ overflow
+ to a data store?
+ </para>
+ </question>
+
+ <answer>
+ <para>Yes. JBoss Cache uses the
+ cache loader to support cache passivation/ overflow. See
+ documentation on how to configure and use this feature.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Is JBoss Cache thread safe?</para>
+ </question>
+
+ <answer>
+ <para>Yes, it is thread safe.</para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Does JBoss Cache support XA (2PC) transactions now?</para>
+ </question>
+
+ <answer>
+ <para>No, although it is also on our to do list. Our internal
+ implementation does use a procedure similar to 2PC to coordinate a
+ transactions among different instances, but JBoss Cache is not an XA resource.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Which transaction managers are supported by
+ JBoss Cache?
+ </para>
+ </question>
+
+ <answer>
+ <para>JBoss Cache supports any TransactionManager that is
+ <ulink url="http://java.sun.com/products/jta/">JTA</ulink>
+ compliant such as JBossTM or JBossTS. JBoss Cache ships with a
+ dummy transaction manager
+ (
+ <literal>org.jboss.cache.transaction.DummyTransactionManager</literal>
+ ) for
+ testing purposes only. But note that
+ <literal>DummyTransactionManager</literal>
+ is not thread safe .i.e.,
+ it does not support concurrent transactions. Instead, only one
+ transaction is allowed at a time.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>How do I set up the cache to be transactional?</para>
+ </question>
+
+ <answer>
+ <para>You either use the default transaction manager that ships with JBoss AS
+ or you have to implement the
+ <literal>org.jboss.cache.transaction.TransactionManagerLookup</literal>
+ interface, and return an
+ instance of your
+ <literal>javax.transaction.TransactionManager</literal>
+ implementation. The
+ configuration property
+ <literal>TransactionManagerLookupClass</literal>
+ defines the class
+ to be used by the cache to fetch a reference to a
+ transaction manager. It is trivial to implement this interface to support
+ other transaction managers. Once this attribute is specified, the
+ cache will look up the transaction context from this transaction
+ manager.
+ </para>
+
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>How do I control the cache locking level?</para>
+ </question>
+
+ <answer>
+ <para>JBoss Cache lets you control the cache locking level through
+ the transaction isolation level. This is configured through the
+ attribute
+ <literal>IsolationLevel</literal>
+ . The transaction
+ isolation levels correspond to database
+ isolation levels, namely,
+ <literal>NONE</literal>
+ ,
+ <literal>READ_UNCOMMITTED</literal>
+ ,
+ <literal>READ_COMMITTED</literal>
+ ,
+ <literal>REPEATABLE_READ</literal>
+ , and
+ <literal>SERIALIZABLE</literal>
+ . Note that these isolation levels are ignored if optimistic locking is used. For details, please
+ refer
+ to the
+ user manual.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>How does JBoss Cache lock data for concurrent access?</para>
+ </question>
+
+ <answer>
+ <para>By default JBoss Cache uses pessimistic locking to lock data nodes, based on the isolation level
+ configured. We also offer optimistic locking to allow for greater concurrency
+ at
+ the cost of slight processing overhead and performance. See the documentation for a more detailed
+ discussion on concurrency and locking in JBoss Cache.
+ </para>
+ </answer>
+ </qandaentry>
+
+
+ <qandaentry>
+ <question>
+ <para>How do I enable Optimistic Locking in JBoss Cache?</para>
+ </question>
+
+ <answer>
+ <para>Use the XMl attribute
+ <code>NodeLockingScheme</code>
+ . Note that
+ <code>IsolationLevel</code>
+ is ignored if
+ <code>NodeLockingScheme</code>
+ is set to
+ <code>OPTIMISTIC</code>
+ . Also note that
+ <code>NodeLockingScheme</code>
+ defaults to
+ <code>PESSIMISTIC</code>
+ if omitted.
+ </para>
+ </answer>
+ </qandaentry>
+
+
+ <qandaentry>
+ <question>
+ <para>How does the write lock apply to an Fqn node, say,
+ "/org/jboss/test"?
+ </para>
+ </question>
+
+ <answer>
+ <para>First of all, JBoss Cache has a notion of
+ <literal>root</literal>
+ that serves as a starting point for every navigational operation.
+ The default is "/" (since the default separator is "/" for the fqn).
+ The locking then is applied to the node under root, for example
+ "/org" (no locking "/").
+ </para>
+
+ <para>Furthermore, let's say when JBoss Cache needs to apply a write
+ lock on node "/org/jboss/test", it will first try to obtain read
+ lock from the parent nodes recursively (in this example, "/org", and
+ "/org/jboss"). Only when it succeeds then it will try to obtain a
+ write lock on "/org/jboss/test".
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Can I use the cache locking level even without a transaction
+ context?
+ </para>
+ </question>
+
+ <answer>
+ <para>Yes. JBoss Cache controls the individual node locking behavior
+ through the isolation level semantics. This means even if you don't
+ use a transaction, you can specify the lock level via isolation
+ level. You can think of the node locking behavior outside of a
+ transaction as if it is under transaction with
+ <literal>auto_commit</literal>
+ on.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>With replication (REPL_SYNC/REPL_ASYNC) or invalidation (INVALIDATION_SYNC/INVALIDATION_ASYNC), how
+ often does the cache broadcast messages over the network?
+ </para>
+ </question>
+
+ <answer>
+ <para>If the updates are under transaction, then the broadcasts
+ happen only when the transaction is about to commit (actually
+ during the prepare stage internally). That is, it will be a batch
+ update. However, if the operations are not under transaction
+ context, then each update will trigger replication. Note that this
+ has performance implication if network transport is heavy (it
+ usually is).
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>How can I do a mass removal?</para>
+ </question>
+
+ <answer>
+ <para>If you do a cache.removeNode(Fqn.fromString("/myroot")), it will recursively remove
+ all the entries under "/myroot".
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Can I monitor and manage the JBoss Cache?</para>
+ </question>
+
+ <answer>
+ <para>Yes, using a JMX console such as the one shipped with JBoss AS or Java 5's
+ <literal>jconsole</literal>
+ utility. See the chapter titled
+ <emphasis role="bold">Management Information</emphasis>
+ in the JBoss Cache user guide for more details.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Can I disable JBoss Cache management attributes?</para>
+ </question>
+
+ <answer>
+ <para>Yes, you can. Set the
+ <literal>UseInterceptorMbeans</literal>
+ configuration attribute to
+ <literal>false</literal>
+ (this defaults to
+ <literal>true</literal>
+ ). See the chapter titled
+ <emphasis role="bold">Management Information</emphasis>
+ in the JBoss Cache user guide for more details.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>What happened to jboss-serialization.jar?</para>
+ </question>
+
+ <answer>
+ <para>
+ As of JBoss Cache 2.0.0, the dependency on JBoss Serialization has been dropped since most of the
+ benefits of JBoss Serialization are available in updated Java 5 VMs. Since JBoss Cache 2.0.0 is
+ baselined on Java 5, there was no need to provide these benefits separately.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Does JBoss Cache support partitioning?</para>
+ </question>
+
+ <answer>
+ <para>Not right now. JBoss Cache does not support partitioning that a
+ user can configure to have different set of data residing on
+ different cache instances while still participating as a replication
+ group.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Does JBoss Cache handle the concept of application classloading
+ inside, say, a J2EE container?
+ </para>
+ </question>
+
+ <answer>
+ <para>Application-specific classloading is used widely inside a Java EE
+ container. For example, a web application may require a new
+ classloader to scope a specific version of the user library.
+ However, by default JBoss Cache is agnostic to the classloader. In
+ general, this leads to two kinds of problems:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Object instance is stored in cache1 and replicated to
+ cache2. As a result, the instance in cache2 is created by the
+ system classloader. The replication may fail if the system
+ classloader on cache2 does not have access to the required
+ class. Even if replication doesn't fail, a user thread in cache2
+ may not be able to access the object if the user thread is
+ expecting a type defined by the application classloader.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Object instance is created by thread 1 and will be
+ accessed by thread 2 (with two different classloaders).
+ JBoss Cache has no notion of the different classloaders involved.
+ As a result, you will have a
+ <literal>ClassCastException</literal>
+ . This is a standard
+ problem in passing an object from one application space to
+ another; JBoss Cache just adds a level of indirection in passing
+ the object.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>To solve the first kind of issue JBoss Cache uses a
+ <literal>CacheMarshaller</literal>
+ .
+ Basically, this allows application code to register a classloader
+ with a portion of the cache tree for use in handling objects
+ replicated to that portion. See the
+ <literal>CacheMarshaller</literal>
+ section of
+ the user guide for more details.
+ </para>
+
+ <para>To solve the second kind of issue, the only solution (that we
+ know of) is to cache "serialized" byte code and only de-serialize it
+ during every object get (and this will be expensive!). That is,
+ during a put operation, the object instance will be serialized and
+ therefore can be deserialized safely by a "foreign" classloader.
+ However, the performance penalty of this approach is quite severe so
+ in general another local in-vm version will need to be used as a
+ "near-line" cache. Note also that each time the serialized bytes are
+ deserialized, a new instance of the object is created.
+ </para>
+
+ <para>To help with this kind of handling, JBoss has a utility class
+ called
+ <literal>MarshalledValue</literal>
+ that wraps around the
+ serialized object. Here is a code snippet that illustrates how you
+ can create a wrapper around JBoss Cache to handle the classloader
+ issue:
+ </para>
+
+ <programlisting>
+ import org.jboss.invocation.MarshalledValue;
+
+ public class CacheService
+ {
+ private Cache cache;
+
+ public Object get(Fqn fqn, String key)
+ {
+ return getUnMarshalledValue(cache.get(fqn, key));
+ }
+
+ public Object set(Fqn fqn, String key, Object value)
+ {
+ cache.put(fqn, key, getMarshalledValue(value));
+ return value; // only if successful
+ }
+
+ ...
+
+ private Object getUnMarshalledValue(object value)
+ {
+ // assuming we use the calling thread context classloader
+ return ((MarshalledValue)value).get();
+ }
+
+ private Object getMarshalledValue(Object value)
+ {
+ return new MarshalledValue(value);
+ }
+ }
+ </programlisting>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Does JBoss Cache currently support pre-event and post-event
+ notification?
+ </para>
+ </question>
+
+ <answer>
+ <para>Yes. A boolean is passed in to each notification callback identifying whether the callback is
+ before
+ or after the event. See the
+ <literal>org.jboss.cache.CacheListener</literal>
+ interface for details.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>How do I implement a custom listener to listen to
+ cache events?
+ </para>
+ </question>
+
+ <answer>
+ <para>
+ Either implement
+ <literal>org.jboss.cache.CacheListener</literal>
+ or extend
+ <literal>org.jboss.cache.AbstractCacheListener</literal>
+ and override for the events you are interested in. You can then register the listener using the
+ <literal>org.jboss.cache.Cache.addCacheListener()</literal>
+ API.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Can I use
+ <literal>UseRegionBasedMarshalling</literal>
+ attribute in JBoss Cache in order to get
+ around ClassCastExceptions happening when accessing data in the cache that has just been redeployed?
+ </para>
+ </question>
+
+ <answer>
+ <para>Yes, you can. Originally, cache Marshalling was designed as a
+ workaround for those replicated caches that upon state transfer did not have access to the
+ classloaders defining the objects in the cache.
+ </para>
+
+ <para>On each deployment, JBoss creates a new classloader per the top level deployment artifact, for
+ example an EAR. You also have to bear in mind that a class in an application server is defined not
+ only by the class name but also its classloader. So, assuming that the cache is not deployed as part
+ of your deployment, you could deploy an application and put instances of classes belonging to this
+ deployment inside the cache. If you did a redeployment and try to do a get operation of the data
+ previously put, this would result on a ClassCastException. This is because even though the class names
+ are the same, the class definitions are not. The current classloader is different to the one when
+ the classes were originally put.
+ </para>
+
+ <para>By enabling marshalling, you can control the lifecycle of the data in the cache and if on
+ undeployment, you deactivate the region and unregister the classloader that you'd have registered on
+ deployment, you'd evict the data in the cache locally. That means that in the next deployment, the
+ data won't be in the cache, therefore avoiding the problem. Obviously, using marshalling to get
+ around this problem is only recommended when you have some kind of persistence backing where the data
+ survives, for example using CacheLoaders, or when JBoss Cache is used as a second level cache in a
+ persistence framework.
+ </para>
+
+ <para>To implement this feature, please follow the instructions indicated in the example located
+ in the CacheMarshaller section of the user's guide. It's worth noting that instead of a
+ <literal>ServletContextListener</literal>
+ , you could add this code into an
+ <literal>MBean</literal>
+ that contained lifecycle methods, such as
+ <literal>start()</literal>
+ and
+ <literal>stop()</literal>
+ .
+ The key would be for this MBean to depend on the target cache, so that it can operate as long as the
+ cache is up and running.
+ </para>
+ </answer>
+ </qandaentry>
+
+ </qandaset>
+ </chapter>
+
+ <chapter id="eviction">
+ <title>Eviction Policies</title>
+ <qandaset>
+ <qandaentry>
+ <question>
+ <para>Does JBoss Cache support eviction policies?</para>
+ </question>
+
+ <answer>
+ <para>Yes. JBoss Cache currently supports multiple eviction policies such as LRU, MRU, and FIFO.
+ Users can also plug in their own eviction policy algorithms. See user
+ manual for details.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Does JBoss Cache's eviction policy operates in
+ replication mode?
+ </para>
+ </question>
+
+ <answer>
+ <para>Yes and no. :-)</para>
+
+ <para>The eviction policy only operates in local mode. That is, nodes are
+ only evicted locally. This may cause the cache contents not to be
+ synchronized temporarily. But when a user tries to obtain the cached
+ contents of an evicted node and finds out that is null (e.g.,
+ <literal>get</literal>
+ returns null), it should get it from the
+ other data source and re-populate the data in the cache. During this
+ moment, the node content will be propagated and the cache content
+ will be in sync.
+ </para>
+
+ <para>However, you still can run eviction policies with cache mode
+ set to either
+ <literal>REPL_SYNC</literal>
+ or
+ <literal>REPL_ASYNC</literal>
+ . Depending on your use case, you can
+ set multiple cache instances to have their own eviction policy
+ (which are applied locally) or just have selected instances with
+ eviction policies activated.
+ </para>
+
+ <para>Also note that, with cache loader option, a locally evicted
+ node can also be persisted to the backend store and a user can
+ retrieve it from the store later on.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Does JBoss Cache support
+ <literal>Region</literal>
+ ?
+ </para>
+ </question>
+
+ <answer>
+ <para>Yes. JBoss Cache has the notion of region where a user can
+ configure the eviction policy parameters (e.g.,
+ <literal>maxNodes</literal>
+ or
+ <literal>timeToIdleSeconds</literal>
+ )
+ </para>
+
+ <para>A region in JBoss Cache denotes a portion of tree hierarchy,
+ e.g., a fully qualified name (
+ <literal>org.jboss.cache.Fqn</literal>
+ ). For example,
+ a user can define
+ <literal>/org/jboss</literal>
+ and
+ <literal>/org/foocom</literal>
+ as two separate regions. But note
+ that you can configure the region programmatically now, i.e.,
+ everything has to be configured through the xml file.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>What are the
+ <literal>EvictionPolicyConfig</literal>
+ tag
+ parameters for
+ <literal>org.jboss.cache.eviction.LRUPolicy</literal>
+ ?
+ </para>
+ </question>
+
+ <answer>
+ <para>They are:</para>
+
+ <table>
+ <title>Parameters</title>
+
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>eventQueueSize</entry>
+
+ <entry>A fine-tuning parameter where you can configure the size of the eviction notification
+ event queue. Defaults to 200,000.
+ </entry>
+ </row>
+
+ <row>
+ <entry>wakeUpIntervalInSeconds</entry>
+
+ <entry>Interval where the clean up thread wakes to process
+ the sitting queue and sweep away the old data.
+ </entry>
+ </row>
+
+ <row>
+ <entry>region</entry>
+
+ <entry>A area where each eviction policy parameters are
+ specified. Note that it needs a minimum of
+ <literal>/_default</literal>
+ region.
+ </entry>
+ </row>
+
+ <row>
+ <entry>maxNodes</entry>
+
+ <entry>Max number of nodes allowed in the eviction queue. 0
+ means no limit.
+ </entry>
+ </row>
+
+ <row>
+ <entry>timeToLiveInSeconds</entry>
+
+ <entry>Age (in seconds) for the node to be evicted in the
+ queue. 0 denotes no limit.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>I have turned on the eviction policy, why do I still get "out
+ of memory" (OOM) exception?
+ </para>
+ </question>
+
+ <answer>
+ <para>OOM can happen when the speed of cache access exceeds the
+ speed of eviction policy handling timer. Eviction policy handler
+ will wake up every
+ <literal>wakeUpIntervalInSeconds</literal>
+ seconds to process the eviction event queue. So when the queue size is full, it will create a
+ backlog and cause out-of-memory exceptions to happen unless the eviction timer catches
+ up. To address this problem, in addition to increase the VM heap
+ size, you can also reduce the
+ <literal>wakeUpIntervaleInSeconds</literal>
+ so the timer thread
+ processes the queue more frequently.
+ </para>
+
+ <para>The eviction queue size is configurable.
+ </para>
+ </answer>
+ </qandaentry>
+ </qandaset>
+ </chapter>
+ <chapter id="cacheloaders">
+ <title>Cache Loaders</title>
+ <qandaset>
+
+
+ <qandaentry>
+ <question>
+ <para>What is a cache loader?</para>
+ </question>
+
+ <answer>
+ <para>A cache loader is the connection of JBoss Cache to a
+ (persistent) data store. The cache loader is called by JBoss Cache to
+ fetch data from a store when that data is not in the cache, and when
+ modifications are made to data in the cache the Cache Loader is
+ called to store those modifications back to the store.
+ </para>
+
+ <para>In conjunction with eviction policies, JBoss Cache with a
+ cache loader allows a user to maintain a bounded cache for a large
+ backend datastore. Frequently used data is fetched from the
+ datastore into the cache, and the least used data is evicted, in
+ order to provide fast access to frequently accessed data. This is
+ all configured through XML, and the programmer doesn't have to take
+ care of loading and eviction.
+ </para>
+
+ <para>JBoss Cache currently ships with several cache loader
+ implementations, including:
+ </para>
+
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>org.jboss.cache.loader.FileCacheLoader</literal>
+ : this implementation uses the file
+ system to store and retrieve data. JBoss Cache nodes are mapped
+ to directories, subnodes to subdirectories etc. Attributes of
+ a node are mapped to a data file
+ inside the
+ directory.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>org.jboss.cache.loader.BdbjeCacheLoader</literal>
+ : this implementation is based on the
+ Oracle's Berkeley DB Java Edition database, a fast and efficient
+ transactional database. It uses a single file for the entire
+ store. Note that if you use the Berkeley DB cache loader with
+ JBoss Cache and wish to ship your product, you will have to acquire a
+ <ulink url="http://www.sleepycat.com/jeforjbosscache">commercial license from Oracle
+ </ulink>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>org.jboss.cache.loader.JDBCCacheLoader</literal>
+ : this implementation uses the relational database as the persistent
+ storage.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>And more. See the chapter on cache loaders in the User Guide for more details.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Is the FileCacheLoader recommended for production use?</para>
+ </question>
+
+ <answer>
+ <para>
+ No, it is not. The FileCacheLoader has some severe limitations which restrict it's use in a production
+ environment, or if used in such an environment, it should be used with due care and sufficient
+ understanding of these limitations.
+ <itemizedlist>
+ <listitem>Due to the way the FileCacheLoader represents a tree structure on disk (directories and
+ files) traversal is inefficient for deep trees.
+ </listitem>
+ <listitem>Usage on shared filesystems like NFS, Windows shares, etc. should be avoided as these do
+ not implement proper file locking and can cause data corruption.
+ </listitem>
+ <listitem>Usage with an isolation level of NONE can cause corrupt writes as multiple threads
+ attempt to write to the same file.
+ </listitem>
+ <listitem>File systems are inherently not transactional, so when attempting to use your cache in a
+ transactional context, failures when writing to the file (which happens during the commit phase)
+ cannot be recovered.
+ </listitem>
+ </itemizedlist>
+
+ As a rule of thumb, it is recommended that the FileCacheLoader not be used in a highly concurrent,
+ transactional or stressful environment, and it's use is restricted to testing.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Can writing to cache loaders be asynchronous?</para>
+ </question>
+
+ <answer>
+ <para>Yes. Set the
+ <literal>async</literal>
+ attrobute to true. See the JBoss Cache User Guide for a more
+ detailed discussion. By default though, all cache loader writes are
+ synchronous and will block.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Can I write my own cache loader ?</para>
+ </question>
+
+ <answer>
+ <para>Yes. A cache loader is a class implementing
+ <literal>org.jboss.cache.loader.CacheLoader</literal>
+ or extending
+ <literal>org.jboss.cache.loader.AbstractCacheLoader</literal>
+ . It is
+ configured via the XML file (see JBoss Cache User Guide).
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Does a cache loader have to use a persistent store ?</para>
+ </question>
+
+ <answer>
+ <para>No, a cache loader could for example fetch (and possibly store)
+ its data from a webdav-capable webserver. Another example is a
+ caching proxy server, which fetches contents from the web. Note that
+ an implementation of CacheLoader may not implement the 'store'
+ functionality in this case, but just the 'load'
+ functionality.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Do I have to pay to use Oracle's Berkeley DB CacheLoader?</para>
+ </question>
+
+ <answer>
+ <para>Not if you use it only for personal use. As soon as you
+ distribute your product with BdbjeCacheLoader, you have to purchase
+ a commercial license from Oracle. See details at
+ <ulink
+ url="http://www.sleepycat.com/jeforjbosscache">http://www.sleepycat.com/jeforjbosscache
+ </ulink>
+ .
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Can I use more than one cache loader?</para>
+ </question>
+
+ <answer>
+ <para>Yes. Within the CacheLoaderConfiguration XML
+ element (see user guide chapter on cache loaders) you can
+ describe several cache loaders. The impact is that the cache will
+ look at all of the cache loaders in the order they've been
+ configured, until it finds a valid, non-null element of data. When
+ performing writes, all cache loaders are written to (except if the
+ ignoreModifications element has been set to true for a specific
+ cache loader.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question>
+ <para>Can I migrate a JDBCacheLoader or FileCacheLoader based cache store containing data formatted with
+ JBoss Cache 1.x.x to JBoss Cache 2.0 format?
+ </para>
+ </question>
+
+ <answer>
+ <para>Yes. See "Transforming Cache Loaders" section within the "Cache Loaders" section located in the
+ JBoss Cache users guide.
+ </para>
+ </answer>
+ </qandaentry>
+
+ </qandaset>
+ </chapter>
+ <chapter id="troubleshooting">
+ <title>Troubleshooting</title>
+ <qandaset>
+
+ <qandaentry>
+ <question>
+ <para>I am having problems getting JBoss Cache to work, where can I get information on troubleshooting?
+ </para>
+ </question>
+ <answer>
+ <para>Troubleshooting section can be found in the following
+ <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossCacheTroubleshooting">wiki link</ulink>
+ .
+ </para>
+ </answer>
+ </qandaentry>
+ </qandaset>
+ </chapter>
+</book>
Added: core/trunk/src/main/docbook/images/BuddyReplication.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/BuddyReplication.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/CacheLoader.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/CacheLoader.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/CacheMgmtInterceptor.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/CacheMgmtInterceptor.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/Configuration.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/Configuration.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/DataVersions.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/DataVersions.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/DelegatingCacheLoader.doc
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/DelegatingCacheLoader.doc
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/DelegatingCacheLoader.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/DelegatingCacheLoader.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/Interceptor.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/Interceptor.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/Listeners.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/Listeners.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/LocalCacheLoader.doc
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/LocalCacheLoader.doc
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/LocalCacheLoader.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/LocalCacheLoader.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/Marshaller.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/Marshaller.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/MultipleCacheLoaders.doc
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/MultipleCacheLoaders.doc
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/MultipleCacheLoaders.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/MultipleCacheLoaders.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/OnlyOneCacheLoader.doc
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/OnlyOneCacheLoader.doc
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/OnlyOneCacheLoader.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/OnlyOneCacheLoader.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/PackageOverview-BuddyReplication.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/PackageOverview-BuddyReplication.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/PublicAPI.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/PublicAPI.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/SPI.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/SPI.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/SharedCacheLoader.doc
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/SharedCacheLoader.doc
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/SharedCacheLoader.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/SharedCacheLoader.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/TransactionLookup.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/TransactionLookup.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/TreeCacheArchitecture.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/TreeCacheArchitecture.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/images/TreeNodeExample.gif
===================================================================
(Binary files differ)
Property changes on: core/trunk/src/main/docbook/images/TreeNodeExample.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/src/main/docbook/tutorial/en/master.xml
===================================================================
--- core/trunk/src/main/docbook/tutorial/en/master.xml (rev 0)
+++ core/trunk/src/main/docbook/tutorial/en/master.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,292 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<article lang="en">
+ <articleinfo>
+ <title>JBoss Cache core Cache Tutorial</title>
+ <releaseinfo>Release 2.0.0</releaseinfo>
+ <pubdate>June 2007</pubdate>
+
+ <author>
+ <firstname>Manik</firstname>
+ <surname>Surtani</surname>
+ <email>manik(a)jboss.org</email>
+ </author>
+ </articleinfo>
+
+ <section>
+ <title>Introduction</title>
+
+ <para>
+ JBoss Cache is an in-memory replicated, transactional, and fine-grained cache.
+ This tutorial focuses on the core Cache API. Please refer to the accompanying tutorial
+ for the Pojo Cache API if it is the Pojo Cache API you are interested in.
+ </para>
+ <para>
+ For details of configuration, usage and APIs, please refer to the
+ <ulink
+ url="http://labs.jboss.org/portal/jbosscache/docs/index.html">user manuals
+ </ulink>
+ .
+ </para>
+ </section>
+
+ <section>
+ <title>What You Will Learn</title>
+
+ <itemizedlist>
+ <listitem>
+ <para>Cache creation and modification</para>
+ </listitem>
+
+ <listitem>
+ <para>Replication of state</para>
+ </listitem>
+
+ <listitem>
+ <para>Transactions</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Configuration</title>
+
+ <para>First download the JBoss Cache 2.x distribution from
+ <ulink
+ url="http://labs.jboss.org/portal/jbosscache/download/index.html">the download page
+ </ulink>
+ . You probably want the
+ <literal>JBossCache-core-2.X.Y.zip</literal>
+ distribution.
+ Unzip it, and you will get a directory containing the distribution, such as
+ <literal>JBossCache-core-2.X.Y</literal>
+ .
+ For the sake of this tutorial, I will refer to this as
+ <literal>JBossCache</literal>
+ .
+ </para>
+
+ <para>The configuration files are located in the
+ <literal>JBossCache/etc</literal>
+ directory. You can
+ modify the behavior of the cache by editing the various configuration files.
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>log4j.xml</literal>
+ . Logging output. You can enable logging, specify log levels or
+ change the name and path to the log file.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>META-INF/replSync-service.xml</literal>
+ . Cache configuration file used for this tutorial.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Script</title>
+
+ <para>The only script needed for this tutorial is the
+ <literal>JBossCache/build.xml</literal>
+ ant script and the accompanying
+ driver scripts (
+ <literal>build.sh</literal>
+ for Unix and
+ <literal>build.bat</literal>
+ for Windows).
+ </para>
+ </section>
+
+ <section>
+ <title>Running The Demo GUI</title>
+
+ <para>
+ The demo is run by calling the ant script (via the driver) with the
+ <literal>run.demo</literal>
+ target. E.g.,
+ </para>
+
+ <para>
+ <literal>./build.sh run.demo</literal>
+ </para>
+ <para>
+ This will cause a GUI window to appear, giving you a tree view of the cache in the top pane and a BeanShell
+ view
+ of the JVM in the lower pane.
+ </para>
+ <para>
+ The BeanShell view is preset with the following variables:
+ <itemizedlist>
+ <listitem>
+ <literal>cache</literal>
+ - a reference to the Cache interface, used by the GUI instance.
+ </listitem>
+ <listitem>
+ <literal>root</literal>
+ - a reference to the root Node instance for the above cache.
+ </listitem>
+ <listitem>
+ <literal>transactionManager</literal>
+ - a reference to the registered transaction manager.
+ </listitem>
+ </itemizedlist>
+ The references made available to the BeanShell window point to the same cache instance used by the tree view in
+ the
+ GUI above.
+ </para>
+
+ <para>
+ To run the demo as a replicated demo, it is useful to start another command line window and run the ant script
+ again as you did above. Now you will have two cache instances running in two separate GUIs, replicating state
+ to
+ each other.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Tutorials</title>
+ Note that it is recommended that you shut down and restart the demo GUI for each of the following tutorials, to
+ ensure
+ clean caches every time.
+ <section>
+ <title>Caches and Nodes</title>
+ <para>
+ For this tutorial, start a single instance of the demo GUI. In this tutorial, we will:
+
+ <itemizedlist>
+ <listitem>Create nodes under the root node.</listitem>
+ <listitem>Remove nodes under the root node, both individually and recursively.</listitem>
+ <listitem>Add and remove data from nodes.</listitem>
+ </itemizedlist>
+
+ <orderedlist>
+ <listitem>Set up the Fqns you need. In the BeanShell pane, create 3 Fqn variables:
+ <programlisting><![CDATA[
+
+ childFqn1 = Fqn.fromString("/child1");
+ childFqn2 = Fqn.fromString("/child2");
+ childFqn3 = Fqn.fromString("/child2/child3");
+
+ ]]></programlisting>
+ </listitem>
+
+ <listitem>
+ Create child nodes under the root node.
+ <programlisting><![CDATA[
+
+ child1 = root.addChild(childFqn1);
+ child2 = root.addChild(childFqn2);
+ child3 = root.addChild(childFqn3);
+
+ ]]></programlisting>
+ </listitem>
+
+ <listitem>
+ Query the nodes
+ <programlisting><![CDATA[
+
+ root.hasChild(childFqn1); // should return true
+ child2.hasChild(childFqn3.getLastElement()); // should return true
+ child3.getParent(); // should return child2
+ child2.getParent(); // should return root
+
+ ]]></programlisting>
+ </listitem>
+
+
+ <listitem>
+ Put some data in the nodes.
+ <programlisting><![CDATA[
+
+ child1.put("key1", "value1");
+ child1.put("key2", "value2");
+ child2.put("key3", "value3");
+ child2.put("key4", "value4");
+ child3.put("key5", "value5");
+ child3.put("key6", "value6");
+
+ ]]></programlisting>
+
+ By selecting the nodes in the tree view, you should see the contents of each node.
+ </listitem>
+
+ <listitem>
+ Query some of the data.
+
+ <programlisting><![CDATA[
+
+ child1.getKeys();
+ child2.getData();
+
+ ]]></programlisting>
+ </listitem>
+
+
+ <listitem>
+ Remove some data in the nodes.
+
+ <programlisting><![CDATA[
+
+ child1.remove("key1");
+ child2.remove("key3");
+ child3.clearData();
+
+ ]]></programlisting>
+ </listitem>
+
+ <listitem>
+ Delete nodes
+
+ <programlisting><![CDATA[
+
+ root.removeChild(childFqn1); // will also remove any data held under child1
+ root.removeChild(childFqn2); // will recursively remove child3 as well.
+
+ ]]></programlisting>
+ </listitem>
+
+ </orderedlist>
+
+ In addition to the above, you should refer to the
+ <literal>Cache</literal>
+ and
+ <literal>Node</literal>
+ <ulink
+ url="http://labs.jboss.org/portal/jbosscache/docs/index.html">API docs
+ </ulink>
+ and try out the APIs in the BeanShell script.
+ </para>
+ </section>
+
+ <section>
+ <title>Replication</title>
+ <para>
+ For this tutorial, start two instances instance of the demo GUI. Repeat the exercises in the previous
+ tutorial,
+ only alternating between the two GUI windows when creating/removing nodes or adding/removing data. This
+ demonstrates
+ how the two cache instances in the two GUIs are kept in sync.
+ </para>
+ </section>
+
+ <section>
+ <title>Transactions</title>
+ <para>
+ For this tutorial, start two instances instance of the demo GUI. Repeat the exercises in the previous
+ tutorial,
+ only starting transactions before creating/removing nodes or adding/removing data. This will depict how
+ replication only occurs on transaction boundaries. Try rolling back a few transactions as well, to see how
+ nothing gets replicated in these cases.
+ </para>
+ </section>
+
+ </section>
+
+</article>
Added: core/trunk/src/main/docbook/userguide/en/master.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/master.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/master.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
+ "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+ <!ENTITY preface SYSTEM "modules/preface.xml">
+ <!ENTITY introduction SYSTEM "modules/introduction.xml">
+ <!ENTITY architecture SYSTEM "modules/architecture.xml">
+ <!ENTITY basic_api SYSTEM "modules/basic_api.xml">
+ <!ENTITY replication SYSTEM "modules/replication.xml">
+ <!ENTITY transactions SYSTEM "modules/transactions.xml">
+ <!ENTITY eviction_policies SYSTEM "modules/eviction_policies.xml">
+ <!ENTITY cache_loaders SYSTEM "modules/cache_loaders.xml">
+ <!ENTITY compatibility SYSTEM "modules/compatibility.xml">
+ <!ENTITY configuration SYSTEM "modules/configuration.xml">
+ <!ENTITY deployment SYSTEM "modules/deployment.xml">
+ <!ENTITY configuration_reference SYSTEM "modules/configuration_reference.xml">
+ <!ENTITY jmx_reference SYSTEM "modules/jmx_reference.xml">
+ ]>
+<book lang="en">
+ <bookinfo>
+ <title>JBoss Cache User Guide</title>
+ <subtitle>A clustered, transactional cache</subtitle>
+
+ <!-- Release version and date -->
+ <releaseinfo>Release 2.0.0 Habanero</releaseinfo>
+ <pubdate>June 2007</pubdate>
+
+ <!-- Authors/contributors -->
+ <author>
+ <firstname>Manik</firstname>
+ <surname>Surtani</surname>
+ <email>manik(a)jboss.org</email>
+ </author>
+
+ <author>
+ <firstname>Bela</firstname>
+ <surname>Ban</surname>
+ <email>bela(a)jboss.com</email>
+ </author>
+
+ <author>
+ <firstname>Ben</firstname>
+ <surname>Wang</surname>
+ <email>ben.wang(a)jboss.com</email>
+ </author>
+
+ <author>
+ <firstname>Brian</firstname>
+ <surname>Stansberry</surname>
+ <email>brian.stansberry(a)jboss.com</email>
+ </author>
+
+ <author>
+ <firstname>Galder</firstname>
+ <surname>Zamarreño</surname>
+ <email>galder.zamarreno(a)jboss.com</email>
+ </author>
+
+ <author>
+ <firstname>Daniel</firstname>
+ <surname>Huang</surname>
+ <email>dhuang(a)jboss.org</email>
+ </author>
+
+ <!--<author>-->
+ <!--<firstname>Joseph</firstname>-->
+ <!--<surname>Marques</surname>-->
+ <!--<email>jmarques(a)redhat.com</email>-->
+ <!--</author>-->
+
+
+ <!-- copyright info -->
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2006</year>
+ <year>2007</year>
+ <holder>JBoss, a division of Red Hat Inc.</holder>
+ </copyright>
+
+ </bookinfo>
+
+ <!-- Adds a table of contents here -->
+ <toc/>
+
+ &preface;
+
+ <part label="I">
+ <title>Introduction to JBoss Cache</title>
+ <partintro>
+ <para>
+ This section covers what developers would need to quickly start using JBoss Cache in their projects. It
+ covers an
+ overview of the concepts and API, configuration and deployment information.
+ </para>
+ </partintro>
+ &introduction;
+ &basic_api;
+ &configuration;
+ &deployment;
+ &compatibility;
+ </part>
+
+ <part label="II">
+ <title>JBoss Cache Architecture</title>
+ <partintro>
+ <para>
+ This section digs deeper into the JBoss Cache architecture, and is meant for developers wishing to extend or
+ enhance JBoss Cache, write plugins or are just looking for detailed knowledge of how things work under the
+ hood.
+ </para>
+ </partintro>
+ &architecture;
+ &replication;
+ &cache_loaders;
+ &eviction_policies;
+ &transactions;
+ </part>
+
+ <part label="III">
+ <title>JBoss Cache References</title>
+ <partintro>
+ <para>
+ This section contains technical references for easy looking up.
+ </para>
+ </partintro>
+
+ &configuration_reference;
+ &jmx_reference;
+ </part>
+</book>
\ No newline at end of file
Added: core/trunk/src/main/docbook/userguide/en/modules/architecture.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/modules/architecture.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/modules/architecture.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,498 @@
+<chapter id="architecture">
+ <title>Architecture</title>
+ <section id="architecture.tree_structure">
+ <title>Data Structures Within The Cache</title>
+
+
+ <para>
+ A
+ <literal>Cache</literal>
+ consists of a collection of
+ <literal>Node</literal>
+ instances, organised in a tree
+ structure. Each
+ <literal>Node</literal>
+ contains a
+ <literal>Map</literal>
+ which holds the data
+ objects to be cached. It is important to note that the structure is a mathematical tree, and not a graph; each
+ <literal>Node</literal>
+ has one and only one parent, and the root node is denoted by the constant fully qualitied name,
+ <literal>Fqn.ROOT</literal>
+ .
+ </para>
+ <para>
+ The reason for organising nodes as such is to improve concurrent access to data and make replication and
+ persistence
+ more fine-grained.
+ </para>
+ <para>
+ <figure>
+ <title>Data structured as a tree</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="TreeCacheArchitecture.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ In the diagram above, each box represents a JVM. You see 2 caches in separate JVMs, replicating data to each
+ other.
+ These VMs can be located on the same physical machine, or on 2 different machines connected by a network link.
+ The
+ underlying group communication between networked nodes is done using
+ <ulink url="http://www.jgroups.org">JGroups</ulink>
+ .
+ </para>
+
+ <para>Any modifications (see
+ <link linkend="api">API chapter</link>
+ ) in one cache instance will be replicated to
+ the other cache. Naturally, you can have more than 2 caches in a cluster.
+ Depending on the transactional settings, this replication will occur either after each modification or at the
+ end of a transaction, at commit time. When a new cache is created, it can optionally acquire the contents
+ from one of the existing caches on startup.
+ </para>
+ </section>
+
+ <section id="architecture.SPI_interfaces">
+ <title>SPI Interfaces</title>
+ <para>
+ In addition to
+ <literal>Cache</literal>
+ and
+ <literal>Node</literal>
+ interfaces, JBoss Cache exposes more powerful
+ <literal>CacheSPI</literal>
+ and
+ <literal>NodeSPI</literal>
+ interfaces, which offer more control over the internals
+ of JBoss Cache. These interfaces are not intended for general use, but are designed for people who wish to
+ extend and enhance JBoss Cache, or write custom
+ <literal>Interceptor</literal>
+ or
+ <literal>CacheLoader</literal>
+ instances.
+ </para>
+ <figure>
+ <title>SPI Interfaces</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="SPI.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ <para>
+ The
+ <literal>CacheSPI</literal>
+ interface cannot be created, but is injected into
+ <literal>Interceptor</literal>
+ and
+ <literal>CacheLoader</literal>
+ implementations by the
+ <literal>setCache(CacheSPI cache)</literal>
+ methods on these interfaces.
+ <literal>CacheSPI</literal>
+ extends
+ <literal>Cache</literal>
+ so all the functionality of the basic API is made available.
+ </para>
+ <para>
+ Similarly, a
+ <literal>NodeSPI</literal>
+ interface cannot be created. Instead, one is obtained by performing operations on
+ <literal>CacheSPI</literal>
+ ,
+ obtained as above. For example,
+ <literal>Cache.getRoot() : Node</literal>
+ is overridden as
+ <literal>CacheSPI.getRoot() : NodeSPI</literal>
+ .
+ </para>
+ <para>
+ It is important to note that directly casting a
+ <literal>Cache</literal>
+ or
+ <literal>Node</literal>
+ to it's SPI
+ counterpart is not recommended and is bad practice, since the inheritace of interfaces it is not a contract
+ that is guaranteed to be upheld moving forward. The exposed public APIs, on the other hand, is guaranteed to
+ be upheld.
+ </para>
+ </section>
+
+ <section id="architecture.invocations">
+ <title>Method Invocations On Nodes</title>
+ <para>
+ Since the cache is essentially a collection of nodes, aspects such as clustering, persistence, eviction, etc.
+ need to be applied to these nodes when operations are invoked on the cache as a whole or on individual nodes.
+ To achieve this in a clean, modular and extensible manner, an interceptor chain is used. The chain is built
+ up of a series of interceptors, each one adding an aspect or particular functionality. The chain is built
+ when the cache is created, based on the configuration used.
+ </para>
+ <para>
+ It is important to note that the
+ <literal>NodeSPI</literal>
+ offers some methods (such as the
+ <literal>xxxDirect()</literal>
+ method
+ family) that operate on a node directly without passing through the interceptor stack. Plugin authors should
+ note
+ that using such methods will affect the aspects of the cache that may need to be applied, such as locking,
+ replication, etc. Basically, don't use such methods unless you
+ <emphasis>really</emphasis>
+ know what you're doing!
+ </para>
+ <section id="architecture.interceptors">
+ <title>Interceptors</title>
+ <para>
+ An
+ <literal>Interceptor</literal>
+ is an abstract class, several of which comprise an interceptor chain. It
+ exposes an
+ <literal>invoke()</literal>
+ method, which must be overridden by implementing classes to add behaviour
+ to a call before passing the call down the chain by calling
+ <literal>super.invoke()</literal>
+ .
+ </para>
+ <figure>
+ <title>SPI Interfaces</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="Interceptor.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ <para>
+ JBoss Cache ships with several interceptors, representing different configuration options, some of which
+ are:
+ <itemizedlist>
+ <listitem>
+ <literal>TxInterceptor</literal>
+ - looks for ongoing transactions and registers with transaction managers to participate in
+ synchronization events
+ </listitem>
+ <listitem>
+ <literal>ReplicationInterceptor</literal>
+ - replicates state across a cluster using a JGroups channel
+ </listitem>
+ <listitem>
+ <literal>CacheLoaderInterceptor</literal>
+ - loads data from a persistent store if the data requested is not available in memory
+ </listitem>
+ </itemizedlist>
+ The interceptor chain configured for your cache instance can be obtained and inspected by calling
+ <literal>CacheSPI.getInterceptorChain()</literal>
+ ,
+ which returns an ordered
+ <literal>List</literal>
+ of interceptors.
+ </para>
+ <section id="architecture.custom_interceptors">
+ <title>Writing Custom Interceptors</title>
+ <para>
+ Custom interceptors to add specific aspects or features can be written by extending
+ <literal>Interceptor</literal>
+ and overriding
+ <literal>invoke()</literal>
+ . The custom interceptor will need to be added to the interceptor chain by using the
+ <literal>CacheSPI.addInterceptor()</literal>
+ method.
+ </para>
+ <para>
+ Adding custom interceptors via XML is not supported at this time.
+ </para>
+ </section>
+ </section>
+
+ <section id="architecture.methodcalls">
+ <title>MethodCalls</title>
+ <para>
+ <literal>org.jboss.cache.marshall.MethodCall</literal>
+ is a class that encapsulates a
+ <literal>java.lang.reflection.Method</literal>
+ and an
+ <literal>Object[]</literal>
+ representing the method's arguments. It is an extension of the
+ <literal>org.jgroups.blocks.MethodCall</literal>
+ class, that adds a mechanism for identifying known methods using magic numbers and method ids,
+ which makes marshalling and unmarshalling more efficient and performant.
+ </para>
+ <para>
+ This is central to the
+ <literal>Interceptor</literal>
+ architecture, and is the only parameter passed in to
+ <literal>Interceptor.invoke()</literal>
+ .
+ </para>
+ </section>
+
+ <section id="architecture.invocationcontext">
+ <title>InvocationContexts</title>
+ <para>
+ <literal>InvocationContext</literal>
+ holds intermediate state for the duration of a single invocation, and is set up and
+ destroyed by the
+ <literal>InvocationContextInterceptor</literal>
+ which sits at the start of the chain.
+ </para>
+ <para>
+ <literal>InvocationContext</literal>
+ , as its name implies, holds contextual information associated with a single cache
+ method invocation. Contextual information includes associated
+ <literal>javax.transaction.Transaction</literal>
+ or
+ <literal>org.jboss.cache.transaction.GlobalTransaction</literal>
+ ,
+ method invocation origin (
+ <literal>InvocationContext.isOriginLocal()</literal>
+ ) as well as
+ <link
+ linkend="configuration.options">
+ <literal>Option</literal>
+ overrides
+ </link>
+ .
+ </para>
+ <para>
+ The
+ <literal>InvocationContext</literal>
+ can be obtained by calling
+ <literal>Cache.getInvocationContext()</literal>
+ .
+ </para>
+ </section>
+ </section>
+
+ <section id="architecture.managers">
+ <title>Managers For Subsystems</title>
+ <para>
+ Some aspects and functionality is shared by more than a single interceptor. Some of these have been
+ encapsulated
+ into managers, for use by various interceptors, and are made available by the
+ <literal>CacheSPI</literal>
+ interface.
+ </para>
+
+ <section id="architecture.rpcmanager">
+ <title>RpcManager</title>
+ <para>
+ This class is responsible for calls made via the JGroups channel for all RPC calls to remote caches, and
+ encapsulates the JGroups channel used.
+ </para>
+ </section>
+
+ <section id="architecture.buddymanager">
+ <title>BuddyManager</title>
+ <para>
+ This class manages buddy groups and invokes group organisation remote calls to organise a cluster of
+ caches into smaller sub-groups.
+ </para>
+ </section>
+
+ <section id="architecture.cacheloadermanager">
+ <title>CacheLoaderManager</title>
+ <para>
+ Sets up and configures cache loaders. This class wraps individual
+ <literal>CacheLoader</literal>
+ instances
+ in delegating classes, such as
+ <literal>SingletonStoreCacheLoader</literal>
+ or
+ <literal>AsyncCacheLoader</literal>
+ ,
+ or may add the
+ <literal>CacheLoader</literal>
+ to a chain using the
+ <literal>ChainingCacheLoader</literal>
+ .
+ </para>
+ </section>
+
+ </section>
+
+ <section id="architecture.marshalling">
+ <title>Marshalling And Wire Formats</title>
+ <para>
+ Early versions of JBoss Cache simply wrote cached data to the network by writing to an
+ <literal>ObjectOutputStream</literal>
+ during replication. Over various releases in the JBoss Cache 1.x.x series this approach was gradually
+ deprecated
+ in favour of a more mature marshalling framework. In the JBoss Cache 2.x.x series, this is the only officially
+ supported and recommended mechanism for writing objects to datastreams.
+ </para>
+ <figure>
+ <title>The Marshaller interface</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="Marshaller.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ <section>
+ <title>The Marshaller Interface</title>
+ <para>
+ The
+ <literal>Marshaller</literal>
+ interface extends
+ <literal>RpcDispatcher.Marshaller</literal>
+ from JGroups.
+ This interface has two main implementations - a delegating
+ <literal>VersionAwareMarshaller</literal>
+ and a
+ concrete
+ <literal>CacheMarshaller200</literal>
+ .
+ </para>
+ <para>
+ The marshaller can be obtained by calling
+ <literal>CacheSPI.getMarshaller()</literal>
+ , and defaults to the
+ <literal>VersionAwareMarshaller</literal>
+ .
+ Users may also write their own marshallers by implementing the
+ <literal>Marshaller</literal>
+ interface and
+ adding it to their configuration, by using the
+ <literal>MarshallerClass</literal>
+ configuration attribute.
+ </para>
+ </section>
+
+ <section>
+ <title>VersionAwareMarshaller</title>
+ <para>
+ As the name suggests, this marshaller adds a version
+ <literal>short</literal>
+ to the start of any stream when
+ writing, enabling similar
+ <literal>VersionAwareMarshaller</literal>
+ instances to read the version short and
+ know which specific marshaller implementation to delegate the call to.
+ For example,
+ <literal>CacheMarshaller200</literal>
+ , is the marshaller for JBoss Cache 2.0.x.
+ JBoss Cache 2.1.x, say, may ship with
+ <literal>CacheMarshaller210</literal>
+ with an improved wire protocol.
+ Using a
+ <literal>VersionAwareMarshaller</literal>
+ helps achieve wire protocol compatibility between minor
+ releases but still affords us the flexibility to tweak and improve the wire protocol between minor or micro
+ releases.
+ </para>
+
+ <section>
+ <title>CacheLoaders</title>
+ <para>
+ Some of the existing cache loaders, such as the
+ <literal>JDBCCacheLoader</literal>
+ and the
+ <literal>FileCacheLoader</literal>
+ relied on persisting data using
+ <literal>ObjectOutputStream</literal>
+ as well, but now, they are using the
+ <literal>VersionAwareMarshaller</literal>
+ to marshall the persisted
+ data to their cache stores.
+ </para>
+ </section>
+
+ </section>
+
+ <section>
+ <title>CacheMarshaller200</title>
+ <para>
+ This marshaller treats well-known objects that need marshalling - such as
+ <literal>MethodCall</literal>
+ ,
+ <literal>Fqn</literal>
+ ,
+ <literal>DataVersion</literal>
+ , and even some JDK objects such as
+ <literal>String</literal>
+ ,
+ <literal>List</literal>
+ ,
+ <literal>Boolean</literal>
+ and others as types that do not need complete class definitions.
+ Instead, each of these well-known types are represented by a
+ <literal>short</literal>
+ , which is a lot more efficient.
+ </para>
+ <para>
+ In addition, reference counting is done to reduce duplication of writing certain objects multiple times, to
+ help
+ keep the streams small and efficient.
+ </para>
+ <para>
+ Also, if
+ <literal>UseRegionBasedMarshalling</literal>
+ is enabled (disabled by default) the marshaller adds region
+ information to the stream before writing any data. This region information is in the form of a
+ <literal>String</literal>
+ representation of an
+ <literal>Fqn</literal>
+ . When unmarshalling, the
+ <literal>RegionManager</literal>
+ can be used to
+ find the relevant
+ <literal>Region</literal>
+ , and use a region-specific
+ <literal>ClassLoader</literal>
+ to unmarshall
+ the stream. This is specifically useful when used to cluster state for application servers, where each
+ deployment has
+ it's own
+ <literal>ClassLoader</literal>
+ . See the section below on
+ <link linkend="architecture.regions">regions</link>
+ for more information.
+ </para>
+ </section>
+
+ </section>
+ <section id="architecture.regions">
+ <title>Class Loading and Regions</title>
+ <para>
+ When used to cluster state of application servers, applications deployed in the application tend to put
+ instances
+ of objects specific to their application in the cache (or in an
+ <literal>HttpSession</literal>
+ object) which
+ would require replication. It is common for application servers to assign separate
+ <literal>ClassLoader</literal>
+ instances to each application deployed, but have JBoss Cache libraries referenced by the application server's
+ <literal>ClassLoader</literal>
+ .
+ </para>
+ <para>
+ To enable us to successfully marshall and unmarshall objects from such class loaders, we use a concept called
+ regions. A region is a portion of the cache which share a common class loader (a region also has other uses -
+ see
+ <link linkend="eviction_policies">eviction policies</link>
+ ).
+ </para>
+ <para>
+ A region is created by using the
+ <literal>Cache.getRegion(Fqn fqn, boolean createIfNotExists)</literal>
+ method,
+ and returns an implementation of the
+ <literal>Region</literal>
+ interface. Once a region is obtained, a
+ class loader for the region can be set or unset, and the region can be activated/deactivated. By default,
+ regions
+ are active unless the
+ <literal>InactiveOnStartup</literal>
+ configuration attribute is set to
+ <literal>true</literal>
+ .
+ </para>
+ </section>
+
+</chapter>
Added: core/trunk/src/main/docbook/userguide/en/modules/basic_api.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/modules/basic_api.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/modules/basic_api.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,719 @@
+<chapter id="api">
+ <title>User API</title>
+ <section>
+ <title>API Classes</title>
+ <para>
+ The
+ <literal>Cache</literal>
+ interface is the primary mechanism for interacting with JBoss Cache. It is
+ constructed and optionally started using the
+ <literal>CacheFactory</literal>
+ . The
+ <literal>CacheFactory</literal>
+ allows you to create a
+ <literal>Cache</literal>
+ either from a
+ <literal>Configuration</literal>
+ object
+ or an XML file. Once you have a reference to a
+ <literal>Cache</literal>
+ , you can use it to look up
+ <literal>Node</literal>
+ objects in the tree structure, and store data in the tree.
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="PublicAPI.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+
+ </para>
+
+ <para>
+ Reviewing the javadoc for the above interfaces is the best way
+ to learn the API. Below we cover some of the main points.
+ </para>
+ </section>
+
+ <section id="api.create_start">
+ <title>Instantiating and Starting the Cache</title>
+ <para>
+ An instance of the
+ <literal>Cache</literal>
+ interface can only be created
+ via a
+ <literal>CacheFactory</literal>
+ . (This is unlike JBoss Cache 1.x,
+ where an instance of the old
+ <literal>TreeCache</literal>
+ class could
+ be directly instantiated.)
+ </para>
+ <para>
+ <literal>CacheFactory</literal>
+ provides a number of overloaded methods
+ for creating a
+ <literal>Cache</literal>
+ , but they all do the same thing:
+ <itemizedlist>
+ <listitem>Gain access to a
+ <literal>Configuration</literal>
+ , either
+ by having one passed in as a method parameter, or by parsing XML
+ content and constructing one. The XML content can come from a
+ provided input stream or from a classpath or filesystem location.
+ See the
+ <link linkend="configuration">chapter on Configuration</link>
+ for
+ more on obtaining a
+ <literal>Configuration</literal>
+ .
+ </listitem>
+ <listitem>Instantiate the
+ <literal>Cache</literal>
+ and provide
+ it with a reference to the
+ <literal>Configuration</literal>
+ .
+ </listitem>
+ <listitem>Optionally invoke the cache's
+ <literal>create()</literal>
+ and
+ <literal>start()</literal>
+ methods.
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ An example of the simplest mechanism for creating and starting
+ a cache, using the default configuration values:
+ </para>
+
+ <programlisting>
+ CacheFactory factory = DefaultCacheFactory.getInstance();
+ Cache cache = factory.createCache();
+ </programlisting>
+
+ <para>Here we tell the
+ <literal>CacheFactory</literal>
+ to find and
+ parse a configuration file on the classpath:
+ </para>
+
+ <programlisting>
+ CacheFactory factory = DefaultCacheFactory.getInstance();
+ Cache cache = factory.createCache("cache-configuration.xml");
+ </programlisting>
+
+ <para>Here we configure the cache from a file, but want to programatically
+ change a configuration element. So, we tell the factory not to start
+ the cache, and instead do it ourselves:
+ </para>
+
+ <programlisting>
+ CacheFactory factory = DefaultCacheFactory.getInstance();
+ Cache cache = factory.createCache("cache-configuration.xml", false);
+ Configuration config = cache.getConfiguration();
+ config.setClusterName(this.getClusterName());
+
+ // Have to create and start cache before using it
+ cache.create();
+ cache.start();
+ </programlisting>
+
+ </section>
+
+ <section>
+ <title>Caching and Retrieving Data</title>
+
+ <para>Next, let's use the
+ <literal>Cache</literal>
+ API to access
+ a
+ <literal>Node</literal>
+ in the cache and then do some
+ simple reads and writes to that node.
+ </para>
+ <programlisting>
+ // Let's get ahold of the root node.
+ Node rootNode = cache.getRoot();
+
+ // Remember, JBoss Cache stores data in a tree structure.
+ // All nodes in the tree structure are identified by Fqn objects.
+ Fqn peterGriffinFqn = Fqn.fromString("/griffin/peter");
+
+ // Create a new Node
+ Node peterGriffin = rootNode.addChild(peterGriffinFqn);
+
+ // let's store some data in the node
+ peterGriffin.put("isCartoonCharacter", Boolean.TRUE);
+ peterGriffin.put("favouriteDrink", new Beer());
+
+ // some tests (just assume this code is in a JUnit test case)
+ assertTrue(peterGriffin.get("isCartoonCharacter"));
+ assertEquals(peterGriffinFqn, peterGriffin.getFqn());
+ assertTrue(rootNode.hasChild(peterGriffinFqn));
+
+ Set keys = new HashSet();
+ keys.add("isCartoonCharacter");
+ keys.add("favouriteDrink");
+
+ assertEquals(keys, peterGriffin.getKeys());
+
+ // let's remove some data from the node
+ peterGriffin.remove("favouriteDrink");
+
+ assertNull(peterGriffin.get("favouriteDrink");
+
+ // let's remove the node altogether
+ rootNode.removeChild(peterGriffinFqn);
+
+ assertFalse(rootNode.hasChild(peterGriffinFqn));
+ </programlisting>
+
+ <para>
+ The
+ <literal>Cache</literal>
+ interface also exposes put/get/remove
+ operations that take an
+ <link linkend="basic_api.fqn">Fqn</link>
+ as an argument:
+ </para>
+
+ <programlisting>
+ Fqn peterGriffinFqn = Fqn.fromString("/griffin/peter");
+
+ cache.put(peterGriffinFqn, "isCartoonCharacter", Boolean.TRUE);
+ cache.put(peterGriffinFqn, "favouriteDrink", new Beer());
+
+ assertTrue(peterGriffin.get(peterGriffinFqn, "isCartoonCharacter"));
+ assertTrue(cache.getRootNode().hasChild(peterGriffinFqn));
+
+ cache.remove(peterGriffinFqn, "favouriteDrink");
+
+ assertNull(cache.get(peterGriffinFqn, "favouriteDrink");
+
+ cache.removeNode(peterGriffinFqn);
+
+ assertFalse(cache.getRootNode().hasChild(peterGriffinFqn));
+ </programlisting>
+ </section>
+
+ <section id="basic_api.fqn">
+ <title>The
+ <literal>Fqn</literal>
+ Class
+ </title>
+
+ <para>
+ The previous section used the
+ <literal>Fqn</literal>
+ class in its
+ examples; now let's learn a bit more about that class.
+ </para>
+
+ <para>
+ A Fully Qualified Name (Fqn) encapsulates a list of names which represent
+ a path to a particular location in the cache's tree structure. The
+ elements in the list are typically
+ <literal>String</literal>
+ s but can be
+ any
+ <literal>Object</literal>
+ or a mix of different types.
+ </para>
+
+ <para>
+ This path can be absolute (i.e., relative to the root node), or relative
+ to any node in the cache. Reading the documentation on each API call that
+ makes use of
+ <literal>Fqn</literal>
+ will tell you whether the API expects
+ a relative or absolute
+ <literal>Fqn</literal>
+ .
+ </para>
+
+ <para>
+ The
+ <literal>Fqn</literal>
+ class provides are variety of constructors;
+ see the javadoc for all the possibilities. The following illustrates the
+ most commonly used approaches to creating an Fqn:
+ </para>
+
+ <programlisting>
+ <![CDATA[
+ // Create an Fqn pointing to node 'Joe' under parent node 'Smith'
+ // under the 'people' section of the tree
+
+ // Parse it from a String
+ Fqn<String> abc = Fqn.fromString("/people/Smith/Joe/");
+
+ // Build it directly. A bit more efficient to construct than parsing
+ String[] strings = new String[] { "people", "Smith", "Joe" };
+ Fqn<String> abc = new Fqn<String>(strings);
+
+ // Here we want to use types other than String
+ Object[] objs = new Object[]{ "accounts", "NY", new Integer(12345) };
+ Fqn<Object> acctFqn = new Fqn<Object>(objs);
+ ]]>
+ </programlisting>
+
+ <para>Note that</para>
+ <para>
+ <programlisting><![CDATA[Fqn<String> f = new Fqn<String>("/a/b/c");]]></programlisting>
+ </para>
+ <para>is
+ <emphasis>not</emphasis>
+ the same as
+ </para>
+ <para>
+ <programlisting><![CDATA[Fqn<String> f = Fqn.fromString("/a/b/c");]]></programlisting>
+ </para>
+
+ <para>
+ The former will result in an Fqn with a single element, called "/a/b/c"
+ which hangs directly under the cache root. The latter will result
+ in a 3 element Fqn, where "c" idicates a child of "b", which is a child
+ of "a", and "a" hangs off the cache root. Another way to
+ look at it is that the "/" separarator is only parsed when it forms
+ part of a String passed in to
+ <literal>Fqn.fromString()</literal>
+ and not
+ otherwise.
+ </para>
+
+ <para>
+ The JBoss Cache API in the 1.x releases included many overloaded
+ convenience methods that took a string in the "/a/b/c" format in place
+ of an
+ <literal>Fqn</literal>
+ . In the interests of API simplicity, no
+ such convenience methods are available in the JBC 2.x API.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Stopping and Destroying the Cache</title>
+ <para>
+ It is good practice to stop and destroy your cache when you are done
+ using it, particularly if it is a clustered cache and has thus
+ used a JGroups channel. Stopping and destroying a cache ensures
+ resources like the JGroups channel are properly cleaned up.
+ </para>
+
+ <programlisting>
+ cache.stop();
+ cache.destroy();
+ </programlisting>
+
+ <para>
+ Not also that a cache that has had
+ <literal>stop()</literal>
+ invoked
+ on it can be started again with a new call to
+ <literal>start()</literal>
+ .
+ Similarly, a cache that has had
+ <literal>destroy()</literal>
+ invoked
+ on it can be created again with a new call to
+ <literal>create()</literal>
+ (and then started again with a
+ <literal>start()</literal>
+ call).
+ </para>
+ </section>
+
+ <section>
+ <title>Cache Modes</title>
+ <para>
+ Although technically not part of the API, the
+ <emphasis>mode</emphasis>
+ in which the cache is configured to operate affects the cluster-wide
+ behavior of any
+ <literal>put</literal>
+ or
+ <literal>remove</literal>
+ operation, so we'll briefly mention the various modes here.
+ </para>
+ <para>
+ JBoss Cache modes are denoted by the
+ <literal>org.jboss.cache.config.Configuration.CacheMode</literal>
+ enumeration.
+ They consist of:
+ <itemizedlist>
+ <listitem>
+ <emphasis>LOCAL</emphasis>
+ - local, non-clustered cache. Local caches don't join a cluster and don't
+ communicate with other caches in a cluster. Therefore their contents don't need to be Serializable;
+ however, we recommend making them Serializable, allowing you the flexibility to change the cache mode at
+ any time.
+ </listitem>
+ <listitem>
+ <emphasis>REPL_SYNC</emphasis>
+ - synchronous replication. Replicated caches replicate all changes to the other
+ caches in the cluster. Synchronous replication means that changes are replicated and the caller blocks
+ until replication acknowledgements are received.
+ </listitem>
+ <listitem>
+ <emphasis>REPL_ASYNC</emphasis>
+ - asynchronous replication. Similar to REPL_SYNC above, replicated caches replicate
+ all changes to the other caches in the cluster. Being asynchronous, the caller does not block until
+ replication acknowledgements are received.
+ </listitem>
+ <listitem>
+ <emphasis>INVALIDATION_SYNC</emphasis>
+ - if a cache is configured for invalidation rather than replication,
+ every time data is changed in a cache other caches in the cluster
+ receive a message informing them that their data is now stale and should
+ be evicted from memory. This reduces replication overhead while still being able to invalidate stale data
+ on remote caches.
+ </listitem>
+ <listitem>
+ <emphasis>INVALIDATION_ASYNC</emphasis>
+ - as above, except this invalidation mode causes invalidation messages
+ to be broadcast asynchronously.
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>See the
+ <link linkend="clustering">chapter on Clustering</link>
+ for
+ more details on how the cache's mode affects behavior. See the
+ <link linkend="configuration">chapter on Configuration</link>
+ for info
+ on how to configure things like the cache's mode.
+ </para>
+ </section>
+
+ <section id="api.listener">
+ <title>
+ Adding a CacheListener
+ </title>
+ <para>
+ The
+ <literal>@org.jboss.cache.notifications.annotation.CacheListener</literal>
+ annotation is a convenient
+ mechanism for receiving notifications from a cache about events that happen in the cache. Classes annotated
+ with
+ <literal>@CacheListener</literal>
+ need to be public classes. In addition, the class needs to have one or
+ more methods annotated with one of the method-level annotations (in the
+ <literal>org.jboss.cache.notifications.annotation</literal>
+ package). Methods annotated as such need to be public, have a void return type, and accept a single parameter
+ of
+ type
+ <literal>org.jboss.cache.notifications.event.Event</literal>
+ or one of it's subtypes.
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>@CacheStarted</literal>
+ - methods annotated such receive a notification when the cache is
+ started. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.CacheStartedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@CacheStopped</literal>
+ - methods annotated such receive a notification when the cache is
+ stopped. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.CacheStoppedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeCreated</literal>
+ - methods annotated such receive a notification when a node is
+ created. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeCreatedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeRemoved</literal>
+ - methods annotated such receive a notification when a node is
+ removed. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeRemovedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeModified</literal>
+ - methods annotated such receive a notification when a node is
+ modified. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeModifiedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeMoved</literal>
+ - methods annotated such receive a notification when a node is
+ moved. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeMovedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeVisited</literal>
+ - methods annotated such receive a notification when a node is
+ started. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeVisitedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeLoaded</literal>
+ - methods annotated such receive a notification when a node is
+ loaded from a
+ <literal>CacheLoader</literal>
+ . Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeLoadedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeEvicted</literal>
+ - methods annotated such receive a notification when a node is
+ evicted from memory. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeEvictedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeActivated</literal>
+ - methods annotated such receive a notification when a node is
+ activated. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeActivatedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodePassivated</literal>
+ - methods annotated such receive a notification when a node is
+ passivated. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodePassivatedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@TransactionRegistered</literal>
+ - methods annotated such receive a notification when the cache
+ registers a
+ <literal>javax.transaction.Synchronization</literal>
+ with a registered transaction manager.
+ Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.TransactionRegisteredEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@TransactionCompleted</literal>
+ - methods annotated such receive a notification when the cache
+ receives a commit or rollback call from a registered transaction manager.
+ Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.TransactionCompletedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@ViewChanged</literal>
+ - methods annotated such receive a notification when the group structure
+ of the cluster changes. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.ViewChangedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@CacheBlocked</literal>
+ - methods annotated such receive a notification when the cluster
+ requests that cache operations are blocked for a state transfer event. Methods need to accept a
+ parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.CacheBlockedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@CacheUnblocked</literal>
+ - methods annotated such receive a notification when the cluster
+ requests that cache operations are unblocked after a state transfer event. Methods need to accept a
+ parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.CacheUnblockedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ </itemizedlist>
+ </para>
+ <para>
+ Refer to the javadocs on the annotations as well as the
+ <literal>Event</literal>
+ subtypes
+ for details of what is passed in to your method, and when.
+ </para>
+ <para>
+ Example:
+ <programlisting><![CDATA[
+
+ @CacheListener
+ public class MyListener
+ {
+
+ @CacheStarted
+ @CacheStopped
+ public void cacheStartStopEvent(Event e)
+ {
+ switch (e.getType())
+ {
+ case Event.Type.CACHE_STARTED:
+ System.out.println("Cache has started");
+ break;
+ case Event.Type.CACHE_STOPPED:
+ System.out.println("Cache has stopped");
+ break;
+ }
+ }
+
+ @NodeCreated
+ @NodeRemoved
+ @NodeVisited
+ @NodeModified
+ @NodeMoved
+ public void logNodeEvent(NodeEvent ne)
+ {
+ log("An event on node " + ne.getFqn() + " has occured");
+ }
+ }
+
+ ]]></programlisting>
+ </para>
+ </section>
+
+ <section>
+ <title>Using Cache Loaders</title>
+ <para>
+ Cache loaders are an important part of JBoss Cache. They allow persistence of nodes to disk or to remote cache
+ clusters, and allow for passivation when caches run out of memory. In addition, cache loaders allow JBoss Cache
+ to perform 'warm starts', where in-memory state can be preloaded from persistent storage. JBoss Cache ships
+ with a number of cache loader implementations.
+ <itemizedlist>
+ <listitem>
+ <literal>org.jboss.cache.loader.FileCacheLoader</literal>
+ - a basic, filesystem based cache loader that persists data to disk. Non-transactional and not very
+ performant, but a very simple solution. Used mainly for testing and not recommended for production use.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.loader.JDBCCacheLoader</literal>
+ - uses a JDBC connection to store data. Connections could be created and maintained in an internal pool
+ (uses the c3p0 pooling library)
+ or from a configured DataSource. The database this CacheLoader connects to could be local or remotely
+ located.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.loader.BdbjeCacheLoader</literal>
+ - uses Oracle's BerkeleyDB file-based transactional database to persist data. Transactional and very
+ performant, but potentially restrictive license.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.loader.JdbmCacheLoader</literal>
+ - an upcoming open source alternative to the BerkeleyDB.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.loader.tcp.TcpCacheLoader</literal>
+ - uses a TCP socket to "persist" data to a remote cluster, using a "far cache" pattern.
+ <footnote>
+ <para>http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossClusteringPatternFarCache</para>
+ </footnote>
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.loader.ClusteredCacheLoader</literal>
+ - used as a "read-only" CacheLoader, where other nodes in the cluster are queried for state.
+ </listitem>
+ </itemizedlist>
+ These CacheLoaders, along with advanced aspects and tuning issues, are discussed in the
+ <link linkend="cache_loaders">chapter dedicated to CacheLoaders</link>
+ .
+ </para>
+ </section>
+
+ <section>
+ <title>Using Eviction Policies</title>
+ <para>
+ Eviction policies are the counterpart to CacheLoaders. They are necessary to make sure the cache does not run
+ out of memory and when the cache starts to fill,
+ the eviction algorithm running in a separate thread offloads in-memory state to the CacheLoader and frees up
+ memory. Eviction policies can be configured
+ on a per-region basis, so different subtrees in the cache could have different eviction preferences.
+
+ JBoss Cache ships with several eviction policies:
+ <itemizedlist>
+ <listitem>
+ <literal>org.jboss.cache.eviction.LRUPolicy</literal>
+ - an eviction policy that evicts the least recently used nodes when thresholds are hit.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.LFUPolicy</literal>
+ - an eviction policy that evicts the least frequently used nodes when thresholds are hit.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.MRUPolicy</literal>
+ - an eviction policy that evicts the most recently used nodes when thresholds are hit.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.FIFOPolicy</literal>
+ - an eviction policy that creates a first-in-first-out queue and evicts the oldest nodes when thresholds
+ are hit.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.ExpirationPolicy</literal>
+ - an eviction policy that selects nodes for eviction based on an expiry time each node is configured
+ with.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.ElementSizePolicy</literal>
+ - an eviction policy that selects nodes for eviction based on the number of key/value pairs held in the
+ node.
+ </listitem>
+ </itemizedlist>
+ Detailed configuration and implementing custom eviction policies are discussed in the
+ <link linkend="eviction_policies">chapter dedicated to eviction policies.</link>
+ .
+ </para>
+ </section>
+</chapter>
Added: core/trunk/src/main/docbook/userguide/en/modules/cache_loaders.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/modules/cache_loaders.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/modules/cache_loaders.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,1325 @@
+<chapter id="cache_loaders">
+ <title>Cache Loaders</title>
+ <para>JBoss Cache can use a
+ <literal>CacheLoader</literal>
+ to back up the in-memory cache to a backend datastore.
+ If JBoss Cache is configured with a cache loader, then the following features are provided:
+ <itemizedlist>
+ <listitem>Whenever a cache element is accessed, and that element is not in
+ the cache (e.g. due to eviction or due to server restart), then the cache loader transparently
+ loads the element into the cache if found in the backend
+ store.
+ </listitem>
+
+ <listitem>Whenever an element is modified, added or removed, then that
+ modification is persisted in the backend store via the cache loader. If
+ transactions are used, all modifications created within a transaction
+ are persisted. To this end, the
+ <literal>CacheLoader</literal>
+ takes part in the two
+ phase commit protocol run by the transaction manager, although it does not do so explicitly.
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <section>
+ <title>The CacheLoader Interface and Lifecycle</title>
+
+ <figure>
+ <title>The CacheLoader interface</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="CacheLoader.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+
+ <para>The interaction between JBoss Cache and a
+ <literal>CacheLoader</literal>
+ implementation is as follows. When
+ <literal>CacheLoaderConfiguration</literal>
+ (see below) is non-null, an
+ instance of each configured
+ <literal>CacheLoader</literal>
+ is created when the cache is created, and started when the cache is started.
+ </para>
+
+ <para>
+ <literal>CacheLoader.create()</literal>
+ and
+ <literal>CacheLoader.start()</literal>
+ are called when the cache is
+ started. Correspondingly,
+ <literal>stop()</literal>
+ and
+ <literal>destroy()</literal>
+ are called when the cache is
+ stopped.
+ </para>
+
+ <para>Next,
+ <literal>setConfig()</literal>
+ and
+ <literal>setCache()</literal>
+ are called. The latter can be used to
+ store a reference to the cache, the former is used to configure this
+ instance of the
+ <literal>CacheLoader</literal>
+ . For example, here a database cache loader
+ could establish a connection to the database.
+ </para>
+
+ <para>The
+ <literal>CacheLoader</literal>
+ interface has a set of methods that are called
+ when no transactions are used:
+ <literal>get()</literal>
+ ,
+ <literal>put()</literal>
+ ,
+ <literal>remove()</literal>
+ and
+ <literal>removeData()</literal>
+ : they get/set/remove the value
+ immediately. These methods are described as javadoc comments in the
+ interface.
+ </para>
+
+ <para>Then there are three methods that are used with transactions:
+ <literal>prepare()</literal>
+ ,
+ <literal>commit()</literal>
+ and
+ <literal>rollback()</literal>
+ . The
+ <literal>prepare()</literal>
+ method
+ is called when a transaction is to be committed. It has a transaction
+ object and a list of modfications as argument. The transaction object
+ can be used as a key into a hashmap of transactions, where the values
+ are the lists of modifications. Each modification list has a number of
+ <literal>Modification</literal>
+ elements, which represent the changes
+ made to a cache for a given transaction. When
+ <literal>prepare()</literal>
+ returns successfully, then the cache loader
+ <emphasis>must</emphasis>
+ be able to commit (or rollback) the
+ transaction successfully.
+ </para>
+
+ <para>
+ JBoss Cache takes care of calling prepare(), commit()
+ and rollback() on the cache loaders at the right time.
+ </para>
+
+ <para>The
+ <literal>commit()</literal>
+ method tells the cache loader to
+ commit the transaction, and the
+ <literal>rollback()</literal>
+ method
+ tells the cache loader to discard the changes associated with that
+ transaction.
+ </para>
+
+ <para>See the javadocs on this interface for a detailed explanation on each method and the contract
+ implementations
+ would need to fulfil.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Configuration</title>
+
+ <para>Cache loaders are configured as follows in the JBoss Cache XML
+ file. Note that you can define several cache loaders, in
+ a chain. The impact is that the cache will look at all of the cache
+ loaders in the order they've been configured, until it finds a valid,
+ non-null element of data. When performing writes, all cache loaders are
+ written to (except if the
+ <literal>ignoreModifications</literal>
+ element has been set to
+ <literal>true</literal>
+ for a specific cache loader. See the configuration section below for
+ details.
+ </para>
+
+ <programlisting>
+ <![CDATA[
+
+...
+
+<!-- Cache loader config block -->
+<attribute name="CacheLoaderConfiguration">
+ <config>
+ <!-- if passivation is true, only the first cache loader is used; the rest are ignored -->
+ <passivation>false</passivation>
+ <!-- comma delimited FQNs to preload -->
+ <preload>/</preload>
+ <!-- are the cache loaders shared in a cluster? -->
+ <shared>false</shared>
+
+ <!-- we can now have multiple cache loaders, which get chained -->
+ <!-- the 'cacheloader' element may be repeated -->
+ <cacheloader>
+
+ <class>org.jboss.cache.loader.JDBCCacheLoader</class>
+
+ <!-- properties to pass in to the cache loader -->
+ <properties>
+ cache.jdbc.driver=com.mysql.jdbc.Driver
+ cache.jdbc.url=jdbc:mysql://localhost:3306/jbossdb
+ cache.jdbc.user=root
+ cache.jdbc.password=
+ cache.jdbc.sql-concat=concat(1,2)
+ </properties>
+
+ <!-- whether the cache loader writes are asynchronous -->
+ <async>false</async>
+
+ <!-- only one cache loader in the chain may set fetchPersistentState to true.
+ An exception is thrown if more than one cache loader sets this to true. -->
+ <fetchPersistentState>true</fetchPersistentState>
+
+ <!-- determines whether this cache loader ignores writes - defaults to false. -->
+ <ignoreModifications>false</ignoreModifications>
+
+ <!-- if set to true, purges the contents of this cache loader when the cache starts up.
+ Defaults to false. -->
+ <purgeOnStartup>false</purgeOnStartup>
+
+ <!-- defines the cache loader as a singleton store where only the coordinator of the
+ cluster will store modifications. -->
+ <singletonStore>
+ <!-- if true, singleton store functionality is enabled, defaults to false -->
+ <enabled>false</enabled>
+
+ <!-- implementation class for singleton store functionality which must extend
+ org.jboss.cache.loader.AbstractDelegatingCacheLoader. Default implementation
+ is org.jboss.cache.loader.SingletonStoreCacheLoader -->
+ <class>org.jboss.cache.loader.SingletonStoreCacheLoader</class>
+
+ <!-- properties and default values for the default singleton store functionality
+ implementation -->
+ <properties>
+ pushStateWhenCoordinator=true
+ pushStateWhenCoordinatorTimeout=20000
+ </properties>
+ </singletonStore>
+ </cacheloader>
+
+ </config>
+</attribute>
+]]>
+ </programlisting>
+
+ <para>The
+ <literal>class</literal>
+ element defines the
+ class of the cache loader implementation. (Note that, because of a bug in
+ the properties editor in JBoss AS, backslashes in variables for Windows
+ filenames might not get expanded correctly, so replace="false" may be
+ necessary). Note that an implementation of cache loader has to have an empty
+ constructor.
+ </para>
+
+ <para>The
+ <literal>properties</literal>
+ element defines a configuration
+ specific to the given implementation. The filesystem-based
+ implementation for example defines the root directory to be used,
+ whereas a database implementation might define the database URL, name
+ and password to establish a database connection. This configuration is
+ passed to the cache loader implementation via
+ <literal>CacheLoader.setConfig(Properties)</literal>
+ . Note that
+ backspaces may have to be escaped.
+ </para>
+
+ <para>
+ <literal>preload</literal>
+ allows us to define a list of nodes, or
+ even entire subtrees, that are visited by the cache on startup, in order
+ to preload the data associated with those nodes. The default ("/") loads
+ the entire data available in the backend store into the cache, which is
+ probably not a good idea given that the data in the backend store might
+ be large. As an example,
+ <literal>/a,
+ /product/catalogue
+ </literal>
+ loads the subtrees
+ <literal>/a</literal>
+ and
+ <literal>/product/catalogue</literal>
+ into the cache, but nothing
+ else. Anything else is loaded lazily when accessed. Preloading makes
+ sense when one anticipates using elements under a given subtree
+ frequently.
+ .
+ </para>
+
+ <para>
+ <literal>fetchPersistentState</literal>
+ determines whether or not
+ to fetch the persistent state of a cache when joining a cluster. Only
+ one configured cache loader may set this property to true; if more than
+ one cache loader does so, a configuration exception will be thrown when
+ starting your cache service.
+ </para>
+
+ <para>
+ <literal>async</literal>
+ determines whether writes to the cache
+ loader block until completed, or are run on a separate thread so writes
+ return immediately. If this is set to true, an instance of
+ <literal>org.jboss.cache.loader.AsyncCacheLoader</literal>
+ is
+ constructed with an instance of the actual cache loader to be used. The
+ <literal>AsyncCacheLoader</literal>
+ then delegates all requests to the
+ underlying cache loader, using a separate thread if necessary. See the
+ Javadocs on
+ <literal>AsyncCacheLoader</literal>
+ for more details. If unspecified, the
+ <literal>async</literal>
+ element
+ defaults to
+ <literal>false</literal>
+ .
+ </para>
+
+ <para>
+ <emphasis role="bold">Note on using the
+ <literal>async</literal>
+ element:
+ </emphasis>
+ there is always the possibility of dirty reads since
+ all writes are performed asynchronously, and it is thus impossible to
+ guarantee when (and even if) a write succeeds. This needs to be kept in
+ mind when setting the
+ <literal>async</literal>
+ element to true.
+ </para>
+
+ <para>
+ <literal>ignoreModifications</literal>
+ determines whether write
+ methods are pushed down to the specific cache loader. Situations may
+ arise where transient application data should only reside in a file
+ based cache loader on the same server as the in-memory cache, for
+ example, with a further shared
+ <literal>JDBCCacheLoader</literal>
+ used by all servers in
+ the network. This feature allows you to write to the 'local' file cache
+ loader but not the shared
+ <literal>JDBCCacheLoader</literal>
+ . This property defaults to
+ <literal>false</literal>
+ , so writes are propagated to all cache loaders
+ configured.
+ </para>
+
+ <para>
+ <literal>purgeOnStatup</literal>
+ empties the specified cache loader
+ (if
+ <literal>ignoreModifications</literal>
+ is
+ <literal>false</literal>
+ )
+ when the cache loader starts up.
+ </para>
+
+ <para>
+ <literal>shared</literal>
+ indicates that the cache loader is shared among different cache instances, for example where all instances in a
+ cluster use the same JDBC settings t talk to the same remote, shared database. Setting this to
+ <literal>true</literal>
+ prevents repeated and unnecessary writes of the same data to the cache loader by different cache instances.
+ Default value is
+ <literal>false</literal>
+ .
+ </para>
+
+ <section>
+ <title>Singleton Store Configuration</title>
+
+ <para>
+ <literal>singletonStore</literal>
+ element enables modifications to be stored by only one node in the cluster,
+ the coordinator. Essentially, whenever any data comes in to some node
+ it is always replicated so as to keep the caches' in-memory states in
+ sync; the coordinator, though, has the sole responsibility of pushing
+ that state to disk. This functionality can be activated setting the
+ <literal>enabled</literal>
+ subelement to true in all nodes, but
+ again only the coordinator of the cluster will store the modifications
+ in the underlying cache loader as defined in
+ <literal>cacheloader</literal>
+ element. You cannot define a cache loader as
+ <literal>shared</literal>
+ and with
+ <literal>singletonStore</literal>
+ enabled at the same time.
+ Default value for
+ <literal>enabled</literal>
+ is
+ <literal>false</literal>
+ .
+ </para>
+
+ <para>
+ Optionally, within the
+ <literal>singletonStore</literal>
+ element, you can define a
+ <literal>class</literal>
+ element that specifies the implementation class that provides the
+ singleton store functionality. This class must extend
+ <literal>org.jboss.cache.loader.AbstractDelegatingCacheLoader</literal>
+ , and if absent, it defaults to
+ <literal>org.jboss.cache.loader.SingletonStoreCacheLoader</literal>
+ .
+ </para>
+
+ <para>
+ The
+ <literal>properties</literal>
+ subelement defines properties that allow changing the behaivour of the
+ class providing the singleton store functionality. By default,
+ <literal>pushStateWhenCoordinator</literal>
+ and
+ <literal>pushStateWhenCoordinatorTimeout</literal>
+ properties have been defined, but more could be added as
+ required by the user-defined class providing singleton store
+ functionality.
+ </para>
+
+ <para>
+ <literal>pushStateWhenCoordinator</literal>
+ allows the in-memory
+ state to be pushed to the cache store when a node becomes the
+ coordinator, as a result of the new election of coordinator due to a
+ cluster topology change. This can be very useful in situations where the
+ coordinator crashes and there's a gap in time until the new coordinator
+ is elected. During this time, if this property was set to
+ <literal>false</literal>
+ and the
+ cache was updated, these changes would never be persisted. Setting this
+ property to
+ <literal>true</literal>
+ would ensure that any changes during this process also
+ get stored in the cache loader. You would also want to set this property
+ to
+ <literal>true</literal>
+ if each node's cache loader is configured with a different
+ location. Default value is
+ <literal>true</literal>
+ .
+ </para>
+
+ <para>
+ <literal>pushStateWhenCoordinatorTimeout</literal>
+ is only relevant if
+ <literal>pushStateWhenCoordinator</literal>
+ is
+ <literal>true</literal>
+ in which case, sets the maximum number of milliseconds that the process
+ of pushing the in-memory state to the underlying cache loader should take,
+ reporting a
+ <literal>PushStateException</literal>
+ if exceeded. Default value is 20000.
+ </para>
+
+ <para>
+ <emphasis role="bold">Note on using the
+ <literal>singletonStore</literal>
+ element:
+ </emphasis>
+ setting
+ up a cache loader as a singleton and using cache passivation (via
+ evictions) can lead to undesired effects. If a node is to be passivated
+ as a result of an eviction, while the cluster is in the process of
+ electing a new coordinator, the data will be lost. This is because no
+ coordinator is active at that time and therefore, none of the nodes in
+ the cluster will store the passivated node. A new coordinator is elected
+ in the cluster when either, the coordinator leaves the cluster, the
+ coordinator crashes or stops responding.
+ </para>
+ </section>
+ </section>
+
+ <section id="cl.impls">
+
+ <title>Shipped Implementations</title>
+
+ <para>The currently available implementations shipped with JBoss Cache are as follows.</para>
+
+ <section>
+ <title>File system based cache loaders</title>
+ <para>
+ JBoss Cache ships with several cache loaders that utilise the file system as a data store. They all require
+ that the
+ <literal><![CDATA[<cacheloader><properties>]]></literal>
+ configuration element
+ contains a
+ <literal>location</literal>
+ property, which maps to a directory to be used as a persistent store.
+ (e.g.,
+ <literal>location=/tmp/myDataStore</literal>
+ ). Used mainly for testing and not recommended for production use.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>FileCacheLoader</literal>
+ , which is a simple filesystem-based implementation. By default, this cache
+ loader checks for any potential character portability issues in the
+ location or tree node names, for example invalid characters, producing
+ warning messages. These checks can be disabled adding
+ <literal>check.character.portability</literal>
+ property to the
+ <literal><![CDATA[<properties>]]></literal>
+ element and setting it to
+ <literal>false</literal>
+ (e.g.,
+ <literal>check.character.portability=false</literal>
+ ).
+ </para>
+ <para>
+ The FileCacheLoader has some severe limitations which restrict it's use in a production
+ environment, or if used in such an environment, it should be used with due care and sufficient
+ understanding of these limitations.
+ <itemizedlist>
+ <listitem>Due to the way the FileCacheLoader represents a tree structure on disk (directories and
+ files) traversal is inefficient for deep trees.
+ </listitem>
+ <listitem>Usage on shared filesystems like NFS, Windows shares, etc. should be avoided as these do
+ not implement proper file locking and can cause data corruption.
+ </listitem>
+ <listitem>Usage with an isolation level of NONE can cause corrupt writes as multiple threads
+ attempt to write to the same file.
+ </listitem>
+ <listitem>File systems are inherently not transactional, so when attempting to use your cache in a
+ transactional context, failures when writing to the file (which happens during the commit phase)
+ cannot be recovered.
+ </listitem>
+ </itemizedlist>
+
+ As a rule of thumb, it is recommended that the FileCacheLoader not be used in a highly concurrent,
+ transactional or stressful environment, and it's use is restricted to testing.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>BdbjeCacheLoader</literal>
+ , which is a cache loader implementation based on the Oracle/Sleepycat's
+ <ulink url="http://www.oracle.com/database/berkeley-db/index.html">BerkeleyDB Java Edition</ulink>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>JdbmCacheLoader</literal>
+ , which is a cache loader
+ implementation based on the
+ <ulink url="http://jdbm.sourceforge.net/">JDBM engine</ulink>
+ , a fast and free alternative to
+ BerkeleyDB.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Note that the BerkeleyDB implementation is much more efficient than
+ the filesystem-based implementation, and provides transactional
+ guarantees, but requires a commercial license if distributed with an
+ application (see http://www.oracle.com/database/berkeley-db/index.html for
+ details).
+ </para>
+
+ </section>
+
+ <section>
+ <title>Cache loaders that delegate to other caches</title>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>LocalDelegatingCacheLoader</literal>
+ , which enables
+ loading from and storing to another local (same JVM) cache.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ClusteredCacheLoader</literal>
+ , which allows querying
+ of other caches in the same cluster for in-memory data via the same
+ clustering protocols used to replicate data. Writes are
+ <emphasis>not</emphasis>
+ 'stored' though, as replication would
+ take care of any updates needed. You need to specify a property
+ called
+ <literal>timeout</literal>
+ , a long value telling the cache
+ loader how many milliseconds to wait for responses from the cluster
+ before assuming a null value. For example,
+ <literal>timeout = 3000</literal>
+ would use a timeout value of 3 seconds.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+
+ <section id="cl.jdbc">
+ <title>JDBCCacheLoader</title>
+
+ <para>JBossCache is distributed with a JDBC-based cache loader
+ implementation that stores/loads nodes' state into a relational database.
+ The implementing class is
+ <literal>org.jboss.cache.loader.JDBCCacheLoader</literal>
+ .
+ </para>
+
+ <para>The current implementation uses just one table. Each row in the table
+ represents one node and contains three columns:
+ <itemizedlist>
+ <listitem>column for
+ <literal>Fqn</literal>
+ (which is also a primary key
+ column)
+ </listitem>
+
+ <listitem>column for node contents (attribute/value
+ pairs)
+ </listitem>
+
+ <listitem>column for parent
+ <literal>Fqn</literal>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ <literal>Fqn</literal>
+ 's are stored as strings. Node content is stored
+ as a BLOB.
+ <emphasis>WARNING:</emphasis>
+ JBoss Cache does not impose any
+ limitations on the types of objects used in
+ <literal>Fqn</literal>
+ but this implementation of
+ cache loader requires
+ <literal>Fqn</literal>
+ to contain only objects of type
+ <literal>java.lang.String</literal>
+ . Another limitation for
+ <literal>Fqn</literal>
+ is its
+ length. Since
+ <literal>Fqn</literal>
+ is a primary key, its default column type is
+ <literal>VARCHAR</literal>
+ which can store text values up to some
+ maximum length determined by the database in use.
+ </para>
+
+ <para>See
+ <ulink
+ url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JDBCCacheLoader">
+ http://wiki.jboss.org/wiki/Wiki.jsp?page=JDBCCacheLoader
+ </ulink>
+ for configuration tips with specific database systems.
+ </para>
+
+ <section>
+ <title>JDBCCacheLoader configuration</title>
+
+ <section>
+ <title>Table configuration</title>
+
+ <para>Table and column names as well as column types are
+ configurable with the following properties.
+ <itemizedlist>
+ <listitem>
+ <emphasis>cache.jdbc.table.name</emphasis>
+ - the name
+ of the table. The default value is 'jbosscache'.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.table.primarykey</emphasis>
+ - the
+ name of the primary key for the table. The default value is
+ 'jbosscache_pk'.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.table.create</emphasis>
+ - can be
+ true or false. Indicates whether to create the table during startup.
+ If true, the table is created if it doesn't already exist. The
+ default value is true.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.table.drop</emphasis>
+ - can be
+ true or false. Indicates whether to drop the table during shutdown. The
+ default value is true.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.fqn.column</emphasis>
+ - FQN
+ column name. The default value is 'fqn'.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.fqn.type</emphasis>
+ - FQN column
+ type. The default value is 'varchar(255)'.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.node.column</emphasis>
+ - node
+ contents column name. The default value is 'node'.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.node.type</emphasis>
+ - node
+ contents column type. The default value is 'blob'. This type must specify
+ a valid binary data type for the database being used.
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>DataSource</title>
+
+ <para>If you are using JBossCache in a managed environment (e.g., an
+ application server) you can specify the JNDI name of the DataSource
+ you want to use.
+ <itemizedlist>
+ <listitem>
+ <emphasis>cache.jdbc.datasource</emphasis>
+ - JNDI name
+ of the DataSource. The default value is
+ <literal>java:/DefaultDS</literal>
+ .
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>JDBC driver</title>
+
+ <para>If you are
+ <emphasis>not</emphasis>
+ using DataSource you have
+ the following properties to configure database access using a JDBC
+ driver.
+ <itemizedlist>
+ <listitem>
+ <emphasis>cache.jdbc.driver</emphasis>
+ - fully
+ qualified JDBC driver name.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.url</emphasis>
+ - URL to connect
+ to the database.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.user</emphasis>
+ - user name to
+ connect to the database.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.password</emphasis>
+ - password to
+ connect to the database.
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>c3p0 connection pooling</title>
+
+ <para>JBoss Cache implements JDBC connection pooling when running outside of an application server
+ standalone using
+ the c3p0:JDBC DataSources/Resource Pools library. In order to enable it, just edit the following
+ property:
+ <itemizedlist>
+ <listitem>
+ <emphasis>cache.jdbc.connection.factory</emphasis>
+ - Connection factory class name.
+ If not set, it defaults to standard non-pooled implementation. To enable c3p0 pooling, just set
+ the
+ connection factory class for c3p0. See example below.
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>You can also set any c3p0 parameters in the same cache loader properties section but don't forget
+ to
+ start the property name with 'c3p0.'. To find a list of available properties, please check the
+ c3p0 documentation for the c3p0 library version distributed in
+ <ulink url="http://sourceforge.net/projects/c3p0">c3p0:JDBC DataSources/Resource Pools</ulink>
+ .
+ Also, in order to provide quick and easy way to try out different pooling
+ parameters, any of these properties can be set via a System property overriding any values these
+ properties might have in the JBoss Cache XML configuration file, for example:
+ <literal>-Dc3p0.maxPoolSize=20</literal>
+ .
+ If a c3p0 property is not defined in either the configuration file or as a System property, default
+ value, as indicated in the c3p0 documentation, will apply.
+ </para>
+ </section>
+
+ <section>
+ <title>Configuration example</title>
+
+ <para>Below is an example of a JDBCCacheLoader using Oracle as
+ database. The CacheLoaderConfiguration XML element contains an
+ arbitrary set of properties which define the database-related
+ configuration.
+ </para>
+
+ <para>
+ <programlisting>
+ <![CDATA[
+<attribute name="CacheLoaderConfiguration">
+<config>
+ <passivation>false</passivation>
+ <preload>/some/stuff</preload>
+ <cacheloader>
+ <class>org.jboss.cache.loader.JDBCCacheLoader</class>
+
+ <properties>
+ cache.jdbc.table.name=jbosscache
+ cache.jdbc.table.create=true
+ cache.jdbc.table.drop=true
+ cache.jdbc.table.primarykey=jbosscache_pk
+ cache.jdbc.fqn.column=fqn
+ cache.jdbc.fqn.type=varchar(255)
+ cache.jdbc.node.column=node
+ cache.jdbc.node.type=blob
+ cache.jdbc.parent.column=parent
+ cache.jdbc.driver=oracle.jdbc.OracleDriver
+ cache.jdbc.url=jdbc:oracle:thin:@localhost:1521:JBOSSDB
+ cache.jdbc.user=SCOTT
+ cache.jdbc.password=TIGER
+ cache.jdbc.sql-concat=concat(1,2)
+ </properties>
+
+ <async>false</async>
+ <fetchPersistentState>true</fetchPersistentState>
+ <ignoreModifications>false</ignoreModifications>
+ <purgeOnStartup>false</purgeOnStartup>
+ </cacheloader>
+</config>
+</attribute>
+]]>
+ </programlisting>
+ </para>
+
+ <para>As an alternative to configuring the entire JDBC connection,
+ the name of an existing data source can be given:
+ </para>
+
+ <programlisting>
+ <![CDATA[
+<attribute name="CacheLoaderConfiguration">
+<config>
+ <passivation>false</passivation>
+ <preload>/some/stuff</preload>
+ <cacheloader>
+ <class>org.jboss.cache.loader.JDBCCacheLoader</class>
+
+ <properties>
+ cache.jdbc.datasource=java:/DefaultDS
+ </properties>
+
+ <async>false</async>
+ <fetchPersistentState>true</fetchPersistentState>
+ <ignoreModifications>false</ignoreModifications>
+ <purgeOnStartup>false</purgeOnStartup>
+ </cacheloader>
+</config>
+</attribute>
+]]>
+ </programlisting>
+
+ <para>Cconfiguration example for a cache loader using c3p0 JDBC connection pooling:</para>
+
+ <programlisting>
+ <![CDATA[
+<attribute name="CacheLoaderConfiguration">
+<config>
+ <passivation>false</passivation>
+ <preload>/some/stuff</preload>
+ <cacheloader>
+ <class>org.jboss.cache.loader.JDBCCacheLoader</class>
+
+ <properties>
+ cache.jdbc.table.name=jbosscache
+ cache.jdbc.table.create=true
+ cache.jdbc.table.drop=true
+ cache.jdbc.table.primarykey=jbosscache_pk
+ cache.jdbc.fqn.column=fqn
+ cache.jdbc.fqn.type=varchar(255)
+ cache.jdbc.node.column=node
+ cache.jdbc.node.type=blob
+ cache.jdbc.parent.column=parent
+ cache.jdbc.driver=oracle.jdbc.OracleDriver
+ cache.jdbc.url=jdbc:oracle:thin:@localhost:1521:JBOSSDB
+ cache.jdbc.user=SCOTT
+ cache.jdbc.password=TIGER
+ cache.jdbc.sql-concat=concat(1,2)
+ cache.jdbc.connection.factory=org.jboss.cache.loader.C3p0ConnectionFactory
+ c3p0.maxPoolSize=20
+ c3p0.checkoutTimeout=5000
+ </properties>
+
+ <async>false</async>
+ <fetchPersistentState>true</fetchPersistentState>
+ <ignoreModifications>false</ignoreModifications>
+ <purgeOnStartup>false</purgeOnStartup>
+ </cacheloader>
+</config>
+</attribute>
+]]>
+ </programlisting>
+
+ </section>
+ </section>
+ </section>
+
+ <section id="cl.tcp">
+ <title>TcpDelegatingCacheLoader</title>
+
+ <para>This cache loader allows to delegate loads and stores to another
+ instance of JBoss Cache, which could reside (a) in the same address
+ space, (b) in a different process on the same host, or (c) in a
+ different process on a different host.
+ </para>
+
+ <para>A TcpDelegatingCacheLoader talks to a remote
+ <literal>org.jboss.cache.loader.tcp.TcpCacheServer</literal>
+ ,
+ which can be a standalone process started on the command line, or embedded as an MBean inside
+ JBoss AS. The
+ <literal>TcpCacheServer</literal>
+ has a reference to another JBoss Cache instance, which
+ it can create itself, or which is given to it (e.g. by JBoss, using
+ dependency injection).
+ </para>
+
+ <para>The TcpDelegatingCacheLoader is configured with the host and
+ port of the remote TcpCacheServer, and uses this to communicate to
+ it.
+ </para>
+
+ <para>The configuration looks as follows:</para>
+
+ <programlisting>
+ <![CDATA[
+<attribute name="CacheLoaderConfiguration">
+<config>
+ <cacheloader>
+ <class>org.jboss.cache.loader.TcpDelegatingCacheLoader</class>
+ <properties>
+ host=myRemoteServer
+ port=7500
+ </properties>
+ </cacheloader>
+</config>
+</attribute>
+]]>
+ </programlisting>
+
+ <para>This means this instance of JBoss Cache will delegate all load
+ and store requests to the remote TcpCacheServer running on
+ <literal>myRemoteServer:7500</literal>
+ .
+ </para>
+
+ <para>A typical use case could be multiple replicated instances of
+ JBoss Cache in the same cluster, all delegating to the same
+ TcpCacheServer instance. The TcpCacheServer might itself delegate to a
+ database via JDBCCacheLoader, but the point here is that - if we have
+ 5 nodes all accessing the same dataset - they will load the data from
+ the TcpCacheServer, which has do execute one SQL statement per
+ unloaded data set. If the nodes went directly to the database, then
+ we'd have the same SQL executed multiple times. So TcpCacheServer
+ serves as a natural cache in front of the DB (assuming that a network
+ round trip is faster than a DB access (which usually also include a
+ network round trip)).
+ </para>
+
+ <para>To alleviate single point of failure, we could configure several cache loaders.
+ The first cache loader is a ClusteredCacheLoader, the second a TcpDelegatingCacheLoader, and the
+ last a JDBCacheLoader, effectively defining our cost of access to a
+ cache in increasing order.
+ </para>
+
+ </section>
+
+ <section id="cl.transforming">
+ <title>Transforming Cache Loaders</title>
+
+ <para>The way cached data is written to
+ <literal>FileCacheLoader</literal>
+ and
+ <literal>JDBCCacheLoader</literal>
+ based cache stores has changed in JBoss Cache 2.0 in such way that
+ these cache loaders now write and read data using the same marhalling framework used to replicate data
+ accross the network. Such change is trivial for replication purpouses as it just requires the rest of the
+ nodes to understand this format. However, changing the format of the data in cache stores brings up a new
+ problem: how do users, which have their data stored in JBoss Cache 1.x.x format, migrate their stores to
+ JBoss Cache 2.0 format?
+ </para>
+
+ <para>With this in mind, JBoss Cache 2.0 comes with two cache loader implementations called
+ <literal>org.jboss.cache.loader.TransformingFileCacheLoader</literal>
+ and
+ <literal>org.jboss.cache.loader.TransformingJDBCCacheLoader</literal>
+ located within the optional
+ jbosscache-cacheloader-migration.jar file. These are one-off cache loaders that read data from the
+ cache store in JBoss Cache 1.x.x format and write data to cache stores in JBoss Cache 2.0 format.
+ </para>
+
+ <para>The idea is for users to modify their existing cache configuration file(s) momentarily to use these
+ cache loaders and for them to create a small Java application that creates an instance of this cache,
+ recursively reads the entire cache and writes the data read back into the cache. Once the data is
+ transformed, users can revert back to their original cache configuration file(s). In order to help the users
+ with this task, a cache loader migration example has been constructed which can be located under the
+ <literal>examples/cacheloader-migration</literal>
+ directory within the JBoss Cache distribution. This
+ example, called
+ <literal>examples.TransformStore</literal>
+ , is independent of the actual data stored in
+ the cache as it writes back whatever it was read recursively. It is highly recommended that anyone
+ interested in porting their data run this example first, which contains a
+ <literal>readme.txt</literal>
+ file with detailed information about the example itself, and also use it as base for their own application.
+ </para>
+
+ </section>
+
+ </section>
+
+
+ <section id="cl.pass">
+ <title>Cache Passivation</title>
+
+ <para>A cache loader can be used to enforce node passivation and
+ activation on eviction in a cache.
+ </para>
+
+ <para>
+ <emphasis>Cache Passivation</emphasis>
+ is the process of removing
+ an object from in-memory cache and writing it to a secondary data store
+ (e.g., file system, database) on eviction.
+ <emphasis>Cache
+ Activation
+ </emphasis>
+ is the process of restoring an object from the
+ data store into the in-memory cache when it's needed to be used. In both
+ cases, the configured cache loader will be used to read from the data
+ store and write to the data store.
+ </para>
+
+ <para>When an eviction policy in effect evicts a node
+ from the cache, if passivation is enabled, a notification that the node
+ is being passivated will be emitted to the cache listeners and the
+ node and its children will be stored in the cache loader store. When a
+ user attempts to retrieve a node that was evicted earlier, the node is loaded
+ (lazy loaded) from the cache loader store into memory. When
+ the node and its children have been loaded, they're removed from the
+ cache loader and a notification is emitted to the cache listeners
+ that the node has been activated.
+ </para>
+
+ <para>To enable cache passivation/activation, you can set
+ <literal>passivation</literal>
+ to true. The default is
+ <literal>false</literal>
+ .
+ When passivation is used, only the first cache loader configured is
+ used and all others are ignored.
+ </para>
+ </section>
+
+ <section>
+ <title>Strategies</title>
+ <para>
+ This section discusses different patterns of combining different cache loader types and configuration
+ options to achieve specific outcomes.
+ </para>
+
+ <section>
+ <title>Local Cache With Store</title>
+
+ <para>This is the simplest case. We have a JBoss Cache instance, whose
+ cache mode is
+ <literal>LOCAL</literal>
+ , therefore no replication is going
+ on. The cache loader simply loads non-existing elements from the store
+ and stores modifications back to the store. When the cache is started,
+ depending on the
+ <literal>preload</literal>
+ element, certain data can
+ be preloaded, so that the cache is partly warmed up.
+ </para>
+ </section>
+
+ <section>
+ <title>Replicated Caches With All Caches Sharing The Same Store</title>
+
+ <para>The following figure shows 2 JBoss Cache instances sharing the same
+ backend store:
+ </para>
+
+ <figure>
+ <title>2 nodes sharing a backend store</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="SharedCacheLoader.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Both nodes have a cache loader that accesses a common shared
+ backend store. This could for example be a shared filesystem (using
+ the FileCacheLoader), or a shared database. Because both nodes access
+ the same store, they don't necessarily need state transfer on
+ startup.
+ <footnote>
+ <para>Of course they can enable state transfer, if they want to
+ have a warm or hot cache after startup.
+ </para>
+ </footnote>
+ Rather, the
+ <literal>FetchInMemoryState</literal>
+ attribute could be set to false, resulting in a 'cold' cache, that
+ gradually warms up as elements are accessed and loaded for the first
+ time. This would mean that individual caches in a cluster might have
+ different in-memory state at any given time (largely depending on
+ their preloading and eviction strategies).
+ </para>
+
+ <para>When storing a value, the writer takes care of storing the
+ change in the backend store. For example, if node1 made change C1 and
+ node2 C2, then node1 would tell its cache loader to store C1, and node2
+ would tell its cache loader to store C2.
+ </para>
+ </section>
+
+ <section>
+ <title>Replicated Caches With Only One Cache Having A Store</title>
+
+ <figure>
+ <title>2 nodes but only one accesses the backend store</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="OnlyOneCacheLoader.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>This is a similar case to the previous one, but here only one
+ node in the cluster interacts with a backend store via its
+ cache loader. All other nodes perform in-memory replication. The idea
+ here is all application state is kept in memory in each node, with
+ the existence of multiple caches making the data highly available.
+ (This assumes that a client that needs the data is able to somehow
+ fail over from one cache to another.) The single persistent backend
+ store then provides a backup copy of the data in case all caches in
+ the cluster fail or need to be restarted.
+ </para>
+ <para>
+ Note that here it may make sense for the cache loader to store
+ changes asynchronously, that is <emphasis>not</emphasis>
+ on the caller's thread, in order not to slow
+ down the cluster by accessing (for example) a database. This is a
+ non-issue when using asynchronous replication.
+ </para>
+ <para>
+ A weakness with this architecture is that the cache with access
+ to the cache loader becomes a single point of failure. Furthermore,
+ if the cluster is restarted, the cache with the cache loader must
+ be started first (easy to forget). A solution to the first problem
+ is to configure a cache loader on each node, but set the
+ <literal>singletonStore</literal> configuration to
+ <literal>true</literal>. With this kind of setup, one but only one
+ node will always be writing to a persistent store. However, this
+ complicates the restart problem, as before restarting you need
+ to determine which cache was writing before the shutdown/failure
+ and then start that cache first.
+ </para>
+ </section>
+
+ <section>
+ <title>Replicated Caches With Each Cache Having Its Own Store</title>
+
+ <figure>
+ <title>2 nodes each having its own backend store</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="LocalCacheLoader.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Here, each node has its own datastore. Modifications to the
+ cache are (a) replicated across the cluster and (b) persisted using
+ the cache loader. This means that all datastores have exactly the same
+ state. When replicating changes synchronously and in a transaction,
+ the two phase commit protocol takes care that all modifications are
+ replicated and persisted in each datastore, or none is replicated and
+ persisted (atomic updates).
+ </para>
+
+ <para>Note that JBoss Cache is
+ <emphasis>not</emphasis>
+ an
+ XA Resource, that means it doesn't implement recovery. When used with a
+ transaction manager that supports recovery, this functionality is not
+ available.
+ </para>
+
+ <para>The challenge here is state transfer: when a new node starts it
+ needs to do the following:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>Tell the coordinator (oldest node in a cluster) to send it
+ the state. This is always a full state transfer, overwriting
+ any state that may already be present.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>The coordinator then needs to wait until all in-flight
+ transactions have completed. During this time, it will not allow
+ for new transactions to be started.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Then the coordinator asks its cache loader for the entire
+ state using
+ <literal>loadEntireState()</literal>
+ . It then sends
+ back that state to the new node.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>The new node then tells its cache loader to store that state
+ in its store, overwriting the old state. This is the
+ <literal>CacheLoader.storeEntireState()</literal>
+ method
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>As an option, the transient (in-memory) state can be
+ transferred as well during the state transfer.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>The new node now has the same state in its backend store as
+ everyone else in the cluster, and modifications received from
+ other nodes will now be persisted using the local
+ cache loader.
+ </para>
+ </listitem>
+ </orderedlist>
+
+
+ </section>
+
+ <section>
+ <title>Hierarchical Caches</title>
+
+ <para>If you need to set up a hierarchy within a single JVM, you can
+ use the
+ <literal>LocalDelegatingCacheLoader</literal>
+ . This type of
+ hierarchy can currently only be set up programmatically.
+ </para>
+
+ <para>
+ Hierarchical caches could also be set up spanning more than one JVM or server, using the
+ <literal>TcpDelegatingCacheLoader</literal>
+ .
+ <figure>
+ <title>TCP delegating cache loader</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="DelegatingCacheLoader.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ </para>
+
+ </section>
+
+
+ <section>
+ <title>Multiple Cache Loaders</title>
+
+ <para>
+ You can set up more than one cache loader in a chain. Internally, a delegating
+ <literal>ChainingCacheLoader</literal>
+ is used, with references to each
+ cache loader you have configured. Use cases vary depending on the type of cache loaders used in the chain.
+ One example is
+ using a filesystem based cache loader, colocated on the same host as the JVM, used as an overflow for
+ memory. This ensures
+ data is available relatively easily and with low cost. An additional remote cache loader, such as a
+ <literal>TcpDelegatingCacheLoader</literal>
+ provides resilience between server restarts.
+ </para>
+
+ <figure>
+ <title>Multiple cache loaders in a chain</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="MultipleCacheLoaders.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ </section>
+
+
+ </section>
+
+
+</chapter>
Added: core/trunk/src/main/docbook/userguide/en/modules/compatibility.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/modules/compatibility.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/modules/compatibility.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,37 @@
+<chapter id="compatibility">
+ <title>Version Compatibility and Interoperability</title>
+
+ <para>
+ Within a major version, releases of JBoss Cache are meant to be compatible and
+ interoperable. Compatible in the sense that it should be possible to
+ upgrade an application from one version to another by simply replacing the
+ jars. Interoperable in the sense that if two different versions of
+ JBoss Cache are used in the same cluster, they should be able to exchange
+ replication and state transfer messages. Note however that interoperability
+ requires use of the same JGroups version in all nodes in the cluster.
+ In most cases, the version of JGroups used by a version of JBoss Cache can
+ be upgraded.
+ </para>
+
+ <para>
+ As such, JBoss Cache 2.x.x is not API or binary compatible with prior 1.x.x versions.
+ However, JBoss Cache 2.1.x will be API and binary compatible with 2.0.x.
+ </para>
+
+ <para>
+ A configuration attribute, <literal>ReplicationVersion</literal>, is available and is used
+ to control the wire format of inter-cache communications. They can be wound back from more
+ efficient and newer protocols to "compatible" versions when talking to older releases.
+ This mechanism allows us to improve JBoss Cache by using more efficient wire formats while
+ still providing a means to preserve interoperability.
+ </para>
+
+ <section>
+ <title>Compatibility Matrix</title>
+ <para>
+ A <ulink url="http://labs.jboss.com/portal/jbosscache/compatibility/index.html">compatibility matrix</ulink> is maintained on the JBoss Cache website, which contains information on
+ different versions of JBoss Cache, JGroups and JBoss AS.
+ </para>
+ </section>
+
+</chapter>
\ No newline at end of file
Added: core/trunk/src/main/docbook/userguide/en/modules/configuration.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/modules/configuration.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/modules/configuration.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,447 @@
+<chapter id="configuration">
+ <title>Configuration</title>
+
+ <section>
+ <title>Configuration Overview</title>
+
+ <para>
+ The
+ <literal>org.jboss.cache.config.Configuration</literal>
+ class
+ (along with its
+ <link linkend="configuration.elements">component parts</link>
+ )
+ is a Java Bean that encapsulates the configuration of the
+ <literal>Cache</literal>
+ and all of its architectural elements
+ (cache loaders, evictions policies, etc.)
+ </para>
+
+ <para>
+ The
+ <literal>Configuration</literal>
+ exposes numerous properties which
+ are summarized in the
+ <link linkend="configuration_reference">configuration reference</link>
+ section of this book and many of which are discussed in later
+ chapters. Any time you see a configuration option
+ discussed in this book, you can assume that the
+ <literal>Configuration</literal>
+ class or one of its component parts exposes a simple property setter/getter for that configuration option.
+ </para>
+
+ </section>
+
+ <section id="configuration.creation">
+ <title>Creating a
+ <literal>Configuration</literal>
+ </title>
+
+ <para>
+ As discussed in the
+ <link linkend="api.create_start">User API section</link>
+ ,
+ before a
+ <literal>Cache</literal>
+ can be created, the
+ <literal>CacheFactory</literal>
+ must be provided with a
+ <literal>Configuration</literal>
+ object or with a file name or
+ input stream to use to parse a
+ <literal>Configuration</literal>
+ from XML. The following sections describe how to accomplish this.
+ </para>
+
+ <section>
+ <title>Parsing an XML-based Configuration File</title>
+ <para>
+ The most convenient way to configure JBoss Cache is via an XML file. The JBoss Cache distribution ships
+ with a number of configuration files for common use cases. It is recommended that these files be used as
+ a starting point, and tweaked to meet specific needs.
+ </para>
+
+ <para>
+ Here is a simple example configuration file:
+ </para>
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Sample JBoss Cache Service Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<server>
+
+ <mbean code="org.jboss.cache.jmx.CacheJmxWrapper" name="jboss.cache:service=Cache">
+
+ <!-- Configure the TransactionManager -->
+ <attribute name="TransactionManagerLookupClass">
+ org.jboss.cache.transaction.GenericTransactionManagerLookup
+ </attribute>
+
+ <!-- Node locking level : SERIALIZABLE
+ REPEATABLE_READ (default)
+ READ_COMMITTED
+ READ_UNCOMMITTED
+ NONE -->
+ <attribute name="IsolationLevel">READ_COMMITTED</attribute>
+
+ <!-- Lock parent before doing node additions/removes -->
+ <attribute name="LockParentForChildInsertRemove">true</attribute>
+
+ <!-- Valid modes are LOCAL (default)
+ REPL_ASYNC
+ REPL_SYNC
+ INVALIDATION_ASYNC
+ INVALIDATION_SYNC -->
+ <attribute name="CacheMode">LOCAL</attribute>
+
+ <!-- Max number of milliseconds to wait for a lock acquisition -->
+ <attribute name="LockAcquisitionTimeout">15000</attribute>
+
+
+ <!-- Specific eviction policy configurations. This is LRU -->
+ <attribute name="EvictionConfig">
+ <config>
+ <attribute name="wakeUpIntervalSeconds">5</attribute>
+ <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+
+ <!-- Cache wide default -->
+ <region name="/_default_">
+ <attribute name="maxNodes">5000</attribute>
+ <attribute name="timeToLiveSeconds">1000</attribute>
+ </region>
+ </config>
+ </attribute>
+ </mbean>
+</server>
+]]>
+ </programlisting>
+
+ <para>
+ Another, more complete, sample XML file is included in the
+ <link linkend="sample_xml_file">configuration reference</link>
+ section of this book,
+ along with
+ <link linkend="configuration_reference">a handy look-up table</link>
+ explaining the various options.
+ </para>
+
+ <para>
+ For historical reasons, the format of the JBoss Cache configuraton
+ file follows that of a JBoss AS Service Archive (SAR) deployment
+ descriptor (and still can be used as such
+ <link linkend="deployment.microkernel">inside JBoss AS</link>
+ ). Because
+ of this dual usage, you may see elements in some configuration files
+ (such as
+ <literal>depends</literal>
+ or
+ <literal>classpath</literal>
+ ) that are
+ not relevant outside JBoss AS. These can safely be ignored.
+ </para>
+
+ <para>
+ Here's how you tell the
+ <literal>CacheFactory</literal>
+ to create
+ and start a cache by finding and parsing a configuration file on the
+ classpath:
+ </para>
+
+ <programlisting>
+ CacheFactory factory = DefaultCacheFactory.getInstance();
+ Cache cache = factory.createCache("cache-configuration.xml");
+ </programlisting>
+
+ </section>
+
+ <section>
+ <title>Programmatic Configuration</title>
+ <para>
+ In addition to the XML-based configuration above, the
+ <literal>Configuration</literal>
+ can be built up programatically,
+ using the simple property mutators exposed by
+ <literal>Configuration</literal>
+ and its components. When constructed,
+ the
+ <literal>Configuration</literal>
+ object is preset with JBoss Cache
+ defaults and can even be used as-is for a quick start.
+ </para>
+
+ <para>
+ Following is an example of programatically creating a
+ <literal>Configuration</literal>
+ configured to match the one produced
+ by the XML example above, and then using it to create a
+ <literal>Cache</literal>
+ :
+ </para>
+
+ <programlisting>
+ <![CDATA[
+ Configuration config = new Configuration();
+ String tmlc = GenericTransactionManagerLookup.class.getName();
+ config.setTransactionManagerLookupClass(tmlc);
+ config.setIsolationLevel(IsolationLevel.READ_COMMITTED);
+ config.setCacheMode(CacheMode.LOCAL);
+ config.setLockParentForChildInsertRemove(true);
+ config.setLockAcquisitionTimeout(15000);
+
+ EvictionConfig ec = new EvictionConfig();
+ ec.setWakeupIntervalSeconds(5);
+ ec.setDefaultEvictionPolicyClass(LRUPolicy.class.getName());
+
+ EvictionRegionConfig erc = new EvictionRegionConfig();
+ erc.setRegionName("_default_");
+
+ LRUConfiguration lru = new LRUConfiguration();
+ lru.setMaxNodes(5000);
+ lru.setTimeToLiveSeconds(1000);
+
+ erc.setEvictionPolicyConfig(lru);
+
+ List<EvictionRegionConfig> ercs = new ArrayList<EvictionRegionConfig>();
+ ercs.add(erc);
+ ec.setEvictionRegionConfigs(erc);
+
+ config.setEvictionConfig(ec);
+
+ CacheFactory factory = DefaultCacheFactory.getInstance();
+ Cache cache = factory.createCache(config);
+]]>
+ </programlisting>
+
+ <para>
+ Even the above fairly simple configuration is pretty tedious programming;
+ hence the preferred use of XML-based configuration. However, if your
+ application requires it, there is no reason not to use XML-based
+ configuration for most of the attributes, and then access the
+ <literal>Configuration</literal>
+ object to programatically change
+ a few items from the defaults, add an eviction region, etc.
+ </para>
+
+ <para>
+ Note that configuration values may not be changed programmatically when a cache is running,
+ except those annotated as
+ <literal>@Dynamic</literal>
+ . Dynamic properties are also marked as such in the
+ <link linkend="configuration_reference">configuration reference</link>
+ table. Attempting to change a non-dynamic
+ property will result in a
+ <literal>ConfigurationException</literal>
+ .
+ </para>
+ </section>
+
+ <section>
+ <title>Using an IOC Framework</title>
+
+ <para>
+ The
+ <literal>Configuration</literal>
+ class and its
+ <link linkend="configuration.elements">component parts</link>
+ are all Java Beans that expose all config elements via simple setters
+ and getters. Therefore, any good IOC framework should be able to
+ build up a
+ <literal>Configuration</literal>
+ from an XML file in
+ the framework's own format. See the
+ <link linkend="deployment.microcontainer">deployment via the JBoss micrcontainer</link>
+ section for an example of this.
+ </para>
+ </section>
+ </section>
+
+ <section id="configuration.elements">
+ <title>Composition of a
+ <literal>Configuration</literal>
+ Object
+ </title>
+
+ <para>
+ A
+ <literal>Configuration</literal>
+ is composed of a number of
+ subobjects:
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="Configuration.png"/>
+ </imageobject>
+ </mediaobject>
+ </para>
+
+ <para>
+ Following is a brief overview of the components of a
+ <literal>Configuration</literal>
+ . See the javadoc and the linked
+ chapters in this book for a more complete explanation of the
+ configurations associated with each component.
+
+ <itemizedlist>
+ <listitem>
+ <literal>Configuration</literal>
+ : top level object
+ in the hierarchy; exposes the configuration properties listed in the
+ <link linkend="configuration_reference">configuration reference</link>
+ section of this book.
+ </listitem>
+
+ <listitem>
+ <literal>BuddyReplicationConfig</literal>
+ : only relevant if
+ <link linkend="br">buddy replication</link>
+ is used. General
+ buddy replication configuration options. Must include a:
+ </listitem>
+
+ <listitem>
+ <literal>BuddyLocatorConfig</literal>
+ : implementation-specific
+ configuration object for the
+ <literal>BuddyLocator</literal>
+ implementation
+ being used. What configuration elements are exposed depends on
+ the needs of the
+ <literal>BuddyLocator</literal>
+ implementation.
+ </listitem>
+
+ <listitem>
+ <literal>EvictionConfig</literal>
+ : only relevant if
+ <link linkend="eviction_policies">eviction</link>
+ is used. General
+ eviction configuration options. Must include at least one:
+ </listitem>
+
+ <listitem>
+ <literal>EvictionRegionConfig</literal>
+ : one for each
+ eviction region; names the region, etc. Must include a:
+ </listitem>
+
+ <listitem>
+ <literal>EvictionPolicyConfig</literal>
+ : implementation-specific
+ configuration object for the
+ <literal>EvictionPolicy</literal>
+ implementation
+ being used. What configuration elements are exposed depends on
+ the needs of the
+ <literal>EvictionPolicy</literal>
+ implementation.
+ </listitem>
+
+ <listitem>
+ <literal>CacheLoaderConfig</literal>
+ : only relevant if a
+ <link linkend="cache_loaders">cache loader</link>
+ is used. General
+ cache loader configuration options. Must include at least one:
+ </listitem>
+
+ <listitem>
+ <literal>IndividualCacheLoaderConfig</literal>
+ : implementation-specific
+ configuration object for the
+ <literal>CacheLoader</literal>
+ implementation
+ being used. What configuration elements are exposed depends on
+ the needs of the
+ <literal>CacheLoader</literal>
+ implementation.
+ </listitem>
+
+ <listitem>
+ <literal>RuntimeConfig</literal>
+ : exposes to cache clients
+ certain information about the cache's runtime environment (e.g. membership
+ in buddy replication groups if
+ <link linkend="br">buddy replication</link>
+ is used.) Also allows
+ direct injection into the cache of needed external services like a
+ JTA
+ <literal>TransactionManager</literal>
+ or a JGroups
+ <literal>ChannelFactory</literal>
+ .
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>Dynamic Reconfiguration</title>
+ <para>
+ Dynamically changing the configuration of
+ <emphasis>some</emphasis>
+ options while the cache is running is supported,
+ by programmatically obtaining the
+ <literal>Configuration</literal>
+ object from the running cache and changing values. E.g.,
+ <programlisting>
+
+ Configuration liveConfig = cache.getConfiguration();
+ liveConfig.setLockAcquisitionTimeout(2000);
+
+ </programlisting>
+ A complete listing of which options may be changed dynamically is in the
+ <link linkend="configuration_reference">configuration reference</link>
+ section. An
+ <literal>org.jboss.cache.config.ConfigurationException</literal>
+ will be thrown if you attempt to change a
+ setting that is not dynamic.
+ </para>
+ </section>
+
+ <section id="configuration.options">
+ <title>Overriding the Configuration Via the Option API</title>
+ <para>
+ The Option API allows you to override certain behaviours of the cache on a per invocation basis.
+ This involves creating an instance of
+ <literal>org.jboss.cache.config.Option</literal>
+ , setting the options
+ you wish to override on the
+ <literal>Option</literal>
+ object and passing it in the
+ <literal>InvocationContext</literal>
+ before invoking your method on the cache.
+ </para>
+ <para>
+ E.g., to override the default node versioning used with optimistic locking:
+ <programlisting>
+
+ DataVersion v = new MyCustomDataVersion();
+ cache.getInvocationContext().getOptionOverrides().setDataVersion(v);
+ Node ch = cache.getRoot().addChild(Fqn.fromString("/a/b/c"));
+
+ </programlisting>
+ </para>
+ <para>
+ E.g., to suppress replication of a put call in a REPL_SYNC cache:
+ <programlisting>
+
+ Node node = cache.getChild(Fqn.fromString("/a/b/c"));
+ cache.getInvocationContext().getOptionOverrides().setLocalOnly(true);
+ node.put("localCounter", new Integer(2));
+
+ </programlisting>
+ </para>
+ <para>
+ See the javadocs on the
+ <literal>Option</literal>
+ class for details on the options available.
+ </para>
+ </section>
+</chapter>
Added: core/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,665 @@
+<chapter id="configuration_reference_chapter">
+ <title>Configuration References</title>
+ <section id="sample_xml_file">
+ <title>Sample XML Configuration File</title>
+ <para>
+ This is what a typical XML configuration file looks like. It is recommended that you use one of the
+ configurations
+ shipped with the JBoss Cache distribution and tweak according to your needs rather than write one from scratch.
+ </para>
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Sample JBoss Cache Service Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<server>
+
+ <!-- ==================================================================== -->
+ <!-- Defines JBoss Cache configuration -->
+ <!-- ==================================================================== -->
+
+ <!-- Note the value of the 'code' attribute has changed since JBC 1.x -->
+ <mbean code="org.jboss.cache.jmx.CacheJmxWrapper" name="jboss.cache:service=Cache">
+
+ <!-- Ensure JNDI and the TransactionManager are started before the
+ cache. Only works inside JBoss AS; ignored otherwise -->
+ <depends>jboss:service=Naming</depends>
+ <depends>jboss:service=TransactionManager</depends>
+
+ <!-- Configure the TransactionManager -->
+ <attribute name="TransactionManagerLookupClass">
+ org.jboss.cache.transaction.GenericTransactionManagerLookup
+ </attribute>
+
+ <!-- Node locking level : SERIALIZABLE
+ REPEATABLE_READ (default)
+ READ_COMMITTED
+ READ_UNCOMMITTED
+ NONE -->
+ <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
+
+ <!-- Lock parent before doing node additions/removes -->
+ <attribute name="LockParentForChildInsertRemove">true</attribute>
+
+ <!-- Valid modes are LOCAL (default)
+ REPL_ASYNC
+ REPL_SYNC
+ INVALIDATION_ASYNC
+ INVALIDATION_SYNC -->
+ <attribute name="CacheMode">REPL_ASYNC</attribute>
+
+ <!-- Name of cluster. Needs to be the same for all JBoss Cache nodes in a
+ cluster in order to find each other.
+ -->
+ <attribute name="ClusterName">JBossCache-Cluster</attribute>
+
+ <!--Uncomment next three statements to use the JGroups multiplexer.
+ This configuration is dependent on the JGroups multiplexer being
+ registered in an MBean server such as JBossAS. This type of
+ dependency injection only works in the AS; outside it's up to
+ your code to inject a ChannelFactory if you want to use one.
+ -->
+ <!--
+ <depends optional-attribute-name="MultiplexerService"
+ proxy-type="attribute">jgroups.mux:name=Multiplexer</depends>
+ <attribute name="MultiplexerStack">tcp</attribute>
+ -->
+
+ <!-- JGroups protocol stack properties.
+ ClusterConfig isn't used if the multiplexer is enabled above.
+ -->
+ <attribute name="ClusterConfig">
+ <config>
+ <!-- UDP: if you have a multihomed machine, set the bind_addr
+ attribute to the appropriate NIC IP address -->
+ <!-- UDP: On Windows machines, because of the media sense feature
+ being broken with multicast (even after disabling media sense)
+ set the loopback attribute to true -->
+ <UDP mcast_addr="228.1.2.3" mcast_port="48866"
+ ip_ttl="64" ip_mcast="true"
+ mcast_send_buf_size="150000" mcast_recv_buf_size="80000"
+ ucast_send_buf_size="150000" ucast_recv_buf_size="80000"
+ loopback="false"/>
+ <PING timeout="2000" num_initial_members="3"/>
+ <MERGE2 min_interval="10000" max_interval="20000"/>
+ <FD shun="true"/>
+ <FD_SOCK/>
+ <VERIFY_SUSPECT timeout="1500"/>
+ <pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
+ max_xmit_size="8192"/>
+ <UNICAST timeout="600,1200,2400",4800/>
+ <pbcast.STABLE desired_avg_gossip="400000"/>
+ <FC max_credits="2000000" min_threshold="0.10"/>
+ <FRAG2 frag_size="8192"/>
+ <pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
+ shun="true" print_local_addr="true"/>
+ <pbcast.STATE_TRANSFER/>
+ </config>
+ </attribute>
+
+ <!--
+ The max amount of time (in milliseconds) we wait until the
+ initial state (ie. the contents of the cache) are retrieved from
+ existing members in a clustered environment
+ -->
+ <attribute name="StateRetrievalTimeout">20000</attribute>
+
+ <!--
+ Number of milliseconds to wait until all responses for a
+ synchronous call have been received.
+ -->
+ <attribute name="SyncReplTimeout">20000</attribute>
+
+ <!-- Max number of milliseconds to wait for a lock acquisition -->
+ <attribute name="LockAcquisitionTimeout">15000</attribute>
+
+
+ <!-- Specific eviction policy configurations. This is LRU -->
+ <attribute name="EvictionConfig">
+ <config>
+ <attribute name="wakeUpIntervalSeconds">5</attribute>
+ <!-- This defaults to 200000 if not specified -->
+ <attribute name="eventQueueSize">200000</attribute>
+ <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+
+ <!-- Cache wide default -->
+ <region name="/_default_">
+ <attribute name="maxNodes">5000</attribute>
+ <attribute name="timeToLiveSeconds">1000</attribute>
+ </region>
+ <region name="/org/jboss/data">
+ <attribute name="maxNodes">5000</attribute>
+ <attribute name="timeToLiveSeconds">1000</attribute>
+ </region>
+ <region name="/org/jboss/test/data">
+ <attribute name="maxNodes">5</attribute>
+ <attribute name="timeToLiveSeconds">4</attribute>
+ </region>
+ <region name="/test">
+ <attribute name="maxNodes">10000</attribute>
+ <attribute name="timeToLiveSeconds">4</attribute>
+ </region>
+ <region name="/maxAgeTest">
+ <attribute name="maxNodes">10000</attribute>
+ <attribute name="timeToLiveSeconds">8</attribute>
+ <attribute name="maxAgeSeconds">10</attribute>
+ </region>
+ </config>
+ </attribute>
+ </mbean>
+</server>
+]]>
+ </programlisting>
+ </section>
+
+
+ <section id="configuration_reference">
+ <title>
+ Reference table of XML attributes
+ </title>
+ <para>A list of definitions of each of the XML attributes used above. If the
+ description of an attribute states that it is
+ <emphasis>dynamic</emphasis>
+ ,
+ that means it can be changed after the cache is created and started.
+ </para>
+
+ <informaltable frame="all">
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>
+ <para>Name</para>
+ </entry>
+
+ <entry>
+ <para>Description</para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <para>BuddyReplicationConfig</para>
+ </entry>
+
+ <entry>
+ <para>An XML element that contains detailed buddy replication
+ configuration. See
+ <link linkend="br">section on Buddy Replication</link>
+ for details.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>CacheLoaderConfig</para>
+ </entry>
+
+ <entry>
+ <para>An XML element that contains detailed cache loader
+ configuration. See
+ <link linkend="cache_loaders">chapter on Cache Loaders</link>
+ for details.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>CacheLoaderConfiguration</para>
+ </entry>
+
+ <entry>
+ <para>
+ <emphasis>Deprecated</emphasis>
+ . Use
+ <literal>CacheLoaderConfig</literal>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>CacheMode</para>
+ </entry>
+
+ <entry>
+ <para>LOCAL, REPL_SYNC, REPL_ASYNC, INVALIDATION_SYNC or
+ INVALIDATION_ASYNC. Defaults to LOCAL. See the
+ <link linkend="clustering">chapter on Clustering</link>
+ for details.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>ClusterConfig</para>
+ </entry>
+
+ <entry>
+ <para>The configuration of the underlying JGroups stack.
+ Ignored if
+ <literal>MultiplexerService</literal>
+ and
+ <literal>MultiplexerStack</literal>
+ are used.
+ See the various *-service.xml files in the source distribution
+ <literal>etc/META-INF</literal>
+ folder for examples.
+ See the
+ <ulink url="http://www.jgroups.org">JGroups documentation</ulink>
+ or the
+ <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JGroups">JGroups wiki page</ulink>
+ for more information.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>ClusterName</para>
+ </entry>
+
+ <entry>
+ <para>Name of cluster. Needs to be the same for all nodes in a
+ cluster in order for them to communicate with each other.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <para>EvictionPolicyConfig</para>
+ </entry>
+
+ <entry>
+ <para>Configuration parameter for the specified eviction policy.
+ See
+ <link linkend="eviction_policies">chapter on eviction policies</link>
+ for details. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>ExposeManagementStatistics</para>
+ </entry>
+
+ <entry>
+ <para>
+ Specifies whether interceptors that provide statistics should have statistics
+ gathering enabled at startup. Also controls whether a
+ <literal>CacheMgmtInterceptor</literal>
+ (whose sole purpose is gathering
+ statistics) should be added to the interceptor chain. Default value is
+ <emphasis>true</emphasis>
+ . See the
+ <link linkend="jmx.statistics">JBoss Cache Statistics section</link>
+ section for more details.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>FetchInMemoryState
+ </para>
+ </entry>
+
+ <entry>
+ <para>Whether or not to acquire the initial in-memory state from
+ existing members. Allows for hot caches when enabled. Also
+ see the
+ <literal>fetchPersistentState</literal>
+ element in
+ <literal>CacheLoaderConfig</literal>
+ . Defaults to
+ <literal>true</literal>
+ . This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>InactiveOnStartup</para>
+ </entry>
+
+ <entry>
+ <para>Whether or not the entire tree is inactive upon startup,
+ only responding to replication messages after
+ <literal>activateRegion()</literal>
+ is called to activate one or
+ more parts of the tree. If true, property
+ <literal>FetchInMemoryState</literal>
+ is ignored. This property
+ should only be set to true if
+ <literal>UseRegionBasedMarshalling</literal>
+ is also
+ <literal>true</literal>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>StateRetrievalTimeout</para>
+ </entry>
+
+ <entry>
+ <para>Time in milliseconds to wait for state
+ retrieval. This should be longer than
+ <literal>LockAcquisitionTimeout</literal>
+ as the node
+ providing state may need to wait that long to acquire
+ necessary read locks on the cache. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+
+ <row>
+ <entry>
+ <para>IsolationLevel</para>
+ </entry>
+
+ <entry>
+ <para>Node locking isolation level : SERIALIZABLE, REPEATABLE_READ
+ (default), READ_COMMITTED, READ_UNCOMMITTED, and NONE. Note that this is ignored if
+ NodeLockingScheme is OPTIMISTIC. Case doesn't matter. See documentation on Transactions and
+ Concurrency for more details.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>LockAcquisitionTimeout</para>
+ </entry>
+
+ <entry>
+ <para>Time in milliseconds to wait for a lock to be acquired. If
+ a lock cannot be acquired an exception will be thrown. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>LockParentForChildInsertRemove</para>
+ </entry>
+
+ <entry>
+ <para>Controls whether inserting or removing a node requires a write
+ lock on the node's parent (when pessimistic locking is used) or whether
+ it results in an update of the parent node's version (when optimistic
+ locking is used). The default value is
+ <code>false</code>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>MarshallerClass</para>
+ </entry>
+
+ <entry>
+ <para>An instance of
+ <literal>org.jboss.cache.marshall.Marshaller</literal>
+ used to serialize data to byte streams.
+ Defaults to
+ <literal>org.jboss.cache.marshall.VersionAwareMarshaller</literal>
+ if not specified.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>MultiplexerService</para>
+ </entry>
+
+ <entry>
+ <para>The JMX object name of the service that defines the JGroups multiplexer.
+ In JBoss AS 5.0 this service is normally defined in the jgroups-multiplexer.sar.
+ This XML attribute can only be handled by the JBoss AS MBean deployment services;
+ if it is included in a file passed to a
+ <literal>CacheFactory</literal>
+ the
+ factory's creation of the cache will fail. Inside JBoss AS, the attribute should
+ be specified using the "depends optional-attribute-name" syntax shown in
+ the example above. Inside the AS if this attribute
+ is defined, an instance of
+ <literal>org.jgroups.jmx.JChannelFactoryMBean</literal>
+ will be injected into the
+ <literal>CacheJmxWrapper</literal>
+ which will use
+ it to obtain a multiplexed JGroups channel. The configuration
+ of the channel will be that associated with
+ <literal>MultiplexerStack</literal>
+ .
+ The
+ <literal>ClusterConfig</literal>
+ attribute will be ignored.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>MultiplexerStack</para>
+ </entry>
+
+ <entry>
+ <para>The name of the JGroups stack to be used with the cache cluster.
+ Stacks are defined in the configuration of the external
+ <literal>MultiplexerService</literal>
+ discussed above. In JBoss AS 5 this is normally done in the
+ jgroups-multiplexer.sar/META-INF/multiplexer-stacks.xml file.
+ The default stack is
+ <literal>udp</literal>
+ . This attribute is used in conjunction with
+ <literal>MultiplexerService</literal>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>NodeLockingScheme</para>
+ </entry>
+
+ <entry>
+ <para>May be PESSIMISTIC (default) or OPTIMISTIC.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>ReplicationVersion</para>
+ </entry>
+ <entry>
+ <para>Tells the cache to serialize cluster traffic
+ in a format consistent with that used by the given release
+ of JBoss Cache. Different JBoss Cache versions use different
+ wire formats; setting this attribute tells a cache from a later
+ release to serialize data using the format from an earlier
+ release. This allows caches from different releases to
+ interoperate. For example, a 2.1.0 cache could have this
+ value set to "2.0.0", allowing it to interoperate with a 2.0.0
+ cache. Valid values are a dot-separated release number, with
+ any final qualifer also separated by a dot, e.g. "2.0.0" or "2.0.0.GA".
+ Values that indicate a 1.x release are not supported in the 2.x series.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>ReplQueueInterval</para>
+ </entry>
+
+ <entry>
+ <para>Time in milliseconds for elements from the replication
+ queue to be replicated. Only used if
+ <literal>UseReplQueue</literal>
+ is enabled. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>ReplQueueMaxElements</para>
+ </entry>
+
+ <entry>
+ <para>Max number of elements in the replication queue until
+ replication kicks in. Only used if
+ <literal>UseReplQueue</literal>
+ is enabled. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>SyncCommitPhase</para>
+ </entry>
+
+ <entry>
+ <para>This option is used to control the behaviour of the commit part of a 2-phase commit protocol,
+ when
+ using REPL_SYNC (does not apply to other cache modes). By default this is set to
+ <literal>false</literal>
+ . There is a performance penalty to enabling this, especially when running
+ in a large cluster, but the upsides are greater cluster-wide data integrity. See the chapter on
+ clustered caches for more information on this. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>SyncReplTimeout</para>
+ </entry>
+
+ <entry>
+ <para>For synchronous replication: time in milliseconds to wait
+ until replication acks have been received from all nodes in the
+ cluster. It is usually best that this is greater than
+ <literal>LockAcquisitionTimeout</literal>
+ .
+ This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>SyncRollbackPhase</para>
+ </entry>
+
+ <entry>
+ <para>This option is used to control the behaviour of the rollback part of a 2-phase commit
+ protocol, when
+ using REPL_SYNC (does not apply to other cache modes). By default this is set to
+ <literal>false</literal>
+ . There is a performance penalty to enabling this, especially when running
+ in a large cluster, but the upsides are greater cluster-wide data integrity. See the chapter on
+ clustered caches for more information on this. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>TransactionManagerLookupClass</para>
+ </entry>
+
+ <entry>
+ <para>The fully qualified name of a class implementing
+ TransactionManagerLookup. Default is
+ JBossTransactionManagerLookup. There is also an option of
+ GenericTransactionManagerLookup for example.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>UseInterceptorMbeans</para>
+ </entry>
+
+ <entry>
+ <para>
+ <emphasis>Deprecated</emphasis>
+ . Use
+ <literal>ExposeManagementStatistics</literal>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>UseRegionBasedMarshalling</para>
+ </entry>
+
+ <entry>
+ <para>When unmarshalling replicated data, this option specifies whether or not to
+ support use of different classloaders for different cache regions. This defaults to
+ <literal>false</literal>
+ if unspecified.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>UseReplQueue</para>
+ </entry>
+
+ <entry>
+ <para>For asynchronous replication: whether or not to use a
+ replication queue. Defaults to
+ <literal>false</literal>
+ .
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </section>
+</chapter>
\ No newline at end of file
Added: core/trunk/src/main/docbook/userguide/en/modules/deployment.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/modules/deployment.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/modules/deployment.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,901 @@
+<chapter id="deployment">
+ <title>Deploying JBoss Cache</title>
+ <section id="deployment.standalone">
+ <title>Standalone Use / Programatic Deployment</title>
+ <para>
+ When used in a standalone Java program, all that needs to be done is to instantiate the cache using the
+ <literal>CacheFactory</literal>
+ and a
+ <literal>Configuration</literal>
+ instance or an XML file, as discussed
+ in the
+ <link linkend="api.create_start">User API</link>
+ and
+ <link linkend="configuration.creation">Configuration</link>
+ chapters.
+ </para>
+
+ <para>
+ The same techniques can be used when an application running in an application
+ server wishes to programatically deploy a cache rather than relying on an application server's
+ deployment features. An example of this would be
+ a webapp deploying a cache via a
+ <literal>javax.servlet.ServletContextListener</literal>
+ .
+ </para>
+
+ <para>
+ If, after deploying your cache you wish to expose a management interface
+ to it in JMX, see the
+ <link linkend="jmx.registration.programatic">section on Programatic Registration in JMX</link>
+ .
+ </para>
+ </section>
+
+ <section id="deployment.microkernel">
+ <title>JMX-Based Deployment in JBoss AS (JBoss AS 5.x and 4.x)</title>
+ <para>If JBoss Cache is run in JBoss AS then the cache can be deployed as an
+ MBean simply by copying a standard cache configuration file to the server's
+ <literal>deploy</literal>
+ directory. The standard format of JBoss Cache's
+ standard XML configuration file (as shown in the
+ <link linkend="sample_xml_file">Configuration Reference</link>
+ ) is the same
+ as a JBoss AS MBean deployment descriptor, so the AS's SAR Deployer has
+ no trouble handling it. Also, you don't have to place the configuration
+ file directly in
+ <literal>deploy</literal>
+ ; you can package it along
+ with other services or JEE components in a SAR or EAR.
+ </para>
+
+ <para>
+ In AS 5, if you're using a server config based on the standard
+ <literal>all</literal>
+ config, then that's all you need to do; all required
+ jars will be on the classpath. Otherwise, you will need to ensure
+ <literal>jbosscache.jar</literal>
+ and
+ <literal>jgroups-all.jar</literal>
+ are on the classpath. You may need to add other jars if you're using
+ things like
+ <literal>JdbmCacheLoader</literal>
+ . The simplest way to do
+ this is to copy the jars from the JBoss Cache distribution's
+ <literal>lib</literal>
+ directory to the server config's
+ <literal>lib</literal>
+ directory. You could also package the jars with the configuration file
+ in Service Archive (.sar) file or an EAR.
+ </para>
+
+ <para>
+ It is possible to deploy a JBoss Cache 2.0 instance in JBoss AS 4.x
+ (at least in 4.2.0.GA; other AS releases are completely untested).
+ However, the significant API changes between the JBoss Cache 2.x and 1.x releases
+ mean none of the standard AS 4.x clustering services (e.g.
+ http session replication) that rely on JBoss Cache will work with
+ JBoss Cache 2.x. Also, be aware that usage of JBoss Cache 2.x in AS 4.x is not
+ something the JBoss Cache developers are making any significant effort to test,
+ so be sure to test your application well (which of course you're doing anyway.)
+ </para>
+
+ <para>
+ Note in the
+ <link linkend="sample_xml_file">example</link>
+ the value of the
+ <literal>mbean</literal>
+ element's
+ <literal>code</literal>
+ attribute:
+ <literal>org.jboss.cache.jmx.CacheJmxWrapper</literal>
+ . This is the
+ class JBoss Cache uses to handle JMX integration; the
+ <literal>Cache</literal>
+ itself does not expose an MBean
+ interface. See the
+ <link linkend="jmx.mbeans">JBoss Cache MBeans section</link>
+ for more on the
+ <literal>CacheJmxWrapper</literal>
+ .
+ </para>
+
+ <para>
+ Once your cache is deployed, in order to use it with an in-VM client
+ such as a servlet, a JMX proxy can be used to get a reference to
+ the cache:
+ </para>
+
+ <programlisting>
+ <![CDATA[
+ MBeanServer server = MBeanServerLocator.locateJBoss();
+ ObjectName on = new ObjectName("jboss.cache:service=Cache");
+ CacheJmxWrapperMBean cacheWrapper =
+ (CacheJmxWrapperMBean) MBeanServerInvocationHandler.newProxyInstance(server, on,
+ CacheJmxWrapperMBean.class, false);
+ Cache cache = cacheWrapper.getCache();
+ Node root = cache.getRoot(); // etc etc
+ ]]>
+ </programlisting>
+
+ <para>The MBeanServerLocator class is a helper to find the (only) JBoss
+ MBean server inside the current JVM. The
+ <literal>javax.management.MBeanServerInvocationHandler</literal>
+ class'
+ <literal>newProxyInstance</literal>
+ method creates a
+ dynamic proxy implementing the given interface and uses JMX to
+ dynamically dispatch methods invoked against the generated interface
+ to the MBean. The name used to look up the MBean is the same as defined
+ in the cache's configuration file.
+ </para>
+
+ <para>
+ Once the proxy to the
+ <literal>CacheJmxWrapper</literal>
+ is obtained,
+ the
+ <literal>getCache()</literal>
+ will return a reference to the
+ <literal>Cache</literal>
+ itself.
+ </para>
+
+ </section>
+
+ <section id="deployment.microcontainer">
+ <title>Via JBoss Microcontainer (JBoss AS 5.x)</title>
+
+ <para>
+ Beginning with AS 5, JBoss AS also supports deployment of POJO services via
+ deployment of a file whose name ends with
+ <literal>-beans.xml</literal>
+ .
+ A POJO service is one whose implementation is via a "Plain Old Java Object",
+ meaning a simple java bean that isn't required to implement any special
+ interfaces or extend any particular superclass. A
+ <literal>Cache</literal>
+ is a POJO service, and all the components in a
+ <literal>Configuration</literal>
+ are also POJOS, so deploying a cache in this way is a natural step.
+ </para>
+ <para>
+ Deployment of the cache is done using the JBoss Microcontainer that forms the
+ core of JBoss AS. JBoss Microcontainer is a sophisticated IOC framework
+ (similar to Spring). A
+ <literal>-beans.xml</literal>
+ file is basically
+ a descriptor that tells the IOC framework how to assemble the various
+ beans that make up a POJO service.
+ </para>
+ <para>
+ The rules for how to deploy the file, how to package it, how to
+ ensure the required jars are on the classpath, etc. are the same
+ as for a
+ <link linkend="deployment.microkernel">JMX-based deployment</link>
+ .
+ </para>
+
+ <para>
+ Following is an example
+ <literal>-beans.xml</literal>
+ file. If you
+ look in the
+ <literal>server/all/deploy</literal>
+ directory of an AS 5
+ installation, you can find several more examples.
+ </para>
+
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <!-- First we create a Configuration object for the cache -->
+ <bean name="ExampleCacheConfig"
+ class="org.jboss.cache.config.Configuration">
+
+ <!-- Externally injected services -->
+ <property name="runtimeConfig">
+ <bean name="ExampleCacheRuntimeConfig" class="org.jboss.cache.config.RuntimeConfig">
+ <property name="transactionManager">
+ <inject bean="jboss:service=TransactionManager"
+ property="TransactionManager"/>
+ </property>
+ <property name="muxChannelFactory"><inject bean="JChannelFactory"/></property>
+ </bean>
+ </property>
+
+ <property name="multiplexerStack">udp</property>
+
+ <property name="clusterName">Example-EntityCache</property>
+
+ <!--
+ Node locking level : SERIALIZABLE
+ REPEATABLE_READ (default)
+ READ_COMMITTED
+ READ_UNCOMMITTED
+ NONE
+ -->
+ <property name="isolationLevel">REPEATABLE_READ</property>
+
+ <!-- Valid modes are LOCAL
+ REPL_ASYNC
+ REPL_SYNC
+ -->
+ <property name="cacheMode">REPL_SYNC</property>
+
+ <!-- The max amount of time (in milliseconds) we wait until the
+ initial state (ie. the contents of the cache) are retrieved from
+ existing members in a clustered environment
+ -->
+ <property name="initialStateRetrievalTimeout">15000</property>
+
+ <!-- Number of milliseconds to wait until all responses for a
+ synchronous call have been received.
+ -->
+ <property name="syncReplTimeout">20000</property>
+
+ <!-- Max number of milliseconds to wait for a lock acquisition -->
+ <property name="lockAcquisitionTimeout">15000</property>
+
+ <property name="exposeManagementStatistics">true</property>
+
+ <!-- Must be true if any entity deployment uses a scoped classloader -->
+ <property name="useRegionBasedMarshalling">true</property>
+ <!-- Must match the value of "useRegionBasedMarshalling" -->
+ <property name="inactiveOnStartup">true</property>
+
+ <!-- Specific eviction policy configurations. This is LRU -->
+ <property name="evictionConfig">
+ <bean name="ExampleEvictionConfig"
+ class="org.jboss.cache.config.EvictionConfig">
+ <property name="defaultEvictionPolicyClass">
+ org.jboss.cache.eviction.LRUPolicy
+ </property>
+ <property name="wakeupIntervalSeconds">5</property>
+ <property name="evictionRegionConfigs">
+ <list>
+ <bean name="ExampleDefaultEvictionRegionConfig"
+ class="org.jboss.cache.config.EvictionRegionConfig">
+ <property name="regionName">/_default_</property>
+ <property name="evictionPolicyConfig">
+ <bean name="ExampleDefaultLRUConfig"
+ class="org.jboss.cache.eviction.LRUConfiguration">
+ <property name="maxNodes">5000</property>
+ <property name="timeToLiveSeconds">1000</property>
+ </bean>
+ </property>
+ </bean>
+ </list>
+ </property>
+ </bean>
+ </property>
+
+ </bean>
+
+ <!-- Factory to build the Cache. -->
+ <bean name="DefaultCacheFactory" class="org.jboss.cache.DefaultCacheFactory">
+ <constructor factoryClass="org.jboss.cache.DefaultCacheFactory"
+ factoryMethod="getInstance"/>
+ </bean>
+
+ <!-- The cache itself -->
+ <bean name="ExampleCache" class="org.jboss.cache.CacheImpl">
+
+ <constructor factoryMethod="createCache">
+ <factory bean="DefaultCacheFactory"/>
+ <parameter><inject bean="ExampleCacheConfig"/></parameter>
+ <parameter>false</false>
+ </constructor>
+
+ </bean>
+
+</deployment>
+]]>
+ </programlisting>
+
+ <para>
+ See the JBoss Microcontainer documentation
+ <footnote>
+ <para>http://labs.jboss.com/jbossmc/docs</para>
+ </footnote>
+ for details on the above syntax. Basically, each
+ <literal>bean</literal>
+ element represents an object; most going to create a
+ <literal>Configuration</literal>
+ and its
+ <link linkend="configuration.elements">constituent parts</link>
+ .
+ </para>
+ <para>
+ An interesting thing to note in the above example is the use of the
+ <literal>RuntimeConfig</literal>
+ object. External resources like
+ a
+ <literal>TransactionManager</literal>
+ and a JGroups
+ <literal>ChannelFactory</literal>
+ that are visible to the
+ microcontainer are dependency injected into the
+ <literal>RuntimeConfig</literal>
+ .
+ The assumption here is that in some other deployment descriptor in the AS,
+ the referenced beans have been described.
+ </para>
+ </section>
+
+ <section>
+ <title>Binding to JNDI in JBoss AS</title>
+ <para>
+ With the 1.x JBoss Cache releases, a proxy to the cache could be bound
+ into JBoss AS's JNDI tree using the AS's
+ <literal>JRMPProxyFactory</literal>
+ service. With JBoss Cache 2.x, this no longer works. An alternative
+ way of doing a similar thing with a POJO (i.e. non-JMX-based) service
+ like a
+ <literal>Cache</literal>
+ is under development by the JBoss AS
+ team
+ <footnote>
+ <para>http://jira.jboss.com/jira/browse/JBAS-4456</para>
+ </footnote>
+ . That feature is not available as of the time of this writing,
+ although it will be completed before AS 5.0.0.GA is released.
+ We will add a wiki page describing how to use it once it becomes available.
+ </para>
+ </section>
+
+ <section>
+ <title>Runtime Management Information</title>
+ <para>JBoss Cache includes JMX MBeans to expose cache functionality and provide statistics that can be
+ used to analyze cache operations. JBoss Cache can also broadcast cache events as MBean notifications for
+ handling
+ via JMX monitoring tools.
+ </para>
+
+ <section id="jmx.mbeans">
+ <title>JBoss Cache MBeans</title>
+ <para>
+ JBoss Cache provides an MBean that can be registered with your environments JMX server to allow access
+ to the cache instance via JMX. This MBean is the
+ <literal>org.jboss.cache.jmx.CacheJmxWrapper</literal>
+ .
+ It is a StandardMBean, so it's MBean interface is
+ <literal>org.jboss.cache.jmx.CacheJmxWrapperMBean</literal>
+ .
+ This MBean can be used to:
+ <itemizedlist>
+ <listitem>Get a reference to the underlying
+ <literal>Cache</literal>
+ .
+ </listitem>
+ <listitem>Invoke create/start/stop/destroy lifecycle operations on
+ the underlying
+ <literal>Cache</literal>
+ .
+ </listitem>
+ <listitem>Inspect various details about the cache's current state (number of nodes, lock information,
+ etc.)
+ </listitem>
+ <listitem>See numerous details about the cache's configuration, and
+ change those configuration items that can be changed when the
+ cache has already been started.
+ </listitem>
+ </itemizedlist>
+ See the
+ <literal>CacheJmxWrapperMBean</literal>
+ javadoc for more details.
+ </para>
+ <para>
+ It is important to note a significant architectural difference between JBoss Cache 1.x and 2.x. In 1.x,
+ the old
+ <literal>TreeCache</literal>
+ class was itself an MBean, and essentially exposed the cache's entire
+ API via JMX. In 2.x, JMX has been returned to it's fundamental role as a management layer. The
+ <literal>Cache</literal>
+ object itself is completely unaware of JMX; instead JMX functionality is added
+ through a wrapper class designed for that purpose. Furthermore, the interface exposed through JMX
+ has been limited to management functions; the general
+ <literal>Cache</literal>
+ API is no longer exposed
+ through JMX. For example, it is no longer possible to invoke a cache
+ <literal>put</literal>
+ or
+ <literal>get</literal>
+ via the JMX interface.
+ </para>
+ <para>
+ If a
+ <literal>CacheJmxWrapper</literal>
+ is registered, JBoss Cache also provides MBeans
+ for each interceptor configured in the cache's interceptor stack. These
+ MBeans are used to capture and expose statistics related to cache operations. They are hierarchically
+ associated with the
+ <literal>CacheJmxWrapper</literal>
+ MBean and have service names that reflect this relationship. For
+ example, a replication interceptor MBean for the
+ <literal>jboss.cache:service=TomcatClusteringCache</literal>
+ instance will be
+ accessible through the service named
+ <literal>jboss.cache:service=TomcatClusteringCache,cache-interceptor=ReplicationInterceptor</literal>
+ .
+ </para>
+ </section>
+
+ <section id="jmx.registration">
+ <title>Registering the CacheJmxWrapper with the MBeanServer</title>
+
+ <para>
+ The best way to ensure the
+ <literal>CacheJmxWrapper</literal>
+ is registered
+ in JMX depends on how you are deploying your cache:
+ </para>
+
+ <section id="jmx.registration.programatic">
+ <title>Programatic Registration</title>
+
+ <para>
+ Simplest way to do this is to create your
+ <literal>Cache</literal>
+ and pass it to the
+ <literal>CacheJmxWrapper</literal>
+ constructor.
+ </para>
+
+ <programlisting>
+ CacheFactory factory = DefaultCacheFactory.getInstance();
+ // Build but don't start the cache
+ // (although it would work OK if we started it)
+ Cache cache = factory.createCache("cache-configuration.xml", false);
+
+ CacheJmxWrapperMBean wrapper = new CacheJmxWrapper(cache);
+ MBeanServer server = getMBeanServer(); // however you do it
+ ObjectName on = new ObjectName("jboss.cache:service=TreeCache");
+ server.registerMBean(wrapper, on);
+
+ // Invoking lifecycle methods on the wrapper results
+ // in a call through to the cache
+ wrapper.create();
+ wrapper.start();
+
+ ... use the cache
+
+ ... on application shutdown
+
+ // Invoking lifecycle methods on the wrapper results
+ // in a call through to the cache
+ wrapper.stop();
+ wrapper.destroy();
+ </programlisting>
+
+ <para>
+ Alternatively, build a
+ <literal>Configuration</literal>
+ object
+ and pass it to the
+ <literal>CacheJmxWrapper</literal>
+ . The wrapper
+ will construct the
+ <literal>Cache</literal>
+ :
+ </para>
+
+ <programlisting>
+ Configuration config = buildConfiguration(); // whatever it does
+
+ CacheJmxWrapperMBean wrapper = new CacheJmxWrapper(config);
+ MBeanServer server = getMBeanServer(); // however you do it
+ ObjectName on = new ObjectName("jboss.cache:service=TreeCache");
+ server.registerMBean(wrapper, on);
+
+ // Call to wrapper.create() will build the Cache if one wasn't injected
+ wrapper.create();
+ wrapper.start();
+
+ // Now that it's built, created and started, get the cache from the wrapper
+ Cache cache = wrapper.getCache();
+
+ ... use the cache
+
+ ... on application shutdown
+
+ wrapper.stop();
+ wrapper.destroy();
+
+ </programlisting>
+ </section>
+
+ <section>
+ <title>JMX-Based Deployment in JBoss AS (JBoss AS 4.x and 5.x)</title>
+
+ <para>
+ When you
+ <link linkend="deployment.microkernel">deploy your cache in JBoss AS using a -service.xml file</link>
+ ,
+ a
+ <literal>CacheJmxWrapper</literal>
+ is automatically registered. There is no need
+ to do anything further. The
+ <literal>CacheJmxWrapper</literal>
+ is accessible from an MBean server
+ through the service name specified in the cache configuration file's
+ <literal>mbean</literal>
+ element.
+ </para>
+ </section>
+
+ <section>
+ <title>Via JBoss Microcontainer (JBoss AS 5.x)</title>
+
+ <para>
+ <literal>CacheJmxWrapper</literal>
+ is a POJO, so the microcontainer
+ has no problem creating one. The trick is
+ getting it to register your bean in JMX. This can be done by
+ specifying the
+ <literal>org.jboss.aop.microcontainer.aspects.jmx.JMX</literal>
+ annotation on the
+ <literal>CacheJmxWrapper</literal>
+ bean:
+ </para>
+
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <!-- First we create a Configuration object for the cache -->
+ <bean name="ExampleCacheConfig"
+ class="org.jboss.cache.config.Configuration">
+
+ ... build up the Configuration
+
+ </bean>
+
+ <!-- Factory to build the Cache. -->
+ <bean name="DefaultCacheFactory" class="org.jboss.cache.DefaultCacheFactory">
+ <constructor factoryClass="org.jboss.cache.DefaultCacheFactory"
+ factoryMethod="getInstance"/>
+ </bean>
+
+ <!-- The cache itself -->
+ <bean name="ExampleCache" class="org.jboss.cache.CacheImpl">
+
+ <constructor factoryMethod="createnewInstance">
+ <factory bean="DefaultCacheFactory"/>
+ <parameter><inject bean="ExampleCacheConfig"/></parameter>
+ <parameter>false</false>
+ </constructor>
+
+ </bean>
+
+ <!-- JMX Management -->
+ <bean name="ExampleCacheJmxWrapper" class="org.jboss.cache.jmx.CacheJmxWrapper">
+
+ <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.cache:service=ExampleTreeCache",
+ exposedInterface=org.jboss.cache.jmx.CacheJmxWrapperMBean.class,
+ registerDirectly=true)</annotation>
+
+ <constructor>
+ <parameter><inject bean="ExampleCache"/></parameter>
+ </constructor>
+
+ </bean>
+
+</deployment>
+]]>
+ </programlisting>
+
+ <para>
+ As discussed in the
+ <link linkend="jmx.registration.programatic">Programatic Registration</link>
+ section,
+ <literal>CacheJmxWrapper</literal>
+ can do the work of building,
+ creating and starting the
+ <literal>Cache</literal>
+ if it is provided
+ with a
+ <literal>Configuration</literal>
+ . With the microcontainer,
+ this is the preferred approach, as it saves the boilerplate XML
+ needed to create the
+ <literal>CacheFactory</literal>
+ :
+ </para>
+
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <!-- First we create a Configuration object for the cache -->
+ <bean name="ExampleCacheConfig"
+ class="org.jboss.cache.config.Configuration">
+
+ ... build up the Configuration
+
+ </bean>
+
+ <bean name="ExampleCache" class="org.jboss.cache.jmx.CacheJmxWrapper">
+
+ <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.cache:service=ExampleTreeCache",
+ exposedInterface=org.jboss.cache.jmx.CacheJmxWrapperMBean.class,
+ registerDirectly=true)</annotation>
+
+ <constructor>
+ <parameter><inject bean="ExampleCacheConfig"/></parameter>
+ </constructor>
+
+ </bean>
+
+</deployment>
+]]>
+ </programlisting>
+ </section>
+
+ </section>
+
+ <section id="jmx.statistics">
+ <title>JBoss Cache Statistics</title>
+ <para>
+ JBoss Cache captures statistics in its interceptors and exposes the statistics through interceptor
+ MBeans. Gathering of statistics is enabled by default; this can be disabled for a specific cache
+ instance through the
+ <literal>ExposeManagementStatistics</literal>
+ configuration attribute. Note that
+ the majority of the statistics are provided by the
+ <literal>CacheMgmtInterceptor</literal>
+ ,
+ so this MBean is the most significant in this regard. If you want to disable all statistics for performance
+ reasons, you set
+ <literal>ExposeManagementStatistics</literal>
+ to
+ <literal>false</literal>
+ as this will
+ prevent the
+ <literal>CacheMgmtInterceptor</literal>
+ from being included in the cache's interceptor stack
+ when the cache is started.
+ </para>
+ <para>
+ If a
+ <literal>CacheJmxWrapper</literal>
+ is registered with JMX, the wrapper also ensures that
+ an MBean is registered in JMX for each interceptor that exposes statistics
+ <footnote>
+ <para>
+ Note that if the
+ <literal>CacheJmxWrapper</literal>
+ is not registered in JMX, the
+ interceptor MBeans will not be registered either. The JBoss Cache 1.4 releases
+ included code that would try to "discover" an
+ <literal>MBeanServer</literal>
+ and
+ automatically register the interceptor MBeans with it. For JBoss Cache 2.x we decided
+ that this sort of "discovery" of the JMX environment was beyond the proper scope of
+ a caching library, so we removed this functionality.
+ </para>
+ </footnote>
+ .
+ Management tools can then access those MBeans to examine the statistics. See the section in the
+ <link linkend="jmx_reference.statistics">JMX Reference chapter</link>
+ pertaining to the
+ statistics that are made available via JMX.
+ </para>
+ <para>
+ The name under which the interceptor MBeans will be registered is derived by taking the
+ <literal>ObjectName</literal>
+ under which the
+ <literal>CacheJmxWrapper</literal>
+ is
+ registered and adding a
+ <literal>cache-interceptor</literal>
+ attribute key whose value
+ is the non-qualified name of the interceptor class. So, for example, if the
+ <literal>CacheJmxWrapper</literal>
+ were registered under
+ <literal>jboss.cache:service=TreeCache</literal>
+ , the name of the
+ <literal>CacheMgmtInterceptor</literal>
+ MBean would be
+ <literal>jboss.cache:service=TreeCache,cache-interceptor=CacheMgmtInterceptor</literal>
+ .
+ </para>
+ <para>
+ Each interceptor's MBean exposes a
+ <literal>StatisticsEnabled</literal>
+ attribute that can be used to disable maintenance of statistics for
+ that interceptor. In addition, each interceptor MBean provides the following common operations and
+ attributes.
+ <itemizedlist>
+ <listitem>
+ <literal>dumpStatistics</literal>
+ - returns a
+ <literal>Map</literal>
+ containing the interceptor's attributes and values.
+ </listitem>
+ <listitem>
+ <literal>resetStatistics</literal>
+ - resets all statistics maintained by the interceptor.
+ </listitem>
+ <listitem>
+ <literal>setStatisticsEnabled(boolean)</literal>
+ - allows statistics to be disabled for a specific interceptor.
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Receiving JMX Notifications</title>
+ <para>
+ JBoss Cache users can register a listener to receive cache events described earlier in the
+ <link linkend="api.listener">User API</link>
+ chapter. Users can alternatively utilize the cache's management information infrastructure to receive these
+ events
+ via JMX notifications. Cache events are accessible as notifications by registering a
+ <literal>NotificationListener</literal>
+ for the
+ <literal>CacheJmxWrapper</literal>
+ .
+ </para>
+
+ <para>
+ See the section in the
+ <link linkend="jmx_reference.notifications">JMX Reference chapter</link>
+ pertaining
+ to JMX notifications for a list of notifications that can be received through the
+ <literal>CacheJmxWrapper</literal>
+ .
+ </para>
+
+
+ <para>
+ The following is an example of how to programmatically receive cache notifications when running in a
+ JBoss AS environment. In this example, the client uses a filter to specify which events are of interest.
+ </para>
+
+ <programlisting>
+ <![CDATA[
+ MyListener listener = new MyListener();
+ NotificationFilterSupport filter = null;
+
+ // get reference to MBean server
+ Context ic = new InitialContext();
+ MBeanServerConnection server = (MBeanServerConnection)ic.lookup("jmx/invoker/RMIAdaptor");
+
+ // get reference to CacheMgmtInterceptor MBean
+ String cache_service = "jboss.cache:service=TomcatClusteringCache";
+ ObjectName mgmt_name = new ObjectName(cache_service);
+
+ // configure a filter to only receive node created and removed events
+ filter = new NotificationFilterSupport();
+ filter.disableAllTypes();
+ filter.enableType(CacheNotificationBroadcaster.NOTIF_NODE_CREATED);
+ filter.enableType(CacheNotificationBroadcaster.NOTIF_NODE_REMOVED);
+
+ // register the listener with a filter
+ // leave the filter null to receive all cache events
+ server.addNotificationListener(mgmt_name, listener, filter, null);
+
+ // ...
+
+ // on completion of processing, unregister the listener
+ server.removeNotificationListener(mgmt_name, listener, filter, null);
+ ]]>
+ </programlisting>
+
+ <para>The following is the simple notification listener implementation used in the previous example.</para>
+ <programlisting>
+ <![CDATA[
+ private class MyListener implements NotificationListener, Serializable
+ {
+ public void handleNotification(Notification notification, Object handback)
+ {
+ String message = notification.getMessage();
+ String type = notification.getType();
+ Object userData = notification.getUserData();
+
+ System.out.println(type + ": " + message);
+
+ if (userData == null)
+ {
+ System.out.println("notification data is null");
+ }
+ else if (userData instanceof String)
+ {
+ System.out.println("notification data: " + (String) userData);
+ }
+ else if (userData instanceof Object[])
+ {
+ Object[] ud = (Object[]) userData;
+ for (Object data : ud)
+ {
+ System.out.println("notification data: " + data.toString());
+ }
+ }
+ else
+ {
+ System.out.println("notification data class: " + userData.getClass().getName());
+ }
+ }
+ }
+ ]]>
+ </programlisting>
+
+ <para>Note that the JBoss Cache management implementation only listens to cache events after a client registers
+ to receive MBean notifications. As soon as no clients are registered for notifications, the MBean will
+ remove
+ itself as a cache listener.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Accessing Cache MBeans in a Standalone Environment</title>
+ <para>
+ JBoss Cache MBeans are easily accessed when running cache instances in an application server that
+ provides an MBean server interface such as JBoss JMX Console. Refer to your server documentation
+ for instructions on how to access MBeans running in a server's MBean container.
+ </para>
+ <para>
+ In addition, though, JBoss Cache MBeans are also accessible when running in a non-server environment if the
+ JVM is JDK 5.0 or later. When running a standalone cache in a JDK 5.0 environment, you can access the
+ cache's MBeans as follows.
+ </para>
+ <para>
+ <orderedlist>
+ <listitem>
+ Set the system property
+ <literal>-Dcom.sun.management.jmxremote</literal>
+ when starting the JVM
+ where the cache will run.
+ </listitem>
+ <listitem>
+ Once the JVM is running, start the JDK 5.0
+ <literal>jconsole</literal>
+ utility, located in your JDK's
+ <literal>/bin</literal>
+ directory.
+ </listitem>
+ <listitem>When the utility loads, you will be able to select your running JVM and connect to it. The
+ JBoss Cache
+ MBeans will be available on the MBeans panel.
+ </listitem>
+ </orderedlist>
+ </para>
+ <para>Note that the
+ <literal>jconsole</literal>
+ utility will automatically register as a listener for cache notifications when
+ connected to a JVM running JBoss Cache instances.
+ </para>
+
+ <para>The following figure shows cache interceptor MBeans in
+ <literal>jconsole</literal>
+ . Cache statistics are displayed
+ for the
+ <literal>CacheMgmtInterceptor</literal>
+ :
+ </para>
+
+ <figure>
+ <title>CacheMgmtInterceptor MBean in jconsole</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="CacheMgmtInterceptor.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ </section>
+ </section>
+</chapter>
Added: core/trunk/src/main/docbook/userguide/en/modules/eviction_policies.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/modules/eviction_policies.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/modules/eviction_policies.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,537 @@
+<chapter id="eviction_policies">
+ <title>Eviction Policies</title>
+
+ <para>
+ Eviction policies control JBoss Cache's memory management by managing how many nodes are allowed to be stored in
+ memory and their life spans. Memory constraints on servers mean cache cannot grow indefinitely, so policies
+ need to be in place to restrict the size of the cache. Eviction policies are most often used alongside
+ <link linkend="cache_loaders">cache loaders</link>
+ .
+ </para>
+
+ <section>
+ <title>Configuring Eviction Policies</title>
+ <section>
+ <title>Basic Configuration</title>
+ <para>
+ The basic eviction policy configuration element looks like:
+ <programlisting>
+ <![CDATA[
+
+ ...
+
+ <attribute name="EvictionConfig">
+ <config>
+ <attribute name="wakeUpIntervalSeconds">3</attribute>
+
+ <!-- This defaults to 200000 if not specified -->
+ <attribute name="eventQueueSize">100000</attribute>
+
+ <!-- Name of the DEFAULT eviction policy class. -->
+ <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+
+ <!-- Cache wide default -->
+ <region name="/_default_">
+ <attribute name="maxNodes">100</attribute>
+ </region>
+
+ <!-- override policy used for this region -->
+ <region name="/org/jboss/data" policyClass="org.jboss.cache.eviction.MRUPolicy">
+ <attribute name="maxNodes">250</attribute>
+ </region>
+
+ <!-- We expect a lot of events for this region,
+ so override the default event queue size -->
+ <region name="/org/jboss/test/data" eventQueueSize="500000">
+ <attribute name="maxNodes">60000</attribute>
+ </region>
+
+ </config>
+ </attribute>
+
+ ...
+]]>
+ </programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <literal>wakeUpIntervalSeconds</literal>
+ - this required parameter defines how often the eviction thread runs
+ </listitem>
+ <listitem>
+ <literal>eventQueueSize</literal>
+ - this optional parameter defines the size of the queue which holds eviction events. If your eviction
+ thread does not run often enough, you may need to increase this. This can be overridden on a
+ per-region basis.
+ </listitem>
+ <listitem>
+ <literal>policyClass</literal>
+ - this is required, unless you set individual policyClass attributes on each and every region. This
+ defines the eviction policy to use if one is not defined for a region.
+ </listitem>
+ </itemizedlist>
+
+ </para>
+ </section>
+ <section>
+ <title>Eviction Regions</title>
+ <para>
+ The concept of regions and the
+ <literal>Region</literal>
+ class were
+ <link linkend="architecture.regions">visited earlier</link>
+ when talking about marshalling. Regions also have another use, in that they are used to define the eviction
+ policy used within the region. In addition to using a region-specific configuration, you can also configure
+ a default, cache-wide eviction policy for nodes that do not fall into predefined regions or if you do not
+ wish to define specific regions. It is important to note that when defining regions using the configuration
+ XML file, all elements of the
+ <literal>Fqn</literal>
+ that defines the region are
+ <literal>java.lang.String</literal>
+ objects.
+ </para>
+ <para>
+ Looking at the eviction configuration snippet above, we see that a default region,
+ <literal>_default_</literal>
+ , holds attributes
+ which apply to nodes that do not fall into any of the other regions defined.
+ </para>
+ <para>
+ For each region, you can define parameters which affect how the policy which applies to the region chooses
+ to evict nodes.
+ In the example above, the
+ <literal>LRUPolicy</literal>
+ allows a
+ <literal>maxNodes</literal>
+ parameter which defines
+ how many nodes can exist in the region before it chooses to start evicting nodes. See the javadocs for each
+ policy for a list of allowed parameters.
+ </para>
+
+ <section>
+ <title>Overlapping Eviction Regions</title>
+
+ <para>It's possible to define regions that overlap. In other words, one region can be defined for
+ <emphasis>/a/b/c</emphasis>
+ , and another
+ defined for
+ <emphasis>/a/b/c/d</emphasis>
+ (which is just the
+ <emphasis>d</emphasis>
+ subtree of the
+ <emphasis>/a/b/c</emphasis>
+ sub-tree).
+ The algorithm, in order to handle scenarios like this consistently, will always choose the first region
+ it encounters.
+ In this way, if the algorithm needed to decide how to handle
+ <emphasis>/a/b/c/d/e</emphasis>
+ , it would start from there and work
+ its way up the tree until it hits the first defined region - in this case
+ <emphasis>/a/b/c/d</emphasis>
+ .
+ </para>
+ </section>
+
+ </section>
+ <section>
+ <title>Programmatic Configuration</title>
+ <para>
+ Configuring eviction using the
+ <literal>Configuration</literal>
+ object entails the use of the
+ <literal>org.jboss.cache.config.EvictionConfig</literal>
+ bean, which is passed into
+ <literal>Configuration.setEvictionConfig()</literal>
+ . See the
+ <link linkend="configuration">chapter on Configuration</link>
+ for more on building a
+ <literal>Configuration</literal>
+ programatically.
+ </para>
+
+ <para>
+ The use of simple POJO beans to represent all elements in a
+ cache's configuration also makes it fairly easy to programatically
+ add eviction regions after the cache is started . For example,
+ assume we had an existing cache configured via XML with the
+ EvictionConfig element shown above. Now at runtime we wished to
+ add a new eviction region named "/org/jboss/fifo", using
+ <literal>LRUPolicy</literal>
+ but a different number of
+ <literal>maxNodes</literal>
+ :
+ </para>
+
+ <programlisting>
+ Fqn fqn = Fqn.fromString("/org/jboss/fifo");
+
+ // Create a configuration for an LRUPolicy
+ LRUConfiguration lruc = new LRUConfiguration();
+ lruc.setMaxNodes(10000);
+
+ // Create the region and set the config
+ Region region = cache.getRegion(fqn, true);
+ region.setEvictionPolicy(lruc);
+ </programlisting>
+ </section>
+ </section>
+
+ <section>
+ <title>Shipped Eviction Policies</title>
+ <section>
+ <title>LRUPolicy - Least Recently Used</title>
+
+ <para>
+ <literal>org.jboss.cache.eviction.LRUPolicy</literal>
+ controls both the node lifetime and age. This policy guarantees a constant order (
+ <literal>O (1)</literal>
+ ) for
+ adds, removals and lookups (visits). It has the following configuration
+ parameters:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <literal>maxNodes</literal>
+ - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
+ </listitem>
+ <listitem>
+ <literal>timeToLiveSeconds</literal>
+ - The amount of time a node is not written to or read (in seconds) before the node is swept away. 0
+ denotes no limit.
+ </listitem>
+
+ <listitem>
+ <literal>maxAgeSeconds</literal>
+ - Lifespan of a node (in seconds) regardless of idle time before the node is swept away. 0 denotes no
+ limit.
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>FIFOPolicy - First In, First Out</title>
+
+ <para>
+ <literal>org.jboss.cache.eviction.FIFOPolicy</literal>
+ controls the eviction in a proper first in first out order. This policy
+ guarantees a constant order (
+ <literal>O (1)</literal>
+ ) for adds, removals and lookups (visits). It has the
+ following configuration parameters:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <literal>maxNodes</literal>
+ - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
+ </listitem>
+ </itemizedlist>
+ </section>
+
+
+ <section>
+ <title>MRUPolicy - Most Recently Used</title>
+
+ <para>
+ <literal>org.jboss.cache.eviction.MRUPolicy</literal>
+ controls
+ the eviction in based on most recently used algorithm. The most recently
+ used nodes will be the first to evict with this policy. This policy
+ guarantees a constant order (
+ <literal>O (1)</literal>
+ ) for adds, removals and lookups (visits). It has the
+ following configuration parameters:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <literal>maxNodes</literal>
+ - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>LFUPolicy - Least Frequently Used</title>
+
+ <para>
+ <literal>org.jboss.cache.eviction.LFUPolicy</literal>
+ controls
+ the eviction in based on least frequently used algorithm. The least
+ frequently used nodes will be the first to evict with this policy. Node
+ usage starts at 1 when a node is first added. Each time it is visted,
+ the node usage counter increments by 1. This number is used to determine
+ which nodes are least frequently used. LFU is also a sorted eviction
+ algorithm. The underlying EvictionQueue implementation and algorithm is
+ sorted in ascending order of the node visits counter. This class
+ guarantees a constant order (
+ <literal>O (1)</literal>
+ ) for adds, removal and searches. However, when any
+ number of nodes are added/visited to the queue for a given processing
+ pass, a single quasilinear (
+ <literal>O (n * log n)</literal>
+ ) operation is used to resort the queue in
+ proper LFU order. Similarly if any nodes are removed or evicted, a
+ single linear (
+ <literal>O (n)</literal>
+ ) pruning operation is necessary to clean up the
+ EvictionQueue. LFU has the following configuration parameters:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <literal>maxNodes</literal>
+ - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
+ </listitem>
+ <listitem>
+ <literal>minNodes</literal>
+ - This is the minimum number of nodes allowed in this region. This value determines what
+ the eviction queue should prune down to per pass. e.g. If
+ minNodes is 10 and the cache grows to 100 nodes, the cache is
+ pruned down to the 10 most frequently used nodes when the
+ eviction timer makes a pass through the eviction
+ algorithm.
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
+ <section>
+ <title>ExpirationPolicy</title>
+
+ <para>
+ <literal>org.jboss.cache.eviction.ExpirationPolicy</literal>
+ is a policy
+ that evicts nodes based on an absolute expiration time. The
+ expiration time is indicated using the
+ <literal>org.jboss.cache.Node.put()</literal>
+ method, using a String key
+ <literal>expiration</literal>
+ and the absolute time as a
+ <literal>java.lang.Long</literal>
+ object, with a value indicated as milliseconds past midnight
+ January 1st, 1970 UTC (the same relative time as provided by
+ <literal>java.lang.System.currentTimeMillis()</literal>
+ ).
+ </para>
+
+ <para>
+ This policy guarantees a constant order (
+ <literal>O (1)</literal>
+ ) for adds and removals.
+ Internally, a sorted set (TreeSet) containing the expiration
+ time and Fqn of the nodes is stored, which essentially
+ functions as a heap.
+ </para>
+
+ <para>
+ This policy has the following configuration parameters:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <literal>expirationKeyName</literal>
+ - This is the Node key name used
+ in the eviction algorithm. The configuration default is
+ <literal>expiration</literal>
+ .
+ </listitem>
+ <listitem>
+ <literal>maxNodes</literal>
+ - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ The following listing shows how the expiration date is indicated and how the
+ policy is applied:
+ <programlisting>
+ <![CDATA[
+ Cache cache = DefaultCacheFactory.createCache();
+ Fqn fqn1 = Fqn.fromString("/node/1");
+ Long future = new Long(System.currentTimeMillis() + 2000);
+
+ // sets the expiry time for a node
+ cache.getRoot().addChild(fqn1).put(ExpirationConfiguration.EXPIRATION_KEY, future);
+
+ assertTrue(cache.getRoot().hasChild(fqn1));
+ Thread.sleep(5000);
+
+ // after 5 seconds, expiration completes
+ assertFalse(cache.getRoot().hasChild(fqn1));
+]]>
+ </programlisting>
+ Note that the expiration time of nodes is only checked when the
+ region manager wakes up every
+ <literal>wakeUpIntervalSeconds</literal>
+ , so eviction
+ may happen a few seconds later than indicated.
+ </para>
+ </section>
+ <section>
+ <title>ElementSizePolicy - Eviction based on number of key/value pairs in a node</title>
+
+ <para>
+ <literal>org.jboss.cache.eviction.ElementSizePolicy</literal>
+ controls
+ the eviction in based on the number of key/value pairs in the node. Nodes The most recently
+ used nodes will be the first to evict with this policy. It has the following configuration parameters:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <literal>maxNodes</literal>
+ - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
+ </listitem>
+ <listitem>
+ <literal>maxElementsPerNode</literal>
+ - This is the trigger number of attributes per node for the node to be selected for eviction. 0 denotes
+ no limit.
+ </listitem>
+ </itemizedlist>
+ </section>
+ </section>
+
+ <section>
+ <title>Writing Your Own Eviction Policies</title>
+ <section>
+ <title>Eviction Policy Plugin Design</title>
+
+ <para>The design of the JBoss Cache eviction policy framework is based
+ on an
+ <literal>EvictionInterceptor</literal>
+ to handle cache events and relay them back to the eviction
+ policies. During the cache start up, an
+ <literal>EvictionInterceptor</literal>
+ will be added to the cache
+ interceptor stack if the eviction policy is specified.
+ Then whenever a node is added, removed, evicted, or visited, the
+ <literal>EvictionInterceptor</literal>
+ will maintain state statistics and
+ information will be relayed to each individual eviction region.
+ </para>
+
+ <para>
+ There is a single eviction thread (timer) that will run at a
+ configured interval. This thread will make calls into each of the policy
+ providers and inform it of any aggregated adds,
+ removes and visits (gets) events to the cache during the configured interval.
+ The eviction thread is responsible for kicking off the eviction policy
+ processing (a single pass) for each configured eviction cache
+ region.
+ </para>
+ </section>
+
+ <section>
+ <title>Interfaces to implement</title>
+ <para>In order to implement an eviction policy, the following interfaces
+ must be implemented:
+ <itemizedlist>
+ <listitem>
+ <literal>org.jboss.cache.eviction.EvictionPolicy</literal>
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.EvictionAlgorithm</literal>
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.EvictionQueue</literal>
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.config.EvictionPolicyConfig</literal>
+ </listitem>
+ </itemizedlist>
+ When compounded
+ together, each of these interface implementations define all the
+ underlying mechanics necessary for a complete eviction policy
+ implementation.
+ </para>
+
+ <para>
+ <emphasis>Note that:</emphasis>
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>The
+ <literal>EvictionPolicyConfig</literal>
+ implementation
+ should maintain
+ getter and setter methods for whatever configuration properties
+ the policy supports (e.g. for
+ <literal>LRUConfiguration</literal>
+ among others there is a
+ <literal>int getMaxNodes()</literal>
+ and a
+ <literal>setMaxNodes(int)</literal>
+ ). When the "EvictionConfig" section of an XML configuration
+ is parsed, these properties will be set by reflection.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Alternatively, the implementation of a new eviction policy
+ provider can be simplified by extending
+ <literal>BaseEvictionPolicy</literal>
+ and
+ <literal>BaseEvictionAlgorithm</literal>
+ . Or for properly sorted EvictionAlgorithms (sorted
+ in eviction order - see
+ <literal>LFUAlgorithm</literal>
+ ) extending
+ <literal>BaseSortedEvictionAlgorithm</literal>
+ and implementing
+ <literal>SortedEvictionQueue</literal>
+ takes
+ care of most of the common functionality available in a set of eviction
+ policy provider classes
+ </para>
+
+
+ <para>
+ <emphasis>Note that:</emphasis>
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>The
+ <literal>BaseEvictionAlgorithm</literal>
+ class maintains a processing
+ structure. It will process the ADD, REMOVE, and VISIT events queued
+ by the region first. It also maintains an collection of
+ items that were not properly evicted during the last go around
+ because of held locks. That list is pruned. Finally, the
+ EvictionQueue itself is pruned for entries that should be evicted
+ based upon the configured eviction rules for the region.
+ </para>
+ </listitem>
+ <listitem>
+ <para>The
+ <literal>BaseSortedEvictionAlgorithm</literal>
+ class will maintain a boolean
+ through the algorithm processing that will determine if any new
+ nodes were added or visited. This allows the Algorithm to determine
+ whether to resort the eviction queue items (in first to evict order)
+ or to skip the potentially expensive sorting if there have been no
+ changes to the cache in this region.
+ </para>
+ </listitem>
+ <listitem>
+ <para>The
+ <literal>SortedEvictionQueue</literal>
+ interface defines the contract used by
+ the
+ <literal>BaseSortedEvictionAlgorithm</literal>
+ abstract class that is used to
+ resort the underlying queue. Again, the queue sorting should be
+ sorted in first to evict order. The first entry in the list should
+ evict before the last entry in the queue. The last entry in the
+ queue should be the last entry that will require eviction.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ </section>
+</chapter>
\ No newline at end of file
Added: core/trunk/src/main/docbook/userguide/en/modules/introduction.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/modules/introduction.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/modules/introduction.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="introduction">
+ <title>Overview</title>
+
+ <section>
+ <title>What is JBoss Cache?</title>
+
+ <para>
+ JBoss Cache is a tree-structured, clustered, transactional cache. It is
+ the backbone for many fundamental JBoss Application Server clustering services, including - in certain
+ versions - clustering JNDI, HTTP and EJB sessions.
+ </para>
+ <para>
+ JBoss Cache can also be used as a standalone transactional and clustered caching library or even an object
+ oriented data store. It can even be embedded in other enterprise Java frameworks and application servers
+ such as BEA WebLogic or IBM WebSphere, Tomcat, Spring, Hibernate, and many others. It is also very commonly
+ used directly by standalone Java applications that do not run from within an application server, to maintain
+ clustered state.
+ </para>
+ <section>
+ <title>And what is Pojo Cache?</title>
+ <para>
+ Pojo Cache is an extension of the core JBoss Cache API. Pojo Cache offers additional functionality such as:
+ <itemizedlist>
+ <listitem>maintaining object references even after replication or persistence.</listitem>
+ <listitem>fine grained replication, where only modified object fields are replicated.</listitem>
+ <listitem>"API-less" clustering model where pojos are simply annotated as being clustered.</listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Pojo Cache has a complete and separate set of documentation, including a user guide, FAQ and tutorial and
+ as such, Pojo Cache is not discussed further in this book.
+ </para>
+ </section>
+
+ </section>
+
+ <section>
+ <title>Summary of Features</title>
+
+ <para>
+ JBoss Cache offers a simple and straightforward API, where data (simple Java objects) can be placed in the
+ cache and, based on configuration options selected, this data may be one or all of:
+ <itemizedlist>
+ <listitem>replicated to some or all cache instances in a cluster.</listitem>
+ <listitem>persisted to disk and/or a remote cluster ("far-cache").</listitem>
+ <listitem>garbage collected from memory when memory runs low, and passivated to disk so state isn't lost.
+ </listitem>
+ </itemizedlist>
+ In addition, JBoss Cache offers a rich set of enterprise-class features:
+ <itemizedlist>
+ <listitem>being able to participate in JTA transactions (works with Java EE compliant TransactionManagers).
+ </listitem>
+ <listitem>attach to JMX servers and provide runtime statistics on the state of the cache.</listitem>
+ <listitem>allow client code to attach listeners and receive notifications on cache events.</listitem>
+ </itemizedlist>
+ </para>
+
+ <para>A cache is organised as a tree, with a single root. Each node in the tree essentially contains a Map,
+ which acts as a store for key/value pairs. The only requirement placed on objects that are cached is that
+ they implement
+ <literal>java.io.Serializable</literal>
+ . Note that this requirement does not exist for Pojo Cache.
+ </para>
+
+ <para>JBoss Cache
+ can be either local or replicated. Local trees exist
+ only inside the JVM in which they are created, whereas replicated trees
+ propagate any changes to some or all other trees in the same cluster. A
+ cluster may span different hosts on a network or just different JVMs
+ on a single host.
+ </para>
+
+ <para>When a change is made to an object in the cache and that change is done in
+ the context of a transaction, the replication of changes is deferred until the transaction
+ commits successfully. All modifications are kept in a list associated with
+ the transaction for the caller. When the transaction commits, we replicate the
+ changes. Otherwise, (on a rollback) we simply undo the changes locally
+ resulting in zero network traffic and overhead. For example, if a caller
+ makes 100 modifications and then rolls back the transaction, we will not replicate
+ anything, resulting in no network traffic.
+ </para>
+
+ <para>If a caller has no transaction associated with it (and isolation level is not
+ NONE - more about this later), we will replicate right after each modification, e.g. in the above
+ case we would send 100 messages, plus an additional message for the
+ rollback. In this sense, running without a transaction can be thought of as analogous as running with
+ auto-commit switched on in JDBC terminology, where each operation is committed automatically.
+ </para>
+
+ <para>
+ JBoss Cache works out of the box with most popular transaction managers, and even provides an API where
+ custom transaction manager lookups can be written.
+ </para>
+
+ <para>
+ The cache is also completely thread-safe. It uses a pessimistic locking scheme for nodes in the tree by
+ default, with an optimistic locking scheme as a configurable option. With pessimistic locking, the degree
+ of concurrency can be tuned using a number of isolation levels, corresponding to database-style
+ transaction isolation levels, i.e., SERIALIZABLE, REPEATABLE_READ, READ_COMMITTED, READ_UNCOMMITTED and NONE.
+ Concurrency, locking and isolation levels will be discussed later.
+ </para>
+ </section>
+
+ <section>
+ <title>
+ Requirements
+ </title>
+ <para>
+ JBoss Cache requires Java 5.0 (or newer).
+ </para>
+ <para>
+ However, there is a way to build JBoss Cache as a Java 1.4.x compatible binary using
+ <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossRetro">JBossRetro</ulink>
+ to retroweave the Java 5.0 binaries. However, Red Hat Inc. does not offer professional support around the
+ retroweaved
+ binary at this time and the Java 1.4.x compatible binary is not in the binary distribution. See
+ <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossCacheHabaneroJava1.4">this wiki</ulink>
+ page for
+ details on building the retroweaved binary for yourself.
+ </para>
+ <para>
+ In addition to Java 5.0, at a minimum, JBoss Cache has dependencies on
+ <ulink url="http://www.jgroups.org">JGroups</ulink>
+ , and Apache's
+ <ulink
+ url="http://jakarta.apache.org/commons/logging/">commons-logging
+ </ulink>
+ . JBoss Cache ships with all dependent libraries necessary to run out of the box.
+ </para>
+ </section>
+
+ <section>
+ <title>License</title>
+ <para>
+ JBoss Cache is an open source product, using the business and OEM-friendly
+ <ulink url="http://www.opensource.org/">OSI-approved</ulink>
+ <ulink url="http://www.gnu.org/copyleft/lesser.html">LGPL license.</ulink>
+ Commercial development support, production support and training for JBoss Cache is available through
+ <ulink url="http://www.jboss.com">JBoss, a division of Red Hat Inc.</ulink>
+ JBoss Cache is a part of JBoss Professional Open Source
+ <ulink url="http://www.jboss.comindex">JEMS</ulink>
+ (JBoss Enterprise Middleware Suite).
+ </para>
+ </section>
+</chapter>
Added: core/trunk/src/main/docbook/userguide/en/modules/jmx_reference.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/modules/jmx_reference.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/modules/jmx_reference.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,308 @@
+<chapter id="jmx_reference">
+ <title>JMX References</title>
+ <section id="jmx_reference.statistics">
+ <title>JBoss Cache Statistics</title>
+ <para>
+ The following table describes the statistics currently available and may be collected via JMX.
+ </para>
+ <table>
+ <title>JBoss Cache Management Statistics</title>
+ <tgroup cols="4">
+ <colspec colnum="1" colwidth="2*"/>
+ <colspec colnum="2" colwidth="2*"/>
+ <colspec colnum="3" colwidth="1*"/>
+ <colspec colnum="4" colwidth="3*"/>
+ <thead>
+ <row>
+ <entry>MBean Name</entry>
+ <entry>Attribute</entry>
+ <entry>Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>ActivationInterceptor</entry>
+ <entry>Activations</entry>
+ <entry>long</entry>
+ <entry>Number of passivated nodes that have been activated.</entry>
+ </row>
+ <row>
+ <entry>CacheLoaderInterceptor</entry>
+ <entry>CacheLoaderLoads</entry>
+ <entry>long</entry>
+ <entry>Number of nodes loaded through a cache loader.</entry>
+ </row>
+ <row>
+ <entry>CacheLoaderInterceptor</entry>
+ <entry>CacheLoaderMisses</entry>
+ <entry>long</entry>
+ <entry>Number of unsuccessful attempts to load a node through a cache loader.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>Hits</entry>
+ <entry>long</entry>
+ <entry>Number of successful attribute retrievals.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>Misses</entry>
+ <entry>long</entry>
+ <entry>Number of unsuccessful attribute retrievals.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>Stores</entry>
+ <entry>long</entry>
+ <entry>Number of attribute store operations.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>Evictions</entry>
+ <entry>long</entry>
+ <entry>Number of node evictions.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>NumberOfAttributes</entry>
+ <entry>int</entry>
+ <entry>Number of attributes currently cached.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>NumberOfNodes</entry>
+ <entry>int</entry>
+ <entry>Number of nodes currently cached.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>ElapsedTime</entry>
+ <entry>long</entry>
+ <entry>Number of seconds that the cache has been running.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>TimeSinceReset</entry>
+ <entry>long</entry>
+ <entry>Number of seconds since the cache statistics have been reset.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>AverageReadTime</entry>
+ <entry>long</entry>
+ <entry>Average time in milliseconds to retrieve a cache attribute, including unsuccessful
+ attribute retrievals.
+ </entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>AverageWriteTime</entry>
+ <entry>long</entry>
+ <entry>Average time in milliseconds to write a cache attribute.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>HitMissRatio</entry>
+ <entry>double</entry>
+ <entry>Ratio of hits to hits and misses. A hit is a get attribute operation that results in an object
+ being
+ returned to the client. The retrieval may be from a cache loader if the entry isn't in the local
+ cache.
+ </entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>ReadWriteRatio</entry>
+ <entry>double</entry>
+ <entry>Ratio of read operations to write operations. This is the ratio of cache hits and misses to
+ cache stores.
+ </entry>
+ </row>
+ <row>
+ <entry>CacheStoreInterceptor</entry>
+ <entry>CacheLoaderStores</entry>
+ <entry>long</entry>
+ <entry>Number of nodes written to the cache loader.</entry>
+ </row>
+ <row>
+ <entry>InvalidationInterceptor</entry>
+ <entry>Invalidations</entry>
+ <entry>long</entry>
+ <entry>Number of cached nodes that have been invalidated.</entry>
+ </row>
+ <row>
+ <entry>PassivationInterceptor</entry>
+ <entry>Passivations</entry>
+ <entry>long</entry>
+ <entry>Number of cached nodes that have been passivated.</entry>
+ </row>
+ <row>
+ <entry>TxInterceptor</entry>
+ <entry>Prepares</entry>
+ <entry>long</entry>
+ <entry>Number of transaction prepare operations performed by this interceptor.</entry>
+ </row>
+ <row>
+ <entry>TxInterceptor</entry>
+ <entry>Commits</entry>
+ <entry>long</entry>
+ <entry>Number of transaction commit operations performed by this interceptor.</entry>
+ </row>
+ <row>
+ <entry>TxInterceptor</entry>
+ <entry>Rollbacks</entry>
+ <entry>long</entry>
+ <entry>Number of transaction rollbacks operations performed by this interceptor.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+
+ <section id="jmx_reference.notifications">
+ <title>JMX MBean Notifications</title>
+ <para>The following table depicts the JMX notifications available for JBoss Cache as well as the cache events to
+ which they correspond. These are the notifications that can be received through the
+ <literal>CacheJmxWrapper</literal>
+ MBean.
+ Each notification represents a single event published by JBoss Cache and provides user data corresponding to
+ the parameters of the event.
+ </para>
+ <table>
+ <title>JBoss Cache MBean Notifications</title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Notification Type</entry>
+ <entry>Notification Data</entry>
+ <entry>CacheListener Event</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>org.jboss.cache.CacheStarted</entry>
+ <entry>String : cache service name</entry>
+ <entry>cacheStarted</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.CacheStopped</entry>
+ <entry>String : cache service name</entry>
+ <entry>cacheStopped</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeCreated</entry>
+ <entry>String : fqn</entry>
+ <entry>NodeCreated</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeEvicted</entry>
+ <entry>String : fqn</entry>
+ <entry>NodeEvicted</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeLoaded</entry>
+ <entry>String : fqn</entry>
+ <entry>NodeLoaded</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeModifed</entry>
+ <entry>String : fqn</entry>
+ <entry>NodeModifed</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeRemoved</entry>
+ <entry>String : fqn</entry>
+ <entry>NodeRemoved</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeVisited</entry>
+ <entry>String : fqn</entry>
+ <entry>NodeVisited</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.ViewChange</entry>
+ <entry>String : view</entry>
+ <entry>ViewChange</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeActivate</entry>
+ <entrytbl cols="1">
+ <tbody>
+ <row>
+ <entry rowsep="0">Object[0]=String: fqn</entry>
+ </row>
+ <row>
+ <entry>Object[1]=Boolean: pre</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ <entry>NodeActivate</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeEvict</entry>
+ <entrytbl cols="1">
+ <tbody>
+ <row>
+ <entry rowsep="0">Object[0]=String: fqn</entry>
+ </row>
+ <row>
+ <entry>Object[1]=Boolean: pre</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ <entry>NodeEvict</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeModify</entry>
+ <entrytbl cols="1">
+ <tbody>
+ <row>
+ <entry rowsep="0">Object[0]=String: fqn</entry>
+ </row>
+ <row>
+ <entry rowsep="0">Object[1]=Boolean: pre</entry>
+ </row>
+ <row>
+ <entry>Object[2]=Boolean: isLocal</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ <entry>NodeModify</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodePassivate</entry>
+ <entrytbl cols="1">
+ <tbody>
+ <row>
+ <entry rowsep="0">Object[0]=String: fqn</entry>
+ </row>
+ <row>
+ <entry>Object[1]=Boolean: pre</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ <entry>NodePassivate</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeRemove</entry>
+ <entrytbl cols="1">
+ <tbody>
+ <row>
+ <entry rowsep="0">Object[0]=String: fqn</entry>
+ </row>
+ <row>
+ <entry rowsep="0">Object[1]=Boolean: pre</entry>
+ </row>
+ <row>
+ <entry>Object[2]=Boolean: isLocal</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ <entry>NodeRemove</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+</chapter>
\ No newline at end of file
Added: core/trunk/src/main/docbook/userguide/en/modules/preface.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/modules/preface.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/modules/preface.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,48 @@
+<preface id="preface">
+ <title>Preface</title>
+
+ <para>
+ This is the official JBoss Cache user guide. Along with its accompanying documents (an FAQ, a tutorial and a
+ whole set of documents on PojoCache), this is freely available on the JBoss Cache <ulink url="http://labs.jboss.com/jbosscache">documentation site.</ulink>
+ </para>
+ <para>
+ When used, JBoss Cache refers to JBoss Cache Core, a tree-structured, clustered, transactional cache.
+ Pojo Cache, also a part of the JBoss Cache distribution, is documented separately. (Pojo Cache is a cache that
+ deals with Plain Old Java Objects, complete with object relationships, with the ability to cluster such pojos
+ while maintaining their relationships. Please see the Pojo Cache documentation for more information about this.)
+ </para>
+
+ <para>
+ This book is targeted at both developers wishing to use JBoss Cache as a clustering and caching library in
+ their codebase, as well as people who wish to "OEM" JBoss Cache by building on and extending its features. As
+ such,
+ this book is split into two major sections - one detailing the "User" API and the other going much deeper into
+ specialist topics and the JBoss Cache architecture.
+ </para>
+
+ <para>
+ In general, a good knowledge of the Java programming language along with a strong appreciation and understanding
+ of transactions and concurrent threads is necessary. No prior knowledge of JBoss Application Server is expected
+ or required.
+ </para>
+
+ <para>
+ For further discussion, use the
+ <ulink url="http://www.jboss.com/index.html?module=bb&op=viewforum&f=157">user forum</ulink>
+ linked on the JBoss Cache <ulink url="http://labs.jboss.com/jbosscache">website.</ulink> We also provide a mechanism for
+ tracking bug reports and feature requests on the JBoss Cache <ulink url="http://jira.jboss.com/jira/browse/JBCACHE">JIRA issue tracker.</ulink>
+
+ If you are interested in the development of JBoss Cache or in translating this documentation into other languages,
+ we'd love
+ to hear from you. Please post a message on the
+ <ulink url="http://www.jboss.com/index.html?module=bb&op=viewforum&f=157">user forum</ulink>
+ or contact us by using the JBoss Cache <ulink url="https://lists.jboss.org/mailman/listinfo/jbosscache-dev">developer mailing list.</ulink>
+ </para>
+
+ <para>
+ This book is specifically targeted at the JBoss Cache release of the same version number. It may not apply to
+ older or newer releases of JBoss Cache. It is important that you use the documentation appropriate to the version
+ of JBoss Cache you intend to use.
+ </para>
+
+</preface>
\ No newline at end of file
Added: core/trunk/src/main/docbook/userguide/en/modules/replication.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/modules/replication.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/modules/replication.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,730 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="clustering">
+ <title>Clustering</title>
+
+ <para>This chapter talks about aspects around clustering JBoss Cache.</para>
+
+ <section>
+ <title>Cache Replication Modes</title>
+
+ <para>JBoss Cache can be configured to be either local (standalone) or
+ clustered. If in a cluster, the cache can be configured to replicate
+ changes, or to invalidate changes. A detailed discussion on this
+ follows.
+ </para>
+
+ <section>
+ <title>Local Mode</title>
+
+ <para>Local caches don't join a cluster and don't communicate with other
+ caches in a cluster. Therefore their elements don't need to be
+ serializable - however, we recommend making them serializable, enabling
+ a user to change the cache mode at any time. The dependency on the
+ JGroups library is still there, although a JGroups channel is not
+ started.
+ </para>
+ </section>
+
+ <section>
+ <title>Replicated Caches</title>
+
+ <para>Replicated caches replicate all changes to some or all of the other cache
+ instances in the cluster. Replication can either happen after each
+ modification (no transactions), or at the end of a transaction (commit
+ time).
+ </para>
+
+ <para>Replication can be synchronous or asynchronous . Use of either one
+ of the options is application dependent. Synchronous replication blocks
+ the caller (e.g. on a
+ <literal>put()</literal>
+ ) until the modifications
+ have been replicated successfully to all nodes in a cluster.
+ Asynchronous replication performs replication in the background (the
+ <literal>put()</literal>
+ returns immediately). JBoss Cache also offers a
+ replication queue, where modifications are replicated periodically (i.e.
+ interval-based), or when the queue size exceeds a number of elements, or
+ a combination thereof.
+ </para>
+
+ <para>Asynchronous replication is faster (no caller blocking), because
+ synchronous replication requires acknowledgments from all nodes in a
+ cluster that they received and applied the modification successfully
+ (round-trip time). However, when a synchronous replication returns
+ successfully, the caller knows for sure that all modifications have been
+ applied to all cache instances, whereas this is not be the case with asynchronous
+ replication. With asynchronous replication, errors are simply written to
+ a log. Even when using transactions, a transaction may succeed but
+ replication may not succeed on all cache instances.
+ </para>
+
+ <section id="replication.tx">
+ <title>Replicated Caches and Transactions</title>
+
+ <para>When using transactions, replication only occurs at the
+ transaction boundary - i.e., when a transaction commits. This results
+ in minimising replication traffic since a single modification is
+ broadcast rather than a series of individual modifications, and can be
+ a lot more efficient than not using transactions. Another effect of
+ this is that if a transaction were to roll back, nothing is broadcast
+ across a cluster.
+ </para>
+
+ <para>Depending on whether you are running your cluster in
+ asynchronous or synchronous mode, JBoss Cache will use either a single
+ phase or
+ <ulink
+ url="http://en.wikipedia.org/wiki/Two-phase_commit_protocol">two phase
+ commit
+ </ulink>
+ protocol, respectively.
+ </para>
+
+ <section>
+ <title>One Phase Commits</title>
+
+ <para>Used when your cache mode is REPL_ASYNC. All modifications are
+ replicated in a single call, which instructs remote caches to apply
+ the changes to their local in-memory state and commit locally.
+ Remote errors/rollbacks are never fed back to the originator of the
+ transaction since the communication is asynchronous.
+ </para>
+ </section>
+
+ <section>
+ <title>Two Phase Commits</title>
+
+ <para>Used when your cache mode is REPL_SYNC. Upon committing your
+ transaction, JBoss Cache broadcasts a prepare call, which carries
+ all modifications relevant to the transaction. Remote caches then
+ acquire local locks on their in-memory state and apply the
+ modifications. Once all remote caches respond to the prepare call,
+ the originator of the transaction broadcasts a commit. This
+ instructs all remote caches to commit their data. If any of the
+ caches fail to respond to the prepare phase, the originator
+ broadcasts a rollback.
+ </para>
+
+ <para>Note that although the prepare phase is synchronous, the
+ commit and rollback phases are asynchronous. This is because
+ <ulink
+ url="http://java.sun.com/products/jta/">Sun's JTA
+ specification
+ </ulink>
+ does not specify how transactional resources
+ should deal with failures at this stage of a transaction; and other
+ resources participating in the transaction may have indeterminate
+ state anyway. As such, we do away with the overhead of synchronous
+ communication for this phase of the transaction. That said, they can
+ be forced to be synchronous using the
+ <literal>SyncCommitPhase</literal>
+ and
+ <literal>SyncRollbackPhase</literal>
+ configuration
+ attributes.
+ </para>
+ </section>
+ </section>
+
+ <section id="br">
+ <title>Buddy Replication</title>
+
+ <para>Buddy Replication allows you to suppress replicating your data
+ to all instances in a cluster. Instead, each instance picks one or
+ more 'buddies' in the cluster, and only replicates to these specific
+ buddies. This greatly helps scalability as there is no longer a memory
+ and network traffic impact every time another instance is added to a
+ cluster.
+ </para>
+
+ <para>One of the most common use cases of Buddy Replication is when a
+ replicated cache is used by a servlet container to store HTTP session
+ data. One of the pre-requisites to buddy replication working well and
+ being a real benefit is the use of
+ <emphasis>session
+ affinity
+ </emphasis>
+ , more casually known as
+ <emphasis>sticky
+ sessions
+ </emphasis>
+ in HTTP session replication speak. What this means
+ is that if certain data is frequently accessed, it is desirable that
+ this is always accessed on one instance rather than in a round-robin
+ fashion as this helps the cache cluster optimise how it chooses
+ buddies, where it stores data, and minimises replication
+ traffic.
+ </para>
+
+ <para>If this is not possible, Buddy Replication may prove to be more
+ of an overhead than a benefit.
+ </para>
+
+ <section>
+ <title>Selecting Buddies</title>
+
+ <figure>
+ <title>BuddyLocator</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="BuddyReplication.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Buddy Replication uses an instance of a
+ <literal>BuddyLocator</literal>
+ which contains the logic used to
+ select buddies in a network. JBoss Cache currently ships with a
+ single implementation,
+ <literal>NextMemberBuddyLocator</literal>
+ ,
+ which is used as a default if no implementation is provided. The
+ <literal>NextMemberBuddyLocator</literal>
+ selects the next member in
+ the cluster, as the name suggests, and guarantees an even spread of
+ buddies for each instance.
+ </para>
+
+ <para>The
+ <literal>NextMemberBuddyLocator</literal>
+ takes in 2
+ parameters, both optional.
+ <itemizedlist>
+ <listitem>
+
+
+ <literal>numBuddies</literal>
+
+ - specifies how many buddies each instance should pick to back its data onto. This defaults to
+ 1.
+ </listitem>
+
+ <listitem>
+
+
+ <literal>ignoreColocatedBuddies</literal>
+
+ - means that each instance will
+
+ <emphasis>try</emphasis>
+
+ to select a buddy on a different physical host. If not able to do so though, it will fall back
+ to colocated instances. This defaults to
+
+ <literal>true</literal>
+
+ .
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>BuddyPools</title>
+
+ <para>Also known as
+ <emphasis>replication groups</emphasis>
+ , a buddy
+ pool is an optional construct where each instance in a cluster may
+ be configured with a buddy pool name. Think of this as an 'exclusive
+ club membership' where when selecting buddies,
+ <literal>BuddyLocator</literal>
+ s that support buddy pools would try
+ and select buddies sharing the same buddy pool name. This allows
+ system administrators a degree of flexibility and control over how
+ buddies are selected. For example, a sysadmin may put two instances
+ on two separate physical servers that may be on two separate
+ physical racks in the same buddy pool. So rather than picking an
+ instance on a different host on the same rack,
+ <literal>BuddyLocator</literal>
+ s would rather pick the instance in
+ the same buddy pool, on a separate rack which may add a degree of
+ redundancy.
+ </para>
+ </section>
+
+ <section>
+ <title>Failover</title>
+
+ <para>In the unfortunate event of an instance crashing, it is
+ assumed that the client connecting to the cache (directly or
+ indirectly, via some other service such as HTTP session replication)
+ is able to redirect the request to any other random cache instance
+ in the cluster. This is where a concept of Data Gravitation comes
+ in.
+ </para>
+
+ <para>Data Gravitation is a concept where if a request is made on a
+ cache in the cluster and the cache does not contain this
+ information, it asks other instances in the cluster for the
+ data. In other words, data is lazily transferred, migrating
+ <emphasis>only</emphasis>
+ when other nodes ask for it. This strategy
+ prevents a network storm effect where lots of data is pushed around
+ healthy nodes because only one (or a few) of them die.
+ </para>
+
+ <para>If the data is not found in the primary section of some node,
+ it would (optionally) ask other instances to check in the backup
+ data they store for other caches.
+ This means that even if a cache containing your session dies, other
+ instances will still be able to access this data by asking the cluster
+ to search through their backups for this data.
+ </para>
+
+ <para>Once located, this data is transferred to the instance
+ which requested it and is added to this instance's data tree.
+ The data is then (optionally) removed from all other instances
+ (and backups) so that if session affinity is used, the affinity
+ should now be to this new cache instance which has just
+ <emphasis>taken
+ ownership
+ </emphasis>
+ of this data.
+ </para>
+
+ <para>Data Gravitation is implemented as an interceptor. The
+ following (all optional) configuration properties pertain to data
+ gravitation.
+ <itemizedlist>
+ <listitem>
+
+
+ <literal>dataGravitationRemoveOnFind</literal>
+
+ - forces all remote caches that own the data or hold backups for the data to remove that data,
+ thereby making the requesting cache the new data owner. This removal, of course, only happens
+ after the new owner finishes replicating data to its buddy. If set to
+
+ <literal>false</literal>
+
+ an evict is broadcast instead of a remove, so any state persisted in cache loaders will remain.
+ This is useful if you have a shared cache loader configured. Defaults to
+
+ <literal>true</literal>
+
+ .
+ </listitem>
+
+ <listitem>
+
+
+ <literal>dataGravitationSearchBackupTrees</literal>
+
+ - Asks remote instances to search through their backups as well as main data trees. Defaults to
+
+ <literal>true</literal>
+
+ . The resulting effect is that if this is
+
+ <literal>true</literal>
+
+ then backup nodes can respond to data gravitation requests in addition to data owners.
+ </listitem>
+
+ <listitem>
+
+
+ <literal>autoDataGravitation</literal>
+
+ - Whether data gravitation occurs for every cache miss. By default this is set to
+
+ <literal>false</literal>
+
+ to prevent unnecessary network calls. Most use cases will know when it may need to gravitate
+ data and will pass in an
+
+ <literal>Option</literal>
+
+ to enable data gravitation on a per-invocation basis. If
+
+ <literal>autoDataGravitation</literal>
+
+ is
+
+ <literal>true</literal>
+
+ this
+
+ <literal>Option</literal>
+
+ is unnecessary.
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>Configuration</title>
+
+ <para>
+ <programlisting>
+ <![CDATA[
+<!-- Buddy Replication config -->
+<attribute name="BuddyReplicationConfig">
+ <config>
+
+ <!-- Enables buddy replication. This is the ONLY mandatory configuration element here. -->
+ <buddyReplicationEnabled>true</buddyReplicationEnabled>
+
+ <!-- These are the default values anyway -->
+ <buddyLocatorClass>org.jboss.cache.buddyreplication.NextMemberBuddyLocator</buddyLocatorClass>
+
+ <!-- numBuddies is the number of backup nodes each node maintains. ignoreColocatedBuddies means
+ that each node will *try* to select a buddy on a different physical host. If not able to do so though,
+ it will fall back to colocated nodes. -->
+ <buddyLocatorProperties>
+ numBuddies = 1
+ ignoreColocatedBuddies = true
+ </buddyLocatorProperties>
+
+ <!-- A way to specify a preferred replication group. If specified, we try and pick a buddy which shares
+ the same pool name (falling back to other buddies if not available). This allows the sysdmin to
+ hint at backup buddies are picked, so for example, nodes may be hinted topick buddies on a different
+ physical rack or power supply for added fault tolerance. -->
+ <buddyPoolName>myBuddyPoolReplicationGroup</buddyPoolName>
+
+ <!-- Communication timeout for inter-buddy group organisation messages (such as assigning to and
+ removing from groups, defaults to 1000. -->
+ <buddyCommunicationTimeout>2000</buddyCommunicationTimeout>
+
+ <!-- Whether data is removed from old owners when gravitated to a new owner. Defaults to true. -->
+ <dataGravitationRemoveOnFind>true</dataGravitationRemoveOnFind>
+
+ <!-- Whether backup nodes can respond to data gravitation requests, or only the data owner is
+ supposed to respond. Defaults to true. -->
+ <dataGravitationSearchBackupTrees>true</dataGravitationSearchBackupTrees>
+
+ <!-- Whether all cache misses result in a data gravitation request. Defaults to false, requiring
+ callers to enable data gravitation on a per-invocation basis using the Options API. -->
+ <autoDataGravitation>false</autoDataGravitation>
+
+ </config>
+</attribute>
+
+]]>
+ </programlisting>
+ </para>
+ </section>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>Invalidation</title>
+
+ <para>If a cache is configured for invalidation rather than replication,
+ every time data is changed in a cache other caches in the cluster receive
+ a message informing them that their data is now stale and should be
+ evicted from memory. Invalidation, when used with a shared cache loader
+ (see chapter on Cache Loaders) would cause remote caches to refer to the
+ shared cache loader to retrieve modified data. The benefit of this is
+ twofold: network traffic is minimised as invalidation messages are very
+ small compared to replicating updated data, and also that other caches in
+ the cluster look up modified data in a lazy manner, only when
+ needed.
+ </para>
+
+ <para>Invalidation messages are sent after each modification (no
+ transactions), or at the end of a transaction, upon successful commit.
+ This is usually more efficient as invalidation messages can be optimised
+ for the transaction as a whole rather than on a per-modification
+ basis.
+ </para>
+
+ <para>Invalidation too can be synchronous or asynchronous, and just as in
+ the case of replication, synchronous invalidation blocks until all caches
+ in the cluster receive invalidation messages and have evicted stale data
+ while asynchronous invalidation works in a 'fire-and-forget' mode, where
+ invalidation messages are broadcast but doesn't block and wait for
+ responses.
+ </para>
+ </section>
+
+ <section>
+ <title>State Transfer</title>
+
+ <para>
+ <emphasis>State Transfer</emphasis>
+ refers to the process by which a
+ JBoss Cache instance prepares itself to begin providing a service by
+ acquiring the current state from another cache instance and integrating
+ that state into its own state.
+ </para>
+
+ <section>
+ <title>State Transfer Types</title>
+
+ <para>There are three divisions of state transfer types depending on a
+ point of view related to state transfer. First, in the context of
+ particular state transfer implementation, the underlying plumbing, there
+ are two starkly different state transfer types: byte array and streaming
+ based state transfer. Second, state transfer can be full or partial
+ state transfer depending on a subtree being transferred. Entire cache
+ tree transfer represents full transfer while transfer of a particular
+ subtree represents partial state transfer. And finally state transfer
+ can be "in-memory" and "persistent" transfer depending on a particular
+ use of cache.
+ </para>
+ </section>
+
+ <section>
+ <title>Byte array and streaming based state transfer</title>
+
+ <para>Byte array based transfer was a default and only transfer
+ methodology for cache in all previous releases up to 2.0. Byte array
+ based transfer loads entire state transferred into a byte array and
+ sends it to a state receiving member. Major limitation of this approach
+ is that the state transfer that is very large (>1GB) would likely
+ result in OutOfMemoryException. Streaming state transfer provides an
+ InputStream to a state reader and an OutputStream to a state writer.
+ OutputStream and InputStream abstractions enable state transfer in byte
+ chunks thus resulting in smaller memory requirements. For example, if
+ application state is represented as a tree whose aggregate size is 1GB,
+ rather than having to provide a 1GB byte array streaming state transfer
+ transfers the state in chunks of N bytes where N is user
+ configurable.
+ </para>
+
+ <para>Byte array and streaming based state transfer are completely API
+ transparent, interchangeable, and statically configured through a
+ standard cache configuration XML file. Refer to JGroups documentation on
+ how to change from one type of transfer to another.
+ </para>
+ </section>
+
+ <section>
+ <title>Full and partial state transfer</title>
+
+ <para>If either in-memory or persistent state transfer is enabled, a
+ full or partial state transfer will be done at various times, depending
+ on how the cache is used. "Full" state transfer refers to the transfer
+ of the state related to the entire tree -- i.e. the root node and all
+ nodes below it. A "partial" state transfer is one where just a portion
+ of the tree is transferred -- i.e. a node at a given Fqn and all nodes
+ below it.
+ </para>
+
+ <para>If either in-memory or persistent state transfer is enabled, state
+ transfer will occur at the following times:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>Initial state transfer. This occurs when the cache is first
+ started (as part of the processing of the
+ <literal>start()</literal>
+ method). This is a full state transfer. The state is retrieved from
+ the cache instance that has been operational the longest.
+ <footnote>
+ <para>The longest operating cache instance is always, in JGroups
+ terms, the coordinator.
+ </para>
+ </footnote>
+ If there is any problem receiving or integrating the state, the cache
+ will not start.
+ </para>
+
+ <para>Initial state transfer will occur unless:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>The cache's
+ <literal>InactiveOnStartup</literal>
+ property
+ is
+ <literal>true</literal>
+ . This property is used in
+ conjunction with region-based marshalling.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Buddy replication is used. See below for more on state
+ transfer with buddy replication.
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+
+ <listitem>
+ <para>Partial state transfer following region activation. When
+ region-based marshalling is used, the application needs to register
+ a specific class loader with the cache. This class loader is used
+ to unmarshall the state for a specific region (subtree) of the cache.
+ </para>
+
+ <para>After registration, the application calls
+ <literal>cache.getRegion(fqn, true).activate()</literal>
+ ,
+ which initiates a partial state transfer of the relevant subtree's
+ state. The request is first made to the oldest cache instance in the
+ cluster. However, if that instance responds with no state, it is then
+ requested from each instance in turn until one either provides state
+ or all instances have been queried.
+ </para>
+
+ <para>Typically when region-based marshalling is used, the cache's
+ <literal>InactiveOnStartup</literal>
+ property is set to
+ <literal>true</literal>
+ . This suppresses initial state transfer,
+ which would fail due to the inability to deserialize the transferred
+ state.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Buddy replication. When buddy replication is used, initial
+ state transfer is disabled. Instead, when a cache instance joins the
+ cluster, it becomes the buddy of one or more other instances, and
+ one or more other instances become its buddy. Each time an instance
+ determines it has a new buddy providing backup for it, it pushes
+ it's current state to the new buddy. This "pushing" of state to the
+ new buddy is slightly different from other forms of state transfer,
+ which are based on a "pull" approach (i.e. recipient asks for and
+ receives state). However, the process of preparing and integrating
+ the state is the same.
+ </para>
+
+ <para>This "push" of state upon buddy group formation only occurs if
+ the
+ <literal>InactiveOnStartup</literal>
+ property is set to
+ <literal>false</literal>
+ . If it is
+ <literal>true</literal>
+ , state
+ transfer amongst the buddies only occurs when the application
+ activates the region on the various members of the group.
+ </para>
+
+ <para>Partial state transfer following a region activation call is
+ slightly different in the buddy replication case as well. Instead of
+ requesting the partial state from one cache instance, and trying all
+ instances until one responds, with buddy replication the instance
+ that is activating a region will request partial state from each
+ instance for which it is serving as a backup.
+ </para>
+ </listitem>
+ </orderedlist>
+ </section>
+
+ <section>
+ <title>Transient ("in-memory") and persistent state transfer</title>
+
+ <para>The state that is acquired and integrated can consist of two basic
+ types:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>"Transient" or "in-memory" state. This consists of the actual
+ in-memory state of another cache instance - the contents of the
+ various in-memory nodes in the cache that is providing state are
+ serialized and transferred; the recipient deserializes the data,
+ creates corresponding nodes in its own in-memory tree, and populates
+ them with the transferred data.
+ </para>
+
+ <para>"In-memory" state transfer is enabled by setting the cache's
+ <literal>FetchInMemoryState</literal>
+ configuration attribute to
+ <literal>true</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>"Persistent" state. Only applicable if a non-shared cache
+ loader is used. The state stored in the state-provider cache's
+ persistent store is deserialized and transferred; the recipient
+ passes the data to its own cache loader, which persists it to the
+ recipient's persistent store.
+ </para>
+
+ <para>"Persistent" state transfer is enabled by setting a cache
+ loader's
+ <literal>fetchPersistentState</literal>
+ attribute to
+ <literal>true</literal>
+ . If multiple cache loaders are configured
+ in a chain, only one can have this property set to true; otherwise
+ you will get an exception at startup.
+ </para>
+
+ <para>Persistent state transfer with a shared cache loader does not
+ make sense, as the same persistent store that provides the data will
+ just end up receiving it. Therefore, if a shared cache loader is
+ used, the cache will not allow a persistent state transfer even if a
+ cache loader has
+ <literal>fetchPersistentState</literal>
+ set to
+ <literal>true</literal>
+ .
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>Which of these types of state transfer is appropriate depends on
+ the usage of the cache.
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>If a write-through cache loader is used, the current cache
+ state is fully represented by the persistent state. Data may have
+ been evicted from the in-memory state, but it will still be in the
+ persistent store. In this case, if the cache loader is not shared,
+ persistent state transfer is used to ensure the new cache has the
+ correct state. In-memory state can be transferred as well if the
+ desire is to have a "hot" cache -- one that has all relevant data in
+ memory when the cache begins providing service. (Note that the
+ <literal><![CDATA[<cacheloader><preload>]]></literal>
+ element in the
+ <literal>CacheLoaderConfig</literal>
+ configuration parameter can be used as well to
+ provide a "warm" or "hot" cache without requiring an in-memory state
+ transfer. This approach somewhat reduces the burden on the cache
+ instance providing state, but increases the load on the persistent
+ store on the recipient side.)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>If a cache loader is used with passivation, the full
+ representation of the state can only be obtained by combining the
+ in-memory (i.e. non-passivated) and persistent (i.e. passivated)
+ states. Therefore an in-memory state transfer is necessary. A
+ persistent state transfer is necessary if the cache loader is not
+ shared.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>If no cache loader is used and the cache is solely a
+ write-aside cache (i.e. one that is used to cache data that can also
+ be found in a persistent store, e.g. a database), whether or not
+ in-memory state should be transferred depends on whether or not a
+ "hot" cache is desired.
+ </para>
+ </listitem>
+ </orderedlist>
+ </section>
+ <section>
+ <title>Configuring State Transfer</title>
+ <para>
+ To ensure state transfer behaves as expected, it is important that all nodes in the cluster are configured
+ with
+ the same settings for persistent and transient state. This is because byte array based transfers, when
+ requested,
+ rely only on the requester's configuration while stream based transfers rely on both the requester and
+ sender's
+ configuration, and this is expected to be identical.
+ </para>
+ </section>
+ </section>
+</chapter>
Added: core/trunk/src/main/docbook/userguide/en/modules/transactions.xml
===================================================================
--- core/trunk/src/main/docbook/userguide/en/modules/transactions.xml (rev 0)
+++ core/trunk/src/main/docbook/userguide/en/modules/transactions.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,345 @@
+<chapter id="transactions">
+ <title>Transactions and Concurrency</title>
+ <section>
+ <title>Concurrent Access</title>
+
+ <para>JBoss Cache is a thread safe caching API, and uses its own efficient mechanisms of controlling concurrent
+ access. It uses a pessimistic locking scheme by default for this purpose. Optimistic locking may alternatively
+ be used, and is discussed later.
+ </para>
+
+ <section>
+ <title>Locks</title>
+ <para>Locking is done internally, on a node-level. For example when we
+ want to access "/a/b/c", a lock will be acquired for nodes "a", "b" and
+ "c". When the same transaction wants to access "/a/b/c/d", since we
+ already hold locks for "a", "b" and "c", we only need to acquire a lock
+ for "d".
+ </para>
+ <para>Lock owners are either transactions (call is made within the scope of an existing transaction)
+ or threads (no transaction associated with the call).
+ Regardless, a transaction or a thread is internally transformed into
+ an instance of
+ <literal>GlobalTransaction</literal>
+ , which is used as a globally unique identifier
+ for modifications across a cluster. E.g. when we run a two-phase commit
+ protocol across the cluster, the
+ <literal>GlobalTransaction</literal>
+ uniquely identifies a unit of work across a cluster.
+ </para>
+
+ <para>Locks can be read or write locks. Write locks serialize read and
+ write access, whereas read-only locks only serialize read access. When a
+ write lock is held, no other write or read locks can be acquired. When a
+ read lock is held, others can acquire read locks. However, to acquire
+ write locks, one has to wait until all read locks have been released. When
+ scheduled concurrently, write locks always have precedence over read
+ locks. Note that (if enabled) read locks can be upgraded to write
+ locks.
+ </para>
+
+ <para>Using read-write locks helps in the following scenario: consider a
+ tree with entries "/a/b/n1" and "/a/b/n2". With write-locks, when Tx1
+ accesses "/a/b/n1", Tx2 cannot access "/a/b/n2" until Tx1 has completed
+ and released its locks. However, with read-write locks this is possible,
+ because Tx1 acquires read-locks for "/a/b" and a read-write lock for
+ "/a/b/n1". Tx2 is then able to acquire read-locks for "/a/b" as well, plus
+ a read-write lock for "/a/b/n2". This allows for more concurrency in
+ accessing the cache.
+ </para>
+ </section>
+
+ <section>
+ <title>Pessimistic locking</title>
+ <para>By default, JBoss Cache uses pessimistic locking. Locking is not exposed directly to user. Instead, a
+ transaction isolation level which provides different locking behaviour is configurable.
+ </para>
+ <section>
+ <title>Isolation levels</title>
+ <para>JBoss Cache supports the following transaction isolation levels, analogous to database ACID isolation
+ levels. A user can configure an instance-wide isolation level of NONE, READ_UNCOMMITTED, READ_COMMITTED,
+ REPEATABLE_READ, or SERIALIZABLE. REPEATABLE_READ is the default isolation level used.
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>NONE. No transaction support is needed. There is no locking at
+ this level, e.g., users will have to manage the data integrity.
+ Implementations use no locks.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>READ_UNCOMMITTED. Data can be read anytime while write
+ operations are exclusive. Note that this level doesn't prevent the
+ so-called "dirty read" where data modified in Tx1 can be read in Tx2
+ before Tx1 commits. In other words, if you have the following
+ sequence,
+ <programlisting>
+ <![CDATA[
+ Tx1 Tx2
+ W
+ R
+]]>
+ </programlisting>
+
+ using this isolation level will not prevent Tx2 read operation.
+ Implementations typically use an exclusive lock for writes while reads
+ don't need to acquire a lock.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>READ_COMMITTED. Data can be read any time as long as there is no
+ write. This level prevents the dirty read. But it doesn’t prevent the
+ so-called ‘non-repeatable read’ where one thread reads the data twice
+ can produce different results. For example, if you have the following
+ sequence,
+ <programlisting>
+ <![CDATA[
+ Tx1 Tx2
+ R
+ W
+ R
+]]>
+ </programlisting>
+ </para>
+
+ <para>where the second read in Tx1 thread will produce different
+ result.
+ </para>
+
+ <para>Implementations usually use a read-write lock; reads succeed
+ acquiring the lock when there are only reads, writes have to wait
+ until there are no more readers holding the lock, and readers are
+ blocked acquiring the lock until there are no more writers holding the
+ lock. Reads typically release the read-lock when done, so that a
+ subsequent read to the same data has to re-acquire a read-lock; this
+ leads to nonrepeatable reads, where 2 reads of the same data might
+ return different values. Note that, the write only applies regardless
+ of transaction state (whether it has been committed or not).
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>REPEATABLE_READ. Data can be read while there is no write and
+ vice versa. This level prevents "non-repeatable read" but it does not
+ completely prevent the so-called "phantom read" where new data can be
+ inserted into the tree from another transaction. Implementations
+ typically use a read-write lock. This is the default isolation level used.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>SERIALIZABLE. Data access is synchronized with exclusive locks.
+ Only 1 writer or reader can have the lock at any given time. Locks are
+ released at the end of the transaction. Regarded as very poor for performance and
+ thread/transaction concurrency.
+ </para>
+ </listitem>
+ </orderedlist>
+
+ </section>
+
+ <section>
+ <title>Insertion and Removal of Nodes</title>
+
+ <para>
+ By default, before inserting a new node into the tree or removing an existing node from the
+ tree, JBoss Cache will only attempt to acquire a read lock on the new node's parent node.
+ This approach does not treat child nodes as an integral part of a parent node's state.
+ This approach allows greater concurrency if nodes are frequently added or removed, but
+ at a cost of lesser correctness. For use cases where greater correctness is necessary, JBoss
+ Cache provides a configuration option
+ <literal>LockParentForChildInsertRemove</literal>
+ .
+ If this is set to
+ <literal>true</literal>
+ , insertions and removals of child nodes
+ require the acquisition of a
+ <emphasis>write lock</emphasis>
+ on the parent node.
+ </para>
+ </section>
+ </section>
+
+ <section>
+ <title>Optimistic Locking</title>
+ <para>The motivation for optimistic locking is to improve concurrency. When a lot of threads have a lot of
+ contention for access to the data tree, it can be inefficient to lock portions of the tree - for reading or
+ writing - for the entire duration of a transaction as we do in pessimistic locking. Optimistic locking
+ allows for greater concurrency of threads and transactions by using a technique called data versioning,
+ explained here. Note that isolation levels (if configured) are ignored if optimistic locking is enabled.
+ </para>
+ <section>
+ <title>Architecture</title>
+ <para>Optimistic locking treats all method calls as transactional
+ <footnote>
+ <para>Because of this requirement, you must always have a transaction manager configured when using
+ optimistic locking.
+ </para>
+ </footnote>
+ . Even if you do not invoke a call within the scope of an ongoing transaction, JBoss Cache creates an
+ <emphasis>implicit transaction</emphasis>
+ and commits this transaction when the invocation completes. Each transaction
+ maintains a transaction workspace, which contains a copy of the data used within the transaction.
+ </para>
+ <para>For example, if a transaction calls
+ <literal>cache.getRoot().getChild( Fqn.fromString("/a/b/c") )</literal>
+ ,
+ nodes a, b and c are copied from the main data tree
+ and into the workspace. The data is versioned and all calls in the transaction work on the copy of the
+ data rather than the actual data. When the transaction commits, its workspace is merged back into the
+ underlying tree by matching versions. If there is a version mismatch - such as when the actual data tree
+ has a higher version than the workspace, perhaps if another transaction were to access the same data,
+ change it and commit before the first transaction can finish - the transaction throws a
+ <literal>RollbackException</literal>
+ when committing and the commit fails.
+ </para>
+ <para>Optimistic locking uses the same locks we speak of above, but the locks are only held for a very short
+ duration - at the start of a transaction to build a workspace, and when the transaction commits and has
+ to merge data back into the tree.
+ </para>
+ <para>
+ So while optimistic locking may occasionally fail if version validations fail or may run slightly slower
+ than pessimistic locking due to the inevitable overhead and extra processing of maintaining workspaces,
+ versioned data and validating on commit, it does buy you a near-SERIALIZABLE degree of data integrity
+ while maintaining a very high level of concurrency.
+ </para>
+ </section>
+ <section>
+ <title>Data Versioning</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="DataVersions.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+ <para>
+ Optimistic locking makes use of the
+ <literal>DataVersion</literal>
+ interface (and an internal and default
+ <literal>DefaultDataVersion</literal>
+ implementation to keep a track of node versioning. In certain cases,
+ where cached data is an in-memory representation of data from an external source such as a database,
+ it makes sense to align the versions used in JBoss Cache with the versions used externally. As such,
+ using the
+ <link linkend="configuration.options">options API</link>
+ , it is possible to set the
+ <literal>DataVersion</literal>
+ you wish to use on a per-invocation basis, allowing you to implement the
+ <literal>DataVersion</literal>
+ interface to hold the versioning information obtained externally before putting your data into the
+ cache.
+ </para>
+ </section>
+ <section>
+ <title>Configuration</title>
+ Optimistic locking is enabled by using the NodeLockingScheme XML attribute, and setting it to "OPTIMISTIC":
+ <programlisting>
+ <![CDATA[
+ ...
+ <!--
+ Node locking scheme:
+ OPTIMISTIC
+ PESSIMISTIC (default)
+ -->
+ <attribute name="NodeLockingScheme">OPTIMISTIC</attribute>
+ ...
+ ]]>
+ </programlisting>
+ </section>
+ </section>
+ </section>
+
+
+ <section>
+ <title>Transactional Support</title>
+
+ <para>JBoss Cache can be configured to use and participate in JTA compliant transactions. Alternatively, if
+ transaction support is disabled, it is equivalent to setting AutoCommit to
+ on where modifications are potentially
+ <footnote>
+ <para>Depending on whether interval-based asynchronous replication is used</para>
+ </footnote>
+ replicated after every change (if replication is
+ enabled).
+ </para>
+
+ <para>What JBoss Cache does on every incoming call is:</para>
+ <orderedlist>
+ <listitem>
+ <para>Retrieve the current
+ <literal>javax.transaction.Transaction</literal>
+ associated with the thread
+ </para>
+ </listitem>
+ <listitem>
+ <para>If not already done, register a
+ <literal>javax.transaction.Synchronization</literal>
+ with the transaction manager to be notified when a transaction commits
+ or is rolled back.
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ In order to do this, the cache has to be provided with a
+ reference to environment's
+ <literal>javax.transaction.TransactionManager</literal>
+ . This is usually done by configuring the cache
+ with the class name of an implementation of the
+ <literal>TransactionManagerLookup</literal>
+ interface. When the cache starts, it will create an instance of this
+ class and invoke its <literal>getTransactionManager()</literal>
+ method, which returns a reference to the
+ <literal>TransactionManager</literal>
+ .
+ </para>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="TransactionLookup.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>JBoss Cache ships with
+ <literal>JBossTransactionManagerLookup</literal>
+ and
+ <literal>GenericTransactionManagerLookup</literal>
+ . The
+ <literal>JBossTransactionManagerLookup</literal>
+ is able to bind to a running JBoss AS instance and retrieve a
+ <literal>TransactionManager</literal>
+ while the
+ <literal>GenericTransactionManagerLookup</literal>
+ is able to bind to most popular Java EE application servers and provide the same functionality. A dummy
+ implementation -
+ <literal>DummyTransactionManagerLookup</literal>
+ - is also provided, primarily for unit tests. Being a dummy, this is just for demo and testing purposes and is
+ not recommended for production use.
+ </para>
+
+ <para>
+ An alternative to configuring a <literal>TransactionManagerLookup</literal>
+ is to programatically inject a reference to the <literal>TransactionManager</literal>
+ into the <literal>Configuration</literal> object's <literal>RuntimeConfig</literal> element:
+ </para>
+
+ <programlisting>
+ TransactionManager tm = getTransactionManager(); // magic method
+ cache.getConfiguration().getRuntimeConfig().setTransactionManager(tm);
+ </programlisting>
+
+ <para>
+ Injecting the <literal>TransactionManager</literal> is the recommended
+ approach when the <literal>Configuration</literal> is built by some sort of
+ IOC container that already has a reference to the TM.
+ </para>
+
+ <para>When the transaction commits, we initiate either a one- two-phase commit
+ protocol. See
+ <link linkend="replication.tx">replicated caches and transactions</link>
+ for details.
+ </para>
+
+ </section>
+</chapter>
Added: core/trunk/src/main/java/org/jboss/cache/MyClass.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/MyClass.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/MyClass.java 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,60 @@
+package org.jboss.cache;
+
+import org.jboss.kernel.plugins.bootstrap.standalone.StandaloneBootstrap;
+
+/**
+ * // TODO: Add Javadocs
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
+ * @since 2.0.0
+ */
+public class MyClass
+{
+ private int x, y;
+
+
+ public MyClass()
+ {
+ // some dummy dependency
+ //
+
+ org.jgroups.Address addr = new org.jgroups.stack.IpAddress();
+ }
+
+ public MyClass(int x, int y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+
+ public int getX()
+ {
+ return x;
+ }
+
+ public void setX(int x)
+ {
+ this.x = x;
+ }
+
+ public int getY()
+ {
+ return y;
+ }
+
+ public void setY(int y)
+ {
+ this.y = y;
+ }
+
+ public int add()
+ {
+ return x + y;
+ }
+
+ public int multiply()
+ {
+ return x * y;
+ }
+}
Added: core/trunk/src/main/resources/replSync-service.xml
===================================================================
--- core/trunk/src/main/resources/replSync-service.xml (rev 0)
+++ core/trunk/src/main/resources/replSync-service.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Sample TreeCache Service Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<server>
+
+ <!-- ==================================================================== -->
+ <!-- Defines TreeCache configuration -->
+ <!-- ==================================================================== -->
+
+ <mbean code="org.jboss.cache.jmx.CacheJmxWrapper"
+ name="jboss.cache:service=TreeCache">
+
+ <depends>jboss:service=Naming</depends>
+ <depends>jboss:service=TransactionManager</depends>
+
+ <!--
+ Configure the TransactionManager
+ -->
+ <attribute name="TransactionManagerLookupClass">org.jboss.cache.transaction.GenericTransactionManagerLookup
+ </attribute>
+
+ <!--
+ Isolation level : SERIALIZABLE
+ REPEATABLE_READ (default)
+ READ_COMMITTED
+ READ_UNCOMMITTED
+ NONE
+ -->
+ <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
+
+ <!--
+ Valid modes are LOCAL
+ REPL_ASYNC
+ REPL_SYNC
+ INVALIDATION_ASYNC
+ INVALIDATION_SYNC
+ -->
+ <attribute name="CacheMode">REPL_SYNC</attribute>
+
+ <!--
+ Just used for async repl: use a replication queue
+ -->
+ <attribute name="UseReplQueue">false</attribute>
+
+ <!--
+ Replication interval for replication queue (in ms)
+ -->
+ <attribute name="ReplQueueInterval">0</attribute>
+
+ <!--
+ Max number of elements which trigger replication
+ -->
+ <attribute name="ReplQueueMaxElements">0</attribute>
+
+ <!-- Name of cluster. Needs to be the same for all TreeCache nodes in a
+ cluster in order to find each other.
+ -->
+ <attribute name="ClusterName">JBossCache-Cluster</attribute>
+
+ <!--Uncomment next three statements to enable JGroups multiplexer.
+This configuration is dependent on the JGroups multiplexer being
+registered in an MBean server such as JBossAS. -->
+ <!--
+ <depends>jgroups.mux:name=Multiplexer</depends>
+ <attribute name="MultiplexerService">jgroups.mux:name=Multiplexer</attribute>
+ <attribute name="MultiplexerStack">fc-fast-minimalthreads</attribute>
+ -->
+
+ <!-- JGroups protocol stack properties.
+ ClusterConfig isn't used if the multiplexer is enabled and successfully initialized.
+ -->
+ <attribute name="ClusterConfig">
+ <config>
+ <UDP mcast_addr="228.10.10.10"
+ mcast_port="45588"
+ tos="8"
+ ucast_recv_buf_size="20000000"
+ ucast_send_buf_size="640000"
+ mcast_recv_buf_size="25000000"
+ mcast_send_buf_size="640000"
+ loopback="false"
+ discard_incompatible_packets="true"
+ max_bundle_size="64000"
+ max_bundle_timeout="30"
+ use_incoming_packet_handler="true"
+ ip_ttl="2"
+ enable_bundling="false"
+ enable_diagnostics="true"
+
+ use_concurrent_stack="true"
+
+ thread_naming_pattern="pl"
+
+ thread_pool.enabled="true"
+ thread_pool.min_threads="1"
+ thread_pool.max_threads="25"
+ thread_pool.keep_alive_time="30000"
+ thread_pool.queue_enabled="true"
+ thread_pool.queue_max_size="10"
+ thread_pool.rejection_policy="Run"
+
+ oob_thread_pool.enabled="true"
+ oob_thread_pool.min_threads="1"
+ oob_thread_pool.max_threads="4"
+ oob_thread_pool.keep_alive_time="10000"
+ oob_thread_pool.queue_enabled="true"
+ oob_thread_pool.queue_max_size="10"
+ oob_thread_pool.rejection_policy="Run"/>
+
+ <PING timeout="2000" num_initial_members="3"/>
+ <MERGE2 max_interval="30000" min_interval="10000"/>
+ <FD_SOCK/>
+ <FD timeout="10000" max_tries="5" shun="true"/>
+ <VERIFY_SUSPECT timeout="1500"/>
+ <pbcast.NAKACK max_xmit_size="60000"
+ use_mcast_xmit="false" gc_lag="0"
+ retransmit_timeout="300,600,1200,2400,4800"
+ discard_delivered_msgs="true"/>
+ <UNICAST timeout="300,600,1200,2400,3600"/>
+ <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
+ max_bytes="400000"/>
+ <pbcast.GMS print_local_addr="true" join_timeout="5000"
+ join_retry_timeout="2000" shun="false"
+ view_bundling="true" view_ack_collection_timeout="5000"/>
+ <FRAG2 frag_size="60000"/>
+ <pbcast.STREAMING_STATE_TRANSFER use_reading_thread="true"/>
+ <!-- <pbcast.STATE_TRANSFER/> -->
+ <pbcast.FLUSH timeout="0"/>
+ </config>
+ </attribute>
+
+
+ <!--
+ Whether or not to fetch state on joining a cluster
+ NOTE this used to be called FetchStateOnStartup and has been renamed to be more descriptive.
+ -->
+ <attribute name="FetchInMemoryState">true</attribute>
+
+ <!--
+ The max amount of time (in milliseconds) we wait until the
+ state (ie. the contents of the cache) are retrieved from
+ existing members in a clustered environment
+ -->
+ <attribute name="StateRetrievalTimeout">15000</attribute>
+
+ <!--
+ Number of milliseconds to wait until all responses for a
+ synchronous call have been received.
+ -->
+ <attribute name="SyncReplTimeout">15000</attribute>
+
+ <!-- Max number of milliseconds to wait for a lock acquisition -->
+ <attribute name="LockAcquisitionTimeout">10000</attribute>
+
+ <!--
+ Indicate whether to use region based marshalling or not. Set this to true if you are running under a scoped
+ class loader, e.g., inside an application server. Default is "false".
+ -->
+ <attribute name="UseRegionBasedMarshalling">true</attribute>
+ </mbean>
+
+
+ <!-- Uncomment to get a graphical view of the TreeCache MBean above -->
+ <!-- <mbean code="org.jboss.cache.TreeCacheView" name="jboss.cache:service=TreeCacheView">-->
+ <!-- <depends>jboss.cache:service=TreeCache</depends>-->
+ <!-- <attribute name="CacheService">jboss.cache:service=TreeCache</attribute>-->
+ <!-- </mbean>-->
+
+
+</server>
Added: core/trunk/src/test/java/org/jboss/cache/MyClassTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/MyClassTest.java (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/MyClassTest.java 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,48 @@
+package org.jboss.cache;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.AfterClass;
+
+/**
+ * // TODO: Add Javadocs
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
+ * @since 2.0.0
+ */
+@Test
+public class MyClassTest
+{
+ private MyClass mc = null;
+
+ @BeforeTest
+ public void create()
+ {
+ mc = new MyClass();
+ }
+
+ @AfterClass
+ public void destroy()
+ {
+ mc = null;
+ }
+
+ @Test
+ public void multiplication()
+ {
+ mc.setX(5);
+ mc.setY(2);
+
+ assert 10 == mc.multiply();
+ }
+
+ @Test
+ public void addition()
+ {
+ mc.setX(5);
+ mc.setY(2);
+
+ assert 7 == mc.add();
+ }
+
+}
Added: core/trunk/src/test/resources/replSync-service-test.xml
===================================================================
--- core/trunk/src/test/resources/replSync-service-test.xml (rev 0)
+++ core/trunk/src/test/resources/replSync-service-test.xml 2007-08-14 16:31:29 UTC (rev 4249)
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Sample TreeCache Service Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<server>
+
+ <!-- ==================================================================== -->
+ <!-- Defines TreeCache configuration -->
+ <!-- ==================================================================== -->
+
+ <mbean code="org.jboss.cache.jmx.CacheJmxWrapper"
+ name="jboss.cache:service=TreeCache">
+
+ <depends>jboss:service=Naming</depends>
+ <depends>jboss:service=TransactionManager</depends>
+
+ <!--
+ Configure the TransactionManager
+ -->
+ <attribute name="TransactionManagerLookupClass">org.jboss.cache.transaction.GenericTransactionManagerLookup
+ </attribute>
+
+ <!--
+ Isolation level : SERIALIZABLE
+ REPEATABLE_READ (default)
+ READ_COMMITTED
+ READ_UNCOMMITTED
+ NONE
+ -->
+ <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
+
+ <!--
+ Valid modes are LOCAL
+ REPL_ASYNC
+ REPL_SYNC
+ INVALIDATION_ASYNC
+ INVALIDATION_SYNC
+ -->
+ <attribute name="CacheMode">REPL_SYNC</attribute>
+
+ <!--
+ Just used for async repl: use a replication queue
+ -->
+ <attribute name="UseReplQueue">false</attribute>
+
+ <!--
+ Replication interval for replication queue (in ms)
+ -->
+ <attribute name="ReplQueueInterval">0</attribute>
+
+ <!--
+ Max number of elements which trigger replication
+ -->
+ <attribute name="ReplQueueMaxElements">0</attribute>
+
+ <!-- Name of cluster. Needs to be the same for all TreeCache nodes in a
+ cluster in order to find each other.
+ -->
+ <attribute name="ClusterName">JBossCache-Cluster</attribute>
+
+ <!--Uncomment next three statements to enable JGroups multiplexer.
+This configuration is dependent on the JGroups multiplexer being
+registered in an MBean server such as JBossAS. -->
+ <!--
+ <depends>jgroups.mux:name=Multiplexer</depends>
+ <attribute name="MultiplexerService">jgroups.mux:name=Multiplexer</attribute>
+ <attribute name="MultiplexerStack">fc-fast-minimalthreads</attribute>
+ -->
+
+ <!-- JGroups protocol stack properties.
+ ClusterConfig isn't used if the multiplexer is enabled and successfully initialized.
+ -->
+ <attribute name="ClusterConfig">
+ <config>
+ <UDP mcast_addr="228.10.10.10"
+ mcast_port="45588"
+ tos="8"
+ ucast_recv_buf_size="20000000"
+ ucast_send_buf_size="640000"
+ mcast_recv_buf_size="25000000"
+ mcast_send_buf_size="640000"
+ loopback="false"
+ discard_incompatible_packets="true"
+ max_bundle_size="64000"
+ max_bundle_timeout="30"
+ use_incoming_packet_handler="true"
+ ip_ttl="2"
+ enable_bundling="false"
+ enable_diagnostics="true"
+
+ use_concurrent_stack="true"
+
+ thread_naming_pattern="pl"
+
+ thread_pool.enabled="true"
+ thread_pool.min_threads="1"
+ thread_pool.max_threads="25"
+ thread_pool.keep_alive_time="30000"
+ thread_pool.queue_enabled="true"
+ thread_pool.queue_max_size="10"
+ thread_pool.rejection_policy="Run"
+
+ oob_thread_pool.enabled="true"
+ oob_thread_pool.min_threads="1"
+ oob_thread_pool.max_threads="4"
+ oob_thread_pool.keep_alive_time="10000"
+ oob_thread_pool.queue_enabled="true"
+ oob_thread_pool.queue_max_size="10"
+ oob_thread_pool.rejection_policy="Run"/>
+
+ <PING timeout="2000" num_initial_members="3"/>
+ <MERGE2 max_interval="30000" min_interval="10000"/>
+ <FD_SOCK/>
+ <FD timeout="10000" max_tries="5" shun="true"/>
+ <VERIFY_SUSPECT timeout="1500"/>
+ <pbcast.NAKACK max_xmit_size="60000"
+ use_mcast_xmit="false" gc_lag="0"
+ retransmit_timeout="300,600,1200,2400,4800"
+ discard_delivered_msgs="true"/>
+ <UNICAST timeout="300,600,1200,2400,3600"/>
+ <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
+ max_bytes="400000"/>
+ <pbcast.GMS print_local_addr="true" join_timeout="5000"
+ join_retry_timeout="2000" shun="false"
+ view_bundling="true" view_ack_collection_timeout="5000"/>
+ <FRAG2 frag_size="60000"/>
+ <pbcast.STREAMING_STATE_TRANSFER use_reading_thread="true"/>
+ <!-- <pbcast.STATE_TRANSFER/> -->
+ <pbcast.FLUSH timeout="0"/>
+ </config>
+ </attribute>
+
+
+ <!--
+ Whether or not to fetch state on joining a cluster
+ NOTE this used to be called FetchStateOnStartup and has been renamed to be more descriptive.
+ -->
+ <attribute name="FetchInMemoryState">true</attribute>
+
+ <!--
+ The max amount of time (in milliseconds) we wait until the
+ state (ie. the contents of the cache) are retrieved from
+ existing members in a clustered environment
+ -->
+ <attribute name="StateRetrievalTimeout">15000</attribute>
+
+ <!--
+ Number of milliseconds to wait until all responses for a
+ synchronous call have been received.
+ -->
+ <attribute name="SyncReplTimeout">15000</attribute>
+
+ <!-- Max number of milliseconds to wait for a lock acquisition -->
+ <attribute name="LockAcquisitionTimeout">10000</attribute>
+
+ <!--
+ Indicate whether to use region based marshalling or not. Set this to true if you are running under a scoped
+ class loader, e.g., inside an application server. Default is "false".
+ -->
+ <attribute name="UseRegionBasedMarshalling">true</attribute>
+ </mbean>
+
+
+ <!-- Uncomment to get a graphical view of the TreeCache MBean above -->
+ <!-- <mbean code="org.jboss.cache.TreeCacheView" name="jboss.cache:service=TreeCacheView">-->
+ <!-- <depends>jboss.cache:service=TreeCache</depends>-->
+ <!-- <attribute name="CacheService">jboss.cache:service=TreeCache</attribute>-->
+ <!-- </mbean>-->
+
+
+</server>
17 years, 4 months
JBoss Cache SVN: r4248 - core/trunk.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2007-08-14 12:29:26 -0400 (Tue, 14 Aug 2007)
New Revision: 4248
Added:
core/trunk/src-old/
Removed:
core/trunk/src/
Log:
Migrating to SVN
Copied: core/trunk/src-old (from rev 4245, core/trunk/src)
17 years, 4 months
JBoss Cache SVN: r4247 - in pojo/trunk: assembly and 25 other directories.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2007-08-14 12:26:14 -0400 (Tue, 14 Aug 2007)
New Revision: 4247
Added:
pojo/trunk/README-Maven.txt
pojo/trunk/assembly/
pojo/trunk/assembly/all.xml
pojo/trunk/assembly/bin.xml
pojo/trunk/assembly/doc.xml
pojo/trunk/pom.xml
pojo/trunk/src/
pojo/trunk/src/main/
pojo/trunk/src/main/docbook/
pojo/trunk/src/main/docbook/css/
pojo/trunk/src/main/docbook/css/css/
pojo/trunk/src/main/docbook/css/css/html.css
pojo/trunk/src/main/docbook/faq/
pojo/trunk/src/main/docbook/faq/en/
pojo/trunk/src/main/docbook/faq/en/master.xml
pojo/trunk/src/main/docbook/images/
pojo/trunk/src/main/docbook/images/images/
pojo/trunk/src/main/docbook/images/images/classes.png
pojo/trunk/src/main/docbook/images/images/demoAddress.png
pojo/trunk/src/main/docbook/images/images/demoAddressInternal.png
pojo/trunk/src/main/docbook/images/images/demoJoe.png
pojo/trunk/src/main/docbook/images/images/demogui.gif
pojo/trunk/src/main/docbook/images/images/get.gif
pojo/trunk/src/main/docbook/images/images/get.png
pojo/trunk/src/main/docbook/images/images/graph.gif
pojo/trunk/src/main/docbook/images/images/guiAddress.png
pojo/trunk/src/main/docbook/images/images/guiJoe.png
pojo/trunk/src/main/docbook/images/images/guiJoeAddress.png
pojo/trunk/src/main/docbook/images/images/guiJoeInternal.png
pojo/trunk/src/main/docbook/images/images/guiMary.png
pojo/trunk/src/main/docbook/images/images/guiMaryAddress.png
pojo/trunk/src/main/docbook/images/images/guiMaryInternal.png
pojo/trunk/src/main/docbook/images/images/map.gif
pojo/trunk/src/main/docbook/images/images/map.png
pojo/trunk/src/main/docbook/images/images/object_split.jpg
pojo/trunk/src/main/docbook/images/images/pojocache_architecture.png
pojo/trunk/src/main/docbook/images/images/reference.png
pojo/trunk/src/main/docbook/images/images/set.gif
pojo/trunk/src/main/docbook/images/images/set.png
pojo/trunk/src/main/docbook/tutorial/
pojo/trunk/src/main/docbook/tutorial/en/
pojo/trunk/src/main/docbook/tutorial/en/master.xml
pojo/trunk/src/main/docbook/userguide/
pojo/trunk/src/main/docbook/userguide/en/
pojo/trunk/src/main/docbook/userguide/en/master.xml
pojo/trunk/src/main/docbook/userguide/en/modules/
pojo/trunk/src/main/docbook/userguide/en/modules/architecture.xml
pojo/trunk/src/main/docbook/userguide/en/modules/basic_api.xml
pojo/trunk/src/main/docbook/userguide/en/modules/cache_loaders.xml
pojo/trunk/src/main/docbook/userguide/en/modules/compatibility.xml
pojo/trunk/src/main/docbook/userguide/en/modules/configuration.xml
pojo/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml
pojo/trunk/src/main/docbook/userguide/en/modules/deployment.xml
pojo/trunk/src/main/docbook/userguide/en/modules/eviction_policies.xml
pojo/trunk/src/main/docbook/userguide/en/modules/introduction.xml
pojo/trunk/src/main/docbook/userguide/en/modules/jmx_reference.xml
pojo/trunk/src/main/docbook/userguide/en/modules/preface.xml
pojo/trunk/src/main/docbook/userguide/en/modules/replication.xml
pojo/trunk/src/main/docbook/userguide/en/modules/transactions.xml
pojo/trunk/src/main/java/
pojo/trunk/src/main/java/org/
pojo/trunk/src/main/java/org/jboss/
pojo/trunk/src/main/java/org/jboss/cache/
pojo/trunk/src/main/java/org/jboss/cache/MyClass.java
pojo/trunk/src/main/resources/
pojo/trunk/src/main/resources/replSync-service.xml
pojo/trunk/src/test/
pojo/trunk/src/test/java/
pojo/trunk/src/test/java/org/
pojo/trunk/src/test/java/org/jboss/
pojo/trunk/src/test/java/org/jboss/cache/
pojo/trunk/src/test/java/org/jboss/cache/MyClassTest.java
pojo/trunk/src/test/resources/
pojo/trunk/src/test/resources/replSync-service-test.xml
Log:
POJO edition of JBoss Cache
Added: pojo/trunk/README-Maven.txt
===================================================================
--- pojo/trunk/README-Maven.txt (rev 0)
+++ pojo/trunk/README-Maven.txt 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,50 @@
+Working with Maven
+------------------
+
+Requirements:
+
+* Java 5.0 and above
+* Maven 2.x
+
+Typical lifecycle phases
+------------------------
+
+Maven will create a target/ directory under the root for the creation of
+output at every stage.
+
+* mvn clean: cleans out any old builds and binaries
+
+* mvn compile: compiles java source code.
+
+* mvn test: runs the TestNG unit test suite on the compiled code. Will also compile the tests.
+
+* mvn package: packages the module as a jar file and builds the javadocs and user documentation from docbook sources.
+
+* mvn install: will install the artifacts in your local repo for use by other projects (such as JBoss Cache POJO edition which depends on JBoss Cache Core). Will also use Maven's assembly plugin to build ZIP files for download (in target/distribution)
+
+* mvn deploy: will build and deploy the project to the JBoss snapshots repository. Note that you should have your WebDAV username and password set up. (Deploys snapshots to http://snapshots.jboss.org/maven2/org/jboss/cache/)
+
+
+Setting up your WebDAV username and password to deploy project snapshots
+------------------------------------------------------------------------
+
+You will also have to configure maven to use your username and password to access this repository. For this, you will have to modify the servers section of maven settings file ($MAVEN_HOME/conf/settings.xml, or ~/.m2/settings.xml). Something similar to the following should be added:
+
+ <servers>
+...
+ <server>
+ <id>snapshots.jboss.org</id>
+ <username>webdav-user</username>
+ <password>webdav-pass</password>
+ </server>
+ </servers>
+
+
+Integration with CruiseControl
+------------------------------
+
+CruiseControl should do the following:
+
+* Go into core/code
+* Run "mvn clean site" - will clean and run tests, and then prepare reports. In addition to unit tests, this project is set up to run FindBugs, PMD, jxr, and a bunch of other code analysis tools and provide a report in target/site/project-reports.html - which should be linked from the CruiseControl summary page.
+
Added: pojo/trunk/assembly/all.xml
===================================================================
--- pojo/trunk/assembly/all.xml (rev 0)
+++ pojo/trunk/assembly/all.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,74 @@
+<assembly>
+ <id>all</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>true</includeBaseDirectory>
+
+ <fileSets>
+
+ <!-- code -->
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory/>
+ <includes>
+ <include>*.jar</include>
+ </includes>
+ </fileSet>
+
+ <!-- resources -->
+ <fileSet>
+ <directory>src/main/resources</directory>
+ <outputDirectory>etc</outputDirectory>
+ </fileSet>
+
+ <!-- srcs -->
+ <fileSet>
+ <directory>src/main/java</directory>
+ <outputDirectory>src</outputDirectory>
+ </fileSet>
+
+ <!-- tests -->
+ <fileSet>
+ <directory>src/test/java</directory>
+ <outputDirectory>test</outputDirectory>
+ </fileSet>
+
+ <!-- test resources -->
+ <fileSet>
+ <directory>src/test/resources</directory>
+ <outputDirectory>test</outputDirectory>
+ </fileSet>
+
+ <!-- EULAs and license files -->
+ <fileSet>
+ <directory>doc</directory>
+ <outputDirectory/>
+ <includes>
+ <include>*.txt</include>
+ </includes>
+ </fileSet>
+
+ <!-- docs -->
+ <fileSet>
+ <directory>target/site/apidocs</directory>
+ <outputDirectory>doc/apidocs</outputDirectory>
+ </fileSet>
+
+ <fileSet>
+ <directory>target/docbook</directory>
+ <outputDirectory>doc/</outputDirectory>
+ </fileSet>
+ </fileSets>
+
+ <dependencySets>
+ <dependencySet>
+ <outputDirectory>lib</outputDirectory>
+ <outputFileNameMapping>${artifactId}.${extension}</outputFileNameMapping>
+ <unpack>false</unpack>
+ <scope>runtime</scope>
+ </dependencySet>
+ </dependencySets>
+</assembly>
Added: pojo/trunk/assembly/bin.xml
===================================================================
--- pojo/trunk/assembly/bin.xml (rev 0)
+++ pojo/trunk/assembly/bin.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,46 @@
+<assembly>
+ <id>bin</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>true</includeBaseDirectory>
+
+ <fileSets>
+ <!-- code -->
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory/>
+ <includes>
+ <include>*.jar</include>
+ </includes>
+ </fileSet>
+
+ <!-- resources -->
+ <fileSet>
+ <directory>src/main/resources</directory>
+ <outputDirectory>etc</outputDirectory>
+ </fileSet>
+
+ <!-- EULAs and license files -->
+ <fileSet>
+ <directory>doc</directory>
+ <outputDirectory/>
+ <includes>
+ <include>*.txt</include>
+ </includes>
+ </fileSet>
+
+ </fileSets>
+
+ <dependencySets>
+ <dependencySet>
+ <outputDirectory>lib</outputDirectory>
+ <outputFileNameMapping>${artifactId}.${extension}</outputFileNameMapping>
+ <unpack>false</unpack>
+ <scope>runtime</scope>
+ </dependencySet>
+ </dependencySets>
+
+</assembly>
Added: pojo/trunk/assembly/doc.xml
===================================================================
--- pojo/trunk/assembly/doc.xml (rev 0)
+++ pojo/trunk/assembly/doc.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,32 @@
+<assembly>
+ <id>doc</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>true</includeBaseDirectory>
+
+ <fileSets>
+ <!-- EULAs and license files -->
+ <fileSet>
+ <directory>doc</directory>
+ <outputDirectory/>
+ <includes>
+ <include>*.txt</include>
+ </includes>
+ </fileSet>
+
+ <!-- docs -->
+ <fileSet>
+ <directory>target/site/apidocs</directory>
+ <outputDirectory>doc/apidocs</outputDirectory>
+ </fileSet>
+
+ <fileSet>
+ <directory>target/docbook</directory>
+ <outputDirectory>doc/</outputDirectory>
+ </fileSet>
+ </fileSets>
+
+</assembly>
Added: pojo/trunk/pom.xml
===================================================================
--- pojo/trunk/pom.xml (rev 0)
+++ pojo/trunk/pom.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,193 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <properties>
+ <jbosscache-pojo-version>2.1.0-SNAPSHOT</jbosscache-pojo-version>
+ </properties>
+ <parent>
+ <groupId>org.jboss.cache</groupId>
+ <artifactId>jbosscache-common-parent</artifactId>
+ <version>1.0</version>
+ </parent>
+ <groupId>org.jboss.cache</groupId>
+ <artifactId>jbosscache-pojo</artifactId>
+ <version>${jbosscache-pojo-version}</version>
+ <name>JBoss Cache - POJO Edition</name>
+ <description>JBoss Cache - POJO Edition</description>
+ <packaging>jar</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.cache</groupId>
+ <artifactId>jbosscache-core</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.2-beta-1</version>
+ <executions>
+ <execution>
+ <id>assemble</id>
+ <phase>install</phase>
+ <goals>
+ <goal>attached</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly/bin.xml</descriptor>
+ <descriptor>assembly/doc.xml</descriptor>
+ <descriptor>assembly/all.xml</descriptor>
+ </descriptors>
+ <finalName>${artifactId}-${jbosscache-pojo-version}</finalName>
+ <outputDirectory>target/distribution</outputDirectory>
+ <workDirectory>target/assembly/work</workDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <!-- the docbook generation plugin for the user guide -->
+ <plugin>
+ <groupId>org.jboss.maven.plugins</groupId>
+ <artifactId>maven-jdocbook-plugin</artifactId>
+ <version>2.0.0</version>
+ <extensions>true</extensions>
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.cache</groupId>
+ <artifactId>jbosscache-doc-xslt-support</artifactId>
+ <version>1.0</version>
+ </dependency>
+ </dependencies>
+ <executions>
+
+ <!-- The User Guide-->
+ <execution>
+ <id>userguide_en</id>
+ <phase>package</phase>
+ <goals>
+ <goal>resources</goal>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <sourceDocumentName>master.xml</sourceDocumentName>
+ <sourceDirectory>${basedir}/src/main/docbook/userguide/en</sourceDirectory>
+ <imageResource>
+ <directory>${basedir}/src/main/docbook/images</directory>
+ </imageResource>
+ <cssResource>
+ <directory>${basedir}/src/main/docbook/css</directory>
+ </cssResource>
+ <targetDirectory>${basedir}/target/docbook/userguide_en</targetDirectory>
+ <formats>
+ <format>
+ <formatName>pdf</formatName>
+ <stylesheetResource>classpath:/standard/fopdf.xsl</stylesheetResource>
+ <finalName>userguide_en.pdf</finalName>
+ </format>
+ <format>
+ <formatName>html</formatName>
+ <stylesheetResource>classpath:/standard/html_chunk.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ </format>
+ <format>
+ <formatName>html_single</formatName>
+ <stylesheetResource>classpath:/standard/html.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ </format>
+ </formats>
+ <options>
+ <xincludeSupported>false</xincludeSupported>
+ </options>
+ </configuration>
+ </execution>
+
+ <!-- The Tutorial -->
+ <execution>
+ <id>tutorial_en</id>
+ <phase>package</phase>
+ <goals>
+ <goal>resources</goal>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <sourceDocumentName>master.xml</sourceDocumentName>
+ <sourceDirectory>${basedir}/src/main/docbook/tutorial/en</sourceDirectory>
+ <imageResource>
+ <directory>${basedir}/src/main/docbook/images</directory>
+ </imageResource>
+ <cssResource>
+ <directory>${basedir}/src/main/docbook/css</directory>
+ </cssResource>
+ <targetDirectory>${basedir}/target/docbook/tutorial_en</targetDirectory>
+ <formats>
+ <format>
+ <formatName>pdf</formatName>
+ <stylesheetResource>classpath:/standard/fopdf.xsl</stylesheetResource>
+ <finalName>tutorial_en.pdf</finalName>
+ </format>
+ <format>
+ <formatName>html</formatName>
+ <stylesheetResource>classpath:/standard/html_chunk.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ </format>
+ <format>
+ <formatName>html_single</formatName>
+ <stylesheetResource>classpath:/standard/html.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ </format>
+ </formats>
+ <options>
+ <xincludeSupported>false</xincludeSupported>
+ </options>
+ </configuration>
+ </execution>
+
+ <!-- the FAQs -->
+ <execution>
+ <id>faq_en</id>
+ <phase>package</phase>
+ <goals>
+ <goal>resources</goal>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <sourceDocumentName>master.xml</sourceDocumentName>
+ <sourceDirectory>${basedir}/src/main/docbook/faq/en</sourceDirectory>
+ <imageResource>
+ <directory>${basedir}/src/main/docbook/images</directory>
+ </imageResource>
+ <cssResource>
+ <directory>${basedir}/src/main/docbook/css</directory>
+ </cssResource>
+ <targetDirectory>${basedir}/target/docbook/faq_en</targetDirectory>
+ <formats>
+ <format>
+ <formatName>pdf</formatName>
+ <stylesheetResource>classpath:/standard/fopdf.xsl</stylesheetResource>
+ <finalName>faq_en.pdf</finalName>
+ </format>
+ <format>
+ <formatName>html</formatName>
+ <stylesheetResource>classpath:/standard/html_chunk.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ </format>
+ <format>
+ <formatName>html_single</formatName>
+ <stylesheetResource>classpath:/standard/html.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ </format>
+ </formats>
+ <options>
+ <xincludeSupported>false</xincludeSupported>
+ </options>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
Added: pojo/trunk/src/main/docbook/css/css/html.css
===================================================================
--- pojo/trunk/src/main/docbook/css/css/html.css (rev 0)
+++ pojo/trunk/src/main/docbook/css/css/html.css 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,168 @@
+* {
+ font-family: sans-serif;
+ font-size: 14px;
+}
+
+A {
+ color: #0000CC;
+}
+
+A:active {
+ color: #0000CC;
+}
+
+A:visited {
+ color: #0000CC;
+}
+
+P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
+ color: #000000;
+}
+
+TD, TH, SPAN {
+ color: #000000;
+}
+
+BLOCKQUOTE {
+ margin-right: 0px;
+}
+
+H1, H2, H3, H4, H5, H6 {
+ color: #003399; /*font-weight: 500;*/
+/*margin-top: 10px;*/
+/*padding-top: 5px;*/
+}
+
+.title {
+ margin-top: 10px;
+ padding-top: 5px;
+ font-weight: bold;
+}
+
+.subtitle {
+ margin-top: 10px;
+ padding-top: 5px;
+ font-style: italic;
+ font-weight: normal;
+}
+
+H1 {
+ font-size: 180%;
+}
+
+H2 {
+ font-size: 140%;
+}
+
+H3 {
+ font-size: 120%;
+}
+
+H4 {
+ font-size: 100%;
+}
+
+H5 {
+ font-size: 100%;
+}
+
+H6 {
+ font-size: 100%;
+}
+
+TABLE {
+ border-collapse: collapse;
+ border-spacing: 0; /*border: 1px dashed #CCCCCC;*/
+ empty-cells: hide;
+ width: 100%
+}
+
+TD {
+ padding: 4pt;
+}
+
+TT {
+ font-size: 100%;
+ color: #111111;
+ font-family: monospace;
+}
+
+PRE {
+ font-size: 100%;
+ padding: 5px;
+ border-style: solid;
+ border-width: 1px;
+ border-color: #CCCCCC;
+ background-color: #F4F4F4;
+ font-family: monospace;
+ width: auto;
+}
+
+HR {
+ width: 100%;
+ height: 1px;
+ background-color: #CCCCCC;
+ border-width: 0px;
+ padding: 0px;
+ color: #CCCCCC;
+}
+
+.term {
+ font-weight: bold;
+}
+
+.note {
+ padding-bottom: 5px;
+ padding-left: 5px;
+ padding-right: 5px;
+ background-color: #FFFFCC;
+}
+
+.warning {
+ padding-bottom: 5px;
+ padding-left: 5px;
+ padding-right: 5px;
+ background-color: #FBDADA;
+}
+
+.releaseinfo {
+ font-size: 100%;
+ font-weight: bold;
+}
+
+.pubdate, .copyright {
+ font-size: 80%;
+ font-style: italic;
+}
+
+.email {
+ font-family: sans-serif;
+ padding-left: 40px;
+ padding-right: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+ font-size: 10pt;
+ margin: 0 0 0 0;
+
+}
+
+.firstname {
+ font-weight: bold;
+ margin: 0 0 0 0;
+ padding: 0 0 0 0;
+ padding-left: 20px;
+ font-size: 10pt;
+}
+
+.surname {
+ font-weight: bold;
+ margin: 0 0 0 0;
+ padding: 0 0 0 0;
+ font-size: 10pt;
+}
+
+.author {
+ padding: 0 0 0 0;
+ margin: 0 0 0 0;
+}
+
Added: pojo/trunk/src/main/docbook/faq/en/master.xml
===================================================================
--- pojo/trunk/src/main/docbook/faq/en/master.xml (rev 0)
+++ pojo/trunk/src/main/docbook/faq/en/master.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,805 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "../../../../docbook-support/support/docbook-dtd/docbookx.dtd"
+ >
+<article class="faq" lang="en">
+ <articleinfo>
+ <title>Frequently Asked Questions about PojoCache</title>
+ <releaseinfo>Release 2.0.0</releaseinfo>
+ <pubdate>June 2007</pubdate>
+
+ <author>
+ <firstname>Ben</firstname>
+ <surname>Wang</surname>
+ <email>ben.wang(a)jboss.com</email>
+ </author>
+ <author>
+ <firstname>Scott</firstname>
+ <surname>Marlow</surname>
+ <email>smarlow(a)novell.com</email>
+ </author>
+
+ </articleinfo>
+
+ <para>These are frequently asked questions regarding Pojocache.</para>
+
+ <qandaset defaultlabel="qanda">
+ <title>General Information</title>
+
+ <qandaentry>
+ <question id="a49">
+ <para>What is PojoCache?</para>
+ </question>
+
+ <answer>
+ <para>PojoCache is a fine-grained field-level replicated and
+ transactional POJO (plain old Java object) cache. By POJO, we mean
+ that the cache: 1) automatically manages object mapping and
+ relationship for a client under both local and replicated cache
+ mode, 2) provides support for inheritance relationship between
+ "aspectized" POJOs. By leveraging the dynamic AOP in JBossAop, it is
+ able to map a complex object into the cache store, preserve and
+ manage the object relationship behind the scene. During replication
+ mode, it performs fine-granularity (i.e., on a per-field basis)
+ update, and thus has the potential to boost cache performance and
+ minimize network traffic.
+ </para>
+
+ <para>From a user perspective, once your POJO is managed by the
+ cache, all cache operations are transparent. Therefore, all the
+ usual in-VM POJO method semantics are still preserved, providing
+ ease of use. For example, if a POJO has been put in PojoCache (by
+ calling
+ <literal>attach</literal>
+ , for example), then any POJO get/set
+ method will be
+ intercepted by PojoCache to provide the data from the
+ cache.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a1">
+ <para>What is the relationship between Cache and PojoCache?</para>
+ </question>
+
+ <answer>
+ <para>The core JBoss Cache library
+ <literal>Cache</literal>
+ is a traditional generic distributed cache system.
+ PojoCache uses Cache as the underlying distributed state system to achieve POJO caching. It uses Cache as
+ a
+ delegate. As a result, all the replication aspects are configured with the Cache configuration XML.
+ Additionally, PojoCache also has API to expose the Cache interface (via
+ <literal>getCache()</literal>
+ API).
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a52">
+ <para>What is the difference between Cache and
+ PojoCache?
+ </para>
+ </question>
+
+ <answer>
+ <para>Think of PojoCache as a Cache on steroids. :-)
+ Seriously, both are cache stores-- one is a generic cache and the other other one POJO Cache.
+ However, while Cache only
+ provides pure object reference storage (e.g.,
+ <literal>put(FQN fqn,
+ Object key, Object value)
+ </literal>
+ ), PojoCache goes beyond that
+ and performs fine-grained field level replication object mapping and
+ relationship management for a user behind the scenes. As a result,
+ if you have complex object systems that you would like to cache, you
+ can have PojoCache manage it for you. You simply treat your
+ object systems as they are residing in-memory, e.g., use your
+ regular POJO methods without worrying about cache management.
+ Furthermore, this is true in replication mode as well.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a521">
+ <para>How does PojoCache work then?</para>
+ </question>
+
+ <answer>
+ <para>PojoCache uses the so-called AOP technology (aspect oriented programming) to do field level
+ interception. Currently, it uses
+ <literal>JBoss Aop</literal>
+ library to do it.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a522">
+ <para>What's changed between 1.x and 2.x release then?</para>
+ </question>
+
+ <answer>
+ <para>Starting in 2.0 release, we have a separate library for PojoCache,
+ <literal>pojocache.jar</literal>
+ that
+ is extra to the core
+ <literal>jboss-cache.jar</literal>
+ . Since we uses Cache as a delegate, user
+ will need to have a regular xml to configure the core Cache functionality (e.g., replication and locking
+ aspect). In addition, there is also the
+ <literal>pojocache-aop.xml</literal>
+ that specifies the PojoCache
+ interceptor stack (that can be left as default).
+ </para>
+ <para>Additionally, here are the changed features:
+ <itemizedlist>
+ <listitem>
+ <para>New APIs. It replaces
+ <literal>putObject, removeObject, and get</literal>
+ with
+ <literal>attach, detach, and find</literal>
+ .
+ </para>
+ </listitem>
+ <listitem>
+ <para>New POJO based events that a user can subscribe to.</para>
+ </listitem>
+ <listitem>
+ <para>New configuration pojocache-aop.xml specifically for PojoCache, in addition to
+ the regular cache-service.xml for the delegating Cache.
+ </para>
+ </listitem>
+ <listitem>
+ <para>New package namespace (
+ <literal>org.jboss.cache.pojo)</literal>
+ for PojoCache.
+ The previous
+ <literal>org.jboss.cache.aop</literal>
+ space has been deprecated.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a53">
+ <para>What are the steps to use the PojoCache feature?</para>
+ </question>
+
+ <answer>
+ <para>In order to use PojoCache, you will need to:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>prepare POJO. You can do either via xml declaration or JDK50 annotation.
+ This is the step to declare your POJO such that it will be instrumented by
+ <literal>JBoss Aop</literal>
+ .
+ </para>
+ </listitem>
+ <listitem>
+ <para>instrumentation. You will need to instrument your POJO either at compile- or load-time.
+ If you do it during compile-time, you use so-called an aop pre-compiler (aopc) to do bytecode
+ manipulation.
+ If you do it via load-time, however, you need either a special system class loader or, in JDK50,
+ you can
+ use the javaagent option. Either way,
+ <literal>JBoss Aop</literal>
+ will byte code manipulate your POJO
+ class such that all field access can be intercepted.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>So if you use JDK50, for example, with annotation and load-time instrumentation, then you won't need
+ any pre-processing step to use PojoCache. For a full example, please refer to the distro examples
+ directory.
+ There are numerous PojoCache examples that uses different options.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a541">
+ <para>What is the JDK version required to run PojoCache 2.x?</para>
+ </question>
+
+ <answer>
+ <para>PojoCache 2.x requires JDK5.0 since it uses the annotation extensively.</para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a542">
+ <para>Can I run PojoCache as a standalone mode?</para>
+ </question>
+
+ <answer>
+ <para>Yes, same as the core Cache library, you can run PojoCache either as a standalone or
+ inside an application server.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a543">
+ <para>What is the JBoss AS recommended version to run PojoCache 2.x?</para>
+ </question>
+
+ <answer>
+ <para>PojoCache can be run either in AS4.0.5 (and up) and 5.0. But either way, it will require
+ JDK5.0 though.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a56">
+ <para>Can I pre-compile the aop classes such that I don't need to
+ use the system classloader and jboss-aop configuration xml during runtime?
+ </para>
+ </question>
+
+ <answer>
+ <para>Yes. The latest versions of JBossCache have a pre-compiler
+ option called
+ <literal>aopc</literal>
+ . You can use this option to
+ pre-compile your "aspectized" POJO. Once the classes have been byte
+ code generated, they can be treated as regular class files, i.e.,
+ you will not need to include any
+ <literal>jboss-aop.xml</literal>
+ that specifies the advisable POJO and to specify the JBossAop system
+ class loader.
+ </para>
+
+ <para>For an example of how to use
+ <literal>aopc</literal>
+ , please
+ see 1)
+ <literal>tools</literal>
+ directory for PojoCacheTasks14.xml
+ and PojoCacheTasks50.xml. Both contain Ant tasks that you can
+ import to your regular project for
+ <literal>aopc</literal>
+ . In addition, please also check out the
+ <literal>examples</literal>
+ directory for concrete examples.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a561">
+ <para>In PojoCache 2.x release, do I still need
+ <literal>annoc</literal>
+ ?
+ </para>
+ </question>
+
+ <answer>
+ <para>The annoc precompiler is needed for JDK1.4 style annotation. For 2.x release, since
+ we require the use of JDK5.0, there is no need to use annoc anymore.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a57">
+ <para>How do I use aopc on multiple module directories?</para>
+ </question>
+
+ <answer>
+ <para>In aopc, you specify the src path for a specific directory. To
+ pre-compile multiple ones, you will need to invoke aopc multiple
+ times.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a57a">
+ <para>Does PojoCache provide POJO event subscription?</para>
+ </question>
+
+ <answer>
+ <para>Yes, since 2.0, you can use PojoCacheListener to subscribe to events
+ such as POJO attach and detach and field updates. And if you need some customization,
+ you can also use the Obervable pattern directly. TO see an example, please check
+ out the test case:
+ <literal>org.jboss.cache.pojo.observer.LocalTest.java</literal>
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a58">
+ <para>What's in the
+ <literal>jboss-aop.xml</literal>
+ configuration?
+ </para>
+ </question>
+
+ <answer>
+ <para>
+ <literal>jboss-aop.xml</literal>
+ is needed for POJO
+ instrumentation. In
+ <literal>jboss-aop.xml</literal>
+ , you can
+ declare your POJO (e.g.,
+ <literal>Person</literal>
+ ) to be
+ "prepared", a JBossAop term to denote that the object will be
+ "aspectized" by the system. After this declaration, JBossAop will
+ invoke any interceptor that associates with this POJO. PojoCache
+ will dynamically add an
+ <literal>org.jboss.cache.pojo.interceptor.dynamic.CacheFieldInterceptor</literal>
+ to this POJO
+ to perform object mapping and relationship management.
+ </para>
+
+ <para>Note that to add your POJO, you should declare all the fields
+ to be "prepared" as in the example.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a58a">
+ <para>What's the difference between
+ <literal>jboss-aop.xml</literal>
+ <literal>pojocache-aop.xml</literal>
+ ?
+ </para>
+ </question>
+
+ <answer>
+ <para>
+ <literal>pojocache-aop.xml</literal>
+ is essentially a
+ <literal>jboss-aop.xml</literal>
+ ,
+ except it is used specifically for PojoCache. The analogy is similar to JBoss' own
+ MBean service file
+ <literal>jboss-service.xml</literal>
+ , for example. So in our documentation,
+ we will use these two terms interchangeably.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a59">
+ <para>Can I use annotation instead of the xml declaration?</para>
+ </question>
+
+ <answer>
+ <para>Yes, in release 2.0, you can use JDK5.0 annotation to
+ instrument your POJO. Check the documentation for details.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a60">
+ <para>What are the pro and con of xml vs. annotation?</para>
+ </question>
+
+ <answer>
+ <para>It really depends on your organization environment, I'd say, since this can be turned into a
+ hot debate. Having said that, I feel strongly that POJO annotation is well suited for PojoCache. This is
+ because once you specify the annotation, you'd probably change it rarely since there is no parameters to
+ tune, for example.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a61">
+ <para>What are the
+ <literal>@org.jboss.cache.pojo.annotation.Transient</literal>
+ and
+ <literal>@org.jboss.cache.pojo.annotation.Serializable</literal>
+ field level annotations?
+ </para>
+ </question>
+
+ <answer>
+ <para>In 2.0, we also offer two additional field-level annotations. The first one,
+ <literal>@org.jboss.cache.pojo.Transient</literal>
+ ,
+ when applied has the same effect as declaring a field
+ <literal>transient</literal>
+ . PojoCache
+ won't put this field under management.
+ </para>
+ <para>The second one,
+ <literal>@org.jboss.cache.pojo.Serializable</literal>
+ when applied,
+ will cause PojoCache to
+ treat the field as a Serializable object even when it is
+ <literal>@org.jboss.cache.pojo.Replicable</literal>
+ .
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a62">
+ <para>What about compile-time vs. load-time instrumentation then?</para>
+ </question>
+
+ <answer>
+ <para>Again it depends. But my preference is to do compile-time instrumentation via aopc. I prefer this
+ approach because it is easier to debug (at least at the development stage). In addition, once I generate
+ the
+ new class, there is no more steps needed.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a63">
+ <para>Is it possible to store the same object multiple times but
+ with different Fqn paths? Like /foo/byName and /foo/byId ?
+ </para>
+ </question>
+
+ <answer>
+ <para>Yes, you can use PojoCache to do that. It supports the
+ notion of object reference. PojoCache manages the unique object
+ through association of the dynamic cache interceptor.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a64">
+ <para>Do I need to declare all my objects "prepared" in
+ <literal>jboss-aop.xml</literal>
+ ?
+ </para>
+ </question>
+
+ <answer>
+ <para>Not necessarily. If there is an object that you don't need the
+ cache to manage for you, you can leave it out of the declaration.
+ The cache will treat this object as a "primitive" type. However, the
+ object will need to implement
+ <literal>Serializable</literal>
+ interface for replication.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a65">
+ <para>Can the cache aop intercept update via reflection?</para>
+ </question>
+
+ <answer>
+ <para>No. The update via reflection will not be intercepted in
+ JBossAop and therefore PojoCache will not be able to perform the
+ necessary synchronization.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a66">
+ <para>When I declare my POJO to be "aspectized", what happens to the
+ fields with transient, static, and final modifiers?
+ </para>
+ </question>
+
+ <answer>
+ <para>PojoCache currently will ignore the fields with these
+ modifiers. That is, it won't put these fields into the cache (and
+ thus no replication either).
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a67">
+ <para>What are those keys such as
+ <literal>JBoss:internal:class</literal>
+ and
+ <literal>PojoInstance</literal>
+ ?
+ </para>
+ </question>
+
+ <answer>
+ <para>They are for internal use only. Users should ignore these keys
+ and values in the node hashmap.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a68">
+ <para>What about Collection classes? Do I need to declare them
+ "prepared"?
+ </para>
+ </question>
+
+ <answer>
+ <para>No. Since the Collection classes such as
+ <literal>ArrayList</literal>
+ are java util classes, aop by default
+ won't instrument these classes. Instead, PojoCache will generate
+ a dynamic class proxy for the Collection classes (upon the
+ <literal>attach</literal>
+ call is invoked). The proxy will
+ delegate the operations to a cache interceptor that implements the
+ actual Collection classes APIs. That is, the system classes won't be
+ invoked when used in PojoCache.
+ </para>
+
+ <para>Internally, the cache interceptor implements the APIs by
+ direct interaction with respect to the underlying cache store. Note
+ that this can have implications in performance for certain APIs. For
+ example, both
+ <literal>ArrayList</literal>
+ and
+ <literal>LinkedList</literal>
+ will have the same implementation.
+ Plan is currently underway to optimize these APIs.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a69">
+ <para>How do I use
+ <literal>List</literal>
+ ,
+ <literal>Set</literal>
+ ,
+ and
+ <literal>Map</literal>
+ dynamic proxy?
+ </para>
+ </question>
+
+ <answer>
+ <para>PojoCache supports classes extending from
+ <literal>List</literal>
+ ,
+ <literal>Set</literal>
+ , and
+ <literal>Map</literal>
+ without users to declare them "aspectized".
+ It is done via a dynamic proxy. Here is a code snippet to use an
+ <literal>ArrayList</literal>
+ proxy class.
+ </para>
+
+ <programlisting>ArrayList list = new ArrayList();
+ list.add("first");
+
+ cache.attach("list/test", list); // Put the list under the aop cache
+ list.add("second"); // Won't work since AOP intercepts the dynamic proxy not the original POJO.
+
+ ArrayList myList = (List)cache.find("list/test"); // we are getting a dynamic proxy instead
+ myList.add("second"); // it works now
+ myList.add("third");
+ myList.remove("third");
+ </programlisting>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a70">
+ <para>What is the proper way of assigning two different keys with
+ Collection class object?
+ </para>
+ </question>
+
+ <answer>
+ <para>Let's say you want to assign a
+ <literal>List</literal>
+ object
+ under two different names, you will need to use the class proxy to
+ insert the second time to ensure both are managed by the cache. Here
+ is the code snippet.
+ </para>
+
+ <programlisting>ArrayList list = new ArrayList();
+ list.add("first");
+
+ cache.attach("list", list); // Put the list under the aop cache
+
+ ArrayList myList = (List)cache.find("list"); // we are getting a dynamic proxy instead
+ myList.add("second"); // it works now
+
+ cache.attach("list_alias", myList); // Note you will need to use the proxy here!!
+ myList.remove("second");
+ </programlisting>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a71">
+ <para>OK, so I know I am supposed to use proxy when manipulating the
+ Collection classes once they are managed by the cache. But what
+ happens to Pojos that share the Collection objects, e.g., a
+ <literal>List</literal>
+ instance that is shared by 2 Pojos?
+ </para>
+ </question>
+
+ <answer>
+ <para>Pojos that share Collection instance references will be
+ handled by the cache automatically. That is, when you ask the Cache
+ to manage it, the Cache will dynamically swap out the regular
+ Collection references with the dynamic proxy ones. As a result, it
+ is transparent to the users.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a72">
+ <para>What happens when my "aspectized" POJO has field members that
+ are of Collection class ?
+ </para>
+ </question>
+
+ <answer>
+ <para>When a user puts a POJO into the cache through the call
+ <literal>attach</literal>
+ , it will recursively map the field
+ members into the cache store as well. When the field member is of a
+ Collection class (e.g., List, Set, or Map), PojoCache will first
+ map the collection into cache. Then, it will swap out dynamically
+ the field reference with an corresponding proxy reference.
+ </para>
+
+ <para>This is necessary so that an internal update on the field
+ member will be intercepted by the cache.
+ </para>
+ </answer>
+ </qandaentry>
+
+
+ <qandaentry>
+ <question id="a73">
+ <para>What are the limitation of Collection classes in PojoCache?</para>
+ </question>
+
+ <answer>
+ <para>Use of Collection class in PojoCache helps you to track fine-grained changes
+ in your collection fields automatically. However, current implementation has the follow
+ limitation that we plan to address soon.
+ </para>
+ <para>Currently, we only support a limited implementation of Collection classes. That is,
+ we support APIs in List, Set, and Map. However, since the APIs do not stipulate
+ of constraints like NULL key or value, it makes mapping of user instance to our proxy tricky.
+ For example, ArrayList would allow NULL value and some other implementation would not.
+ The Set interface maps to java.util.HashSet implementation. The List interface maps
+ to java.util.ArrayList implementation. The Map interface maps to java.util.HashMap
+ implementation.
+ </para>
+ <para>Another related issue is the expected performance. For example, the current implementation is ordered,
+ so
+ that makes insert/delete from the Collection slow. Performance between Set, Map and List collections also
+ vary.
+ Adding items to a Set is slower than a List or Map, since Set does not allow duplicate entries.
+ </para>
+ </answer>
+ </qandaentry>
+
+
+ <qandaentry>
+ <question id="a74">
+ <para>What are the pros and cons of PojoCache?</para>
+ </question>
+
+ <answer>
+ <para>As mentioned in the reference doc, PojoCache has the following advantages:</para>
+ <itemizedlist>
+ <listitem>
+ <para>Fine-grained replication and/or persistency. If you use a distributed PojoCache
+ and once your POJO is put in the cache store, there is no need to use another API to
+ trigger your changes. Furthermore, the replication are fine-grained field level. Note this
+ also applies to persistency.
+ </para>
+ </listitem>
+ <listitem>
+ <para>Fine-grained replication can have potential performance gain if your POJO is big and
+ the changes are fine-grained, e.g., only to some selected fields.
+ </para>
+ </listitem>
+ <listitem>
+ <para>POJO can posses object relationship, e.g., multiple referenced. Distributed
+ PojoCache will handle this transparently for you.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>And here are some cases that you may not want to use PojoCache:</para>
+ <itemizedlist>
+ <listitem>
+ <para>You use only cache. That is you don't need replication or persistency. Then since
+ everything is operated on the in-memory POJO reference, there is no need for PojoCache.
+ </para>
+ </listitem>
+ <listitem>
+ <para>You have simple and small POJOs. Your POJO is small in size and also there is no
+ object relationship, then PojoCache possess not clear advantage to plain cache.
+ </para>
+ </listitem>
+ <listitem>
+ <para>Your application is bounded by memory usage. Because PojoCache need almost twice as much
+ of memory (the original POJO in-memory space and also the additional cache store for the
+ primitive fields), you may not want to use PojoCache.
+ </para>
+ </listitem>
+ <listitem>
+ <para>Your POJO lifetime is short. That is, you need to create and destroy your POJO often.
+ Then you need to do "attach" and "detach" often, it will be slow in performance.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </answer>
+ </qandaentry>
+ </qandaset>
+
+
+ <qandaset defaultlabel="qanda">
+ <title>Passiviation and eviction</title>
+ <qandaentry>
+ <question id="a80">
+ <para>Can I use eviction to evict POJO from the memory?</para>
+ </question>
+ <answer>
+ <para>No. In 2.0 release, we have deprecated the POJO-based eviction policy since it has always been
+ problematic in earlier release. The main reason is that when we evict a POJO from
+ the memory, the user has no ways of knowing it. So if the POJO is accessed after the
+ eviction, there won't be any PojoCache interception (e.g., it will be just like ordinary POJO),
+ but user may still expect that it will be managed by PojoCache.
+ </para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="a81">
+ <para>So what do I do now?</para>
+ </question>
+ <answer>
+ <para>In order to keep your memory from overflowing, you can use the passivation feature that comes with
+ the core Cache. Passivation uses the combination of eviction and cache loader such that when the
+ items are old, it will be evicted from memory and store in a cache store (can be DB or file). Next time,
+ when the item needs to be accessed again, we will retrieve it from the cache store.
+ </para>
+ <para>In this sense, PojoCache level is not aware of the passivation aspect. It is configured through
+ the underlying cache xml.
+ </para>
+ </answer>
+ </qandaentry>
+ </qandaset>
+
+ <qandaset defaultlabel="qanda">
+ <title>Troubleshooting</title>
+ <qandaentry>
+ <question id="a90">
+ <para>I am having problems getting PojoCache to work, where can I get information on troubleshooting?</para>
+ </question>
+ <answer>
+ <para>Troubleshooting section can be found in the following
+ <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=PojoCacheTroubleshooting">wiki link</ulink>
+ .
+ </para>
+ </answer>
+ </qandaentry>
+ </qandaset>
+</article>
Added: pojo/trunk/src/main/docbook/images/images/classes.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/classes.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/demoAddress.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/demoAddress.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/demoAddressInternal.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/demoAddressInternal.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/demoJoe.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/demoJoe.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/demogui.gif
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/demogui.gif
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/get.gif
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/get.gif
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/get.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/get.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/graph.gif
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/graph.gif
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/guiAddress.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/guiAddress.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/guiJoe.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/guiJoe.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/guiJoeAddress.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/guiJoeAddress.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/guiJoeInternal.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/guiJoeInternal.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/guiMary.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/guiMary.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/guiMaryAddress.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/guiMaryAddress.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/guiMaryInternal.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/guiMaryInternal.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/map.gif
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/map.gif
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/map.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/map.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/object_split.jpg
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/object_split.jpg
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/pojocache_architecture.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/pojocache_architecture.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/reference.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/reference.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/set.gif
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/set.gif
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/images/images/set.png
===================================================================
(Binary files differ)
Property changes on: pojo/trunk/src/main/docbook/images/images/set.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: pojo/trunk/src/main/docbook/tutorial/en/master.xml
===================================================================
--- pojo/trunk/src/main/docbook/tutorial/en/master.xml (rev 0)
+++ pojo/trunk/src/main/docbook/tutorial/en/master.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,398 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<article lang="en">
+ <articleinfo>
+ <title>PojoCache Tutorial</title>
+ <releaseinfo>Release 2.0.0</releaseinfo>
+ <pubdate>June 2007</pubdate>
+ <author>
+ <firstname>Ben</firstname>
+ <surname>Wang</surname>
+ <email>ben.wang(a)jboss.com</email>
+ </author>
+ <author>
+ <firstname>Galder</firstname>
+ <surname>Zamarreño</surname>
+ <email>galder.zamarreno(a)jboss.com</email>
+ </author>
+ </articleinfo>
+
+ <section>
+ <title>Introduction</title>
+
+ <para>PojoCache is an in-memory, transactional, and replicated POJO (plain old Java object) cache system that
+ allows users to operate on a POJO transparently without active user management of either replication or
+ persistency aspects. This tutorial focuses on the usage of the PojoCache API.
+ </para>
+ <para>For details of configuration, usage and APIs, please refer to the
+ <ulink url="http://labs.jboss.org/portal/jbosscache/docs/index.html">users manual</ulink>.
+ </para>
+ </section>
+
+ <section>
+ <title>What You Will Learn</title>
+
+ <itemizedlist>
+ <listitem>
+ <para>PojoCache creation and modification</para>
+ </listitem>
+
+ <listitem>
+ <para>Replication of POJO fields</para>
+ </listitem>
+
+ <listitem>
+ <para>Using Collections in PojoCache</para>
+ </listitem>
+
+ <listitem>
+ <para>Transactions</para>
+ </listitem>
+
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Configuration</title>
+
+ <para>First download the JBoss Cache 2.x distribution from
+ <ulink url="http://labs.jboss.org/portal/jbosscache/download/index.html">the download page</ulink>
+ . You probably want the
+ <literal>JBossCache-pojo-2.X.Y.zip</literal>
+ distribution. Unzip it, and you will get a directory containing the distribution, such as
+ <literal>JBossCache-pojo-2.X.Y</literal>
+ .
+ For the sake of this tutorial, I will refer to this as
+ <literal>PojoCache</literal>
+ .
+ </para>
+
+ <para>The configuration files are located under the
+ <literal>PojoCache/etc</literal>
+ directory. You can modify the behavior of the underlying cache through editing the various configuration files.
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>log4j.xml</literal>
+ . Logging output. You can enable logging, specify log levels or change the name and path to the log file.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>META-INF/replSync-service.xml</literal>
+ . Cache configuration file used for this tutorial.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>pojocache-aop.xml</literal>
+ . PojoCache configuration file that contains, amongst other things, the annotation to use on POJOs so
+ that they're aspectised. For more information, please the PojoCache
+ <ulink url="http://labs.jboss.org/portal/jbosscache/docs/index.html">users manual</ulink>
+ .
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Script</title>
+
+ <para>The only script needed for this tutorial is the
+ <literal>PojoCache/build.xml</literal>
+ ant script and the accompanying
+ driver scripts (
+ <literal>build.sh</literal>
+ for Unix and
+ <literal>build.bat</literal>
+ for Windows).
+ </para>
+ </section>
+
+ <section>
+ <title>Example POJOs</title>
+
+ <para>The example POJO classes used for PojoCache demo are:
+ <literal>org.jboss.cache.pojo.test.Person</literal>
+ and
+ <literal>org.jboss.cache.pojo.test.Address</literal>
+ . They are located
+ under
+ <literal>tests/functional</literal>
+ directory.The demo will demonstrate that once a POJO has been attached to the cache, plain get/set POJO methods
+ will be intercepted by the cache.
+ </para>
+
+ <para>Here is the snippet of the class definition for
+ <literal>Person</literal>
+ and
+ <literal>Address</literal>
+ with the
+ <literal>Replicable</literal>
+ annotation.
+ </para>
+
+ <programlisting><![CDATA[
+ @org.jboss.cache.pojo.annotation.Replicable
+ public class Person {
+ ...
+ public String getName() { return name; }
+ public void setName(String name) { this.name=name; }
+ ...
+ public List<String> getLanguages() { return languages; }
+ public void setLanguages(List<String> languages) { this.languages = languages; }
+ ...
+ public Address getAddress() { return address; }
+ public void setAddress(Address address) { this.address = address; }
+ ...
+ }
+ ]]></programlisting>
+
+ <programlisting><![CDATA[
+ @org.jboss.cache.pojo.annotation.Replicable
+ public class Address {
+ ...
+ public String getStreet() { return street; }
+ public void setStreet(String street) { this.street=street; }
+ ...
+ }
+ ]]></programlisting>
+ </section>
+
+ <section>
+ <title>Running The Demo GUI</title>
+
+ <para>
+ The demo is run by calling the ant script (via the driver) with the
+ <literal>run.demo.pojocache</literal>
+ target. E.g.,
+ </para>
+
+ <para>
+ <literal>./build.sh run.demo.pojocache</literal>
+ </para>
+ <para>
+ This will cause a GUI window to appear, giving you a tree view of the cache in the top pane and a BeanShell
+ view of the JVM in the lower pane.
+ </para>
+ <para>
+ The BeanShell view is preset with the following variables:
+ <itemizedlist>
+ <listitem>
+ <literal>cache</literal>
+ - a reference to the PojoCache interface, used by the GUI instance.
+ </listitem>
+ <listitem>
+ <literal>transactionManager</literal>
+ - a reference to the registered transaction manager.
+ </listitem>
+ </itemizedlist>
+ The references made available to the BeanShell window point to the same cache instance used by the tree view in
+ the GUI above.
+ </para>
+
+ <para>
+ To run the demo as a replicated demo, it is useful to start another command line window and run the ant script
+ again as you did above. Now you will have two cache instances running in two separate GUIs, replicating state
+ to each other.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Tutorials</title>
+ It is recommended that you shut down and restart the demo GUI for each of the following tutorials, to ensure
+ clean caches every time. To inspect POJO attribute changes via GUI, please refer to the PojoCache
+ <ulink
+ url="http://labs.jboss.org/portal/jbosscache/docs/index.html">user manual
+ </ulink>
+ to understand how the POJOs are mapped internally in the cache.
+
+ <section>
+ <title>PojoCache API, POJO manipulation, and Replication</title>
+ <para>
+ For this tutorial, start two instance of the demo GUI. In this tutorial, we will:
+
+ <itemizedlist>
+ <listitem>Attach POJOs to the cache and see them being replicated.</listitem>
+ <listitem>After attaching, manipulate the POJOs and see the individual changes replicated.</listitem>
+ <listitem>Retrieve POJOs from the cache, manipulate them and see the changes replicated.</listitem>
+ <listitem>Create POJOs that share a common POJO and the consequences of changes to this.</listitem>
+ <listitem>Detach POJOs from the cache.</listitem>
+ <listitem>After detaching, manipulates the POJOs and see how the values in the cache are unchanged.</listitem>
+ </itemizedlist>
+
+ </para>
+
+ <orderedlist>
+ <listitem>In the 1st GUI instance, create a POJO, i.e. a Person with an Address:
+ <programlisting><![CDATA[
+
+ joe = new Person();
+ joe.setName("Joe Black");
+ joe.setAge(31);
+
+ addr = new Address();
+ addr.setCity("Sunnyvale");
+ addr.setStreet("123 Albert Ave");
+ addr.setZip(94086);
+
+ joe.setAddress(addr);
+
+ ]]></programlisting>
+ </listitem>
+
+ <listitem>Attach the POJO to the cache:
+ <programlisting><![CDATA[
+
+ cache.attach("pojo/joe", joe);
+
+ ]]></programlisting>
+ </listitem>
+
+ <listitem>Change attributes of the POJO and see the individual changes being propagated to the 2nd
+ cache GUI:
+ <programlisting><![CDATA[
+
+ joe.setAge(41);
+
+ ]]></programlisting>
+ </listitem>
+
+ <listitem>In the 2nd GUI instance, get a reference to the Person in the cache and create a second Person
+ with the existing Person's Address:
+ <programlisting><![CDATA[
+
+ joe = cache.find("pojo/joe");
+
+ mary = new Person();
+ mary.setName("Mary White");
+ mary.setAge(30);
+
+ mary.setAddress(joe.getAddress());
+
+ ]]></programlisting>
+ </listitem>
+
+ <listitem>Attach the new POJO to the cache:
+ <programlisting><![CDATA[
+
+ cache.attach("pojo/mary", mary);
+
+ ]]></programlisting>
+ </listitem>
+
+ <listitem>Now, change either Person's Address and see how the change applies to both POJOs and has been
+ propagated to the other cache, visible in the 1st GUI instance:
+ <programlisting><![CDATA[
+
+ mary.getAddress().setZip(95000);
+
+ ]]></programlisting>
+ </listitem>
+
+
+ <listitem>Still in the 2nd GUI instance, detach the POJOs from the cache and see how the POJOs are no longer
+ visible:
+ <programlisting><![CDATA[
+
+ cache.detach("pojo/joe");
+ cache.detach("pojo/mary");
+
+ ]]></programlisting>
+ </listitem>
+
+ <listitem>Finally, in any of GUI instances, change some attributes of the POJO and see these changes have
+ no effect in the cache:
+ <programlisting><![CDATA[
+
+ joe.setName("Joe White");
+
+ ]]></programlisting>
+ </listitem>
+
+ </orderedlist>
+
+ </section>
+
+ <section>
+ <title>Collections</title>
+ <para>
+ For this tutorial, start two instances of the demo GUI. In this tutorial, we will:
+
+ <itemizedlist>
+ <listitem>Attach a POJO to the cache and see it being replicated.</listitem>
+ <listitem>Set a Collection attribute in this POJO</listitem>
+ <listitem>Manipulate this Collection attribute and see the changes visible in the GUI and being replicated</listitem>
+ <listitem>Detach a POJO from the cache.</listitem>
+ </itemizedlist>
+
+ </para>
+
+ <orderedlist>
+ <listitem>In the 1st GUI instance, create a POJO with a Collection attribute:
+ <programlisting><![CDATA[
+
+ joe = new Person();
+ joe.setName("Joe Black");
+
+ lang = new ArrayList();
+ lang.add("Spanish");
+
+ joe.setLanguages(lang);
+
+ ]]></programlisting>
+ </listitem>
+
+ <listitem>Attach the POJO to the cache:
+ <programlisting><![CDATA[
+
+ cache.attach("pojo/joe", joe);
+
+ ]]></programlisting>
+ </listitem>
+
+ <listitem>Get a proxy reference to the Collection and add a new element to it:
+ <programlisting><![CDATA[
+
+ proxyLang = joe.getLanguages();
+ proxyLang.add("English");
+
+ ]]></programlisting>
+ </listitem>
+
+ <listitem>Detach the pojo from the cache:
+ <programlisting><![CDATA[
+
+ cache.detach("pojo/joe");
+
+ ]]></programlisting>
+ </listitem>
+
+ <listitem>Use the proxy reference to the Collection to add another element and see how this does not get
+ added to the cache:
+ <programlisting><![CDATA[
+
+ proxyLang.add("French");
+
+ ]]></programlisting>
+ </listitem>
+
+ </orderedlist>
+ </section>
+ </section>
+
+ <section>
+ <title>Transactions</title>
+ <para>
+ For this tutorial, start two instances instance of the demo GUI. Repeat the exercises in the previous
+ tutorial, only starting transactions before attaching/detaching nodes or modiying the POJOs. This will depict
+ how replication only occurs on transaction boundaries. Try rolling back a few transactions as well, to see how
+ nothing gets replicated in these cases.
+ </para>
+ </section>
+
+</article>
\ No newline at end of file
Added: pojo/trunk/src/main/docbook/userguide/en/master.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/master.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/master.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,102 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
+ "../../../../docbook-support/support/docbook-dtd/docbookx.dtd"
+ [
+ <!ENTITY term SYSTEM "modules/term.xml">
+ <!ENTITY intro SYSTEM "modules/introduction.xml">
+ <!ENTITY arch SYSTEM "modules/architecture.xml">
+ <!ENTITY api SYSTEM "modules/api.xml">
+ <!ENTITY config SYSTEM "modules/configuration.xml">
+ <!ENTITY instrumentation SYSTEM "modules/instrumentation.xml">
+ <!ENTITY example SYSTEM "modules/example.xml">
+ <!ENTITY trouble SYSTEM "modules/troubleshooting.xml">
+ <!ENTITY appendix SYSTEM "modules/appendix.xml">
+ ]>
+
+<book lang="en">
+
+ <bookinfo>
+ <title>POJO Cache</title>
+ <subtitle>User Documentation</subtitle>
+ <releaseinfo>Release 2.0.0</releaseinfo>
+ <pubdate>July 2007</pubdate>
+
+ <author>
+ <firstname>Ben</firstname>
+ <surname>Wang</surname>
+ <email>ben.wang(a)jboss.com</email>
+ </author>
+ <author>
+ <firstname>Jason</firstname>
+ <surname>Greene</surname>
+ <email>jason.greene(a)jboss.com</email>
+ </author>
+ </bookinfo>
+
+ <toc/>
+
+ <preface id="preface" revision="1">
+ <title>Preface</title>
+
+ <para>
+ POJO Cache is an in-memory, transactional, and clustered cache system that
+ allows users to operate on a POJO (Plain Old Java Object) transparently and without
+ active user management of either replication or persistence aspects.
+
+ JBoss Cache, which includes POJO Cache, is a 100% Java based library that can be
+ run either as a standalone program or inside an application server.
+ </para>
+
+ <para>
+ This document is meant to be a user and reference guide to explain the architecture, api, configuration, and
+ examples for POJO Cache. We assume the readers are familiar with both JGroups and the core JBoss Cache usages.
+ </para>
+
+ <para>
+ If you have questions, use the user
+ <ulink url="http://www.jboss.com/index.html?module=bb&op=viewforum&f=157">forum</ulink>
+ linked on the JBoss Cache website. We also
+ provide tracking links for tracking bug reports and feature requests on
+ <ulink url="http://jira.jboss.com">JBoss Jira web site</ulink>
+ . If you
+ are interested in the development of POJO Cache, post a message on the forum. If
+ you are interested in translating this documentation into your language, contact us
+ on the developer mailing list.
+ </para>
+
+ <para>
+ JBoss Cache is an open source product, using the business and OEM-friendly OSI-approved LGPL license.
+ Commercial development support, production support and training for JBoss Cache is available through
+ <ulink url="http://www.jboss.com">JBoss, a division of Red Hat Inc.</ulink>
+ </para>
+
+ <para>
+ In some of the example listings, what is meant to be displayed on one line does not fit
+ inside the available page width. These lines have been broken up. A '\' at the end of a
+ line means that a break has been introduced to fit in the page, with the following lines
+ indented. So:
+ <programlisting>
+ Let's pretend to have an extremely \
+ long line that \
+ does not fit
+ This one is short
+ </programlisting>
+ Is really:
+ <programlisting>
+ Let's pretend to have an extremely long line that does not fit
+ This one is short
+ </programlisting>
+ </para>
+ </preface>
+
+
+ &term;
+ &intro;
+ &arch;
+ &api;
+ &config;
+ &instrumentation;
+ &trouble;
+ &appendix;
+</book>
+
Added: pojo/trunk/src/main/docbook/userguide/en/modules/architecture.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/architecture.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/architecture.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,498 @@
+<chapter id="architecture">
+ <title>Architecture</title>
+ <section id="architecture.tree_structure">
+ <title>Data Structures Within The Cache</title>
+
+
+ <para>
+ A
+ <literal>Cache</literal>
+ consists of a collection of
+ <literal>Node</literal>
+ instances, organised in a tree
+ structure. Each
+ <literal>Node</literal>
+ contains a
+ <literal>Map</literal>
+ which holds the data
+ objects to be cached. It is important to note that the structure is a mathematical tree, and not a graph; each
+ <literal>Node</literal>
+ has one and only one parent, and the root node is denoted by the constant fully qualitied name,
+ <literal>Fqn.ROOT</literal>
+ .
+ </para>
+ <para>
+ The reason for organising nodes as such is to improve concurrent access to data and make replication and
+ persistence
+ more fine-grained.
+ </para>
+ <para>
+ <figure>
+ <title>Data structured as a tree</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="TreeCacheArchitecture.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ In the diagram above, each box represents a JVM. You see 2 caches in separate JVMs, replicating data to each
+ other.
+ These VMs can be located on the same physical machine, or on 2 different machines connected by a network link.
+ The
+ underlying group communication between networked nodes is done using
+ <ulink url="http://www.jgroups.org">JGroups</ulink>
+ .
+ </para>
+
+ <para>Any modifications (see
+ <link linkend="api">API chapter</link>
+ ) in one cache instance will be replicated to
+ the other cache. Naturally, you can have more than 2 caches in a cluster.
+ Depending on the transactional settings, this replication will occur either after each modification or at the
+ end of a transaction, at commit time. When a new cache is created, it can optionally acquire the contents
+ from one of the existing caches on startup.
+ </para>
+ </section>
+
+ <section id="architecture.SPI_interfaces">
+ <title>SPI Interfaces</title>
+ <para>
+ In addition to
+ <literal>Cache</literal>
+ and
+ <literal>Node</literal>
+ interfaces, JBoss Cache exposes more powerful
+ <literal>CacheSPI</literal>
+ and
+ <literal>NodeSPI</literal>
+ interfaces, which offer more control over the internals
+ of JBoss Cache. These interfaces are not intended for general use, but are designed for people who wish to
+ extend and enhance JBoss Cache, or write custom
+ <literal>Interceptor</literal>
+ or
+ <literal>CacheLoader</literal>
+ instances.
+ </para>
+ <figure>
+ <title>SPI Interfaces</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="SPI.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ <para>
+ The
+ <literal>CacheSPI</literal>
+ interface cannot be created, but is injected into
+ <literal>Interceptor</literal>
+ and
+ <literal>CacheLoader</literal>
+ implementations by the
+ <literal>setCache(CacheSPI cache)</literal>
+ methods on these interfaces.
+ <literal>CacheSPI</literal>
+ extends
+ <literal>Cache</literal>
+ so all the functionality of the basic API is made available.
+ </para>
+ <para>
+ Similarly, a
+ <literal>NodeSPI</literal>
+ interface cannot be created. Instead, one is obtained by performing operations on
+ <literal>CacheSPI</literal>
+ ,
+ obtained as above. For example,
+ <literal>Cache.getRoot() : Node</literal>
+ is overridden as
+ <literal>CacheSPI.getRoot() : NodeSPI</literal>
+ .
+ </para>
+ <para>
+ It is important to note that directly casting a
+ <literal>Cache</literal>
+ or
+ <literal>Node</literal>
+ to it's SPI
+ counterpart is not recommended and is bad practice, since the inheritace of interfaces it is not a contract
+ that is guaranteed to be upheld moving forward. The exposed public APIs, on the other hand, is guaranteed to
+ be upheld.
+ </para>
+ </section>
+
+ <section id="architecture.invocations">
+ <title>Method Invocations On Nodes</title>
+ <para>
+ Since the cache is essentially a collection of nodes, aspects such as clustering, persistence, eviction, etc.
+ need to be applied to these nodes when operations are invoked on the cache as a whole or on individual nodes.
+ To achieve this in a clean, modular and extensible manner, an interceptor chain is used. The chain is built
+ up of a series of interceptors, each one adding an aspect or particular functionality. The chain is built
+ when the cache is created, based on the configuration used.
+ </para>
+ <para>
+ It is important to note that the
+ <literal>NodeSPI</literal>
+ offers some methods (such as the
+ <literal>xxxDirect()</literal>
+ method
+ family) that operate on a node directly without passing through the interceptor stack. Plugin authors should
+ note
+ that using such methods will affect the aspects of the cache that may need to be applied, such as locking,
+ replication, etc. Basically, don't use such methods unless you
+ <emphasis>really</emphasis>
+ know what you're doing!
+ </para>
+ <section id="architecture.interceptors">
+ <title>Interceptors</title>
+ <para>
+ An
+ <literal>Interceptor</literal>
+ is an abstract class, several of which comprise an interceptor chain. It
+ exposes an
+ <literal>invoke()</literal>
+ method, which must be overridden by implementing classes to add behaviour
+ to a call before passing the call down the chain by calling
+ <literal>super.invoke()</literal>
+ .
+ </para>
+ <figure>
+ <title>SPI Interfaces</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="Interceptor.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ <para>
+ JBoss Cache ships with several interceptors, representing different configuration options, some of which
+ are:
+ <itemizedlist>
+ <listitem>
+ <literal>TxInterceptor</literal>
+ - looks for ongoing transactions and registers with transaction managers to participate in
+ synchronization events
+ </listitem>
+ <listitem>
+ <literal>ReplicationInterceptor</literal>
+ - replicates state across a cluster using a JGroups channel
+ </listitem>
+ <listitem>
+ <literal>CacheLoaderInterceptor</literal>
+ - loads data from a persistent store if the data requested is not available in memory
+ </listitem>
+ </itemizedlist>
+ The interceptor chain configured for your cache instance can be obtained and inspected by calling
+ <literal>CacheSPI.getInterceptorChain()</literal>
+ ,
+ which returns an ordered
+ <literal>List</literal>
+ of interceptors.
+ </para>
+ <section id="architecture.custom_interceptors">
+ <title>Writing Custom Interceptors</title>
+ <para>
+ Custom interceptors to add specific aspects or features can be written by extending
+ <literal>Interceptor</literal>
+ and overriding
+ <literal>invoke()</literal>
+ . The custom interceptor will need to be added to the interceptor chain by using the
+ <literal>CacheSPI.addInterceptor()</literal>
+ method.
+ </para>
+ <para>
+ Adding custom interceptors via XML is not supported at this time.
+ </para>
+ </section>
+ </section>
+
+ <section id="architecture.methodcalls">
+ <title>MethodCalls</title>
+ <para>
+ <literal>org.jboss.cache.marshall.MethodCall</literal>
+ is a class that encapsulates a
+ <literal>java.lang.reflection.Method</literal>
+ and an
+ <literal>Object[]</literal>
+ representing the method's arguments. It is an extension of the
+ <literal>org.jgroups.blocks.MethodCall</literal>
+ class, that adds a mechanism for identifying known methods using magic numbers and method ids,
+ which makes marshalling and unmarshalling more efficient and performant.
+ </para>
+ <para>
+ This is central to the
+ <literal>Interceptor</literal>
+ architecture, and is the only parameter passed in to
+ <literal>Interceptor.invoke()</literal>
+ .
+ </para>
+ </section>
+
+ <section id="architecture.invocationcontext">
+ <title>InvocationContexts</title>
+ <para>
+ <literal>InvocationContext</literal>
+ holds intermediate state for the duration of a single invocation, and is set up and
+ destroyed by the
+ <literal>InvocationContextInterceptor</literal>
+ which sits at the start of the chain.
+ </para>
+ <para>
+ <literal>InvocationContext</literal>
+ , as its name implies, holds contextual information associated with a single cache
+ method invocation. Contextual information includes associated
+ <literal>javax.transaction.Transaction</literal>
+ or
+ <literal>org.jboss.cache.transaction.GlobalTransaction</literal>
+ ,
+ method invocation origin (
+ <literal>InvocationContext.isOriginLocal()</literal>
+ ) as well as
+ <link
+ linkend="configuration.options">
+ <literal>Option</literal>
+ overrides
+ </link>
+ .
+ </para>
+ <para>
+ The
+ <literal>InvocationContext</literal>
+ can be obtained by calling
+ <literal>Cache.getInvocationContext()</literal>
+ .
+ </para>
+ </section>
+ </section>
+
+ <section id="architecture.managers">
+ <title>Managers For Subsystems</title>
+ <para>
+ Some aspects and functionality is shared by more than a single interceptor. Some of these have been
+ encapsulated
+ into managers, for use by various interceptors, and are made available by the
+ <literal>CacheSPI</literal>
+ interface.
+ </para>
+
+ <section id="architecture.rpcmanager">
+ <title>RpcManager</title>
+ <para>
+ This class is responsible for calls made via the JGroups channel for all RPC calls to remote caches, and
+ encapsulates the JGroups channel used.
+ </para>
+ </section>
+
+ <section id="architecture.buddymanager">
+ <title>BuddyManager</title>
+ <para>
+ This class manages buddy groups and invokes group organisation remote calls to organise a cluster of
+ caches into smaller sub-groups.
+ </para>
+ </section>
+
+ <section id="architecture.cacheloadermanager">
+ <title>CacheLoaderManager</title>
+ <para>
+ Sets up and configures cache loaders. This class wraps individual
+ <literal>CacheLoader</literal>
+ instances
+ in delegating classes, such as
+ <literal>SingletonStoreCacheLoader</literal>
+ or
+ <literal>AsyncCacheLoader</literal>
+ ,
+ or may add the
+ <literal>CacheLoader</literal>
+ to a chain using the
+ <literal>ChainingCacheLoader</literal>
+ .
+ </para>
+ </section>
+
+ </section>
+
+ <section id="architecture.marshalling">
+ <title>Marshalling And Wire Formats</title>
+ <para>
+ Early versions of JBoss Cache simply wrote cached data to the network by writing to an
+ <literal>ObjectOutputStream</literal>
+ during replication. Over various releases in the JBoss Cache 1.x.x series this approach was gradually
+ deprecated
+ in favour of a more mature marshalling framework. In the JBoss Cache 2.x.x series, this is the only officially
+ supported and recommended mechanism for writing objects to datastreams.
+ </para>
+ <figure>
+ <title>The Marshaller interface</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="Marshaller.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ <section>
+ <title>The Marshaller Interface</title>
+ <para>
+ The
+ <literal>Marshaller</literal>
+ interface extends
+ <literal>RpcDispatcher.Marshaller</literal>
+ from JGroups.
+ This interface has two main implementations - a delegating
+ <literal>VersionAwareMarshaller</literal>
+ and a
+ concrete
+ <literal>CacheMarshaller200</literal>
+ .
+ </para>
+ <para>
+ The marshaller can be obtained by calling
+ <literal>CacheSPI.getMarshaller()</literal>
+ , and defaults to the
+ <literal>VersionAwareMarshaller</literal>
+ .
+ Users may also write their own marshallers by implementing the
+ <literal>Marshaller</literal>
+ interface and
+ adding it to their configuration, by using the
+ <literal>MarshallerClass</literal>
+ configuration attribute.
+ </para>
+ </section>
+
+ <section>
+ <title>VersionAwareMarshaller</title>
+ <para>
+ As the name suggests, this marshaller adds a version
+ <literal>short</literal>
+ to the start of any stream when
+ writing, enabling similar
+ <literal>VersionAwareMarshaller</literal>
+ instances to read the version short and
+ know which specific marshaller implementation to delegate the call to.
+ For example,
+ <literal>CacheMarshaller200</literal>
+ , is the marshaller for JBoss Cache 2.0.x.
+ JBoss Cache 2.1.x, say, may ship with
+ <literal>CacheMarshaller210</literal>
+ with an improved wire protocol.
+ Using a
+ <literal>VersionAwareMarshaller</literal>
+ helps achieve wire protocol compatibility between minor
+ releases but still affords us the flexibility to tweak and improve the wire protocol between minor or micro
+ releases.
+ </para>
+
+ <section>
+ <title>CacheLoaders</title>
+ <para>
+ Some of the existing cache loaders, such as the
+ <literal>JDBCCacheLoader</literal>
+ and the
+ <literal>FileCacheLoader</literal>
+ relied on persisting data using
+ <literal>ObjectOutputStream</literal>
+ as well, but now, they are using the
+ <literal>VersionAwareMarshaller</literal>
+ to marshall the persisted
+ data to their cache stores.
+ </para>
+ </section>
+
+ </section>
+
+ <section>
+ <title>CacheMarshaller200</title>
+ <para>
+ This marshaller treats well-known objects that need marshalling - such as
+ <literal>MethodCall</literal>
+ ,
+ <literal>Fqn</literal>
+ ,
+ <literal>DataVersion</literal>
+ , and even some JDK objects such as
+ <literal>String</literal>
+ ,
+ <literal>List</literal>
+ ,
+ <literal>Boolean</literal>
+ and others as types that do not need complete class definitions.
+ Instead, each of these well-known types are represented by a
+ <literal>short</literal>
+ , which is a lot more efficient.
+ </para>
+ <para>
+ In addition, reference counting is done to reduce duplication of writing certain objects multiple times, to
+ help
+ keep the streams small and efficient.
+ </para>
+ <para>
+ Also, if
+ <literal>UseRegionBasedMarshalling</literal>
+ is enabled (disabled by default) the marshaller adds region
+ information to the stream before writing any data. This region information is in the form of a
+ <literal>String</literal>
+ representation of an
+ <literal>Fqn</literal>
+ . When unmarshalling, the
+ <literal>RegionManager</literal>
+ can be used to
+ find the relevant
+ <literal>Region</literal>
+ , and use a region-specific
+ <literal>ClassLoader</literal>
+ to unmarshall
+ the stream. This is specifically useful when used to cluster state for application servers, where each
+ deployment has
+ it's own
+ <literal>ClassLoader</literal>
+ . See the section below on
+ <link linkend="architecture.regions">regions</link>
+ for more information.
+ </para>
+ </section>
+
+ </section>
+ <section id="architecture.regions">
+ <title>Class Loading and Regions</title>
+ <para>
+ When used to cluster state of application servers, applications deployed in the application tend to put
+ instances
+ of objects specific to their application in the cache (or in an
+ <literal>HttpSession</literal>
+ object) which
+ would require replication. It is common for application servers to assign separate
+ <literal>ClassLoader</literal>
+ instances to each application deployed, but have JBoss Cache libraries referenced by the application server's
+ <literal>ClassLoader</literal>
+ .
+ </para>
+ <para>
+ To enable us to successfully marshall and unmarshall objects from such class loaders, we use a concept called
+ regions. A region is a portion of the cache which share a common class loader (a region also has other uses -
+ see
+ <link linkend="eviction_policies">eviction policies</link>
+ ).
+ </para>
+ <para>
+ A region is created by using the
+ <literal>Cache.getRegion(Fqn fqn, boolean createIfNotExists)</literal>
+ method,
+ and returns an implementation of the
+ <literal>Region</literal>
+ interface. Once a region is obtained, a
+ class loader for the region can be set or unset, and the region can be activated/deactivated. By default,
+ regions
+ are active unless the
+ <literal>InactiveOnStartup</literal>
+ configuration attribute is set to
+ <literal>true</literal>
+ .
+ </para>
+ </section>
+
+</chapter>
Added: pojo/trunk/src/main/docbook/userguide/en/modules/basic_api.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/basic_api.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/basic_api.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,719 @@
+<chapter id="api">
+ <title>User API</title>
+ <section>
+ <title>API Classes</title>
+ <para>
+ The
+ <literal>Cache</literal>
+ interface is the primary mechanism for interacting with JBoss Cache. It is
+ constructed and optionally started using the
+ <literal>CacheFactory</literal>
+ . The
+ <literal>CacheFactory</literal>
+ allows you to create a
+ <literal>Cache</literal>
+ either from a
+ <literal>Configuration</literal>
+ object
+ or an XML file. Once you have a reference to a
+ <literal>Cache</literal>
+ , you can use it to look up
+ <literal>Node</literal>
+ objects in the tree structure, and store data in the tree.
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="PublicAPI.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+
+ </para>
+
+ <para>
+ Reviewing the javadoc for the above interfaces is the best way
+ to learn the API. Below we cover some of the main points.
+ </para>
+ </section>
+
+ <section id="api.create_start">
+ <title>Instantiating and Starting the Cache</title>
+ <para>
+ An instance of the
+ <literal>Cache</literal>
+ interface can only be created
+ via a
+ <literal>CacheFactory</literal>
+ . (This is unlike JBoss Cache 1.x,
+ where an instance of the old
+ <literal>TreeCache</literal>
+ class could
+ be directly instantiated.)
+ </para>
+ <para>
+ <literal>CacheFactory</literal>
+ provides a number of overloaded methods
+ for creating a
+ <literal>Cache</literal>
+ , but they all do the same thing:
+ <itemizedlist>
+ <listitem>Gain access to a
+ <literal>Configuration</literal>
+ , either
+ by having one passed in as a method parameter, or by parsing XML
+ content and constructing one. The XML content can come from a
+ provided input stream or from a classpath or filesystem location.
+ See the
+ <link linkend="configuration">chapter on Configuration</link>
+ for
+ more on obtaining a
+ <literal>Configuration</literal>
+ .
+ </listitem>
+ <listitem>Instantiate the
+ <literal>Cache</literal>
+ and provide
+ it with a reference to the
+ <literal>Configuration</literal>
+ .
+ </listitem>
+ <listitem>Optionally invoke the cache's
+ <literal>create()</literal>
+ and
+ <literal>start()</literal>
+ methods.
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ An example of the simplest mechanism for creating and starting
+ a cache, using the default configuration values:
+ </para>
+
+ <programlisting>
+ CacheFactory factory = DefaultCacheFactory.getInstance();
+ Cache cache = factory.createCache();
+ </programlisting>
+
+ <para>Here we tell the
+ <literal>CacheFactory</literal>
+ to find and
+ parse a configuration file on the classpath:
+ </para>
+
+ <programlisting>
+ CacheFactory factory = DefaultCacheFactory.getInstance();
+ Cache cache = factory.createCache("cache-configuration.xml");
+ </programlisting>
+
+ <para>Here we configure the cache from a file, but want to programatically
+ change a configuration element. So, we tell the factory not to start
+ the cache, and instead do it ourselves:
+ </para>
+
+ <programlisting>
+ CacheFactory factory = DefaultCacheFactory.getInstance();
+ Cache cache = factory.createCache("cache-configuration.xml", false);
+ Configuration config = cache.getConfiguration();
+ config.setClusterName(this.getClusterName());
+
+ // Have to create and start cache before using it
+ cache.create();
+ cache.start();
+ </programlisting>
+
+ </section>
+
+ <section>
+ <title>Caching and Retrieving Data</title>
+
+ <para>Next, let's use the
+ <literal>Cache</literal>
+ API to access
+ a
+ <literal>Node</literal>
+ in the cache and then do some
+ simple reads and writes to that node.
+ </para>
+ <programlisting>
+ // Let's get ahold of the root node.
+ Node rootNode = cache.getRoot();
+
+ // Remember, JBoss Cache stores data in a tree structure.
+ // All nodes in the tree structure are identified by Fqn objects.
+ Fqn peterGriffinFqn = Fqn.fromString("/griffin/peter");
+
+ // Create a new Node
+ Node peterGriffin = rootNode.addChild(peterGriffinFqn);
+
+ // let's store some data in the node
+ peterGriffin.put("isCartoonCharacter", Boolean.TRUE);
+ peterGriffin.put("favouriteDrink", new Beer());
+
+ // some tests (just assume this code is in a JUnit test case)
+ assertTrue(peterGriffin.get("isCartoonCharacter"));
+ assertEquals(peterGriffinFqn, peterGriffin.getFqn());
+ assertTrue(rootNode.hasChild(peterGriffinFqn));
+
+ Set keys = new HashSet();
+ keys.add("isCartoonCharacter");
+ keys.add("favouriteDrink");
+
+ assertEquals(keys, peterGriffin.getKeys());
+
+ // let's remove some data from the node
+ peterGriffin.remove("favouriteDrink");
+
+ assertNull(peterGriffin.get("favouriteDrink");
+
+ // let's remove the node altogether
+ rootNode.removeChild(peterGriffinFqn);
+
+ assertFalse(rootNode.hasChild(peterGriffinFqn));
+ </programlisting>
+
+ <para>
+ The
+ <literal>Cache</literal>
+ interface also exposes put/get/remove
+ operations that take an
+ <link linkend="basic_api.fqn">Fqn</link>
+ as an argument:
+ </para>
+
+ <programlisting>
+ Fqn peterGriffinFqn = Fqn.fromString("/griffin/peter");
+
+ cache.put(peterGriffinFqn, "isCartoonCharacter", Boolean.TRUE);
+ cache.put(peterGriffinFqn, "favouriteDrink", new Beer());
+
+ assertTrue(peterGriffin.get(peterGriffinFqn, "isCartoonCharacter"));
+ assertTrue(cache.getRootNode().hasChild(peterGriffinFqn));
+
+ cache.remove(peterGriffinFqn, "favouriteDrink");
+
+ assertNull(cache.get(peterGriffinFqn, "favouriteDrink");
+
+ cache.removeNode(peterGriffinFqn);
+
+ assertFalse(cache.getRootNode().hasChild(peterGriffinFqn));
+ </programlisting>
+ </section>
+
+ <section id="basic_api.fqn">
+ <title>The
+ <literal>Fqn</literal>
+ Class
+ </title>
+
+ <para>
+ The previous section used the
+ <literal>Fqn</literal>
+ class in its
+ examples; now let's learn a bit more about that class.
+ </para>
+
+ <para>
+ A Fully Qualified Name (Fqn) encapsulates a list of names which represent
+ a path to a particular location in the cache's tree structure. The
+ elements in the list are typically
+ <literal>String</literal>
+ s but can be
+ any
+ <literal>Object</literal>
+ or a mix of different types.
+ </para>
+
+ <para>
+ This path can be absolute (i.e., relative to the root node), or relative
+ to any node in the cache. Reading the documentation on each API call that
+ makes use of
+ <literal>Fqn</literal>
+ will tell you whether the API expects
+ a relative or absolute
+ <literal>Fqn</literal>
+ .
+ </para>
+
+ <para>
+ The
+ <literal>Fqn</literal>
+ class provides are variety of constructors;
+ see the javadoc for all the possibilities. The following illustrates the
+ most commonly used approaches to creating an Fqn:
+ </para>
+
+ <programlisting>
+ <![CDATA[
+ // Create an Fqn pointing to node 'Joe' under parent node 'Smith'
+ // under the 'people' section of the tree
+
+ // Parse it from a String
+ Fqn<String> abc = Fqn.fromString("/people/Smith/Joe/");
+
+ // Build it directly. A bit more efficient to construct than parsing
+ String[] strings = new String[] { "people", "Smith", "Joe" };
+ Fqn<String> abc = new Fqn<String>(strings);
+
+ // Here we want to use types other than String
+ Object[] objs = new Object[]{ "accounts", "NY", new Integer(12345) };
+ Fqn<Object> acctFqn = new Fqn<Object>(objs);
+ ]]>
+ </programlisting>
+
+ <para>Note that</para>
+ <para>
+ <programlisting><![CDATA[Fqn<String> f = new Fqn<String>("/a/b/c");]]></programlisting>
+ </para>
+ <para>is
+ <emphasis>not</emphasis>
+ the same as
+ </para>
+ <para>
+ <programlisting><![CDATA[Fqn<String> f = Fqn.fromString("/a/b/c");]]></programlisting>
+ </para>
+
+ <para>
+ The former will result in an Fqn with a single element, called "/a/b/c"
+ which hangs directly under the cache root. The latter will result
+ in a 3 element Fqn, where "c" idicates a child of "b", which is a child
+ of "a", and "a" hangs off the cache root. Another way to
+ look at it is that the "/" separarator is only parsed when it forms
+ part of a String passed in to
+ <literal>Fqn.fromString()</literal>
+ and not
+ otherwise.
+ </para>
+
+ <para>
+ The JBoss Cache API in the 1.x releases included many overloaded
+ convenience methods that took a string in the "/a/b/c" format in place
+ of an
+ <literal>Fqn</literal>
+ . In the interests of API simplicity, no
+ such convenience methods are available in the JBC 2.x API.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Stopping and Destroying the Cache</title>
+ <para>
+ It is good practice to stop and destroy your cache when you are done
+ using it, particularly if it is a clustered cache and has thus
+ used a JGroups channel. Stopping and destroying a cache ensures
+ resources like the JGroups channel are properly cleaned up.
+ </para>
+
+ <programlisting>
+ cache.stop();
+ cache.destroy();
+ </programlisting>
+
+ <para>
+ Not also that a cache that has had
+ <literal>stop()</literal>
+ invoked
+ on it can be started again with a new call to
+ <literal>start()</literal>
+ .
+ Similarly, a cache that has had
+ <literal>destroy()</literal>
+ invoked
+ on it can be created again with a new call to
+ <literal>create()</literal>
+ (and then started again with a
+ <literal>start()</literal>
+ call).
+ </para>
+ </section>
+
+ <section>
+ <title>Cache Modes</title>
+ <para>
+ Although technically not part of the API, the
+ <emphasis>mode</emphasis>
+ in which the cache is configured to operate affects the cluster-wide
+ behavior of any
+ <literal>put</literal>
+ or
+ <literal>remove</literal>
+ operation, so we'll briefly mention the various modes here.
+ </para>
+ <para>
+ JBoss Cache modes are denoted by the
+ <literal>org.jboss.cache.config.Configuration.CacheMode</literal>
+ enumeration.
+ They consist of:
+ <itemizedlist>
+ <listitem>
+ <emphasis>LOCAL</emphasis>
+ - local, non-clustered cache. Local caches don't join a cluster and don't
+ communicate with other caches in a cluster. Therefore their contents don't need to be Serializable;
+ however, we recommend making them Serializable, allowing you the flexibility to change the cache mode at
+ any time.
+ </listitem>
+ <listitem>
+ <emphasis>REPL_SYNC</emphasis>
+ - synchronous replication. Replicated caches replicate all changes to the other
+ caches in the cluster. Synchronous replication means that changes are replicated and the caller blocks
+ until replication acknowledgements are received.
+ </listitem>
+ <listitem>
+ <emphasis>REPL_ASYNC</emphasis>
+ - asynchronous replication. Similar to REPL_SYNC above, replicated caches replicate
+ all changes to the other caches in the cluster. Being asynchronous, the caller does not block until
+ replication acknowledgements are received.
+ </listitem>
+ <listitem>
+ <emphasis>INVALIDATION_SYNC</emphasis>
+ - if a cache is configured for invalidation rather than replication,
+ every time data is changed in a cache other caches in the cluster
+ receive a message informing them that their data is now stale and should
+ be evicted from memory. This reduces replication overhead while still being able to invalidate stale data
+ on remote caches.
+ </listitem>
+ <listitem>
+ <emphasis>INVALIDATION_ASYNC</emphasis>
+ - as above, except this invalidation mode causes invalidation messages
+ to be broadcast asynchronously.
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>See the
+ <link linkend="clustering">chapter on Clustering</link>
+ for
+ more details on how the cache's mode affects behavior. See the
+ <link linkend="configuration">chapter on Configuration</link>
+ for info
+ on how to configure things like the cache's mode.
+ </para>
+ </section>
+
+ <section id="api.listener">
+ <title>
+ Adding a CacheListener
+ </title>
+ <para>
+ The
+ <literal>@org.jboss.cache.notifications.annotation.CacheListener</literal>
+ annotation is a convenient
+ mechanism for receiving notifications from a cache about events that happen in the cache. Classes annotated
+ with
+ <literal>@CacheListener</literal>
+ need to be public classes. In addition, the class needs to have one or
+ more methods annotated with one of the method-level annotations (in the
+ <literal>org.jboss.cache.notifications.annotation</literal>
+ package). Methods annotated as such need to be public, have a void return type, and accept a single parameter
+ of
+ type
+ <literal>org.jboss.cache.notifications.event.Event</literal>
+ or one of it's subtypes.
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>@CacheStarted</literal>
+ - methods annotated such receive a notification when the cache is
+ started. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.CacheStartedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@CacheStopped</literal>
+ - methods annotated such receive a notification when the cache is
+ stopped. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.CacheStoppedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeCreated</literal>
+ - methods annotated such receive a notification when a node is
+ created. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeCreatedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeRemoved</literal>
+ - methods annotated such receive a notification when a node is
+ removed. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeRemovedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeModified</literal>
+ - methods annotated such receive a notification when a node is
+ modified. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeModifiedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeMoved</literal>
+ - methods annotated such receive a notification when a node is
+ moved. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeMovedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeVisited</literal>
+ - methods annotated such receive a notification when a node is
+ started. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeVisitedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeLoaded</literal>
+ - methods annotated such receive a notification when a node is
+ loaded from a
+ <literal>CacheLoader</literal>
+ . Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeLoadedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeEvicted</literal>
+ - methods annotated such receive a notification when a node is
+ evicted from memory. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeEvictedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodeActivated</literal>
+ - methods annotated such receive a notification when a node is
+ activated. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodeActivatedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@NodePassivated</literal>
+ - methods annotated such receive a notification when a node is
+ passivated. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.NodePassivatedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@TransactionRegistered</literal>
+ - methods annotated such receive a notification when the cache
+ registers a
+ <literal>javax.transaction.Synchronization</literal>
+ with a registered transaction manager.
+ Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.TransactionRegisteredEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@TransactionCompleted</literal>
+ - methods annotated such receive a notification when the cache
+ receives a commit or rollback call from a registered transaction manager.
+ Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.TransactionCompletedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@ViewChanged</literal>
+ - methods annotated such receive a notification when the group structure
+ of the cluster changes. Methods need to accept a parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.ViewChangedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@CacheBlocked</literal>
+ - methods annotated such receive a notification when the cluster
+ requests that cache operations are blocked for a state transfer event. Methods need to accept a
+ parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.CacheBlockedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>@CacheUnblocked</literal>
+ - methods annotated such receive a notification when the cluster
+ requests that cache operations are unblocked after a state transfer event. Methods need to accept a
+ parameter type which is assignable from
+ <literal>org.jboss.cache.notifications.event.CacheUnblockedEvent</literal>
+ .
+ </para>
+ </listitem>
+
+ </itemizedlist>
+ </para>
+ <para>
+ Refer to the javadocs on the annotations as well as the
+ <literal>Event</literal>
+ subtypes
+ for details of what is passed in to your method, and when.
+ </para>
+ <para>
+ Example:
+ <programlisting><![CDATA[
+
+ @CacheListener
+ public class MyListener
+ {
+
+ @CacheStarted
+ @CacheStopped
+ public void cacheStartStopEvent(Event e)
+ {
+ switch (e.getType())
+ {
+ case Event.Type.CACHE_STARTED:
+ System.out.println("Cache has started");
+ break;
+ case Event.Type.CACHE_STOPPED:
+ System.out.println("Cache has stopped");
+ break;
+ }
+ }
+
+ @NodeCreated
+ @NodeRemoved
+ @NodeVisited
+ @NodeModified
+ @NodeMoved
+ public void logNodeEvent(NodeEvent ne)
+ {
+ log("An event on node " + ne.getFqn() + " has occured");
+ }
+ }
+
+ ]]></programlisting>
+ </para>
+ </section>
+
+ <section>
+ <title>Using Cache Loaders</title>
+ <para>
+ Cache loaders are an important part of JBoss Cache. They allow persistence of nodes to disk or to remote cache
+ clusters, and allow for passivation when caches run out of memory. In addition, cache loaders allow JBoss Cache
+ to perform 'warm starts', where in-memory state can be preloaded from persistent storage. JBoss Cache ships
+ with a number of cache loader implementations.
+ <itemizedlist>
+ <listitem>
+ <literal>org.jboss.cache.loader.FileCacheLoader</literal>
+ - a basic, filesystem based cache loader that persists data to disk. Non-transactional and not very
+ performant, but a very simple solution. Used mainly for testing and not recommended for production use.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.loader.JDBCCacheLoader</literal>
+ - uses a JDBC connection to store data. Connections could be created and maintained in an internal pool
+ (uses the c3p0 pooling library)
+ or from a configured DataSource. The database this CacheLoader connects to could be local or remotely
+ located.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.loader.BdbjeCacheLoader</literal>
+ - uses Oracle's BerkeleyDB file-based transactional database to persist data. Transactional and very
+ performant, but potentially restrictive license.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.loader.JdbmCacheLoader</literal>
+ - an upcoming open source alternative to the BerkeleyDB.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.loader.tcp.TcpCacheLoader</literal>
+ - uses a TCP socket to "persist" data to a remote cluster, using a "far cache" pattern.
+ <footnote>
+ <para>http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossClusteringPatternFarCache</para>
+ </footnote>
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.loader.ClusteredCacheLoader</literal>
+ - used as a "read-only" CacheLoader, where other nodes in the cluster are queried for state.
+ </listitem>
+ </itemizedlist>
+ These CacheLoaders, along with advanced aspects and tuning issues, are discussed in the
+ <link linkend="cache_loaders">chapter dedicated to CacheLoaders</link>
+ .
+ </para>
+ </section>
+
+ <section>
+ <title>Using Eviction Policies</title>
+ <para>
+ Eviction policies are the counterpart to CacheLoaders. They are necessary to make sure the cache does not run
+ out of memory and when the cache starts to fill,
+ the eviction algorithm running in a separate thread offloads in-memory state to the CacheLoader and frees up
+ memory. Eviction policies can be configured
+ on a per-region basis, so different subtrees in the cache could have different eviction preferences.
+
+ JBoss Cache ships with several eviction policies:
+ <itemizedlist>
+ <listitem>
+ <literal>org.jboss.cache.eviction.LRUPolicy</literal>
+ - an eviction policy that evicts the least recently used nodes when thresholds are hit.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.LFUPolicy</literal>
+ - an eviction policy that evicts the least frequently used nodes when thresholds are hit.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.MRUPolicy</literal>
+ - an eviction policy that evicts the most recently used nodes when thresholds are hit.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.FIFOPolicy</literal>
+ - an eviction policy that creates a first-in-first-out queue and evicts the oldest nodes when thresholds
+ are hit.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.ExpirationPolicy</literal>
+ - an eviction policy that selects nodes for eviction based on an expiry time each node is configured
+ with.
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.ElementSizePolicy</literal>
+ - an eviction policy that selects nodes for eviction based on the number of key/value pairs held in the
+ node.
+ </listitem>
+ </itemizedlist>
+ Detailed configuration and implementing custom eviction policies are discussed in the
+ <link linkend="eviction_policies">chapter dedicated to eviction policies.</link>
+ .
+ </para>
+ </section>
+</chapter>
Added: pojo/trunk/src/main/docbook/userguide/en/modules/cache_loaders.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/cache_loaders.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/cache_loaders.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,1325 @@
+<chapter id="cache_loaders">
+ <title>Cache Loaders</title>
+ <para>JBoss Cache can use a
+ <literal>CacheLoader</literal>
+ to back up the in-memory cache to a backend datastore.
+ If JBoss Cache is configured with a cache loader, then the following features are provided:
+ <itemizedlist>
+ <listitem>Whenever a cache element is accessed, and that element is not in
+ the cache (e.g. due to eviction or due to server restart), then the cache loader transparently
+ loads the element into the cache if found in the backend
+ store.
+ </listitem>
+
+ <listitem>Whenever an element is modified, added or removed, then that
+ modification is persisted in the backend store via the cache loader. If
+ transactions are used, all modifications created within a transaction
+ are persisted. To this end, the
+ <literal>CacheLoader</literal>
+ takes part in the two
+ phase commit protocol run by the transaction manager, although it does not do so explicitly.
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <section>
+ <title>The CacheLoader Interface and Lifecycle</title>
+
+ <figure>
+ <title>The CacheLoader interface</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="CacheLoader.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+
+ <para>The interaction between JBoss Cache and a
+ <literal>CacheLoader</literal>
+ implementation is as follows. When
+ <literal>CacheLoaderConfiguration</literal>
+ (see below) is non-null, an
+ instance of each configured
+ <literal>CacheLoader</literal>
+ is created when the cache is created, and started when the cache is started.
+ </para>
+
+ <para>
+ <literal>CacheLoader.create()</literal>
+ and
+ <literal>CacheLoader.start()</literal>
+ are called when the cache is
+ started. Correspondingly,
+ <literal>stop()</literal>
+ and
+ <literal>destroy()</literal>
+ are called when the cache is
+ stopped.
+ </para>
+
+ <para>Next,
+ <literal>setConfig()</literal>
+ and
+ <literal>setCache()</literal>
+ are called. The latter can be used to
+ store a reference to the cache, the former is used to configure this
+ instance of the
+ <literal>CacheLoader</literal>
+ . For example, here a database cache loader
+ could establish a connection to the database.
+ </para>
+
+ <para>The
+ <literal>CacheLoader</literal>
+ interface has a set of methods that are called
+ when no transactions are used:
+ <literal>get()</literal>
+ ,
+ <literal>put()</literal>
+ ,
+ <literal>remove()</literal>
+ and
+ <literal>removeData()</literal>
+ : they get/set/remove the value
+ immediately. These methods are described as javadoc comments in the
+ interface.
+ </para>
+
+ <para>Then there are three methods that are used with transactions:
+ <literal>prepare()</literal>
+ ,
+ <literal>commit()</literal>
+ and
+ <literal>rollback()</literal>
+ . The
+ <literal>prepare()</literal>
+ method
+ is called when a transaction is to be committed. It has a transaction
+ object and a list of modfications as argument. The transaction object
+ can be used as a key into a hashmap of transactions, where the values
+ are the lists of modifications. Each modification list has a number of
+ <literal>Modification</literal>
+ elements, which represent the changes
+ made to a cache for a given transaction. When
+ <literal>prepare()</literal>
+ returns successfully, then the cache loader
+ <emphasis>must</emphasis>
+ be able to commit (or rollback) the
+ transaction successfully.
+ </para>
+
+ <para>
+ JBoss Cache takes care of calling prepare(), commit()
+ and rollback() on the cache loaders at the right time.
+ </para>
+
+ <para>The
+ <literal>commit()</literal>
+ method tells the cache loader to
+ commit the transaction, and the
+ <literal>rollback()</literal>
+ method
+ tells the cache loader to discard the changes associated with that
+ transaction.
+ </para>
+
+ <para>See the javadocs on this interface for a detailed explanation on each method and the contract
+ implementations
+ would need to fulfil.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Configuration</title>
+
+ <para>Cache loaders are configured as follows in the JBoss Cache XML
+ file. Note that you can define several cache loaders, in
+ a chain. The impact is that the cache will look at all of the cache
+ loaders in the order they've been configured, until it finds a valid,
+ non-null element of data. When performing writes, all cache loaders are
+ written to (except if the
+ <literal>ignoreModifications</literal>
+ element has been set to
+ <literal>true</literal>
+ for a specific cache loader. See the configuration section below for
+ details.
+ </para>
+
+ <programlisting>
+ <![CDATA[
+
+...
+
+<!-- Cache loader config block -->
+<attribute name="CacheLoaderConfiguration">
+ <config>
+ <!-- if passivation is true, only the first cache loader is used; the rest are ignored -->
+ <passivation>false</passivation>
+ <!-- comma delimited FQNs to preload -->
+ <preload>/</preload>
+ <!-- are the cache loaders shared in a cluster? -->
+ <shared>false</shared>
+
+ <!-- we can now have multiple cache loaders, which get chained -->
+ <!-- the 'cacheloader' element may be repeated -->
+ <cacheloader>
+
+ <class>org.jboss.cache.loader.JDBCCacheLoader</class>
+
+ <!-- properties to pass in to the cache loader -->
+ <properties>
+ cache.jdbc.driver=com.mysql.jdbc.Driver
+ cache.jdbc.url=jdbc:mysql://localhost:3306/jbossdb
+ cache.jdbc.user=root
+ cache.jdbc.password=
+ cache.jdbc.sql-concat=concat(1,2)
+ </properties>
+
+ <!-- whether the cache loader writes are asynchronous -->
+ <async>false</async>
+
+ <!-- only one cache loader in the chain may set fetchPersistentState to true.
+ An exception is thrown if more than one cache loader sets this to true. -->
+ <fetchPersistentState>true</fetchPersistentState>
+
+ <!-- determines whether this cache loader ignores writes - defaults to false. -->
+ <ignoreModifications>false</ignoreModifications>
+
+ <!-- if set to true, purges the contents of this cache loader when the cache starts up.
+ Defaults to false. -->
+ <purgeOnStartup>false</purgeOnStartup>
+
+ <!-- defines the cache loader as a singleton store where only the coordinator of the
+ cluster will store modifications. -->
+ <singletonStore>
+ <!-- if true, singleton store functionality is enabled, defaults to false -->
+ <enabled>false</enabled>
+
+ <!-- implementation class for singleton store functionality which must extend
+ org.jboss.cache.loader.AbstractDelegatingCacheLoader. Default implementation
+ is org.jboss.cache.loader.SingletonStoreCacheLoader -->
+ <class>org.jboss.cache.loader.SingletonStoreCacheLoader</class>
+
+ <!-- properties and default values for the default singleton store functionality
+ implementation -->
+ <properties>
+ pushStateWhenCoordinator=true
+ pushStateWhenCoordinatorTimeout=20000
+ </properties>
+ </singletonStore>
+ </cacheloader>
+
+ </config>
+</attribute>
+]]>
+ </programlisting>
+
+ <para>The
+ <literal>class</literal>
+ element defines the
+ class of the cache loader implementation. (Note that, because of a bug in
+ the properties editor in JBoss AS, backslashes in variables for Windows
+ filenames might not get expanded correctly, so replace="false" may be
+ necessary). Note that an implementation of cache loader has to have an empty
+ constructor.
+ </para>
+
+ <para>The
+ <literal>properties</literal>
+ element defines a configuration
+ specific to the given implementation. The filesystem-based
+ implementation for example defines the root directory to be used,
+ whereas a database implementation might define the database URL, name
+ and password to establish a database connection. This configuration is
+ passed to the cache loader implementation via
+ <literal>CacheLoader.setConfig(Properties)</literal>
+ . Note that
+ backspaces may have to be escaped.
+ </para>
+
+ <para>
+ <literal>preload</literal>
+ allows us to define a list of nodes, or
+ even entire subtrees, that are visited by the cache on startup, in order
+ to preload the data associated with those nodes. The default ("/") loads
+ the entire data available in the backend store into the cache, which is
+ probably not a good idea given that the data in the backend store might
+ be large. As an example,
+ <literal>/a,
+ /product/catalogue
+ </literal>
+ loads the subtrees
+ <literal>/a</literal>
+ and
+ <literal>/product/catalogue</literal>
+ into the cache, but nothing
+ else. Anything else is loaded lazily when accessed. Preloading makes
+ sense when one anticipates using elements under a given subtree
+ frequently.
+ .
+ </para>
+
+ <para>
+ <literal>fetchPersistentState</literal>
+ determines whether or not
+ to fetch the persistent state of a cache when joining a cluster. Only
+ one configured cache loader may set this property to true; if more than
+ one cache loader does so, a configuration exception will be thrown when
+ starting your cache service.
+ </para>
+
+ <para>
+ <literal>async</literal>
+ determines whether writes to the cache
+ loader block until completed, or are run on a separate thread so writes
+ return immediately. If this is set to true, an instance of
+ <literal>org.jboss.cache.loader.AsyncCacheLoader</literal>
+ is
+ constructed with an instance of the actual cache loader to be used. The
+ <literal>AsyncCacheLoader</literal>
+ then delegates all requests to the
+ underlying cache loader, using a separate thread if necessary. See the
+ Javadocs on
+ <literal>AsyncCacheLoader</literal>
+ for more details. If unspecified, the
+ <literal>async</literal>
+ element
+ defaults to
+ <literal>false</literal>
+ .
+ </para>
+
+ <para>
+ <emphasis role="bold">Note on using the
+ <literal>async</literal>
+ element:
+ </emphasis>
+ there is always the possibility of dirty reads since
+ all writes are performed asynchronously, and it is thus impossible to
+ guarantee when (and even if) a write succeeds. This needs to be kept in
+ mind when setting the
+ <literal>async</literal>
+ element to true.
+ </para>
+
+ <para>
+ <literal>ignoreModifications</literal>
+ determines whether write
+ methods are pushed down to the specific cache loader. Situations may
+ arise where transient application data should only reside in a file
+ based cache loader on the same server as the in-memory cache, for
+ example, with a further shared
+ <literal>JDBCCacheLoader</literal>
+ used by all servers in
+ the network. This feature allows you to write to the 'local' file cache
+ loader but not the shared
+ <literal>JDBCCacheLoader</literal>
+ . This property defaults to
+ <literal>false</literal>
+ , so writes are propagated to all cache loaders
+ configured.
+ </para>
+
+ <para>
+ <literal>purgeOnStatup</literal>
+ empties the specified cache loader
+ (if
+ <literal>ignoreModifications</literal>
+ is
+ <literal>false</literal>
+ )
+ when the cache loader starts up.
+ </para>
+
+ <para>
+ <literal>shared</literal>
+ indicates that the cache loader is shared among different cache instances, for example where all instances in a
+ cluster use the same JDBC settings t talk to the same remote, shared database. Setting this to
+ <literal>true</literal>
+ prevents repeated and unnecessary writes of the same data to the cache loader by different cache instances.
+ Default value is
+ <literal>false</literal>
+ .
+ </para>
+
+ <section>
+ <title>Singleton Store Configuration</title>
+
+ <para>
+ <literal>singletonStore</literal>
+ element enables modifications to be stored by only one node in the cluster,
+ the coordinator. Essentially, whenever any data comes in to some node
+ it is always replicated so as to keep the caches' in-memory states in
+ sync; the coordinator, though, has the sole responsibility of pushing
+ that state to disk. This functionality can be activated setting the
+ <literal>enabled</literal>
+ subelement to true in all nodes, but
+ again only the coordinator of the cluster will store the modifications
+ in the underlying cache loader as defined in
+ <literal>cacheloader</literal>
+ element. You cannot define a cache loader as
+ <literal>shared</literal>
+ and with
+ <literal>singletonStore</literal>
+ enabled at the same time.
+ Default value for
+ <literal>enabled</literal>
+ is
+ <literal>false</literal>
+ .
+ </para>
+
+ <para>
+ Optionally, within the
+ <literal>singletonStore</literal>
+ element, you can define a
+ <literal>class</literal>
+ element that specifies the implementation class that provides the
+ singleton store functionality. This class must extend
+ <literal>org.jboss.cache.loader.AbstractDelegatingCacheLoader</literal>
+ , and if absent, it defaults to
+ <literal>org.jboss.cache.loader.SingletonStoreCacheLoader</literal>
+ .
+ </para>
+
+ <para>
+ The
+ <literal>properties</literal>
+ subelement defines properties that allow changing the behaivour of the
+ class providing the singleton store functionality. By default,
+ <literal>pushStateWhenCoordinator</literal>
+ and
+ <literal>pushStateWhenCoordinatorTimeout</literal>
+ properties have been defined, but more could be added as
+ required by the user-defined class providing singleton store
+ functionality.
+ </para>
+
+ <para>
+ <literal>pushStateWhenCoordinator</literal>
+ allows the in-memory
+ state to be pushed to the cache store when a node becomes the
+ coordinator, as a result of the new election of coordinator due to a
+ cluster topology change. This can be very useful in situations where the
+ coordinator crashes and there's a gap in time until the new coordinator
+ is elected. During this time, if this property was set to
+ <literal>false</literal>
+ and the
+ cache was updated, these changes would never be persisted. Setting this
+ property to
+ <literal>true</literal>
+ would ensure that any changes during this process also
+ get stored in the cache loader. You would also want to set this property
+ to
+ <literal>true</literal>
+ if each node's cache loader is configured with a different
+ location. Default value is
+ <literal>true</literal>
+ .
+ </para>
+
+ <para>
+ <literal>pushStateWhenCoordinatorTimeout</literal>
+ is only relevant if
+ <literal>pushStateWhenCoordinator</literal>
+ is
+ <literal>true</literal>
+ in which case, sets the maximum number of milliseconds that the process
+ of pushing the in-memory state to the underlying cache loader should take,
+ reporting a
+ <literal>PushStateException</literal>
+ if exceeded. Default value is 20000.
+ </para>
+
+ <para>
+ <emphasis role="bold">Note on using the
+ <literal>singletonStore</literal>
+ element:
+ </emphasis>
+ setting
+ up a cache loader as a singleton and using cache passivation (via
+ evictions) can lead to undesired effects. If a node is to be passivated
+ as a result of an eviction, while the cluster is in the process of
+ electing a new coordinator, the data will be lost. This is because no
+ coordinator is active at that time and therefore, none of the nodes in
+ the cluster will store the passivated node. A new coordinator is elected
+ in the cluster when either, the coordinator leaves the cluster, the
+ coordinator crashes or stops responding.
+ </para>
+ </section>
+ </section>
+
+ <section id="cl.impls">
+
+ <title>Shipped Implementations</title>
+
+ <para>The currently available implementations shipped with JBoss Cache are as follows.</para>
+
+ <section>
+ <title>File system based cache loaders</title>
+ <para>
+ JBoss Cache ships with several cache loaders that utilise the file system as a data store. They all require
+ that the
+ <literal><![CDATA[<cacheloader><properties>]]></literal>
+ configuration element
+ contains a
+ <literal>location</literal>
+ property, which maps to a directory to be used as a persistent store.
+ (e.g.,
+ <literal>location=/tmp/myDataStore</literal>
+ ). Used mainly for testing and not recommended for production use.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>FileCacheLoader</literal>
+ , which is a simple filesystem-based implementation. By default, this cache
+ loader checks for any potential character portability issues in the
+ location or tree node names, for example invalid characters, producing
+ warning messages. These checks can be disabled adding
+ <literal>check.character.portability</literal>
+ property to the
+ <literal><![CDATA[<properties>]]></literal>
+ element and setting it to
+ <literal>false</literal>
+ (e.g.,
+ <literal>check.character.portability=false</literal>
+ ).
+ </para>
+ <para>
+ The FileCacheLoader has some severe limitations which restrict it's use in a production
+ environment, or if used in such an environment, it should be used with due care and sufficient
+ understanding of these limitations.
+ <itemizedlist>
+ <listitem>Due to the way the FileCacheLoader represents a tree structure on disk (directories and
+ files) traversal is inefficient for deep trees.
+ </listitem>
+ <listitem>Usage on shared filesystems like NFS, Windows shares, etc. should be avoided as these do
+ not implement proper file locking and can cause data corruption.
+ </listitem>
+ <listitem>Usage with an isolation level of NONE can cause corrupt writes as multiple threads
+ attempt to write to the same file.
+ </listitem>
+ <listitem>File systems are inherently not transactional, so when attempting to use your cache in a
+ transactional context, failures when writing to the file (which happens during the commit phase)
+ cannot be recovered.
+ </listitem>
+ </itemizedlist>
+
+ As a rule of thumb, it is recommended that the FileCacheLoader not be used in a highly concurrent,
+ transactional or stressful environment, and it's use is restricted to testing.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>BdbjeCacheLoader</literal>
+ , which is a cache loader implementation based on the Oracle/Sleepycat's
+ <ulink url="http://www.oracle.com/database/berkeley-db/index.html">BerkeleyDB Java Edition</ulink>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>JdbmCacheLoader</literal>
+ , which is a cache loader
+ implementation based on the
+ <ulink url="http://jdbm.sourceforge.net/">JDBM engine</ulink>
+ , a fast and free alternative to
+ BerkeleyDB.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Note that the BerkeleyDB implementation is much more efficient than
+ the filesystem-based implementation, and provides transactional
+ guarantees, but requires a commercial license if distributed with an
+ application (see http://www.oracle.com/database/berkeley-db/index.html for
+ details).
+ </para>
+
+ </section>
+
+ <section>
+ <title>Cache loaders that delegate to other caches</title>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>LocalDelegatingCacheLoader</literal>
+ , which enables
+ loading from and storing to another local (same JVM) cache.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ClusteredCacheLoader</literal>
+ , which allows querying
+ of other caches in the same cluster for in-memory data via the same
+ clustering protocols used to replicate data. Writes are
+ <emphasis>not</emphasis>
+ 'stored' though, as replication would
+ take care of any updates needed. You need to specify a property
+ called
+ <literal>timeout</literal>
+ , a long value telling the cache
+ loader how many milliseconds to wait for responses from the cluster
+ before assuming a null value. For example,
+ <literal>timeout = 3000</literal>
+ would use a timeout value of 3 seconds.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+
+ <section id="cl.jdbc">
+ <title>JDBCCacheLoader</title>
+
+ <para>JBossCache is distributed with a JDBC-based cache loader
+ implementation that stores/loads nodes' state into a relational database.
+ The implementing class is
+ <literal>org.jboss.cache.loader.JDBCCacheLoader</literal>
+ .
+ </para>
+
+ <para>The current implementation uses just one table. Each row in the table
+ represents one node and contains three columns:
+ <itemizedlist>
+ <listitem>column for
+ <literal>Fqn</literal>
+ (which is also a primary key
+ column)
+ </listitem>
+
+ <listitem>column for node contents (attribute/value
+ pairs)
+ </listitem>
+
+ <listitem>column for parent
+ <literal>Fqn</literal>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ <literal>Fqn</literal>
+ 's are stored as strings. Node content is stored
+ as a BLOB.
+ <emphasis>WARNING:</emphasis>
+ JBoss Cache does not impose any
+ limitations on the types of objects used in
+ <literal>Fqn</literal>
+ but this implementation of
+ cache loader requires
+ <literal>Fqn</literal>
+ to contain only objects of type
+ <literal>java.lang.String</literal>
+ . Another limitation for
+ <literal>Fqn</literal>
+ is its
+ length. Since
+ <literal>Fqn</literal>
+ is a primary key, its default column type is
+ <literal>VARCHAR</literal>
+ which can store text values up to some
+ maximum length determined by the database in use.
+ </para>
+
+ <para>See
+ <ulink
+ url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JDBCCacheLoader">
+ http://wiki.jboss.org/wiki/Wiki.jsp?page=JDBCCacheLoader
+ </ulink>
+ for configuration tips with specific database systems.
+ </para>
+
+ <section>
+ <title>JDBCCacheLoader configuration</title>
+
+ <section>
+ <title>Table configuration</title>
+
+ <para>Table and column names as well as column types are
+ configurable with the following properties.
+ <itemizedlist>
+ <listitem>
+ <emphasis>cache.jdbc.table.name</emphasis>
+ - the name
+ of the table. The default value is 'jbosscache'.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.table.primarykey</emphasis>
+ - the
+ name of the primary key for the table. The default value is
+ 'jbosscache_pk'.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.table.create</emphasis>
+ - can be
+ true or false. Indicates whether to create the table during startup.
+ If true, the table is created if it doesn't already exist. The
+ default value is true.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.table.drop</emphasis>
+ - can be
+ true or false. Indicates whether to drop the table during shutdown. The
+ default value is true.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.fqn.column</emphasis>
+ - FQN
+ column name. The default value is 'fqn'.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.fqn.type</emphasis>
+ - FQN column
+ type. The default value is 'varchar(255)'.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.node.column</emphasis>
+ - node
+ contents column name. The default value is 'node'.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.node.type</emphasis>
+ - node
+ contents column type. The default value is 'blob'. This type must specify
+ a valid binary data type for the database being used.
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>DataSource</title>
+
+ <para>If you are using JBossCache in a managed environment (e.g., an
+ application server) you can specify the JNDI name of the DataSource
+ you want to use.
+ <itemizedlist>
+ <listitem>
+ <emphasis>cache.jdbc.datasource</emphasis>
+ - JNDI name
+ of the DataSource. The default value is
+ <literal>java:/DefaultDS</literal>
+ .
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>JDBC driver</title>
+
+ <para>If you are
+ <emphasis>not</emphasis>
+ using DataSource you have
+ the following properties to configure database access using a JDBC
+ driver.
+ <itemizedlist>
+ <listitem>
+ <emphasis>cache.jdbc.driver</emphasis>
+ - fully
+ qualified JDBC driver name.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.url</emphasis>
+ - URL to connect
+ to the database.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.user</emphasis>
+ - user name to
+ connect to the database.
+ </listitem>
+
+ <listitem>
+ <emphasis>cache.jdbc.password</emphasis>
+ - password to
+ connect to the database.
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>c3p0 connection pooling</title>
+
+ <para>JBoss Cache implements JDBC connection pooling when running outside of an application server
+ standalone using
+ the c3p0:JDBC DataSources/Resource Pools library. In order to enable it, just edit the following
+ property:
+ <itemizedlist>
+ <listitem>
+ <emphasis>cache.jdbc.connection.factory</emphasis>
+ - Connection factory class name.
+ If not set, it defaults to standard non-pooled implementation. To enable c3p0 pooling, just set
+ the
+ connection factory class for c3p0. See example below.
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>You can also set any c3p0 parameters in the same cache loader properties section but don't forget
+ to
+ start the property name with 'c3p0.'. To find a list of available properties, please check the
+ c3p0 documentation for the c3p0 library version distributed in
+ <ulink url="http://sourceforge.net/projects/c3p0">c3p0:JDBC DataSources/Resource Pools</ulink>
+ .
+ Also, in order to provide quick and easy way to try out different pooling
+ parameters, any of these properties can be set via a System property overriding any values these
+ properties might have in the JBoss Cache XML configuration file, for example:
+ <literal>-Dc3p0.maxPoolSize=20</literal>
+ .
+ If a c3p0 property is not defined in either the configuration file or as a System property, default
+ value, as indicated in the c3p0 documentation, will apply.
+ </para>
+ </section>
+
+ <section>
+ <title>Configuration example</title>
+
+ <para>Below is an example of a JDBCCacheLoader using Oracle as
+ database. The CacheLoaderConfiguration XML element contains an
+ arbitrary set of properties which define the database-related
+ configuration.
+ </para>
+
+ <para>
+ <programlisting>
+ <![CDATA[
+<attribute name="CacheLoaderConfiguration">
+<config>
+ <passivation>false</passivation>
+ <preload>/some/stuff</preload>
+ <cacheloader>
+ <class>org.jboss.cache.loader.JDBCCacheLoader</class>
+
+ <properties>
+ cache.jdbc.table.name=jbosscache
+ cache.jdbc.table.create=true
+ cache.jdbc.table.drop=true
+ cache.jdbc.table.primarykey=jbosscache_pk
+ cache.jdbc.fqn.column=fqn
+ cache.jdbc.fqn.type=varchar(255)
+ cache.jdbc.node.column=node
+ cache.jdbc.node.type=blob
+ cache.jdbc.parent.column=parent
+ cache.jdbc.driver=oracle.jdbc.OracleDriver
+ cache.jdbc.url=jdbc:oracle:thin:@localhost:1521:JBOSSDB
+ cache.jdbc.user=SCOTT
+ cache.jdbc.password=TIGER
+ cache.jdbc.sql-concat=concat(1,2)
+ </properties>
+
+ <async>false</async>
+ <fetchPersistentState>true</fetchPersistentState>
+ <ignoreModifications>false</ignoreModifications>
+ <purgeOnStartup>false</purgeOnStartup>
+ </cacheloader>
+</config>
+</attribute>
+]]>
+ </programlisting>
+ </para>
+
+ <para>As an alternative to configuring the entire JDBC connection,
+ the name of an existing data source can be given:
+ </para>
+
+ <programlisting>
+ <![CDATA[
+<attribute name="CacheLoaderConfiguration">
+<config>
+ <passivation>false</passivation>
+ <preload>/some/stuff</preload>
+ <cacheloader>
+ <class>org.jboss.cache.loader.JDBCCacheLoader</class>
+
+ <properties>
+ cache.jdbc.datasource=java:/DefaultDS
+ </properties>
+
+ <async>false</async>
+ <fetchPersistentState>true</fetchPersistentState>
+ <ignoreModifications>false</ignoreModifications>
+ <purgeOnStartup>false</purgeOnStartup>
+ </cacheloader>
+</config>
+</attribute>
+]]>
+ </programlisting>
+
+ <para>Cconfiguration example for a cache loader using c3p0 JDBC connection pooling:</para>
+
+ <programlisting>
+ <![CDATA[
+<attribute name="CacheLoaderConfiguration">
+<config>
+ <passivation>false</passivation>
+ <preload>/some/stuff</preload>
+ <cacheloader>
+ <class>org.jboss.cache.loader.JDBCCacheLoader</class>
+
+ <properties>
+ cache.jdbc.table.name=jbosscache
+ cache.jdbc.table.create=true
+ cache.jdbc.table.drop=true
+ cache.jdbc.table.primarykey=jbosscache_pk
+ cache.jdbc.fqn.column=fqn
+ cache.jdbc.fqn.type=varchar(255)
+ cache.jdbc.node.column=node
+ cache.jdbc.node.type=blob
+ cache.jdbc.parent.column=parent
+ cache.jdbc.driver=oracle.jdbc.OracleDriver
+ cache.jdbc.url=jdbc:oracle:thin:@localhost:1521:JBOSSDB
+ cache.jdbc.user=SCOTT
+ cache.jdbc.password=TIGER
+ cache.jdbc.sql-concat=concat(1,2)
+ cache.jdbc.connection.factory=org.jboss.cache.loader.C3p0ConnectionFactory
+ c3p0.maxPoolSize=20
+ c3p0.checkoutTimeout=5000
+ </properties>
+
+ <async>false</async>
+ <fetchPersistentState>true</fetchPersistentState>
+ <ignoreModifications>false</ignoreModifications>
+ <purgeOnStartup>false</purgeOnStartup>
+ </cacheloader>
+</config>
+</attribute>
+]]>
+ </programlisting>
+
+ </section>
+ </section>
+ </section>
+
+ <section id="cl.tcp">
+ <title>TcpDelegatingCacheLoader</title>
+
+ <para>This cache loader allows to delegate loads and stores to another
+ instance of JBoss Cache, which could reside (a) in the same address
+ space, (b) in a different process on the same host, or (c) in a
+ different process on a different host.
+ </para>
+
+ <para>A TcpDelegatingCacheLoader talks to a remote
+ <literal>org.jboss.cache.loader.tcp.TcpCacheServer</literal>
+ ,
+ which can be a standalone process started on the command line, or embedded as an MBean inside
+ JBoss AS. The
+ <literal>TcpCacheServer</literal>
+ has a reference to another JBoss Cache instance, which
+ it can create itself, or which is given to it (e.g. by JBoss, using
+ dependency injection).
+ </para>
+
+ <para>The TcpDelegatingCacheLoader is configured with the host and
+ port of the remote TcpCacheServer, and uses this to communicate to
+ it.
+ </para>
+
+ <para>The configuration looks as follows:</para>
+
+ <programlisting>
+ <![CDATA[
+<attribute name="CacheLoaderConfiguration">
+<config>
+ <cacheloader>
+ <class>org.jboss.cache.loader.TcpDelegatingCacheLoader</class>
+ <properties>
+ host=myRemoteServer
+ port=7500
+ </properties>
+ </cacheloader>
+</config>
+</attribute>
+]]>
+ </programlisting>
+
+ <para>This means this instance of JBoss Cache will delegate all load
+ and store requests to the remote TcpCacheServer running on
+ <literal>myRemoteServer:7500</literal>
+ .
+ </para>
+
+ <para>A typical use case could be multiple replicated instances of
+ JBoss Cache in the same cluster, all delegating to the same
+ TcpCacheServer instance. The TcpCacheServer might itself delegate to a
+ database via JDBCCacheLoader, but the point here is that - if we have
+ 5 nodes all accessing the same dataset - they will load the data from
+ the TcpCacheServer, which has do execute one SQL statement per
+ unloaded data set. If the nodes went directly to the database, then
+ we'd have the same SQL executed multiple times. So TcpCacheServer
+ serves as a natural cache in front of the DB (assuming that a network
+ round trip is faster than a DB access (which usually also include a
+ network round trip)).
+ </para>
+
+ <para>To alleviate single point of failure, we could configure several cache loaders.
+ The first cache loader is a ClusteredCacheLoader, the second a TcpDelegatingCacheLoader, and the
+ last a JDBCacheLoader, effectively defining our cost of access to a
+ cache in increasing order.
+ </para>
+
+ </section>
+
+ <section id="cl.transforming">
+ <title>Transforming Cache Loaders</title>
+
+ <para>The way cached data is written to
+ <literal>FileCacheLoader</literal>
+ and
+ <literal>JDBCCacheLoader</literal>
+ based cache stores has changed in JBoss Cache 2.0 in such way that
+ these cache loaders now write and read data using the same marhalling framework used to replicate data
+ accross the network. Such change is trivial for replication purpouses as it just requires the rest of the
+ nodes to understand this format. However, changing the format of the data in cache stores brings up a new
+ problem: how do users, which have their data stored in JBoss Cache 1.x.x format, migrate their stores to
+ JBoss Cache 2.0 format?
+ </para>
+
+ <para>With this in mind, JBoss Cache 2.0 comes with two cache loader implementations called
+ <literal>org.jboss.cache.loader.TransformingFileCacheLoader</literal>
+ and
+ <literal>org.jboss.cache.loader.TransformingJDBCCacheLoader</literal>
+ located within the optional
+ jbosscache-cacheloader-migration.jar file. These are one-off cache loaders that read data from the
+ cache store in JBoss Cache 1.x.x format and write data to cache stores in JBoss Cache 2.0 format.
+ </para>
+
+ <para>The idea is for users to modify their existing cache configuration file(s) momentarily to use these
+ cache loaders and for them to create a small Java application that creates an instance of this cache,
+ recursively reads the entire cache and writes the data read back into the cache. Once the data is
+ transformed, users can revert back to their original cache configuration file(s). In order to help the users
+ with this task, a cache loader migration example has been constructed which can be located under the
+ <literal>examples/cacheloader-migration</literal>
+ directory within the JBoss Cache distribution. This
+ example, called
+ <literal>examples.TransformStore</literal>
+ , is independent of the actual data stored in
+ the cache as it writes back whatever it was read recursively. It is highly recommended that anyone
+ interested in porting their data run this example first, which contains a
+ <literal>readme.txt</literal>
+ file with detailed information about the example itself, and also use it as base for their own application.
+ </para>
+
+ </section>
+
+ </section>
+
+
+ <section id="cl.pass">
+ <title>Cache Passivation</title>
+
+ <para>A cache loader can be used to enforce node passivation and
+ activation on eviction in a cache.
+ </para>
+
+ <para>
+ <emphasis>Cache Passivation</emphasis>
+ is the process of removing
+ an object from in-memory cache and writing it to a secondary data store
+ (e.g., file system, database) on eviction.
+ <emphasis>Cache
+ Activation
+ </emphasis>
+ is the process of restoring an object from the
+ data store into the in-memory cache when it's needed to be used. In both
+ cases, the configured cache loader will be used to read from the data
+ store and write to the data store.
+ </para>
+
+ <para>When an eviction policy in effect evicts a node
+ from the cache, if passivation is enabled, a notification that the node
+ is being passivated will be emitted to the cache listeners and the
+ node and its children will be stored in the cache loader store. When a
+ user attempts to retrieve a node that was evicted earlier, the node is loaded
+ (lazy loaded) from the cache loader store into memory. When
+ the node and its children have been loaded, they're removed from the
+ cache loader and a notification is emitted to the cache listeners
+ that the node has been activated.
+ </para>
+
+ <para>To enable cache passivation/activation, you can set
+ <literal>passivation</literal>
+ to true. The default is
+ <literal>false</literal>
+ .
+ When passivation is used, only the first cache loader configured is
+ used and all others are ignored.
+ </para>
+ </section>
+
+ <section>
+ <title>Strategies</title>
+ <para>
+ This section discusses different patterns of combining different cache loader types and configuration
+ options to achieve specific outcomes.
+ </para>
+
+ <section>
+ <title>Local Cache With Store</title>
+
+ <para>This is the simplest case. We have a JBoss Cache instance, whose
+ cache mode is
+ <literal>LOCAL</literal>
+ , therefore no replication is going
+ on. The cache loader simply loads non-existing elements from the store
+ and stores modifications back to the store. When the cache is started,
+ depending on the
+ <literal>preload</literal>
+ element, certain data can
+ be preloaded, so that the cache is partly warmed up.
+ </para>
+ </section>
+
+ <section>
+ <title>Replicated Caches With All Caches Sharing The Same Store</title>
+
+ <para>The following figure shows 2 JBoss Cache instances sharing the same
+ backend store:
+ </para>
+
+ <figure>
+ <title>2 nodes sharing a backend store</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="SharedCacheLoader.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Both nodes have a cache loader that accesses a common shared
+ backend store. This could for example be a shared filesystem (using
+ the FileCacheLoader), or a shared database. Because both nodes access
+ the same store, they don't necessarily need state transfer on
+ startup.
+ <footnote>
+ <para>Of course they can enable state transfer, if they want to
+ have a warm or hot cache after startup.
+ </para>
+ </footnote>
+ Rather, the
+ <literal>FetchInMemoryState</literal>
+ attribute could be set to false, resulting in a 'cold' cache, that
+ gradually warms up as elements are accessed and loaded for the first
+ time. This would mean that individual caches in a cluster might have
+ different in-memory state at any given time (largely depending on
+ their preloading and eviction strategies).
+ </para>
+
+ <para>When storing a value, the writer takes care of storing the
+ change in the backend store. For example, if node1 made change C1 and
+ node2 C2, then node1 would tell its cache loader to store C1, and node2
+ would tell its cache loader to store C2.
+ </para>
+ </section>
+
+ <section>
+ <title>Replicated Caches With Only One Cache Having A Store</title>
+
+ <figure>
+ <title>2 nodes but only one accesses the backend store</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="OnlyOneCacheLoader.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>This is a similar case to the previous one, but here only one
+ node in the cluster interacts with a backend store via its
+ cache loader. All other nodes perform in-memory replication. The idea
+ here is all application state is kept in memory in each node, with
+ the existence of multiple caches making the data highly available.
+ (This assumes that a client that needs the data is able to somehow
+ fail over from one cache to another.) The single persistent backend
+ store then provides a backup copy of the data in case all caches in
+ the cluster fail or need to be restarted.
+ </para>
+ <para>
+ Note that here it may make sense for the cache loader to store
+ changes asynchronously, that is <emphasis>not</emphasis>
+ on the caller's thread, in order not to slow
+ down the cluster by accessing (for example) a database. This is a
+ non-issue when using asynchronous replication.
+ </para>
+ <para>
+ A weakness with this architecture is that the cache with access
+ to the cache loader becomes a single point of failure. Furthermore,
+ if the cluster is restarted, the cache with the cache loader must
+ be started first (easy to forget). A solution to the first problem
+ is to configure a cache loader on each node, but set the
+ <literal>singletonStore</literal> configuration to
+ <literal>true</literal>. With this kind of setup, one but only one
+ node will always be writing to a persistent store. However, this
+ complicates the restart problem, as before restarting you need
+ to determine which cache was writing before the shutdown/failure
+ and then start that cache first.
+ </para>
+ </section>
+
+ <section>
+ <title>Replicated Caches With Each Cache Having Its Own Store</title>
+
+ <figure>
+ <title>2 nodes each having its own backend store</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="LocalCacheLoader.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Here, each node has its own datastore. Modifications to the
+ cache are (a) replicated across the cluster and (b) persisted using
+ the cache loader. This means that all datastores have exactly the same
+ state. When replicating changes synchronously and in a transaction,
+ the two phase commit protocol takes care that all modifications are
+ replicated and persisted in each datastore, or none is replicated and
+ persisted (atomic updates).
+ </para>
+
+ <para>Note that JBoss Cache is
+ <emphasis>not</emphasis>
+ an
+ XA Resource, that means it doesn't implement recovery. When used with a
+ transaction manager that supports recovery, this functionality is not
+ available.
+ </para>
+
+ <para>The challenge here is state transfer: when a new node starts it
+ needs to do the following:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>Tell the coordinator (oldest node in a cluster) to send it
+ the state. This is always a full state transfer, overwriting
+ any state that may already be present.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>The coordinator then needs to wait until all in-flight
+ transactions have completed. During this time, it will not allow
+ for new transactions to be started.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Then the coordinator asks its cache loader for the entire
+ state using
+ <literal>loadEntireState()</literal>
+ . It then sends
+ back that state to the new node.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>The new node then tells its cache loader to store that state
+ in its store, overwriting the old state. This is the
+ <literal>CacheLoader.storeEntireState()</literal>
+ method
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>As an option, the transient (in-memory) state can be
+ transferred as well during the state transfer.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>The new node now has the same state in its backend store as
+ everyone else in the cluster, and modifications received from
+ other nodes will now be persisted using the local
+ cache loader.
+ </para>
+ </listitem>
+ </orderedlist>
+
+
+ </section>
+
+ <section>
+ <title>Hierarchical Caches</title>
+
+ <para>If you need to set up a hierarchy within a single JVM, you can
+ use the
+ <literal>LocalDelegatingCacheLoader</literal>
+ . This type of
+ hierarchy can currently only be set up programmatically.
+ </para>
+
+ <para>
+ Hierarchical caches could also be set up spanning more than one JVM or server, using the
+ <literal>TcpDelegatingCacheLoader</literal>
+ .
+ <figure>
+ <title>TCP delegating cache loader</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="DelegatingCacheLoader.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ </para>
+
+ </section>
+
+
+ <section>
+ <title>Multiple Cache Loaders</title>
+
+ <para>
+ You can set up more than one cache loader in a chain. Internally, a delegating
+ <literal>ChainingCacheLoader</literal>
+ is used, with references to each
+ cache loader you have configured. Use cases vary depending on the type of cache loaders used in the chain.
+ One example is
+ using a filesystem based cache loader, colocated on the same host as the JVM, used as an overflow for
+ memory. This ensures
+ data is available relatively easily and with low cost. An additional remote cache loader, such as a
+ <literal>TcpDelegatingCacheLoader</literal>
+ provides resilience between server restarts.
+ </para>
+
+ <figure>
+ <title>Multiple cache loaders in a chain</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="MultipleCacheLoaders.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ </section>
+
+
+ </section>
+
+
+</chapter>
Added: pojo/trunk/src/main/docbook/userguide/en/modules/compatibility.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/compatibility.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/compatibility.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,37 @@
+<chapter id="compatibility">
+ <title>Version Compatibility and Interoperability</title>
+
+ <para>
+ Within a major version, releases of JBoss Cache are meant to be compatible and
+ interoperable. Compatible in the sense that it should be possible to
+ upgrade an application from one version to another by simply replacing the
+ jars. Interoperable in the sense that if two different versions of
+ JBoss Cache are used in the same cluster, they should be able to exchange
+ replication and state transfer messages. Note however that interoperability
+ requires use of the same JGroups version in all nodes in the cluster.
+ In most cases, the version of JGroups used by a version of JBoss Cache can
+ be upgraded.
+ </para>
+
+ <para>
+ As such, JBoss Cache 2.x.x is not API or binary compatible with prior 1.x.x versions.
+ However, JBoss Cache 2.1.x will be API and binary compatible with 2.0.x.
+ </para>
+
+ <para>
+ A configuration attribute, <literal>ReplicationVersion</literal>, is available and is used
+ to control the wire format of inter-cache communications. They can be wound back from more
+ efficient and newer protocols to "compatible" versions when talking to older releases.
+ This mechanism allows us to improve JBoss Cache by using more efficient wire formats while
+ still providing a means to preserve interoperability.
+ </para>
+
+ <section>
+ <title>Compatibility Matrix</title>
+ <para>
+ A <ulink url="http://labs.jboss.com/portal/jbosscache/compatibility/index.html">compatibility matrix</ulink> is maintained on the JBoss Cache website, which contains information on
+ different versions of JBoss Cache, JGroups and JBoss AS.
+ </para>
+ </section>
+
+</chapter>
\ No newline at end of file
Added: pojo/trunk/src/main/docbook/userguide/en/modules/configuration.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/configuration.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/configuration.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,447 @@
+<chapter id="configuration">
+ <title>Configuration</title>
+
+ <section>
+ <title>Configuration Overview</title>
+
+ <para>
+ The
+ <literal>org.jboss.cache.config.Configuration</literal>
+ class
+ (along with its
+ <link linkend="configuration.elements">component parts</link>
+ )
+ is a Java Bean that encapsulates the configuration of the
+ <literal>Cache</literal>
+ and all of its architectural elements
+ (cache loaders, evictions policies, etc.)
+ </para>
+
+ <para>
+ The
+ <literal>Configuration</literal>
+ exposes numerous properties which
+ are summarized in the
+ <link linkend="configuration_reference">configuration reference</link>
+ section of this book and many of which are discussed in later
+ chapters. Any time you see a configuration option
+ discussed in this book, you can assume that the
+ <literal>Configuration</literal>
+ class or one of its component parts exposes a simple property setter/getter for that configuration option.
+ </para>
+
+ </section>
+
+ <section id="configuration.creation">
+ <title>Creating a
+ <literal>Configuration</literal>
+ </title>
+
+ <para>
+ As discussed in the
+ <link linkend="api.create_start">User API section</link>
+ ,
+ before a
+ <literal>Cache</literal>
+ can be created, the
+ <literal>CacheFactory</literal>
+ must be provided with a
+ <literal>Configuration</literal>
+ object or with a file name or
+ input stream to use to parse a
+ <literal>Configuration</literal>
+ from XML. The following sections describe how to accomplish this.
+ </para>
+
+ <section>
+ <title>Parsing an XML-based Configuration File</title>
+ <para>
+ The most convenient way to configure JBoss Cache is via an XML file. The JBoss Cache distribution ships
+ with a number of configuration files for common use cases. It is recommended that these files be used as
+ a starting point, and tweaked to meet specific needs.
+ </para>
+
+ <para>
+ Here is a simple example configuration file:
+ </para>
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Sample JBoss Cache Service Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<server>
+
+ <mbean code="org.jboss.cache.jmx.CacheJmxWrapper" name="jboss.cache:service=Cache">
+
+ <!-- Configure the TransactionManager -->
+ <attribute name="TransactionManagerLookupClass">
+ org.jboss.cache.transaction.GenericTransactionManagerLookup
+ </attribute>
+
+ <!-- Node locking level : SERIALIZABLE
+ REPEATABLE_READ (default)
+ READ_COMMITTED
+ READ_UNCOMMITTED
+ NONE -->
+ <attribute name="IsolationLevel">READ_COMMITTED</attribute>
+
+ <!-- Lock parent before doing node additions/removes -->
+ <attribute name="LockParentForChildInsertRemove">true</attribute>
+
+ <!-- Valid modes are LOCAL (default)
+ REPL_ASYNC
+ REPL_SYNC
+ INVALIDATION_ASYNC
+ INVALIDATION_SYNC -->
+ <attribute name="CacheMode">LOCAL</attribute>
+
+ <!-- Max number of milliseconds to wait for a lock acquisition -->
+ <attribute name="LockAcquisitionTimeout">15000</attribute>
+
+
+ <!-- Specific eviction policy configurations. This is LRU -->
+ <attribute name="EvictionConfig">
+ <config>
+ <attribute name="wakeUpIntervalSeconds">5</attribute>
+ <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+
+ <!-- Cache wide default -->
+ <region name="/_default_">
+ <attribute name="maxNodes">5000</attribute>
+ <attribute name="timeToLiveSeconds">1000</attribute>
+ </region>
+ </config>
+ </attribute>
+ </mbean>
+</server>
+]]>
+ </programlisting>
+
+ <para>
+ Another, more complete, sample XML file is included in the
+ <link linkend="sample_xml_file">configuration reference</link>
+ section of this book,
+ along with
+ <link linkend="configuration_reference">a handy look-up table</link>
+ explaining the various options.
+ </para>
+
+ <para>
+ For historical reasons, the format of the JBoss Cache configuraton
+ file follows that of a JBoss AS Service Archive (SAR) deployment
+ descriptor (and still can be used as such
+ <link linkend="deployment.microkernel">inside JBoss AS</link>
+ ). Because
+ of this dual usage, you may see elements in some configuration files
+ (such as
+ <literal>depends</literal>
+ or
+ <literal>classpath</literal>
+ ) that are
+ not relevant outside JBoss AS. These can safely be ignored.
+ </para>
+
+ <para>
+ Here's how you tell the
+ <literal>CacheFactory</literal>
+ to create
+ and start a cache by finding and parsing a configuration file on the
+ classpath:
+ </para>
+
+ <programlisting>
+ CacheFactory factory = DefaultCacheFactory.getInstance();
+ Cache cache = factory.createCache("cache-configuration.xml");
+ </programlisting>
+
+ </section>
+
+ <section>
+ <title>Programmatic Configuration</title>
+ <para>
+ In addition to the XML-based configuration above, the
+ <literal>Configuration</literal>
+ can be built up programatically,
+ using the simple property mutators exposed by
+ <literal>Configuration</literal>
+ and its components. When constructed,
+ the
+ <literal>Configuration</literal>
+ object is preset with JBoss Cache
+ defaults and can even be used as-is for a quick start.
+ </para>
+
+ <para>
+ Following is an example of programatically creating a
+ <literal>Configuration</literal>
+ configured to match the one produced
+ by the XML example above, and then using it to create a
+ <literal>Cache</literal>
+ :
+ </para>
+
+ <programlisting>
+ <![CDATA[
+ Configuration config = new Configuration();
+ String tmlc = GenericTransactionManagerLookup.class.getName();
+ config.setTransactionManagerLookupClass(tmlc);
+ config.setIsolationLevel(IsolationLevel.READ_COMMITTED);
+ config.setCacheMode(CacheMode.LOCAL);
+ config.setLockParentForChildInsertRemove(true);
+ config.setLockAcquisitionTimeout(15000);
+
+ EvictionConfig ec = new EvictionConfig();
+ ec.setWakeupIntervalSeconds(5);
+ ec.setDefaultEvictionPolicyClass(LRUPolicy.class.getName());
+
+ EvictionRegionConfig erc = new EvictionRegionConfig();
+ erc.setRegionName("_default_");
+
+ LRUConfiguration lru = new LRUConfiguration();
+ lru.setMaxNodes(5000);
+ lru.setTimeToLiveSeconds(1000);
+
+ erc.setEvictionPolicyConfig(lru);
+
+ List<EvictionRegionConfig> ercs = new ArrayList<EvictionRegionConfig>();
+ ercs.add(erc);
+ ec.setEvictionRegionConfigs(erc);
+
+ config.setEvictionConfig(ec);
+
+ CacheFactory factory = DefaultCacheFactory.getInstance();
+ Cache cache = factory.createCache(config);
+]]>
+ </programlisting>
+
+ <para>
+ Even the above fairly simple configuration is pretty tedious programming;
+ hence the preferred use of XML-based configuration. However, if your
+ application requires it, there is no reason not to use XML-based
+ configuration for most of the attributes, and then access the
+ <literal>Configuration</literal>
+ object to programatically change
+ a few items from the defaults, add an eviction region, etc.
+ </para>
+
+ <para>
+ Note that configuration values may not be changed programmatically when a cache is running,
+ except those annotated as
+ <literal>@Dynamic</literal>
+ . Dynamic properties are also marked as such in the
+ <link linkend="configuration_reference">configuration reference</link>
+ table. Attempting to change a non-dynamic
+ property will result in a
+ <literal>ConfigurationException</literal>
+ .
+ </para>
+ </section>
+
+ <section>
+ <title>Using an IOC Framework</title>
+
+ <para>
+ The
+ <literal>Configuration</literal>
+ class and its
+ <link linkend="configuration.elements">component parts</link>
+ are all Java Beans that expose all config elements via simple setters
+ and getters. Therefore, any good IOC framework should be able to
+ build up a
+ <literal>Configuration</literal>
+ from an XML file in
+ the framework's own format. See the
+ <link linkend="deployment.microcontainer">deployment via the JBoss micrcontainer</link>
+ section for an example of this.
+ </para>
+ </section>
+ </section>
+
+ <section id="configuration.elements">
+ <title>Composition of a
+ <literal>Configuration</literal>
+ Object
+ </title>
+
+ <para>
+ A
+ <literal>Configuration</literal>
+ is composed of a number of
+ subobjects:
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="Configuration.png"/>
+ </imageobject>
+ </mediaobject>
+ </para>
+
+ <para>
+ Following is a brief overview of the components of a
+ <literal>Configuration</literal>
+ . See the javadoc and the linked
+ chapters in this book for a more complete explanation of the
+ configurations associated with each component.
+
+ <itemizedlist>
+ <listitem>
+ <literal>Configuration</literal>
+ : top level object
+ in the hierarchy; exposes the configuration properties listed in the
+ <link linkend="configuration_reference">configuration reference</link>
+ section of this book.
+ </listitem>
+
+ <listitem>
+ <literal>BuddyReplicationConfig</literal>
+ : only relevant if
+ <link linkend="br">buddy replication</link>
+ is used. General
+ buddy replication configuration options. Must include a:
+ </listitem>
+
+ <listitem>
+ <literal>BuddyLocatorConfig</literal>
+ : implementation-specific
+ configuration object for the
+ <literal>BuddyLocator</literal>
+ implementation
+ being used. What configuration elements are exposed depends on
+ the needs of the
+ <literal>BuddyLocator</literal>
+ implementation.
+ </listitem>
+
+ <listitem>
+ <literal>EvictionConfig</literal>
+ : only relevant if
+ <link linkend="eviction_policies">eviction</link>
+ is used. General
+ eviction configuration options. Must include at least one:
+ </listitem>
+
+ <listitem>
+ <literal>EvictionRegionConfig</literal>
+ : one for each
+ eviction region; names the region, etc. Must include a:
+ </listitem>
+
+ <listitem>
+ <literal>EvictionPolicyConfig</literal>
+ : implementation-specific
+ configuration object for the
+ <literal>EvictionPolicy</literal>
+ implementation
+ being used. What configuration elements are exposed depends on
+ the needs of the
+ <literal>EvictionPolicy</literal>
+ implementation.
+ </listitem>
+
+ <listitem>
+ <literal>CacheLoaderConfig</literal>
+ : only relevant if a
+ <link linkend="cache_loaders">cache loader</link>
+ is used. General
+ cache loader configuration options. Must include at least one:
+ </listitem>
+
+ <listitem>
+ <literal>IndividualCacheLoaderConfig</literal>
+ : implementation-specific
+ configuration object for the
+ <literal>CacheLoader</literal>
+ implementation
+ being used. What configuration elements are exposed depends on
+ the needs of the
+ <literal>CacheLoader</literal>
+ implementation.
+ </listitem>
+
+ <listitem>
+ <literal>RuntimeConfig</literal>
+ : exposes to cache clients
+ certain information about the cache's runtime environment (e.g. membership
+ in buddy replication groups if
+ <link linkend="br">buddy replication</link>
+ is used.) Also allows
+ direct injection into the cache of needed external services like a
+ JTA
+ <literal>TransactionManager</literal>
+ or a JGroups
+ <literal>ChannelFactory</literal>
+ .
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>Dynamic Reconfiguration</title>
+ <para>
+ Dynamically changing the configuration of
+ <emphasis>some</emphasis>
+ options while the cache is running is supported,
+ by programmatically obtaining the
+ <literal>Configuration</literal>
+ object from the running cache and changing values. E.g.,
+ <programlisting>
+
+ Configuration liveConfig = cache.getConfiguration();
+ liveConfig.setLockAcquisitionTimeout(2000);
+
+ </programlisting>
+ A complete listing of which options may be changed dynamically is in the
+ <link linkend="configuration_reference">configuration reference</link>
+ section. An
+ <literal>org.jboss.cache.config.ConfigurationException</literal>
+ will be thrown if you attempt to change a
+ setting that is not dynamic.
+ </para>
+ </section>
+
+ <section id="configuration.options">
+ <title>Overriding the Configuration Via the Option API</title>
+ <para>
+ The Option API allows you to override certain behaviours of the cache on a per invocation basis.
+ This involves creating an instance of
+ <literal>org.jboss.cache.config.Option</literal>
+ , setting the options
+ you wish to override on the
+ <literal>Option</literal>
+ object and passing it in the
+ <literal>InvocationContext</literal>
+ before invoking your method on the cache.
+ </para>
+ <para>
+ E.g., to override the default node versioning used with optimistic locking:
+ <programlisting>
+
+ DataVersion v = new MyCustomDataVersion();
+ cache.getInvocationContext().getOptionOverrides().setDataVersion(v);
+ Node ch = cache.getRoot().addChild(Fqn.fromString("/a/b/c"));
+
+ </programlisting>
+ </para>
+ <para>
+ E.g., to suppress replication of a put call in a REPL_SYNC cache:
+ <programlisting>
+
+ Node node = cache.getChild(Fqn.fromString("/a/b/c"));
+ cache.getInvocationContext().getOptionOverrides().setLocalOnly(true);
+ node.put("localCounter", new Integer(2));
+
+ </programlisting>
+ </para>
+ <para>
+ See the javadocs on the
+ <literal>Option</literal>
+ class for details on the options available.
+ </para>
+ </section>
+</chapter>
Added: pojo/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,665 @@
+<chapter id="configuration_reference_chapter">
+ <title>Configuration References</title>
+ <section id="sample_xml_file">
+ <title>Sample XML Configuration File</title>
+ <para>
+ This is what a typical XML configuration file looks like. It is recommended that you use one of the
+ configurations
+ shipped with the JBoss Cache distribution and tweak according to your needs rather than write one from scratch.
+ </para>
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Sample JBoss Cache Service Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<server>
+
+ <!-- ==================================================================== -->
+ <!-- Defines JBoss Cache configuration -->
+ <!-- ==================================================================== -->
+
+ <!-- Note the value of the 'code' attribute has changed since JBC 1.x -->
+ <mbean code="org.jboss.cache.jmx.CacheJmxWrapper" name="jboss.cache:service=Cache">
+
+ <!-- Ensure JNDI and the TransactionManager are started before the
+ cache. Only works inside JBoss AS; ignored otherwise -->
+ <depends>jboss:service=Naming</depends>
+ <depends>jboss:service=TransactionManager</depends>
+
+ <!-- Configure the TransactionManager -->
+ <attribute name="TransactionManagerLookupClass">
+ org.jboss.cache.transaction.GenericTransactionManagerLookup
+ </attribute>
+
+ <!-- Node locking level : SERIALIZABLE
+ REPEATABLE_READ (default)
+ READ_COMMITTED
+ READ_UNCOMMITTED
+ NONE -->
+ <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
+
+ <!-- Lock parent before doing node additions/removes -->
+ <attribute name="LockParentForChildInsertRemove">true</attribute>
+
+ <!-- Valid modes are LOCAL (default)
+ REPL_ASYNC
+ REPL_SYNC
+ INVALIDATION_ASYNC
+ INVALIDATION_SYNC -->
+ <attribute name="CacheMode">REPL_ASYNC</attribute>
+
+ <!-- Name of cluster. Needs to be the same for all JBoss Cache nodes in a
+ cluster in order to find each other.
+ -->
+ <attribute name="ClusterName">JBossCache-Cluster</attribute>
+
+ <!--Uncomment next three statements to use the JGroups multiplexer.
+ This configuration is dependent on the JGroups multiplexer being
+ registered in an MBean server such as JBossAS. This type of
+ dependency injection only works in the AS; outside it's up to
+ your code to inject a ChannelFactory if you want to use one.
+ -->
+ <!--
+ <depends optional-attribute-name="MultiplexerService"
+ proxy-type="attribute">jgroups.mux:name=Multiplexer</depends>
+ <attribute name="MultiplexerStack">tcp</attribute>
+ -->
+
+ <!-- JGroups protocol stack properties.
+ ClusterConfig isn't used if the multiplexer is enabled above.
+ -->
+ <attribute name="ClusterConfig">
+ <config>
+ <!-- UDP: if you have a multihomed machine, set the bind_addr
+ attribute to the appropriate NIC IP address -->
+ <!-- UDP: On Windows machines, because of the media sense feature
+ being broken with multicast (even after disabling media sense)
+ set the loopback attribute to true -->
+ <UDP mcast_addr="228.1.2.3" mcast_port="48866"
+ ip_ttl="64" ip_mcast="true"
+ mcast_send_buf_size="150000" mcast_recv_buf_size="80000"
+ ucast_send_buf_size="150000" ucast_recv_buf_size="80000"
+ loopback="false"/>
+ <PING timeout="2000" num_initial_members="3"/>
+ <MERGE2 min_interval="10000" max_interval="20000"/>
+ <FD shun="true"/>
+ <FD_SOCK/>
+ <VERIFY_SUSPECT timeout="1500"/>
+ <pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
+ max_xmit_size="8192"/>
+ <UNICAST timeout="600,1200,2400",4800/>
+ <pbcast.STABLE desired_avg_gossip="400000"/>
+ <FC max_credits="2000000" min_threshold="0.10"/>
+ <FRAG2 frag_size="8192"/>
+ <pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
+ shun="true" print_local_addr="true"/>
+ <pbcast.STATE_TRANSFER/>
+ </config>
+ </attribute>
+
+ <!--
+ The max amount of time (in milliseconds) we wait until the
+ initial state (ie. the contents of the cache) are retrieved from
+ existing members in a clustered environment
+ -->
+ <attribute name="StateRetrievalTimeout">20000</attribute>
+
+ <!--
+ Number of milliseconds to wait until all responses for a
+ synchronous call have been received.
+ -->
+ <attribute name="SyncReplTimeout">20000</attribute>
+
+ <!-- Max number of milliseconds to wait for a lock acquisition -->
+ <attribute name="LockAcquisitionTimeout">15000</attribute>
+
+
+ <!-- Specific eviction policy configurations. This is LRU -->
+ <attribute name="EvictionConfig">
+ <config>
+ <attribute name="wakeUpIntervalSeconds">5</attribute>
+ <!-- This defaults to 200000 if not specified -->
+ <attribute name="eventQueueSize">200000</attribute>
+ <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+
+ <!-- Cache wide default -->
+ <region name="/_default_">
+ <attribute name="maxNodes">5000</attribute>
+ <attribute name="timeToLiveSeconds">1000</attribute>
+ </region>
+ <region name="/org/jboss/data">
+ <attribute name="maxNodes">5000</attribute>
+ <attribute name="timeToLiveSeconds">1000</attribute>
+ </region>
+ <region name="/org/jboss/test/data">
+ <attribute name="maxNodes">5</attribute>
+ <attribute name="timeToLiveSeconds">4</attribute>
+ </region>
+ <region name="/test">
+ <attribute name="maxNodes">10000</attribute>
+ <attribute name="timeToLiveSeconds">4</attribute>
+ </region>
+ <region name="/maxAgeTest">
+ <attribute name="maxNodes">10000</attribute>
+ <attribute name="timeToLiveSeconds">8</attribute>
+ <attribute name="maxAgeSeconds">10</attribute>
+ </region>
+ </config>
+ </attribute>
+ </mbean>
+</server>
+]]>
+ </programlisting>
+ </section>
+
+
+ <section id="configuration_reference">
+ <title>
+ Reference table of XML attributes
+ </title>
+ <para>A list of definitions of each of the XML attributes used above. If the
+ description of an attribute states that it is
+ <emphasis>dynamic</emphasis>
+ ,
+ that means it can be changed after the cache is created and started.
+ </para>
+
+ <informaltable frame="all">
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>
+ <para>Name</para>
+ </entry>
+
+ <entry>
+ <para>Description</para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <para>BuddyReplicationConfig</para>
+ </entry>
+
+ <entry>
+ <para>An XML element that contains detailed buddy replication
+ configuration. See
+ <link linkend="br">section on Buddy Replication</link>
+ for details.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>CacheLoaderConfig</para>
+ </entry>
+
+ <entry>
+ <para>An XML element that contains detailed cache loader
+ configuration. See
+ <link linkend="cache_loaders">chapter on Cache Loaders</link>
+ for details.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>CacheLoaderConfiguration</para>
+ </entry>
+
+ <entry>
+ <para>
+ <emphasis>Deprecated</emphasis>
+ . Use
+ <literal>CacheLoaderConfig</literal>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>CacheMode</para>
+ </entry>
+
+ <entry>
+ <para>LOCAL, REPL_SYNC, REPL_ASYNC, INVALIDATION_SYNC or
+ INVALIDATION_ASYNC. Defaults to LOCAL. See the
+ <link linkend="clustering">chapter on Clustering</link>
+ for details.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>ClusterConfig</para>
+ </entry>
+
+ <entry>
+ <para>The configuration of the underlying JGroups stack.
+ Ignored if
+ <literal>MultiplexerService</literal>
+ and
+ <literal>MultiplexerStack</literal>
+ are used.
+ See the various *-service.xml files in the source distribution
+ <literal>etc/META-INF</literal>
+ folder for examples.
+ See the
+ <ulink url="http://www.jgroups.org">JGroups documentation</ulink>
+ or the
+ <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JGroups">JGroups wiki page</ulink>
+ for more information.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>ClusterName</para>
+ </entry>
+
+ <entry>
+ <para>Name of cluster. Needs to be the same for all nodes in a
+ cluster in order for them to communicate with each other.
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <para>EvictionPolicyConfig</para>
+ </entry>
+
+ <entry>
+ <para>Configuration parameter for the specified eviction policy.
+ See
+ <link linkend="eviction_policies">chapter on eviction policies</link>
+ for details. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>ExposeManagementStatistics</para>
+ </entry>
+
+ <entry>
+ <para>
+ Specifies whether interceptors that provide statistics should have statistics
+ gathering enabled at startup. Also controls whether a
+ <literal>CacheMgmtInterceptor</literal>
+ (whose sole purpose is gathering
+ statistics) should be added to the interceptor chain. Default value is
+ <emphasis>true</emphasis>
+ . See the
+ <link linkend="jmx.statistics">JBoss Cache Statistics section</link>
+ section for more details.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>FetchInMemoryState
+ </para>
+ </entry>
+
+ <entry>
+ <para>Whether or not to acquire the initial in-memory state from
+ existing members. Allows for hot caches when enabled. Also
+ see the
+ <literal>fetchPersistentState</literal>
+ element in
+ <literal>CacheLoaderConfig</literal>
+ . Defaults to
+ <literal>true</literal>
+ . This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>InactiveOnStartup</para>
+ </entry>
+
+ <entry>
+ <para>Whether or not the entire tree is inactive upon startup,
+ only responding to replication messages after
+ <literal>activateRegion()</literal>
+ is called to activate one or
+ more parts of the tree. If true, property
+ <literal>FetchInMemoryState</literal>
+ is ignored. This property
+ should only be set to true if
+ <literal>UseRegionBasedMarshalling</literal>
+ is also
+ <literal>true</literal>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>StateRetrievalTimeout</para>
+ </entry>
+
+ <entry>
+ <para>Time in milliseconds to wait for state
+ retrieval. This should be longer than
+ <literal>LockAcquisitionTimeout</literal>
+ as the node
+ providing state may need to wait that long to acquire
+ necessary read locks on the cache. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+
+ <row>
+ <entry>
+ <para>IsolationLevel</para>
+ </entry>
+
+ <entry>
+ <para>Node locking isolation level : SERIALIZABLE, REPEATABLE_READ
+ (default), READ_COMMITTED, READ_UNCOMMITTED, and NONE. Note that this is ignored if
+ NodeLockingScheme is OPTIMISTIC. Case doesn't matter. See documentation on Transactions and
+ Concurrency for more details.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>LockAcquisitionTimeout</para>
+ </entry>
+
+ <entry>
+ <para>Time in milliseconds to wait for a lock to be acquired. If
+ a lock cannot be acquired an exception will be thrown. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>LockParentForChildInsertRemove</para>
+ </entry>
+
+ <entry>
+ <para>Controls whether inserting or removing a node requires a write
+ lock on the node's parent (when pessimistic locking is used) or whether
+ it results in an update of the parent node's version (when optimistic
+ locking is used). The default value is
+ <code>false</code>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>MarshallerClass</para>
+ </entry>
+
+ <entry>
+ <para>An instance of
+ <literal>org.jboss.cache.marshall.Marshaller</literal>
+ used to serialize data to byte streams.
+ Defaults to
+ <literal>org.jboss.cache.marshall.VersionAwareMarshaller</literal>
+ if not specified.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>MultiplexerService</para>
+ </entry>
+
+ <entry>
+ <para>The JMX object name of the service that defines the JGroups multiplexer.
+ In JBoss AS 5.0 this service is normally defined in the jgroups-multiplexer.sar.
+ This XML attribute can only be handled by the JBoss AS MBean deployment services;
+ if it is included in a file passed to a
+ <literal>CacheFactory</literal>
+ the
+ factory's creation of the cache will fail. Inside JBoss AS, the attribute should
+ be specified using the "depends optional-attribute-name" syntax shown in
+ the example above. Inside the AS if this attribute
+ is defined, an instance of
+ <literal>org.jgroups.jmx.JChannelFactoryMBean</literal>
+ will be injected into the
+ <literal>CacheJmxWrapper</literal>
+ which will use
+ it to obtain a multiplexed JGroups channel. The configuration
+ of the channel will be that associated with
+ <literal>MultiplexerStack</literal>
+ .
+ The
+ <literal>ClusterConfig</literal>
+ attribute will be ignored.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>MultiplexerStack</para>
+ </entry>
+
+ <entry>
+ <para>The name of the JGroups stack to be used with the cache cluster.
+ Stacks are defined in the configuration of the external
+ <literal>MultiplexerService</literal>
+ discussed above. In JBoss AS 5 this is normally done in the
+ jgroups-multiplexer.sar/META-INF/multiplexer-stacks.xml file.
+ The default stack is
+ <literal>udp</literal>
+ . This attribute is used in conjunction with
+ <literal>MultiplexerService</literal>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>NodeLockingScheme</para>
+ </entry>
+
+ <entry>
+ <para>May be PESSIMISTIC (default) or OPTIMISTIC.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>ReplicationVersion</para>
+ </entry>
+ <entry>
+ <para>Tells the cache to serialize cluster traffic
+ in a format consistent with that used by the given release
+ of JBoss Cache. Different JBoss Cache versions use different
+ wire formats; setting this attribute tells a cache from a later
+ release to serialize data using the format from an earlier
+ release. This allows caches from different releases to
+ interoperate. For example, a 2.1.0 cache could have this
+ value set to "2.0.0", allowing it to interoperate with a 2.0.0
+ cache. Valid values are a dot-separated release number, with
+ any final qualifer also separated by a dot, e.g. "2.0.0" or "2.0.0.GA".
+ Values that indicate a 1.x release are not supported in the 2.x series.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>ReplQueueInterval</para>
+ </entry>
+
+ <entry>
+ <para>Time in milliseconds for elements from the replication
+ queue to be replicated. Only used if
+ <literal>UseReplQueue</literal>
+ is enabled. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>ReplQueueMaxElements</para>
+ </entry>
+
+ <entry>
+ <para>Max number of elements in the replication queue until
+ replication kicks in. Only used if
+ <literal>UseReplQueue</literal>
+ is enabled. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>SyncCommitPhase</para>
+ </entry>
+
+ <entry>
+ <para>This option is used to control the behaviour of the commit part of a 2-phase commit protocol,
+ when
+ using REPL_SYNC (does not apply to other cache modes). By default this is set to
+ <literal>false</literal>
+ . There is a performance penalty to enabling this, especially when running
+ in a large cluster, but the upsides are greater cluster-wide data integrity. See the chapter on
+ clustered caches for more information on this. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>SyncReplTimeout</para>
+ </entry>
+
+ <entry>
+ <para>For synchronous replication: time in milliseconds to wait
+ until replication acks have been received from all nodes in the
+ cluster. It is usually best that this is greater than
+ <literal>LockAcquisitionTimeout</literal>
+ .
+ This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>SyncRollbackPhase</para>
+ </entry>
+
+ <entry>
+ <para>This option is used to control the behaviour of the rollback part of a 2-phase commit
+ protocol, when
+ using REPL_SYNC (does not apply to other cache modes). By default this is set to
+ <literal>false</literal>
+ . There is a performance penalty to enabling this, especially when running
+ in a large cluster, but the upsides are greater cluster-wide data integrity. See the chapter on
+ clustered caches for more information on this. This property is
+ <emphasis>dynamic</emphasis>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>TransactionManagerLookupClass</para>
+ </entry>
+
+ <entry>
+ <para>The fully qualified name of a class implementing
+ TransactionManagerLookup. Default is
+ JBossTransactionManagerLookup. There is also an option of
+ GenericTransactionManagerLookup for example.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>UseInterceptorMbeans</para>
+ </entry>
+
+ <entry>
+ <para>
+ <emphasis>Deprecated</emphasis>
+ . Use
+ <literal>ExposeManagementStatistics</literal>
+ .
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>UseRegionBasedMarshalling</para>
+ </entry>
+
+ <entry>
+ <para>When unmarshalling replicated data, this option specifies whether or not to
+ support use of different classloaders for different cache regions. This defaults to
+ <literal>false</literal>
+ if unspecified.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>UseReplQueue</para>
+ </entry>
+
+ <entry>
+ <para>For asynchronous replication: whether or not to use a
+ replication queue. Defaults to
+ <literal>false</literal>
+ .
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </section>
+</chapter>
\ No newline at end of file
Added: pojo/trunk/src/main/docbook/userguide/en/modules/deployment.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/deployment.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/deployment.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,901 @@
+<chapter id="deployment">
+ <title>Deploying JBoss Cache</title>
+ <section id="deployment.standalone">
+ <title>Standalone Use / Programatic Deployment</title>
+ <para>
+ When used in a standalone Java program, all that needs to be done is to instantiate the cache using the
+ <literal>CacheFactory</literal>
+ and a
+ <literal>Configuration</literal>
+ instance or an XML file, as discussed
+ in the
+ <link linkend="api.create_start">User API</link>
+ and
+ <link linkend="configuration.creation">Configuration</link>
+ chapters.
+ </para>
+
+ <para>
+ The same techniques can be used when an application running in an application
+ server wishes to programatically deploy a cache rather than relying on an application server's
+ deployment features. An example of this would be
+ a webapp deploying a cache via a
+ <literal>javax.servlet.ServletContextListener</literal>
+ .
+ </para>
+
+ <para>
+ If, after deploying your cache you wish to expose a management interface
+ to it in JMX, see the
+ <link linkend="jmx.registration.programatic">section on Programatic Registration in JMX</link>
+ .
+ </para>
+ </section>
+
+ <section id="deployment.microkernel">
+ <title>JMX-Based Deployment in JBoss AS (JBoss AS 5.x and 4.x)</title>
+ <para>If JBoss Cache is run in JBoss AS then the cache can be deployed as an
+ MBean simply by copying a standard cache configuration file to the server's
+ <literal>deploy</literal>
+ directory. The standard format of JBoss Cache's
+ standard XML configuration file (as shown in the
+ <link linkend="sample_xml_file">Configuration Reference</link>
+ ) is the same
+ as a JBoss AS MBean deployment descriptor, so the AS's SAR Deployer has
+ no trouble handling it. Also, you don't have to place the configuration
+ file directly in
+ <literal>deploy</literal>
+ ; you can package it along
+ with other services or JEE components in a SAR or EAR.
+ </para>
+
+ <para>
+ In AS 5, if you're using a server config based on the standard
+ <literal>all</literal>
+ config, then that's all you need to do; all required
+ jars will be on the classpath. Otherwise, you will need to ensure
+ <literal>jbosscache.jar</literal>
+ and
+ <literal>jgroups-all.jar</literal>
+ are on the classpath. You may need to add other jars if you're using
+ things like
+ <literal>JdbmCacheLoader</literal>
+ . The simplest way to do
+ this is to copy the jars from the JBoss Cache distribution's
+ <literal>lib</literal>
+ directory to the server config's
+ <literal>lib</literal>
+ directory. You could also package the jars with the configuration file
+ in Service Archive (.sar) file or an EAR.
+ </para>
+
+ <para>
+ It is possible to deploy a JBoss Cache 2.0 instance in JBoss AS 4.x
+ (at least in 4.2.0.GA; other AS releases are completely untested).
+ However, the significant API changes between the JBoss Cache 2.x and 1.x releases
+ mean none of the standard AS 4.x clustering services (e.g.
+ http session replication) that rely on JBoss Cache will work with
+ JBoss Cache 2.x. Also, be aware that usage of JBoss Cache 2.x in AS 4.x is not
+ something the JBoss Cache developers are making any significant effort to test,
+ so be sure to test your application well (which of course you're doing anyway.)
+ </para>
+
+ <para>
+ Note in the
+ <link linkend="sample_xml_file">example</link>
+ the value of the
+ <literal>mbean</literal>
+ element's
+ <literal>code</literal>
+ attribute:
+ <literal>org.jboss.cache.jmx.CacheJmxWrapper</literal>
+ . This is the
+ class JBoss Cache uses to handle JMX integration; the
+ <literal>Cache</literal>
+ itself does not expose an MBean
+ interface. See the
+ <link linkend="jmx.mbeans">JBoss Cache MBeans section</link>
+ for more on the
+ <literal>CacheJmxWrapper</literal>
+ .
+ </para>
+
+ <para>
+ Once your cache is deployed, in order to use it with an in-VM client
+ such as a servlet, a JMX proxy can be used to get a reference to
+ the cache:
+ </para>
+
+ <programlisting>
+ <![CDATA[
+ MBeanServer server = MBeanServerLocator.locateJBoss();
+ ObjectName on = new ObjectName("jboss.cache:service=Cache");
+ CacheJmxWrapperMBean cacheWrapper =
+ (CacheJmxWrapperMBean) MBeanServerInvocationHandler.newProxyInstance(server, on,
+ CacheJmxWrapperMBean.class, false);
+ Cache cache = cacheWrapper.getCache();
+ Node root = cache.getRoot(); // etc etc
+ ]]>
+ </programlisting>
+
+ <para>The MBeanServerLocator class is a helper to find the (only) JBoss
+ MBean server inside the current JVM. The
+ <literal>javax.management.MBeanServerInvocationHandler</literal>
+ class'
+ <literal>newProxyInstance</literal>
+ method creates a
+ dynamic proxy implementing the given interface and uses JMX to
+ dynamically dispatch methods invoked against the generated interface
+ to the MBean. The name used to look up the MBean is the same as defined
+ in the cache's configuration file.
+ </para>
+
+ <para>
+ Once the proxy to the
+ <literal>CacheJmxWrapper</literal>
+ is obtained,
+ the
+ <literal>getCache()</literal>
+ will return a reference to the
+ <literal>Cache</literal>
+ itself.
+ </para>
+
+ </section>
+
+ <section id="deployment.microcontainer">
+ <title>Via JBoss Microcontainer (JBoss AS 5.x)</title>
+
+ <para>
+ Beginning with AS 5, JBoss AS also supports deployment of POJO services via
+ deployment of a file whose name ends with
+ <literal>-beans.xml</literal>
+ .
+ A POJO service is one whose implementation is via a "Plain Old Java Object",
+ meaning a simple java bean that isn't required to implement any special
+ interfaces or extend any particular superclass. A
+ <literal>Cache</literal>
+ is a POJO service, and all the components in a
+ <literal>Configuration</literal>
+ are also POJOS, so deploying a cache in this way is a natural step.
+ </para>
+ <para>
+ Deployment of the cache is done using the JBoss Microcontainer that forms the
+ core of JBoss AS. JBoss Microcontainer is a sophisticated IOC framework
+ (similar to Spring). A
+ <literal>-beans.xml</literal>
+ file is basically
+ a descriptor that tells the IOC framework how to assemble the various
+ beans that make up a POJO service.
+ </para>
+ <para>
+ The rules for how to deploy the file, how to package it, how to
+ ensure the required jars are on the classpath, etc. are the same
+ as for a
+ <link linkend="deployment.microkernel">JMX-based deployment</link>
+ .
+ </para>
+
+ <para>
+ Following is an example
+ <literal>-beans.xml</literal>
+ file. If you
+ look in the
+ <literal>server/all/deploy</literal>
+ directory of an AS 5
+ installation, you can find several more examples.
+ </para>
+
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <!-- First we create a Configuration object for the cache -->
+ <bean name="ExampleCacheConfig"
+ class="org.jboss.cache.config.Configuration">
+
+ <!-- Externally injected services -->
+ <property name="runtimeConfig">
+ <bean name="ExampleCacheRuntimeConfig" class="org.jboss.cache.config.RuntimeConfig">
+ <property name="transactionManager">
+ <inject bean="jboss:service=TransactionManager"
+ property="TransactionManager"/>
+ </property>
+ <property name="muxChannelFactory"><inject bean="JChannelFactory"/></property>
+ </bean>
+ </property>
+
+ <property name="multiplexerStack">udp</property>
+
+ <property name="clusterName">Example-EntityCache</property>
+
+ <!--
+ Node locking level : SERIALIZABLE
+ REPEATABLE_READ (default)
+ READ_COMMITTED
+ READ_UNCOMMITTED
+ NONE
+ -->
+ <property name="isolationLevel">REPEATABLE_READ</property>
+
+ <!-- Valid modes are LOCAL
+ REPL_ASYNC
+ REPL_SYNC
+ -->
+ <property name="cacheMode">REPL_SYNC</property>
+
+ <!-- The max amount of time (in milliseconds) we wait until the
+ initial state (ie. the contents of the cache) are retrieved from
+ existing members in a clustered environment
+ -->
+ <property name="initialStateRetrievalTimeout">15000</property>
+
+ <!-- Number of milliseconds to wait until all responses for a
+ synchronous call have been received.
+ -->
+ <property name="syncReplTimeout">20000</property>
+
+ <!-- Max number of milliseconds to wait for a lock acquisition -->
+ <property name="lockAcquisitionTimeout">15000</property>
+
+ <property name="exposeManagementStatistics">true</property>
+
+ <!-- Must be true if any entity deployment uses a scoped classloader -->
+ <property name="useRegionBasedMarshalling">true</property>
+ <!-- Must match the value of "useRegionBasedMarshalling" -->
+ <property name="inactiveOnStartup">true</property>
+
+ <!-- Specific eviction policy configurations. This is LRU -->
+ <property name="evictionConfig">
+ <bean name="ExampleEvictionConfig"
+ class="org.jboss.cache.config.EvictionConfig">
+ <property name="defaultEvictionPolicyClass">
+ org.jboss.cache.eviction.LRUPolicy
+ </property>
+ <property name="wakeupIntervalSeconds">5</property>
+ <property name="evictionRegionConfigs">
+ <list>
+ <bean name="ExampleDefaultEvictionRegionConfig"
+ class="org.jboss.cache.config.EvictionRegionConfig">
+ <property name="regionName">/_default_</property>
+ <property name="evictionPolicyConfig">
+ <bean name="ExampleDefaultLRUConfig"
+ class="org.jboss.cache.eviction.LRUConfiguration">
+ <property name="maxNodes">5000</property>
+ <property name="timeToLiveSeconds">1000</property>
+ </bean>
+ </property>
+ </bean>
+ </list>
+ </property>
+ </bean>
+ </property>
+
+ </bean>
+
+ <!-- Factory to build the Cache. -->
+ <bean name="DefaultCacheFactory" class="org.jboss.cache.DefaultCacheFactory">
+ <constructor factoryClass="org.jboss.cache.DefaultCacheFactory"
+ factoryMethod="getInstance"/>
+ </bean>
+
+ <!-- The cache itself -->
+ <bean name="ExampleCache" class="org.jboss.cache.CacheImpl">
+
+ <constructor factoryMethod="createCache">
+ <factory bean="DefaultCacheFactory"/>
+ <parameter><inject bean="ExampleCacheConfig"/></parameter>
+ <parameter>false</false>
+ </constructor>
+
+ </bean>
+
+</deployment>
+]]>
+ </programlisting>
+
+ <para>
+ See the JBoss Microcontainer documentation
+ <footnote>
+ <para>http://labs.jboss.com/jbossmc/docs</para>
+ </footnote>
+ for details on the above syntax. Basically, each
+ <literal>bean</literal>
+ element represents an object; most going to create a
+ <literal>Configuration</literal>
+ and its
+ <link linkend="configuration.elements">constituent parts</link>
+ .
+ </para>
+ <para>
+ An interesting thing to note in the above example is the use of the
+ <literal>RuntimeConfig</literal>
+ object. External resources like
+ a
+ <literal>TransactionManager</literal>
+ and a JGroups
+ <literal>ChannelFactory</literal>
+ that are visible to the
+ microcontainer are dependency injected into the
+ <literal>RuntimeConfig</literal>
+ .
+ The assumption here is that in some other deployment descriptor in the AS,
+ the referenced beans have been described.
+ </para>
+ </section>
+
+ <section>
+ <title>Binding to JNDI in JBoss AS</title>
+ <para>
+ With the 1.x JBoss Cache releases, a proxy to the cache could be bound
+ into JBoss AS's JNDI tree using the AS's
+ <literal>JRMPProxyFactory</literal>
+ service. With JBoss Cache 2.x, this no longer works. An alternative
+ way of doing a similar thing with a POJO (i.e. non-JMX-based) service
+ like a
+ <literal>Cache</literal>
+ is under development by the JBoss AS
+ team
+ <footnote>
+ <para>http://jira.jboss.com/jira/browse/JBAS-4456</para>
+ </footnote>
+ . That feature is not available as of the time of this writing,
+ although it will be completed before AS 5.0.0.GA is released.
+ We will add a wiki page describing how to use it once it becomes available.
+ </para>
+ </section>
+
+ <section>
+ <title>Runtime Management Information</title>
+ <para>JBoss Cache includes JMX MBeans to expose cache functionality and provide statistics that can be
+ used to analyze cache operations. JBoss Cache can also broadcast cache events as MBean notifications for
+ handling
+ via JMX monitoring tools.
+ </para>
+
+ <section id="jmx.mbeans">
+ <title>JBoss Cache MBeans</title>
+ <para>
+ JBoss Cache provides an MBean that can be registered with your environments JMX server to allow access
+ to the cache instance via JMX. This MBean is the
+ <literal>org.jboss.cache.jmx.CacheJmxWrapper</literal>
+ .
+ It is a StandardMBean, so it's MBean interface is
+ <literal>org.jboss.cache.jmx.CacheJmxWrapperMBean</literal>
+ .
+ This MBean can be used to:
+ <itemizedlist>
+ <listitem>Get a reference to the underlying
+ <literal>Cache</literal>
+ .
+ </listitem>
+ <listitem>Invoke create/start/stop/destroy lifecycle operations on
+ the underlying
+ <literal>Cache</literal>
+ .
+ </listitem>
+ <listitem>Inspect various details about the cache's current state (number of nodes, lock information,
+ etc.)
+ </listitem>
+ <listitem>See numerous details about the cache's configuration, and
+ change those configuration items that can be changed when the
+ cache has already been started.
+ </listitem>
+ </itemizedlist>
+ See the
+ <literal>CacheJmxWrapperMBean</literal>
+ javadoc for more details.
+ </para>
+ <para>
+ It is important to note a significant architectural difference between JBoss Cache 1.x and 2.x. In 1.x,
+ the old
+ <literal>TreeCache</literal>
+ class was itself an MBean, and essentially exposed the cache's entire
+ API via JMX. In 2.x, JMX has been returned to it's fundamental role as a management layer. The
+ <literal>Cache</literal>
+ object itself is completely unaware of JMX; instead JMX functionality is added
+ through a wrapper class designed for that purpose. Furthermore, the interface exposed through JMX
+ has been limited to management functions; the general
+ <literal>Cache</literal>
+ API is no longer exposed
+ through JMX. For example, it is no longer possible to invoke a cache
+ <literal>put</literal>
+ or
+ <literal>get</literal>
+ via the JMX interface.
+ </para>
+ <para>
+ If a
+ <literal>CacheJmxWrapper</literal>
+ is registered, JBoss Cache also provides MBeans
+ for each interceptor configured in the cache's interceptor stack. These
+ MBeans are used to capture and expose statistics related to cache operations. They are hierarchically
+ associated with the
+ <literal>CacheJmxWrapper</literal>
+ MBean and have service names that reflect this relationship. For
+ example, a replication interceptor MBean for the
+ <literal>jboss.cache:service=TomcatClusteringCache</literal>
+ instance will be
+ accessible through the service named
+ <literal>jboss.cache:service=TomcatClusteringCache,cache-interceptor=ReplicationInterceptor</literal>
+ .
+ </para>
+ </section>
+
+ <section id="jmx.registration">
+ <title>Registering the CacheJmxWrapper with the MBeanServer</title>
+
+ <para>
+ The best way to ensure the
+ <literal>CacheJmxWrapper</literal>
+ is registered
+ in JMX depends on how you are deploying your cache:
+ </para>
+
+ <section id="jmx.registration.programatic">
+ <title>Programatic Registration</title>
+
+ <para>
+ Simplest way to do this is to create your
+ <literal>Cache</literal>
+ and pass it to the
+ <literal>CacheJmxWrapper</literal>
+ constructor.
+ </para>
+
+ <programlisting>
+ CacheFactory factory = DefaultCacheFactory.getInstance();
+ // Build but don't start the cache
+ // (although it would work OK if we started it)
+ Cache cache = factory.createCache("cache-configuration.xml", false);
+
+ CacheJmxWrapperMBean wrapper = new CacheJmxWrapper(cache);
+ MBeanServer server = getMBeanServer(); // however you do it
+ ObjectName on = new ObjectName("jboss.cache:service=TreeCache");
+ server.registerMBean(wrapper, on);
+
+ // Invoking lifecycle methods on the wrapper results
+ // in a call through to the cache
+ wrapper.create();
+ wrapper.start();
+
+ ... use the cache
+
+ ... on application shutdown
+
+ // Invoking lifecycle methods on the wrapper results
+ // in a call through to the cache
+ wrapper.stop();
+ wrapper.destroy();
+ </programlisting>
+
+ <para>
+ Alternatively, build a
+ <literal>Configuration</literal>
+ object
+ and pass it to the
+ <literal>CacheJmxWrapper</literal>
+ . The wrapper
+ will construct the
+ <literal>Cache</literal>
+ :
+ </para>
+
+ <programlisting>
+ Configuration config = buildConfiguration(); // whatever it does
+
+ CacheJmxWrapperMBean wrapper = new CacheJmxWrapper(config);
+ MBeanServer server = getMBeanServer(); // however you do it
+ ObjectName on = new ObjectName("jboss.cache:service=TreeCache");
+ server.registerMBean(wrapper, on);
+
+ // Call to wrapper.create() will build the Cache if one wasn't injected
+ wrapper.create();
+ wrapper.start();
+
+ // Now that it's built, created and started, get the cache from the wrapper
+ Cache cache = wrapper.getCache();
+
+ ... use the cache
+
+ ... on application shutdown
+
+ wrapper.stop();
+ wrapper.destroy();
+
+ </programlisting>
+ </section>
+
+ <section>
+ <title>JMX-Based Deployment in JBoss AS (JBoss AS 4.x and 5.x)</title>
+
+ <para>
+ When you
+ <link linkend="deployment.microkernel">deploy your cache in JBoss AS using a -service.xml file</link>
+ ,
+ a
+ <literal>CacheJmxWrapper</literal>
+ is automatically registered. There is no need
+ to do anything further. The
+ <literal>CacheJmxWrapper</literal>
+ is accessible from an MBean server
+ through the service name specified in the cache configuration file's
+ <literal>mbean</literal>
+ element.
+ </para>
+ </section>
+
+ <section>
+ <title>Via JBoss Microcontainer (JBoss AS 5.x)</title>
+
+ <para>
+ <literal>CacheJmxWrapper</literal>
+ is a POJO, so the microcontainer
+ has no problem creating one. The trick is
+ getting it to register your bean in JMX. This can be done by
+ specifying the
+ <literal>org.jboss.aop.microcontainer.aspects.jmx.JMX</literal>
+ annotation on the
+ <literal>CacheJmxWrapper</literal>
+ bean:
+ </para>
+
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <!-- First we create a Configuration object for the cache -->
+ <bean name="ExampleCacheConfig"
+ class="org.jboss.cache.config.Configuration">
+
+ ... build up the Configuration
+
+ </bean>
+
+ <!-- Factory to build the Cache. -->
+ <bean name="DefaultCacheFactory" class="org.jboss.cache.DefaultCacheFactory">
+ <constructor factoryClass="org.jboss.cache.DefaultCacheFactory"
+ factoryMethod="getInstance"/>
+ </bean>
+
+ <!-- The cache itself -->
+ <bean name="ExampleCache" class="org.jboss.cache.CacheImpl">
+
+ <constructor factoryMethod="createnewInstance">
+ <factory bean="DefaultCacheFactory"/>
+ <parameter><inject bean="ExampleCacheConfig"/></parameter>
+ <parameter>false</false>
+ </constructor>
+
+ </bean>
+
+ <!-- JMX Management -->
+ <bean name="ExampleCacheJmxWrapper" class="org.jboss.cache.jmx.CacheJmxWrapper">
+
+ <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.cache:service=ExampleTreeCache",
+ exposedInterface=org.jboss.cache.jmx.CacheJmxWrapperMBean.class,
+ registerDirectly=true)</annotation>
+
+ <constructor>
+ <parameter><inject bean="ExampleCache"/></parameter>
+ </constructor>
+
+ </bean>
+
+</deployment>
+]]>
+ </programlisting>
+
+ <para>
+ As discussed in the
+ <link linkend="jmx.registration.programatic">Programatic Registration</link>
+ section,
+ <literal>CacheJmxWrapper</literal>
+ can do the work of building,
+ creating and starting the
+ <literal>Cache</literal>
+ if it is provided
+ with a
+ <literal>Configuration</literal>
+ . With the microcontainer,
+ this is the preferred approach, as it saves the boilerplate XML
+ needed to create the
+ <literal>CacheFactory</literal>
+ :
+ </para>
+
+ <programlisting>
+ <![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <!-- First we create a Configuration object for the cache -->
+ <bean name="ExampleCacheConfig"
+ class="org.jboss.cache.config.Configuration">
+
+ ... build up the Configuration
+
+ </bean>
+
+ <bean name="ExampleCache" class="org.jboss.cache.jmx.CacheJmxWrapper">
+
+ <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.cache:service=ExampleTreeCache",
+ exposedInterface=org.jboss.cache.jmx.CacheJmxWrapperMBean.class,
+ registerDirectly=true)</annotation>
+
+ <constructor>
+ <parameter><inject bean="ExampleCacheConfig"/></parameter>
+ </constructor>
+
+ </bean>
+
+</deployment>
+]]>
+ </programlisting>
+ </section>
+
+ </section>
+
+ <section id="jmx.statistics">
+ <title>JBoss Cache Statistics</title>
+ <para>
+ JBoss Cache captures statistics in its interceptors and exposes the statistics through interceptor
+ MBeans. Gathering of statistics is enabled by default; this can be disabled for a specific cache
+ instance through the
+ <literal>ExposeManagementStatistics</literal>
+ configuration attribute. Note that
+ the majority of the statistics are provided by the
+ <literal>CacheMgmtInterceptor</literal>
+ ,
+ so this MBean is the most significant in this regard. If you want to disable all statistics for performance
+ reasons, you set
+ <literal>ExposeManagementStatistics</literal>
+ to
+ <literal>false</literal>
+ as this will
+ prevent the
+ <literal>CacheMgmtInterceptor</literal>
+ from being included in the cache's interceptor stack
+ when the cache is started.
+ </para>
+ <para>
+ If a
+ <literal>CacheJmxWrapper</literal>
+ is registered with JMX, the wrapper also ensures that
+ an MBean is registered in JMX for each interceptor that exposes statistics
+ <footnote>
+ <para>
+ Note that if the
+ <literal>CacheJmxWrapper</literal>
+ is not registered in JMX, the
+ interceptor MBeans will not be registered either. The JBoss Cache 1.4 releases
+ included code that would try to "discover" an
+ <literal>MBeanServer</literal>
+ and
+ automatically register the interceptor MBeans with it. For JBoss Cache 2.x we decided
+ that this sort of "discovery" of the JMX environment was beyond the proper scope of
+ a caching library, so we removed this functionality.
+ </para>
+ </footnote>
+ .
+ Management tools can then access those MBeans to examine the statistics. See the section in the
+ <link linkend="jmx_reference.statistics">JMX Reference chapter</link>
+ pertaining to the
+ statistics that are made available via JMX.
+ </para>
+ <para>
+ The name under which the interceptor MBeans will be registered is derived by taking the
+ <literal>ObjectName</literal>
+ under which the
+ <literal>CacheJmxWrapper</literal>
+ is
+ registered and adding a
+ <literal>cache-interceptor</literal>
+ attribute key whose value
+ is the non-qualified name of the interceptor class. So, for example, if the
+ <literal>CacheJmxWrapper</literal>
+ were registered under
+ <literal>jboss.cache:service=TreeCache</literal>
+ , the name of the
+ <literal>CacheMgmtInterceptor</literal>
+ MBean would be
+ <literal>jboss.cache:service=TreeCache,cache-interceptor=CacheMgmtInterceptor</literal>
+ .
+ </para>
+ <para>
+ Each interceptor's MBean exposes a
+ <literal>StatisticsEnabled</literal>
+ attribute that can be used to disable maintenance of statistics for
+ that interceptor. In addition, each interceptor MBean provides the following common operations and
+ attributes.
+ <itemizedlist>
+ <listitem>
+ <literal>dumpStatistics</literal>
+ - returns a
+ <literal>Map</literal>
+ containing the interceptor's attributes and values.
+ </listitem>
+ <listitem>
+ <literal>resetStatistics</literal>
+ - resets all statistics maintained by the interceptor.
+ </listitem>
+ <listitem>
+ <literal>setStatisticsEnabled(boolean)</literal>
+ - allows statistics to be disabled for a specific interceptor.
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ </para>
+ </section>
+
+ <section>
+ <title>Receiving JMX Notifications</title>
+ <para>
+ JBoss Cache users can register a listener to receive cache events described earlier in the
+ <link linkend="api.listener">User API</link>
+ chapter. Users can alternatively utilize the cache's management information infrastructure to receive these
+ events
+ via JMX notifications. Cache events are accessible as notifications by registering a
+ <literal>NotificationListener</literal>
+ for the
+ <literal>CacheJmxWrapper</literal>
+ .
+ </para>
+
+ <para>
+ See the section in the
+ <link linkend="jmx_reference.notifications">JMX Reference chapter</link>
+ pertaining
+ to JMX notifications for a list of notifications that can be received through the
+ <literal>CacheJmxWrapper</literal>
+ .
+ </para>
+
+
+ <para>
+ The following is an example of how to programmatically receive cache notifications when running in a
+ JBoss AS environment. In this example, the client uses a filter to specify which events are of interest.
+ </para>
+
+ <programlisting>
+ <![CDATA[
+ MyListener listener = new MyListener();
+ NotificationFilterSupport filter = null;
+
+ // get reference to MBean server
+ Context ic = new InitialContext();
+ MBeanServerConnection server = (MBeanServerConnection)ic.lookup("jmx/invoker/RMIAdaptor");
+
+ // get reference to CacheMgmtInterceptor MBean
+ String cache_service = "jboss.cache:service=TomcatClusteringCache";
+ ObjectName mgmt_name = new ObjectName(cache_service);
+
+ // configure a filter to only receive node created and removed events
+ filter = new NotificationFilterSupport();
+ filter.disableAllTypes();
+ filter.enableType(CacheNotificationBroadcaster.NOTIF_NODE_CREATED);
+ filter.enableType(CacheNotificationBroadcaster.NOTIF_NODE_REMOVED);
+
+ // register the listener with a filter
+ // leave the filter null to receive all cache events
+ server.addNotificationListener(mgmt_name, listener, filter, null);
+
+ // ...
+
+ // on completion of processing, unregister the listener
+ server.removeNotificationListener(mgmt_name, listener, filter, null);
+ ]]>
+ </programlisting>
+
+ <para>The following is the simple notification listener implementation used in the previous example.</para>
+ <programlisting>
+ <![CDATA[
+ private class MyListener implements NotificationListener, Serializable
+ {
+ public void handleNotification(Notification notification, Object handback)
+ {
+ String message = notification.getMessage();
+ String type = notification.getType();
+ Object userData = notification.getUserData();
+
+ System.out.println(type + ": " + message);
+
+ if (userData == null)
+ {
+ System.out.println("notification data is null");
+ }
+ else if (userData instanceof String)
+ {
+ System.out.println("notification data: " + (String) userData);
+ }
+ else if (userData instanceof Object[])
+ {
+ Object[] ud = (Object[]) userData;
+ for (Object data : ud)
+ {
+ System.out.println("notification data: " + data.toString());
+ }
+ }
+ else
+ {
+ System.out.println("notification data class: " + userData.getClass().getName());
+ }
+ }
+ }
+ ]]>
+ </programlisting>
+
+ <para>Note that the JBoss Cache management implementation only listens to cache events after a client registers
+ to receive MBean notifications. As soon as no clients are registered for notifications, the MBean will
+ remove
+ itself as a cache listener.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Accessing Cache MBeans in a Standalone Environment</title>
+ <para>
+ JBoss Cache MBeans are easily accessed when running cache instances in an application server that
+ provides an MBean server interface such as JBoss JMX Console. Refer to your server documentation
+ for instructions on how to access MBeans running in a server's MBean container.
+ </para>
+ <para>
+ In addition, though, JBoss Cache MBeans are also accessible when running in a non-server environment if the
+ JVM is JDK 5.0 or later. When running a standalone cache in a JDK 5.0 environment, you can access the
+ cache's MBeans as follows.
+ </para>
+ <para>
+ <orderedlist>
+ <listitem>
+ Set the system property
+ <literal>-Dcom.sun.management.jmxremote</literal>
+ when starting the JVM
+ where the cache will run.
+ </listitem>
+ <listitem>
+ Once the JVM is running, start the JDK 5.0
+ <literal>jconsole</literal>
+ utility, located in your JDK's
+ <literal>/bin</literal>
+ directory.
+ </listitem>
+ <listitem>When the utility loads, you will be able to select your running JVM and connect to it. The
+ JBoss Cache
+ MBeans will be available on the MBeans panel.
+ </listitem>
+ </orderedlist>
+ </para>
+ <para>Note that the
+ <literal>jconsole</literal>
+ utility will automatically register as a listener for cache notifications when
+ connected to a JVM running JBoss Cache instances.
+ </para>
+
+ <para>The following figure shows cache interceptor MBeans in
+ <literal>jconsole</literal>
+ . Cache statistics are displayed
+ for the
+ <literal>CacheMgmtInterceptor</literal>
+ :
+ </para>
+
+ <figure>
+ <title>CacheMgmtInterceptor MBean in jconsole</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="CacheMgmtInterceptor.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ </section>
+ </section>
+</chapter>
Added: pojo/trunk/src/main/docbook/userguide/en/modules/eviction_policies.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/eviction_policies.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/eviction_policies.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,537 @@
+<chapter id="eviction_policies">
+ <title>Eviction Policies</title>
+
+ <para>
+ Eviction policies control JBoss Cache's memory management by managing how many nodes are allowed to be stored in
+ memory and their life spans. Memory constraints on servers mean cache cannot grow indefinitely, so policies
+ need to be in place to restrict the size of the cache. Eviction policies are most often used alongside
+ <link linkend="cache_loaders">cache loaders</link>
+ .
+ </para>
+
+ <section>
+ <title>Configuring Eviction Policies</title>
+ <section>
+ <title>Basic Configuration</title>
+ <para>
+ The basic eviction policy configuration element looks like:
+ <programlisting>
+ <![CDATA[
+
+ ...
+
+ <attribute name="EvictionConfig">
+ <config>
+ <attribute name="wakeUpIntervalSeconds">3</attribute>
+
+ <!-- This defaults to 200000 if not specified -->
+ <attribute name="eventQueueSize">100000</attribute>
+
+ <!-- Name of the DEFAULT eviction policy class. -->
+ <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+
+ <!-- Cache wide default -->
+ <region name="/_default_">
+ <attribute name="maxNodes">100</attribute>
+ </region>
+
+ <!-- override policy used for this region -->
+ <region name="/org/jboss/data" policyClass="org.jboss.cache.eviction.MRUPolicy">
+ <attribute name="maxNodes">250</attribute>
+ </region>
+
+ <!-- We expect a lot of events for this region,
+ so override the default event queue size -->
+ <region name="/org/jboss/test/data" eventQueueSize="500000">
+ <attribute name="maxNodes">60000</attribute>
+ </region>
+
+ </config>
+ </attribute>
+
+ ...
+]]>
+ </programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <literal>wakeUpIntervalSeconds</literal>
+ - this required parameter defines how often the eviction thread runs
+ </listitem>
+ <listitem>
+ <literal>eventQueueSize</literal>
+ - this optional parameter defines the size of the queue which holds eviction events. If your eviction
+ thread does not run often enough, you may need to increase this. This can be overridden on a
+ per-region basis.
+ </listitem>
+ <listitem>
+ <literal>policyClass</literal>
+ - this is required, unless you set individual policyClass attributes on each and every region. This
+ defines the eviction policy to use if one is not defined for a region.
+ </listitem>
+ </itemizedlist>
+
+ </para>
+ </section>
+ <section>
+ <title>Eviction Regions</title>
+ <para>
+ The concept of regions and the
+ <literal>Region</literal>
+ class were
+ <link linkend="architecture.regions">visited earlier</link>
+ when talking about marshalling. Regions also have another use, in that they are used to define the eviction
+ policy used within the region. In addition to using a region-specific configuration, you can also configure
+ a default, cache-wide eviction policy for nodes that do not fall into predefined regions or if you do not
+ wish to define specific regions. It is important to note that when defining regions using the configuration
+ XML file, all elements of the
+ <literal>Fqn</literal>
+ that defines the region are
+ <literal>java.lang.String</literal>
+ objects.
+ </para>
+ <para>
+ Looking at the eviction configuration snippet above, we see that a default region,
+ <literal>_default_</literal>
+ , holds attributes
+ which apply to nodes that do not fall into any of the other regions defined.
+ </para>
+ <para>
+ For each region, you can define parameters which affect how the policy which applies to the region chooses
+ to evict nodes.
+ In the example above, the
+ <literal>LRUPolicy</literal>
+ allows a
+ <literal>maxNodes</literal>
+ parameter which defines
+ how many nodes can exist in the region before it chooses to start evicting nodes. See the javadocs for each
+ policy for a list of allowed parameters.
+ </para>
+
+ <section>
+ <title>Overlapping Eviction Regions</title>
+
+ <para>It's possible to define regions that overlap. In other words, one region can be defined for
+ <emphasis>/a/b/c</emphasis>
+ , and another
+ defined for
+ <emphasis>/a/b/c/d</emphasis>
+ (which is just the
+ <emphasis>d</emphasis>
+ subtree of the
+ <emphasis>/a/b/c</emphasis>
+ sub-tree).
+ The algorithm, in order to handle scenarios like this consistently, will always choose the first region
+ it encounters.
+ In this way, if the algorithm needed to decide how to handle
+ <emphasis>/a/b/c/d/e</emphasis>
+ , it would start from there and work
+ its way up the tree until it hits the first defined region - in this case
+ <emphasis>/a/b/c/d</emphasis>
+ .
+ </para>
+ </section>
+
+ </section>
+ <section>
+ <title>Programmatic Configuration</title>
+ <para>
+ Configuring eviction using the
+ <literal>Configuration</literal>
+ object entails the use of the
+ <literal>org.jboss.cache.config.EvictionConfig</literal>
+ bean, which is passed into
+ <literal>Configuration.setEvictionConfig()</literal>
+ . See the
+ <link linkend="configuration">chapter on Configuration</link>
+ for more on building a
+ <literal>Configuration</literal>
+ programatically.
+ </para>
+
+ <para>
+ The use of simple POJO beans to represent all elements in a
+ cache's configuration also makes it fairly easy to programatically
+ add eviction regions after the cache is started . For example,
+ assume we had an existing cache configured via XML with the
+ EvictionConfig element shown above. Now at runtime we wished to
+ add a new eviction region named "/org/jboss/fifo", using
+ <literal>LRUPolicy</literal>
+ but a different number of
+ <literal>maxNodes</literal>
+ :
+ </para>
+
+ <programlisting>
+ Fqn fqn = Fqn.fromString("/org/jboss/fifo");
+
+ // Create a configuration for an LRUPolicy
+ LRUConfiguration lruc = new LRUConfiguration();
+ lruc.setMaxNodes(10000);
+
+ // Create the region and set the config
+ Region region = cache.getRegion(fqn, true);
+ region.setEvictionPolicy(lruc);
+ </programlisting>
+ </section>
+ </section>
+
+ <section>
+ <title>Shipped Eviction Policies</title>
+ <section>
+ <title>LRUPolicy - Least Recently Used</title>
+
+ <para>
+ <literal>org.jboss.cache.eviction.LRUPolicy</literal>
+ controls both the node lifetime and age. This policy guarantees a constant order (
+ <literal>O (1)</literal>
+ ) for
+ adds, removals and lookups (visits). It has the following configuration
+ parameters:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <literal>maxNodes</literal>
+ - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
+ </listitem>
+ <listitem>
+ <literal>timeToLiveSeconds</literal>
+ - The amount of time a node is not written to or read (in seconds) before the node is swept away. 0
+ denotes no limit.
+ </listitem>
+
+ <listitem>
+ <literal>maxAgeSeconds</literal>
+ - Lifespan of a node (in seconds) regardless of idle time before the node is swept away. 0 denotes no
+ limit.
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>FIFOPolicy - First In, First Out</title>
+
+ <para>
+ <literal>org.jboss.cache.eviction.FIFOPolicy</literal>
+ controls the eviction in a proper first in first out order. This policy
+ guarantees a constant order (
+ <literal>O (1)</literal>
+ ) for adds, removals and lookups (visits). It has the
+ following configuration parameters:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <literal>maxNodes</literal>
+ - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
+ </listitem>
+ </itemizedlist>
+ </section>
+
+
+ <section>
+ <title>MRUPolicy - Most Recently Used</title>
+
+ <para>
+ <literal>org.jboss.cache.eviction.MRUPolicy</literal>
+ controls
+ the eviction in based on most recently used algorithm. The most recently
+ used nodes will be the first to evict with this policy. This policy
+ guarantees a constant order (
+ <literal>O (1)</literal>
+ ) for adds, removals and lookups (visits). It has the
+ following configuration parameters:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <literal>maxNodes</literal>
+ - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>LFUPolicy - Least Frequently Used</title>
+
+ <para>
+ <literal>org.jboss.cache.eviction.LFUPolicy</literal>
+ controls
+ the eviction in based on least frequently used algorithm. The least
+ frequently used nodes will be the first to evict with this policy. Node
+ usage starts at 1 when a node is first added. Each time it is visted,
+ the node usage counter increments by 1. This number is used to determine
+ which nodes are least frequently used. LFU is also a sorted eviction
+ algorithm. The underlying EvictionQueue implementation and algorithm is
+ sorted in ascending order of the node visits counter. This class
+ guarantees a constant order (
+ <literal>O (1)</literal>
+ ) for adds, removal and searches. However, when any
+ number of nodes are added/visited to the queue for a given processing
+ pass, a single quasilinear (
+ <literal>O (n * log n)</literal>
+ ) operation is used to resort the queue in
+ proper LFU order. Similarly if any nodes are removed or evicted, a
+ single linear (
+ <literal>O (n)</literal>
+ ) pruning operation is necessary to clean up the
+ EvictionQueue. LFU has the following configuration parameters:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <literal>maxNodes</literal>
+ - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
+ </listitem>
+ <listitem>
+ <literal>minNodes</literal>
+ - This is the minimum number of nodes allowed in this region. This value determines what
+ the eviction queue should prune down to per pass. e.g. If
+ minNodes is 10 and the cache grows to 100 nodes, the cache is
+ pruned down to the 10 most frequently used nodes when the
+ eviction timer makes a pass through the eviction
+ algorithm.
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
+ <section>
+ <title>ExpirationPolicy</title>
+
+ <para>
+ <literal>org.jboss.cache.eviction.ExpirationPolicy</literal>
+ is a policy
+ that evicts nodes based on an absolute expiration time. The
+ expiration time is indicated using the
+ <literal>org.jboss.cache.Node.put()</literal>
+ method, using a String key
+ <literal>expiration</literal>
+ and the absolute time as a
+ <literal>java.lang.Long</literal>
+ object, with a value indicated as milliseconds past midnight
+ January 1st, 1970 UTC (the same relative time as provided by
+ <literal>java.lang.System.currentTimeMillis()</literal>
+ ).
+ </para>
+
+ <para>
+ This policy guarantees a constant order (
+ <literal>O (1)</literal>
+ ) for adds and removals.
+ Internally, a sorted set (TreeSet) containing the expiration
+ time and Fqn of the nodes is stored, which essentially
+ functions as a heap.
+ </para>
+
+ <para>
+ This policy has the following configuration parameters:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <literal>expirationKeyName</literal>
+ - This is the Node key name used
+ in the eviction algorithm. The configuration default is
+ <literal>expiration</literal>
+ .
+ </listitem>
+ <listitem>
+ <literal>maxNodes</literal>
+ - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ The following listing shows how the expiration date is indicated and how the
+ policy is applied:
+ <programlisting>
+ <![CDATA[
+ Cache cache = DefaultCacheFactory.createCache();
+ Fqn fqn1 = Fqn.fromString("/node/1");
+ Long future = new Long(System.currentTimeMillis() + 2000);
+
+ // sets the expiry time for a node
+ cache.getRoot().addChild(fqn1).put(ExpirationConfiguration.EXPIRATION_KEY, future);
+
+ assertTrue(cache.getRoot().hasChild(fqn1));
+ Thread.sleep(5000);
+
+ // after 5 seconds, expiration completes
+ assertFalse(cache.getRoot().hasChild(fqn1));
+]]>
+ </programlisting>
+ Note that the expiration time of nodes is only checked when the
+ region manager wakes up every
+ <literal>wakeUpIntervalSeconds</literal>
+ , so eviction
+ may happen a few seconds later than indicated.
+ </para>
+ </section>
+ <section>
+ <title>ElementSizePolicy - Eviction based on number of key/value pairs in a node</title>
+
+ <para>
+ <literal>org.jboss.cache.eviction.ElementSizePolicy</literal>
+ controls
+ the eviction in based on the number of key/value pairs in the node. Nodes The most recently
+ used nodes will be the first to evict with this policy. It has the following configuration parameters:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <literal>maxNodes</literal>
+ - This is the maximum number of nodes allowed in this region. 0 denotes no limit.
+ </listitem>
+ <listitem>
+ <literal>maxElementsPerNode</literal>
+ - This is the trigger number of attributes per node for the node to be selected for eviction. 0 denotes
+ no limit.
+ </listitem>
+ </itemizedlist>
+ </section>
+ </section>
+
+ <section>
+ <title>Writing Your Own Eviction Policies</title>
+ <section>
+ <title>Eviction Policy Plugin Design</title>
+
+ <para>The design of the JBoss Cache eviction policy framework is based
+ on an
+ <literal>EvictionInterceptor</literal>
+ to handle cache events and relay them back to the eviction
+ policies. During the cache start up, an
+ <literal>EvictionInterceptor</literal>
+ will be added to the cache
+ interceptor stack if the eviction policy is specified.
+ Then whenever a node is added, removed, evicted, or visited, the
+ <literal>EvictionInterceptor</literal>
+ will maintain state statistics and
+ information will be relayed to each individual eviction region.
+ </para>
+
+ <para>
+ There is a single eviction thread (timer) that will run at a
+ configured interval. This thread will make calls into each of the policy
+ providers and inform it of any aggregated adds,
+ removes and visits (gets) events to the cache during the configured interval.
+ The eviction thread is responsible for kicking off the eviction policy
+ processing (a single pass) for each configured eviction cache
+ region.
+ </para>
+ </section>
+
+ <section>
+ <title>Interfaces to implement</title>
+ <para>In order to implement an eviction policy, the following interfaces
+ must be implemented:
+ <itemizedlist>
+ <listitem>
+ <literal>org.jboss.cache.eviction.EvictionPolicy</literal>
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.EvictionAlgorithm</literal>
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.eviction.EvictionQueue</literal>
+ </listitem>
+ <listitem>
+ <literal>org.jboss.cache.config.EvictionPolicyConfig</literal>
+ </listitem>
+ </itemizedlist>
+ When compounded
+ together, each of these interface implementations define all the
+ underlying mechanics necessary for a complete eviction policy
+ implementation.
+ </para>
+
+ <para>
+ <emphasis>Note that:</emphasis>
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>The
+ <literal>EvictionPolicyConfig</literal>
+ implementation
+ should maintain
+ getter and setter methods for whatever configuration properties
+ the policy supports (e.g. for
+ <literal>LRUConfiguration</literal>
+ among others there is a
+ <literal>int getMaxNodes()</literal>
+ and a
+ <literal>setMaxNodes(int)</literal>
+ ). When the "EvictionConfig" section of an XML configuration
+ is parsed, these properties will be set by reflection.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Alternatively, the implementation of a new eviction policy
+ provider can be simplified by extending
+ <literal>BaseEvictionPolicy</literal>
+ and
+ <literal>BaseEvictionAlgorithm</literal>
+ . Or for properly sorted EvictionAlgorithms (sorted
+ in eviction order - see
+ <literal>LFUAlgorithm</literal>
+ ) extending
+ <literal>BaseSortedEvictionAlgorithm</literal>
+ and implementing
+ <literal>SortedEvictionQueue</literal>
+ takes
+ care of most of the common functionality available in a set of eviction
+ policy provider classes
+ </para>
+
+
+ <para>
+ <emphasis>Note that:</emphasis>
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>The
+ <literal>BaseEvictionAlgorithm</literal>
+ class maintains a processing
+ structure. It will process the ADD, REMOVE, and VISIT events queued
+ by the region first. It also maintains an collection of
+ items that were not properly evicted during the last go around
+ because of held locks. That list is pruned. Finally, the
+ EvictionQueue itself is pruned for entries that should be evicted
+ based upon the configured eviction rules for the region.
+ </para>
+ </listitem>
+ <listitem>
+ <para>The
+ <literal>BaseSortedEvictionAlgorithm</literal>
+ class will maintain a boolean
+ through the algorithm processing that will determine if any new
+ nodes were added or visited. This allows the Algorithm to determine
+ whether to resort the eviction queue items (in first to evict order)
+ or to skip the potentially expensive sorting if there have been no
+ changes to the cache in this region.
+ </para>
+ </listitem>
+ <listitem>
+ <para>The
+ <literal>SortedEvictionQueue</literal>
+ interface defines the contract used by
+ the
+ <literal>BaseSortedEvictionAlgorithm</literal>
+ abstract class that is used to
+ resort the underlying queue. Again, the queue sorting should be
+ sorted in first to evict order. The first entry in the list should
+ evict before the last entry in the queue. The last entry in the
+ queue should be the last entry that will require eviction.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ </section>
+</chapter>
\ No newline at end of file
Added: pojo/trunk/src/main/docbook/userguide/en/modules/introduction.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/introduction.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/introduction.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="introduction">
+ <title>Overview</title>
+
+ <section>
+ <title>What is JBoss Cache?</title>
+
+ <para>
+ JBoss Cache is a tree-structured, clustered, transactional cache. It is
+ the backbone for many fundamental JBoss Application Server clustering services, including - in certain
+ versions - clustering JNDI, HTTP and EJB sessions.
+ </para>
+ <para>
+ JBoss Cache can also be used as a standalone transactional and clustered caching library or even an object
+ oriented data store. It can even be embedded in other enterprise Java frameworks and application servers
+ such as BEA WebLogic or IBM WebSphere, Tomcat, Spring, Hibernate, and many others. It is also very commonly
+ used directly by standalone Java applications that do not run from within an application server, to maintain
+ clustered state.
+ </para>
+ <section>
+ <title>And what is Pojo Cache?</title>
+ <para>
+ Pojo Cache is an extension of the core JBoss Cache API. Pojo Cache offers additional functionality such as:
+ <itemizedlist>
+ <listitem>maintaining object references even after replication or persistence.</listitem>
+ <listitem>fine grained replication, where only modified object fields are replicated.</listitem>
+ <listitem>"API-less" clustering model where pojos are simply annotated as being clustered.</listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Pojo Cache has a complete and separate set of documentation, including a user guide, FAQ and tutorial and
+ as such, Pojo Cache is not discussed further in this book.
+ </para>
+ </section>
+
+ </section>
+
+ <section>
+ <title>Summary of Features</title>
+
+ <para>
+ JBoss Cache offers a simple and straightforward API, where data (simple Java objects) can be placed in the
+ cache and, based on configuration options selected, this data may be one or all of:
+ <itemizedlist>
+ <listitem>replicated to some or all cache instances in a cluster.</listitem>
+ <listitem>persisted to disk and/or a remote cluster ("far-cache").</listitem>
+ <listitem>garbage collected from memory when memory runs low, and passivated to disk so state isn't lost.
+ </listitem>
+ </itemizedlist>
+ In addition, JBoss Cache offers a rich set of enterprise-class features:
+ <itemizedlist>
+ <listitem>being able to participate in JTA transactions (works with Java EE compliant TransactionManagers).
+ </listitem>
+ <listitem>attach to JMX servers and provide runtime statistics on the state of the cache.</listitem>
+ <listitem>allow client code to attach listeners and receive notifications on cache events.</listitem>
+ </itemizedlist>
+ </para>
+
+ <para>A cache is organised as a tree, with a single root. Each node in the tree essentially contains a Map,
+ which acts as a store for key/value pairs. The only requirement placed on objects that are cached is that
+ they implement
+ <literal>java.io.Serializable</literal>
+ . Note that this requirement does not exist for Pojo Cache.
+ </para>
+
+ <para>JBoss Cache
+ can be either local or replicated. Local trees exist
+ only inside the JVM in which they are created, whereas replicated trees
+ propagate any changes to some or all other trees in the same cluster. A
+ cluster may span different hosts on a network or just different JVMs
+ on a single host.
+ </para>
+
+ <para>When a change is made to an object in the cache and that change is done in
+ the context of a transaction, the replication of changes is deferred until the transaction
+ commits successfully. All modifications are kept in a list associated with
+ the transaction for the caller. When the transaction commits, we replicate the
+ changes. Otherwise, (on a rollback) we simply undo the changes locally
+ resulting in zero network traffic and overhead. For example, if a caller
+ makes 100 modifications and then rolls back the transaction, we will not replicate
+ anything, resulting in no network traffic.
+ </para>
+
+ <para>If a caller has no transaction associated with it (and isolation level is not
+ NONE - more about this later), we will replicate right after each modification, e.g. in the above
+ case we would send 100 messages, plus an additional message for the
+ rollback. In this sense, running without a transaction can be thought of as analogous as running with
+ auto-commit switched on in JDBC terminology, where each operation is committed automatically.
+ </para>
+
+ <para>
+ JBoss Cache works out of the box with most popular transaction managers, and even provides an API where
+ custom transaction manager lookups can be written.
+ </para>
+
+ <para>
+ The cache is also completely thread-safe. It uses a pessimistic locking scheme for nodes in the tree by
+ default, with an optimistic locking scheme as a configurable option. With pessimistic locking, the degree
+ of concurrency can be tuned using a number of isolation levels, corresponding to database-style
+ transaction isolation levels, i.e., SERIALIZABLE, REPEATABLE_READ, READ_COMMITTED, READ_UNCOMMITTED and NONE.
+ Concurrency, locking and isolation levels will be discussed later.
+ </para>
+ </section>
+
+ <section>
+ <title>
+ Requirements
+ </title>
+ <para>
+ JBoss Cache requires Java 5.0 (or newer).
+ </para>
+ <para>
+ However, there is a way to build JBoss Cache as a Java 1.4.x compatible binary using
+ <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossRetro">JBossRetro</ulink>
+ to retroweave the Java 5.0 binaries. However, Red Hat Inc. does not offer professional support around the
+ retroweaved
+ binary at this time and the Java 1.4.x compatible binary is not in the binary distribution. See
+ <ulink url="http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossCacheHabaneroJava1.4">this wiki</ulink>
+ page for
+ details on building the retroweaved binary for yourself.
+ </para>
+ <para>
+ In addition to Java 5.0, at a minimum, JBoss Cache has dependencies on
+ <ulink url="http://www.jgroups.org">JGroups</ulink>
+ , and Apache's
+ <ulink
+ url="http://jakarta.apache.org/commons/logging/">commons-logging
+ </ulink>
+ . JBoss Cache ships with all dependent libraries necessary to run out of the box.
+ </para>
+ </section>
+
+ <section>
+ <title>License</title>
+ <para>
+ JBoss Cache is an open source product, using the business and OEM-friendly
+ <ulink url="http://www.opensource.org/">OSI-approved</ulink>
+ <ulink url="http://www.gnu.org/copyleft/lesser.html">LGPL license.</ulink>
+ Commercial development support, production support and training for JBoss Cache is available through
+ <ulink url="http://www.jboss.com">JBoss, a division of Red Hat Inc.</ulink>
+ JBoss Cache is a part of JBoss Professional Open Source
+ <ulink url="http://www.jboss.comindex">JEMS</ulink>
+ (JBoss Enterprise Middleware Suite).
+ </para>
+ </section>
+</chapter>
Added: pojo/trunk/src/main/docbook/userguide/en/modules/jmx_reference.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/jmx_reference.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/jmx_reference.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,308 @@
+<chapter id="jmx_reference">
+ <title>JMX References</title>
+ <section id="jmx_reference.statistics">
+ <title>JBoss Cache Statistics</title>
+ <para>
+ The following table describes the statistics currently available and may be collected via JMX.
+ </para>
+ <table>
+ <title>JBoss Cache Management Statistics</title>
+ <tgroup cols="4">
+ <colspec colnum="1" colwidth="2*"/>
+ <colspec colnum="2" colwidth="2*"/>
+ <colspec colnum="3" colwidth="1*"/>
+ <colspec colnum="4" colwidth="3*"/>
+ <thead>
+ <row>
+ <entry>MBean Name</entry>
+ <entry>Attribute</entry>
+ <entry>Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>ActivationInterceptor</entry>
+ <entry>Activations</entry>
+ <entry>long</entry>
+ <entry>Number of passivated nodes that have been activated.</entry>
+ </row>
+ <row>
+ <entry>CacheLoaderInterceptor</entry>
+ <entry>CacheLoaderLoads</entry>
+ <entry>long</entry>
+ <entry>Number of nodes loaded through a cache loader.</entry>
+ </row>
+ <row>
+ <entry>CacheLoaderInterceptor</entry>
+ <entry>CacheLoaderMisses</entry>
+ <entry>long</entry>
+ <entry>Number of unsuccessful attempts to load a node through a cache loader.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>Hits</entry>
+ <entry>long</entry>
+ <entry>Number of successful attribute retrievals.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>Misses</entry>
+ <entry>long</entry>
+ <entry>Number of unsuccessful attribute retrievals.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>Stores</entry>
+ <entry>long</entry>
+ <entry>Number of attribute store operations.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>Evictions</entry>
+ <entry>long</entry>
+ <entry>Number of node evictions.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>NumberOfAttributes</entry>
+ <entry>int</entry>
+ <entry>Number of attributes currently cached.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>NumberOfNodes</entry>
+ <entry>int</entry>
+ <entry>Number of nodes currently cached.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>ElapsedTime</entry>
+ <entry>long</entry>
+ <entry>Number of seconds that the cache has been running.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>TimeSinceReset</entry>
+ <entry>long</entry>
+ <entry>Number of seconds since the cache statistics have been reset.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>AverageReadTime</entry>
+ <entry>long</entry>
+ <entry>Average time in milliseconds to retrieve a cache attribute, including unsuccessful
+ attribute retrievals.
+ </entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>AverageWriteTime</entry>
+ <entry>long</entry>
+ <entry>Average time in milliseconds to write a cache attribute.</entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>HitMissRatio</entry>
+ <entry>double</entry>
+ <entry>Ratio of hits to hits and misses. A hit is a get attribute operation that results in an object
+ being
+ returned to the client. The retrieval may be from a cache loader if the entry isn't in the local
+ cache.
+ </entry>
+ </row>
+ <row>
+ <entry>CacheMgmtInterceptor</entry>
+ <entry>ReadWriteRatio</entry>
+ <entry>double</entry>
+ <entry>Ratio of read operations to write operations. This is the ratio of cache hits and misses to
+ cache stores.
+ </entry>
+ </row>
+ <row>
+ <entry>CacheStoreInterceptor</entry>
+ <entry>CacheLoaderStores</entry>
+ <entry>long</entry>
+ <entry>Number of nodes written to the cache loader.</entry>
+ </row>
+ <row>
+ <entry>InvalidationInterceptor</entry>
+ <entry>Invalidations</entry>
+ <entry>long</entry>
+ <entry>Number of cached nodes that have been invalidated.</entry>
+ </row>
+ <row>
+ <entry>PassivationInterceptor</entry>
+ <entry>Passivations</entry>
+ <entry>long</entry>
+ <entry>Number of cached nodes that have been passivated.</entry>
+ </row>
+ <row>
+ <entry>TxInterceptor</entry>
+ <entry>Prepares</entry>
+ <entry>long</entry>
+ <entry>Number of transaction prepare operations performed by this interceptor.</entry>
+ </row>
+ <row>
+ <entry>TxInterceptor</entry>
+ <entry>Commits</entry>
+ <entry>long</entry>
+ <entry>Number of transaction commit operations performed by this interceptor.</entry>
+ </row>
+ <row>
+ <entry>TxInterceptor</entry>
+ <entry>Rollbacks</entry>
+ <entry>long</entry>
+ <entry>Number of transaction rollbacks operations performed by this interceptor.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+
+ <section id="jmx_reference.notifications">
+ <title>JMX MBean Notifications</title>
+ <para>The following table depicts the JMX notifications available for JBoss Cache as well as the cache events to
+ which they correspond. These are the notifications that can be received through the
+ <literal>CacheJmxWrapper</literal>
+ MBean.
+ Each notification represents a single event published by JBoss Cache and provides user data corresponding to
+ the parameters of the event.
+ </para>
+ <table>
+ <title>JBoss Cache MBean Notifications</title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Notification Type</entry>
+ <entry>Notification Data</entry>
+ <entry>CacheListener Event</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>org.jboss.cache.CacheStarted</entry>
+ <entry>String : cache service name</entry>
+ <entry>cacheStarted</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.CacheStopped</entry>
+ <entry>String : cache service name</entry>
+ <entry>cacheStopped</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeCreated</entry>
+ <entry>String : fqn</entry>
+ <entry>NodeCreated</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeEvicted</entry>
+ <entry>String : fqn</entry>
+ <entry>NodeEvicted</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeLoaded</entry>
+ <entry>String : fqn</entry>
+ <entry>NodeLoaded</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeModifed</entry>
+ <entry>String : fqn</entry>
+ <entry>NodeModifed</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeRemoved</entry>
+ <entry>String : fqn</entry>
+ <entry>NodeRemoved</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeVisited</entry>
+ <entry>String : fqn</entry>
+ <entry>NodeVisited</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.ViewChange</entry>
+ <entry>String : view</entry>
+ <entry>ViewChange</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeActivate</entry>
+ <entrytbl cols="1">
+ <tbody>
+ <row>
+ <entry rowsep="0">Object[0]=String: fqn</entry>
+ </row>
+ <row>
+ <entry>Object[1]=Boolean: pre</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ <entry>NodeActivate</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeEvict</entry>
+ <entrytbl cols="1">
+ <tbody>
+ <row>
+ <entry rowsep="0">Object[0]=String: fqn</entry>
+ </row>
+ <row>
+ <entry>Object[1]=Boolean: pre</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ <entry>NodeEvict</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeModify</entry>
+ <entrytbl cols="1">
+ <tbody>
+ <row>
+ <entry rowsep="0">Object[0]=String: fqn</entry>
+ </row>
+ <row>
+ <entry rowsep="0">Object[1]=Boolean: pre</entry>
+ </row>
+ <row>
+ <entry>Object[2]=Boolean: isLocal</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ <entry>NodeModify</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodePassivate</entry>
+ <entrytbl cols="1">
+ <tbody>
+ <row>
+ <entry rowsep="0">Object[0]=String: fqn</entry>
+ </row>
+ <row>
+ <entry>Object[1]=Boolean: pre</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ <entry>NodePassivate</entry>
+ </row>
+ <row>
+ <entry>org.jboss.cache.NodeRemove</entry>
+ <entrytbl cols="1">
+ <tbody>
+ <row>
+ <entry rowsep="0">Object[0]=String: fqn</entry>
+ </row>
+ <row>
+ <entry rowsep="0">Object[1]=Boolean: pre</entry>
+ </row>
+ <row>
+ <entry>Object[2]=Boolean: isLocal</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ <entry>NodeRemove</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+</chapter>
\ No newline at end of file
Added: pojo/trunk/src/main/docbook/userguide/en/modules/preface.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/preface.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/preface.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,48 @@
+<preface id="preface">
+ <title>Preface</title>
+
+ <para>
+ This is the official JBoss Cache user guide. Along with its accompanying documents (an FAQ, a tutorial and a
+ whole set of documents on PojoCache), this is freely available on the JBoss Cache <ulink url="http://labs.jboss.com/jbosscache">documentation site.</ulink>
+ </para>
+ <para>
+ When used, JBoss Cache refers to JBoss Cache Core, a tree-structured, clustered, transactional cache.
+ Pojo Cache, also a part of the JBoss Cache distribution, is documented separately. (Pojo Cache is a cache that
+ deals with Plain Old Java Objects, complete with object relationships, with the ability to cluster such pojos
+ while maintaining their relationships. Please see the Pojo Cache documentation for more information about this.)
+ </para>
+
+ <para>
+ This book is targeted at both developers wishing to use JBoss Cache as a clustering and caching library in
+ their codebase, as well as people who wish to "OEM" JBoss Cache by building on and extending its features. As
+ such,
+ this book is split into two major sections - one detailing the "User" API and the other going much deeper into
+ specialist topics and the JBoss Cache architecture.
+ </para>
+
+ <para>
+ In general, a good knowledge of the Java programming language along with a strong appreciation and understanding
+ of transactions and concurrent threads is necessary. No prior knowledge of JBoss Application Server is expected
+ or required.
+ </para>
+
+ <para>
+ For further discussion, use the
+ <ulink url="http://www.jboss.com/index.html?module=bb&op=viewforum&f=157">user forum</ulink>
+ linked on the JBoss Cache <ulink url="http://labs.jboss.com/jbosscache">website.</ulink> We also provide a mechanism for
+ tracking bug reports and feature requests on the JBoss Cache <ulink url="http://jira.jboss.com/jira/browse/JBCACHE">JIRA issue tracker.</ulink>
+
+ If you are interested in the development of JBoss Cache or in translating this documentation into other languages,
+ we'd love
+ to hear from you. Please post a message on the
+ <ulink url="http://www.jboss.com/index.html?module=bb&op=viewforum&f=157">user forum</ulink>
+ or contact us by using the JBoss Cache <ulink url="https://lists.jboss.org/mailman/listinfo/jbosscache-dev">developer mailing list.</ulink>
+ </para>
+
+ <para>
+ This book is specifically targeted at the JBoss Cache release of the same version number. It may not apply to
+ older or newer releases of JBoss Cache. It is important that you use the documentation appropriate to the version
+ of JBoss Cache you intend to use.
+ </para>
+
+</preface>
\ No newline at end of file
Added: pojo/trunk/src/main/docbook/userguide/en/modules/replication.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/replication.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/replication.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,730 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="clustering">
+ <title>Clustering</title>
+
+ <para>This chapter talks about aspects around clustering JBoss Cache.</para>
+
+ <section>
+ <title>Cache Replication Modes</title>
+
+ <para>JBoss Cache can be configured to be either local (standalone) or
+ clustered. If in a cluster, the cache can be configured to replicate
+ changes, or to invalidate changes. A detailed discussion on this
+ follows.
+ </para>
+
+ <section>
+ <title>Local Mode</title>
+
+ <para>Local caches don't join a cluster and don't communicate with other
+ caches in a cluster. Therefore their elements don't need to be
+ serializable - however, we recommend making them serializable, enabling
+ a user to change the cache mode at any time. The dependency on the
+ JGroups library is still there, although a JGroups channel is not
+ started.
+ </para>
+ </section>
+
+ <section>
+ <title>Replicated Caches</title>
+
+ <para>Replicated caches replicate all changes to some or all of the other cache
+ instances in the cluster. Replication can either happen after each
+ modification (no transactions), or at the end of a transaction (commit
+ time).
+ </para>
+
+ <para>Replication can be synchronous or asynchronous . Use of either one
+ of the options is application dependent. Synchronous replication blocks
+ the caller (e.g. on a
+ <literal>put()</literal>
+ ) until the modifications
+ have been replicated successfully to all nodes in a cluster.
+ Asynchronous replication performs replication in the background (the
+ <literal>put()</literal>
+ returns immediately). JBoss Cache also offers a
+ replication queue, where modifications are replicated periodically (i.e.
+ interval-based), or when the queue size exceeds a number of elements, or
+ a combination thereof.
+ </para>
+
+ <para>Asynchronous replication is faster (no caller blocking), because
+ synchronous replication requires acknowledgments from all nodes in a
+ cluster that they received and applied the modification successfully
+ (round-trip time). However, when a synchronous replication returns
+ successfully, the caller knows for sure that all modifications have been
+ applied to all cache instances, whereas this is not be the case with asynchronous
+ replication. With asynchronous replication, errors are simply written to
+ a log. Even when using transactions, a transaction may succeed but
+ replication may not succeed on all cache instances.
+ </para>
+
+ <section id="replication.tx">
+ <title>Replicated Caches and Transactions</title>
+
+ <para>When using transactions, replication only occurs at the
+ transaction boundary - i.e., when a transaction commits. This results
+ in minimising replication traffic since a single modification is
+ broadcast rather than a series of individual modifications, and can be
+ a lot more efficient than not using transactions. Another effect of
+ this is that if a transaction were to roll back, nothing is broadcast
+ across a cluster.
+ </para>
+
+ <para>Depending on whether you are running your cluster in
+ asynchronous or synchronous mode, JBoss Cache will use either a single
+ phase or
+ <ulink
+ url="http://en.wikipedia.org/wiki/Two-phase_commit_protocol">two phase
+ commit
+ </ulink>
+ protocol, respectively.
+ </para>
+
+ <section>
+ <title>One Phase Commits</title>
+
+ <para>Used when your cache mode is REPL_ASYNC. All modifications are
+ replicated in a single call, which instructs remote caches to apply
+ the changes to their local in-memory state and commit locally.
+ Remote errors/rollbacks are never fed back to the originator of the
+ transaction since the communication is asynchronous.
+ </para>
+ </section>
+
+ <section>
+ <title>Two Phase Commits</title>
+
+ <para>Used when your cache mode is REPL_SYNC. Upon committing your
+ transaction, JBoss Cache broadcasts a prepare call, which carries
+ all modifications relevant to the transaction. Remote caches then
+ acquire local locks on their in-memory state and apply the
+ modifications. Once all remote caches respond to the prepare call,
+ the originator of the transaction broadcasts a commit. This
+ instructs all remote caches to commit their data. If any of the
+ caches fail to respond to the prepare phase, the originator
+ broadcasts a rollback.
+ </para>
+
+ <para>Note that although the prepare phase is synchronous, the
+ commit and rollback phases are asynchronous. This is because
+ <ulink
+ url="http://java.sun.com/products/jta/">Sun's JTA
+ specification
+ </ulink>
+ does not specify how transactional resources
+ should deal with failures at this stage of a transaction; and other
+ resources participating in the transaction may have indeterminate
+ state anyway. As such, we do away with the overhead of synchronous
+ communication for this phase of the transaction. That said, they can
+ be forced to be synchronous using the
+ <literal>SyncCommitPhase</literal>
+ and
+ <literal>SyncRollbackPhase</literal>
+ configuration
+ attributes.
+ </para>
+ </section>
+ </section>
+
+ <section id="br">
+ <title>Buddy Replication</title>
+
+ <para>Buddy Replication allows you to suppress replicating your data
+ to all instances in a cluster. Instead, each instance picks one or
+ more 'buddies' in the cluster, and only replicates to these specific
+ buddies. This greatly helps scalability as there is no longer a memory
+ and network traffic impact every time another instance is added to a
+ cluster.
+ </para>
+
+ <para>One of the most common use cases of Buddy Replication is when a
+ replicated cache is used by a servlet container to store HTTP session
+ data. One of the pre-requisites to buddy replication working well and
+ being a real benefit is the use of
+ <emphasis>session
+ affinity
+ </emphasis>
+ , more casually known as
+ <emphasis>sticky
+ sessions
+ </emphasis>
+ in HTTP session replication speak. What this means
+ is that if certain data is frequently accessed, it is desirable that
+ this is always accessed on one instance rather than in a round-robin
+ fashion as this helps the cache cluster optimise how it chooses
+ buddies, where it stores data, and minimises replication
+ traffic.
+ </para>
+
+ <para>If this is not possible, Buddy Replication may prove to be more
+ of an overhead than a benefit.
+ </para>
+
+ <section>
+ <title>Selecting Buddies</title>
+
+ <figure>
+ <title>BuddyLocator</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="BuddyReplication.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>Buddy Replication uses an instance of a
+ <literal>BuddyLocator</literal>
+ which contains the logic used to
+ select buddies in a network. JBoss Cache currently ships with a
+ single implementation,
+ <literal>NextMemberBuddyLocator</literal>
+ ,
+ which is used as a default if no implementation is provided. The
+ <literal>NextMemberBuddyLocator</literal>
+ selects the next member in
+ the cluster, as the name suggests, and guarantees an even spread of
+ buddies for each instance.
+ </para>
+
+ <para>The
+ <literal>NextMemberBuddyLocator</literal>
+ takes in 2
+ parameters, both optional.
+ <itemizedlist>
+ <listitem>
+
+
+ <literal>numBuddies</literal>
+
+ - specifies how many buddies each instance should pick to back its data onto. This defaults to
+ 1.
+ </listitem>
+
+ <listitem>
+
+
+ <literal>ignoreColocatedBuddies</literal>
+
+ - means that each instance will
+
+ <emphasis>try</emphasis>
+
+ to select a buddy on a different physical host. If not able to do so though, it will fall back
+ to colocated instances. This defaults to
+
+ <literal>true</literal>
+
+ .
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>BuddyPools</title>
+
+ <para>Also known as
+ <emphasis>replication groups</emphasis>
+ , a buddy
+ pool is an optional construct where each instance in a cluster may
+ be configured with a buddy pool name. Think of this as an 'exclusive
+ club membership' where when selecting buddies,
+ <literal>BuddyLocator</literal>
+ s that support buddy pools would try
+ and select buddies sharing the same buddy pool name. This allows
+ system administrators a degree of flexibility and control over how
+ buddies are selected. For example, a sysadmin may put two instances
+ on two separate physical servers that may be on two separate
+ physical racks in the same buddy pool. So rather than picking an
+ instance on a different host on the same rack,
+ <literal>BuddyLocator</literal>
+ s would rather pick the instance in
+ the same buddy pool, on a separate rack which may add a degree of
+ redundancy.
+ </para>
+ </section>
+
+ <section>
+ <title>Failover</title>
+
+ <para>In the unfortunate event of an instance crashing, it is
+ assumed that the client connecting to the cache (directly or
+ indirectly, via some other service such as HTTP session replication)
+ is able to redirect the request to any other random cache instance
+ in the cluster. This is where a concept of Data Gravitation comes
+ in.
+ </para>
+
+ <para>Data Gravitation is a concept where if a request is made on a
+ cache in the cluster and the cache does not contain this
+ information, it asks other instances in the cluster for the
+ data. In other words, data is lazily transferred, migrating
+ <emphasis>only</emphasis>
+ when other nodes ask for it. This strategy
+ prevents a network storm effect where lots of data is pushed around
+ healthy nodes because only one (or a few) of them die.
+ </para>
+
+ <para>If the data is not found in the primary section of some node,
+ it would (optionally) ask other instances to check in the backup
+ data they store for other caches.
+ This means that even if a cache containing your session dies, other
+ instances will still be able to access this data by asking the cluster
+ to search through their backups for this data.
+ </para>
+
+ <para>Once located, this data is transferred to the instance
+ which requested it and is added to this instance's data tree.
+ The data is then (optionally) removed from all other instances
+ (and backups) so that if session affinity is used, the affinity
+ should now be to this new cache instance which has just
+ <emphasis>taken
+ ownership
+ </emphasis>
+ of this data.
+ </para>
+
+ <para>Data Gravitation is implemented as an interceptor. The
+ following (all optional) configuration properties pertain to data
+ gravitation.
+ <itemizedlist>
+ <listitem>
+
+
+ <literal>dataGravitationRemoveOnFind</literal>
+
+ - forces all remote caches that own the data or hold backups for the data to remove that data,
+ thereby making the requesting cache the new data owner. This removal, of course, only happens
+ after the new owner finishes replicating data to its buddy. If set to
+
+ <literal>false</literal>
+
+ an evict is broadcast instead of a remove, so any state persisted in cache loaders will remain.
+ This is useful if you have a shared cache loader configured. Defaults to
+
+ <literal>true</literal>
+
+ .
+ </listitem>
+
+ <listitem>
+
+
+ <literal>dataGravitationSearchBackupTrees</literal>
+
+ - Asks remote instances to search through their backups as well as main data trees. Defaults to
+
+ <literal>true</literal>
+
+ . The resulting effect is that if this is
+
+ <literal>true</literal>
+
+ then backup nodes can respond to data gravitation requests in addition to data owners.
+ </listitem>
+
+ <listitem>
+
+
+ <literal>autoDataGravitation</literal>
+
+ - Whether data gravitation occurs for every cache miss. By default this is set to
+
+ <literal>false</literal>
+
+ to prevent unnecessary network calls. Most use cases will know when it may need to gravitate
+ data and will pass in an
+
+ <literal>Option</literal>
+
+ to enable data gravitation on a per-invocation basis. If
+
+ <literal>autoDataGravitation</literal>
+
+ is
+
+ <literal>true</literal>
+
+ this
+
+ <literal>Option</literal>
+
+ is unnecessary.
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>Configuration</title>
+
+ <para>
+ <programlisting>
+ <![CDATA[
+<!-- Buddy Replication config -->
+<attribute name="BuddyReplicationConfig">
+ <config>
+
+ <!-- Enables buddy replication. This is the ONLY mandatory configuration element here. -->
+ <buddyReplicationEnabled>true</buddyReplicationEnabled>
+
+ <!-- These are the default values anyway -->
+ <buddyLocatorClass>org.jboss.cache.buddyreplication.NextMemberBuddyLocator</buddyLocatorClass>
+
+ <!-- numBuddies is the number of backup nodes each node maintains. ignoreColocatedBuddies means
+ that each node will *try* to select a buddy on a different physical host. If not able to do so though,
+ it will fall back to colocated nodes. -->
+ <buddyLocatorProperties>
+ numBuddies = 1
+ ignoreColocatedBuddies = true
+ </buddyLocatorProperties>
+
+ <!-- A way to specify a preferred replication group. If specified, we try and pick a buddy which shares
+ the same pool name (falling back to other buddies if not available). This allows the sysdmin to
+ hint at backup buddies are picked, so for example, nodes may be hinted topick buddies on a different
+ physical rack or power supply for added fault tolerance. -->
+ <buddyPoolName>myBuddyPoolReplicationGroup</buddyPoolName>
+
+ <!-- Communication timeout for inter-buddy group organisation messages (such as assigning to and
+ removing from groups, defaults to 1000. -->
+ <buddyCommunicationTimeout>2000</buddyCommunicationTimeout>
+
+ <!-- Whether data is removed from old owners when gravitated to a new owner. Defaults to true. -->
+ <dataGravitationRemoveOnFind>true</dataGravitationRemoveOnFind>
+
+ <!-- Whether backup nodes can respond to data gravitation requests, or only the data owner is
+ supposed to respond. Defaults to true. -->
+ <dataGravitationSearchBackupTrees>true</dataGravitationSearchBackupTrees>
+
+ <!-- Whether all cache misses result in a data gravitation request. Defaults to false, requiring
+ callers to enable data gravitation on a per-invocation basis using the Options API. -->
+ <autoDataGravitation>false</autoDataGravitation>
+
+ </config>
+</attribute>
+
+]]>
+ </programlisting>
+ </para>
+ </section>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>Invalidation</title>
+
+ <para>If a cache is configured for invalidation rather than replication,
+ every time data is changed in a cache other caches in the cluster receive
+ a message informing them that their data is now stale and should be
+ evicted from memory. Invalidation, when used with a shared cache loader
+ (see chapter on Cache Loaders) would cause remote caches to refer to the
+ shared cache loader to retrieve modified data. The benefit of this is
+ twofold: network traffic is minimised as invalidation messages are very
+ small compared to replicating updated data, and also that other caches in
+ the cluster look up modified data in a lazy manner, only when
+ needed.
+ </para>
+
+ <para>Invalidation messages are sent after each modification (no
+ transactions), or at the end of a transaction, upon successful commit.
+ This is usually more efficient as invalidation messages can be optimised
+ for the transaction as a whole rather than on a per-modification
+ basis.
+ </para>
+
+ <para>Invalidation too can be synchronous or asynchronous, and just as in
+ the case of replication, synchronous invalidation blocks until all caches
+ in the cluster receive invalidation messages and have evicted stale data
+ while asynchronous invalidation works in a 'fire-and-forget' mode, where
+ invalidation messages are broadcast but doesn't block and wait for
+ responses.
+ </para>
+ </section>
+
+ <section>
+ <title>State Transfer</title>
+
+ <para>
+ <emphasis>State Transfer</emphasis>
+ refers to the process by which a
+ JBoss Cache instance prepares itself to begin providing a service by
+ acquiring the current state from another cache instance and integrating
+ that state into its own state.
+ </para>
+
+ <section>
+ <title>State Transfer Types</title>
+
+ <para>There are three divisions of state transfer types depending on a
+ point of view related to state transfer. First, in the context of
+ particular state transfer implementation, the underlying plumbing, there
+ are two starkly different state transfer types: byte array and streaming
+ based state transfer. Second, state transfer can be full or partial
+ state transfer depending on a subtree being transferred. Entire cache
+ tree transfer represents full transfer while transfer of a particular
+ subtree represents partial state transfer. And finally state transfer
+ can be "in-memory" and "persistent" transfer depending on a particular
+ use of cache.
+ </para>
+ </section>
+
+ <section>
+ <title>Byte array and streaming based state transfer</title>
+
+ <para>Byte array based transfer was a default and only transfer
+ methodology for cache in all previous releases up to 2.0. Byte array
+ based transfer loads entire state transferred into a byte array and
+ sends it to a state receiving member. Major limitation of this approach
+ is that the state transfer that is very large (>1GB) would likely
+ result in OutOfMemoryException. Streaming state transfer provides an
+ InputStream to a state reader and an OutputStream to a state writer.
+ OutputStream and InputStream abstractions enable state transfer in byte
+ chunks thus resulting in smaller memory requirements. For example, if
+ application state is represented as a tree whose aggregate size is 1GB,
+ rather than having to provide a 1GB byte array streaming state transfer
+ transfers the state in chunks of N bytes where N is user
+ configurable.
+ </para>
+
+ <para>Byte array and streaming based state transfer are completely API
+ transparent, interchangeable, and statically configured through a
+ standard cache configuration XML file. Refer to JGroups documentation on
+ how to change from one type of transfer to another.
+ </para>
+ </section>
+
+ <section>
+ <title>Full and partial state transfer</title>
+
+ <para>If either in-memory or persistent state transfer is enabled, a
+ full or partial state transfer will be done at various times, depending
+ on how the cache is used. "Full" state transfer refers to the transfer
+ of the state related to the entire tree -- i.e. the root node and all
+ nodes below it. A "partial" state transfer is one where just a portion
+ of the tree is transferred -- i.e. a node at a given Fqn and all nodes
+ below it.
+ </para>
+
+ <para>If either in-memory or persistent state transfer is enabled, state
+ transfer will occur at the following times:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>Initial state transfer. This occurs when the cache is first
+ started (as part of the processing of the
+ <literal>start()</literal>
+ method). This is a full state transfer. The state is retrieved from
+ the cache instance that has been operational the longest.
+ <footnote>
+ <para>The longest operating cache instance is always, in JGroups
+ terms, the coordinator.
+ </para>
+ </footnote>
+ If there is any problem receiving or integrating the state, the cache
+ will not start.
+ </para>
+
+ <para>Initial state transfer will occur unless:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>The cache's
+ <literal>InactiveOnStartup</literal>
+ property
+ is
+ <literal>true</literal>
+ . This property is used in
+ conjunction with region-based marshalling.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Buddy replication is used. See below for more on state
+ transfer with buddy replication.
+ </para>
+ </listitem>
+ </orderedlist>
+ </listitem>
+
+ <listitem>
+ <para>Partial state transfer following region activation. When
+ region-based marshalling is used, the application needs to register
+ a specific class loader with the cache. This class loader is used
+ to unmarshall the state for a specific region (subtree) of the cache.
+ </para>
+
+ <para>After registration, the application calls
+ <literal>cache.getRegion(fqn, true).activate()</literal>
+ ,
+ which initiates a partial state transfer of the relevant subtree's
+ state. The request is first made to the oldest cache instance in the
+ cluster. However, if that instance responds with no state, it is then
+ requested from each instance in turn until one either provides state
+ or all instances have been queried.
+ </para>
+
+ <para>Typically when region-based marshalling is used, the cache's
+ <literal>InactiveOnStartup</literal>
+ property is set to
+ <literal>true</literal>
+ . This suppresses initial state transfer,
+ which would fail due to the inability to deserialize the transferred
+ state.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Buddy replication. When buddy replication is used, initial
+ state transfer is disabled. Instead, when a cache instance joins the
+ cluster, it becomes the buddy of one or more other instances, and
+ one or more other instances become its buddy. Each time an instance
+ determines it has a new buddy providing backup for it, it pushes
+ it's current state to the new buddy. This "pushing" of state to the
+ new buddy is slightly different from other forms of state transfer,
+ which are based on a "pull" approach (i.e. recipient asks for and
+ receives state). However, the process of preparing and integrating
+ the state is the same.
+ </para>
+
+ <para>This "push" of state upon buddy group formation only occurs if
+ the
+ <literal>InactiveOnStartup</literal>
+ property is set to
+ <literal>false</literal>
+ . If it is
+ <literal>true</literal>
+ , state
+ transfer amongst the buddies only occurs when the application
+ activates the region on the various members of the group.
+ </para>
+
+ <para>Partial state transfer following a region activation call is
+ slightly different in the buddy replication case as well. Instead of
+ requesting the partial state from one cache instance, and trying all
+ instances until one responds, with buddy replication the instance
+ that is activating a region will request partial state from each
+ instance for which it is serving as a backup.
+ </para>
+ </listitem>
+ </orderedlist>
+ </section>
+
+ <section>
+ <title>Transient ("in-memory") and persistent state transfer</title>
+
+ <para>The state that is acquired and integrated can consist of two basic
+ types:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>"Transient" or "in-memory" state. This consists of the actual
+ in-memory state of another cache instance - the contents of the
+ various in-memory nodes in the cache that is providing state are
+ serialized and transferred; the recipient deserializes the data,
+ creates corresponding nodes in its own in-memory tree, and populates
+ them with the transferred data.
+ </para>
+
+ <para>"In-memory" state transfer is enabled by setting the cache's
+ <literal>FetchInMemoryState</literal>
+ configuration attribute to
+ <literal>true</literal>
+ .
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>"Persistent" state. Only applicable if a non-shared cache
+ loader is used. The state stored in the state-provider cache's
+ persistent store is deserialized and transferred; the recipient
+ passes the data to its own cache loader, which persists it to the
+ recipient's persistent store.
+ </para>
+
+ <para>"Persistent" state transfer is enabled by setting a cache
+ loader's
+ <literal>fetchPersistentState</literal>
+ attribute to
+ <literal>true</literal>
+ . If multiple cache loaders are configured
+ in a chain, only one can have this property set to true; otherwise
+ you will get an exception at startup.
+ </para>
+
+ <para>Persistent state transfer with a shared cache loader does not
+ make sense, as the same persistent store that provides the data will
+ just end up receiving it. Therefore, if a shared cache loader is
+ used, the cache will not allow a persistent state transfer even if a
+ cache loader has
+ <literal>fetchPersistentState</literal>
+ set to
+ <literal>true</literal>
+ .
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>Which of these types of state transfer is appropriate depends on
+ the usage of the cache.
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>If a write-through cache loader is used, the current cache
+ state is fully represented by the persistent state. Data may have
+ been evicted from the in-memory state, but it will still be in the
+ persistent store. In this case, if the cache loader is not shared,
+ persistent state transfer is used to ensure the new cache has the
+ correct state. In-memory state can be transferred as well if the
+ desire is to have a "hot" cache -- one that has all relevant data in
+ memory when the cache begins providing service. (Note that the
+ <literal><![CDATA[<cacheloader><preload>]]></literal>
+ element in the
+ <literal>CacheLoaderConfig</literal>
+ configuration parameter can be used as well to
+ provide a "warm" or "hot" cache without requiring an in-memory state
+ transfer. This approach somewhat reduces the burden on the cache
+ instance providing state, but increases the load on the persistent
+ store on the recipient side.)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>If a cache loader is used with passivation, the full
+ representation of the state can only be obtained by combining the
+ in-memory (i.e. non-passivated) and persistent (i.e. passivated)
+ states. Therefore an in-memory state transfer is necessary. A
+ persistent state transfer is necessary if the cache loader is not
+ shared.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>If no cache loader is used and the cache is solely a
+ write-aside cache (i.e. one that is used to cache data that can also
+ be found in a persistent store, e.g. a database), whether or not
+ in-memory state should be transferred depends on whether or not a
+ "hot" cache is desired.
+ </para>
+ </listitem>
+ </orderedlist>
+ </section>
+ <section>
+ <title>Configuring State Transfer</title>
+ <para>
+ To ensure state transfer behaves as expected, it is important that all nodes in the cluster are configured
+ with
+ the same settings for persistent and transient state. This is because byte array based transfers, when
+ requested,
+ rely only on the requester's configuration while stream based transfers rely on both the requester and
+ sender's
+ configuration, and this is expected to be identical.
+ </para>
+ </section>
+ </section>
+</chapter>
Added: pojo/trunk/src/main/docbook/userguide/en/modules/transactions.xml
===================================================================
--- pojo/trunk/src/main/docbook/userguide/en/modules/transactions.xml (rev 0)
+++ pojo/trunk/src/main/docbook/userguide/en/modules/transactions.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,345 @@
+<chapter id="transactions">
+ <title>Transactions and Concurrency</title>
+ <section>
+ <title>Concurrent Access</title>
+
+ <para>JBoss Cache is a thread safe caching API, and uses its own efficient mechanisms of controlling concurrent
+ access. It uses a pessimistic locking scheme by default for this purpose. Optimistic locking may alternatively
+ be used, and is discussed later.
+ </para>
+
+ <section>
+ <title>Locks</title>
+ <para>Locking is done internally, on a node-level. For example when we
+ want to access "/a/b/c", a lock will be acquired for nodes "a", "b" and
+ "c". When the same transaction wants to access "/a/b/c/d", since we
+ already hold locks for "a", "b" and "c", we only need to acquire a lock
+ for "d".
+ </para>
+ <para>Lock owners are either transactions (call is made within the scope of an existing transaction)
+ or threads (no transaction associated with the call).
+ Regardless, a transaction or a thread is internally transformed into
+ an instance of
+ <literal>GlobalTransaction</literal>
+ , which is used as a globally unique identifier
+ for modifications across a cluster. E.g. when we run a two-phase commit
+ protocol across the cluster, the
+ <literal>GlobalTransaction</literal>
+ uniquely identifies a unit of work across a cluster.
+ </para>
+
+ <para>Locks can be read or write locks. Write locks serialize read and
+ write access, whereas read-only locks only serialize read access. When a
+ write lock is held, no other write or read locks can be acquired. When a
+ read lock is held, others can acquire read locks. However, to acquire
+ write locks, one has to wait until all read locks have been released. When
+ scheduled concurrently, write locks always have precedence over read
+ locks. Note that (if enabled) read locks can be upgraded to write
+ locks.
+ </para>
+
+ <para>Using read-write locks helps in the following scenario: consider a
+ tree with entries "/a/b/n1" and "/a/b/n2". With write-locks, when Tx1
+ accesses "/a/b/n1", Tx2 cannot access "/a/b/n2" until Tx1 has completed
+ and released its locks. However, with read-write locks this is possible,
+ because Tx1 acquires read-locks for "/a/b" and a read-write lock for
+ "/a/b/n1". Tx2 is then able to acquire read-locks for "/a/b" as well, plus
+ a read-write lock for "/a/b/n2". This allows for more concurrency in
+ accessing the cache.
+ </para>
+ </section>
+
+ <section>
+ <title>Pessimistic locking</title>
+ <para>By default, JBoss Cache uses pessimistic locking. Locking is not exposed directly to user. Instead, a
+ transaction isolation level which provides different locking behaviour is configurable.
+ </para>
+ <section>
+ <title>Isolation levels</title>
+ <para>JBoss Cache supports the following transaction isolation levels, analogous to database ACID isolation
+ levels. A user can configure an instance-wide isolation level of NONE, READ_UNCOMMITTED, READ_COMMITTED,
+ REPEATABLE_READ, or SERIALIZABLE. REPEATABLE_READ is the default isolation level used.
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>NONE. No transaction support is needed. There is no locking at
+ this level, e.g., users will have to manage the data integrity.
+ Implementations use no locks.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>READ_UNCOMMITTED. Data can be read anytime while write
+ operations are exclusive. Note that this level doesn't prevent the
+ so-called "dirty read" where data modified in Tx1 can be read in Tx2
+ before Tx1 commits. In other words, if you have the following
+ sequence,
+ <programlisting>
+ <![CDATA[
+ Tx1 Tx2
+ W
+ R
+]]>
+ </programlisting>
+
+ using this isolation level will not prevent Tx2 read operation.
+ Implementations typically use an exclusive lock for writes while reads
+ don't need to acquire a lock.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>READ_COMMITTED. Data can be read any time as long as there is no
+ write. This level prevents the dirty read. But it doesn’t prevent the
+ so-called ‘non-repeatable read’ where one thread reads the data twice
+ can produce different results. For example, if you have the following
+ sequence,
+ <programlisting>
+ <![CDATA[
+ Tx1 Tx2
+ R
+ W
+ R
+]]>
+ </programlisting>
+ </para>
+
+ <para>where the second read in Tx1 thread will produce different
+ result.
+ </para>
+
+ <para>Implementations usually use a read-write lock; reads succeed
+ acquiring the lock when there are only reads, writes have to wait
+ until there are no more readers holding the lock, and readers are
+ blocked acquiring the lock until there are no more writers holding the
+ lock. Reads typically release the read-lock when done, so that a
+ subsequent read to the same data has to re-acquire a read-lock; this
+ leads to nonrepeatable reads, where 2 reads of the same data might
+ return different values. Note that, the write only applies regardless
+ of transaction state (whether it has been committed or not).
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>REPEATABLE_READ. Data can be read while there is no write and
+ vice versa. This level prevents "non-repeatable read" but it does not
+ completely prevent the so-called "phantom read" where new data can be
+ inserted into the tree from another transaction. Implementations
+ typically use a read-write lock. This is the default isolation level used.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>SERIALIZABLE. Data access is synchronized with exclusive locks.
+ Only 1 writer or reader can have the lock at any given time. Locks are
+ released at the end of the transaction. Regarded as very poor for performance and
+ thread/transaction concurrency.
+ </para>
+ </listitem>
+ </orderedlist>
+
+ </section>
+
+ <section>
+ <title>Insertion and Removal of Nodes</title>
+
+ <para>
+ By default, before inserting a new node into the tree or removing an existing node from the
+ tree, JBoss Cache will only attempt to acquire a read lock on the new node's parent node.
+ This approach does not treat child nodes as an integral part of a parent node's state.
+ This approach allows greater concurrency if nodes are frequently added or removed, but
+ at a cost of lesser correctness. For use cases where greater correctness is necessary, JBoss
+ Cache provides a configuration option
+ <literal>LockParentForChildInsertRemove</literal>
+ .
+ If this is set to
+ <literal>true</literal>
+ , insertions and removals of child nodes
+ require the acquisition of a
+ <emphasis>write lock</emphasis>
+ on the parent node.
+ </para>
+ </section>
+ </section>
+
+ <section>
+ <title>Optimistic Locking</title>
+ <para>The motivation for optimistic locking is to improve concurrency. When a lot of threads have a lot of
+ contention for access to the data tree, it can be inefficient to lock portions of the tree - for reading or
+ writing - for the entire duration of a transaction as we do in pessimistic locking. Optimistic locking
+ allows for greater concurrency of threads and transactions by using a technique called data versioning,
+ explained here. Note that isolation levels (if configured) are ignored if optimistic locking is enabled.
+ </para>
+ <section>
+ <title>Architecture</title>
+ <para>Optimistic locking treats all method calls as transactional
+ <footnote>
+ <para>Because of this requirement, you must always have a transaction manager configured when using
+ optimistic locking.
+ </para>
+ </footnote>
+ . Even if you do not invoke a call within the scope of an ongoing transaction, JBoss Cache creates an
+ <emphasis>implicit transaction</emphasis>
+ and commits this transaction when the invocation completes. Each transaction
+ maintains a transaction workspace, which contains a copy of the data used within the transaction.
+ </para>
+ <para>For example, if a transaction calls
+ <literal>cache.getRoot().getChild( Fqn.fromString("/a/b/c") )</literal>
+ ,
+ nodes a, b and c are copied from the main data tree
+ and into the workspace. The data is versioned and all calls in the transaction work on the copy of the
+ data rather than the actual data. When the transaction commits, its workspace is merged back into the
+ underlying tree by matching versions. If there is a version mismatch - such as when the actual data tree
+ has a higher version than the workspace, perhaps if another transaction were to access the same data,
+ change it and commit before the first transaction can finish - the transaction throws a
+ <literal>RollbackException</literal>
+ when committing and the commit fails.
+ </para>
+ <para>Optimistic locking uses the same locks we speak of above, but the locks are only held for a very short
+ duration - at the start of a transaction to build a workspace, and when the transaction commits and has
+ to merge data back into the tree.
+ </para>
+ <para>
+ So while optimistic locking may occasionally fail if version validations fail or may run slightly slower
+ than pessimistic locking due to the inevitable overhead and extra processing of maintaining workspaces,
+ versioned data and validating on commit, it does buy you a near-SERIALIZABLE degree of data integrity
+ while maintaining a very high level of concurrency.
+ </para>
+ </section>
+ <section>
+ <title>Data Versioning</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="DataVersions.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+ <para>
+ Optimistic locking makes use of the
+ <literal>DataVersion</literal>
+ interface (and an internal and default
+ <literal>DefaultDataVersion</literal>
+ implementation to keep a track of node versioning. In certain cases,
+ where cached data is an in-memory representation of data from an external source such as a database,
+ it makes sense to align the versions used in JBoss Cache with the versions used externally. As such,
+ using the
+ <link linkend="configuration.options">options API</link>
+ , it is possible to set the
+ <literal>DataVersion</literal>
+ you wish to use on a per-invocation basis, allowing you to implement the
+ <literal>DataVersion</literal>
+ interface to hold the versioning information obtained externally before putting your data into the
+ cache.
+ </para>
+ </section>
+ <section>
+ <title>Configuration</title>
+ Optimistic locking is enabled by using the NodeLockingScheme XML attribute, and setting it to "OPTIMISTIC":
+ <programlisting>
+ <![CDATA[
+ ...
+ <!--
+ Node locking scheme:
+ OPTIMISTIC
+ PESSIMISTIC (default)
+ -->
+ <attribute name="NodeLockingScheme">OPTIMISTIC</attribute>
+ ...
+ ]]>
+ </programlisting>
+ </section>
+ </section>
+ </section>
+
+
+ <section>
+ <title>Transactional Support</title>
+
+ <para>JBoss Cache can be configured to use and participate in JTA compliant transactions. Alternatively, if
+ transaction support is disabled, it is equivalent to setting AutoCommit to
+ on where modifications are potentially
+ <footnote>
+ <para>Depending on whether interval-based asynchronous replication is used</para>
+ </footnote>
+ replicated after every change (if replication is
+ enabled).
+ </para>
+
+ <para>What JBoss Cache does on every incoming call is:</para>
+ <orderedlist>
+ <listitem>
+ <para>Retrieve the current
+ <literal>javax.transaction.Transaction</literal>
+ associated with the thread
+ </para>
+ </listitem>
+ <listitem>
+ <para>If not already done, register a
+ <literal>javax.transaction.Synchronization</literal>
+ with the transaction manager to be notified when a transaction commits
+ or is rolled back.
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ In order to do this, the cache has to be provided with a
+ reference to environment's
+ <literal>javax.transaction.TransactionManager</literal>
+ . This is usually done by configuring the cache
+ with the class name of an implementation of the
+ <literal>TransactionManagerLookup</literal>
+ interface. When the cache starts, it will create an instance of this
+ class and invoke its <literal>getTransactionManager()</literal>
+ method, which returns a reference to the
+ <literal>TransactionManager</literal>
+ .
+ </para>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="TransactionLookup.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>JBoss Cache ships with
+ <literal>JBossTransactionManagerLookup</literal>
+ and
+ <literal>GenericTransactionManagerLookup</literal>
+ . The
+ <literal>JBossTransactionManagerLookup</literal>
+ is able to bind to a running JBoss AS instance and retrieve a
+ <literal>TransactionManager</literal>
+ while the
+ <literal>GenericTransactionManagerLookup</literal>
+ is able to bind to most popular Java EE application servers and provide the same functionality. A dummy
+ implementation -
+ <literal>DummyTransactionManagerLookup</literal>
+ - is also provided, primarily for unit tests. Being a dummy, this is just for demo and testing purposes and is
+ not recommended for production use.
+ </para>
+
+ <para>
+ An alternative to configuring a <literal>TransactionManagerLookup</literal>
+ is to programatically inject a reference to the <literal>TransactionManager</literal>
+ into the <literal>Configuration</literal> object's <literal>RuntimeConfig</literal> element:
+ </para>
+
+ <programlisting>
+ TransactionManager tm = getTransactionManager(); // magic method
+ cache.getConfiguration().getRuntimeConfig().setTransactionManager(tm);
+ </programlisting>
+
+ <para>
+ Injecting the <literal>TransactionManager</literal> is the recommended
+ approach when the <literal>Configuration</literal> is built by some sort of
+ IOC container that already has a reference to the TM.
+ </para>
+
+ <para>When the transaction commits, we initiate either a one- two-phase commit
+ protocol. See
+ <link linkend="replication.tx">replicated caches and transactions</link>
+ for details.
+ </para>
+
+ </section>
+</chapter>
Added: pojo/trunk/src/main/java/org/jboss/cache/MyClass.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/MyClass.java (rev 0)
+++ pojo/trunk/src/main/java/org/jboss/cache/MyClass.java 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,60 @@
+package org.jboss.cache;
+
+import org.jboss.kernel.plugins.bootstrap.standalone.StandaloneBootstrap;
+
+/**
+ * // TODO: Add Javadocs
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
+ * @since 2.0.0
+ */
+public class MyClass
+{
+ private int x, y;
+
+
+ public MyClass()
+ {
+ // some dummy dependency
+ //
+
+ org.jgroups.Address addr = new org.jgroups.stack.IpAddress();
+ }
+
+ public MyClass(int x, int y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+
+ public int getX()
+ {
+ return x;
+ }
+
+ public void setX(int x)
+ {
+ this.x = x;
+ }
+
+ public int getY()
+ {
+ return y;
+ }
+
+ public void setY(int y)
+ {
+ this.y = y;
+ }
+
+ public int add()
+ {
+ return x + y;
+ }
+
+ public int multiply()
+ {
+ return x * y;
+ }
+}
Added: pojo/trunk/src/main/resources/replSync-service.xml
===================================================================
--- pojo/trunk/src/main/resources/replSync-service.xml (rev 0)
+++ pojo/trunk/src/main/resources/replSync-service.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Sample TreeCache Service Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<server>
+
+ <!-- ==================================================================== -->
+ <!-- Defines TreeCache configuration -->
+ <!-- ==================================================================== -->
+
+ <mbean code="org.jboss.cache.jmx.CacheJmxWrapper"
+ name="jboss.cache:service=TreeCache">
+
+ <depends>jboss:service=Naming</depends>
+ <depends>jboss:service=TransactionManager</depends>
+
+ <!--
+ Configure the TransactionManager
+ -->
+ <attribute name="TransactionManagerLookupClass">org.jboss.cache.transaction.GenericTransactionManagerLookup
+ </attribute>
+
+ <!--
+ Isolation level : SERIALIZABLE
+ REPEATABLE_READ (default)
+ READ_COMMITTED
+ READ_UNCOMMITTED
+ NONE
+ -->
+ <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
+
+ <!--
+ Valid modes are LOCAL
+ REPL_ASYNC
+ REPL_SYNC
+ INVALIDATION_ASYNC
+ INVALIDATION_SYNC
+ -->
+ <attribute name="CacheMode">REPL_SYNC</attribute>
+
+ <!--
+ Just used for async repl: use a replication queue
+ -->
+ <attribute name="UseReplQueue">false</attribute>
+
+ <!--
+ Replication interval for replication queue (in ms)
+ -->
+ <attribute name="ReplQueueInterval">0</attribute>
+
+ <!--
+ Max number of elements which trigger replication
+ -->
+ <attribute name="ReplQueueMaxElements">0</attribute>
+
+ <!-- Name of cluster. Needs to be the same for all TreeCache nodes in a
+ cluster in order to find each other.
+ -->
+ <attribute name="ClusterName">JBossCache-Cluster</attribute>
+
+ <!--Uncomment next three statements to enable JGroups multiplexer.
+This configuration is dependent on the JGroups multiplexer being
+registered in an MBean server such as JBossAS. -->
+ <!--
+ <depends>jgroups.mux:name=Multiplexer</depends>
+ <attribute name="MultiplexerService">jgroups.mux:name=Multiplexer</attribute>
+ <attribute name="MultiplexerStack">fc-fast-minimalthreads</attribute>
+ -->
+
+ <!-- JGroups protocol stack properties.
+ ClusterConfig isn't used if the multiplexer is enabled and successfully initialized.
+ -->
+ <attribute name="ClusterConfig">
+ <config>
+ <UDP mcast_addr="228.10.10.10"
+ mcast_port="45588"
+ tos="8"
+ ucast_recv_buf_size="20000000"
+ ucast_send_buf_size="640000"
+ mcast_recv_buf_size="25000000"
+ mcast_send_buf_size="640000"
+ loopback="false"
+ discard_incompatible_packets="true"
+ max_bundle_size="64000"
+ max_bundle_timeout="30"
+ use_incoming_packet_handler="true"
+ ip_ttl="2"
+ enable_bundling="false"
+ enable_diagnostics="true"
+
+ use_concurrent_stack="true"
+
+ thread_naming_pattern="pl"
+
+ thread_pool.enabled="true"
+ thread_pool.min_threads="1"
+ thread_pool.max_threads="25"
+ thread_pool.keep_alive_time="30000"
+ thread_pool.queue_enabled="true"
+ thread_pool.queue_max_size="10"
+ thread_pool.rejection_policy="Run"
+
+ oob_thread_pool.enabled="true"
+ oob_thread_pool.min_threads="1"
+ oob_thread_pool.max_threads="4"
+ oob_thread_pool.keep_alive_time="10000"
+ oob_thread_pool.queue_enabled="true"
+ oob_thread_pool.queue_max_size="10"
+ oob_thread_pool.rejection_policy="Run"/>
+
+ <PING timeout="2000" num_initial_members="3"/>
+ <MERGE2 max_interval="30000" min_interval="10000"/>
+ <FD_SOCK/>
+ <FD timeout="10000" max_tries="5" shun="true"/>
+ <VERIFY_SUSPECT timeout="1500"/>
+ <pbcast.NAKACK max_xmit_size="60000"
+ use_mcast_xmit="false" gc_lag="0"
+ retransmit_timeout="300,600,1200,2400,4800"
+ discard_delivered_msgs="true"/>
+ <UNICAST timeout="300,600,1200,2400,3600"/>
+ <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
+ max_bytes="400000"/>
+ <pbcast.GMS print_local_addr="true" join_timeout="5000"
+ join_retry_timeout="2000" shun="false"
+ view_bundling="true" view_ack_collection_timeout="5000"/>
+ <FRAG2 frag_size="60000"/>
+ <pbcast.STREAMING_STATE_TRANSFER use_reading_thread="true"/>
+ <!-- <pbcast.STATE_TRANSFER/> -->
+ <pbcast.FLUSH timeout="0"/>
+ </config>
+ </attribute>
+
+
+ <!--
+ Whether or not to fetch state on joining a cluster
+ NOTE this used to be called FetchStateOnStartup and has been renamed to be more descriptive.
+ -->
+ <attribute name="FetchInMemoryState">true</attribute>
+
+ <!--
+ The max amount of time (in milliseconds) we wait until the
+ state (ie. the contents of the cache) are retrieved from
+ existing members in a clustered environment
+ -->
+ <attribute name="StateRetrievalTimeout">15000</attribute>
+
+ <!--
+ Number of milliseconds to wait until all responses for a
+ synchronous call have been received.
+ -->
+ <attribute name="SyncReplTimeout">15000</attribute>
+
+ <!-- Max number of milliseconds to wait for a lock acquisition -->
+ <attribute name="LockAcquisitionTimeout">10000</attribute>
+
+ <!--
+ Indicate whether to use region based marshalling or not. Set this to true if you are running under a scoped
+ class loader, e.g., inside an application server. Default is "false".
+ -->
+ <attribute name="UseRegionBasedMarshalling">true</attribute>
+ </mbean>
+
+
+ <!-- Uncomment to get a graphical view of the TreeCache MBean above -->
+ <!-- <mbean code="org.jboss.cache.TreeCacheView" name="jboss.cache:service=TreeCacheView">-->
+ <!-- <depends>jboss.cache:service=TreeCache</depends>-->
+ <!-- <attribute name="CacheService">jboss.cache:service=TreeCache</attribute>-->
+ <!-- </mbean>-->
+
+
+</server>
Added: pojo/trunk/src/test/java/org/jboss/cache/MyClassTest.java
===================================================================
--- pojo/trunk/src/test/java/org/jboss/cache/MyClassTest.java (rev 0)
+++ pojo/trunk/src/test/java/org/jboss/cache/MyClassTest.java 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,48 @@
+package org.jboss.cache;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.AfterClass;
+
+/**
+ * // TODO: Add Javadocs
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
+ * @since 2.0.0
+ */
+@Test
+public class MyClassTest
+{
+ private MyClass mc = null;
+
+ @BeforeTest
+ public void create()
+ {
+ mc = new MyClass();
+ }
+
+ @AfterClass
+ public void destroy()
+ {
+ mc = null;
+ }
+
+ @Test
+ public void multiplication()
+ {
+ mc.setX(5);
+ mc.setY(2);
+
+ assert 10 == mc.multiply();
+ }
+
+ @Test
+ public void addition()
+ {
+ mc.setX(5);
+ mc.setY(2);
+
+ assert 7 == mc.add();
+ }
+
+}
Added: pojo/trunk/src/test/resources/replSync-service-test.xml
===================================================================
--- pojo/trunk/src/test/resources/replSync-service-test.xml (rev 0)
+++ pojo/trunk/src/test/resources/replSync-service-test.xml 2007-08-14 16:26:14 UTC (rev 4247)
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Sample TreeCache Service Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<server>
+
+ <!-- ==================================================================== -->
+ <!-- Defines TreeCache configuration -->
+ <!-- ==================================================================== -->
+
+ <mbean code="org.jboss.cache.jmx.CacheJmxWrapper"
+ name="jboss.cache:service=TreeCache">
+
+ <depends>jboss:service=Naming</depends>
+ <depends>jboss:service=TransactionManager</depends>
+
+ <!--
+ Configure the TransactionManager
+ -->
+ <attribute name="TransactionManagerLookupClass">org.jboss.cache.transaction.GenericTransactionManagerLookup
+ </attribute>
+
+ <!--
+ Isolation level : SERIALIZABLE
+ REPEATABLE_READ (default)
+ READ_COMMITTED
+ READ_UNCOMMITTED
+ NONE
+ -->
+ <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
+
+ <!--
+ Valid modes are LOCAL
+ REPL_ASYNC
+ REPL_SYNC
+ INVALIDATION_ASYNC
+ INVALIDATION_SYNC
+ -->
+ <attribute name="CacheMode">REPL_SYNC</attribute>
+
+ <!--
+ Just used for async repl: use a replication queue
+ -->
+ <attribute name="UseReplQueue">false</attribute>
+
+ <!--
+ Replication interval for replication queue (in ms)
+ -->
+ <attribute name="ReplQueueInterval">0</attribute>
+
+ <!--
+ Max number of elements which trigger replication
+ -->
+ <attribute name="ReplQueueMaxElements">0</attribute>
+
+ <!-- Name of cluster. Needs to be the same for all TreeCache nodes in a
+ cluster in order to find each other.
+ -->
+ <attribute name="ClusterName">JBossCache-Cluster</attribute>
+
+ <!--Uncomment next three statements to enable JGroups multiplexer.
+This configuration is dependent on the JGroups multiplexer being
+registered in an MBean server such as JBossAS. -->
+ <!--
+ <depends>jgroups.mux:name=Multiplexer</depends>
+ <attribute name="MultiplexerService">jgroups.mux:name=Multiplexer</attribute>
+ <attribute name="MultiplexerStack">fc-fast-minimalthreads</attribute>
+ -->
+
+ <!-- JGroups protocol stack properties.
+ ClusterConfig isn't used if the multiplexer is enabled and successfully initialized.
+ -->
+ <attribute name="ClusterConfig">
+ <config>
+ <UDP mcast_addr="228.10.10.10"
+ mcast_port="45588"
+ tos="8"
+ ucast_recv_buf_size="20000000"
+ ucast_send_buf_size="640000"
+ mcast_recv_buf_size="25000000"
+ mcast_send_buf_size="640000"
+ loopback="false"
+ discard_incompatible_packets="true"
+ max_bundle_size="64000"
+ max_bundle_timeout="30"
+ use_incoming_packet_handler="true"
+ ip_ttl="2"
+ enable_bundling="false"
+ enable_diagnostics="true"
+
+ use_concurrent_stack="true"
+
+ thread_naming_pattern="pl"
+
+ thread_pool.enabled="true"
+ thread_pool.min_threads="1"
+ thread_pool.max_threads="25"
+ thread_pool.keep_alive_time="30000"
+ thread_pool.queue_enabled="true"
+ thread_pool.queue_max_size="10"
+ thread_pool.rejection_policy="Run"
+
+ oob_thread_pool.enabled="true"
+ oob_thread_pool.min_threads="1"
+ oob_thread_pool.max_threads="4"
+ oob_thread_pool.keep_alive_time="10000"
+ oob_thread_pool.queue_enabled="true"
+ oob_thread_pool.queue_max_size="10"
+ oob_thread_pool.rejection_policy="Run"/>
+
+ <PING timeout="2000" num_initial_members="3"/>
+ <MERGE2 max_interval="30000" min_interval="10000"/>
+ <FD_SOCK/>
+ <FD timeout="10000" max_tries="5" shun="true"/>
+ <VERIFY_SUSPECT timeout="1500"/>
+ <pbcast.NAKACK max_xmit_size="60000"
+ use_mcast_xmit="false" gc_lag="0"
+ retransmit_timeout="300,600,1200,2400,4800"
+ discard_delivered_msgs="true"/>
+ <UNICAST timeout="300,600,1200,2400,3600"/>
+ <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
+ max_bytes="400000"/>
+ <pbcast.GMS print_local_addr="true" join_timeout="5000"
+ join_retry_timeout="2000" shun="false"
+ view_bundling="true" view_ack_collection_timeout="5000"/>
+ <FRAG2 frag_size="60000"/>
+ <pbcast.STREAMING_STATE_TRANSFER use_reading_thread="true"/>
+ <!-- <pbcast.STATE_TRANSFER/> -->
+ <pbcast.FLUSH timeout="0"/>
+ </config>
+ </attribute>
+
+
+ <!--
+ Whether or not to fetch state on joining a cluster
+ NOTE this used to be called FetchStateOnStartup and has been renamed to be more descriptive.
+ -->
+ <attribute name="FetchInMemoryState">true</attribute>
+
+ <!--
+ The max amount of time (in milliseconds) we wait until the
+ state (ie. the contents of the cache) are retrieved from
+ existing members in a clustered environment
+ -->
+ <attribute name="StateRetrievalTimeout">15000</attribute>
+
+ <!--
+ Number of milliseconds to wait until all responses for a
+ synchronous call have been received.
+ -->
+ <attribute name="SyncReplTimeout">15000</attribute>
+
+ <!-- Max number of milliseconds to wait for a lock acquisition -->
+ <attribute name="LockAcquisitionTimeout">10000</attribute>
+
+ <!--
+ Indicate whether to use region based marshalling or not. Set this to true if you are running under a scoped
+ class loader, e.g., inside an application server. Default is "false".
+ -->
+ <attribute name="UseRegionBasedMarshalling">true</attribute>
+ </mbean>
+
+
+ <!-- Uncomment to get a graphical view of the TreeCache MBean above -->
+ <!-- <mbean code="org.jboss.cache.TreeCacheView" name="jboss.cache:service=TreeCacheView">-->
+ <!-- <depends>jboss.cache:service=TreeCache</depends>-->
+ <!-- <attribute name="CacheService">jboss.cache:service=TreeCache</attribute>-->
+ <!-- </mbean>-->
+
+
+</server>
17 years, 4 months
JBoss Cache SVN: r4246 - in support/trunk: common and 5 other directories.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2007-08-14 12:25:04 -0400 (Tue, 14 Aug 2007)
New Revision: 4246
Added:
support/trunk/common/
support/trunk/common/pom.xml
support/trunk/pom.xml
support/trunk/xslt/
support/trunk/xslt/pom.xml
support/trunk/xslt/src/
support/trunk/xslt/src/main/
support/trunk/xslt/src/main/resources/
support/trunk/xslt/src/main/resources/standard/
support/trunk/xslt/src/main/resources/standard/fopdf.xsl
support/trunk/xslt/src/main/resources/standard/html.xsl
support/trunk/xslt/src/main/resources/standard/html_chunk.xsl
Log:
Added maven support POMs
Added: support/trunk/common/pom.xml
===================================================================
--- support/trunk/common/pom.xml (rev 0)
+++ support/trunk/common/pom.xml 2007-08-14 16:25:04 UTC (rev 4246)
@@ -0,0 +1,309 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.jboss.cache</groupId>
+ <artifactId>jbosscache-support</artifactId>
+ <version>1.0</version>
+ </parent>
+
+ <groupId>org.jboss.cache</groupId>
+ <artifactId>jbosscache-common-parent</artifactId>
+ <packaging>pom</packaging>
+
+ <name>JBoss Cache Common Parent</name>
+ <description>The parent POM for all JBoss Cache modules.</description>
+ <url>http://labs.jboss.org/jbosscache</url>
+
+ <organization>
+ <name>JBoss, a division of Red Hat</name>
+ <url>http://labs.jboss.org</url>
+ </organization>
+
+ <licenses>
+ <license>
+ <name>GNU Lesser General Public License</name>
+ <url>http://www.gnu.org/copyleft/lesser.html</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+
+ <scm>
+ <connection>scm:svn:http://anonsvn.jboss.org/repos/jbosscache/core/trunk/</connection>
+ <developerConnection>scm:svn:https://svn.jboss.org/repos/jbosscache/core/trunk</developerConnection>
+ <url>http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbosscache/</url>
+ </scm>
+
+ <issueManagement>
+ <system>jira</system>
+ <url>http://jira.jboss.com/jira/browse/JBCACHE</url>
+ </issueManagement>
+
+ <ciManagement>
+ <system>cruisecontrol</system>
+ <url>http://cruisecontrol.jboss.com/cc/</url>
+ <notifiers>
+ <notifier>
+ <type>mail</type>
+ <address>jbosscache-dev(a)lists.jboss.org</address>
+ </notifier>
+ </notifiers>
+ </ciManagement>
+
+ <mailingLists>
+ <mailingList>
+ <name>JBoss Cache Announcements</name>
+ <post>jbosscache-announce(a)lists.jboss.org</post>
+ <subscribe>https://lists.jboss.org/mailman/listinfo/jbosscache-announce</subscribe>
+ <unsubscribe>https://lists.jboss.org/mailman/listinfo/jbosscache-announce</unsubscribe>
+ <archive>http://lists.jboss.org/pipermail/jbosscache-dev/</archive>
+ </mailingList>
+ <mailingList>
+ <name>JBoss Cache Commit Notificatons</name>
+ <post>jbosscache-commits(a)lists.jboss.org</post>
+ <subscribe>https://lists.jboss.org/mailman/listinfo/jbosscache-commits</subscribe>
+ <unsubscribe>https://lists.jboss.org/mailman/listinfo/jbosscache-commits</unsubscribe>
+ <archive>http://lists.jboss.org/pipermail/jbosscache-commits/</archive>
+ </mailingList>
+ <mailingList>
+ <name>JBoss Cache Developers</name>
+ <post>jbosscache-dev(a)lists.jboss.org</post>
+ <subscribe>https://lists.jboss.org/mailman/listinfo/jbosscache-dev</subscribe>
+ <unsubscribe>https://lists.jboss.org/mailman/listinfo/jbosscache-dev</unsubscribe>
+ <archive>http://lists.jboss.org/pipermail/jbosscache-dev/</archive>
+ </mailingList>
+ <mailingList>
+ <name>JBoss Cache Issue Notifications</name>
+ <post>jbosscache-issues(a)lists.jboss.org</post>
+ <subscribe>https://lists.jboss.org/mailman/listinfo/jbosscache-issues</subscribe>
+ <unsubscribe>https://lists.jboss.org/mailman/listinfo/jbosscache-issues</unsubscribe>
+ <archive>http://lists.jboss.org/pipermail/jbosscache-issues/</archive>
+ </mailingList>
+ </mailingLists>
+
+ <build>
+ <plugins>
+ <!-- require at least JDK 1.5 to run the build -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <version>1.0-alpha-3</version>
+ <executions>
+ <execution>
+ <id>enforce-java</id>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ <configuration>
+ <rules>
+ <requireJavaVersion>
+ <version>[1.5,)</version>
+ </requireJavaVersion>
+ </rules>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- by default, compile to JDK 1.5 compatibility (individual modules and/or user can override) -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.0.2</version>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+
+ <!-- add specification/implementation details to the manifests -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifest>
+ <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
+ <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+ </manifest>
+ </archive>
+ </configuration>
+ </plugin>
+
+ <!-- we need the 2.4-collab-SNAPSHOT version of surefire to work with the latest TestNG -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.4-collab-SNAPSHOT</version>
+ <!--
+ <configuration>
+ <groups>functest,util</groups>
+ </configuration>
+ -->
+ </plugin>
+
+ <!-- javadocs : we want these run in the 'package' lifecycle phase-->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>javadoc</goal>
+ </goals>
+ <configuration>
+ <aggregate>${jbosscache.reports.aggregate}</aggregate>
+ <links>
+ <link>http://java.sun.com/j2se/1.5.0/docs/api/</link>
+ <link>http://java.sun.com/javaee/5/docs/api/</link>
+ </links>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+
+ <finalName>${artifactId}</finalName>
+ </build>
+
+ <reporting>
+ <plugins>
+ <!-- unit test reports -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ <version>2.4-collab-SNAPSHOT</version>
+ <!--
+ <configuration>
+ <groups>functest,util</groups>
+ </configuration>
+ -->
+ </plugin>
+
+ <!-- javadocs -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <aggregate>${jbosscache.reports.aggregate}</aggregate>
+ <links>
+ <link>http://java.sun.com/j2se/1.5.0/docs/api/</link>
+ <link>http://java.sun.com/javaee/5/docs/api/</link>
+ </links>
+ </configuration>
+ </plugin>
+
+ <!-- JXR - links from javadocs and junit reports to an html representation of the code -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jxr-plugin</artifactId>
+ <configuration>
+ <aggregate>${jbosscache.reports.aggregate}</aggregate>
+ </configuration>
+ </plugin>
+
+ <!-- PMD code analysis reports -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-pmd-plugin</artifactId>
+ <configuration>
+ <aggregate>${jbosscache.reports.aggregate}</aggregate>
+ <linkXref>true</linkXref>
+ <minimumTokens>100</minimumTokens>
+ <targetJdk>1.4</targetJdk>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>taglist-maven-plugin</artifactId>
+ <configuration>
+ <aggregate>${jbosscache.reports.aggregate}</aggregate>
+ <tags>
+ <tag>@FIXME</tag>
+ <tag>@fixme</tag>
+ <tag>FIXME</tag>
+ <tag>fixme</tag>
+ <tag>@TODO</tag>
+ <tag>@todo</tag>
+ <tag>TODO</tag>
+ <tag>todo</tag>
+ </tags>
+ </configuration>
+ </plugin>
+ <plugin>
+ <!-- Note: aggregate-able, may cause problems if we aggregate jxr and not this because of the xref links -->
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>javancss-maven-plugin</artifactId>
+ </plugin>
+
+ <!-- Findbugs report -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>findbugs-maven-plugin</artifactId>
+ <configuration>
+ <onlyAnalyze>org.jboss.cache.*</onlyAnalyze>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+
+ <properties>
+ <!-- for now, at least, lets aggregate them -->
+ <jbosscache.reports.aggregate>true</jbosscache.reports.aggregate>
+ </properties>
+
+ <repositories>
+ <repository>
+ <id>repository.jboss.org</id>
+ <url>http://repository.jboss.org/maven2</url>
+ </repository>
+
+ <repository>
+ <id>snapshots.jboss.org</id>
+ <url>http://snapshots.jboss.org/maven2</url>
+ </repository>
+ </repositories>
+
+ <pluginRepositories>
+
+ <pluginRepository>
+ <id>apache.snapshots</id>
+ <url>http://people.apache.org/repo/m2-snapshot-repository/</url>
+ </pluginRepository>
+
+ <pluginRepository>
+ <id>repository.jboss.org</id>
+ <url>http://repository.jboss.org/maven2</url>
+ </pluginRepository>
+
+ <pluginRepository>
+ <id>snapshots.jboss.org</id>
+ <url>http://snapshots.jboss.org/maven2</url>
+ </pluginRepository>
+
+ </pluginRepositories>
+
+ <dependencies>
+ <!-- test dependencies to run the test suites -->
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>5.5</version>
+ <scope>test</scope>
+ <classifier>jdk15</classifier>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ <version>10.2.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
Added: support/trunk/pom.xml
===================================================================
--- support/trunk/pom.xml (rev 0)
+++ support/trunk/pom.xml 2007-08-14 16:25:04 UTC (rev 4246)
@@ -0,0 +1,44 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.jboss.cache</groupId>
+ <artifactId>jbosscache-support</artifactId>
+ <version>1.0</version>
+ <packaging>pom</packaging>
+
+ <name>JBoss Cache Support Modules</name>
+ <description>Grouping of JBoss Cache support modules</description>
+
+ <modules>
+ <module>xslt</module>
+ <module>common</module>
+ </modules>
+
+ <build>
+ <!-- WebDAV plugin to upload snapshots -->
+ <extensions>
+ <extension>
+ <groupId>org.apache.maven.wagon</groupId>
+ <artifactId>wagon-webdav</artifactId>
+ <version>1.0-beta-2</version>
+ </extension>
+ </extensions>
+ </build>
+
+ <distributionManagement>
+ <repository>
+ <id>repository.jboss.org</id>
+ <name>JBoss Repository</name>
+ <url>dav:https://repository.jboss.org/maven2</url>
+ </repository>
+ <snapshotRepository>
+ <id>snapshots.jboss.org</id>
+ <name>JBoss Snapshot Repository</name>
+ <url>dav:https://snapshots.jboss.org/maven2</url>
+ </snapshotRepository>
+ </distributionManagement>
+
+</project>
Added: support/trunk/xslt/pom.xml
===================================================================
--- support/trunk/xslt/pom.xml (rev 0)
+++ support/trunk/xslt/pom.xml 2007-08-14 16:25:04 UTC (rev 4246)
@@ -0,0 +1,17 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.jboss.cache</groupId>
+ <artifactId>jbosscache-support</artifactId>
+ <version>1.0</version>
+ </parent>
+
+ <groupId>org.jboss.cache</groupId>
+ <artifactId>jbosscache-doc-xslt-support</artifactId>
+ <name>JBoss Cache Documentation XSLT support</name>
+ <description>JBoss Cache Documentation XSLT support</description>
+
+</project>
Added: support/trunk/xslt/src/main/resources/standard/fopdf.xsl
===================================================================
--- support/trunk/xslt/src/main/resources/standard/fopdf.xsl (rev 0)
+++ support/trunk/xslt/src/main/resources/standard/fopdf.xsl 2007-08-14 16:25:04 UTC (rev 4246)
@@ -0,0 +1,568 @@
+<?xml version="1.0"?>
+
+<!--
+ This was originally the XSL FO configuration file for the Hibernate
+ Reference Documentation. It defines a custom titlepage and
+ the parameters for the A4 sized PDF printable output. It is released
+ under the LGPL.
+
+ Modifications were made to better suit the needs of the JBoss documentation.
+-->
+
+<!DOCTYPE xsl:stylesheet>
+
+<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/TR/xhtml1/transitional"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format" exclude-result-prefixes="#default">
+
+
+ <!-- import the main docbook.xsl before we apply our overrides -->
+ <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl" />
+
+
+ <!-- ########## XRef -->
+ <!-- this controls whether xrefs have the title in it. We
+don't want that -->
+ <xsl:param name="xref.with.number.and.title" select="0"/>
+
+ <xsl:template match="processing-instruction('lb')">
+ <fo:block>
+ <xsl:text></xsl:text>
+ </fo:block>
+ </xsl:template>
+
+ <!--########## Custom Title Page -->
+ <xsl:template name="book.titlepage.recto">
+ <fo:block>
+ <fo:table table-layout="fixed" width="175mm">
+ <fo:table-column column-width="175mm"/>
+ <fo:table-body>
+ <fo:table-row>
+ <fo:table-cell text-align="center">
+ <xsl:if test="bookinfo/mediaobject">
+ <fo:block>
+ <fo:external-graphic>
+ <xsl:attribute name="src">
+ FILE:
+ <xsl:value-of
+ select="bookinfo/mediaobject/imageobject/imagedata/@fileref"/>
+ </xsl:attribute>
+ </fo:external-graphic>
+ </fo:block>
+ </xsl:if>
+ <xsl:if test="bookinfo/title">
+ <fo:block font-family="Helvetica" font-size="26pt" padding-before="10mm" text-align="left"
+ font-weight="bold">
+ <xsl:value-of select="bookinfo/title"/>
+ </fo:block>
+ </xsl:if>
+ <xsl:if test="bookinfo/subtitle">
+ <fo:block font-family="Helvetica" font-size="20pt" padding-before="10mm" text-align="left">
+ <xsl:value-of select="bookinfo/subtitle"/>
+ </fo:block>
+ </xsl:if>
+ <xsl:if test="bookinfo/releaseinfo">
+ <fo:block font-family="Helvetica" font-size="10pt" text-align="left" padding-before="30mm">
+ <xsl:value-of select="bookinfo/releaseinfo"/>
+ </fo:block>
+ </xsl:if>
+ <xsl:if test="bookinfo/pubdate">
+ <fo:block font-family="Helvetica" font-size="10pt" text-align="left">
+ <xsl:value-of select="bookinfo/pubdate"/>
+ </fo:block>
+ </xsl:if>
+
+
+ <xsl:if test="bookinfo/author">
+ <fo:block font-family="Helvetica" font-size="10pt" padding="2mm" text-align="left"
+ font-weight="bold" padding-before="20mm">
+ <xsl:text>Authors:</xsl:text>
+ </fo:block>
+ <xsl:for-each select="bookinfo/author">
+ <fo:block font-family="Helvetica" font-size="10pt" padding="2mm" text-align="left">
+ <xsl:if test="firstname">
+ <xsl:value-of select="firstname"/>
+ <xsl:if test="surname">
+ <xsl:text></xsl:text>
+ </xsl:if>
+ </xsl:if>
+ <xsl:if test="surname">
+ <xsl:value-of select="surname"/>
+ </xsl:if>
+ <xsl:if test="email">
+ <xsl:text>(</xsl:text>
+ <xsl:value-of select="email"/>
+ <xsl:text>)</xsl:text>
+ </xsl:if>
+ </fo:block>
+ </xsl:for-each>
+ </xsl:if>
+
+
+ <xsl:if test="bookinfo/copyright">
+ <fo:block font-family="Helvetica" font-size="8pt" padding="10mm" padding-before="20mm">
+
+ <xsl:apply-templates select="bookinfo/copyright" mode="titlepage.mode"/>
+ </fo:block>
+ </xsl:if>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-body>
+ </fo:table>
+ </fo:block>
+ </xsl:template>
+
+ <!-- Prevent blank pages in output -->
+ <xsl:template name="book.titlepage.before.verso"/>
+ <xsl:template name="book.titlepage.verso"/>
+ <xsl:template name="book.titlepage.separator"/>
+
+
+ <!--###################################################
+ Header
+ ################################################### -->
+ <!-- More space in the center header for long text -->
+ <xsl:attribute-set name="header.content.properties">
+ <xsl:attribute name="font-family">
+ <xsl:value-of select="$body.font.family"/>
+ </xsl:attribute>
+ <xsl:attribute name="margin-left">-5em</xsl:attribute>
+ <xsl:attribute name="margin-right">-5em</xsl:attribute>
+ </xsl:attribute-set>
+
+
+ <!--###################################################
+ Custom Footer
+ ################################################### -->
+ <!-- This footer prints the Hibernate version number on the left side -->
+ <xsl:template name="footer.content">
+ <xsl:param name="pageclass" select="''"/>
+ <xsl:param name="sequence" select="''"/>
+ <xsl:param name="position" select="''"/>
+ <xsl:param name="gentext-key" select="''"/>
+ <xsl:variable name="Version">
+ <xsl:choose>
+ <xsl:when test="//releaseinfo">
+ <xsl:value-of select="//releaseinfo"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- nop -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="$sequence='blank'">
+ <xsl:choose>
+ <xsl:when test="$double.sided != 0 and $position = 'left'">
+ <xsl:value-of select="$Version"/>
+ </xsl:when>
+ <xsl:when test="$double.sided = 0 and $position = 'center'">
+ <!-- nop -->
+ </xsl:when>
+ <xsl:otherwise>
+ <fo:page-number/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:when test="$pageclass='titlepage'">
+ <!-- nop: other titlepage sequences have no footer -->
+ </xsl:when>
+ <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='left'">
+ <fo:page-number/>
+ </xsl:when>
+ <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='right'">
+ <fo:page-number/>
+ </xsl:when>
+ <xsl:when test="$double.sided = 0 and $position='right'">
+ <fo:page-number/>
+ </xsl:when>
+ <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='left'">
+ <xsl:value-of select="$Version"/>
+ </xsl:when>
+ <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='right'">
+ <xsl:value-of select="$Version"/>
+ </xsl:when>
+ <xsl:when test="$double.sided = 0 and $position='left'">
+ <xsl:value-of select="$Version"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- nop -->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+
+ <!--###################################################
+ Custom Toc Line
+ ################################################### -->
+ <!-- Improve the TOC. -->
+ <xsl:template name="toc.trt">
+ <xsl:variable name="id">
+ <xsl:call-template name="object.id"/>
+ </xsl:variable>
+ <xsl:variable name="label">
+ <xsl:apply-templates select="." mode="label.markup"/>
+ </xsl:variable>
+ <fo:block text-align-last="justify" end-indent="{$toc.indent.width}pt"
+ last-line-end-indent="-{$toc.indent.width}pt">
+ <fo:inline keep-with-next.within-line="always">
+ <fo:basic-link internal-destination="{$id}">
+ <!-- Chapter titles should be bold. -->
+ <xsl:choose>
+ <xsl:when test="local-name(.) = 'chapter'">
+ <xsl:attribute name="font-weight">bold</xsl:attribute>
+ </xsl:when>
+ </xsl:choose>
+ <xsl:if test="$label != ''">
+ <xsl:copy-of select="$label"/>
+ <xsl:value-of select="$autotoc.label.separator"/>
+ </xsl:if>
+ <xsl:apply-templates select="." mode="titleabbrev.markup"/>
+ </fo:basic-link>
+ </fo:inline>
+ <fo:inline keep-together.within-line="always">
+ <xsl:text/>
+ <fo:leader leader-pattern="dots" leader-pattern-width="3pt"
+ leader-alignment="reference-area" keep-with-next.within-line="always"/>
+ <xsl:text/>
+ <fo:basic-link internal-destination="{$id}">
+ <fo:page-number-citation ref-id="{$id}"/>
+ </fo:basic-link>
+ </fo:inline>
+ </fo:block>
+ </xsl:template>
+
+
+ <!--###################################################
+ Extensions
+ ################################################### -->
+ <!-- These extensions are required for table printing and other stuff -->
+ <xsl:param name="use.extensions">1</xsl:param>
+
+ <xsl:param name="linenumbering.extension">1</xsl:param>
+ <xsl:param name="linenumbering.everyNth">1</xsl:param>
+ <xsl:param name="linenumbering.separator">:</xsl:param>
+
+ <xsl:param name="tablecolumns.extension">0</xsl:param>
+ <!-- FOP provide only PDF Bookmarks at the moment -->
+ <xsl:param name="fop.extensions">1</xsl:param>
+
+
+ <!--###################################################
+ Table Of Contents
+ ################################################### -->
+ <!-- Generate the TOCs for named components only -->
+ <xsl:param name="generate.toc">book toc,title</xsl:param>
+ <!-- ,figure,table,equation -->
+ <!-- Show only Sections up to level 3 in the TOCs -->
+ <xsl:param name="toc.section.depth">3</xsl:param>
+ <!-- Dot and Whitespace as separator in TOC between Label and Title-->
+ <xsl:param name="autotoc.label.separator" select="'. '"/>
+
+
+ <!--###################################################
+ Paper & Page Size
+ ################################################### -->
+ <!-- Paper type, no headers on blank pages, no double sided printing -->
+ <!-- <xsl:param name="paper.type" select="'A4'"/>-->
+ <xsl:param name="double.sided">0</xsl:param>
+ <xsl:param name="headers.on.blank.pages">0</xsl:param>
+ <xsl:param name="footers.on.blank.pages">0</xsl:param>
+ <!-- Space between paper border and content (chaotic stuff, don't touch) -->
+ <xsl:param name="page.margin.top">5mm</xsl:param>
+ <xsl:param name="region.before.extent">10mm</xsl:param>
+ <xsl:param name="body.margin.top">10mm</xsl:param>
+ <xsl:param name="body.margin.bottom">15mm</xsl:param>
+ <xsl:param name="region.after.extent">10mm</xsl:param>
+ <xsl:param name="page.margin.bottom">0mm</xsl:param>
+ <xsl:param name="page.margin.outer">18mm</xsl:param>
+ <xsl:param name="page.margin.inner">18mm</xsl:param>
+ <!-- No intendation of Titles -->
+ <xsl:param name="title.margin.left">0pc</xsl:param>
+
+
+ <!--###################################################
+ Fonts & Styles
+ ################################################### -->
+ <!-- Default Font size -->
+ <xsl:param name="body.font.master">11</xsl:param>
+ <!-- Line height in body text -->
+ <xsl:param name="line-height">1.4</xsl:param>
+ <!-- Monospaced fonts are smaller than regular text -->
+ <xsl:attribute-set name="monospace.properties">
+ <xsl:attribute name="font-family">
+ <xsl:value-of select="$monospace.font.family"/>
+ </xsl:attribute>
+ <xsl:attribute name="font-size">0.8em</xsl:attribute>
+ </xsl:attribute-set>
+
+
+ <!--###################################################
+ Tables
+ ################################################### -->
+ <!-- The table width should be adapted to the paper size -->
+ <xsl:param name="default.table.width">17.4cm</xsl:param>
+ <!-- Some padding inside tables -->
+ <xsl:attribute-set name="table.cell.padding">
+ <xsl:attribute name="padding-left">4pt</xsl:attribute>
+ <xsl:attribute name="padding-right">4pt</xsl:attribute>
+ <xsl:attribute name="padding-top">4pt</xsl:attribute>
+ <xsl:attribute name="padding-bottom">4pt</xsl:attribute>
+ </xsl:attribute-set>
+ <!-- Only hairlines as frame and cell borders in tables -->
+ <xsl:param name="table.frame.border.thickness">0.1pt</xsl:param>
+ <xsl:param name="table.cell.border.thickness">0.1pt</xsl:param>
+
+
+ <!--###################################################
+ Labels
+ ################################################### -->
+ <!-- Label Chapters and Sections (numbering) -->
+ <xsl:param name="chapter.autolabel">1</xsl:param>
+ <xsl:param name="section.autolabel" select="1"/>
+ <xsl:param name="section.label.includes.component.label" select="1"/>
+
+
+ <!--###################################################
+ Titles
+ ################################################### -->
+
+ <xsl:attribute-set name="chapter.titlepage.recto.style">
+ <xsl:attribute name="text-align">right</xsl:attribute>
+ <xsl:attribute name="font-weight">bold</xsl:attribute>
+ <xsl:attribute name="font-size">
+ <xsl:value-of select="$body.font.master * 1.8"/>
+ <xsl:text>pt</xsl:text>
+ </xsl:attribute>
+ </xsl:attribute-set>
+
+
+ <xsl:attribute-set name="appendix.titlepage.recto.style">
+ <xsl:attribute name="text-align">right</xsl:attribute>
+ <xsl:attribute name="font-weight">bold</xsl:attribute>
+ <xsl:attribute name="font-size">
+ <xsl:value-of select="$body.font.master * 1.8"/>
+ <xsl:text>pt</xsl:text>
+ </xsl:attribute>
+ </xsl:attribute-set>
+
+ <xsl:template name="appendix.titlepage.before.recto">
+ <xsl:param name="node" select="ancestor-or-self::appendix[1]"/>
+ <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ text-align="right"
+ font-size="72pt" font-weight="bold">
+ <xsl:number from="book" format="A"/>
+ </fo:block>
+ </xsl:template>
+
+ <xsl:template name="chapter.titlepage.before.recto">
+ <xsl:param name="node" select="ancestor-or-self::chapter[1]"/>
+ <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ text-align="right"
+ font-size="72pt" font-weight="bold">
+ <xsl:number from="book" format="1"/>
+ </fo:block>
+ </xsl:template>
+
+ <xsl:template match="title" mode="appendix.titlepage.recto.auto.mode">
+ <xsl:variable name="titleabbrev">
+ <xsl:apply-templates select="ancestor-or-self::appendix[1]"
+ mode="titleabbrev.markup"/>
+ </xsl:variable>
+
+ <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ xsl:use-attribute-sets="appendix.titlepage.recto.style">
+ <xsl:value-of select="$titleabbrev"/>
+ </fo:block>
+ </xsl:template>
+
+ <xsl:template match="title" mode="chapter.titlepage.recto.auto.mode">
+ <xsl:variable name="titleabbrev">
+ <xsl:apply-templates select="ancestor-or-self::chapter[1]"
+ mode="titleabbrev.markup"/>
+ </xsl:variable>
+
+ <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ xsl:use-attribute-sets="chapter.titlepage.recto.style">
+ <xsl:value-of select="$titleabbrev"/>
+ </fo:block>
+ </xsl:template>
+
+
+ <!-- Sections 1, 2 and 3 titles have a small bump factor and padding -->
+ <xsl:attribute-set name="section.title.level1.properties">
+ <xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
+ <xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
+ <xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
+ <xsl:attribute name="font-size">
+ <xsl:value-of select="$body.font.master * 1.5"/>
+ <xsl:text>pt</xsl:text>
+ </xsl:attribute>
+ <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+ <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+ <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+ </xsl:attribute-set>
+ <xsl:attribute-set name="section.title.level2.properties">
+ <xsl:attribute name="space-before.optimum">0.6em</xsl:attribute>
+ <xsl:attribute name="space-before.minimum">0.6em</xsl:attribute>
+ <xsl:attribute name="space-before.maximum">0.6em</xsl:attribute>
+ <xsl:attribute name="font-size">
+ <xsl:value-of select="$body.font.master * 1.25"/>
+ <xsl:text>pt</xsl:text>
+ </xsl:attribute>
+ <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+ <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+ <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+ </xsl:attribute-set>
+ <xsl:attribute-set name="section.title.level3.properties">
+ <xsl:attribute name="space-before.optimum">0.4em</xsl:attribute>
+ <xsl:attribute name="space-before.minimum">0.4em</xsl:attribute>
+ <xsl:attribute name="space-before.maximum">0.4em</xsl:attribute>
+ <xsl:attribute name="font-size">
+ <xsl:value-of select="$body.font.master * 1.0"/>
+ <xsl:text>pt</xsl:text>
+ </xsl:attribute>
+ <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+ <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+ <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+ </xsl:attribute-set>
+
+ <!-- Titles of formal objects (tables, examples, ...) -->
+ <xsl:attribute-set name="formal.title.properties"
+ use-attribute-sets="normal.para.spacing">
+ <xsl:attribute name="font-weight">bold</xsl:attribute>
+ <xsl:attribute name="font-size">
+ <xsl:value-of select="$body.font.master"/>
+ <xsl:text>pt</xsl:text>
+ </xsl:attribute>
+ <xsl:attribute name="hyphenate">false</xsl:attribute>
+ <xsl:attribute name="space-after.minimum">0.4em</xsl:attribute>
+ <xsl:attribute name="space-after.optimum">0.6em</xsl:attribute>
+ <xsl:attribute name="space-after.maximum">0.8em</xsl:attribute>
+ </xsl:attribute-set>
+
+
+ <!-- ########## blockquote -->
+ <xsl:attribute-set name="blockquote.properties">
+ <xsl:attribute name="space-before.minimum">1em</xsl:attribute>
+ <xsl:attribute name="space-before.optimum">1em</xsl:attribute>
+ <xsl:attribute name="space-before.maximum">1em</xsl:attribute>
+ <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+ <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+ <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+ <xsl:attribute name="border-color">#444444</xsl:attribute>
+ <xsl:attribute name="border-style">solid</xsl:attribute>
+ <xsl:attribute name="border-width">0.1pt</xsl:attribute>
+ <xsl:attribute name="padding-top">0.5em</xsl:attribute>
+ <xsl:attribute name="padding-left">0.5em</xsl:attribute>
+ <xsl:attribute name="padding-right">0.5em</xsl:attribute>
+ <xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
+ <xsl:attribute name="margin-left">0.5em</xsl:attribute>
+ <xsl:attribute name="margin-right">0.5em</xsl:attribute>
+ <xsl:attribute name="background-color">#F0F0F0</xsl:attribute>
+ </xsl:attribute-set>
+
+
+ <!--###################################################
+ Programlistings
+ ################################################### -->
+ <!-- Verbatim text formatting (programlistings) -->
+ <xsl:attribute-set name="verbatim.properties">
+ <xsl:attribute name="space-before.minimum">1em</xsl:attribute>
+ <xsl:attribute name="space-before.optimum">1em</xsl:attribute>
+ <xsl:attribute name="space-before.maximum">1em</xsl:attribute>
+ <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+ <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+ <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+ <xsl:attribute name="border-color">#444444</xsl:attribute>
+ <xsl:attribute name="border-style">solid</xsl:attribute>
+ <xsl:attribute name="border-width">0.1pt</xsl:attribute>
+ <xsl:attribute name="padding-top">0.5em</xsl:attribute>
+ <xsl:attribute name="padding-left">0.5em</xsl:attribute>
+ <xsl:attribute name="padding-right">0.5em</xsl:attribute>
+ <xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
+ <xsl:attribute name="margin-left">0.5em</xsl:attribute>
+ <xsl:attribute name="margin-right">0.5em</xsl:attribute>
+ </xsl:attribute-set>
+ <!-- Shade (background) programlistings -->
+ <xsl:param name="shade.verbatim">1</xsl:param>
+ <xsl:attribute-set name="shade.verbatim.style">
+ <xsl:attribute name="background-color">#F0F0F0</xsl:attribute>
+ </xsl:attribute-set>
+
+
+ <!--###################################################
+ Callouts
+ ################################################### -->
+ <!-- We want to use callouts... -->
+ <xsl:param name="callout.extensions">1</xsl:param>
+ <!-- Place callout bullets at this column in programmlisting.-->
+ <xsl:param name="callout.defaultcolumn">90</xsl:param>
+ <!--
+ No, don't use crappy graphics for the callout bullets. This setting
+ enables some weird Unicode rendering for some fancy bullet points
+ in callouts. By default, this can only count to 10 and produces
+ strange results if you ever have more than 10 callouts for one
+ programlisting. We will fix that next.
+ -->
+ <xsl:param name="callout.graphics">0</xsl:param>
+ <!--
+ Again, fun with DocBook XSL: The callout bullets are rendered in
+ two places: In the programlisting itself and in the list below
+ the listing, with the actual callout text. The rendering in the
+ programlisting is some XSL transformer extension (e.g. a Saxon
+ extension), so we can't change that without messing with the
+ extensions. We only can turn it off by setting this limit to
+ zero, then, a simple bracket style like "(3)" and "(4)" will
+ be used in the programlisting.
+ -->
+ <xsl:param name="callout.unicode.number.limit" select="'0'"/>
+ <!--
+ The callout bullets in the actual callout list will be rendered
+ with an XSL FO template. The default template is broken: limited to 10
+ nice looking Unicode bullet points and then it doesn't print anything,
+ the fallback doesn't work. We implement our own template, which is not
+ as complicated, more ugly, but works. As always, function is more
+ important than form.
+ -->
+ <xsl:template name="callout-bug">
+ <xsl:param name="conum" select="1"/>
+ <fo:inline color="black" padding-top="0.1em" padding-bottom="0.1em"
+ padding-start="0.2em" padding-end="0.2em" baseline-shift="0.1em"
+ font-family="{$monospace.font.family}" font-weight="bold" font-size="75%">
+ <xsl:text>(</xsl:text>
+ <xsl:value-of select="$conum"/>
+ <xsl:text>)</xsl:text>
+ </fo:inline>
+ </xsl:template>
+
+
+ <!--###################################################
+ Misc
+ ################################################### -->
+ <!-- Correct placement of titles for figures and examples. -->
+ <xsl:param name="formal.title.placement">figure after example before
+ equation before table before procedure before
+ </xsl:param>
+ <!-- Format Variable Lists as Blocks (prevents horizontal overflow). -->
+ <xsl:param name="variablelist.as.blocks">1</xsl:param>
+ <!-- The horrible list spacing problems, this is much better. -->
+ <xsl:attribute-set name="list.block.spacing">
+ <xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
+ <xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
+ <xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
+ <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+ <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+ <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+ </xsl:attribute-set>
+ <!-- Newer DocBook XSL apparently thinks that some sections are by
+ default "draft" status, and this idiotic thing is by default
+ also set to "maybe", so it spits out a lot of errors with the
+ latest FOP as the XSL/FO styles have references to some draft
+ watermarks, which you actually don't want in the first place.
+ Turn this crap off. If you have to work with the "status"
+ attribute, don't.
+ -->
+ <xsl:param name="draft.mode" select="'no'"/>
+
+</xsl:stylesheet>
Added: support/trunk/xslt/src/main/resources/standard/html.xsl
===================================================================
--- support/trunk/xslt/src/main/resources/standard/html.xsl (rev 0)
+++ support/trunk/xslt/src/main/resources/standard/html.xsl 2007-08-14 16:25:04 UTC (rev 4246)
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+
+<!--
+
+ This is the XSL HTML configuration file for the Hibernate
+ Reference Documentation.
+
+ It took me days to figure out this stuff and fix most of
+ the obvious bugs in the DocBook XSL distribution. Some of
+ the workarounds might not be appropriate with a newer version
+ of DocBook XSL. This file is released as part of Hibernate,
+ hence LGPL licensed.
+
+ christian(a)hibernate.org
+-->
+
+<!DOCTYPE xsl:stylesheet>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0"
+ xmlns="http://www.w3.org/TR/xhtml1/transitional"
+ exclude-result-prefixes="#default">
+
+ <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl" />
+
+ <!--###################################################
+ HTML Settings
+ ################################################### -->
+
+ <xsl:param name="html.stylesheet">html.css</xsl:param>
+
+ <!-- These extensions are required for table printing and other stuff -->
+ <xsl:param name="use.extensions">1</xsl:param>
+ <xsl:param name="tablecolumns.extension">0</xsl:param>
+ <xsl:param name="callout.extensions">1</xsl:param>
+ <xsl:param name="graphicsize.extension">0</xsl:param>
+
+ <!--###################################################
+ Table Of Contents
+ ################################################### -->
+
+ <!-- Generate the TOCs for named components only -->
+ <xsl:param name="generate.toc">
+ book toc
+ </xsl:param>
+
+ <!-- Show only Sections up to level 3 in the TOCs -->
+ <xsl:param name="toc.section.depth">3</xsl:param>
+
+ <!--###################################################
+ Labels
+ ################################################### -->
+
+ <!-- Label Chapters and Sections (numbering) -->
+ <xsl:param name="chapter.autolabel">1</xsl:param>
+ <xsl:param name="section.autolabel" select="1"/>
+ <xsl:param name="section.label.includes.component.label" select="1"/>
+
+ <!--###################################################
+ Callouts
+ ################################################### -->
+
+ <!-- Don't use graphics, use a simple number style -->
+ <xsl:param name="callout.graphics">0</xsl:param>
+
+ <!-- Place callout marks at this column in annotated areas -->
+ <xsl:param name="callout.defaultcolumn">90</xsl:param>
+
+ <!--###################################################
+ Misc
+ ################################################### -->
+
+ <!-- Placement of titles -->
+ <xsl:param name="formal.title.placement">
+ figure after
+ example before
+ equation before
+ table before
+ procedure before
+ </xsl:param>
+
+</xsl:stylesheet>
Added: support/trunk/xslt/src/main/resources/standard/html_chunk.xsl
===================================================================
--- support/trunk/xslt/src/main/resources/standard/html_chunk.xsl (rev 0)
+++ support/trunk/xslt/src/main/resources/standard/html_chunk.xsl 2007-08-14 16:25:04 UTC (rev 4246)
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+
+<!--
+
+ This is the XSL HTML configuration file for the Hibernate
+ Reference Documentation.
+
+ It took me days to figure out this stuff and fix most of
+ the obvious bugs in the DocBook XSL distribution. Some of
+ the workarounds might not be appropriate with a newer version
+ of DocBook XSL. This file is released as part of Hibernate,
+ hence LGPL licensed.
+
+ christian(a)hibernate.org
+-->
+
+<!DOCTYPE xsl:stylesheet>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0"
+ xmlns="http://www.w3.org/TR/xhtml1/transitional"
+ exclude-result-prefixes="#default">
+
+ <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl" />
+
+ <!--###################################################
+ HTML Settings
+ ################################################### -->
+
+ <xsl:param name="chunk.section.depth">'5'</xsl:param>
+ <xsl:param name="use.id.as.filename">'1'</xsl:param>
+ <xsl:param name="html.stylesheet">html.css</xsl:param>
+
+ <!-- These extensions are required for table printing and other stuff -->
+ <xsl:param name="use.extensions">1</xsl:param>
+ <xsl:param name="tablecolumns.extension">0</xsl:param>
+ <xsl:param name="callout.extensions">1</xsl:param>
+ <xsl:param name="graphicsize.extension">0</xsl:param>
+
+ <!--###################################################
+ Table Of Contents
+ ################################################### -->
+
+ <!-- Generate the TOCs for named components only -->
+ <xsl:param name="generate.toc">
+ book toc
+ </xsl:param>
+
+ <!-- Show only Sections up to level 3 in the TOCs -->
+ <xsl:param name="toc.section.depth">4</xsl:param>
+
+ <!--###################################################
+ Labels
+ ################################################### -->
+
+ <!-- Label Chapters and Sections (numbering) -->
+ <xsl:param name="chapter.autolabel">1</xsl:param>
+ <xsl:param name="section.autolabel" select="1"/>
+ <xsl:param name="section.label.includes.component.label" select="1"/>
+
+ <!--###################################################
+ Callouts
+ ################################################### -->
+
+ <!-- Don't use graphics, use a simple number style -->
+ <xsl:param name="callout.graphics">0</xsl:param>
+
+ <!-- Place callout marks at this column in annotated areas -->
+ <xsl:param name="callout.defaultcolumn">90</xsl:param>
+
+ <!--###################################################
+ Misc
+ ################################################### -->
+
+ <!-- Placement of titles -->
+ <xsl:param name="formal.title.placement">
+ figure after
+ example before
+ equation before
+ table before
+ procedure before
+ </xsl:param>
+
+</xsl:stylesheet>
17 years, 4 months
JBoss Cache SVN: r4245 - support.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2007-08-14 12:05:05 -0400 (Tue, 14 Aug 2007)
New Revision: 4245
Added:
support/branches/
Log:
17 years, 4 months
JBoss Cache SVN: r4244 - support.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2007-08-14 12:04:57 -0400 (Tue, 14 Aug 2007)
New Revision: 4244
Added:
support/tags/
Log:
17 years, 4 months