Index: lams_common/conf/jar/META-INF/MANIFEST.MF =================================================================== diff -u --- lams_common/conf/jar/META-INF/MANIFEST.MF (revision 0) +++ lams_common/conf/jar/META-INF/MANIFEST.MF (revision f8ae59adef57f2f13c9d22cca469423d817e4fb9) @@ -0,0 +1,4 @@ +Implementation-Title: LAMS +Implementation-Version: 1.1 +Implementation-Vendor: LAMS Foundation (http://lamsfoundation.org) +Class-Path: jboss-cache.jar, jgroups.jar Index: lams_common/src/java/org/lamsfoundation/lams/cache/CacheDebugListener.java =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/cache/CacheDebugListener.java (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/cache/CacheDebugListener.java (revision f8ae59adef57f2f13c9d22cca469423d817e4fb9) @@ -0,0 +1,74 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.lams.cache; + +import org.apache.log4j.Logger; +import org.jboss.cache.Fqn; +import org.jboss.cache.TreeCache; +import org.jboss.cache.TreeCacheListener; + +/** Log the addition/removal/eviction of items from the JBOSS cache. + * Turn on and off using UseCacheDebugListener entry in lams.xml + * + * @author Fiona Malikoff + */ +public class CacheDebugListener implements TreeCacheListener { + + protected Logger log = Logger.getLogger(CacheManager.class); + private String cacheNameString = "Cache unknown: "; + + private void logMessage(String message) { + log.info(cacheNameString+message); + } + + public void cacheStarted(TreeCache cache) { + cacheNameString = "Cache "+cache.getName()+": "; + logMessage("started"); + } + + public void cacheStopped(TreeCache cache) { + logMessage("stopped"); + } + + public void nodeCreated(Fqn fqn) { + logMessage("node created "+fqn); + } + public void nodeEvicted(Fqn fqn) { + logMessage("node evicted "+fqn); + } + public void nodeLoaded(Fqn fqn) { + logMessage("node loaded "+fqn); + } + public void nodeModified(Fqn fqn) { + logMessage("node modified "+fqn); + } + public void nodeRemoved(Fqn fqn) { + logMessage("node removed "+fqn); + } + public void nodeVisited(Fqn fqn) { + logMessage("node visited "+fqn); + } + public void viewChange(org.jgroups.View new_view){ + logMessage("view changed "); + } +} Index: lams_common/src/java/org/lamsfoundation/lams/cache/CacheManager.java =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/cache/CacheManager.java (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/cache/CacheManager.java (revision f8ae59adef57f2f13c9d22cca469423d817e4fb9) @@ -0,0 +1,230 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.lams.cache; + +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; + +import org.apache.log4j.Logger; +import org.jboss.cache.CacheException; +import org.jboss.cache.Fqn; +import org.jboss.cache.TreeCacheListener; +import org.jboss.cache.TreeCacheMBean; +import org.jboss.mx.util.MBeanProxyExt; +import org.jboss.mx.util.MBeanServerLocator; +import org.lamsfoundation.lams.util.Configuration; +import org.lamsfoundation.lams.util.ConfigurationKeys; + +/** + * Wraps the JBOSS cache. See ICacheManager for more details. + */ +public class CacheManager implements ICacheManager { + + protected Logger log = Logger.getLogger(CacheManager.class); + private String DEFAULT_CACHE_OBJECT_NAME="jboss.cache:service=TreeCache"; + + /* Spring configured variables */ + private String cacheObjectName = null; + + /* There is one cache across the whole system, so it should be safe to + * use a static cache bean. Do not use this attribute directly - always + * get it via getCache(). */ + private TreeCacheMBean treeCache = null; + private TreeCacheListener listener = null; + + /** Get the tree cache. + *
+ * If necessary, gets it via the MBean. If gets via MBean, then
+ * also sets up the cache listener at the same time, if required. */
+ private TreeCacheMBean getCache() {
+ if ( treeCache == null ) {
+
+ try {
+ if ( cacheObjectName == null )
+ cacheObjectName = DEFAULT_CACHE_OBJECT_NAME;
+ MBeanServer server=MBeanServerLocator.locate();
+ treeCache = (TreeCacheMBean)MBeanProxyExt.create(TreeCacheMBean.class, cacheObjectName, server);
+
+ if ( Configuration.getAsBoolean(ConfigurationKeys.USE_CACHE_DEBUG_LISTENER) ) {
+ if ( listener != null )
+ treeCache.removeTreeCacheListener(listener);
+ listener = new CacheDebugListener();
+ treeCache.addTreeCacheListener(listener);
+ log.info("Added tree cache listener.");
+ }
+ } catch (MalformedObjectNameException e) {
+ log.error("Unable to access the JBOSS cache mbean "+cacheObjectName+". Cache not available.",e);
+ }
+ }
+ return treeCache;
+ }
+
+ /** Get the String[] version of the objects class name. */
+ public String[] getPartsFromClass(Class clasz) {
+ return clasz.getName().split("\\.");
+ }
+
+ /** Get the Fqn for this object, based on the class name. The Fqn is used as the part of the key to the cached object. */
+ private Fqn getFqn(Class clasz) {
+ return new Fqn(getPartsFromClass(clasz));
+ }
+
+ /** Get the Fqn for this object, based on classNameParts. The Fqn is used as the part of the key to the cached object. */
+ private Fqn getFqn(String[] classNameParts) {
+ return new Fqn(classNameParts);
+ }
+
+ /* (non-Javadoc)
+ * @see org.lamsfoundation.lams.cache.ICacheManager#getItem(java.lang.String[], java.lang.Object)
+ */
+ public Object getItem(String[] classNameParts, Object key){
+ if ( key == null || classNameParts == null )
+ return null;
+
+ return getItem(getFqn(classNameParts),key);
+ }
+
+ /* (non-Javadoc)
+ * @see org.lamsfoundation.lams.cache.ICacheManager#getItem(java.lang.Class, java.lang.Object)
+ */
+ public Object getItem(Class clasz, Object key) {
+ if ( key == null || clasz == null )
+ return null;
+
+ return getItem(getFqn(clasz), key);
+ }
+
+ /** Does the "real" get from the cache. Key and fqn must not be null or an exception may be thrown. */
+ private Object getItem(Fqn fqn, Object key) {
+ TreeCacheMBean cache = getCache();
+ if (cache==null) {
+ log.error("Unable to get item with fqn "+fqn+" key "+key+" as we can't get the JBOSS Cache mbean.");
+ return null;
+ }
+
+ Object obj = null;
+ try {
+ obj = (Object) cache.get(fqn, key);
+ if ( obj != null ) {
+ log.debug("Retrieved object from cache fqn "+fqn+" key "+key);
+ }
+ } catch (CacheException e) {
+ log.error("JBOSS Cache exception occured getting object from cache. fqn "+fqn+" key "+key, e);
+ }
+
+ return obj;
+ }
+
+ /* (non-Javadoc)
+ * @see org.lamsfoundation.lams.cache.ICacheManager#addItem(java.lang.String[], java.lang.Object, java.lang.Object)
+ */
+ public void addItem(String[] classNameParts, Object key, Object item){
+ if ( item != null && key != null && classNameParts != null )
+ addItem(getFqn(classNameParts), key, item);
+ }
+
+ /* (non-Javadoc)
+ * @see org.lamsfoundation.lams.cache.ICacheManager#addItem(java.lang.Class, java.lang.Object, java.lang.Object)
+ */
+ public void addItem(Class clasz, Object key, Object item){
+ if ( item != null && key != null && clasz != null )
+ addItem(getFqn(clasz),key,item);
+ }
+
+ /** Does the "real" put in the cache. Key, fqn and item must not be null or an exception may be thrown. */
+ private void addItem(Fqn fqn, Object key, Object item){
+ TreeCacheMBean cache = getCache();
+ if (cache==null) {
+ log.error("Unable to get cache item with fqn "+fqn+" key "+key+" as we can't get the JBOSS Cache mbean.");
+ return;
+ }
+
+ try {
+ cache.put(fqn, key, item);
+ } catch (CacheException e) {
+ log.error("JBOSS Cache exception occured putting object in cache. fqn "+fqn+" key "+key,e);
+ }
+ }
+
+ public Map getCachedItems() {
+ TreeCacheMBean cache = getCache();
+ Map allChildNames = new TreeMap();
+ if (cache==null) {
+ log.error("Unable to get cache items as we can't get the JBOSS Cache mbean.");
+ } else {
+ addChildren("/", cache, allChildNames);
+ }
+ return allChildNames;
+ }
+
+ /* Recursively add all the child nodes to the map. This is where the format of FQNs is important -
+ * this code will hardcode in "/" between each step. */
+ private void addChildren(String node, TreeCacheMBean cache, Map allChildNames ) {
+ try {
+ Set childNames = cache.getChildrenNames(node);
+ if ( childNames != null ) {
+ allChildNames.put(node, childNames);
+ Iterator iter = childNames.iterator();
+ while ( iter.hasNext() ) {
+ String childNode = (String) iter.next();
+ if ( node.endsWith("/") ) {
+ addChildren(node+childNode,cache,allChildNames);
+ } else {
+ addChildren(node+"/"+childNode,cache,allChildNames);
+ }
+ }
+ }
+ } catch (CacheException e) {
+ log.error("JBOSS Cache exception occured getting child names from cache",e);
+ }
+ }
+
+ /** Clear all the nodes in the cache. Works on nodes starting with /org, /com and /net */
+ public void clearCache(String node) {
+ TreeCacheMBean cache = getCache();
+ if (cache==null) {
+ log.error("Unable to clear cache items as we can't get the JBOSS Cache mbean.");
+ } else {
+ try {
+ cache.remove(node);
+ } catch (CacheException e) {
+ log.error("JBOSS Cache exception occured getting child names from cache",e);
+ }
+ }
+ }
+ /* **** Spring initialisation methods */
+
+ public String getCacheObjectName() {
+ return cacheObjectName;
+ }
+
+ public void setCacheObjectName(String cacheObjectName) {
+ this.cacheObjectName = cacheObjectName;
+ }
+
+}
Index: lams_common/src/java/org/lamsfoundation/lams/cache/ICacheManager.java
===================================================================
diff -u
--- lams_common/src/java/org/lamsfoundation/lams/cache/ICacheManager.java (revision 0)
+++ lams_common/src/java/org/lamsfoundation/lams/cache/ICacheManager.java (revision f8ae59adef57f2f13c9d22cca469423d817e4fb9)
@@ -0,0 +1,53 @@
+package org.lamsfoundation.lams.cache;
+
+/** Wraps up the JBOSS Cache in some simple methods to add, get and
+ * remove an object to/from the cache. Used for manually caching objects,
+ * rather than Hibernate managed objects.
+ *
+ * Each item in the cache is specified using a Fqn based on the object's classpath
+ * a unique value. The Fqn can be generated by the CacheManager from the object's
+ * class or the calling code can pass the object's type split into parts. The
+ * latter may be handy if the object's type is always known. Use getPartsFromClass(Class clasz)
+ * to generate the appropriate string array.
+ *
+ * It is expected that it will be available to modules via a spring bean (singleton).
+ * Therefore we will have one CacheManager per web-app. However the underlying cache
+ * will be the shared across the whole system so objects that are cached by one
+ * module will be available via the cache to another module (should it know the right Class
+ * and key).
+ *
+ * If errors occur putting values in the cache, or getting values from the cache,
+ * then they will be logged in the server log. Exceptions are not thrown - better
+ * to have the system degrade if the cache isn't available, rather than failing.
+ */
+public interface ICacheManager {
+
+ /** Get the String[] version of the objects class name. */
+ public String[] getPartsFromClass(Class clasz);
+
+ /**
+ * Get an item based on key. Works out the Fqn from classNameParts.
+ * If key or classNameParts is null, then null is returned.
+ */
+ public abstract Object getItem(String[] classNameParts, Object key);
+
+ /**
+ * Get an item, of type clasz from the jboss cache, based on key. Works out the Fqn from the supplied Class type.
+ * If key or clasz is null, then null is returned.
+ */
+ public abstract Object getItem(Class clasz, Object key);
+
+ /**
+ * Cache an item, with the supplied key. Works out the Fqn from classNameParts.
+ * Will only cache if all parameters are not null.
+ */
+ public abstract void addItem(String[] classNameParts, Object key,
+ Object item);
+
+ /**
+ * Cache an item, with the supplied key. Works out the Fqn from the clasz.
+ * Will only cache if all parameters are not null.
+ */
+ public abstract void addItem(Class clasz, Object key, Object item);
+
+}
\ No newline at end of file
Index: lams_common/src/java/org/lamsfoundation/lams/commonContext.xml
===================================================================
diff -u -r927823cd79983dee2a5793f9449f6f0bc7a083d8 -rf8ae59adef57f2f13c9d22cca469423d817e4fb9
--- lams_common/src/java/org/lamsfoundation/lams/commonContext.xml (.../commonContext.xml) (revision 927823cd79983dee2a5793f9449f6f0bc7a083d8)
+++ lams_common/src/java/org/lamsfoundation/lams/commonContext.xml (.../commonContext.xml) (revision f8ae59adef57f2f13c9d22cca469423d817e4fb9)
@@ -16,7 +16,9 @@
-
+
+
+
* View Source *
* + * Manually caches the user objects (by user id) in the shared cache. + * Whenever a user object is modified, the cached version must be + * removed. + * * @author Fei Yang, Manpreet Minhas */ public class UserManagementService implements IUserManagementService { + protected Logger log = Logger.getLogger(UserManagementService.class); + private IUserDAO userDAO; private IRoleDAO roleDAO; @@ -78,8 +87,11 @@ protected ILearningDesignDAO learningDesignDAO; + protected ICacheManager cacheManager; + private FlashMessage flashMessage; + private String[] userClassParts = null; /** * @param workspaceFolderDAO * The workspaceFolderDAO to set. @@ -139,13 +151,29 @@ this.authenticationMethodDAO = authenticationMethodDAO; } + public void setCacheManager(ICacheManager cacheManager) { + this.cacheManager = cacheManager; + } + /** + * Tries to get the user from the cache and if that fails then reads it from the database and puts it in the cache. * @see org.lamsfoundation.lams.usermanagement.service.IUserManagementService#getUserById(java.lang.Integer) */ public User getUserById(Integer userId) { - return userDAO.getUserById(userId); - } + if ( this.userClassParts == null ) { + this.userClassParts = cacheManager.getPartsFromClass(User.class); + } + User user = (User) cacheManager.getItem(this.userClassParts, userId); + if ( user == null ) { + user = userDAO.getUserById(userId); + if ( user != null ) { + cacheManager.addItem(this.userClassParts,userId,user); + } + } + return user; + } + /** * @see org.lamsfoundation.lams.usermanagement.service.IUserManagementService#getUserByLogin(java.lang.String) */ @@ -550,5 +578,6 @@ + organisationID + " exists", FlashMessage.ERROR); return flashMessage.serializeMessage(); - } + } + } Index: lams_common/src/java/org/lamsfoundation/lams/util/ConfigurationKeys.java =================================================================== diff -u -r816a4020f1ba070c76c2d88aa0b6de1660a14b19 -rf8ae59adef57f2f13c9d22cca469423d817e4fb9 --- lams_common/src/java/org/lamsfoundation/lams/util/ConfigurationKeys.java (.../ConfigurationKeys.java) (revision 816a4020f1ba070c76c2d88aa0b6de1660a14b19) +++ lams_common/src/java/org/lamsfoundation/lams/util/ConfigurationKeys.java (.../ConfigurationKeys.java) (revision f8ae59adef57f2f13c9d22cca469423d817e4fb9) @@ -34,4 +34,7 @@ * Do not set this parameter to true in production. */ public static String ALLOW_MULTIPLE_LOGIN="AllowMultipleLogin"; + /** Turn on the cache debugging listener. Logs whenever an item is added/removed/evicted + * to/from the cache. Not on in production. Must be set to a boolean value */ + public static String USE_CACHE_DEBUG_LISTENER="UseCacheDebugListener"; }