« Return to Thread: Re:esup-portal-ws Project

LAYOUT_CACHE: Is this an interesting enhancement?

by Drew Wills :: Rate this Message:

Reply to Author | View in Thread

Hey folks,

I'm working at JHU, and we've put together an enhancement to DLM:  the
ability to store users' layouts in a standard, portal managed cache.
Currently users' layouts are stored (at least in DLM) as a member
variable on each user's LayoutManager instance.

This situation means that:
   - User layouts never change until (1) the user makes a manual change,
or (2) the user logs in again
   - There's no way to manage in-memory layout data administratively

With this enhancement, you'd be able to:
   - specify that user layouts should expire and be rebuilt, say, 15 min
after creation or after 10 min of "idle" time (i.e. not used for 10 min)
   - specify that no more than, say, 500 layouts should be held in
memory at one time
   - use JMX to "clear" (drop) all the layouts in a running instance of
uPortal
   - write Java tools that intelligently invalidate individual layouts
(or all layouts) when certain portal events happen

The changes are relatively small & encapsulated, so they're unlikely to
"break" existing features or even custom Java tech that integrates with DLM.

I'm attaching a .patch that shows the delta.

Please share thoughts on whether this enhancement is desirable or even
acceptable.  If there's interest, I'll create the JIRA etc.

drew wills



--
You are currently subscribed to uportal-dev@... as: lists@...
To unsubscribe, change settings or access archives, see http://www.ja-sig.org/wiki/display/JSG/uportal-dev
Index: uportal-impl/src/main/java/org/jasig/portal/layout/dlm/DistributedLayoutManager.java
===================================================================
--- uportal-impl/src/main/java/org/jasig/portal/layout/dlm/DistributedLayoutManager.java (revision 6156)
+++ uportal-impl/src/main/java/org/jasig/portal/layout/dlm/DistributedLayoutManager.java (working copy)
@@ -90,7 +90,7 @@
      */
     static final String FOLDER_LABEL_POLICY = "FolderLabelPolicy";
     
-    protected Document userLayoutDocument=null;
+    private final Map<String,Document> layoutCache = LayoutCachingService.getInstance().getLayoutCache();
     
     protected static Random rnd=new Random();
     protected String cacheKey="initialKey";
@@ -226,7 +226,8 @@
     }
 
     private void setUserLayoutDOM(Document doc) {
-        this.userLayoutDocument = doc;
+
+     layoutCache.put(owner.getUserName(), doc);
         this.updateCacheKey();
 
         // determine if this is a layout fragment by looking at the root node
@@ -243,6 +244,7 @@
         if (labelPolicy != null) {
             labelPolicy.coordinateFolderLabels(owner.getID(), isFragmentOwner, doc);
         }
+        
     }
     private int domRequests = 0;
 
@@ -261,7 +263,7 @@
             {
                 LOG.debug("domRequest: " + (domRequests++));
             }
