Author: rwatler
Date: Wed Mar  3 19:34:46 2010
New Revision: 918656

URL: http://svn.apache.org/viewvc?rev=918656&view=rev
Log:
Scoped Fragment Property Cache Refactoring
-----------------------------------------------------
- add DBPM cache of user/principal specific scoped fragment properties.
- merge principal and global scoped fragment properties on DBPM access.
- revise DBPM cache notifications to minimize clustered PSML and properties 
cache notifications.
- upgrade ehcache to 1.7.2 to ensure removeQuiet() operations are not 
replicated in clustered environment.
- extend cache test cases to include tests of new scoped fragment properties 
cache operation.


Added:
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/page/impl/DatabasePageManagerCachedFragmentPropertyList.java
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/page/impl/DatabasePageManagerFragmentKeyCacheObject.java
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/page/impl/DatabasePageManagerPrincipalKeyCacheObject.java
Modified:
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/om/page/impl/FragmentPropertyList.java
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/page/impl/DatabasePageManager.java
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/page/impl/DatabasePageManagerCache.java
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/page/impl/DatabasePageManagerCacheObject.java
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/page/impl/TransactionedOperation.java
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/test/java/org/apache/jetspeed/page/cache/DatabasePageManagerServer.java
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/test/java/org/apache/jetspeed/page/cache/TestDatabasePageManagerCache.java
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/test/resources/database-page-manager-base.xml
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/test/resources/database-page-manager.xml
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/test/resources/distributed-ehcache.xml
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/test/resources/ehcache.xml
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/test/resources/log4j-stdout.properties
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/test/resources/log4j.properties
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/test/resources/secure-database-page-manager.xml
    
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/test/resources/secure-permissions-database-page-manager.xml
    
portals/jetspeed-2/portal/trunk/components/jetspeed-portal-site/src/test/resources/cache-test.xml
    
portals/jetspeed-2/portal/trunk/components/jetspeed-portal/src/test/assembly/cache-test.xml
    
portals/jetspeed-2/portal/trunk/components/jetspeed-profiler/src/test/resources/cache-test.xml
    
portals/jetspeed-2/portal/trunk/components/jetspeed-registry/src/test/resources/cache-test.xml
    
portals/jetspeed-2/portal/trunk/components/jetspeed-security/src/test/resources/cache-test.xml
    
portals/jetspeed-2/portal/trunk/components/jetspeed-sso/src/test/resources/cache-test.xml
    portals/jetspeed-2/portal/trunk/etc/import/assembly/import-page-manager.xml
    
portals/jetspeed-2/portal/trunk/jetspeed-portal-resources/src/main/resources/assembly/cache.xml
    
portals/jetspeed-2/portal/trunk/jetspeed-portal-resources/src/main/resources/assembly/page-manager.xml
    
portals/jetspeed-2/portal/trunk/jetspeed-portal-resources/src/main/resources/db-ojb/distributed-ehcache.xml
    
portals/jetspeed-2/portal/trunk/jetspeed-portal-resources/src/main/resources/db-ojb/ehcache.xml

Modified: 
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/om/page/impl/FragmentPropertyList.java
URL: 
http://svn.apache.org/viewvc/portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/om/page/impl/FragmentPropertyList.java?rev=918656&r1=918655&r2=918656&view=diff
==============================================================================
--- 
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/om/page/impl/FragmentPropertyList.java
 (original)
+++ 
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/om/page/impl/FragmentPropertyList.java
 Wed Mar  3 19:34:46 2010
@@ -182,6 +182,18 @@
         }
         return null;
     }
+    
+    /**
+     * Clear all transient properties.
+     */
+    public synchronized void clearProperties()
+    {
+        properties.clear();
+        if (removedProperties != null)
+        {
+            removedProperties.clear();
+        }
+    }
 
     /**
      * Recycle removed property.

Modified: 
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/page/impl/DatabasePageManager.java
URL: 
http://svn.apache.org/viewvc/portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/page/impl/DatabasePageManager.java?rev=918656&r1=918655&r2=918656&view=diff
==============================================================================
--- 
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/page/impl/DatabasePageManager.java
 (original)
+++ 
portals/jetspeed-2/portal/trunk/components/jetspeed-page-manager/src/main/java/org/apache/jetspeed/page/impl/DatabasePageManager.java
 Wed Mar  3 19:34:46 2010
@@ -18,6 +18,7 @@
 
 import java.security.AccessController;
 import java.security.Principal;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -117,6 +118,9 @@
 import org.apache.ojb.broker.query.QueryByCriteria;
 import org.apache.ojb.broker.query.QueryFactory;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * DatabasePageManager
  * 
@@ -126,6 +130,8 @@
  */
 public class DatabasePageManager extends InitablePersistenceBrokerDaoSupport 
