Merged V3.1 to HEAD

12983: Merged V2.1-A to V3.1
      8668: Added authorityDisplayName
   12985: Merged V2.1-A to V3.1
      8706: (record-only) Build fixes after removing the guest user - DO NOT MERGE
   12990: Merged V3.0 to V3.1
      12922: Merged V2.2 to V3.0
         12555: Fix ETWOTWO-972 (Remove Lookup Cache)
         12558: Fix ETWOTWO-978 (L2 Cache removal for No Row Issues)
      12928: Merged V2.2 to V3.0
         11319: Fix for ETWOTWO-73 (missed merge ?)
   ___________________________________________________________________
   Modified: svn:mergeinfo
      Merged /alfresco/BRANCHES/V2.1-A:r8668,8706
      Merged /alfresco/BRANCHES/V3.0:r12922,12928
      Merged /alfresco/BRANCHES/V2.2:r12555,12558
      Merged /alfresco/BRANCHES/V3.1:r12983,12985,12990


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13546 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2009-03-11 01:48:45 +00:00
parent 9ad1644441
commit e3503a6a88
20 changed files with 1115 additions and 395 deletions

View File

@@ -154,17 +154,7 @@
</property> </property>
</bean> </bean>
<bean id="lookupCache" class="org.alfresco.repo.avm.LookupCache"> <bean id="lookupCache" class="org.alfresco.repo.avm.NOOPLookupCache"/>
<property name="avmNodeDAO">
<ref bean="avmNodeDAO"/>
</property>
<property name="avmStoreDAO">
<ref bean="avmStoreDAO"/>
</property>
<property name="transactionalCache">
<ref bean="avmLookupCache"/>
</property>
</bean>
<bean id="rawServices" class="org.alfresco.repo.avm.util.RawServices"/> <bean id="rawServices" class="org.alfresco.repo.avm.util.RawServices"/>

View File

@@ -422,42 +422,6 @@
</property> </property>
</bean> </bean>
<!-- ===================================== -->
<!-- AVM Lookup Cache -->
<!-- ===================================== -->
<!-- The cross-transaction shared cache for AVM lookups -->
<bean name="avmLookupSharedCache" class="org.alfresco.repo.cache.EhCacheAdapter">
<property name="cache">
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref bean="internalEHCacheManager"/>
</property>
<property name="cacheName">
<value>org.alfresco.repo.avm.lookupSharedCache</value>
</property>
</bean>
</property>
</bean>
<!-- Transactional cache for AVM lookups -->
<bean name="avmLookupCache" class="org.alfresco.repo.cache.TransactionalCache">
<property name="sharedCache">
<ref bean="avmLookupSharedCache"/>
</property>
<property name="cacheManager">
<ref bean="transactionalEHCacheManager"/>
</property>
<property name="name">
<value>org.alfresco.repo.avm.lookupTransactionalCache</value>
</property>
<property name="maxCacheSize">
<value>100</value>
</property>
</bean>
<!-- ===================================== --> <!-- ===================================== -->
<!-- AVM Store lookup cache --> <!-- AVM Store lookup cache -->
<!-- ===================================== --> <!-- ===================================== -->

View File

@@ -207,15 +207,17 @@
eternal="true" eternal="true"
overflowToDisk="false" overflowToDisk="false"
/> />
<!-- Note: Workaround for ETWOTWO-978: no row issues - do not adjust -->
<cache <cache
name="org.alfresco.repo.avm.VersionRootImpl" name="org.alfresco.repo.avm.VersionRootImpl"
maxElementsInMemory="200" maxElementsInMemory="0"
eternal="true" eternal="true"
overflowToDisk="false" overflowToDisk="false"
/> />
<!-- Note: Workaround for ETWOTWO-978: no row issues - do not adjust -->
<cache <cache
name="org.alfresco.repo.avm.ChildEntryImpl" name="org.alfresco.repo.avm.ChildEntryImpl"
maxElementsInMemory="10000" maxElementsInMemory="0"
eternal="true" eternal="true"
overflowToDisk="false" overflowToDisk="false"
/> />

View File

