Commit 29a52862 authored by Pete Matern's avatar Pete Matern Committed by pete

Moved some cache related classes to org.jivesoftware.util.cache. Made Cache an...

Moved some cache related classes to org.jivesoftware.util.cache. Made Cache an interface and moved its implementation down into DefaultCache. Initial pass at porting CacheFactory from clearspace.

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@8139 b35dd754-fafc-0310-a699-88a17e54d16e
parent da320be4
......@@ -12,8 +12,8 @@
package org.jivesoftware.openfire;
import org.dom4j.Element;
import org.jivesoftware.util.Cache;
import org.jivesoftware.util.CacheManager;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheManager;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.openfire.disco.ServerFeaturesProvider;
......
......@@ -17,6 +17,8 @@ import org.dom4j.io.SAXReader;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.database.SequenceManager;
import org.jivesoftware.util.*;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheManager;
import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.openfire.event.UserEventDispatcher;
import org.jivesoftware.openfire.event.UserEventListener;
......
......@@ -11,9 +11,9 @@
package org.jivesoftware.openfire;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.cache.CacheSizes;
import org.jivesoftware.util.StringUtils;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.util.cache.Cacheable;
/**
* Represents a set of permissions that an entity has for an object in the system. For example,
......
......@@ -12,6 +12,8 @@
package org.jivesoftware.openfire.auth;
import org.jivesoftware.util.*;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheManager;
import org.jivesoftware.openfire.user.UserAlreadyExistsException;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
......
......@@ -11,7 +11,8 @@
package org.jivesoftware.openfire.filetransfer;
import org.dom4j.Element;
import org.jivesoftware.util.Cache;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.DefaultCache;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.container.BasicModule;
......@@ -58,7 +59,7 @@ public class DefaultFileTransferManager extends BasicModule implements FileTrans
size = JiveGlobals.getIntProperty("cache." + propertiesName + ".size", size);
expirationTime = (long) JiveGlobals.getIntProperty(
"cache." + propertiesName + ".expirationTime", (int) expirationTime);
return new Cache<String, FileTransfer>(name, size, expirationTime);
return new DefaultCache<String, FileTransfer>(name, size, expirationTime);
}
/**
......
......@@ -10,8 +10,8 @@
*/
package org.jivesoftware.openfire.filetransfer;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.cache.Cacheable;
import org.jivesoftware.util.cache.CacheSizes;
import java.io.Serializable;
......
......@@ -10,7 +10,7 @@
*/
package org.jivesoftware.openfire.filetransfer.proxy;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.cache.CacheSizes;
import java.util.concurrent.Future;
import java.io.IOException;
......
......@@ -11,6 +11,8 @@
package org.jivesoftware.openfire.filetransfer.proxy;
import org.jivesoftware.util.*;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.DefaultCache;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.filetransfer.FileTransferManager;
import org.jivesoftware.openfire.filetransfer.FileTransferRejectedException;
......@@ -58,7 +60,7 @@ public class ProxyConnectionManager {
public ProxyConnectionManager(FileTransferManager manager) {
String cacheName = "File Transfer";
connectionMap = new Cache<String, ProxyTransfer>(cacheName, -1, 1000 * 60 * 10);
connectionMap = new DefaultCache<String, ProxyTransfer>(cacheName, -1, 1000 * 60 * 10);
className = JiveGlobals.getProperty("provider.transfer.proxy",
"org.jivesoftware.openfire.filetransfer.proxy.DefaultProxyTransfer");
......
......@@ -9,7 +9,7 @@
*/
package org.jivesoftware.openfire.filetransfer.proxy;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.util.cache.Cacheable;
import org.jivesoftware.openfire.filetransfer.FileTransferProgress;
import java.io.IOException;
......
......@@ -14,8 +14,8 @@ package org.jivesoftware.openfire.group;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.event.GroupEventDispatcher;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.util.cache.CacheSizes;
import org.jivesoftware.util.cache.Cacheable;
import org.jivesoftware.util.Log;
import org.xmpp.packet.JID;
......
......@@ -12,6 +12,8 @@
package org.jivesoftware.openfire.group;
import org.jivesoftware.util.*;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheManager;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.event.GroupEventDispatcher;
import org.jivesoftware.openfire.event.GroupEventListener;
......
......@@ -11,6 +11,8 @@
package org.jivesoftware.openfire.http;
import org.jivesoftware.util.*;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheManager;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
......
......@@ -12,6 +12,8 @@
package org.jivesoftware.openfire.ldap;
import org.jivesoftware.util.*;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheManager;
import org.jivesoftware.openfire.auth.AuthProvider;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.user.UserNotFoundException;
......
......@@ -12,8 +12,8 @@
package org.jivesoftware.openfire.privacy;
import org.dom4j.Element;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.util.cache.CacheSizes;
import org.jivesoftware.util.cache.Cacheable;
import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.user.UserNotFoundException;
......
......@@ -13,8 +13,8 @@ package org.jivesoftware.openfire.privacy;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.util.cache.CacheSizes;
import org.jivesoftware.util.cache.Cacheable;
import org.jivesoftware.util.Log;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.roster.Roster;
......
package org.jivesoftware.openfire.privacy;
import org.dom4j.Element;
import org.jivesoftware.util.Cache;
import org.jivesoftware.util.CacheManager;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheManager;
/**
* A Privacy list manager creates, gets, updates and removes privacy lists. Loaded lists
......
......@@ -12,8 +12,8 @@
package org.jivesoftware.openfire.roster;
import org.jivesoftware.database.JiveID;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.util.cache.CacheSizes;
import org.jivesoftware.util.cache.Cacheable;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.Log;
import org.jivesoftware.openfire.*;
......
......@@ -11,8 +11,8 @@
package org.jivesoftware.openfire.roster;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.util.cache.CacheSizes;
import org.jivesoftware.util.cache.Cacheable;
import org.jivesoftware.util.IntEnum;
import org.jivesoftware.openfire.SharedGroupException;
import org.jivesoftware.openfire.group.Group;
......
......@@ -11,8 +11,8 @@
package org.jivesoftware.openfire.roster;
import org.jivesoftware.util.Cache;
import org.jivesoftware.util.CacheManager;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheManager;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.openfire.ChannelHandler;
import org.jivesoftware.openfire.RoutingTable;
......
......@@ -16,6 +16,8 @@ import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.util.*;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheManager;
import org.jivesoftware.openfire.PacketDeliverer;
import org.jivesoftware.openfire.PresenceManager;
import org.jivesoftware.openfire.SessionManager;
......
......@@ -16,8 +16,8 @@ import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.auth.AuthFactory;
import org.jivesoftware.openfire.event.UserEventDispatcher;
import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.util.cache.CacheSizes;
import org.jivesoftware.util.cache.Cacheable;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.ExternalizableUtil;
......
......@@ -19,6 +19,8 @@ import org.jivesoftware.openfire.event.UserEventListener;
import org.jivesoftware.stringprep.Stringprep;
import org.jivesoftware.stringprep.StringprepException;
import org.jivesoftware.util.*;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheManager;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
......
......@@ -13,6 +13,8 @@ package org.jivesoftware.openfire.vcard;
import org.dom4j.Element;
import org.jivesoftware.util.*;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheManager;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.openfire.disco.ServerFeaturesProvider;
......
......@@ -15,6 +15,8 @@ import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheManager;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
......
/**
* $Revision$
* $Date$
*
* Copyright (C) 1999-2005 Jive Software. All rights reserved.
* This software is the proprietary information of Jive Software. Use is subject to license terms.
*/
package org.jivesoftware.util;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* Exception thrown during application or component initialization failure.
*/
public class InitializationException extends Exception {
private Throwable nestedThrowable = null;
public InitializationException() {
super();
}
public InitializationException(String msg) {
super(msg);
}
public InitializationException(Throwable nestedThrowable) {
this.nestedThrowable = nestedThrowable;
}
public InitializationException(String msg, Throwable nestedThrowable) {
super(msg);
this.nestedThrowable = nestedThrowable;
}
public void printStackTrace() {
super.printStackTrace();
if (nestedThrowable != null) {
nestedThrowable.printStackTrace();
}
}
public void printStackTrace(PrintStream ps) {
super.printStackTrace(ps);
if (nestedThrowable != null) {
nestedThrowable.printStackTrace(ps);
}
}
public void printStackTrace(PrintWriter pw) {
super.printStackTrace(pw);
if (nestedThrowable != null) {
nestedThrowable.printStackTrace(pw);
}
}
}
......@@ -18,6 +18,8 @@ import org.jivesoftware.openfire.muc.MultiUserChatServer;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.user.User;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheManager;
import java.io.*;
import java.net.URL;
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.util.cache;
import org.jivesoftware.util.*;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.*;
/**
* General purpose cache. It stores objects associated with unique keys in
* memory for fast access. All keys and values added to the cache must
* implement the Serializable interface. Values may implement the Cacheable
* interface, which allows the cache to determine object size much more quickly.
* These restrictions allow a cache to never grow larger than a specified number
* of bytes and to optionally be distributed over a cluster of servers.<p>
*
* If the cache does grow too large, objects will be removed such that those
* that are accessed least frequently are removed first. Because expiration
* happens automatically, the cache makes <b>no</b> gaurantee as to how long
* an object will remain in cache after it is put in.<p>
*
* Optionally, a maximum lifetime for all objects can be specified. In that
* case, objects will be deleted from cache after that amount of time, even
* if they are frequently accessed. This feature is useful if objects put in
* cache represent data that should be periodically refreshed; for example,
* information from a database.<p>
*
* All cache operations are thread safe.<p>
*
* @see Cacheable
*/
public interface Cache<K,V> extends java.util.Map<K,V> {
/**
* Returns the name of the cache.
*
* @return the name of the cache.
*/
String getName();
/**
* Sets the name of the cache
*
* @param name the name of the cache
*/
void setName(String name);
/**
* Returns the maximum size of the cache in bytes. If the cache grows larger
* than the max size, the least frequently used items will be removed. If
* the max cache size is set to -1, there is no size limit.
*
* @return the maximum size of the cache in bytes.
*/
int getMaxCacheSize();
/**
* Sets the maximum size of the cache in bytes. If the cache grows larger
* than the max size, the least frequently used items will be removed. If
* the max cache size is set to -1, there is no size limit.
*
* @param maxSize the maximum size of the cache in bytes.
*/
void setMaxCacheSize(int maxSize);
/**
* Returns the maximum number of milliseconds that any object can live
* in cache. Once the specified number of milliseconds passes, the object
* will be automatically expried from cache. If the max lifetime is set
* to -1, then objects never expire.
*
* @return the maximum number of milliseconds before objects are expired.
*/
long getMaxLifetime();
/**
* Sets the maximum number of milliseconds that any object can live
* in cache. Once the specified number of milliseconds passes, the object
* will be automatically expried from cache. If the max lifetime is set
* to -1, then objects never expire.
*
* @param maxLifetime the maximum number of milliseconds before objects are expired.
*/
void setMaxLifetime(long maxLifetime);
/**
* Returns the size of the cache contents in bytes. This value is only a
* rough approximation, so cache users should expect that actual VM
* memory used by the cache could be significantly higher than the value
* reported by this method.
*
* @return the size of the cache contents in bytes.
*/
int getCacheSize();
/**
* Returns the number of cache hits. A cache hit occurs every
* time the get method is called and the cache contains the requested
* object.<p>
*
* Keeping track of cache hits and misses lets one measure how efficient
* the cache is; the higher the percentage of hits, the more efficient.
*
* @return the number of cache hits.
*/
long getCacheHits();
/**
* Returns the number of cache misses. A cache miss occurs every
* time the get method is called and the cache does not contain the
* requested object.<p>
*
* Keeping track of cache hits and misses lets one measure how efficient
* the cache is; the higher the percentage of hits, the more efficient.
*
* @return the number of cache hits.
*/
long getCacheMisses();
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 1999-2005 Jive Software. All rights reserved.
* This software is the proprietary information of Jive Software. Use is subject to license terms.
*/
package org.jivesoftware.util.cache;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.InitializationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.*;
/**
* Creates Cache objects. The returned caches will either be local or clustered
* depending on the clustering enabled setting and a user's license.<p>
* <p/>
* When clustered caching is turned on, cache usage statistics for all caches
* that have been created are periodically published to the clustered cache
* named "opt-$cacheStats".
*
* @src.include false
*/
public class CacheFactory {
public static String CLUSTER_PROPERTY_NAME = "cache.clustering.enabled";
public static String LOCAL_CACHE_PROPERTY_NAME = "cache.clustering.local.class";
public static String CLUSTERED_CACHE_PROPERTY_NAME = "cache.clustering.clustered.class";
private static boolean clusteringEnabled = false;
/**
* Storage for all caches that get created.
*/
private static Map<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
/**
* List of registered listeners to be notified when clustering is enabled or disabled.
*/
private static List<ClusteringListener> listeners = new CopyOnWriteArrayList<ClusteringListener>();
private static String localCacheFactoryClass;
private static String clusteredCacheFactoryClass;
private static CacheFactoryStrategy cacheFactoryStrategy;
static {
localCacheFactoryClass = JiveGlobals.getProperty(LOCAL_CACHE_PROPERTY_NAME,
"com.jivesoftware.base.coherence.cache.CoherenceLocalCacheFactory");
clusteredCacheFactoryClass = JiveGlobals.getProperty(CLUSTERED_CACHE_PROPERTY_NAME,
"com.jivesoftware.base.coherence.cache.CoherenceClusteredCacheFactory");
}
private CacheFactory() {
}
/**
* Returns an array of all caches in the system.
* @return an array of all caches in the system.
*/
public static synchronized Cache[] getAllCaches() {
List<Cache> values = new ArrayList<Cache>();
for (Cache cache : caches.values()) {
values.add(cache);
}
return values.toArray(new Cache[values.size()]);
}
/**
* Returns the named cache, creating it as necessary.
*
* @param name the name of the cache to create.
* @return the named cache, creating it as necessary.
*/
@SuppressWarnings("unchecked")
public static synchronized <T extends Cache> T createCache(String name) {
T cache = (T) caches.get(name);
if (cache != null) {
return cache;
}
cache = (T) cacheFactoryStrategy.createCache(name);
return wrapCache(cache, name);
}
public static void lockKey(Object key, long timeout) {
cacheFactoryStrategy.lockKey(key, timeout);
}
public static void unlockKey(Object key) {
cacheFactoryStrategy.unlockKey(key);
}
@SuppressWarnings("unchecked")
private static <T extends Cache> T wrapCache(T cache, String name) {
cache = (T) new CacheWrapper(cache);
cache.setName(name);
caches.put(name, cache);
return cache;
}
/**
* Returns true if this node is currently a member of a cluster. The last step of application
* initialization is to join a cluster, so this method returns false during most of application startup.
*
* @return true if this node is currently a member of a cluster.
*/
public static boolean isClusteringEnabled() {
return clusteringEnabled;
}
/**
* Returns true if this instance is configured to run in a cluster.
* @return true if this instance is configured to run in a cluster.
*/
public static boolean isClusteringConfigured() {
return JiveGlobals.getBooleanProperty(CLUSTER_PROPERTY_NAME);
}
/**
* Returns a string uniquely identifying this member of the cluster.
*
* @return a string uniquely identifying this member of the cluster.
*/
public static String getClusterMemberID() {
return cacheFactoryStrategy.getClusterMemberID();
}
/**
* Sets whether cache clustering should be enabled. Anytime this value is
* changed, the application server must be restarted
*
* @param enabled true if cache clustering should be enabled.
* @throws Exception if an error occurs while using the new cache type.
*/
public static synchronized void setClusteringEnabled(boolean enabled) throws Exception {
if (enabled == clusteringEnabled) {
return;
}
JiveGlobals.setProperty(CLUSTER_PROPERTY_NAME, String.valueOf(enabled));
if (!enabled) {
clusteringEnabled = false;
CacheFactoryStrategy clusteredFactory = cacheFactoryStrategy;
cacheFactoryStrategy = (CacheFactoryStrategy) Class.forName(localCacheFactoryClass)
.newInstance();
// Loop through clustered caches and change them to local caches.
for (String cacheName : caches.keySet()) {
CacheWrapper wrapper = (CacheWrapper) caches.get(cacheName);
wrapper.setWrappedCache(cacheFactoryStrategy.createCache(cacheName));
}
// Stop the cluster
clusteredFactory.stopCluster();
fireClusteringStopped();
}
else {
// Reload Jive properties. This will ensure that this nodes copy of the
// properties starts correct.
//TODO see if there is something analagous in openfire
// DbJiveProperties.getInstance().init();
startClustering();
}
}
public synchronized static void clearCaches() {
for (String cacheName : caches.keySet()) {
Cache cache = caches.get(cacheName);
cache.clear();
}
}
/**
* Returns true if this member is the senior member in the cluster. If clustering
* is not enabled, this method will also return true. This test is useful for
* tasks that should only be run on a single member in a cluster.
*
* @return true if this cluster member is the senior or if clustering is not enabled.
*/
public static boolean isSeniorClusterMember() {
synchronized(CacheFactory.class) {
if (!isClusteringEnabled()) {
return true;
}
}
return cacheFactoryStrategy.isSeniorClusterMember();
}
/**
* Invokes a task on other cluster members in an asynchronous fashion. The task will not be
* executed on the local cluster member. If clustering is not enabled, this method
* will do nothing.
*
* @param task the task to be invoked on all other cluster members.
*/
public static void doClusterTask(final ClusterTask task) {
if (!clusteringEnabled) {
return;
}
synchronized(CacheFactory.class) {
if (!clusteringEnabled) {
return;
}
}
cacheFactoryStrategy.doClusterTask(buildClusterTask(task));
}
/**
* Invokes a task on other cluster members synchronously and returns the result as a Collection
* (method will not return until the task has been executed on each cluster member).
* The task will not be executed on the local cluster member. If clustering is not enabled,
* this method will return an empty collection.
*
* @param task the ClusterTask object to be invoked on all other cluster members.
* @param includeLocalMember true to run the task on the local member, false otherwise
* @return collection with the result of the execution.
*/
public static Collection<Object> doSynchronousClusterTask(ClusterTask task, boolean includeLocalMember) {
synchronized(CacheFactory.class) {
if (!clusteringEnabled) {
return Collections.emptyList();
}
}
return cacheFactoryStrategy.doSynchronousClusterTask(buildClusterTask(task), includeLocalMember);
}
/**
* Shuts down the clustering service. This method should be called when the Jive
* system is shutting down, and must not be called otherwise. By default, a
* ServletContextListener is registered to listen for the web application shutting down, and
* will automatically call this method. However, if the Jive system is being used in
* another context, such as a command-line application, this method should be called
* explicitly. Failing to call this method may temporarily impact cluster performance,
* as the system will have to do extra work to recover from a non-clean shutdown.
* If clustering is not enabled, this method will do nothing.
*/
public static synchronized void shutdownClusteringService() {
Log.debug("Shutting down clustered cache service.");
cacheFactoryStrategy.stopCluster();
}
public static void addClusteringListener(ClusteringListener listener) {
listeners.add(listener);
}
public static void removeClusteringListener(ClusteringListener listener) {
listeners.remove(listener);
}
private static void fireClusteringStarted() {
for (ClusteringListener listener : listeners) {
(listener).clusteringStarted();
}
}
private static void fireClusteringStopped() {
for (ClusteringListener listener : listeners) {
(listener).clusteringStopped();
}
}
/**
* Saves current cache settings to local properties.
*/
public static void saveCacheSettings() {
for (Cache toSave : caches.values()) {
setMaxSizeProperty(toSave.getName(), toSave.getMaxCacheSize());
setMaxLifetimeProperty(toSave.getName(), toSave.getMaxLifetime());
}
}
/**
* Sets a local property which overrides the maximum cache size as configured in coherence-cache-config.xml for the
* supplied cache name.
* @param cacheName the name of the cache to store a value for.
* @param size the maximum cache size.
*/
public static void setMaxSizeProperty(String cacheName, int size) {
cacheName = cacheName.replaceAll(" ", "");
JiveGlobals.setProperty("cache." + cacheName + ".size", Integer.toString(size));
}
/**
* Sets a local property which overrides the maximum cache entry lifetime as configured in coherence-cache-config.xml
* for the supplied cache name.
* @param cacheName the name of the cache to store a value for.
* @param lifetime the maximum cache entry lifetime.
*/
public static void setMaxLifetimeProperty(String cacheName, long lifetime) {
cacheName = cacheName.replaceAll(" ", "");
JiveGlobals.setProperty("cache." + cacheName + ".maxLifetime", Long.toString(lifetime));
}
/**
* If a local property is found for the supplied name which specifies a value for cache size, it is returned. Otherwise,
* the defaultSize argument is returned.
* @param cacheName the name of the cache to look up a corresponding property for.
* @param defaultSize the value to return if no property is set.
* @return either the property value or the default value.
*/
public static int getMaxSizeFromProperty(String cacheName, int defaultSize) {
String propName = "cache." + cacheName.replaceAll(" ", "") + ".size";
String sizeProp = JiveGlobals.getProperty(propName);
if (sizeProp != null) {
try {
return Integer.parseInt(sizeProp);
}
catch (NumberFormatException nfe) {
Log.warn("Unable to parse " + propName + " using default value of " + defaultSize);
return defaultSize;
}
}
else {
return defaultSize;
}
}
/**
* If a local property is found for the supplied name which specifies a value for cache entry lifetime, it is returned.
* Otherwise, the defaultLifetime argument is returned.
* @param cacheName the name of the cache to look up a corresponding property for.
* @param defaultLifetime the value to return if no property is set.
* @return either the property value or the default value.
*/
public static long getMaxLifetimeFromProperty(String cacheName, long defaultLifetime) {
String propName = "cache." + cacheName.replaceAll(" ", "") + ".maxLifetime";
String lifetimeProp = JiveGlobals.getProperty(propName);
if (lifetimeProp != null) {
try {
return Long.parseLong(lifetimeProp);
}
catch (NumberFormatException nfe) {
Log.warn("Unable to parse " + propName + " using default value of " + defaultLifetime);
return defaultLifetime;
}
}
else {
return defaultLifetime;
}
}
public static synchronized void initialize() throws InitializationException {
try {
cacheFactoryStrategy = (CacheFactoryStrategy) Class
.forName(localCacheFactoryClass).newInstance();
}
catch (InstantiationException e) {
throw new InitializationException(e);
}
catch (IllegalAccessException e) {
throw new InitializationException(e);
}
catch (ClassNotFoundException e) {
throw new InitializationException(e);
}
}
/**
* Starts the cluster service if clustering is enabled, and begins tracking cache statistics. Before this method is called,
* any {@link Cache}s returned by calls to {@link #createCache} will return local caches. The process of starting clustering
* will recreate them as distributed caches. This is safer than the alternative - where clustering is started before
* any caches are created. In that scenario, cluster tasks can fire off in this process before it is safe for them to do so,
* and cluster wide deadlocks can occur.
*/
public static synchronized void startup() {
if (clusteringEnabled) {
return;
}
// See if clustering should be enabled.
String enabled = JiveGlobals.getProperty(CLUSTER_PROPERTY_NAME);
// If the user tried to turn on clustering, make sure they're actually allowed to.
if (Boolean.valueOf(enabled)) {
startClustering();
}
// Start a timing thread with 1 second of accuracy.
Thread t = new Thread("Cache Stats") {
private volatile boolean destroyed = false;
public void run() {
// Run the timer indefinitely.
//TODO set the destroyed flag through some listener
while (!destroyed) {
// Publish cache stats for this cluster node (assuming clustering is
// enabled and there are stats to publish).
try {
cacheFactoryStrategy.updateCacheStats(caches);
}
catch (Exception e) {
Log.error(e);
}
try {
// Sleep 10 seconds.
sleep(10000);
}
catch (InterruptedException ie) {
// Ignore.
}
}
Log.debug("Cache stats thread terminated.");
}
};
t.setDaemon(true);
t.start();
}
private static void startClustering() {
clusteringEnabled = false;
try {
cacheFactoryStrategy = (CacheFactoryStrategy) Class.forName(clusteredCacheFactoryClass)
.newInstance();
boolean clusterStarted = cacheFactoryStrategy.startCluster();
if (clusterStarted) {
// Loop through local caches and switch them to clustered cache.
for (String cacheName : caches.keySet()) {
CacheWrapper wrapper = (CacheWrapper) caches.get(cacheName);
wrapper.setWrappedCache(cacheFactoryStrategy.createCache(cacheName));
}
clusteringEnabled = true;
fireClusteringStarted();
}
}
catch (Exception e) {
Log.error("Unable to start clustering - continuing in local mode", e);
}
}
/**
* Creates a new Cluster Task that will execute the wrapped task and ensure
* that any DAO context is also closed after the execution of the task.
*
* @param task the cluster task to wrap.
* @return new Cluster Task that will execute the wrapped task.
*/
public static ClusterTask buildClusterTask(final ClusterTask task) {
return new ClusterTask() {
ClusterTask taskToRun = task;
public void run() {
task.run();
}
public Object getResult() {
return task.getResult();
}
};
}
/**
* Listener interface for any object which needs to be notified when clustering starts or stops
*/
public static interface ClusteringListener {
public void clusteringStarted();
public void clusteringStopped();
}
}
\ No newline at end of file
/**
* $Revision$
* $Date$
*
* Copyright (C) 1999-2005 Jive Software. All rights reserved.
* This software is the proprietary information of Jive Software. Use is subject to license terms.
*/
package org.jivesoftware.util.cache;
import java.util.Collection;
import java.util.Map;
/**
* Implementation of CacheFactory that relies on the specific clustering solution.
*
* @author Gaston Dombiak
*/
public interface CacheFactoryStrategy {
/**
* Returns true if the cluster has been started. When running in local
* mode a true value should be returned.<p>
*
* An error should be logged when the cluster fails to be started.
*
* @return true if the cluster has been started.
*/
boolean startCluster();
/**
* Stops the cluster. When not running in a cluster this request will be ignored.
*/
void stopCluster();
/**
* Creates a new cache for the cache name specified. The created cache is
* already configured. Different implementations could store the cache
* configuration in different ways. It is recommended to store the cache
* configuration in an external file so it is easier for customers to change
* the default configuration.
*
* @param name name of the cache to create.
* @return newly created and configured cache.
*/
Cache createCache(String name);
/**
* Returns true if this node is the maste node of the cluster. When not running
* in cluster mode a value of true should be returned.
*
* @return true if this node is the maste node of the cluster.
*/
boolean isSeniorClusterMember();
/**
* Returns a string uniquely identifying this member within the cluster.
*
* @return a string uniquely identifying this member within the cluster.
*/
String getClusterMemberID();
/**
* Invokes a task on other cluster members in an asynchronous fashion. The task will not be
* executed on the local cluster member. If clustering is not enabled, this method
* will do nothing.
*
* @param task the task to be invoked on all other cluster members.
*/
void doClusterTask(final ClusterTask task);
/**
* Invokes a task on other cluster members synchronously and returns the result as a Collection
* (method will not return until the task has been executed on each cluster member).
* The task will not be executed on the local cluster member. If clustering is not enabled,
* this method will return an empty collection.
*
* @param task the ClusterTask object to be invoked on all other cluster members.
* @param includeLocalMember true to run the task on the local member, false otherwise
* @return collection with the result of the execution.
*/
Collection<Object> doSynchronousClusterTask(ClusterTask task, boolean includeLocalMember);
/**
* Updates the statistics of the specified caches and publishes them into
* a cache for statistics. The statistics cache is already known to the application
* but this could change in the future (?). When not in cluster mode then
* do nothing.<p>
*
* The statistics cache must contain a long array of 5 positions for each cache
* with the following content:
* <ol>
* <li>cache.getCacheSize()</li>
* <li>cache.getMaxCacheSize()</li>
* <li>cache.size()</li>
* <li>cache.getCacheHits()</li>
* <li>cache.getCacheMisses()</li>
* </ol>
*
* @param caches caches to get their stats and publish them in a statistics cache.
*/
void updateCacheStats(Map<String, Cache> caches);
/**
* Locks the specified key in the locking map. The map should be clusterable
* thus locking a key is visible to the cluster. When not in cluster mode
* the lock is only visible to this JVM.
*
* @param key the key to lock.
* @param timeout number of milliseconds to wait to obtain the lock. -1 means wait forever.
*/
void lockKey(Object key, long timeout);
/**
* Unlocks the specified key in the locking map. The map should be clusterable
* thus locking a key is visible to the cluster. When not in cluster mode
* the lock is only visible to this JVM.
*
* @param key the key to unlock.
*/
void unlockKey(Object key);
}
......@@ -7,7 +7,11 @@
* Use is subject to license terms.
*/
package org.jivesoftware.util;
package org.jivesoftware.util.cache;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.JiveGlobals;
import java.util.Collection;
import java.util.HashMap;
......@@ -73,7 +77,7 @@ public class CacheManager {
size = JiveGlobals.getIntProperty("cache." + propertiesName + ".size", size);
expirationTime = (long) JiveGlobals.getIntProperty(
"cache." + propertiesName + ".expirationTime", (int) expirationTime);
cache = new Cache<K,V>(name, size, expirationTime);
cache = new DefaultCache<K,V>(name, size, expirationTime);
caches.put(name, cache);
}
return cache;
......
......@@ -9,7 +9,9 @@
* a copy of which is included in this distribution.
*/
package org.jivesoftware.util;
package org.jivesoftware.util.cache;
import org.jivesoftware.util.cache.Cacheable;
import java.util.Map;
import java.util.Collection;
......
/**
* $Revision$
* $Date$
*
* Copyright (C) 1999-2005 Jive Software. All rights reserved.
* This software is the proprietary information of Jive Software. Use is subject to license terms.
*/
package org.jivesoftware.util.cache;
import java.util.*;
/**
* Acts as a proxy for a Cache implementation. The Cache implementation can be switched on the fly,
* which enables users to hold a reference to a CacheWrapper object, but for the underlying
* Cache implementation to switch from clustered to local, etc.
*
*/
public class CacheWrapper<K, V> implements Cache<K, V> {
private Cache<K, V> cache;
public CacheWrapper(Cache<K, V> cache) {
this.cache = cache;
}
public Cache<K, V> getWrappedCache() {
return cache;
}
public void setWrappedCache(Cache<K, V> cache) {
this.cache = cache;
}
public String getName() {
return cache.getName();
}
public void setName(String name) {
cache.setName(name);
}
public int getMaxCacheSize() {
return cache.getMaxCacheSize();
}
public void setMaxCacheSize(int maxSize) {
cache.setMaxCacheSize(maxSize);
}
public long getMaxLifetime() {
return cache.getMaxLifetime();
}
public void setMaxLifetime(long maxLifetime) {
cache.setMaxLifetime(maxLifetime);
}
public int getCacheSize() {
return cache.getCacheSize();
}
public long getCacheHits() {
return cache.getCacheHits();
}
public long getCacheMisses() {
return cache.getCacheMisses();
}
public int size() {
return cache.size();
}
public void clear() {
cache.clear();
}
public boolean isEmpty() {
return cache.isEmpty();
}
public boolean containsKey(Object key) {
return cache.containsKey(key);
}
public boolean containsValue(Object value) {
return cache.containsValue(value);
}
public Collection<V> values() {
return cache.values();
}
public void putAll(Map<? extends K, ? extends V> t) {
cache.putAll(t);
}
public Set<Map.Entry<K, V>> entrySet() {
return cache.entrySet();
}
public Set<K> keySet() {
return cache.keySet();
}
public V get(Object key) {
return cache.get(key);
}
public V remove(Object key) {
return cache.remove(key);
}
public V put(K key, V value) {
return cache.put(key, value);
}
}
\ No newline at end of file
......@@ -9,7 +9,7 @@
* a copy of which is included in this distribution.
*/
package org.jivesoftware.util;
package org.jivesoftware.util.cache;
/**
* Interface that defines the necessary behavior for objects added to a Cache.
......@@ -22,7 +22,7 @@ package org.jivesoftware.util;
* speedy.
*
* @author Jive Software
* @see org.jivesoftware.util.Cache
* @see org.jivesoftware.util.cache.Cache
*/
public interface Cacheable extends java.io.Serializable {
......
/**
* $Revision$
* $Date$
*
* Copyright (C) 1999-2005 Jive Software. All rights reserved.
* This software is the proprietary information of Jive Software. Use is subject to license terms.
*/
package org.jivesoftware.util.cache;
import java.io.Serializable;
/**
* An interface to mix in Serializable and Runnable, which are both required for
* sending invocable tasks across a cluster.
*/
public interface ClusterTask extends Runnable, Serializable {
public Object getResult();
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
* Copyright (C) 1999-2005 Jive Software. All rights reserved.
* This software is the proprietary information of Jive Software. Use is subject to license terms.
*/
package org.jivesoftware.util.cache;
package org.jivesoftware.util;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.LinkedListNode;
import java.io.IOException;
import java.util.*;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
/**
* Default, non-distributed implementation of the Cache interface.
......@@ -41,12 +40,12 @@ import java.util.*;
*
* @author Matt Tucker
*/
public class Cache<K, V> implements Map<K, V> {
public class DefaultCache<K, V> implements Cache<K, V> {
/**
* The map the keys and values are stored in.
*/
protected Map<K, CacheObject<V>> map;
protected Map<K, DefaultCache.CacheObject<V>> map;
/**
* Linked list to maintain order that cache objects are accessed
......@@ -58,7 +57,7 @@ public class Cache<K, V> implements Map<K, V> {
* Linked list to maintain time that cache objects were initially added
* to the cache, most recently added to oldest added.
*/
protected LinkedList ageList;
protected org.jivesoftware.util.LinkedList ageList;
/**
* Maximum size in bytes that the cache can grow to.
......@@ -91,7 +90,7 @@ public class Cache<K, V> implements Map<K, V> {
private String name;
/**
* Create a new cache and specify the maximum size of for the cache in
* Create a new default cache and specify the maximum size of for the cache in
* bytes, and the maximum lifetime of objects.
*
* @param name a name for the cache.
......@@ -100,7 +99,7 @@ public class Cache<K, V> implements Map<K, V> {
* @param maxLifetime the maximum amount of time objects can exist in
* cache before being deleted. -1 means objects never expire.
*/
public Cache(String name, int maxSize, long maxLifetime) {
public DefaultCache(String name, int maxSize, long maxLifetime) {
this.name = name;
this.maxCacheSize = maxSize;
this.maxLifetime = maxLifetime;
......@@ -109,8 +108,8 @@ public class Cache<K, V> implements Map<K, V> {
// is too small in almost all cases, so we set it bigger.
map = new HashMap<K, CacheObject<V>>(103);
lastAccessedList = new LinkedList();
ageList = new LinkedList();
lastAccessedList = new org.jivesoftware.util.LinkedList();
ageList = new org.jivesoftware.util.LinkedList();
}
public synchronized V put(K key, V value) {
......@@ -126,7 +125,7 @@ public class Cache<K, V> implements Map<K, V> {
return value;
}
cacheSize += objectSize;
CacheObject<V> cacheObject = new CacheObject<V>(value, objectSize);
DefaultCache.CacheObject<V> cacheObject = new DefaultCache.CacheObject<V>(value, objectSize);
map.put(key, cacheObject);
// Make an entry into the cache order list.
LinkedListNode lastAccessedNode = lastAccessedList.addFirst(key);
......@@ -152,7 +151,7 @@ public class Cache<K, V> implements Map<K, V> {
// maximum defined age.
deleteExpiredEntries();
CacheObject<V> cacheObject = map.get(key);
DefaultCache.CacheObject<V> cacheObject = map.get(key);
if (cacheObject == null) {
// The object didn't exist in cache, so increment cache misses.
cacheMisses++;
......@@ -173,7 +172,7 @@ public class Cache<K, V> implements Map<K, V> {
}
public synchronized V remove(Object key) {
CacheObject<V> cacheObject = map.get(key);
DefaultCache.CacheObject<V> cacheObject = map.get(key);
// If the object is not in cache, stop trying to remove it.
if (cacheObject == null) {
return null;
......@@ -200,9 +199,9 @@ public class Cache<K, V> implements Map<K, V> {
// Now, reset all containers.
map.clear();
lastAccessedList.clear();
lastAccessedList = new LinkedList();
lastAccessedList = new org.jivesoftware.util.LinkedList();
ageList.clear();
ageList = new LinkedList();
ageList = new org.jivesoftware.util.LinkedList();
cacheSize = 0;
cacheHits = 0;
......@@ -229,16 +228,16 @@ public class Cache<K, V> implements Map<K, V> {
// First, clear all entries that have been in cache longer than the
// maximum defined age.
deleteExpiredEntries();
return new CacheObjectCollection(map.values());
return new DefaultCache.CacheObjectCollection(map.values());
}
/**
* Wraps a cached object collection to return a view of its inner objects
*/
private final class CacheObjectCollection<V> implements Collection<V> {
private Collection<CacheObject<V>> cachedObjects;
private Collection<DefaultCache.CacheObject<V>> cachedObjects;
private CacheObjectCollection(Collection<CacheObject<V>> cachedObjects) {
private CacheObjectCollection(Collection<DefaultCache.CacheObject<V>> cachedObjects) {
this.cachedObjects = new ArrayList<CacheObject<V>>(cachedObjects);
}
......@@ -262,7 +261,7 @@ public class Cache<K, V> implements Map<K, V> {
public Iterator<V> iterator() {
return new Iterator<V>() {
private final Iterator<CacheObject<V>> it = cachedObjects.iterator();
private final Iterator<DefaultCache.CacheObject<V>> it = cachedObjects.iterator();
public boolean hasNext() {
return it.hasNext();
......@@ -270,7 +269,7 @@ public class Cache<K, V> implements Map<K, V> {
public V next() {
if(it.hasNext()) {
CacheObject<V> object = it.next();
DefaultCache.CacheObject<V> object = it.next();
if(object == null) {
return null;
} else {
......@@ -413,6 +412,15 @@ public class Cache<K, V> implements Map<K, V> {
return name;
}
/**
* Sets the name of this cache.
*
* @param name the name of this cache.
*/
public void setName(String name) {
this.name = name;
}
/**
* Returns the number of cache hits. A cache hit occurs every
* time the get method is called and the cache contains the requested
......@@ -539,7 +547,7 @@ public class Cache<K, V> implements Map<K, V> {
int size = 1;
try {
// Default to serializing the object out to determine size.
NullOutputStream out = new NullOutputStream();
DefaultCache.NullOutputStream out = new DefaultCache.NullOutputStream();
ObjectOutputStream outObj = new ObjectOutputStream(out);
outObj.writeObject(object);
size = out.size();
......
<%@ page import="org.jivesoftware.util.Cache"%>
<%@ page import="org.jivesoftware.util.cache.Cache"%>
<%@ page import="org.jivesoftware.util.ParamUtils"%>
<%@ page import="java.text.DecimalFormat"%>
<%--
......@@ -92,15 +92,15 @@
<% // Get parameters
boolean doClearCache = request.getParameter("clear") != null;
int refresh = ParamUtils.getIntParameter(request,"refresh",-1);
int[] cacheIDs = ParamUtils.getIntParameters(request,"cacheID",-1);
int refresh = ParamUtils.getIntParameter(request, "refresh", -1);
int[] cacheIDs = ParamUtils.getIntParameters(request, "cacheID", -1);
// Get the list of existing caches
Cache[] caches = webManager.getCaches();
// Clear one or multiple caches if requested.
if (doClearCache) {
for (int i=0; i<cacheIDs.length; i++) {
for (int i = 0; i < cacheIDs.length; i++) {
caches[cacheIDs[i]].clear();
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment