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 @@ - + + + @@ -26,12 +28,15 @@ 20 1800 50 - - + org.jboss.hibernate.cache.DeployedTreeCacheProvider + jboss.cache:service=TreeCache + + + @@ -96,6 +101,7 @@ + @@ -195,4 +201,9 @@ 60 + + + jboss.cache:service=TreeCache + + Index: lams_common/src/java/org/lamsfoundation/lams/usermanagement/service/UserManagementService.java =================================================================== diff -u -rfc947ff9a995fcf7fb1ffb39b165340c50140379 -rf8ae59adef57f2f13c9d22cca469423d817e4fb9 --- lams_common/src/java/org/lamsfoundation/lams/usermanagement/service/UserManagementService.java (.../UserManagementService.java) (revision fc947ff9a995fcf7fb1ffb39b165340c50140379) +++ lams_common/src/java/org/lamsfoundation/lams/usermanagement/service/UserManagementService.java (.../UserManagementService.java) (revision f8ae59adef57f2f13c9d22cca469423d817e4fb9) @@ -23,41 +23,50 @@ package org.lamsfoundation.lams.usermanagement.service; import java.io.IOException; -import java.util.Date; -import java.util.List; import java.util.ArrayList; +import java.util.Date; import java.util.Iterator; +import java.util.List; import java.util.Vector; + +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.cache.ICacheManager; import org.lamsfoundation.lams.learningdesign.dao.ILearningDesignDAO; -import org.lamsfoundation.lams.usermanagement.dao.IAuthenticationMethodDAO; -import org.lamsfoundation.lams.usermanagement.dao.IOrganisationDAO; -import org.lamsfoundation.lams.usermanagement.dao.IOrganisationTypeDAO; -import org.lamsfoundation.lams.usermanagement.dao.IUserOrganisationDAO; -import org.lamsfoundation.lams.usermanagement.dao.IUserOrganisationRoleDAO; -import org.lamsfoundation.lams.usermanagement.dao.IUserDAO; -import org.lamsfoundation.lams.usermanagement.dao.IRoleDAO; -import org.lamsfoundation.lams.usermanagement.dao.IWorkspaceDAO; -import org.lamsfoundation.lams.usermanagement.dao.IWorkspaceFolderDAO; +import org.lamsfoundation.lams.usermanagement.AuthenticationMethod; import org.lamsfoundation.lams.usermanagement.Organisation; import org.lamsfoundation.lams.usermanagement.OrganisationType; import org.lamsfoundation.lams.usermanagement.Role; import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.UserOrganisation; import org.lamsfoundation.lams.usermanagement.UserOrganisationRole; -import org.lamsfoundation.lams.usermanagement.AuthenticationMethod; import org.lamsfoundation.lams.usermanagement.Workspace; import org.lamsfoundation.lams.usermanagement.WorkspaceFolder; +import org.lamsfoundation.lams.usermanagement.dao.IAuthenticationMethodDAO; +import org.lamsfoundation.lams.usermanagement.dao.IOrganisationDAO; +import org.lamsfoundation.lams.usermanagement.dao.IOrganisationTypeDAO; +import org.lamsfoundation.lams.usermanagement.dao.IRoleDAO; +import org.lamsfoundation.lams.usermanagement.dao.IUserDAO; +import org.lamsfoundation.lams.usermanagement.dao.IUserOrganisationDAO; +import org.lamsfoundation.lams.usermanagement.dao.IUserOrganisationRoleDAO; +import org.lamsfoundation.lams.usermanagement.dao.IWorkspaceDAO; +import org.lamsfoundation.lams.usermanagement.dao.IWorkspaceFolderDAO; import org.lamsfoundation.lams.util.wddx.FlashMessage; /** *

* 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"; }