@@ -0,0 +1,57 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<!-- Activate this extension to enable AVM lookup path caching. -->
<!-- This was the default behaviour prior to 2.2 SP3 & 3.1 -->
<beans>
<bean id="lookupCache" class="org.alfresco.repo.avm.TransactionalLookupCache">
<property name="avmNodeDAO">
<ref bean="avmNodeDAO"/>
</property>
<property name="avmStoreDAO">
<ref bean="avmStoreDAO"/>
</property>
<property name="transactionalCache">
<ref bean="avmLookupCache"/>
</property>
</bean>
<!-- ===================================== -->
<!-- AVM Lookup Cache -->
<!-- ===================================== -->
<!-- The cross-transaction shared cache for AVM lookups -->
<bean name="avmLookupSharedCache" class="org.alfresco.repo.cache.EhCacheAdapter">
<property name="cache">
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref bean="internalEHCacheManager"/>
</property>
<property name="cacheName">
<value>org.alfresco.repo.avm.lookupSharedCache</value>
</property>
</bean>
</property>
</bean>
<!-- Transactional cache for AVM lookups -->
<bean name="avmLookupCache" class="org.alfresco.repo.cache.TransactionalCache">
<property name="sharedCache">
<ref bean="avmLookupSharedCache"/>
</property>
<property name="cacheManager">
<ref bean="transactionalEHCacheManager"/>
</property>
<property name="name">
<value>org.alfresco.repo.avm.lookupTransactionalCache</value>
</property>
<property name="maxCacheSize">
<value>100</value>
</property>
</bean>
</beans>

View File

@@ -702,6 +702,8 @@
org.alfresco.service.cmr.security.AuthorityService.getName=ACL_ALLOW 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.authorityExists=ACL_METHOD.ROLE_ADMINISTRATOR
org.alfresco.service.cmr.security.AuthorityService.getAuthoritiesForUser=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
</value> </value>
</property> </property>
</bean> </bean>

View File

@@ -294,6 +294,8 @@ public interface ContentModel
static final QName TYPE_AUTHORITY_CONTAINER = QName.createQName(USER_MODEL_URI, "authorityContainer"); 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_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 ASSOC_MEMBER = QName.createQName(USER_MODEL_URI, "member");
static final QName PROP_MEMBERS = QName.createQName(USER_MODEL_URI, "members"); static final QName PROP_MEMBERS = QName.createQName(USER_MODEL_URI, "members");

View File

@@ -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; package org.alfresco.repo.avm;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.repo.avm.util.SimplePath; 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. * 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<LookupKey, Lookup> fCache;
/** // Following are the cache invalidation calls.
* Reference to the Node DAO.
*/
private AVMNodeDAO fAVMNodeDAO;
/** /**
* Reference to the Store DAO. * Called when a simple write operation occurs. This
*/ * invalidates all read lookups and all layered lookups.
private AVMStoreDAO fAVMStoreDAO; */
public void onWrite(String storeName);
/** /**
* Make one up. * Called when a delete has occurred in a store. This invalidates both
*/ * reads and write lookups in that store.
public LookupCache() */
{ public void onDelete(String storeName);
}
/** /**
* Set up the node dao. * Called when a snapshot occurs in a store. This invalidates write
* @param dao The dao to set. * lookups. Read lookups stay untouched.
*/ */
public void setAvmNodeDAO(AVMNodeDAO dao) public void onSnapshot(String storeName);
{
fAVMNodeDAO = dao;
}
/** /**
* Set the store dao. * Full reset of cache.
* @param dao The dao to set. */
*/ public void reset();
public void setAvmStoreDAO(AVMStoreDAO dao)
{
fAVMStoreDAO = dao;
}
public void setTransactionalCache(SimpleCache<LookupKey, Lookup> 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<AVMNode, Boolean> 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<AVMNode, Boolean> 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<LookupKey> keys = new ArrayList<LookupKey>();
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<LookupKey> keys = new ArrayList<LookupKey>();
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<LookupKey> keys = new ArrayList<LookupKey>();
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();
}
} }

View File

@@ -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<AVMNode, Boolean> 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<AVMNode, Boolean> 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()
{
}
}

View File

@@ -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<LookupKey, Lookup> 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<LookupKey, Lookup> 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<AVMNode, Boolean> 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<AVMNode, Boolean> 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<LookupKey> keys = new ArrayList<LookupKey>();
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<LookupKey> keys = new ArrayList<LookupKey>();
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<LookupKey> keys = new ArrayList<LookupKey>();
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();
}
}

View File

