mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merge DEV/V3.4-BUG-FIX to HEAD (28799-28800,28864,28875,28879,28916,28941,28956,28970,28993)
28993: HomeFolderProviderSynchronizer: Provider used for LDAP to continue to use username as home folder name directly under .../app:company_home/app:user_homes Property spaces.user_homes.regex.pattern now set to "" rather than "^(..)" which would have given a single level hash structure. 28970: Merge DEV/ALAN/HOME_FOLDER to DEV/V3.4-BUG-FIX 28947: - Introduction of version 2 HomeFolderProvider2 and re-factor of version 1 so that the code used to create the folders is now in the HomeFolderManager. - Re-factor homeFolderProviderSynchronizer to handle HomeFolderProvider2. - Addition of AbstractHomeFolderProvider.V2Adaptor to allow external providers that extend AbstractHomeFolderPathProvider to be handled by homeFolderProviderSynchronizer. 28860: Minor change to class comment and removed unused imports 28858: ALF-4727 Hashed home folder provider added and used by default for LDAP sync users - based on Romain Guinot work. ALF-7797 HomeFolderProviderSynchronizer added to move existing users (normally those added by LDAP sync) into location preferred by home folder provider. - HomeFolderProviderSynchronizer bug fixes - tenant accounts supported for first time - addition of a phase to create parent folders before moving home folder to avoid a race condition - check for conditions that would result in FileExistExceptions as we don't want a the transaction to be discarded as this results in retries. - HomeFolderProviderSynchronizerTest integration test including tenant services - HomeFolderManager now sets the HOME_FOLDER_PROVIDER if it uses a default when HOME_FOLDER_PROVIDER is not set. - AbstractHomeFolderProvider clears cache when path reset as it will be invalid. - UIDBasedHomeFolderProvider.createNewParent creates its own mutable List as the one passed in may not be mutable. 28580: Save code changes - added comments to do with LDAP syn overriding the HFP value and related to this added a global property to keep empty parent folders. 28347: HomeFolderProviderSynchronizer - issue to do with new run of sync having created a user via UI that has a home folder as one of the parent folders. - issue to do with catching exception when creating temporary folder - transaction is gone - give up if error in any phase 28298: Addition of HomeFolderPathProvider (based on Romain's work) and addition of HomeFolderProviderSynchronizer. 28956: Merged DEV to V3.4-BUG-FIX ALF-9428: Multitenancy users not preserved after upgrade from 3.2.2.7 to 3.4.2 - Provide correct RunAs context in FixUserQNamesPatch batching. 28941: ALF-9361 : CLONE -sync Flat IMAP client with Alfresco is slow and inaccurate 28916: ALF-9421 The AlfrescoJavaScript action now includes company home in the JavaScript scope. 28879: Fixed ALF-9296: Alfresco Dashboard: Impossible to approve/reject task from My Tasks dashlet on My Alfresco 28875: Fixed ALF-6329: SPANISH - Share, translation on Transfer Target configuration 28864: Message: ALF-9430: RuntimeExec waitForCompletion logic is obscure - Only a single flag 'isCompleted' - Set flag in try-finally - Added notify() However, the wait() code doesn't, in practice, get called because the waitForCompletion is synchronized with the run() and is called a while after the reading thread is triggered. So the logic is less obscure and safer for the finally. 28800: File for rev 28799: ALF-9240 28799: Merged DEV to V3.4-BUG-FIX 28797: ALF-9240: Issue with adding an aspect with large multivalued list Added unit test to stress, but could not reproduce git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@28995 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -18,15 +18,27 @@
|
||||
*/
|
||||
package org.alfresco.repo.security.person;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.node.NodeServicePolicies;
|
||||
import org.alfresco.repo.policy.JavaBehaviour;
|
||||
import org.alfresco.repo.policy.PolicyComponent;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileFolderUtil;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.model.FileNotFoundException;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
@@ -34,26 +46,43 @@ import org.alfresco.service.namespace.QName;
|
||||
/**
|
||||
* Manage home folder creation by binding to events from the cm:person type.
|
||||
*
|
||||
* @author Andy Hind
|
||||
* @author Andy Hind,
|
||||
* Alan Davis (support v1 and v2 HomeFolderProviders - code from
|
||||
* v1 HomeFolderProviders moved into HomeFolderManager).
|
||||
*/
|
||||
public class HomeFolderManager implements NodeServicePolicies.OnCreateNodePolicy
|
||||
{
|
||||
|
||||
private PolicyComponent policyComponent;
|
||||
|
||||
private NodeService nodeService;
|
||||
|
||||
private boolean enableHomeFolderCreationAsPeopleAreCreated = false;
|
||||
|
||||
private ServiceRegistry serviceRegistry;
|
||||
|
||||
private TenantService tenantService;
|
||||
|
||||
/**
|
||||
* A default provider
|
||||
*/
|
||||
private HomeFolderProvider defaultProvider;
|
||||
private HomeFolderProvider2 defaultProvider;
|
||||
|
||||
/**
|
||||
* Providers that have registered and are looken up by name (== bean name)
|
||||
* Original Providers (now depreciated) that have registered and are looked up by bean name.
|
||||
*/
|
||||
private Map<String, HomeFolderProvider> providers = new HashMap<String, HomeFolderProvider>();
|
||||
@SuppressWarnings("deprecation")
|
||||
private Map<String, HomeFolderProvider> v1Providers = new HashMap<String, HomeFolderProvider>();
|
||||
|
||||
/**
|
||||
* Providers that have registered and are looked up by bean name.
|
||||
*/
|
||||
private Map<String, HomeFolderProvider2> v2Providers = new HashMap<String, HomeFolderProvider2>();
|
||||
|
||||
/**
|
||||
* Cache the result of the path look up.
|
||||
*/
|
||||
private Map<String, Map<String, NodeRef>> rootPathNodeRefMaps =
|
||||
new ConcurrentHashMap<String, Map<String, NodeRef>>();
|
||||
|
||||
/**
|
||||
* Bind the class behaviour to this implementation
|
||||
@@ -90,21 +119,65 @@ public class HomeFolderManager implements NodeServicePolicies.OnCreateNodePolicy
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the service registry.
|
||||
*/
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tenant service
|
||||
*/
|
||||
public void setTenantService(TenantService tenantService)
|
||||
{
|
||||
this.tenantService = tenantService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a home folder provider.
|
||||
*
|
||||
* @param provider
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void addProvider(HomeFolderProvider provider)
|
||||
{
|
||||
providers.put(provider.getName(), provider);
|
||||
v1Providers.put(provider.getName(), provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a home folder provider.
|
||||
*
|
||||
* @param provider
|
||||
*/
|
||||
public void addProvider(HomeFolderProvider2 provider)
|
||||
{
|
||||
v2Providers.put(provider.getName(), provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version 1 HomeFolderProvider with the given name.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public HomeFolderProvider getHomeFolderProvider1(String providerName)
|
||||
{
|
||||
return v1Providers.get(providerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version 2 HomeFolderProvider2 with the given name.
|
||||
*/
|
||||
public HomeFolderProvider2 getHomeFolderProvider2(String providerName)
|
||||
{
|
||||
return v2Providers.get(providerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default home folder provider (user which none is specified or when one is not found)
|
||||
* @param defaultProvider
|
||||
*/
|
||||
public void setDefaultProvider(HomeFolderProvider defaultProvider)
|
||||
public void setDefaultProvider(HomeFolderProvider2 defaultProvider)
|
||||
{
|
||||
this.defaultProvider = defaultProvider;
|
||||
}
|
||||
@@ -123,22 +196,302 @@ public class HomeFolderManager implements NodeServicePolicies.OnCreateNodePolicy
|
||||
/**
|
||||
* Find the provider and call.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void makeHomeFolder(ChildAssociationRef childAssocRef)
|
||||
{
|
||||
HomeFolderProvider provider = defaultProvider;
|
||||
String providerName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(childAssocRef
|
||||
HomeFolderProvider2 v2Provider = defaultProvider;
|
||||
HomeFolderProvider v1Provider = null;
|
||||
String providerName = DefaultTypeConverter.INSTANCE.convert(
|
||||
String.class, nodeService.getProperty(childAssocRef
|
||||
.getChildRef(), ContentModel.PROP_HOME_FOLDER_PROVIDER));
|
||||
if (providerName != null)
|
||||
{
|
||||
provider = providers.get(providerName);
|
||||
if (provider == null)
|
||||
v2Provider = getHomeFolderProvider2(providerName);
|
||||
if (v2Provider == null)
|
||||
{
|
||||
provider = defaultProvider;
|
||||
v1Provider = getHomeFolderProvider1(providerName);
|
||||
if (v1Provider == null)
|
||||
{
|
||||
v2Provider = defaultProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (provider != null)
|
||||
else
|
||||
{
|
||||
provider.onCreateNode(childAssocRef);
|
||||
providerName = defaultProvider.getName();
|
||||
nodeService.setProperty(childAssocRef.getChildRef(),
|
||||
ContentModel.PROP_HOME_FOLDER_PROVIDER, providerName);
|
||||
}
|
||||
if (v2Provider != null)
|
||||
{
|
||||
// If a V2Adaptor we still must call onCreateNode just like a
|
||||
// v1 HomeFolderProvider in case it has been overridden
|
||||
if (v2Provider instanceof AbstractHomeFolderProvider.V2Adaptor)
|
||||
{
|
||||
((AbstractHomeFolderProvider.V2Adaptor)v2Provider).onCreateNode(childAssocRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
homeFolderCreateAndSetPermissions(v2Provider, childAssocRef.getChildRef());
|
||||
}
|
||||
}
|
||||
else if (v1Provider != null)
|
||||
{
|
||||
v1Provider.onCreateNode(childAssocRef);
|
||||
}
|
||||
}
|
||||
|
||||
void homeFolderCreateAndSetPermissions(HomeFolderProvider2 provider, NodeRef personNodeRef)
|
||||
{
|
||||
AuthenticationUtil.RunAsWork<NodeRef> action =
|
||||
new RunAsCreateAndSetPermissions(provider, personNodeRef);
|
||||
AuthenticationUtil.runAs(action, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to encapsulate the creation and setting permissions etc
|
||||
*/
|
||||
private class RunAsCreateAndSetPermissions implements AuthenticationUtil.RunAsWork<NodeRef>
|
||||
{
|
||||
NodeRef personNodeRef;
|
||||
HomeFolderProvider2 provider;
|
||||
|
||||
RunAsCreateAndSetPermissions(HomeFolderProvider2 provider, NodeRef personNodeRef)
|
||||
{
|
||||
this.personNodeRef = personNodeRef;
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public NodeRef doWork() throws Exception
|
||||
{
|
||||
// Get home folder
|
||||
HomeSpaceNodeRef homeFolder = provider.getHomeFolder(personNodeRef);
|
||||
|
||||
// If it exists
|
||||
if (homeFolder.getNodeRef() != null)
|
||||
{
|
||||
// Get uid and keep
|
||||
String uid = DefaultTypeConverter.INSTANCE.convert(String.class,
|
||||
serviceRegistry.getNodeService().getProperty(
|
||||
personNodeRef, ContentModel.PROP_USERNAME));
|
||||
|
||||
// If created or found then set (other wise it was already set correctly)
|
||||
if (homeFolder.getStatus() != HomeSpaceNodeRef.Status.VALID)
|
||||
{
|
||||
serviceRegistry.getNodeService().setProperty(
|
||||
personNodeRef, ContentModel.PROP_HOMEFOLDER, homeFolder.getNodeRef());
|
||||
}
|
||||
|
||||
final String providerSuppliedOwner = provider.getOwner();
|
||||
String owner = (providerSuppliedOwner == null) ? uid : providerSuppliedOwner;
|
||||
// If created..
|
||||
if (homeFolder.getStatus() == HomeSpaceNodeRef.Status.CREATED)
|
||||
{
|
||||
PermissionsManager onCreatePermissionsManager =
|
||||
provider.getOnCreatePermissionsManager();
|
||||
if (onCreatePermissionsManager != null)
|
||||
{
|
||||
onCreatePermissionsManager.setPermissions(
|
||||
homeFolder.getNodeRef(), owner, uid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PermissionsManager onReferencePermissionsManager =
|
||||
provider.getOnReferencePermissionsManager();
|
||||
if (onReferencePermissionsManager != null)
|
||||
{
|
||||
onReferencePermissionsManager.setPermissions(
|
||||
homeFolder.getNodeRef(), owner, uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
return homeFolder.getNodeRef();
|
||||
}
|
||||
}
|
||||
|
||||
private StoreRef getStoreRef(HomeFolderProvider2 provider)
|
||||
{
|
||||
// Could check to see if provider is a V2Adaptor to avoid
|
||||
// object creation, but there is little point.
|
||||
return new StoreRef(provider.getStoreUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for {@link HomeFolderProvider2.getHomeFolder} (so that it
|
||||
* does not need its own NodeService) that returns a person property value.
|
||||
*/
|
||||
public String getPersonProperty(NodeRef person, QName name)
|
||||
{
|
||||
String value = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(person, name));
|
||||
|
||||
if(value == null || value.length() == 0)
|
||||
{
|
||||
throw new PersonException("Can not create a home folder when the "+name+" property is null or empty");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void clearCaches(HomeFolderProvider2 provider)
|
||||
{
|
||||
getRootPathNodeRefMap(provider).clear();
|
||||
}
|
||||
|
||||
NodeRef getRootPathNodeRef(HomeFolderProvider2 provider)
|
||||
{
|
||||
String rootPath = provider.getRootPath();
|
||||
String tenantDomain = (tenantService != null ? tenantService.getCurrentUserDomain() : TenantService.DEFAULT_DOMAIN);
|
||||
Map<String, NodeRef> rootPathNodeRefMap = getRootPathNodeRefMap(provider);
|
||||
NodeRef rootPathNodeRef = rootPathNodeRefMap.get(tenantDomain);
|
||||
if (rootPathNodeRef == null)
|
||||
{
|
||||
// ok with race condition for initial construction
|
||||
rootPathNodeRef = resolvePath(provider, rootPath);
|
||||
rootPathNodeRefMap.put(tenantDomain, rootPathNodeRef);
|
||||
}
|
||||
return rootPathNodeRef;
|
||||
}
|
||||
|
||||
private Map<String, NodeRef> getRootPathNodeRefMap(HomeFolderProvider2 provider)
|
||||
{
|
||||
String name = provider.getName();
|
||||
Map<String, NodeRef> rootPathNodeRefMap = rootPathNodeRefMaps.get(name);
|
||||
if (rootPathNodeRefMap == null)
|
||||
{
|
||||
// ok with race condition for initial construction
|
||||
rootPathNodeRefMap = new ConcurrentHashMap<String, NodeRef>();
|
||||
rootPathNodeRefMaps.put(name, rootPathNodeRefMap);
|
||||
}
|
||||
return rootPathNodeRefMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to resolve paths to nodes.
|
||||
*/
|
||||
NodeRef resolvePath(HomeFolderProvider2 provider, String pathToResolve)
|
||||
{
|
||||
List<NodeRef> refs = serviceRegistry.getSearchService().selectNodes(
|
||||
serviceRegistry.getNodeService().getRootNode(getStoreRef(provider)),
|
||||
pathToResolve, null,
|
||||
serviceRegistry.getNamespaceService(), false);
|
||||
if (refs.size() != 1)
|
||||
{
|
||||
throw new IllegalStateException("Non-unique path: found : " +
|
||||
pathToResolve + " " + refs.size());
|
||||
}
|
||||
return refs.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for {@link HomeFolderProvider2.getHomeFolder(NodeRef)}
|
||||
* implementations to return a {@link HomeSpaceNodeRef}
|
||||
* @param referenceRootNode indicates that a reference to the root node
|
||||
* should be returned if the home folder property on the person
|
||||
* has not yet been set.
|
||||
*/
|
||||
public HomeSpaceNodeRef getHomeFolder(HomeFolderProvider2 provider, NodeRef person, boolean referenceRootNode)
|
||||
{
|
||||
HomeSpaceNodeRef homeSpaceNodeRef = null;
|
||||
NodeRef existingHomeFolder = DefaultTypeConverter.INSTANCE.convert(
|
||||
NodeRef.class, serviceRegistry.getNodeService().getProperty(
|
||||
person, ContentModel.PROP_HOMEFOLDER));
|
||||
if (existingHomeFolder != null)
|
||||
{
|
||||
homeSpaceNodeRef = new HomeSpaceNodeRef(existingHomeFolder,
|
||||
HomeSpaceNodeRef.Status.VALID);
|
||||
}
|
||||
else if (referenceRootNode)
|
||||
{
|
||||
homeSpaceNodeRef = new HomeSpaceNodeRef(getRootPathNodeRef(provider),
|
||||
HomeSpaceNodeRef.Status.REFERENCED);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileFolderService fileFolderService = serviceRegistry.getFileFolderService();
|
||||
List<String> homeFolderPath = provider.getHomeFolderPath(person);
|
||||
|
||||
FileInfo fileInfo;
|
||||
|
||||
// Test if it already exists
|
||||
NodeRef existing = getExisting(provider, fileFolderService, homeFolderPath);
|
||||
if (existing != null)
|
||||
{
|
||||
fileInfo = fileFolderService.getFileInfo(existing);
|
||||
}
|
||||
else
|
||||
{
|
||||
fileInfo = createTree(provider, getRootPathNodeRef(provider), homeFolderPath,
|
||||
provider.getTemplateNodeRef(), fileFolderService);
|
||||
}
|
||||
NodeRef homeFolderNodeRef = fileInfo.getNodeRef();
|
||||
return new HomeSpaceNodeRef(homeFolderNodeRef, HomeSpaceNodeRef.Status.CREATED);
|
||||
}
|
||||
return homeSpaceNodeRef;
|
||||
}
|
||||
|
||||
private NodeRef getExisting(HomeFolderProvider2 provider, FileFolderService fileFolderService,
|
||||
List<String> homeFolderPath)
|
||||
{
|
||||
NodeRef existing;
|
||||
try
|
||||
{
|
||||
FileInfo existingFileInfo = fileFolderService.resolveNamePath(getRootPathNodeRef(provider), homeFolderPath);
|
||||
existing = existingFileInfo.getNodeRef();
|
||||
}
|
||||
catch (FileNotFoundException fnfe)
|
||||
{
|
||||
existing = null;// home folder noderef doesn't exist yet
|
||||
}
|
||||
return existing;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a tree of folder nodes based on the path elements provided.
|
||||
*/
|
||||
private FileInfo createTree(HomeFolderProvider2 provider, NodeRef root,
|
||||
List<String> homeFolderPath, NodeRef templateNodeRef,
|
||||
FileFolderService fileFolderService)
|
||||
{
|
||||
NodeRef newParent = createNewParentIfRequired(root, homeFolderPath, fileFolderService);
|
||||
String homeFolderName = homeFolderPath.get(homeFolderPath.size()-1);
|
||||
FileInfo fileInfo;
|
||||
if (templateNodeRef == null)
|
||||
{
|
||||
fileInfo = fileFolderService.create(
|
||||
newParent,
|
||||
homeFolderName,
|
||||
ContentModel.TYPE_FOLDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
fileInfo = fileFolderService.copy(
|
||||
templateNodeRef,
|
||||
newParent,
|
||||
homeFolderName);
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
throw new PersonException("Invalid template to create home space");
|
||||
}
|
||||
}
|
||||
return fileInfo;
|
||||
}
|
||||
|
||||
private NodeRef createNewParentIfRequired(NodeRef root,
|
||||
List<String> homeFolderPath, FileFolderService fileFolderService)
|
||||
{
|
||||
if (homeFolderPath.size() > 1)
|
||||
{
|
||||
List<String> parentPath = new ArrayList<String>(homeFolderPath);
|
||||
parentPath.remove(parentPath.size()-1);
|
||||
return FileFolderUtil.makeFolders(fileFolderService, root,
|
||||
parentPath, ContentModel.TYPE_FOLDER).getNodeRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user