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 [email protected] as: [EMAIL 
PROTECTED]
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"

Reply via email to