diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml
index 06f21ffa6f..629a9ee404 100644
--- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml
+++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml
@@ -892,9 +892,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.alfresco.cache.caveatConfigCache
+
+
+
+
+
+
+
+
+
+
+
+
+ org.alfresco.caveatConfigTransactionalCache
+
+
+
+
+
+
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/caveat/RMCaveatConfigComponentImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/caveat/RMCaveatConfigComponentImpl.java
index 09a94de97a..60781a2f83 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/caveat/RMCaveatConfigComponentImpl.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/caveat/RMCaveatConfigComponentImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2011 Alfresco Software Limited.
+ * Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -22,18 +22,22 @@ import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.caveat.RMListOfValuesConstraint.MatchLogic;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
+import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.content.ContentServicePolicies;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.node.NodeServicePolicies;
@@ -97,16 +101,25 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
private static final QName DATATYPE_TEXT = DataTypeDefinition.TEXT;
+ /**
+ * Lock objects
+ */
+ private ReadWriteLock lock = new ReentrantReadWriteLock();
+ private Lock readLock = lock.readLock();
+ private Lock writeLock = lock.writeLock();
/*
- * Caveat Config
+ * Caveat Config (Shared) config
* first string is property name
* second string is authority name (user or group full name)
* third string is list of values of property
- */
+ */
+ private SimpleCache>> caveatConfig;
- // TODO - convert to SimpleCache to be cluster-aware (for dynamic changes to caveat config across a cluster)
- private Map>> caveatConfig = new ConcurrentHashMap>>(2);
+ public void setCaveatConfig(SimpleCache>> caveatConfig)
+ {
+ this.caveatConfig = caveatConfig;
+ }
public void setPolicyComponent(PolicyComponent policyComponent)
{
@@ -252,6 +265,12 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
validateAndReset(childAssocRef.getChildRef());
}
+ /**
+ * Validate the caveat config and optionally update the cache.
+ *
+ * @param nodeRef The nodeRef of the config
+ * @param updateCache Set to true
to update the cache
+ */
@SuppressWarnings("unchecked")
protected void validateAndReset(NodeRef nodeRef)
{
@@ -409,15 +428,29 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
}
}
- // Valid, so update
- caveatConfig.clear();
-
- for (Map.Entry conEntry : caveatConfigMap.entrySet())
+ try
{
- String conStr = conEntry.getKey();
- Map> caveatMap = (Map>)conEntry.getValue();
+ writeLock.lock();
+ // we can't just clear the cache, as all puts to the cache afterwards in this transaction will be ignored
+ // first delete all keys that are now not in the config
+ caveatConfig.getKeys().retainAll(caveatConfigMap.keySet());
- caveatConfig.put(conStr, caveatMap);
+ for (Map.Entry conEntry : caveatConfigMap.entrySet())
+ {
+ String conStr = conEntry.getKey();
+ Map> caveatMap = (Map>)conEntry.getValue();
+
+ Map> cacheValue = caveatConfig.get(conStr);
+ if (cacheValue == null || !cacheValue.equals(caveatMap))
+ {
+ // update the cache
+ caveatConfig.put(conStr, caveatMap);
+ }
+ }
+ }
+ finally
+ {
+ writeLock.unlock();
}
}
catch (JSONException e)
@@ -495,9 +528,19 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
}
// Get list of all caveat qualified names
- public Set getRMConstraintNames()
+ public Collection getRMConstraintNames()
{
- return caveatConfig.keySet();
+ Collection rmConstraintNames = Collections.emptySet();
+ try
+ {
+ readLock.lock();
+ rmConstraintNames = caveatConfig.getKeys();
+ }
+ finally
+ {
+ readLock.unlock();
+ }
+ return Collections.unmodifiableCollection(rmConstraintNames);
}
// Get allowed values for given caveat (for current user)
@@ -510,8 +553,7 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
{
if (! (AuthenticationUtil.isMtEnabled() && AuthenticationUtil.isRunAsUserTheSystemUser()))
{
- // note: userName and userGroupNames must not be null
- Map> caveatConstraintDef = caveatConfig.get(constraintName);
+ // note: userName and userGroupNames must not be null
Set userGroupFullNames = authorityService.getAuthoritiesForUser(userName);
allowedValues = getRMAllowedValues(userName, userGroupFullNames, constraintName);
}
@@ -525,7 +567,16 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
SetallowedValues = new HashSet();
// note: userName and userGroupNames must not be null
- Map> caveatConstraintDef = caveatConfig.get(constraintName);
+ Map> caveatConstraintDef = null;
+ try
+ {
+ readLock.lock();
+ caveatConstraintDef = caveatConfig.get(constraintName);
+ }
+ finally
+ {
+ readLock.unlock();
+ }
if (caveatConstraintDef != null)
{
@@ -547,7 +598,7 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
Listret = new ArrayList();
ret.addAll(allowedValues);
- return ret;
+ return Collections.unmodifiableList(ret);
}
/**
@@ -692,23 +743,53 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
*
* @param listName the name of the RMConstraintList
* @param authorityName
- * @param values
+ * @param value
* @throws AlfrescoRuntimeException if either the list or the authority do not already exist.
*/
public void addRMConstraintListValue(String listName, String authorityName, String value)
{
- Map> members = caveatConfig.get(listName);
- if(members == null)
+ Map> members = null;
+ try
{
- throw new AlfrescoRuntimeException("unable to add to list, list not defined:"+ listName);
+ readLock.lock();
+ members = caveatConfig.get(listName);
+ if(members == null)
+ {
+ throw new AlfrescoRuntimeException("unable to add to list, list not defined:"+ listName);
+ }
+
+ try
+ {
+ readLock.unlock();
+ writeLock.lock();
+ // check again
+ members = caveatConfig.get(listName);
+ if(members == null)
+ {
+ throw new AlfrescoRuntimeException("unable to add to list, list not defined:"+ listName);
+ }
+
+ List values = members.get(authorityName);
+ if(values == null)
+ {
+ throw new AlfrescoRuntimeException("Unable to add to authority in list. Authority not member listName: "+ listName + " authorityName:" +authorityName);
+ }
+ values.add(value);
+
+ caveatConfig.put(listName, members);
+ updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
+ }
+ finally
+ {
+ readLock.lock();
+ writeLock.unlock();
+ }
+
}
- List values = members.get(authorityName);
- if(values == null)
+ finally
{
- throw new AlfrescoRuntimeException("Unable to add to authority in list. Authority not member listName: "+ listName + " authorityName:" +authorityName);
+ readLock.unlock();
}
- values.add(value);
- updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
}
/**
@@ -718,7 +799,24 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
*/
public Map> getListDetails(String listName)
{
- return caveatConfig.get(listName);
+ Map> listDetails = null;
+ try
+ {
+ readLock.lock();
+ listDetails = caveatConfig.get(listName);
+ }
+ finally
+ {
+ readLock.unlock();
+ }
+ if (listDetails == null)
+ {
+ return Collections.emptyMap();
+ }
+ else
+ {
+ return Collections.unmodifiableMap(listDetails);
+ }
}
public List getRMCaveatModels()
@@ -738,20 +836,30 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
*/
public void updateRMConstraintListAuthority(String listName, String authorityName, Listvalues)
{
- Map> members = caveatConfig.get(listName);
- if(members == null)
+ Map> members = null;
+ try
{
- // Create the new list, with the authority name
- Map> constraint = new HashMap>(0);
- constraint.put(authorityName, values);
- caveatConfig.put(listName, constraint);
- }
- else
- {
- members.put(authorityName, values);
- }
+ writeLock.lock();
+ members = caveatConfig.get(listName);
+ if(members == null)
+ {
+ // Create the new list, with the authority name
+ Map> constraint = new HashMap>(0);
+ constraint.put(authorityName, new ArrayList(values));
+ members = constraint;
+ }
+ else
+ {
+ members.put(authorityName, new ArrayList(values));
+ }
- updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
+ caveatConfig.put(listName, members);
+ updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
+ }
+ finally
+ {
+ writeLock.unlock();
+ }
}
/**
@@ -764,57 +872,19 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
public void updateRMConstraintListValue(String listName, String valueName, Listauthorities)
{
- // members contains member, values[]
- Map> members = caveatConfig.get(listName);
-
- if(members == null)
+ Map> members = null;
+ try
{
- // Members List does not exist
- Map> emptyConstraint = new HashMap>(0);
- caveatConfig.put(listName, emptyConstraint);
- members = emptyConstraint;
-
- }
- // authorities contains authority, values[]
- // pivot contains value, members[]
- Map> pivot = PivotUtil.getPivot(members);
+ writeLock.lock();
- // remove all authorities which have this value
- List existingAuthorities = pivot.get(valueName);
- if(existingAuthorities != null)
- {
- for(String authority : existingAuthorities)
+ if(members == null)
{
- List vals = members.get(authority);
- vals.remove(valueName);
+ // Members List does not exist
+ Map> emptyConstraint = new HashMap>(0);
+ caveatConfig.put(listName, emptyConstraint);
+ members = emptyConstraint;
+
}
- }
- // add the new authorities for this value
- for(String authority : authorities)
- {
- List vals = members.get(authority);
- if(vals == null)
- {
- vals= new ArrayList();
- members.put(authority, vals);
- }
- vals.add(valueName);
- }
-
- updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
- }
-
- public void removeRMConstraintListValue(String listName, String valueName)
- {
- // members contains member, values[]
- Map> members = caveatConfig.get(listName);
-
- if(members == null)
- {
- // list does not exist
- }
- else
- {
// authorities contains authority, values[]
// pivot contains value, members[]
Map> pivot = PivotUtil.getPivot(members);
@@ -829,8 +899,82 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
vals.remove(valueName);
}
}
-
- updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
+ // add the new authorities for this value
+ for(String authority : authorities)
+ {
+ List vals = members.get(authority);
+ if(vals == null)
+ {
+ vals= new ArrayList();
+ members.put(authority, vals);
+ }
+ vals.add(valueName);
+ }
+ caveatConfig.put(listName, members);
+ updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
+ }
+ finally
+ {
+ writeLock.unlock();
+ }
+ }
+
+ public void removeRMConstraintListValue(String listName, String valueName)
+ {
+ Map> members = null;
+ try
+ {
+ readLock.lock();
+
+ members = caveatConfig.get(listName);
+ if(members == null)
+ {
+ // list does not exist
+ }
+ else
+ {
+ try
+ {
+ readLock.unlock();
+ writeLock.lock();
+ // check again
+ members = caveatConfig.get(listName);
+ if(members == null)
+ {
+ // list does not exist
+ }
+ else
+ {
+ // authorities contains authority, values[]
+ // pivot contains value, members[]
+ Map> pivot = PivotUtil.getPivot(members);
+
+ // remove all authorities which have this value
+ List existingAuthorities = pivot.get(valueName);
+ if(existingAuthorities != null)
+ {
+ for(String authority : existingAuthorities)
+ {
+ List vals = members.get(authority);
+ vals.remove(valueName);
+ }
+ caveatConfig.put(listName, members);
+ }
+ }
+
+ updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
+ }
+ finally
+ {
+ readLock.lock();
+ writeLock.unlock();
+ }
+
+ }
+ }
+ finally
+ {
+ readLock.unlock();
}
}
@@ -843,26 +987,37 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
*/
public void removeRMConstraintListAuthority(String listName, String authorityName)
{
- Map> members = caveatConfig.get(listName);
- if(members != null)
+ Map> members = null;
+ try
{
- members.remove(listName);
+ writeLock.lock();
+ members = caveatConfig.get(listName);
+ if(members != null)
+ {
+ members.remove(listName);
+ }
+
+ caveatConfig.put(listName, members);
+ updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
+
}
-
- updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
- }
+ finally
+ {
+ writeLock.unlock();
+ }
+}
/**
* @param config the configuration to convert
* @return a String containing the JSON representation of the configuration.
*/
- private String convertToJSONString(Map>> config)
+ private String convertToJSONString(SimpleCache>> config)
{
JSONObject obj = new JSONObject();
try
{
- Set listNames = config.keySet();
+ Collection listNames = config.getKeys();
for(String listName : listNames)
{
Map> members = config.get(listName);
@@ -932,14 +1087,30 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon
public void deleteRMConstraint(String listName)
{
- caveatConfig.remove(listName);
- updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
+ try
+ {
+ writeLock.lock();
+ caveatConfig.remove(listName);
+ updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
+ }
+ finally
+ {
+ writeLock.unlock();
+ }
}
public void addRMConstraint(String listName)
{
- Map> emptyConstraint = new HashMap>(0);
- caveatConfig.put(listName, emptyConstraint);
- updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
+ try
+ {
+ writeLock.lock();
+ Map> emptyConstraint = new HashMap>(0);
+ caveatConfig.put(listName, emptyConstraint);
+ updateOrCreateCaveatConfig(convertToJSONString(caveatConfig));
+ }
+ finally
+ {
+ writeLock.unlock();
+ }
}
}