implements PageManager
 {
+    private static Logger log = 
LoggerFactory.getLogger(DatabasePageManager.class);
+    
     private static ThreadLocal fragmentPropertyListsCache = new ThreadLocal();
     
     private static Map modelClasses = new HashMap();
@@ -166,11 +172,12 @@
     
     private PageManager pageManagerProxy;
 
-    public DatabasePageManager(String repositoryPath, IdGenerator generator, 
boolean isPermissionsSecurity, boolean isConstraintsSecurity, JetspeedCache 
oidCache, JetspeedCache pathCache, JetspeedCache propertiesCache, JetspeedCache 
propertiesPathCache)
+    public DatabasePageManager(String repositoryPath, IdGenerator generator, 
boolean isPermissionsSecurity, boolean isConstraintsSecurity, JetspeedCache 
oidCache, JetspeedCache pathCache,
+                               JetspeedCache propertiesCache, JetspeedCache 
propertiesPathCache, JetspeedCache principalPropertiesCache, JetspeedCache 
principalPropertiesPathCache)
     {
         super(repositoryPath);
         delegator = new DelegatingPageManager(generator, 
isPermissionsSecurity, isConstraintsSecurity, modelClasses);
-        DatabasePageManagerCache.cacheInit(oidCache, pathCache, 
propertiesCache, propertiesPathCache, this);
+        DatabasePageManagerCache.cacheInit(oidCache, pathCache, 
propertiesCache, propertiesPathCache, principalPropertiesCache, 
principalPropertiesPathCache, this);
     }
 
     /**
@@ -2561,11 +2568,11 @@
         if (pages.length > 0 && pages[0].getPath().equals("/tx__test1.psml"))
         {
             // for tx testing
-            System.out.println("Adding first page");
+            log.debug("Adding first page");
             this.updatePage(pages[0]);
-            System.out.println("Adding second page");
+            log.debug("Adding second page");
             this.updatePage(pages[1]);
-            System.out.println("About to throw ex");
+            log.debug("About to throw ex");
             throw new NodeException("Its gonna blow captain!");
         }
         for (int ix = 0; ix < pages.length; ix++)
@@ -2663,41 +2670,32 @@
     public FragmentPropertyList 
getFragmentPropertyList(BaseFragmentElementImpl baseFragmentElementImpl, 
FragmentPropertyList transientList)
     {
         // access thread local fragment property lists cache
-        String cacheKey = 
getFragmentPropertyListCacheKey(baseFragmentElementImpl);
+        String fragmentKey = 
getFragmentPropertyListFragmentKey(baseFragmentElementImpl);
+        Subject subject = JSSubject.getSubject(AccessController.getContext());
+        Principal userPrincipal = ((subject != null) ? 
SubjectHelper.getBestPrincipal(subject, User.class) : null);
+        String fragmentListKey = getFragmentPropertyListKey(fragmentKey, 
userPrincipal);
         Map threadLocalCache = (Map)fragmentPropertyListsCache.get();
+        FragmentPropertyList list = ((threadLocalCache != null) ? 
(FragmentPropertyList)threadLocalCache.get(fragmentListKey) : null);
 
-        // get cached persistent list
-        FragmentPropertyList list = ((threadLocalCache != null) ? 
(FragmentPropertyList)threadLocalCache.get(cacheKey) : null);
+        // get and cache persistent list
         if (list == null)
         {
-            // lookup fragment property list in cache
-            list = 
DatabasePageManagerCache.fragmentPropertyListCacheLookup(cacheKey);
-            
-            // save fragment property list in thread local cache
-            if (list != null)
+            // get cached fragment property list components or
+            // query from database if not cached and cache
+            DatabasePageManagerCachedFragmentPropertyList 
globalFragmentPropertyList = 
DatabasePageManagerCache.fragmentPropertyListCacheLookup(fragmentKey);
+            if (globalFragmentPropertyList == null)
             {
-                if (threadLocalCache == null)
-                {
-                    threadLocalCache = new HashMap();
-                    fragmentPropertyListsCache.set(threadLocalCache);
-                }
-                threadLocalCache.put(cacheKey, list);
+                globalFragmentPropertyList = new 
DatabasePageManagerCachedFragmentPropertyList(baseFragmentElementImpl.getBaseFragmentsElement().getPath());
+                Criteria filter = new Criteria();
+                filter.addEqualTo("fragment", new 
Integer(baseFragmentElementImpl.getIdentity()));
+                filter.addIsNull("scope");
+                QueryByCriteria query = 
QueryFactory.newQuery(FragmentPropertyImpl.class, filter);
+                Collection fragmentProperties = 
getPersistenceBrokerTemplate().getCollectionByQuery(query);
+                globalFragmentPropertyList.addAll(fragmentProperties);
+                
DatabasePageManagerCache.fragmentPropertyListCacheAdd(fragmentKey, 
globalFragmentPropertyList, false);
             }
-        }
-        if (list == null)
-        {
-            // use transient list or create new fragment property list
-            list = ((transientList != null) ? transientList : new 
FragmentPropertyList(baseFragmentElementImpl));
-            
-            // build fragment properties database query
-            Criteria filter = new Criteria();
-            filter.addEqualTo("fragment", new 
Integer(baseFragmentElementImpl.getIdentity()));
-            Criteria scopesFilter = new Criteria();
-            Criteria globalScopeFilter = new Criteria();
-            globalScopeFilter.addIsNull("scope");
-            scopesFilter.addOrCriteria(globalScopeFilter);
-            // add scopes for current user, groups, and roles
-            Subject subject = 
JSSubject.getSubject(AccessController.getContext());
+            Map principalFragmentPropertyLists = null;
+            DatabasePageManagerCachedFragmentPropertyList 
userFragmentPropertyList = null;
             if (subject != null)
             {
                 if (GROUP_AND_ROLE_PROPERTY_SCOPES_ENABLED)
@@ -2707,61 +2705,116 @@
                     while (principalsIter.hasNext())
                     {
                         Principal principal = (Principal)principalsIter.next();
+                        String principalScope = null;
                         if (principal instanceof User)
                         {
-                            Criteria userScopeFilter = new Criteria();
-                            userScopeFilter.addEqualTo("scope", 
USER_PROPERTY_SCOPE);
-                            userScopeFilter.addEqualTo("scopeValue", 
principal.getName());
-                            scopesFilter.addOrCriteria(userScopeFilter);
+                            principalScope = USER_PROPERTY_SCOPE;
                         }
                         else if (principal instanceof Group)
                         {
-                            Criteria groupScopeFilter = new Criteria();
-                            groupScopeFilter.addEqualTo("scope", 
GROUP_PROPERTY_SCOPE);
-                            groupScopeFilter.addEqualTo("scopeValue", 
principal.getName());
-                            scopesFilter.addOrCriteria(groupScopeFilter);
+                            principalScope = GROUP_PROPERTY_SCOPE;
                         }
                         else if (principal instanceof Role)
                         {
-                            Criteria roleScopeFilter = new Criteria();
-                            roleScopeFilter.addEqualTo("scope", 
ROLE_PROPERTY_SCOPE);
-                            roleScopeFilter.addEqualTo("scopeValue", 
principal.getName());
-                            scopesFilter.addOrCriteria(roleScopeFilter);
+                            principalScope = ROLE_PROPERTY_SCOPE;
+                        }
+                        if (principalScope != null)
+                        {
+                            String principalKey = 
getFragmentPropertyListPrincipalKey(principalScope, principal.getName());
+                            DatabasePageManagerCachedFragmentPropertyList 
principalFragmentPropertyList = 
DatabasePageManagerCache.principalFragmentPropertyListCacheLookup(principalKey);
+                            if (principalFragmentPropertyList == null)
+                            {
+                                principalFragmentPropertyList = new 
DatabasePageManagerCachedFragmentPropertyList(principalScope, principalKey);
+                                Criteria filter = new Criteria();
+                                filter.addEqualTo("scope", principalScope);
+                                filter.addEqualTo("scopeValue", 
principal.getName());
+                                QueryByCriteria query = 
QueryFactory.newQuery(FragmentPropertyImpl.class, filter);
+                                Collection fragmentProperties = 
getPersistenceBrokerTemplate().getCollectionByQuery(query);
+                                
principalFragmentPropertyList.addAll(fragmentProperties);
+                                
DatabasePageManagerCache.principalFragmentPropertyListCacheAdd(principalKey, 
principalFragmentPropertyList, false);
+                            }
+                            if (principalFragmentPropertyList != null)
+                            {
+                                if (principalFragmentPropertyLists == null)
+                                {
+                                    principalFragmentPropertyLists = new 
HashMap();
+                                }
+                                
principalFragmentPropertyLists.put(principalKey, principalFragmentPropertyList);
+                            }
                         }
                     }
                 }
-                else
+                else if (userPrincipal != null)
                 {
-                    Principal userPrincipal = 
SubjectHelper.getBestPrincipal(subject, User.class);
-                    if (userPrincipal != null)
+                    String principalKey = 
getFragmentPropertyListPrincipalKey(USER_PROPERTY_SCOPE, 
userPrincipal.getName());
+                    userFragmentPropertyList = 
DatabasePageManagerCache.principalFragmentPropertyListCacheLookup(principalKey);
+                    if (userFragmentPropertyList == null)
                     {
-                        Criteria userScopeFilter = new Criteria();
-                        userScopeFilter.addEqualTo("scope", 
USER_PROPERTY_SCOPE);
-                        userScopeFilter.addEqualTo("scopeValue", 
userPrincipal.getName());
-                        scopesFilter.addOrCriteria(userScopeFilter);
+                        userFragmentPropertyList = new 
DatabasePageManagerCachedFragmentPropertyList(USER_PROPERTY_SCOPE, 
principalKey);
+                        Criteria filter = new Criteria();
+                        filter.addEqualTo("scope", USER_PROPERTY_SCOPE);
+                        filter.addEqualTo("scopeValue", 
userPrincipal.getName());
+                        QueryByCriteria query = 
QueryFactory.newQuery(FragmentPropertyImpl.class, filter);
+                        Collection fragmentProperties = 
getPersistenceBrokerTemplate().getCollectionByQuery(query);
+                        userFragmentPropertyList.addAll(fragmentProperties);
+                        
DatabasePageManagerCache.principalFragmentPropertyListCacheAdd(principalKey, 
userFragmentPropertyList, false);
                     }
                 }
             }
-            filter.addAndCriteria(scopesFilter);
-            // query for fragment properties for list using database query
-            QueryByCriteria query = 
QueryFactory.newQuery(FragmentPropertyImpl.class, filter);
-            Collection fragmentProperties = 
getPersistenceBrokerTemplate().getCollectionByQuery(query);
-            list.getProperties().addAll(fragmentProperties);
-        
-            // save fragment property list in thread local cache
-            if (threadLocalCache == null)
+            
+            // assemble fragment property list instance, (use transient
+            // list or create new fragment property list)
+            list = new FragmentPropertyList(baseFragmentElementImpl);
+            list.getProperties().addAll(globalFragmentPropertyList);
+            if (subject != null)
             {
-                threadLocalCache = new HashMap();
-                fragmentPropertyListsCache.set(threadLocalCache);
+                if (GROUP_AND_ROLE_PROPERTY_SCOPES_ENABLED)
+                {
+                    if (principalFragmentPropertyLists != null)
+                    {                        
+                        Set principals = subject.getPrincipals();
+                        Iterator principalsIter = principals.iterator();
+                        while (principalsIter.hasNext())
+                        {
+                            Principal principal = 
(Principal)principalsIter.next();
+                            String principalScope = null;
+                            if (principal instanceof User)
+                            {
+                                principalScope = USER_PROPERTY_SCOPE;
+                            }
+                            else if (principal instanceof Group)
+                            {
+                                principalScope = GROUP_PROPERTY_SCOPE;
+                            }
+                            else if (principal instanceof Role)
+                            {
+                                principalScope = ROLE_PROPERTY_SCOPE;
+                            }
+                            if (principalScope != null)
+                            {
+                                String principalKey = 
getFragmentPropertyListPrincipalKey(principalScope, principal.getName());
+                                DatabasePageManagerCachedFragmentPropertyList 
principalFragmentPropertyList = 
(DatabasePageManagerCachedFragmentPropertyList)principalFragmentPropertyLists.get(principalKey);
+                                List principalFragmentProperties = 
filterPrincipalFragmentPropertyList(principalFragmentPropertyList, 
baseFragmentElementImpl);
+                                if (principalFragmentProperties != null)
+                                {
+                                    
list.getProperties().addAll(principalFragmentProperties);
+                                }
+                            }
+                        }
+                    }
+                }
+                else if (userFragmentPropertyList != null)
+                {
+                    List userFragmentProperties = 
filterPrincipalFragmentPropertyList(userFragmentPropertyList, 
baseFragmentElementImpl);
+                    if (userFragmentProperties != null)
+                    {
+                        list.getProperties().addAll(userFragmentProperties);
+                    }
+                }
             }
-            threadLocalCache.put(cacheKey, list);
 
-            // save fragment property list in cache
-            DatabasePageManagerCache.fragmentPropertyListCacheAdd(cacheKey, 
list, false, false);
-        }
-        else if (transientList != null)
-        {
-            synchronized (list)
+            // merge results into transient list if specified
+            if ((list != null) && (transientList != null))
             {
                 synchronized (transientList)
                 {
@@ -2786,14 +2839,17 @@
                     }
                     
                     // clear transient list
-                    transientList.getProperties().clear();
-                    List removedProperties = 
transientList.getRemovedProperties();
-                    if (removedProperties != null)
-                    {
-                        removedProperties.clear();
-                    }
+                    transientList.clearProperties();
                 }
             }
+
+            // save fragment property list in thread local cache
+            if (threadLocalCache == null)
+            {
+                threadLocalCache = new HashMap();
+                fragmentPropertyListsCache.set(threadLocalCache);
+            }
+            threadLocalCache.put(fragmentListKey, list);
         }
         return list;
     }
@@ -2811,35 +2867,141 @@
         FragmentPropertyList list = 
getFragmentPropertyList(baseFragmentElementImpl, transientList);
         if (list != null)
         {
+            // get subject
+            Subject subject = 
JSSubject.getSubject(AccessController.getContext());
+            Principal userPrincipal = ((subject != null) ? 
SubjectHelper.getBestPrincipal(subject, User.class) : null);
+            String userPrincipalKey = ((userPrincipal != null) ? 
getFragmentPropertyListPrincipalKey(USER_PROPERTY_SCOPE, 
userPrincipal.getName()) : null);
+            
             // update fragment properties in list in database
             boolean updateAllScopes = ((scope != null) && 
scope.equals(ALL_PROPERTY_SCOPE));
             synchronized (list)
             {
-                // store property objects for add/update
-                boolean update = false;
-                boolean sharedUpdate = false;
-                Iterator propertiesIter = list.getProperties().iterator();
+                // store property objects for add/update and decompose
+                // update into cache updates, (assumes scoped property
+                // extents are fully represented in list).
+                boolean updateTransaction = false;
+                DatabasePageManagerCachedFragmentPropertyList 
globalFragmentPropertyList = null;
+                Map principalPartialFragmentPropertyLists = null;
+                String fragmentKey = 
getFragmentPropertyListFragmentKey(baseFragmentElementImpl);
+                List properties = list.getProperties();
+                List removedProperties = list.getRemovedProperties();
+                
+                // construct scoped properties lists for cache updates from
+                // all properties, (add, update, and remove)
+                List allProperties = new ArrayList(properties);
+                if (removedProperties != null)
+                {
+                    allProperties.addAll(removedProperties);                   
 
+                }
+                Iterator allPropertiesIter = allProperties.iterator();
+                while (allPropertiesIter.hasNext())
+                {
+                    FragmentPropertyImpl property = 
(FragmentPropertyImpl)allPropertiesIter.next();
+                    property.setFragment(baseFragmentElementImpl);
+                    String propertyScope = property.getScope();
+                    String propertyScopeValue = property.getScopeValue();
+                    if (updateAllScopes || ((scope == null) && (propertyScope 
== null)) || ((scope != null) && scope.equals(propertyScope)))
+                    {
+                        // classify property by scopes and create scoped lists
+                        if (propertyScope == null)
+                        {
+                            if (globalFragmentPropertyList == null)
+                            {
+                                globalFragmentPropertyList = new 
DatabasePageManagerCachedFragmentPropertyList(baseFragmentElementImpl.getBaseFragmentsElement().getPath());
+                            }
+                        }
+                        else if ((subject != null) && 
GROUP_AND_ROLE_PROPERTY_SCOPES_ENABLED)
+                        {
+                            boolean subjectHasPrincipal = false;
+                            if (propertyScope.equals(USER_PROPERTY_SCOPE))
+                            {
+                                subjectHasPrincipal = ((userPrincipal != null) 
&& userPrincipal.getName().equals(propertyScopeValue));
+                            }
+                            else if 
(propertyScope.equals(GROUP_PROPERTY_SCOPE))
+                            {
+                                subjectHasPrincipal = 
(SubjectHelper.getPrincipal(subject, Group.class, propertyScopeValue) != null);
+                            }
+                            else if (propertyScope.equals(ROLE_PROPERTY_SCOPE))
+                            {
+                                subjectHasPrincipal = 
(SubjectHelper.getPrincipal(subject, Role.class, propertyScopeValue) != null);
+                            }
+                            if (subjectHasPrincipal)
+                            {
+                                if (principalPartialFragmentPropertyLists == 
null)
+                                {
+                                    principalPartialFragmentPropertyLists = 
new HashMap();
+                                }
+                                String principalKey = 
getFragmentPropertyListPrincipalKey(propertyScope, propertyScopeValue);
+                                DatabasePageManagerCachedFragmentPropertyList 
principalPartialFragmentPropertyList = 
(DatabasePageManagerCachedFragmentPropertyList)principalPartialFragmentPropertyLists.get(principalKey);
+                                if (principalPartialFragmentPropertyList == 
null)
+                                {
+                                    principalPartialFragmentPropertyList = new 
DatabasePageManagerCachedFragmentPropertyList(propertyScope, principalKey);
+                                    
principalPartialFragmentPropertyLists.put(principalKey, 
principalPartialFragmentPropertyList);
+                                }
+                            }
+                        }
+                        else if ((subject != null) && 
propertyScope.equals(USER_PROPERTY_SCOPE))
+                        {
+                            if ((userPrincipal != null) && 
userPrincipal.getName().equals(propertyScopeValue))
+                            {
+                                if (principalPartialFragmentPropertyLists == 
null)
+                                {
+                                    principalPartialFragmentPropertyLists = 
new HashMap();
+                                }
+                                DatabasePageManagerCachedFragmentPropertyList 
principalPartialFragmentPropertyList = 
(DatabasePageManagerCachedFragmentPropertyList)principalPartialFragmentPropertyLists.get(userPrincipalKey);
+                                if (principalPartialFragmentPropertyList == 
null)
+                                {
+                                    principalPartialFragmentPropertyList = new 
DatabasePageManagerCachedFragmentPropertyList(USER_PROPERTY_SCOPE, 
userPrincipalKey);
+                                    
principalPartialFragmentPropertyLists.put(userPrincipalKey, 
principalPartialFragmentPropertyList);
+                                }
+                            }
+                        }
+                    }
+                }
+                
+                // populate properties lists for cache updates and
+                // update persistent properties
+                Iterator propertiesIter = properties.iterator();
                 while (propertiesIter.hasNext())
                 {
                     FragmentPropertyImpl storeProperty = 
(FragmentPropertyImpl)propertiesIter.next();
-                    storeProperty.setFragment(baseFragmentElementImpl);
                     String storePropertyScope = storeProperty.getScope();
+                    String storePropertyScopeValue = 
storeProperty.getScopeValue();
                     if (updateAllScopes || ((scope == null) && 
(storePropertyScope == null)) || ((scope != null) && 
scope.equals(storePropertyScope)))
                     {
-                        // track operation type
-                        if (storeProperty.getIdentity() != 0)
+                        // classify and decompose update into individual 
caches:
+                        // allow update only if scoped properties list created 
above
+                        // exists since the subject matching rules are checked 
there
+                        updateTransaction = (updateTransaction || 
(storeProperty.getIdentity() != 0));
+                        boolean store = false;
+                        if (storePropertyScope == null)
+                        {
+                            if (globalFragmentPropertyList != null)
+                            {
+                                globalFragmentPropertyList.add(storeProperty);
+                                store = true;
+                            }
+                        }
+                        else if (subject != null)
                         {
-                            update = true;
+                            if (principalPartialFragmentPropertyLists != null)
+                            {
+                                String principalKey = 
getFragmentPropertyListPrincipalKey(storePropertyScope, 
storePropertyScopeValue);
+                                DatabasePageManagerCachedFragmentPropertyList 
principalPartialFragmentPropertyList = 
(DatabasePageManagerCachedFragmentPropertyList)principalPartialFragmentPropertyLists.get(principalKey);
+                                if (principalPartialFragmentPropertyList != 
null)
+                                {
+                                    
principalPartialFragmentPropertyList.add(storeProperty);
+                                    store = true;
+                                }
+                            }
                         }
-                        if ((storePropertyScope == null) || 
!storePropertyScope.equals(USER_PROPERTY_SCOPE))
+                        // store persistent property object
+                        if (store)
                         {
-                            sharedUpdate = true;
+                            
getPersistenceBrokerTemplate().store(storeProperty);
                         }
-                        // store property object
-                        getPersistenceBrokerTemplate().store(storeProperty);
                     }
                 }
-                List removedProperties = list.getRemovedProperties();
                 if (removedProperties != null)
                 {
                     Iterator removedPropertiesIter = 
removedProperties.iterator();
@@ -2848,25 +3010,66 @@
                         FragmentPropertyImpl deleteProperty = 
(FragmentPropertyImpl)removedPropertiesIter.next();
                         deleteProperty.setFragment(baseFragmentElementImpl);
                         String deletePropertyScope = deleteProperty.getScope();
+                        String deletePropertyScopeValue = 
deleteProperty.getScopeValue();
                         if (updateAllScopes || ((scope == null) && 
(deletePropertyScope == null)) || ((scope != null) && 
scope.equals(deletePropertyScope)))
                         {
-                            // track operation type
-                            update = true;
-                            if ((deletePropertyScope == null) || 
!deletePropertyScope.equals(USER_PROPERTY_SCOPE))
+                            // classify and decompose delete: allow delete only
+                            // if scoped properties list created above exists
+                            // since the subject matching rules are checked 
there
+                            updateTransaction = true;
+                            boolean delete = false;
+                            if (deletePropertyScope == null)
                             {
-                                sharedUpdate = true;
+                                delete = (globalFragmentPropertyList != null);
+                            }
+                            else if (subject != null)
+                            {
+                                if (principalPartialFragmentPropertyLists != 
null)
+                                {
+                                    String principalKey = 
getFragmentPropertyListPrincipalKey(deletePropertyScope, 
deletePropertyScopeValue);
+                                    delete = 
principalPartialFragmentPropertyLists.containsKey(principalKey);
+                                }
+                            }
+                            // delete persistent property object
+                            if (delete)
+                            {
+                                
getPersistenceBrokerTemplate().delete(deleteProperty);
                             }
-                            // delete property object
-                            
getPersistenceBrokerTemplate().delete(deleteProperty);
                         }
                     }
                 }
                 
                 // interoperate with cache to signal update operations and
                 // record thread transactions
-                String cacheKey = 
getFragmentPropertyListCacheKey(baseFragmentElementImpl);
-                String transactionOperationPath = 
DatabasePageManagerCache.fragmentPropertyListCacheAdd(cacheKey, list, (update 
|| sharedUpdate), sharedUpdate);
-                DatabasePageManagerCache.addTransaction(new 
TransactionedOperation(transactionOperationPath, (update ? 
TransactionedOperation.UPDATE_FRAGMENT_PROPERTIES_OPERATION : 
TransactionedOperation.ADD_FRAGMENT_PROPERTIES_OPERATION)));
+                if (globalFragmentPropertyList != null)
+                {
+                    // cache new global fragment property list
+                    
DatabasePageManagerCache.fragmentPropertyListCacheAdd(fragmentKey, 
globalFragmentPropertyList, true);
+                    DatabasePageManagerCache.addTransaction(new 
TransactionedOperation(fragmentKey, (updateTransaction ? 
TransactionedOperation.UPDATE_FRAGMENT_PROPERTIES_OPERATION : 
TransactionedOperation.ADD_FRAGMENT_PROPERTIES_OPERATION)));
+                }
+                if (principalPartialFragmentPropertyLists != null)
+                {
+                    // update cached principal scoped fragment property lists
+                    Iterator listsIter = 
principalPartialFragmentPropertyLists.entrySet().iterator();
+                    while (listsIter.hasNext())
+                    {
+                        Map.Entry entry = (Map.Entry)listsIter.next();
+                        String principalKey = (String)entry.getKey();
+                        DatabasePageManagerCachedFragmentPropertyList 
principalPartialFragmentPropertyList = 
(DatabasePageManagerCachedFragmentPropertyList)entry.getValue();
+                        // update cached principal scoped fragment property 
list
+                        DatabasePageManagerCachedFragmentPropertyList 
cachedPrincipalFragmentPropertyList = 
DatabasePageManagerCache.principalFragmentPropertyListCacheLookup(principalKey);
+                        if (cachedPrincipalFragmentPropertyList != null)
+                        {
+                            synchronized (cachedPrincipalFragmentPropertyList)
+                            {
+                                
removeAllPrincipalFragmentPropertyList(cachedPrincipalFragmentPropertyList, 
baseFragmentElementImpl);
+                                
cachedPrincipalFragmentPropertyList.addAll(principalPartialFragmentPropertyList);
+                            }
+                            
DatabasePageManagerCache.principalFragmentPropertyListCacheAdd(principalKey, 
cachedPrincipalFragmentPropertyList, true);
+                        }
+                        DatabasePageManagerCache.addTransaction(new 
TransactionedOperation(principalKey, (updateTransaction ? 
TransactionedOperation.UPDATE_PRINCIPAL_FRAGMENT_PROPERTIES_OPERATION : 
TransactionedOperation.ADD_PRINCIPAL_FRAGMENT_PROPERTIES_OPERATION)));
+                    }
+                }
             }
         }
     }
@@ -2880,73 +3083,125 @@
     public void removeFragmentPropertyList(BaseFragmentElementImpl 
baseFragmentElementImpl, FragmentPropertyList transientList)
     {
         // access thread local fragment property lists cache
-        String cacheKey = 
getFragmentPropertyListCacheKey(baseFragmentElementImpl);
+        String fragmentKey = 
getFragmentPropertyListFragmentKey(baseFragmentElementImpl);
+        Subject subject = JSSubject.getSubject(AccessController.getContext());
+        Principal userPrincipal = ((subject != null) ? 
SubjectHelper.getBestPrincipal(subject, User.class) : null);
+        String fragmentListKey = getFragmentPropertyListKey(fragmentKey, 
userPrincipal);
         Map threadLocalCache = (Map)fragmentPropertyListsCache.get();
+        FragmentPropertyList list = ((threadLocalCache != null) ? 
(FragmentPropertyList)threadLocalCache.get(fragmentListKey) : null);
 
         // remove cached persistent list
-        FragmentPropertyList list = ((threadLocalCache != null) ? 
(FragmentPropertyList)threadLocalCache.get(cacheKey) : null);
         if (list != null)
         {
             // remove list from cache
-            threadLocalCache.remove(cacheKey);
+            threadLocalCache.remove(fragmentKey);
             // cleanup list
-            synchronized (list)
-            {
-                list.getProperties().clear();
-                List removedProperties = list.getRemovedProperties();
-                if (removedProperties != null)
-                {
-                    removedProperties.clear();
-                }
-            }
+            list.clearProperties();
         }
-        
         // cleanup transient list
         if (transientList != null)
         {
-            synchronized (transientList)
-            {
-                transientList.getProperties().clear();
-                List removedProperties = transientList.getRemovedProperties();
-                if (removedProperties != null)
-                {
-                    removedProperties.clear();
-                }
-            }
+            transientList.clearProperties();
         }
 
         // remove all fragment properties in list from database
+        Integer fragmentId = new 
Integer(baseFragmentElementImpl.getIdentity());
         Criteria filter = new Criteria();
-        filter.addEqualTo("fragment", new 
Integer(baseFragmentElementImpl.getIdentity()));
+        filter.addEqualTo("fragment", fragmentId);
         QueryByCriteria query = 
QueryFactory.newQuery(FragmentPropertyImpl.class, filter);
         getPersistenceBrokerTemplate().deleteByQuery(query);
         
         // interoperate with cache to signal remove operations
-        String path = 
baseFragmentElementImpl.getBaseFragmentsElement().getPath();
-        DatabasePageManagerCache.fragmentPropertyListCacheRemove(path);
+        DatabasePageManagerCache.fragmentPropertyListCacheRemove(fragmentKey);
+        DatabasePageManagerCache.addTransaction(new 
TransactionedOperation(fragmentKey, 
TransactionedOperation.UPDATE_FRAGMENT_PROPERTIES_OPERATION));
+    }
+    
+    /**
+     * Compute thread local fragment property list key for fragment properties.
+     * 
+     * @param fragmentKey fragment key
+     * @param userPrincipal current subject user principal
+     * @return fragment property list key string
+     */
+    private static String getFragmentPropertyListKey(String fragmentKey, 
Principal userPrincipal)
+    {
+        if (userPrincipal != null)
+        {
+            return fragmentKey+"/"+userPrincipal.getName();
+        }
+        return fragmentKey;
     }
     
     /**
-     * Compute thread local cache key for fragment properties.
+     * Compute fragment key for fragment properties.
      * 
      * @param baseFragmentElementImpl owner of fragment properties
-     * @return key string
+     * @return fragment key string
      */
-    private static String 
getFragmentPropertyListCacheKey(BaseFragmentElementImpl baseFragmentElementImpl)
+    private static String 
getFragmentPropertyListFragmentKey(BaseFragmentElementImpl 
baseFragmentElementImpl)
     {
-        // base key
-        String key = 
baseFragmentElementImpl.getBaseFragmentsElement().getPath()+"/"+baseFragmentElementImpl.getId();
-        // append current user if available
-        Subject subject = JSSubject.getSubject(AccessController.getContext());
-        if (subject != null)
+        return 
baseFragmentElementImpl.getBaseFragmentsElement().getPath()+"/"+baseFragmentElementImpl.getId()+":"+baseFragmentElementImpl.getIdentity();
+    }
+    
+    /**
+     * Compute principal key for fragment properties.
+     * 
+     * @param principalType principal type
+     * @param principalName principal name
+     * @return principal key string
+     */
+    private static String getFragmentPropertyListPrincipalKey(String 
principalType, String principalName)
+    {
+        return principalType+":"+principalName;
+    }
+    
+    /**
+     * Filter principal fragment property list.
+     * 
+     * @param principalFragmentPropertyList principal fragment property list
+     * @param baseFragmentElementImpl fragment property owning fragment
+     * @return fragment property list for owning fragment
+     */
+    private static List 
filterPrincipalFragmentPropertyList(DatabasePageManagerCachedFragmentPropertyList
 principalFragmentPropertyList, BaseFragmentElementImpl baseFragmentElementImpl)
+    {
+        List filteredList = null;
+        synchronized (principalFragmentPropertyList)
+        {
+            for (Iterator iter = principalFragmentPropertyList.iterator(); 
iter.hasNext();)
+            {
+                FragmentPropertyImpl fragmentProperty = 
(FragmentPropertyImpl)iter.next();
+                if 
(((BaseFragmentElementImpl)fragmentProperty.getFragment()).getIdentity() == 
baseFragmentElementImpl.getIdentity())
+                {
+                    if (filteredList == null)
+                    {
+                        filteredList = new ArrayList();
+                    }
+                    filteredList.add(fragmentProperty);
+                }
+            }
+        }
+        return filteredList;
+    }
+    
+    /**
+     * Remove matching principal fragment properties from list.
+     * 
+     * @param principalFragmentPropertyList principal fragment property list
+     * @param baseFragmentElementImpl fragment property owning fragment
+     */
+    private static void 
removeAllPrincipalFragmentPropertyList(DatabasePageManagerCachedFragmentPropertyList
 principalFragmentPropertyList, BaseFragmentElementImpl baseFragmentElementImpl)
+    {
+        synchronized (principalFragmentPropertyList)
         {
-            Principal userPrincipal = SubjectHelper.getBestPrincipal(subject, 
User.class);
-            if (userPrincipal != null)
+            for (Iterator iter = principalFragmentPropertyList.iterator(); 
iter.hasNext();)
             {
-                key = key+"/"+userPrincipal.getName();
+                FragmentPropertyImpl fragmentProperty = 
(FragmentPropertyImpl)iter.next();
+                if 
(((BaseFragmentElementImpl)fragmentProperty.getFragment()).getIdentity() == 
baseFragmentElementImpl.getIdentity())
+                {
+                    iter.remove();
+                }
             }
         }
-        return key;
     }
     
     /**



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to