@@ -153,7 +153,7 @@ class AVMStoreDAOHibernate extends HibernateDaoSupport implements
/* (non-Javadoc) /* (non-Javadoc)
* @see org.alfresco.repo.avm.AVMStoreDAO#invalidateCache() * @see org.alfresco.repo.avm.AVMStoreDAO#invalidateCache()
*/ */
public synchronized void invalidateCache() public void invalidateCache()
{ {
fNameCache.clear(); fNameCache.clear();
} }

View File

@@ -427,6 +427,12 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions
return; return;
} }
// avoid NullPointerException if it was not created
if (acl == null)
{
return;
}
switch (acl.getAclType()) switch (acl.getAclType())
{ {
case FIXED: case FIXED:

View File

@@ -90,6 +90,9 @@
<property name="usr:members"> <property name="usr:members">
<type>d:text</type> <type>d:text</type>
<multiple>true</multiple> <multiple>true</multiple>
</property>
<property name="usr:authorityDisplayName">
<type>d:text</type>
</property> </property>
</properties> </properties>
<associations> <associations>

View File

@@ -44,8 +44,9 @@ public interface AuthorityDAO
* *
* @param parentName * @param parentName
* @param name * @param name
* @param authorityDisplayName
*/ */
void createAuthority(String parentName, String name); void createAuthority(String parentName, String name, String authorityDisplayName);
/** /**
* Delete an authority. * Delete an authority.
@@ -122,4 +123,20 @@ public interface AuthorityDAO
*/ */
public String getAuthorityName(NodeRef authorityRef); 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);
} }

View File

@@ -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<QName, Serializable> props = new HashMap<QName, Serializable>(); HashMap<QName, Serializable> props = new HashMap<QName, Serializable>();
props.put(ContentModel.PROP_AUTHORITY_NAME, name); props.put(ContentModel.PROP_AUTHORITY_NAME, name);
props.put(ContentModel.PROP_AUTHORITY_DISPLAY_NAME, authorityDisplayName);
if (parentName != null) if (parentName != null)
{ {
NodeRef parentRef = getAuthorityOrNull(parentName); NodeRef parentRef = getAuthorityOrNull(parentName);
@@ -543,4 +544,30 @@ public class AuthorityDAOImpl implements AuthorityDAO
return name; 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);
}
} }

View File

@@ -261,10 +261,7 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
public String createAuthority(AuthorityType type, String parentName, String shortName) public String createAuthority(AuthorityType type, String parentName, String shortName)
{ {
checkTypeIsMutable(type); return createAuthority(type, parentName, shortName, shortName);
String name = getName(type, shortName);
authorityDAO.createAuthority(parentName, name);
return name;
} }
public void deleteAuthority(String name) public void deleteAuthority(String name)
@@ -334,4 +331,29 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
return authorityDAO.authorityExists(name); 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);
}
} }

View File

@@ -867,4 +867,30 @@ public class AuthorityServiceTest extends TestCase
properties.put(ContentModel.PROP_ORGID, orgId); properties.put(ContentModel.PROP_ORGID, orgId);
return properties; 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");
}
} }

View File

@@ -262,4 +262,19 @@ public class SimpleAuthorityServiceImpl implements AuthorityService
return authorities; 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)
{
}
} }

View File

@@ -113,6 +113,7 @@ public interface AuthorityService
* authority is created. * authority is created.
* @param shortName - * @param shortName -
* the short name of the authority to create * 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 * @return the name of the authority (this will be the prefix, if any
* associated with the type appended with the short name) * associated with the type appended with the short name)
@@ -120,6 +121,26 @@ public interface AuthorityService
@Auditable(parameters = {"type", "parentName", "shortName"}) @Auditable(parameters = {"type", "parentName", "shortName"})
public String createAuthority(AuthorityType type, String parentName, String 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 * Set an authority to include another authority. For example, adding a
* group to a group or adding a user to a group. * group to a group or adding a user to a group.
@@ -219,4 +240,23 @@ public interface AuthorityService
@Auditable(parameters = {"name"}) @Auditable(parameters = {"name"})
public boolean authorityExists(String 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);
} }

View File

