diff --git a/config/alfresco/avm-services-context.xml b/config/alfresco/avm-services-context.xml
index f335103458..9a8a048ba6 100644
--- a/config/alfresco/avm-services-context.xml
+++ b/config/alfresco/avm-services-context.xml
@@ -154,17 +154,7 @@
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/config/alfresco/cache-context.xml b/config/alfresco/cache-context.xml
index ed811bcd2c..6218260b5d 100644
--- a/config/alfresco/cache-context.xml
+++ b/config/alfresco/cache-context.xml
@@ -423,42 +423,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
- org.alfresco.repo.avm.lookupSharedCache
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- org.alfresco.repo.avm.lookupTransactionalCache
-
-
- 100
-
-
-
-
diff --git a/config/alfresco/ehcache-default.xml b/config/alfresco/ehcache-default.xml
index 84f1057c32..a5e893385b 100644
--- a/config/alfresco/ehcache-default.xml
+++ b/config/alfresco/ehcache-default.xml
@@ -207,15 +207,17 @@
eternal="true"
overflowToDisk="false"
/>
+
+
diff --git a/config/alfresco/extension/avm-lookup-cache-context.xml.sample b/config/alfresco/extension/avm-lookup-cache-context.xml.sample
new file mode 100644
index 0000000000..cd7f13953d
--- /dev/null
+++ b/config/alfresco/extension/avm-lookup-cache-context.xml.sample
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.alfresco.repo.avm.lookupSharedCache
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.alfresco.repo.avm.lookupTransactionalCache
+
+
+ 100
+
+
+
+
diff --git a/config/alfresco/public-services-security-context.xml b/config/alfresco/public-services-security-context.xml
index c62f51a069..722098322f 100644
--- a/config/alfresco/public-services-security-context.xml
+++ b/config/alfresco/public-services-security-context.xml
@@ -702,6 +702,8 @@
org.alfresco.service.cmr.security.AuthorityService.getName=ACL_ALLOW
org.alfresco.service.cmr.security.AuthorityService.authorityExists=ACL_METHOD.ROLE_ADMINISTRATOR
org.alfresco.service.cmr.security.AuthorityService.getAuthoritiesForUser=ACL_METHOD.ROLE_ADMINISTRATOR
+ org.alfresco.service.cmr.security.AuthorityService.setAuthorityDisplayName=ACL_METHOD.ROLE_ADMINISTRATOR
+ org.alfresco.service.cmr.security.AuthorityService.getAuthorityDisplayName=ACL_ALLOW
diff --git a/source/java/org/alfresco/model/ContentModel.java b/source/java/org/alfresco/model/ContentModel.java
index 5c8cacc96f..bda5e4dcf7 100644
--- a/source/java/org/alfresco/model/ContentModel.java
+++ b/source/java/org/alfresco/model/ContentModel.java
@@ -294,6 +294,8 @@ public interface ContentModel
static final QName TYPE_AUTHORITY_CONTAINER = QName.createQName(USER_MODEL_URI, "authorityContainer");
static final QName PROP_AUTHORITY_NAME = QName.createQName(USER_MODEL_URI, "authorityName");
+ static final QName PROP_AUTHORITY_DISPLAY_NAME = QName.createQName(USER_MODEL_URI, "authorityDisplayName");
+
static final QName ASSOC_MEMBER = QName.createQName(USER_MODEL_URI, "member");
static final QName PROP_MEMBERS = QName.createQName(USER_MODEL_URI, "members");
diff --git a/source/java/org/alfresco/repo/avm/LookupCache.java b/source/java/org/alfresco/repo/avm/LookupCache.java
index ec2dc7fc89..b507e7c74c 100644
--- a/source/java/org/alfresco/repo/avm/LookupCache.java
+++ b/source/java/org/alfresco/repo/avm/LookupCache.java
@@ -1,305 +1,62 @@
-/**
+/*
+ * Copyright (C) 2005-2009 Alfresco Software Limited.
*
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.avm;
-import java.util.ArrayList;
-import java.util.List;
-
import org.alfresco.repo.avm.util.SimplePath;
-import org.alfresco.repo.cache.SimpleCache;
-import org.alfresco.repo.security.permissions.AccessDeniedException;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.util.Pair;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
/**
* All lookup traffic goes through here.
- * @author britt
*/
-public class LookupCache
+public interface LookupCache
{
- private static Log fgLogger = LogFactory.getLog(LookupCache.class);
+
+ public Lookup lookup(AVMStore store, int version, SimplePath path, boolean write, boolean includeDeleted);
- /**
- * The Map of of keys to lookups.
- */
- private SimpleCache fCache;
+ // Following are the cache invalidation calls.
- /**
- * Reference to the Node DAO.
- */
- private AVMNodeDAO fAVMNodeDAO;
+ /**
+ * Called when a simple write operation occurs. This
+ * invalidates all read lookups and all layered lookups.
+ */
+ public void onWrite(String storeName);
- /**
- * Reference to the Store DAO.
- */
- private AVMStoreDAO fAVMStoreDAO;
+ /**
+ * Called when a delete has occurred in a store. This invalidates both
+ * reads and write lookups in that store.
+ */
+ public void onDelete(String storeName);
- /**
- * Make one up.
- */
- public LookupCache()
- {
- }
+ /**
+ * Called when a snapshot occurs in a store. This invalidates write
+ * lookups. Read lookups stay untouched.
+ */
+ public void onSnapshot(String storeName);
- /**
- * Set up the node dao.
- * @param dao The dao to set.
- */
- public void setAvmNodeDAO(AVMNodeDAO dao)
- {
- fAVMNodeDAO = dao;
- }
+ /**
+ * Full reset of cache.
+ */
+ public void reset();
- /**
- * Set the store dao.
- * @param dao The dao to set.
- */
- public void setAvmStoreDAO(AVMStoreDAO dao)
- {
- fAVMStoreDAO = dao;
- }
-
- public void setTransactionalCache(SimpleCache cache)
- {
- fCache = cache;
- }
-
- /**
- * Lookup a path. Try to fulfill the request from the cache.
- * @param store The AVMStore.
- * @param version The versions.
- * @param path The path we are looking up.
- * @param write Whether this is a write lookup.
- * @param includeDeleted
- * @return
- */
- public Lookup lookup(AVMStore store, int version, SimplePath path,
- boolean write, boolean includeDeleted)
- {
- // Create a key object.
- LookupKey key = new LookupKey(version, path, store.getName(), write, includeDeleted);
- // Is it in the cache?
- Lookup found = findInCache(key);
- // TODO Testing.
- // found = null;
- if (found != null)
- {
- if (fgLogger.isDebugEnabled())
- {
- fgLogger.debug("Cache Hit: " + key + ", " + found.getCurrentNode().getId());
- }
- return found;
- }
- // Make up a Lookup to hold the results.
- if (path.size() == 0)
- {
- return null;
- }
- Lookup result = new Lookup(store, store.getName(), version);
- // Grab the root node to start the lookup.
- DirectoryNode dir = null;
- // Versions less than 0 mean get current.
- if (version < 0)
- {
- dir = store.getRoot();
- }
- else
- {
- VersionRoot vRoot = AVMDAOs.Instance().fVersionRootDAO.getByVersionID(store, version);
- if (vRoot != null)
- {
- dir = vRoot.getRoot();
- }
-// dir = fAVMNodeDAO.getAVMStoreRoot(store, version);
- }
- if (dir == null)
- {
- return null;
- }
- dir = (DirectoryNode)AVMNodeUnwrapper.Unwrap(dir);
- // Add an entry for the root.
- result.add(dir, "", true, write);
- dir = (DirectoryNode)result.getCurrentNode();
- if (path.size() == 1 && path.get(0).equals(""))
- {
- fCache.put(key, result);
- return result;
- }
- // Now look up each path element in sequence up to one
- // before the end.
- for (int i = 0; i < path.size() - 1; i++)
- {
- if (!AVMRepository.GetInstance().can(null, dir, PermissionService.READ_CHILDREN))
- {
- throw new AccessDeniedException("Not allowed to read children: " + path.get(i));
- }
- Pair child = dir.lookupChild(result, path.get(i), includeDeleted);
- if (child == null)
- {
- return null;
- }
- // Every element that is not the last needs to be a directory.
- if (child.getFirst().getType() != AVMNodeType.PLAIN_DIRECTORY &&
- child.getFirst().getType() != AVMNodeType.LAYERED_DIRECTORY)
- {
- return null;
- }
- result.add(child.getFirst(), path.get(i), child.getSecond(), write);
- dir = (DirectoryNode)result.getCurrentNode();
- }
- // Now look up the last element.
- if (!AVMRepository.GetInstance().can(null, dir, PermissionService.READ_CHILDREN))
- {
- throw new AccessDeniedException("Not allowed to read children: " + path.get(path.size() - 1));
- }
- Pair child = dir.lookupChild(result, path.get(path.size() - 1),
- includeDeleted);
- if (child == null)
- {
- return null;
- }
- result.add(child.getFirst(), path.get(path.size() - 1), child.getSecond(), write);
- fCache.put(key, result);
- return result;
- }
-
- /**
- * Try to find a match in the cache.
- * @param key The lookup key.
- * @return A valid for this session Lookup or null if not found.
- */
- private synchronized Lookup findInCache(LookupKey key)
- {
- Lookup found = fCache.get(key);
- if (found != null)
- {
- // Get a freshened Lookup.
- Lookup result = new Lookup(found, fAVMNodeDAO, fAVMStoreDAO);
- // Check that nothing horrible is wrong. This should
- // be assertible, but I'll leave the check in for now.
- if (!result.isValid())
- {
- fgLogger.error("Invalid entry in cache: " + key);
- return null;
- }
- return result;
- }
- // Alternatively for a read lookup a write can match.
- if (!key.isWrite())
- {
- // Make a copy of the key and set it to 'write'
- LookupKey newKey = new LookupKey(key);
- newKey.setWrite(true);
- found = fCache.get(newKey);
- if (found != null)
- {
- // We found it. Make a freshened copy of the Lookup.
- Lookup result = new Lookup(found, fAVMNodeDAO, fAVMStoreDAO);
- // Check for badness. This should be assertible but I'll
- // leave the check in for now.
- if (!result.isValid())
- {
- fgLogger.error("Invalid entry in cache: " + newKey);
- return null;
- }
- return result;
- }
- }
- return null;
- }
-
- // Following are the cache invalidation calls.
-
- /**
- * Called when a simple write operation occurs. This
- * invalidates all read lookups and all layered lookups.
- */
- public synchronized void onWrite(String storeName)
- {
- // Invalidate if it's a read lookup in the store, or
- // any read lookup is it's layered.
- List keys = new ArrayList();
- for (LookupKey key : fCache.getKeys())
- {
- keys.add(key);
- }
- for (LookupKey key : keys)
- {
- Lookup value = fCache.get(key);
- if ((key.getStoreName().equals(storeName) &&
- !key.isWrite()) || value == null ||
- (!key.isWrite() && value.isLayered()))
- {
- if (fgLogger.isDebugEnabled())
- {
- fgLogger.debug("Invalidating: " + key + ", " + (value != null ? value.getCurrentNode().getId() : -2));
- }
- fCache.remove(key);
- }
- }
- }
-
- /**
- * Called when a delete has occurred in a store. This invalidates both
- * reads and write lookups in that store.
- */
- public synchronized void onDelete(String storeName)
- {
- // Invalidate any entries that are in the store or are layered lookups.
- List keys = new ArrayList();
- for (LookupKey key : fCache.getKeys())
- {
- keys.add(key);
- }
- for (LookupKey key : keys)
- {
- Lookup value = fCache.get(key);
- if (key.getStoreName().equals(storeName) ||
- value == null || value.isLayered())
- {
- if (fgLogger.isDebugEnabled())
- {
- fgLogger.debug("Invalidating: " + key + ", " + (value != null ? value.getCurrentNode().getId() : -2));
- }
- fCache.remove(key);
- }
- }
- }
-
- /**
- * Called when a snapshot occurs in a store. This invalidates write
- * lookups. Read lookups stay untouched.
- */
- public synchronized void onSnapshot(String storeName)
- {
- // Invalidate any entries that in the store and writes or
- // any layered lookups.
- List keys = new ArrayList();
- for (LookupKey key : fCache.getKeys())
- {
- keys.add(key);
- }
- for (LookupKey key : keys)
- {
- Lookup value = fCache.get(key);
- if ((key.getStoreName().equals(storeName) &&
- key.isWrite()) ||
- value == null || value.isLayered())
- {
- if (fgLogger.isDebugEnabled())
- {
- fgLogger.debug("Invalidating: " + key + ", " + (value != null ? value.getCurrentNode().getId() : -2));
- }
- fCache.remove(key);
- }
- }
- }
-
- public synchronized void reset()
- {
- fCache.clear();
- }
}
diff --git a/source/java/org/alfresco/repo/avm/NOOPLookupCache.java b/source/java/org/alfresco/repo/avm/NOOPLookupCache.java
new file mode 100644
index 0000000000..64f81c3c47
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/NOOPLookupCache.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2005-2009 Alfresco Software Limited.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.avm;
+
+import org.alfresco.repo.avm.util.SimplePath;
+import org.alfresco.repo.security.permissions.AccessDeniedException;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.util.Pair;
+
+/**
+ * A NO-OP implementation of AVM path lookup cache
+ */
+public class NOOPLookupCache implements LookupCache
+{
+ /**
+ * Make one up.
+ */
+ public NOOPLookupCache()
+ {
+ }
+
+ /**
+ * Lookup a path.
+ *
+ * @param store The AVMStore.
+ * @param version The versions.
+ * @param path The path we are looking up.
+ * @param write Whether this is a write lookup.
+ * @param includeDeleted
+ * @return
+ */
+ public Lookup lookup(AVMStore store, int version, SimplePath path,
+ boolean write, boolean includeDeleted)
+ {
+ // Make up a Lookup to hold the results.
+ if (path.size() == 0)
+ {
+ return null;
+ }
+ Lookup result = new Lookup(store, store.getName(), version);
+ // Grab the root node to start the lookup.
+ DirectoryNode dir = null;
+ // Versions less than 0 mean get current.
+ if (version < 0)
+ {
+ dir = store.getRoot();
+ }
+ else
+ {
+ VersionRoot vRoot = AVMDAOs.Instance().fVersionRootDAO.getByVersionID(store, version);
+ if (vRoot != null)
+ {
+ dir = vRoot.getRoot();
+ }
+// dir = fAVMNodeDAO.getAVMStoreRoot(store, version);
+ }
+ if (dir == null)
+ {
+ return null;
+ }
+ dir = (DirectoryNode)AVMNodeUnwrapper.Unwrap(dir);
+ // Add an entry for the root.
+ result.add(dir, "", true, write);
+ dir = (DirectoryNode)result.getCurrentNode();
+ if (path.size() == 1 && path.get(0).equals(""))
+ {
+ return result;
+ }
+ // Now look up each path element in sequence up to one
+ // before the end.
+ for (int i = 0; i < path.size() - 1; i++)
+ {
+ if (!AVMRepository.GetInstance().can(null, dir, PermissionService.READ_CHILDREN))
+ {
+ throw new AccessDeniedException("Not allowed to read children: " + path.get(i));
+ }
+ Pair child = dir.lookupChild(result, path.get(i), includeDeleted);
+ if (child == null)
+ {
+ return null;
+ }
+ // Every element that is not the last needs to be a directory.
+ if (child.getFirst().getType() != AVMNodeType.PLAIN_DIRECTORY &&
+ child.getFirst().getType() != AVMNodeType.LAYERED_DIRECTORY)
+ {
+ return null;
+ }
+ result.add(child.getFirst(), path.get(i), child.getSecond(), write);
+ dir = (DirectoryNode)result.getCurrentNode();
+ }
+ // Now look up the last element.
+ if (!AVMRepository.GetInstance().can(null, dir, PermissionService.READ_CHILDREN))
+ {
+ throw new AccessDeniedException("Not allowed to read children: " + path.get(path.size() - 1));
+ }
+ Pair child = dir.lookupChild(result, path.get(path.size() - 1),
+ includeDeleted);
+ if (child == null)
+ {
+ return null;
+ }
+ result.add(child.getFirst(), path.get(path.size() - 1), child.getSecond(), write);
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.avm.LookupCache#onWrite(java.lang.String)
+ */
+ public void onWrite(String storeName)
+ {
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.avm.LookupCache#onDelete(java.lang.String)
+ */
+ public void onDelete(String storeName)
+ {
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.avm.LookupCache#onSnapshot(java.lang.String)
+ */
+ public void onSnapshot(String storeName)
+ {
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.avm.LookupCache#reset()
+ */
+ public void reset()
+ {
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/avm/TransactionalLookupCache.java b/source/java/org/alfresco/repo/avm/TransactionalLookupCache.java
new file mode 100644
index 0000000000..abcece7207
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/TransactionalLookupCache.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2005-2009 Alfresco Software Limited.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.avm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.alfresco.repo.avm.util.SimplePath;
+import org.alfresco.repo.cache.SimpleCache;
+import org.alfresco.repo.security.permissions.AccessDeniedException;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.util.Pair;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+
+/**
+ * A Transactional? implementation of AVM path lookup cache
+ *
+ * @author britt
+ */
+public class TransactionalLookupCache implements LookupCache, InitializingBean
+{
+ private static Log fgLogger = LogFactory.getLog(TransactionalLookupCache.class);
+ private static Log fgLoggerInit = LogFactory.getLog(TransactionalLookupCache.class.getName() + ".init");
+
+
+ /**
+ * The Map of of keys to lookups.
+ */
+ private SimpleCache fCache;
+
+ /**
+ * Reference to the Node DAO.
+ */
+ private AVMNodeDAO fAVMNodeDAO;
+
+ /**
+ * Reference to the Store DAO.
+ */
+ private AVMStoreDAO fAVMStoreDAO;
+
+ /**
+ * Make one up.
+ */
+ public TransactionalLookupCache()
+ {
+ }
+
+ /**
+ * Set up the node dao.
+ * @param dao The dao to set.
+ */
+ public void setAvmNodeDAO(AVMNodeDAO dao)
+ {
+ fAVMNodeDAO = dao;
+ }
+
+ /**
+ * Set the store dao.
+ * @param dao The dao to set.
+ */
+ public void setAvmStoreDAO(AVMStoreDAO dao)
+ {
+ fAVMStoreDAO = dao;
+ }
+
+ public void setTransactionalCache(SimpleCache cache)
+ {
+ fCache = cache;
+ }
+
+ /* (non-Javadoc)
+ * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
+ */
+ public void afterPropertiesSet() throws Exception
+ {
+ if (fgLoggerInit.isDebugEnabled())
+ fgLoggerInit.debug("Transactional AVM lookup cache initialised");
+ }
+
+ /**
+ * Lookup a path. Try to fulfill the request from the cache.
+ * @param store The AVMStore.
+ * @param version The versions.
+ * @param path The path we are looking up.
+ * @param write Whether this is a write lookup.
+ * @param includeDeleted
+ * @return
+ */
+ public Lookup lookup(AVMStore store, int version, SimplePath path,
+ boolean write, boolean includeDeleted)
+ {
+ // Create a key object.
+ LookupKey key = new LookupKey(version, path, store.getName(), write, includeDeleted);
+ // Is it in the cache?
+ Lookup found = findInCache(key);
+ // TODO Testing.
+ // found = null;
+ if (found != null)
+ {
+ if (fgLogger.isDebugEnabled())
+ {
+ fgLogger.debug("Cache Hit: " + key + ", " + found.getCurrentNode().getId());
+ }
+ return found;
+ }
+ // Make up a Lookup to hold the results.
+ if (path.size() == 0)
+ {
+ return null;
+ }
+ Lookup result = new Lookup(store, store.getName(), version);
+ // Grab the root node to start the lookup.
+ DirectoryNode dir = null;
+ // Versions less than 0 mean get current.
+ if (version < 0)
+ {
+ dir = store.getRoot();
+ }
+ else
+ {
+ VersionRoot vRoot = AVMDAOs.Instance().fVersionRootDAO.getByVersionID(store, version);
+ if (vRoot != null)
+ {
+ dir = vRoot.getRoot();
+ }
+// dir = fAVMNodeDAO.getAVMStoreRoot(store, version);
+ }
+ if (dir == null)
+ {
+ return null;
+ }
+ dir = (DirectoryNode)AVMNodeUnwrapper.Unwrap(dir);
+ // Add an entry for the root.
+ result.add(dir, "", true, write);
+ dir = (DirectoryNode)result.getCurrentNode();
+ if (path.size() == 1 && path.get(0).equals(""))
+ {
+ fCache.put(key, result);
+ return result;
+ }
+ // Now look up each path element in sequence up to one
+ // before the end.
+ for (int i = 0; i < path.size() - 1; i++)
+ {
+ if (!AVMRepository.GetInstance().can(null, dir, PermissionService.READ_CHILDREN))
+ {
+ throw new AccessDeniedException("Not allowed to read children: " + path.get(i));
+ }
+ Pair child = dir.lookupChild(result, path.get(i), includeDeleted);
+ if (child == null)
+ {
+ return null;
+ }
+ // Every element that is not the last needs to be a directory.
+ if (child.getFirst().getType() != AVMNodeType.PLAIN_DIRECTORY &&
+ child.getFirst().getType() != AVMNodeType.LAYERED_DIRECTORY)
+ {
+ return null;
+ }
+ result.add(child.getFirst(), path.get(i), child.getSecond(), write);
+ dir = (DirectoryNode)result.getCurrentNode();
+ }
+ // Now look up the last element.
+ if (!AVMRepository.GetInstance().can(null, dir, PermissionService.READ_CHILDREN))
+ {
+ throw new AccessDeniedException("Not allowed to read children: " + path.get(path.size() - 1));
+ }
+ Pair child = dir.lookupChild(result, path.get(path.size() - 1),
+ includeDeleted);
+ if (child == null)
+ {
+ return null;
+ }
+ result.add(child.getFirst(), path.get(path.size() - 1), child.getSecond(), write);
+ fCache.put(key, result);
+ return result;
+ }
+
+ /**
+ * Try to find a match in the cache.
+ * @param key The lookup key.
+ * @return A valid for this session Lookup or null if not found.
+ */
+ private synchronized Lookup findInCache(LookupKey key)
+ {
+ Lookup found = fCache.get(key);
+ if (found != null)
+ {
+ // Get a freshened Lookup.
+ Lookup result = new Lookup(found, fAVMNodeDAO, fAVMStoreDAO);
+ // Check that nothing horrible is wrong. This should
+ // be assertible, but I'll leave the check in for now.
+ if (!result.isValid())
+ {
+ fgLogger.error("Invalid entry in cache: " + key);
+ return null;
+ }
+ return result;
+ }
+ // Alternatively for a read lookup a write can match.
+ if (!key.isWrite())
+ {
+ // Make a copy of the key and set it to 'write'
+ LookupKey newKey = new LookupKey(key);
+ newKey.setWrite(true);
+ found = fCache.get(newKey);
+ if (found != null)
+ {
+ // We found it. Make a freshened copy of the Lookup.
+ Lookup result = new Lookup(found, fAVMNodeDAO, fAVMStoreDAO);
+ // Check for badness. This should be assertible but I'll
+ // leave the check in for now.
+ if (!result.isValid())
+ {
+ fgLogger.error("Invalid entry in cache: " + newKey);
+ return null;
+ }
+ return result;
+ }
+ }
+ return null;
+ }
+
+ // Following are the cache invalidation calls.
+
+ /**
+ * Called when a simple write operation occurs. This
+ * invalidates all read lookups and all layered lookups.
+ */
+ public synchronized void onWrite(String storeName)
+ {
+ // Invalidate if it's a read lookup in the store, or
+ // any read lookup is it's layered.
+ List keys = new ArrayList();
+ for (LookupKey key : fCache.getKeys())
+ {
+ keys.add(key);
+ }
+ for (LookupKey key : keys)
+ {
+ Lookup value = fCache.get(key);
+ if ((key.getStoreName().equals(storeName) &&
+ !key.isWrite()) || value == null ||
+ (!key.isWrite() && value.isLayered()))
+ {
+ if (fgLogger.isDebugEnabled())
+ {
+ fgLogger.debug("Invalidating: " + key + ", " + (value != null ? value.getCurrentNode().getId() : -2));
+ }
+ fCache.remove(key);
+ }
+ }
+ }
+
+ /**
+ * Called when a delete has occurred in a store. This invalidates both
+ * reads and write lookups in that store.
+ */
+ public synchronized void onDelete(String storeName)
+ {
+ // Invalidate any entries that are in the store or are layered lookups.
+ List keys = new ArrayList();
+ for (LookupKey key : fCache.getKeys())
+ {
+ keys.add(key);
+ }
+ for (LookupKey key : keys)
+ {
+ Lookup value = fCache.get(key);
+ if (key.getStoreName().equals(storeName) ||
+ value == null || value.isLayered())
+ {
+ if (fgLogger.isDebugEnabled())
+ {
+ fgLogger.debug("Invalidating: " + key + ", " + (value != null ? value.getCurrentNode().getId() : -2));
+ }
+ fCache.remove(key);
+ }
+ }
+ }
+
+ /**
+ * Called when a snapshot occurs in a store. This invalidates write
+ * lookups. Read lookups stay untouched.
+ */
+ public synchronized void onSnapshot(String storeName)
+ {
+ // Invalidate any entries that in the store and writes or
+ // any layered lookups.
+ List keys = new ArrayList();
+ for (LookupKey key : fCache.getKeys())
+ {
+ keys.add(key);
+ }
+ for (LookupKey key : keys)
+ {
+ Lookup value = fCache.get(key);
+ if ((key.getStoreName().equals(storeName) &&
+ key.isWrite()) ||
+ value == null || value.isLayered())
+ {
+ if (fgLogger.isDebugEnabled())
+ {
+ fgLogger.debug("Invalidating: " + key + ", " + (value != null ? value.getCurrentNode().getId() : -2));
+ }
+ fCache.remove(key);
+ }
+ }
+ }
+
+ public synchronized void reset()
+ {
+ fCache.clear();
+ }
+}
diff --git a/source/java/org/alfresco/repo/avm/hibernate/AVMStoreDAOHibernate.java b/source/java/org/alfresco/repo/avm/hibernate/AVMStoreDAOHibernate.java
index bd3e2d44b3..3d30eddad4 100644
--- a/source/java/org/alfresco/repo/avm/hibernate/AVMStoreDAOHibernate.java
+++ b/source/java/org/alfresco/repo/avm/hibernate/AVMStoreDAOHibernate.java
@@ -153,7 +153,7 @@ class AVMStoreDAOHibernate extends HibernateDaoSupport implements
/* (non-Javadoc)
* @see org.alfresco.repo.avm.AVMStoreDAO#invalidateCache()
*/
- public synchronized void invalidateCache()
+ public void invalidateCache()
{
fNameCache.clear();
}
diff --git a/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java
index 4a0c0b8472..9e52ddc576 100644
--- a/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java
+++ b/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java
@@ -427,6 +427,12 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions
return;
}
+ // avoid NullPointerException if it was not created
+ if (acl == null)
+ {
+ return;
+ }
+
switch (acl.getAclType())
{
case FIXED:
diff --git a/source/java/org/alfresco/repo/security/authentication/userModel.xml b/source/java/org/alfresco/repo/security/authentication/userModel.xml
index 53b765ad7f..a80e02439c 100644
--- a/source/java/org/alfresco/repo/security/authentication/userModel.xml
+++ b/source/java/org/alfresco/repo/security/authentication/userModel.xml
@@ -90,6 +90,9 @@
d:text
true
+
+
+ d:text
diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityDAO.java b/source/java/org/alfresco/repo/security/authority/AuthorityDAO.java
index 07549210d9..e16f3200a8 100644
--- a/source/java/org/alfresco/repo/security/authority/AuthorityDAO.java
+++ b/source/java/org/alfresco/repo/security/authority/AuthorityDAO.java
@@ -44,8 +44,9 @@ public interface AuthorityDAO
*
* @param parentName
* @param name
+ * @param authorityDisplayName
*/
- void createAuthority(String parentName, String name);
+ void createAuthority(String parentName, String name, String authorityDisplayName);
/**
* Delete an authority.
@@ -122,4 +123,20 @@ public interface AuthorityDAO
*/
public String getAuthorityName(NodeRef authorityRef);
+ /**
+ * Get the display name for an authority
+ *
+ * @param authorityName
+ * @return the display name
+ */
+ String getAuthorityDisplayName(String authorityName);
+
+ /**
+ * Set the display name for an authority
+ *
+ * @param authorityName
+ * @param authorityDisplayName
+ */
+ void setAuthorityDisplayName(String authorityName, String authorityDisplayName);
+
}
diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java b/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java
index f441c0d3e7..ea05ab9c86 100644
--- a/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java
+++ b/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java
@@ -144,10 +144,11 @@ public class AuthorityDAOImpl implements AuthorityDAO
}
}
- public void createAuthority(String parentName, String name)
+ public void createAuthority(String parentName, String name, String authorityDisplayName)
{
HashMap props = new HashMap();
props.put(ContentModel.PROP_AUTHORITY_NAME, name);
+ props.put(ContentModel.PROP_AUTHORITY_DISPLAY_NAME, authorityDisplayName);
if (parentName != null)
{
NodeRef parentRef = getAuthorityOrNull(parentName);
@@ -543,4 +544,30 @@ public class AuthorityDAOImpl implements AuthorityDAO
return name;
}
+ public String getAuthorityDisplayName(String authorityName)
+ {
+ NodeRef ref = getAuthorityOrNull(authorityName);
+ if(ref == null)
+ {
+ return null;
+ }
+ Serializable value = nodeService.getProperty(ref, ContentModel.PROP_AUTHORITY_DISPLAY_NAME);
+ if(value == null)
+ {
+ return null;
+ }
+ return DefaultTypeConverter.INSTANCE.convert(String.class, value);
+ }
+
+ public void setAuthorityDisplayName(String authorityName, String authorityDisplayName)
+ {
+ NodeRef ref = getAuthorityOrNull(authorityName);
+ if(ref == null)
+ {
+ return;
+ }
+ nodeService.setProperty(ref, ContentModel.PROP_AUTHORITY_DISPLAY_NAME, authorityDisplayName);
+
+ }
+
}
diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java b/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java
index 1c45c1f9f0..60e1c4e556 100644
--- a/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java
+++ b/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java
@@ -261,10 +261,7 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
public String createAuthority(AuthorityType type, String parentName, String shortName)
{
- checkTypeIsMutable(type);
- String name = getName(type, shortName);
- authorityDAO.createAuthority(parentName, name);
- return name;
+ return createAuthority(type, parentName, shortName, shortName);
}
public void deleteAuthority(String name)
@@ -334,4 +331,29 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
return authorityDAO.authorityExists(name);
}
+ public String createAuthority(AuthorityType type, String parentName, String shortName, String authorityDisplayName)
+ {
+ checkTypeIsMutable(type);
+ String name = getName(type, shortName);
+ authorityDAO.createAuthority(parentName, name, authorityDisplayName);
+ return name;
+ }
+
+ public String getAuthorityDisplayName(String name)
+ {
+ String displayName = authorityDAO.getAuthorityDisplayName(name);
+ if(displayName == null)
+ {
+ displayName = getShortName(name);
+ }
+ return displayName;
+ }
+
+ public void setAuthorityDisplayName(String authorityName, String authorityDisplayName)
+ {
+ AuthorityType type = AuthorityType.getAuthorityType(authorityName);
+ checkTypeIsMutable(type);
+ authorityDAO.setAuthorityDisplayName(authorityName, authorityDisplayName);
+ }
+
}
diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java b/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java
index ef147aeb40..80360364d9 100644
--- a/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java
+++ b/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java
@@ -867,4 +867,30 @@ public class AuthorityServiceTest extends TestCase
properties.put(ContentModel.PROP_ORGID, orgId);
return properties;
}
+
+ public void testAuthorityDisplayNames()
+ {
+ String authOne = pubAuthorityService.createAuthority(AuthorityType.GROUP, null, "One");
+ assertEquals(pubAuthorityService.getAuthorityDisplayName(authOne), "One");
+ pubAuthorityService.setAuthorityDisplayName(authOne, "Selfish Crocodile");
+ assertEquals(pubAuthorityService.getAuthorityDisplayName(authOne), "Selfish Crocodile");
+
+ String authTwo = pubAuthorityService.createAuthority(AuthorityType.GROUP, null, "Two", "Lamp posts");
+ assertEquals(pubAuthorityService.getAuthorityDisplayName(authTwo), "Lamp posts");
+ pubAuthorityService.setAuthorityDisplayName(authTwo, "Happy Hippos");
+ assertEquals(pubAuthorityService.getAuthorityDisplayName(authTwo), "Happy Hippos");
+
+ assertEquals(pubAuthorityService.getAuthorityDisplayName("GROUP_Loon"), "Loon");
+ assertEquals(pubAuthorityService.getAuthorityDisplayName("ROLE_Gibbon"), "Gibbon");
+ assertEquals(pubAuthorityService.getAuthorityDisplayName("Monkey"), "Monkey");
+
+ authenticationComponent.setCurrentUser("andy");
+ assertEquals(pubAuthorityService.getAuthorityDisplayName(authOne), "Selfish Crocodile");
+ assertEquals(pubAuthorityService.getAuthorityDisplayName(authTwo), "Happy Hippos");
+ assertEquals(pubAuthorityService.getAuthorityDisplayName("GROUP_Loon"), "Loon");
+ assertEquals(pubAuthorityService.getAuthorityDisplayName("GROUP_Loon"), "Loon");
+ assertEquals(pubAuthorityService.getAuthorityDisplayName("ROLE_Gibbon"), "Gibbon");
+ assertEquals(pubAuthorityService.getAuthorityDisplayName("Monkey"), "Monkey");
+
+ }
}
diff --git a/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceImpl.java b/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceImpl.java
index 5e548c331d..8484bc939d 100644
--- a/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceImpl.java
+++ b/source/java/org/alfresco/repo/security/authority/SimpleAuthorityServiceImpl.java
@@ -262,4 +262,19 @@ public class SimpleAuthorityServiceImpl implements AuthorityService
return authorities;
}
+ public String createAuthority(AuthorityType type, String parentName, String shortName, String authorityDisplayName)
+ {
+ return "";
+ }
+
+ public String getAuthorityDisplayName(String name)
+ {
+ return "";
+ }
+
+ public void setAuthorityDisplayName(String authorityName, String authorityDisplayName)
+ {
+
+ }
+
}
diff --git a/source/java/org/alfresco/service/cmr/security/AuthorityService.java b/source/java/org/alfresco/service/cmr/security/AuthorityService.java
index 3fd92d42bc..1f644bb287 100644
--- a/source/java/org/alfresco/service/cmr/security/AuthorityService.java
+++ b/source/java/org/alfresco/service/cmr/security/AuthorityService.java
@@ -113,6 +113,7 @@ public interface AuthorityService
* authority is created.
* @param shortName -
* the short name of the authority to create
+ * this will also be set as the default display name for the authority
*
* @return the name of the authority (this will be the prefix, if any
* associated with the type appended with the short name)
@@ -120,6 +121,26 @@ public interface AuthorityService
@Auditable(parameters = {"type", "parentName", "shortName"})
public String createAuthority(AuthorityType type, String parentName, String shortName);
+ /**
+ * Create an authority. If the parent is null thisw method creates a root
+ * authority.
+ *
+ * @param type -
+ * the type of the authority
+ * @param parentName -
+ * the name of the parent authority. If this is null then a root
+ * authority is created.
+ * @param shortName -
+ * the short name of the authority to create
+ * @param authorityDisplayName
+ * the display name for the authority
+ *
+ * @return the name of the authority (this will be the prefix, if any
+ * associated with the type appended with the short name)
+ */
+ @Auditable(parameters = {"type", "parentName", "shortName", "authorityDisplayName"})
+ public String createAuthority(AuthorityType type, String parentName, String shortName, String authorityDisplayName);
+
/**
* Set an authority to include another authority. For example, adding a
* group to a group or adding a user to a group.
@@ -218,5 +239,24 @@ public interface AuthorityService
*/
@Auditable(parameters = {"name"})
public boolean authorityExists(String name);
+
+ /**
+ * Get the display name for the given authority.
+ *
+ * @param name - the full authority string including any prefix (e.g. GROUP_woof)
+ * @return - the display name
+ */
+ @Auditable(parameters = {"name"})
+ public String getAuthorityDisplayName(String name);
+
+ /**
+ * Set the display name for the given authority.
+ * Setting the display name is only supported for authorities of type group
+ *
+ * @param authorityName
+ * @param authorityDisplayName
+ */
+ @Auditable(parameters = {"authorityName", "authorityDisplayName"})
+ public void setAuthorityDisplayName(String authorityName, String authorityDisplayName);
}
diff --git a/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java b/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java
index baf3fc1982..5af355db80 100644
--- a/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java
+++ b/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java
@@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.alfresco.config.JNDIConstants;
import org.alfresco.error.AlfrescoRuntimeException;
@@ -340,7 +341,7 @@ public final class SandboxFactory extends WCMUtil
permissionService.setPermission(dirRef, PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
}
- private void updateStagingAreaManagers(String storeId, NodeRef webProjectNodeRef, final List managers)
+ private void updateStagingAreaManagers(String storeId, final List managers)
{
// The stores have the mask set in updateSandboxManagers
String storeName = WCMUtil.buildStagingStoreName(storeId);
@@ -931,9 +932,9 @@ public final class SandboxFactory extends WCMUtil
}
}
- public void updateSandboxManagers(final String wpStoreId, NodeRef wpNodeRef, List managers)
+ public void updateSandboxManagers(final String wpStoreId, List managers)
{
- // walk existing user sandboxes and reapply manager permissions to include new manager user
+ // walk existing user sandboxes and reapply manager permissions to include new managers
List sbInfos = AuthenticationUtil.runAs(new RunAsWork>()
{
public List doWork() throws Exception
@@ -951,7 +952,7 @@ public final class SandboxFactory extends WCMUtil
}
}
- updateStagingAreaManagers(wpStoreId, wpNodeRef, managers);
+ updateStagingAreaManagers(wpStoreId, managers);
}
/**
@@ -985,6 +986,174 @@ public final class SandboxFactory extends WCMUtil
}
}
+ public void removeSandboxManagers(final String wpStoreId, List managers)
+ {
+ // walk existing user sandboxes and remove manager permissions to exclude old managers
+ List sbInfos = AuthenticationUtil.runAs(new RunAsWork>()
+ {
+ public List doWork() throws Exception
+ {
+ return listSandboxes(wpStoreId, AuthenticationUtil.getSystemUserName());
+ }
+ }, AuthenticationUtil.getSystemUserName());
+
+ for (SandboxInfo sbInfo : sbInfos)
+ {
+ if (sbInfo.getSandboxType().equals(SandboxConstants.PROP_SANDBOX_AUTHOR_MAIN))
+ {
+ String username = sbInfo.getName();
+ removeUserSandboxManagers(wpStoreId, managers, username);
+ }
+ }
+
+ removeStagingAreaManagers(wpStoreId, managers);
+ }
+
+ /**
+ * Removes the permissions for the list of sandbox ex-managers.
+ *
+ * @param storeId The store id of the sandbox to update
+ * @param managersToRemove The list of authorities who have had ContentManager role in the web project
+ * @param username Username of the user sandbox to update
+ */
+ private void removeUserSandboxManagers(String storeId, List managersToRemove, String username)
+ {
+ final String userStoreName = WCMUtil.buildUserMainStoreName(storeId, username);
+ final String previewStoreName = WCMUtil.buildUserPreviewStoreName(storeId, username);
+
+ final NodeRef mainDirRef = AVMNodeConverter.ToNodeRef(-1, WCMUtil.buildStoreRootPath(userStoreName));
+ final NodeRef previewDirRef = AVMNodeConverter.ToNodeRef(-1, WCMUtil.buildStoreRootPath(previewStoreName));
+ for (String manager : managersToRemove)
+ {
+ permissionService.deletePermission(mainDirRef.getStoreRef(), manager, WCMUtil.ROLE_CONTENT_MANAGER);
+ permissionService.deletePermission(previewDirRef.getStoreRef(), manager, WCMUtil.ROLE_CONTENT_MANAGER);
+ }
+ }
+ /**
+ * Removes the ContentManager role on staging area to ex-managers.
+ *
+ * @param storeId The store id of the sandbox to update
+ * @param managersToRemove The list of authorities who have had ContentManager role in the web project
+ */
+ private void removeStagingAreaManagers(String storeId, List managersToRemove)
+ {
+ final String storeName = WCMUtil.buildStagingStoreName(storeId);
+
+ final NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, WCMUtil.buildStoreRootPath(storeName));
+ for (String manager : managersToRemove)
+ {
+ permissionService.deletePermission(dirRef, manager, WCMUtil.ROLE_CONTENT_MANAGER);
+
+ permissionService.deletePermission(dirRef.getStoreRef(), manager,
+ PermissionService.CHANGE_PERMISSIONS);
+ permissionService.deletePermission(dirRef.getStoreRef(), manager,
+ PermissionService.READ_PERMISSIONS);
+ }
+
+ }
+
+ public void updateSandboxRoles(final String wpStoreId, List usersToUpdate, Set permissionsList)
+ {
+ // walk existing user sandboxes and remove manager permissions to exclude old managers
+ List sbInfos = AuthenticationUtil.runAs(new RunAsWork>()
+ {
+ public List doWork() throws Exception
+ {
+ return listSandboxes(wpStoreId, AuthenticationUtil.getSystemUserName());
+ }
+ }, AuthenticationUtil.getSystemUserName());
+
+ for (SandboxInfo sbInfo : sbInfos)
+ {
+ if (sbInfo.getSandboxType().equals(SandboxConstants.PROP_SANDBOX_AUTHOR_MAIN))
+ {
+ String username = sbInfo.getName();
+ updateUserSandboxRole(wpStoreId, username ,usersToUpdate, permissionsList);
+ }
+ }
+
+ updateStagingAreaRole(wpStoreId, usersToUpdate, permissionsList);
+ }
+
+ /**
+ * Updates roles on the sandbox identified by username to users from usersToUpdate list.
+ *
+ * @param storeId The store id of the sandbox to update
+ * @param username Username of the user sandbox to update
+ * @param usersToUpdate The list of users who have role changes
+ * @param permissionsList List of permissions @see org.alfresco.web.bean.wcm.InviteWebsiteUsersWizard.getPermissionsForType(). It is not mandatory.
+ */
+ private void updateUserSandboxRole(String storeId, String username, List usersToUpdate, Set permissionsList)
+ {
+ final String userStoreName = WCMUtil.buildUserMainStoreName(storeId, username);
+ final String previewStoreName = WCMUtil.buildUserPreviewStoreName(storeId, username);
+
+ final NodeRef mainDirRef = AVMNodeConverter.ToNodeRef(-1, WCMUtil.buildStoreRootPath(userStoreName));
+ final NodeRef previewDirRef = AVMNodeConverter.ToNodeRef(-1, WCMUtil.buildStoreRootPath(previewStoreName));
+
+ // If permissionsList is set remove all possible user permissions and set only necessary.
+ // This will fix previous wrong role changes. (paranoid)
+ // For little better performance just set permissionsList to null.
+ // But in this case it removes only previous permission.
+ if (permissionsList != null && permissionsList.size() != 0)
+ {
+ for (UserRoleWrapper user : usersToUpdate)
+ {
+ for (String permission : permissionsList)
+ {
+ permissionService.deletePermission(mainDirRef, user.getUserAuth(), permission);
+ permissionService.deletePermission(previewDirRef, user.getUserAuth(), permission);
+ }
+
+ permissionService.setPermission(mainDirRef, user.getUserAuth(), user.getNewRole(), true);
+ permissionService.setPermission(previewDirRef, user.getUserAuth(), user.getNewRole(), true);
+ }
+ }
+ else
+ {
+ for (UserRoleWrapper user: usersToUpdate)
+ {
+ permissionService.deletePermission(mainDirRef, user.getUserAuth(), user.getOldRole());
+ permissionService.deletePermission(previewDirRef, user.getUserAuth(), user.getOldRole());
+ permissionService.setPermission(mainDirRef, user.getUserAuth(), user.getNewRole(), true);
+ permissionService.setPermission(previewDirRef, user.getUserAuth(), user.getNewRole(), true);
+ }
+ }
+ }
+
+ /**
+ * Updates roles on staging sandbox to users from usersToUpdate list.
+ *
+ * @param storeId The store id of the sandbox to update
+ * @param usersToUpdate The list of users who have role changes
+ * @param permissionsList List of permissions @see org.alfresco.web.bean.wcm.InviteWebsiteUsersWizard.getPermissionsForType(). It is not mandatory.
+ */
+ private void updateStagingAreaRole(String storeId, List usersToUpdate, Set permissionsList)
+ {
+ final String storeName = WCMUtil.buildStagingStoreName(storeId);
+ final NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, WCMUtil.buildStoreRootPath(storeName));
+
+ if (permissionsList != null && permissionsList.size() != 0)
+ {
+ for (UserRoleWrapper user : usersToUpdate)
+ {
+ for (String permission : permissionsList)
+ {
+ permissionService.deletePermission(dirRef, user.getUserAuth(), permission);
+ }
+ permissionService.setPermission(dirRef, user.getUserAuth(), user.getNewRole(), true);
+ }
+ }
+ else
+ {
+ for (UserRoleWrapper user : usersToUpdate)
+ {
+ permissionService.deletePermission(dirRef, user.getUserAuth(), user.getOldRole());
+ permissionService.setPermission(dirRef, user.getUserAuth(), user.getNewRole(), true);
+ }
+ }
+ }
+
/**
* Tag a named store with a DNS path meta-data attribute.
* The DNS meta-data attribute is set to the system path 'store:/www/avm_webapps'
@@ -1049,4 +1218,43 @@ public final class SandboxFactory extends WCMUtil
logger.debug(" " + name + ": " + props.get(name));
}
}
+
+ public class UserRoleWrapper
+ {
+ private String newRole;
+ private String oldRole;
+ private String userAuth;
+
+ public UserRoleWrapper(String userAuth, String oldRole, String newRole)
+ {
+ this.userAuth = userAuth;
+ this.oldRole = oldRole;
+ this.newRole = newRole;
+ }
+
+ public String getNewRole()
+ {
+ return newRole;
+ }
+ public void setNewRole(String newRole)
+ {
+ this.newRole = newRole;
+ }
+ public String getOldRole()
+ {
+ return oldRole;
+ }
+ public void setOldRole(String oldRole)
+ {
+ this.oldRole = oldRole;
+ }
+ public String getUserAuth()
+ {
+ return userAuth;
+ }
+ public void setUserAuth(String userAuth)
+ {
+ this.userAuth = userAuth;
+ }
+ }
}
diff --git a/source/java/org/alfresco/wcm/webproject/WebProjectServiceImpl.java b/source/java/org/alfresco/wcm/webproject/WebProjectServiceImpl.java
index 4f17bcecb7..651c1da8d1 100644
--- a/source/java/org/alfresco/wcm/webproject/WebProjectServiceImpl.java
+++ b/source/java/org/alfresco/wcm/webproject/WebProjectServiceImpl.java
@@ -69,6 +69,7 @@ import org.alfresco.util.DNSNameMangler;
import org.alfresco.util.ParameterCheck;
import org.alfresco.wcm.sandbox.SandboxFactory;
import org.alfresco.wcm.sandbox.SandboxInfo;
+import org.alfresco.wcm.sandbox.SandboxFactory.UserRoleWrapper;
import org.alfresco.wcm.util.WCMUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -790,9 +791,19 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
private String getWebUserRoleImpl(NodeRef wpNodeRef, String userName)
{
- long start = System.currentTimeMillis();
+ NodeRef userRef = getWebUserRef(wpNodeRef, userName);
String userRole = null;
-
+
+ if (userRef != null)
+ {
+ userRole = (String)nodeService.getProperty(userRef, WCMAppModel.PROP_WEBUSERROLE);
+ }
+
+ return userRole;
+ }
+
+ private NodeRef getWebUserRef(NodeRef wpNodeRef, String userName)
+ {
StringBuilder query = new StringBuilder(128);
query.append("+PARENT:\"").append(wpNodeRef).append("\" ");
query.append("+TYPE:\"").append(WCMAppModel.TYPE_WEBUSER).append("\" ");
@@ -820,27 +831,23 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
if (nodes.size() == 1)
{
- userRole = (String)nodeService.getProperty(nodes.get(0), WCMAppModel.PROP_WEBUSERROLE);
+ return nodes.get(0);
}
else if (nodes.size() == 0)
{
if (logger.isTraceEnabled())
{
- logger.trace("getWebProjectUserRole: user role not found for " + userName);
+ logger.trace("getWebUserRef: web user ("+userName+") not found in web project: "+wpNodeRef);
}
}
else
{
- logger.warn("getWebProjectUserRole: more than one user role found for " + userName);
+ logger.error("getWebUserRef: more than one web user ("+userName+") found in web project: "+wpNodeRef);
}
-
- if (logger.isTraceEnabled())
- {
- logger.trace("getWebProjectUserRole: "+userName+" "+userRole+" in "+(System.currentTimeMillis()-start)+" ms");
- }
-
- return userRole;
+
+ return null;
}
+
/* (non-Javadoc)
* @see org.alfresco.wcm.webproject.WebProjectService#findWebProjectNodeFromPath(java.lang.String)
@@ -889,7 +896,9 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
// build a list of managers who will have full permissions on ALL staging areas
List managers = new ArrayList(4);
- Set existingUsers = new HashSet(8);
+ Map webSiteUsers = new HashMap(8);
+ List managersToRemove = new LinkedList();
+ List usersToUpdate = new LinkedList();
// retrieve the list of managers from the existing users
for (Map.Entry userRole : userGroupRoles.entrySet())
@@ -906,19 +915,21 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
}
}
- Map existingUserRoles = listWebUsers(wpNodeRef);
- for (Map.Entry userRole : existingUserRoles.entrySet())
+ List userInfoRefs = nodeService.getChildAssocs(wpNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
+
+ for (ChildAssociationRef ref : userInfoRefs)
{
- String username = userRole.getKey();
- String userrole = userRole.getValue();
-
+ NodeRef userInfoRef = ref.getChildRef();
+ String username = (String)nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
+ String userrole = (String)nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
+
if (WCMUtil.ROLE_CONTENT_MANAGER.equals(userrole) && managers.contains(username) == false)
{
managers.add(username);
}
- // add each existing user to the exclude this - we cannot add them more than once!
- existingUsers.add(username);
+ // add each existing user to the map which will be rechecked for update changed user permissions
+ webSiteUsers.put(username, userInfoRef);
}
List sandboxInfoList = new LinkedList();
@@ -933,7 +944,7 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
for (String userAuth : findNestedUserAuthorities(authority))
{
- if (existingUsers.contains(userAuth) == false)
+ if (webSiteUsers.keySet().contains(userAuth) == false)
{
if (autoCreateAuthorSandbox)
{
@@ -955,18 +966,54 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
}
else
{
- logger.warn("User '"+userAuth+"' already invited to web project: "+wpNodeRef+"(store id: "+wpStoreId+")");
+ // TODO - split out into separate 'change role'
+ // if user role have been changed then update required properties etc.
+ NodeRef userRef = webSiteUsers.get(userAuth);
+ String oldUserRole = (String)nodeService.getProperty(userRef, WCMAppModel.PROP_WEBUSERROLE);
+
+ if (!role.equals(oldUserRole))
+ {
+ // change in role
+ Map props = nodeService.getProperties(userRef);
+ props.put(WCMAppModel.PROP_WEBUSERNAME, userAuth);
+ props.put(WCMAppModel.PROP_WEBUSERROLE, role);
+ nodeService.setProperties(userRef, props);
+
+ if (WCMUtil.ROLE_CONTENT_MANAGER.equals(role))
+ {
+ managersUpdateRequired = true;
+ }
+ else if (WCMUtil.ROLE_CONTENT_MANAGER.equals(oldUserRole))
+ {
+ managersToRemove.add(userAuth);
+ }
+
+ usersToUpdate.add(sandboxFactory.new UserRoleWrapper(userAuth, oldUserRole, role));
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(userAuth +"'s role has been changed from '" + oldUserRole +
+ "' to '" + role + "'");
+ }
+ }
}
}
}
-
+
// Bind the post-commit transaction listener with data required for virtualization server notification
CreateSandboxTransactionListener tl = new CreateSandboxTransactionListener(sandboxInfoList, listWebApps(wpNodeRef));
AlfrescoTransactionSupport.bindListener(tl);
if (managersUpdateRequired == true)
{
- sandboxFactory.updateSandboxManagers(wpStoreId, wpNodeRef, managers);
+ sandboxFactory.updateSandboxManagers(wpStoreId, managers);
+ }
+
+ // TODO - split out into separate 'change role'
+ // remove ex-managers from sandboxes
+ if (managersToRemove.size() != 0)
+ {
+ sandboxFactory.removeSandboxManagers(wpStoreId, managersToRemove);
}
// get permissions and roles for a web project folder type
@@ -990,6 +1037,13 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
}
}
}
+
+ // TODO - split out into separate 'change role'
+ // update user's roles
+ if (usersToUpdate.size() != 0)
+ {
+ sandboxFactory.updateSandboxRoles(wpStoreId, usersToUpdate, perms);
+ }
if (logger.isInfoEnabled())
{
@@ -1027,29 +1081,65 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
WebProjectInfo wpInfo = getWebProject(wpNodeRef);
final String wpStoreId = wpInfo.getStoreId();
- if (isWebUser(wpNodeRef, userAuth))
+ // build a list of managers who will have full permissions on ALL staging areas
+ List managers = new ArrayList(4);
+
+ // retrieve the list of managers from the existing users
+ Map existingUserRoles = listWebUsers(wpNodeRef);
+ for (Map.Entry userRole : existingUserRoles.entrySet())
{
- logger.warn("User '"+userAuth+"' already invited to web project: "+wpNodeRef+" (store id: "+wpStoreId+")");
- return;
+ String username = userRole.getKey();
+ String userrole = userRole.getValue();
+
+ if (WCMUtil.ROLE_CONTENT_MANAGER.equals(userrole) && managers.contains(username) == false)
+ {
+ managers.add(username);
+ }
+ }
+
+ // get permissions and roles for a web project folder type
+ Set perms = permissionService.getSettablePermissions(WCMAppModel.TYPE_AVMWEBFOLDER);
+
+ NodeRef userRef = getWebUserRef(wpNodeRef, userAuth);
+ if (userRef != null)
+ {
+ // TODO - split out into separate 'change role'
+ // if user role has been changed then update required properties etc.
+ String oldUserRole = (String)nodeService.getProperty(userRef, WCMAppModel.PROP_WEBUSERROLE);
+ if (!role.equals(oldUserRole))
+ {
+ // change in role
+ Map props = nodeService.getProperties(userRef);
+ props.put(WCMAppModel.PROP_WEBUSERNAME, userAuth);
+ props.put(WCMAppModel.PROP_WEBUSERROLE, role);
+ nodeService.setProperties(userRef, props);
+
+ if (WCMUtil.ROLE_CONTENT_MANAGER.equals(role))
+ {
+ managers.add(userAuth);
+ sandboxFactory.updateSandboxManagers(wpStoreId, managers);
+ }
+ else if (WCMUtil.ROLE_CONTENT_MANAGER.equals(oldUserRole))
+ {
+ List managersToRemove = new LinkedList();
+ managersToRemove.add(userAuth);
+
+ sandboxFactory.removeSandboxManagers(wpStoreId, managersToRemove);
+ }
+
+ List usersToUpdate = new LinkedList();
+ usersToUpdate.add(sandboxFactory.new UserRoleWrapper(userAuth, oldUserRole, role));
+
+ sandboxFactory.updateSandboxRoles(wpStoreId, usersToUpdate, perms);
+
+ if (logger.isInfoEnabled())
+ {
+ logger.info("Web user "+userAuth +"'s role has been changed from '" + oldUserRole + "' to '" + role + "' (store id: "+wpStoreId+")");
+ }
+ }
}
else
{
- // build a list of managers who will have full permissions on ALL staging areas
- List managers = new ArrayList(4);
-
- // retrieve the list of managers from the existing users
- Map existingUserRoles = listWebUsers(wpNodeRef);
- for (Map.Entry userRole : existingUserRoles.entrySet())
- {
- String username = userRole.getKey();
- String userrole = userRole.getValue();
-
- if (WCMUtil.ROLE_CONTENT_MANAGER.equals(userrole) && managers.contains(username) == false)
- {
- managers.add(username);
- }
- }
-
if (autoCreateAuthorSandbox)
{
// create a sandbox for the user with permissions based on role
@@ -1068,7 +1158,7 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
if (WCMUtil.ROLE_CONTENT_MANAGER.equals(role))
{
managers.add(userAuth);
- sandboxFactory.updateSandboxManagers(wpStoreId, wpNodeRef, managers);
+ sandboxFactory.updateSandboxManagers(wpStoreId, managers);
}
sandboxFactory.addStagingAreaUser(wpStoreId, userAuth, role);
@@ -1076,9 +1166,6 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
// create an app:webuser instance for the user and assoc to the web project node
createWebUser(wpNodeRef, userAuth, role);
- // get permissions and roles for a web project folder type
- Set perms = permissionService.getSettablePermissions(WCMAppModel.TYPE_AVMWEBFOLDER);
-
// set permissions for the user
for (String permission : perms)
{