-            Document userLayoutDocument = this.userLayoutDocument;
+            Document userLayoutDocument = layoutCache.get(owner.getUserName());
             if ( null == userLayoutDocument )
             {
                 IUserLayoutStore layoutStore = getLayoutStore();
@@ -407,7 +409,7 @@
         try {
             //Clear the loaded document first if this is a forced reload
             if (reload) {
-                this.userLayoutDocument = null;
+             layoutCache.remove(owner.getUserName());
             }
             
             uli=getUserLayoutDOM();
@@ -1507,7 +1509,7 @@
         }
         //this.markedUserLayout=null;
         this.updateCacheKey();
-        this.userLayoutDocument=doc;
+        layoutCache.put(owner.getUserName(), doc);
     }
 
     /* Returns the ID attribute of the root folder of the layout. This folder
@@ -1689,7 +1691,7 @@
             // so we need to refresh our local copy of their layout
             if (person == owner)
             {
-                this.userLayoutDocument = null;
+             layoutCache.remove(owner.getUserName());
                 updateCacheKey();
                 getUserLayoutDOM();
             }
Index: uportal-impl/src/main/java/org/jasig/portal/layout/dlm/LayoutCachingService.java
===================================================================
--- uportal-impl/src/main/java/org/jasig/portal/layout/dlm/LayoutCachingService.java (revision 0)
+++ uportal-impl/src/main/java/org/jasig/portal/layout/dlm/LayoutCachingService.java (revision 0)
@@ -0,0 +1,120 @@
+/**
+ * Copyright 2008 The JA-SIG Collaborative.  All rights reserved.
+ * See license distributed with this file and
+ * available online at http://www.uportal.org/license.html
+ */
+
+package org.jasig.portal.layout.dlm;
+
+import java.util.Map;
+import org.w3c.dom.Document;
+
+import org.springframework.beans.factory.annotation.Required;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jasig.portal.utils.cache.CacheFactory;
+
+/**
+ * Provides caching services for layouts contained in
+ * <code>DistributedLayoutManager</code> instances.  This class is an old-school
+ * singleton whose backing-map is "injected" by a spring context at startup.
+ */
+public final class LayoutCachingService {
+
+ /**
+ * The name of the cache used by <code>LayoutCachingService</code>.  A cache
+ * of this name must be defined within uPortal's <code>'cacheFactory'</code>
+ * bean.
+ */
+ private static final String CACHE_NAME = "org.jasig.portal.layout.dlm.LAYOUT_CACHE";
+
+ /**
+ * Single(ton) instance of this class.
+ */
+ private static LayoutCachingService instance = null;
+
+ /**
+ * "Injected" at startup by the bean container.  This object is typically
+ * defined as the bean with id='cacheFactory' in cacheContext.xml.
+ */
+ private CacheFactory cacheFactory = null;
+
+    private final Log log = LogFactory.getLog(LayoutCachingService.class);
+
+ /*
+ * Public API.
+ */
+    
+    /**
+     * Accessor method or the single(ton) instance of this class.
+     */
+    public static LayoutCachingService getInstance() {
+
+ if (instance == null) {
+ init();
+ }
+
+ return instance;
+
+ }
+
+    /**
+     * Called by the spring IoC container at startup.
+     *
+     * @param cf Ordinarily 'cacheFactory' bean defined in cacheContext.xml
+     */
+ @Required
+ public void setCacheFactory(CacheFactory cf) {
+
+ // Assertions.
+ if (cf == null) {
+ String msg = "Argument 'cpf [CacheFactory]' cannot be null.";
+ throw new IllegalArgumentException(msg);
+ }
+
+ log.debug("INITIALIZING:  Setting cacheFactory.");
+
+ this.cacheFactory = cf;
+
+ }
+
+ /**
+ * Provides clients of <code>LayoutCachingService</code> with access to the
+ * layout cache.
+ *
+ * @return A <code>Map</code> of cached layouts.
+ */
+ public Map<String,Document> getLayoutCache() {
+ return cacheFactory.getCache(CACHE_NAME);
+ }
+
+ /*
+ * Implementation.
+ */
+
+ /**
+ * Private as per classic Singleton pattern.
+ */
+ private LayoutCachingService() {
+ log.debug("INITIALIZING:  Constructing.");
+ }
+
+ /**
+ * Method that creates the single(ton) instance of
+ * <code>LayoutCachingService</code>, synchronized to be sure it only
+ * happens once.
+ */
+ private static synchronized void init() {
+
+ // Make sure we only create one instance...
+ if (instance != null) {
+ // Must have invoked getInstance() w/ 2 threads.
+ return;
+ }
+
+ instance = new LayoutCachingService();
+
+ }
+
+}
Index: uportal-impl/src/main/resources/properties/contexts/cacheContext.xml
===================================================================
--- uportal-impl/src/main/resources/properties/contexts/cacheContext.xml (revision 6156)
+++ uportal-impl/src/main/resources/properties/contexts/cacheContext.xml (working copy)
@@ -43,4 +43,22 @@
         <property name="cacheManagerName" value="uPortal.cacheManager" />
         <property name="configLocation" value="classpath:/properties/ehcache.xml" />
     </bean>
-</beans>
\ No newline at end of file
+    
+    <!--
+     | Service used by DLM to cache Layouts.
+     +-->
+    <bean id="layoutCachingService" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
+        <property name="targetClass" value="org.jasig.portal.layout.dlm.LayoutCachingService" />
+        <property name="targetMethod" value="getInstance" />
+    </bean>
+    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
+        <property name="targetObject" ref="layoutCachingService" />
+        <property name="targetMethod" value="setCacheFactory" />
+        <property name="arguments">
+            <list>
+                <ref bean="cacheFactory"/>
+            </list>
+        </property>
+    </bean>
+
+</beans>
Index: uportal-impl/src/main/resources/properties/ehcache.xml
===================================================================
--- uportal-impl/src/main/resources/properties/ehcache.xml (revision 6156)
+++ uportal-impl/src/main/resources/properties/ehcache.xml (working copy)
@@ -81,6 +81,10 @@
                 replicateRemovals=true "/>
     </cache>
 
+    <cache name="org.jasig.portal.layout.dlm.LAYOUT_CACHE"
+        eternal="false" maxElementsInMemory="250" overflowToDisk="false" diskPersistent="false"
+        timeToIdleSeconds="0" timeToLiveSeconds="0" memoryStoreEvictionPolicy="LRU" />
+
     <!-- uPortal IBasicEntity Caches -->
 
     <cache name="org.jasig.portal.ChannelDefinition"

 « Return to Thread: Re:esup-portal-ws Project

LightInTheBox - Buy quality products at wholesale price!