@@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.alfresco.config.JNDIConstants; import org.alfresco.config.JNDIConstants;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
@@ -340,7 +341,7 @@ public final class SandboxFactory extends WCMUtil
permissionService.setPermission(dirRef, PermissionService.ALL_AUTHORITIES, PermissionService.READ, true); permissionService.setPermission(dirRef, PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
} }
private void updateStagingAreaManagers(String storeId, NodeRef webProjectNodeRef, final List<String> managers) private void updateStagingAreaManagers(String storeId, final List<String> managers)
{ {
// The stores have the mask set in updateSandboxManagers // The stores have the mask set in updateSandboxManagers
String storeName = WCMUtil.buildStagingStoreName(storeId); String storeName = WCMUtil.buildStagingStoreName(storeId);
@@ -931,9 +932,9 @@ public final class SandboxFactory extends WCMUtil
} }
} }
public void updateSandboxManagers(final String wpStoreId, NodeRef wpNodeRef, List<String> managers) public void updateSandboxManagers(final String wpStoreId, List<String> 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<SandboxInfo> sbInfos = AuthenticationUtil.runAs(new RunAsWork<List<SandboxInfo>>() List<SandboxInfo> sbInfos = AuthenticationUtil.runAs(new RunAsWork<List<SandboxInfo>>()
{ {
public List<SandboxInfo> doWork() throws Exception public List<SandboxInfo> 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<String> managers)
{
// walk existing user sandboxes and remove manager permissions to exclude old managers
List<SandboxInfo> sbInfos = AuthenticationUtil.runAs(new RunAsWork<List<SandboxInfo>>()
{
public List<SandboxInfo> 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<String> 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<String> 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<UserRoleWrapper> usersToUpdate, Set<String> permissionsList)
{
// walk existing user sandboxes and remove manager permissions to exclude old managers
List<SandboxInfo> sbInfos = AuthenticationUtil.runAs(new RunAsWork<List<SandboxInfo>>()
{
public List<SandboxInfo> 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<UserRoleWrapper> usersToUpdate, Set<String> 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<UserRoleWrapper> usersToUpdate, Set<String> 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. * 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' * 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)); 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;
}
}
} }

View File

@@ -69,6 +69,7 @@ import org.alfresco.util.DNSNameMangler;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
import org.alfresco.wcm.sandbox.SandboxFactory; import org.alfresco.wcm.sandbox.SandboxFactory;
import org.alfresco.wcm.sandbox.SandboxInfo; import org.alfresco.wcm.sandbox.SandboxInfo;
import org.alfresco.wcm.sandbox.SandboxFactory.UserRoleWrapper;
import org.alfresco.wcm.util.WCMUtil; import org.alfresco.wcm.util.WCMUtil;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -790,9 +791,19 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
private String getWebUserRoleImpl(NodeRef wpNodeRef, String userName) private String getWebUserRoleImpl(NodeRef wpNodeRef, String userName)
{ {
long start = System.currentTimeMillis(); NodeRef userRef = getWebUserRef(wpNodeRef, userName);
String userRole = null; 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); StringBuilder query = new StringBuilder(128);
query.append("+PARENT:\"").append(wpNodeRef).append("\" "); query.append("+PARENT:\"").append(wpNodeRef).append("\" ");
query.append("+TYPE:\"").append(WCMAppModel.TYPE_WEBUSER).append("\" "); query.append("+TYPE:\"").append(WCMAppModel.TYPE_WEBUSER).append("\" ");
@@ -820,28 +831,24 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
if (nodes.size() == 1) if (nodes.size() == 1)
{ {
userRole = (String)nodeService.getProperty(nodes.get(0), WCMAppModel.PROP_WEBUSERROLE); return nodes.get(0);
} }
else if (nodes.size() == 0) else if (nodes.size() == 0)
{ {
if (logger.isTraceEnabled()) 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 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()) return null;
{
logger.trace("getWebProjectUserRole: "+userName+" "+userRole+" in "+(System.currentTimeMillis()-start)+" ms");
}
return userRole;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see org.alfresco.wcm.webproject.WebProjectService#findWebProjectNodeFromPath(java.lang.String) * @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 // build a list of managers who will have full permissions on ALL staging areas
List<String> managers = new ArrayList<String>(4); List<String> managers = new ArrayList<String>(4);
Set<String> existingUsers = new HashSet<String>(8); Map<String, NodeRef> webSiteUsers = new HashMap<String, NodeRef>(8);
List<String> managersToRemove = new LinkedList<String>();
List<UserRoleWrapper> usersToUpdate = new LinkedList<UserRoleWrapper>();
// retrieve the list of managers from the existing users // retrieve the list of managers from the existing users
for (Map.Entry<String, String> userRole : userGroupRoles.entrySet()) for (Map.Entry<String, String> userRole : userGroupRoles.entrySet())
@@ -906,19 +915,21 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
} }
} }
Map<String, String> existingUserRoles = listWebUsers(wpNodeRef); List<ChildAssociationRef> userInfoRefs = nodeService.getChildAssocs(wpNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (Map.Entry<String, String> userRole : existingUserRoles.entrySet())
for (ChildAssociationRef ref : userInfoRefs)
{ {
String username = userRole.getKey(); NodeRef userInfoRef = ref.getChildRef();
String userrole = userRole.getValue(); 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) if (WCMUtil.ROLE_CONTENT_MANAGER.equals(userrole) && managers.contains(username) == false)
{ {
managers.add(username); managers.add(username);
} }
// add each existing user to the exclude this - we cannot add them more than once! // add each existing user to the map which will be rechecked for update changed user permissions
existingUsers.add(username); webSiteUsers.put(username, userInfoRef);
} }
List<SandboxInfo> sandboxInfoList = new LinkedList<SandboxInfo>(); List<SandboxInfo> sandboxInfoList = new LinkedList<SandboxInfo>();
@@ -933,7 +944,7 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
for (String userAuth : findNestedUserAuthorities(authority)) for (String userAuth : findNestedUserAuthorities(authority))
{ {
if (existingUsers.contains(userAuth) == false) if (webSiteUsers.keySet().contains(userAuth) == false)
{ {
if (autoCreateAuthorSandbox) if (autoCreateAuthorSandbox)
{ {
@@ -955,7 +966,36 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
} }
else 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<QName, Serializable> 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 + "'");
}
}
} }
} }
} }
@@ -966,7 +1006,14 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
if (managersUpdateRequired == true) 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 // get permissions and roles for a web project folder type
@@ -991,6 +1038,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()) if (logger.isInfoEnabled())
{ {
logger.info("Invited "+invitedCount+" web users (store id: "+wpStoreId+")"); logger.info("Invited "+invitedCount+" web users (store id: "+wpStoreId+")");
@@ -1027,29 +1081,65 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
WebProjectInfo wpInfo = getWebProject(wpNodeRef); WebProjectInfo wpInfo = getWebProject(wpNodeRef);
final String wpStoreId = wpInfo.getStoreId(); final String wpStoreId = wpInfo.getStoreId();
if (isWebUser(wpNodeRef, userAuth)) // build a list of managers who will have full permissions on ALL staging areas
List<String> managers = new ArrayList<String>(4);
// retrieve the list of managers from the existing users
Map<String, String> existingUserRoles = listWebUsers(wpNodeRef);
for (Map.Entry<String, String> userRole : existingUserRoles.entrySet())
{ {
logger.warn("User '"+userAuth+"' already invited to web project: "+wpNodeRef+" (store id: "+wpStoreId+")"); String username = userRole.getKey();
return; 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<String> 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<QName, Serializable> 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<String> managersToRemove = new LinkedList<String>();
managersToRemove.add(userAuth);
sandboxFactory.removeSandboxManagers(wpStoreId, managersToRemove);
}
List<UserRoleWrapper> usersToUpdate = new LinkedList<UserRoleWrapper>();
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 else
{ {
// build a list of managers who will have full permissions on ALL staging areas
List<String> managers = new ArrayList<String>(4);
// retrieve the list of managers from the existing users
Map<String, String> existingUserRoles = listWebUsers(wpNodeRef);
for (Map.Entry<String, String> 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) if (autoCreateAuthorSandbox)
{ {
// create a sandbox for the user with permissions based on role // 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)) if (WCMUtil.ROLE_CONTENT_MANAGER.equals(role))
{ {
managers.add(userAuth); managers.add(userAuth);
sandboxFactory.updateSandboxManagers(wpStoreId, wpNodeRef, managers); sandboxFactory.updateSandboxManagers(wpStoreId, managers);
} }
sandboxFactory.addStagingAreaUser(wpStoreId, userAuth, role); 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 // create an app:webuser instance for the user and assoc to the web project node
createWebUser(wpNodeRef, userAuth, role); createWebUser(wpNodeRef, userAuth, role);
// get permissions and roles for a web project folder type
Set<String> perms = permissionService.getSettablePermissions(WCMAppModel.TYPE_AVMWEBFOLDER);
// set permissions for the user // set permissions for the user
for (String permission : perms) for (String permission : perms)
{ {