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:
@@ -375,13 +375,22 @@
|
|||||||
<ref bean="userHomesHomeFolderProvider" />
|
<ref bean="userHomesHomeFolderProvider" />
|
||||||
</property>
|
</property>
|
||||||
<property name="enableHomeFolderCreationAsPeopleAreCreated">
|
<property name="enableHomeFolderCreationAsPeopleAreCreated">
|
||||||
<!--<value>false</value> -->
|
|
||||||
<value>${home.folder.creation.eager}</value>
|
<value>${home.folder.creation.eager}</value>
|
||||||
</property>
|
</property>
|
||||||
|
<!-- Requests services via ServiceRegistry for audit -->
|
||||||
|
<property name="serviceRegistry">
|
||||||
|
<ref bean="ServiceRegistry" />
|
||||||
|
</property>
|
||||||
|
<property name="tenantService">
|
||||||
|
<ref bean="tenantService" />
|
||||||
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean name="baseHomeFolderProvider" class="org.alfresco.repo.security.person.AbstractHomeFolderProvider" abstract="true">
|
<!-- deprecated use baseHomeFolderProvider2 -->
|
||||||
<!-- Requests services via ServiceRegistry for auditability -->
|
<bean name="baseHomeFolderProvider"
|
||||||
|
class="org.alfresco.repo.security.person.AbstractHomeFolderProvider"
|
||||||
|
abstract="true">
|
||||||
|
<!-- Requests services via ServiceRegistry for audit -->
|
||||||
<property name="serviceRegistry">
|
<property name="serviceRegistry">
|
||||||
<ref bean="ServiceRegistry" />
|
<ref bean="ServiceRegistry" />
|
||||||
</property>
|
</property>
|
||||||
@@ -393,8 +402,47 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean name="companyHomeFolderProvider" class="org.alfresco.repo.security.person.ExistingPathBasedHomeFolderProvider" parent="baseHomeFolderProvider">
|
<bean name="baseHomeFolderProvider2"
|
||||||
<property name="path">
|
class="org.alfresco.repo.security.person.AbstractHomeFolderProvider2"
|
||||||
|
abstract="true">
|
||||||
|
<property name="homeFolderManager">
|
||||||
|
<ref bean="homeFolderManager" />
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean name="existingHomeFolderProvider"
|
||||||
|
class="org.alfresco.repo.security.person.ExistingPathBasedHomeFolderProvider2"
|
||||||
|
abstract="true" parent="baseHomeFolderProvider2">
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean name="usernameHomeFolderProvider"
|
||||||
|
class="org.alfresco.repo.security.person.UsernameHomeFolderProvider"
|
||||||
|
abstract="true" parent="baseHomeFolderProvider2">
|
||||||
|
<property name="onCreatePermissionsManager">
|
||||||
|
<ref bean="defaultOnCreatePermissionsManager" />
|
||||||
|
</property>
|
||||||
|
<property name="onReferencePermissionsManager">
|
||||||
|
<ref bean="defaultOnReferencePermissionsManager" />
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean name="regexHomeFolderProvider"
|
||||||
|
class="org.alfresco.repo.security.person.RegexHomeFolderProvider"
|
||||||
|
abstract="true" parent="usernameHomeFolderProvider">
|
||||||
|
<property name="propertyName">
|
||||||
|
<value>${spaces.user_homes.regex.key}</value>
|
||||||
|
</property>
|
||||||
|
<property name="pattern">
|
||||||
|
<value>${spaces.user_homes.regex.pattern}</value>
|
||||||
|
</property>
|
||||||
|
<property name="groupOrder">
|
||||||
|
<value>${spaces.user_homes.regex.group_order}</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
|
<bean name="companyHomeFolderProvider" parent="existingHomeFolderProvider">
|
||||||
|
<property name="rootPath">
|
||||||
<value>/${spaces.company_home.childname}</value>
|
<value>/${spaces.company_home.childname}</value>
|
||||||
</property>
|
</property>
|
||||||
<property name="storeUrl">
|
<property name="storeUrl">
|
||||||
@@ -402,7 +450,8 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean name="guestHomeFolderProviderPermissionsManager" class="org.alfresco.repo.security.person.PermissionsManagerImpl">
|
<bean name="guestHomeFolderProviderPermissionsManager"
|
||||||
|
class="org.alfresco.repo.security.person.PermissionsManagerImpl">
|
||||||
<property name="permissionService">
|
<property name="permissionService">
|
||||||
<ref bean="permissionServiceImpl" />
|
<ref bean="permissionServiceImpl" />
|
||||||
</property>
|
</property>
|
||||||
@@ -417,12 +466,8 @@
|
|||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
<bean name="guestHomeFolderProvider" class="org.alfresco.repo.security.person.ExistingPathBasedHomeFolderProvider" parent="baseHomeFolderProvider">
|
<bean name="guestHomeFolderProvider" parent="existingHomeFolderProvider">
|
||||||
<!-- Requests services via ServiceRegistry for auditability -->
|
<property name="rootPath">
|
||||||
<property name="serviceRegistry">
|
|
||||||
<ref bean="ServiceRegistry" />
|
|
||||||
</property>
|
|
||||||
<property name="path">
|
|
||||||
<value>/${spaces.company_home.childname}/${spaces.guest_home.childname}</value>
|
<value>/${spaces.company_home.childname}/${spaces.guest_home.childname}</value>
|
||||||
</property>
|
</property>
|
||||||
<property name="storeUrl">
|
<property name="storeUrl">
|
||||||
@@ -436,9 +481,12 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean name="bootstrapHomeFolderProvider" class="org.alfresco.repo.security.person.BootstrapHomeFolderProvider" parent="baseHomeFolderProvider" />
|
<bean name="bootstrapHomeFolderProvider"
|
||||||
|
class="org.alfresco.repo.security.person.BootstrapHomeFolderProvider"
|
||||||
|
parent="baseHomeFolderProvider2" />
|
||||||
|
|
||||||
<bean name="defaultOnCreatePermissionsManager" class="org.alfresco.repo.security.person.PermissionsManagerImpl" >
|
<bean name="defaultOnCreatePermissionsManager"
|
||||||
|
class="org.alfresco.repo.security.person.PermissionsManagerImpl" >
|
||||||
<property name="permissionService">
|
<property name="permissionService">
|
||||||
<ref bean="permissionServiceImpl" />
|
<ref bean="permissionServiceImpl" />
|
||||||
</property>
|
</property>
|
||||||
@@ -460,7 +508,8 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean name="defaultOnReferencePermissionsManager" class="org.alfresco.repo.security.person.PermissionsManagerImpl" >
|
<bean name="defaultOnReferencePermissionsManager"
|
||||||
|
class="org.alfresco.repo.security.person.PermissionsManagerImpl" >
|
||||||
<property name="permissionService">
|
<property name="permissionService">
|
||||||
<ref bean="permissionServiceImpl" />
|
<ref bean="permissionServiceImpl" />
|
||||||
</property>
|
</property>
|
||||||
@@ -474,40 +523,32 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean name="personalHomeFolderProvider" class="org.alfresco.repo.security.person.UIDBasedHomeFolderProvider" parent="baseHomeFolderProvider">
|
<bean name="personalHomeFolderProvider" parent="usernameHomeFolderProvider">
|
||||||
<!-- Requests services via ServiceRegistry for auditability -->
|
<property name="rootPath">
|
||||||
<property name="serviceRegistry">
|
|
||||||
<ref bean="ServiceRegistry" />
|
|
||||||
</property>
|
|
||||||
<property name="path">
|
|
||||||
<value>/${spaces.company_home.childname}</value>
|
<value>/${spaces.company_home.childname}</value>
|
||||||
</property>
|
</property>
|
||||||
<property name="storeUrl">
|
<property name="storeUrl">
|
||||||
<value>${spaces.store}</value>
|
<value>${spaces.store}</value>
|
||||||
</property>
|
</property>
|
||||||
<property name="onCreatePermissionsManager">
|
|
||||||
<ref bean="defaultOnCreatePermissionsManager" />
|
|
||||||
</property>
|
|
||||||
<property name="onReferencePermissionsManager">
|
|
||||||
<ref bean="defaultOnReferencePermissionsManager" />
|
|
||||||
</property>
|
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean name="userHomesHomeFolderProvider" class="org.alfresco.repo.security.person.UIDBasedHomeFolderProvider" parent="baseHomeFolderProvider">
|
<bean name="userHomesHomeFolderProvider" parent="usernameHomeFolderProvider">
|
||||||
<property name="path">
|
<property name="rootPath">
|
||||||
<value>/${spaces.company_home.childname}/${spaces.user_homes.childname}</value>
|
<value>/${spaces.company_home.childname}/${spaces.user_homes.childname}</value>
|
||||||
</property>
|
</property>
|
||||||
<property name="storeUrl">
|
<property name="storeUrl">
|
||||||
<value>${spaces.store}</value>
|
<value>${spaces.store}</value>
|
||||||
</property>
|
</property>
|
||||||
<property name="onCreatePermissionsManager">
|
|
||||||
<ref bean="defaultOnCreatePermissionsManager" />
|
|
||||||
</property>
|
|
||||||
<property name="onReferencePermissionsManager">
|
|
||||||
<ref bean="defaultOnReferencePermissionsManager" />
|
|
||||||
</property>
|
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean name="largeHomeFolderProvider" parent="regexHomeFolderProvider">
|
||||||
|
<property name="rootPath">
|
||||||
|
<value>/${spaces.company_home.childname}/${spaces.user_homes.childname}</value>
|
||||||
|
</property>
|
||||||
|
<property name="storeUrl">
|
||||||
|
<value>${spaces.store}</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
<!-- The ticket component. -->
|
<!-- The ticket component. -->
|
||||||
|
@@ -687,6 +687,18 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<!-- Synchronization of home folders locations to their HomeFolderProvider -->
|
||||||
|
<bean id="homeFolderProviderSynchronizer" class="org.alfresco.repo.security.person.HomeFolderProviderSynchronizer">
|
||||||
|
<constructor-arg ref="global-properties" />
|
||||||
|
<constructor-arg ref="transactionService" />
|
||||||
|
<constructor-arg ref="authorityService" />
|
||||||
|
<constructor-arg ref="personService" />
|
||||||
|
<constructor-arg ref="nodeService" />
|
||||||
|
<constructor-arg ref="fileFolderService" />
|
||||||
|
<constructor-arg ref="homeFolderManager" />
|
||||||
|
<constructor-arg ref="tenantAdminService" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
<!-- User registry synchronization jobs (e.g. LDAP) -->
|
<!-- User registry synchronization jobs (e.g. LDAP) -->
|
||||||
<bean id="Synchronization" class="org.alfresco.repo.management.subsystems.ChildApplicationContextFactory" parent="abstractPropertyBackedBean">
|
<bean id="Synchronization" class="org.alfresco.repo.management.subsystems.ChildApplicationContextFactory" parent="abstractPropertyBackedBean">
|
||||||
<property name="autoStart">
|
<property name="autoStart">
|
||||||
|
@@ -175,7 +175,7 @@
|
|||||||
<title>Can this resource be enabled/disabled.</title>
|
<title>Can this resource be enabled/disabled.</title>
|
||||||
<properties>
|
<properties>
|
||||||
<property name="trx:enabled">
|
<property name="trx:enabled">
|
||||||
<title>Is this enabled.</title>
|
<title>Enabled</title>
|
||||||
<type>d:boolean</type>
|
<type>d:boolean</type>
|
||||||
<mandatory>true</mandatory>
|
<mandatory>true</mandatory>
|
||||||
</property>
|
</property>
|
||||||
|
@@ -384,6 +384,9 @@ spaces.wcm.childname=app:wcm
|
|||||||
spaces.wcm_content_forms.childname=app:wcm_forms
|
spaces.wcm_content_forms.childname=app:wcm_forms
|
||||||
spaces.content_forms.childname=app:forms
|
spaces.content_forms.childname=app:forms
|
||||||
spaces.user_homes.childname=app:user_homes
|
spaces.user_homes.childname=app:user_homes
|
||||||
|
spaces.user_homes.regex.key=userName
|
||||||
|
spaces.user_homes.regex.pattern=
|
||||||
|
spaces.user_homes.regex.group_order=
|
||||||
spaces.sites.childname=st:sites
|
spaces.sites.childname=st:sites
|
||||||
spaces.templates.email.invite.childname=cm:invite
|
spaces.templates.email.invite.childname=cm:invite
|
||||||
spaces.templates.email.activities.childname=cm:activities
|
spaces.templates.email.activities.childname=cm:activities
|
||||||
@@ -399,6 +402,7 @@ spaces.extension_webscripts.childname=cm:extensionwebscripts
|
|||||||
spaces.models.childname=app:models
|
spaces.models.childname=app:models
|
||||||
spaces.workflow.definitions.childname=app:workflow_defs
|
spaces.workflow.definitions.childname=app:workflow_defs
|
||||||
|
|
||||||
|
|
||||||
# ADM VersionStore Configuration
|
# ADM VersionStore Configuration
|
||||||
version.store.deprecated.lightWeightVersionStore=workspace://lightWeightVersionStore
|
version.store.deprecated.lightWeightVersionStore=workspace://lightWeightVersionStore
|
||||||
version.store.version2Store=workspace://version2Store
|
version.store.version2Store=workspace://version2Store
|
||||||
|
@@ -99,7 +99,7 @@ ldap.synchronization.userEmailAttributeName=mail
|
|||||||
ldap.synchronization.userOrganizationalIdAttributeName=company
|
ldap.synchronization.userOrganizationalIdAttributeName=company
|
||||||
|
|
||||||
# The default home folder provider to use for people created via LDAP import
|
# The default home folder provider to use for people created via LDAP import
|
||||||
ldap.synchronization.defaultHomeFolderProvider=userHomesHomeFolderProvider
|
ldap.synchronization.defaultHomeFolderProvider=largeHomeFolderProvider
|
||||||
|
|
||||||
# The attribute on LDAP group objects to map to the authority name property in Alfresco
|
# The attribute on LDAP group objects to map to the authority name property in Alfresco
|
||||||
ldap.synchronization.groupIdAttributeName=cn
|
ldap.synchronization.groupIdAttributeName=cn
|
||||||
|
@@ -105,7 +105,7 @@ ldap.synchronization.userEmailAttributeName=mail
|
|||||||
ldap.synchronization.userOrganizationalIdAttributeName=o
|
ldap.synchronization.userOrganizationalIdAttributeName=o
|
||||||
|
|
||||||
# The default home folder provider to use for people created via LDAP import
|
# The default home folder provider to use for people created via LDAP import
|
||||||
ldap.synchronization.defaultHomeFolderProvider=userHomesHomeFolderProvider
|
ldap.synchronization.defaultHomeFolderProvider=largeHomeFolderProvider
|
||||||
|
|
||||||
# The attribute on LDAP group objects to map to the authority name property in Alfresco
|
# The attribute on LDAP group objects to map to the authority name property in Alfresco
|
||||||
ldap.synchronization.groupIdAttributeName=cn
|
ldap.synchronization.groupIdAttributeName=cn
|
||||||
|
@@ -33,6 +33,7 @@ import org.alfresco.repo.batch.BatchProcessor;
|
|||||||
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
|
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
|
||||||
import org.alfresco.repo.domain.qname.QNameDAO;
|
import org.alfresco.repo.domain.qname.QNameDAO;
|
||||||
import org.alfresco.repo.importer.ImporterBootstrap;
|
import org.alfresco.repo.importer.ImporterBootstrap;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.rule.RuleService;
|
import org.alfresco.service.cmr.rule.RuleService;
|
||||||
@@ -110,18 +111,22 @@ public class FixUserQNamesPatch extends AbstractPatch implements ApplicationEven
|
|||||||
20,
|
20,
|
||||||
this.applicationEventPublisher, logger, 1000);
|
this.applicationEventPublisher, logger, 1000);
|
||||||
|
|
||||||
|
final String runAsUser = AuthenticationUtil.getRunAsUser();
|
||||||
|
|
||||||
int updated = batchProcessor.process(new BatchProcessWorker<ChildAssociationRef>()
|
int updated = batchProcessor.process(new BatchProcessWorker<ChildAssociationRef>()
|
||||||
{
|
{
|
||||||
public void beforeProcess() throws Throwable
|
public void beforeProcess() throws Throwable
|
||||||
{
|
{
|
||||||
// Disable rules
|
// Disable rules
|
||||||
ruleService.disableRules();
|
ruleService.disableRules();
|
||||||
|
AuthenticationUtil.setRunAsUser(runAsUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void afterProcess() throws Throwable
|
public void afterProcess() throws Throwable
|
||||||
{
|
{
|
||||||
// Enable rules
|
// Enable rules
|
||||||
ruleService.enableRules();
|
ruleService.enableRules();
|
||||||
|
AuthenticationUtil.clearCurrentSecurityContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getIdentifier(ChildAssociationRef entry)
|
public String getIdentifier(ChildAssociationRef entry)
|
||||||
|
@@ -480,7 +480,14 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
|||||||
{
|
{
|
||||||
logger.debug("[getMessageInternal] " + this);
|
logger.debug("[getMessageInternal] " + this);
|
||||||
}
|
}
|
||||||
AbstractMimeMessage mes = (AbstractMimeMessage) messages.get(uid).getMimeMessage();
|
SimpleStoredMessage storedMessage = messages.get(uid);
|
||||||
|
if (storedMessage == null)
|
||||||
|
{
|
||||||
|
messagesCache.remove(uid);
|
||||||
|
msnCache.remove(uid);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
AbstractMimeMessage mes = (AbstractMimeMessage) storedMessage.getMimeMessage();
|
||||||
FileInfo mesInfo = mes.getMessageInfo();
|
FileInfo mesInfo = mes.getMessageInfo();
|
||||||
|
|
||||||
Date modified = (Date) serviceRegistry.getNodeService().getProperty(mesInfo.getNodeRef(), ContentModel.PROP_MODIFIED);
|
Date modified = (Date) serviceRegistry.getNodeService().getProperty(mesInfo.getNodeRef(), ContentModel.PROP_MODIFIED);
|
||||||
@@ -1181,7 +1188,10 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
|||||||
if (nodeService.hasAspect(folderNodeRef, ImapModel.ASPECT_IMAP_FOLDER))
|
if (nodeService.hasAspect(folderNodeRef, ImapModel.ASPECT_IMAP_FOLDER))
|
||||||
{
|
{
|
||||||
modifDate = ((Long) nodeService.getProperty(folderNodeRef, ImapModel.PROP_UIDVALIDITY));
|
modifDate = ((Long) nodeService.getProperty(folderNodeRef, ImapModel.PROP_UIDVALIDITY));
|
||||||
return (modifDate - YEAR_2005) / 1000;
|
// we need tens part of the second at least, because
|
||||||
|
// we should avoid issues when several changes were completed within a second.
|
||||||
|
// so, divide by 100 instead of 1000. see ImapServiceImplCacheTest#testRepoBehaviourWithFoldersCache()
|
||||||
|
return (modifDate - YEAR_2005) / 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Long(0);
|
return new Long(0);
|
||||||
|
@@ -100,6 +100,8 @@ import org.springframework.extensions.surf.util.AbstractLifecycleBean;
|
|||||||
import org.springframework.extensions.surf.util.I18NUtil;
|
import org.springframework.extensions.surf.util.I18NUtil;
|
||||||
import org.springframework.util.FileCopyUtils;
|
import org.springframework.util.FileCopyUtils;
|
||||||
|
|
||||||
|
import com.icegreen.greenmail.imap.ImapConstants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Dmitry Vaserin
|
* @author Dmitry Vaserin
|
||||||
* @author Arseny Kovalchuk
|
* @author Arseny Kovalchuk
|
||||||
@@ -216,6 +218,11 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol
|
|||||||
this.foldersCache = foldersCache;
|
this.foldersCache = foldersCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SimpleCache<Serializable, Object> getFoldersCache()
|
||||||
|
{
|
||||||
|
return foldersCache;
|
||||||
|
}
|
||||||
|
|
||||||
public FileFolderService getFileFolderService()
|
public FileFolderService getFileFolderService()
|
||||||
{
|
{
|
||||||
return fileFolderService;
|
return fileFolderService;
|
||||||
@@ -792,11 +799,13 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol
|
|||||||
/**
|
/**
|
||||||
* Check whether resultFolder is stale
|
* Check whether resultFolder is stale
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
if(resultFolder.isStale())
|
if(resultFolder.isStale())
|
||||||
{
|
{
|
||||||
logger.debug("folder is stale");
|
logger.debug("folder is stale");
|
||||||
resultFolder = null;
|
resultFolder = null;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultFolder == null)
|
if (resultFolder == null)
|
||||||
@@ -841,7 +850,7 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol
|
|||||||
|
|
||||||
NodeRef targetNode = fileFolderService.searchSimple(nodeRef, folderNames[i]);
|
NodeRef targetNode = fileFolderService.searchSimple(nodeRef, folderNames[i]);
|
||||||
|
|
||||||
if (targetNode == null)
|
if (i == 0 && targetNode == null)
|
||||||
{
|
{
|
||||||
resultFolder = new AlfrescoImapFolder(user.getQualifiedMailboxName(), serviceRegistry);
|
resultFolder = new AlfrescoImapFolder(user.getQualifiedMailboxName(), serviceRegistry);
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
@@ -1294,6 +1303,20 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol
|
|||||||
|
|
||||||
logger.debug("listMailboxes returning size:" + result.size());
|
logger.debug("listMailboxes returning size:" + result.size());
|
||||||
|
|
||||||
|
StringBuilder prefix = new StringBuilder(128);
|
||||||
|
prefix.append(ImapConstants.USER_NAMESPACE)
|
||||||
|
.append(AlfrescoImapConst.HIERARCHY_DELIMITER)
|
||||||
|
.append(user.getQualifiedMailboxName())
|
||||||
|
.append(AlfrescoImapConst.HIERARCHY_DELIMITER);
|
||||||
|
int prefixLength = prefix.length();
|
||||||
|
|
||||||
|
for(AlfrescoImapFolder folder : result)
|
||||||
|
{
|
||||||
|
String cacheKey = folder.getFullName().substring(prefixLength + 1, folder.getFullName().length() - 1);
|
||||||
|
logger.debug("[listMailboxes] Adding the cache entry : " + cacheKey);
|
||||||
|
foldersCache.put(cacheKey, folder);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2150,6 +2173,38 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void beforeDeleteNode(NodeRef nodeRef)
|
||||||
|
{
|
||||||
|
|
||||||
|
NodeRef parentNodeRef = nodeService.getPrimaryParent(nodeRef).getParentRef();
|
||||||
|
if (ContentModel.TYPE_FOLDER.equals(nodeService.getType(nodeRef)))
|
||||||
|
{
|
||||||
|
// If a node is a folder, we need to remove its' cache with its' children cache as well
|
||||||
|
invalidateFolderCacheByNodeRef(nodeRef, true);
|
||||||
|
}
|
||||||
|
else if (ContentModel.TYPE_CONTENT.equals(nodeService.getType(nodeRef)))
|
||||||
|
{
|
||||||
|
// If a node is a content, it is simpler to remove its' parent cache
|
||||||
|
// to avoid of deal with folder messages cache
|
||||||
|
invalidateFolderCacheByNodeRef(parentNodeRef, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Add a listener once, when a lots of messsages were created/moved into the folder
|
||||||
|
if (AlfrescoTransactionSupport.getResource(UIDVALIDITY_LISTENER_ALREADY_BOUND) == null)
|
||||||
|
{
|
||||||
|
AlfrescoTransactionSupport.bindListener(new UidValidityTransactionListener(parentNodeRef, nodeService));
|
||||||
|
AlfrescoTransactionSupport.bindResource(UIDVALIDITY_LISTENER_ALREADY_BOUND, true);
|
||||||
|
}
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("[beforeDeleteNode] Node " + nodeRef + " going to be removed. UIDVALIDITY will be changed for " + parentNodeRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class UidValidityTransactionListener extends TransactionListenerAdapter
|
private class UidValidityTransactionListener extends TransactionListenerAdapter
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -2202,7 +2257,7 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol
|
|||||||
}
|
}
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("UIDVALIDITY was modified");
|
logger.debug("UIDVALIDITY was modified for " + folderNodeRef);
|
||||||
}
|
}
|
||||||
return modifDate;
|
return modifDate;
|
||||||
}
|
}
|
||||||
@@ -2212,6 +2267,69 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void invalidateFolderCacheByNodeRef(NodeRef folderNodeRef, boolean invalidateChildren)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
if (invalidateChildren)
|
||||||
|
{
|
||||||
|
logger.debug("[invalidateFolderCacheByNodeRef] Invalidate cache entries for " + folderNodeRef);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.debug("[invalidateFolderCacheByNodeRef] Invalidate cache entries for " + folderNodeRef + " and children");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalidateChildren)
|
||||||
|
{
|
||||||
|
SimpleCache<Serializable, Object> foldersCache = getFoldersCache();
|
||||||
|
List<Serializable> toRemove = new LinkedList<Serializable>();
|
||||||
|
for(Serializable name : foldersCache.getKeys())
|
||||||
|
{
|
||||||
|
AlfrescoImapFolder folder = (AlfrescoImapFolder) foldersCache.get(name);
|
||||||
|
if (folderNodeRef.equals(folder.getFolderInfo().getNodeRef()))
|
||||||
|
{
|
||||||
|
toRemove.add(name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toRemove.size() > 0)
|
||||||
|
{
|
||||||
|
String rootName = (String) toRemove.get(0);
|
||||||
|
for(Serializable name : foldersCache.getKeys())
|
||||||
|
{
|
||||||
|
if (((String) name).startsWith(rootName))
|
||||||
|
{
|
||||||
|
toRemove.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Caches to invalidate: " + toRemove.toString());
|
||||||
|
}
|
||||||
|
for(Serializable name : toRemove)
|
||||||
|
{
|
||||||
|
foldersCache.remove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SimpleCache<Serializable, Object> foldersCache = getFoldersCache();
|
||||||
|
for(Serializable name : foldersCache.getKeys())
|
||||||
|
{
|
||||||
|
AlfrescoImapFolder folder = (AlfrescoImapFolder) foldersCache.get(name);
|
||||||
|
if (folderNodeRef.equals(folder.getFolderInfo().getNodeRef()))
|
||||||
|
{
|
||||||
|
foldersCache.remove(name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if provided nodeRef is in Sites/.../documentlibrary
|
* Return true if provided nodeRef is in Sites/.../documentlibrary
|
||||||
*/
|
*/
|
||||||
|
224
source/java/org/alfresco/repo/imap/ImapServiceImplCacheTest.java
Normal file
224
source/java/org/alfresco/repo/imap/ImapServiceImplCacheTest.java
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
package org.alfresco.repo.imap;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
|
||||||
|
import org.alfresco.repo.model.filefolder.FileFolderServiceImpl;
|
||||||
|
import org.alfresco.service.ServiceRegistry;
|
||||||
|
import org.alfresco.service.cmr.model.FileFolderService;
|
||||||
|
import org.alfresco.service.cmr.model.FileInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.ContentService;
|
||||||
|
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||||
|
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.search.SearchService;
|
||||||
|
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||||
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
|
import org.alfresco.util.ApplicationContextHelper;
|
||||||
|
import org.alfresco.util.config.RepositoryFolderConfigBean;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
|
import com.icegreen.greenmail.store.SimpleStoredMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit test for cache implementation in the ImapServiceImpl. Based on ImapServiceImplTest, but
|
||||||
|
* we need this separate test because we need to get transactions to commit to trigger behaviours in ImapServiceImpl.
|
||||||
|
*
|
||||||
|
* @author ArsenyKo
|
||||||
|
*/
|
||||||
|
public class ImapServiceImplCacheTest extends TestCase
|
||||||
|
{
|
||||||
|
private static final String USER_NAME = "admin";
|
||||||
|
private static final String USER_PASSWORD = "admin";
|
||||||
|
|
||||||
|
private static final String TEST_IMAP_FOLDER_NAME = "aaa";
|
||||||
|
|
||||||
|
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||||
|
private NodeService nodeService;
|
||||||
|
private MutableAuthenticationService authenticationService;
|
||||||
|
private SearchService searchService;
|
||||||
|
private NamespaceService namespaceService;
|
||||||
|
private FileFolderService fileFolderService;
|
||||||
|
private ContentService contentService;
|
||||||
|
|
||||||
|
private ImapService imapService;
|
||||||
|
|
||||||
|
private NodeRef testImapFolderNodeRef;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception
|
||||||
|
{
|
||||||
|
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean("ServiceRegistry");
|
||||||
|
nodeService = serviceRegistry.getNodeService();
|
||||||
|
authenticationService = serviceRegistry.getAuthenticationService();
|
||||||
|
imapService = serviceRegistry.getImapService();
|
||||||
|
searchService = serviceRegistry.getSearchService();
|
||||||
|
namespaceService = serviceRegistry.getNamespaceService();
|
||||||
|
fileFolderService = serviceRegistry.getFileFolderService();
|
||||||
|
contentService = serviceRegistry.getContentService();
|
||||||
|
|
||||||
|
authenticationService.authenticate(USER_NAME, USER_PASSWORD.toCharArray());
|
||||||
|
|
||||||
|
String storePath = "workspace://SpacesStore";
|
||||||
|
String companyHomePathInStore = "/app:company_home";
|
||||||
|
|
||||||
|
StoreRef storeRef = new StoreRef(storePath);
|
||||||
|
|
||||||
|
NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef);
|
||||||
|
|
||||||
|
List<NodeRef> nodeRefs = searchService.selectNodes(storeRootNodeRef, companyHomePathInStore, null, namespaceService, false);
|
||||||
|
NodeRef companyHomeNodeRef = nodeRefs.get(0);
|
||||||
|
|
||||||
|
ChildApplicationContextFactory imap = (ChildApplicationContextFactory) ctx.getBean("imap");
|
||||||
|
ApplicationContext imapCtx = imap.getApplicationContext();
|
||||||
|
ImapServiceImpl imapServiceImpl = (ImapServiceImpl)imapCtx.getBean("imapService");
|
||||||
|
|
||||||
|
// Creating IMAP test folder for IMAP root
|
||||||
|
LinkedList<String> folders = new LinkedList<String>();
|
||||||
|
folders.add(TEST_IMAP_FOLDER_NAME);
|
||||||
|
FileFolderServiceImpl.makeFolders(fileFolderService, companyHomeNodeRef, folders, ContentModel.TYPE_FOLDER);
|
||||||
|
|
||||||
|
// Setting IMAP root
|
||||||
|
RepositoryFolderConfigBean imapHome = new RepositoryFolderConfigBean();
|
||||||
|
imapHome.setStore(storePath);
|
||||||
|
imapHome.setRootPath(companyHomePathInStore);
|
||||||
|
imapHome.setFolderPath(TEST_IMAP_FOLDER_NAME);
|
||||||
|
imapServiceImpl.setImapHome(imapHome);
|
||||||
|
|
||||||
|
// Starting IMAP
|
||||||
|
imapServiceImpl.startup();
|
||||||
|
|
||||||
|
nodeRefs = searchService.selectNodes(storeRootNodeRef,
|
||||||
|
companyHomePathInStore + "/" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + TEST_IMAP_FOLDER_NAME,
|
||||||
|
null,
|
||||||
|
namespaceService,
|
||||||
|
false);
|
||||||
|
testImapFolderNodeRef = nodeRefs.get(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tearDown() throws Exception
|
||||||
|
{
|
||||||
|
fileFolderService.delete(testImapFolderNodeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testRepoBehaviourWithFoldersCache() throws Exception
|
||||||
|
{
|
||||||
|
AlfrescoImapUser localUser = new AlfrescoImapUser(USER_NAME + "@alfresco.com", USER_NAME, USER_PASSWORD);
|
||||||
|
String folderName = "ALF9361";
|
||||||
|
String mailbox = "Alfresco IMAP" + AlfrescoImapConst.HIERARCHY_DELIMITER +
|
||||||
|
TEST_IMAP_FOLDER_NAME + AlfrescoImapConst.HIERARCHY_DELIMITER +
|
||||||
|
folderName;
|
||||||
|
int contentItemsCount = 3;
|
||||||
|
// Create a tree like ALF9361/ALF9361_0/sub_0
|
||||||
|
// Mailbox path with default mount point should be like 'Alfresco IMAP/aaa/ALF9361/ALF9361_0/sub_0
|
||||||
|
FileInfo localRootFolder = fileFolderService.create(testImapFolderNodeRef, folderName, ContentModel.TYPE_FOLDER);
|
||||||
|
List<FileInfo> subFolders = new ArrayList<FileInfo>(10);
|
||||||
|
for(int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
String childMailbox = folderName + "_" + i;
|
||||||
|
FileInfo subFolder = fileFolderService.create(localRootFolder.getNodeRef(), childMailbox, ContentModel.TYPE_FOLDER);
|
||||||
|
for(int j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
String subChildMailbox = "sub_" + j;
|
||||||
|
fileFolderService.create(subFolder.getNodeRef(), subChildMailbox, ContentModel.TYPE_FOLDER);
|
||||||
|
}
|
||||||
|
subFolders.add(subFolder);
|
||||||
|
}
|
||||||
|
// Create content within 'Alfresco IMAP/aaa/ALF9361'
|
||||||
|
createTestContent(localRootFolder, contentItemsCount);
|
||||||
|
// Load the cache
|
||||||
|
imapService.listMailboxes(localUser, "*");
|
||||||
|
imapService.listSubscribedMailboxes(localUser, "*");
|
||||||
|
// Get the folder to examine
|
||||||
|
AlfrescoImapFolder folder = imapService.getFolder(localUser, mailbox);
|
||||||
|
// Check the folder exist via IMAP
|
||||||
|
assertNotNull("Folder wasn't successfully gotten from IMAP", folder);
|
||||||
|
assertEquals(contentItemsCount, folder.getMessageCount());
|
||||||
|
// Check UIDVALIDITY
|
||||||
|
long uidValidityBefore = folder.getUidValidity();
|
||||||
|
// Delete first childMailbox 'ALF9361/ALF9361_0'
|
||||||
|
//System.out.println(" --------------------- DELETE FOLDER --------------------");
|
||||||
|
//System.out.println(" Parent " + localRootFolder.getNodeRef());
|
||||||
|
fileFolderService.delete(subFolders.get(0).getNodeRef());
|
||||||
|
// Get the folder once more and check it was changed since child was removed
|
||||||
|
folder = imapService.getFolder(localUser, mailbox);
|
||||||
|
// Content count should be the same since we havn't deleted a content yet
|
||||||
|
assertEquals(contentItemsCount, folder.getMessageCount());
|
||||||
|
long uidValidity = folder.getUidValidity();
|
||||||
|
assertTrue("UIDVALIDITY wasn't incremented", (uidValidity - uidValidityBefore) > 0);
|
||||||
|
uidValidityBefore = uidValidity;
|
||||||
|
// Try to get deleted child
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String subFolderName = mailbox + AlfrescoImapConst.HIERARCHY_DELIMITER + folderName + "_0";
|
||||||
|
folder = imapService.getFolder(localUser, subFolderName);
|
||||||
|
fail("The folder still in the cache");
|
||||||
|
}
|
||||||
|
catch (RuntimeException e)
|
||||||
|
{
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
// Try to get deleted sub child. If the cache wasn't invalidated we will get it
|
||||||
|
// But it should be connected to AlfrescoImapFolder.isStale() method.
|
||||||
|
// ArsenyKo: I think we should avoid repo API invocation like isStale...
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String subSubFolderName = mailbox + AlfrescoImapConst.HIERARCHY_DELIMITER + mailbox + "_0" + AlfrescoImapConst.HIERARCHY_DELIMITER + "sub_0";
|
||||||
|
folder = imapService.getFolder(localUser, subSubFolderName);
|
||||||
|
fail("The folder still in the cache");
|
||||||
|
}
|
||||||
|
catch (RuntimeException e)
|
||||||
|
{
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
// Do manipulations with a content in the folder to check the cache behaviour
|
||||||
|
folder = imapService.getFolder(localUser, mailbox);
|
||||||
|
SimpleStoredMessage message = folder.getMessages().get(0);
|
||||||
|
AbstractMimeMessage alfrescoMessage = (AbstractMimeMessage) message.getMimeMessage();
|
||||||
|
long uid = message.getUid();
|
||||||
|
//System.out.println(" --------------------- DELETE FILE --------------------");
|
||||||
|
//System.out.println(" Parent " + folder.getFolderInfo().getNodeRef());
|
||||||
|
// Delete a content
|
||||||
|
fileFolderService.delete(alfrescoMessage.getMessageInfo().getNodeRef());
|
||||||
|
// Get a folder once again. We expect that the folder would be retrieved from the repo,
|
||||||
|
// since its' cache should be invalidated
|
||||||
|
folder = imapService.getFolder(localUser, mailbox);
|
||||||
|
// Get UIDVALIDITY. It should be changed, since we removed a message form the mailbox.
|
||||||
|
uidValidity = folder.getUidValidity();
|
||||||
|
assertTrue("UIDVALIDITY wasn't incremented", (uidValidity - uidValidityBefore) > 0);
|
||||||
|
// Additional check whether messages cache is valid. Messages cache should be recreated
|
||||||
|
//with the new inctance of AlfrescoImapMessage
|
||||||
|
assertTrue("Messages cache is stale", contentItemsCount > folder.getMessageCount());
|
||||||
|
long[] uids = folder.getMessageUids();
|
||||||
|
Arrays.sort(uids);
|
||||||
|
assertFalse("Messages msn cache is stale", Arrays.binarySearch(uids, uid) > 0);
|
||||||
|
assertNull("Message is still in the messages cache", folder.getMessage(uid));
|
||||||
|
//System.out.println(" --------------------- THE END --------------------");
|
||||||
|
fileFolderService.delete(localRootFolder.getNodeRef());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FileInfo> createTestContent(FileInfo parent, int count)
|
||||||
|
{
|
||||||
|
List<FileInfo> result = new ArrayList<FileInfo>(count);
|
||||||
|
for(int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
FileInfo contentItem = fileFolderService.create(parent.getNodeRef(), "content_" + i, ContentModel.TYPE_CONTENT, ContentModel.ASSOC_CONTAINS);
|
||||||
|
ContentWriter contentWriter = contentService.getWriter(contentItem.getNodeRef(), ContentModel.PROP_CONTENT, false);
|
||||||
|
contentWriter.setEncoding("UTF-8");
|
||||||
|
contentWriter.putContent("TEST" + i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -441,8 +441,14 @@ public class ScriptServiceImpl implements ScriptService
|
|||||||
|
|
||||||
// add the well known node wrapper objects
|
// add the well known node wrapper objects
|
||||||
model.put("companyhome", companyHome);
|
model.put("companyhome", companyHome);
|
||||||
|
if (userHome!= null)
|
||||||
|
{
|
||||||
model.put("userhome", userHome);
|
model.put("userhome", userHome);
|
||||||
|
}
|
||||||
|
if (person != null)
|
||||||
|
{
|
||||||
model.put("person", person);
|
model.put("person", person);
|
||||||
|
}
|
||||||
if (script != null)
|
if (script != null)
|
||||||
{
|
{
|
||||||
model.put("script", script);
|
model.put("script", script);
|
||||||
|
@@ -18,9 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.security;
|
package org.alfresco.repo.security;
|
||||||
|
|
||||||
|
import junit.framework.JUnit4TestAdapter;
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
import org.alfresco.repo.audit.access.AccessAuditorTest;
|
||||||
import org.alfresco.repo.ownable.impl.OwnableServiceTest;
|
import org.alfresco.repo.ownable.impl.OwnableServiceTest;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationBootstrapTest;
|
import org.alfresco.repo.security.authentication.AuthenticationBootstrapTest;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationTest;
|
import org.alfresco.repo.security.authentication.AuthenticationTest;
|
||||||
@@ -37,6 +39,7 @@ import org.alfresco.repo.security.permissions.impl.acegi.ACLEntryAfterInvocation
|
|||||||
import org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterTest;
|
import org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterTest;
|
||||||
import org.alfresco.repo.security.permissions.impl.acegi.FilteringResultSetTest;
|
import org.alfresco.repo.security.permissions.impl.acegi.FilteringResultSetTest;
|
||||||
import org.alfresco.repo.security.permissions.impl.model.PermissionModelTest;
|
import org.alfresco.repo.security.permissions.impl.model.PermissionModelTest;
|
||||||
|
import org.alfresco.repo.security.person.HomeFolderProviderSynchronizerTest;
|
||||||
import org.alfresco.repo.security.person.PersonTest;
|
import org.alfresco.repo.security.person.PersonTest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,6 +77,8 @@ public class SecurityTestSuite extends TestSuite
|
|||||||
suite.addTestSuite(OwnableServiceTest.class);
|
suite.addTestSuite(OwnableServiceTest.class);
|
||||||
suite.addTestSuite(ReadPermissionTest.class);
|
suite.addTestSuite(ReadPermissionTest.class);
|
||||||
|
|
||||||
|
suite.addTest(new JUnit4TestAdapter(HomeFolderProviderSynchronizerTest.class));
|
||||||
|
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This file is part of Alfresco
|
* This file is part of Alfresco
|
||||||
*
|
*
|
||||||
@@ -19,17 +19,12 @@
|
|||||||
package org.alfresco.repo.security.person;
|
package org.alfresco.repo.security.person;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
|
||||||
import org.alfresco.repo.tenant.TenantService;
|
import org.alfresco.repo.tenant.TenantService;
|
||||||
import org.alfresco.service.ServiceRegistry;
|
import org.alfresco.service.ServiceRegistry;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
|
||||||
import org.alfresco.util.PropertyCheck;
|
import org.alfresco.util.PropertyCheck;
|
||||||
import org.springframework.beans.factory.BeanNameAware;
|
import org.springframework.beans.factory.BeanNameAware;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
@@ -38,6 +33,9 @@ import org.springframework.beans.factory.InitializingBean;
|
|||||||
* Common support for creating home folders This is hooked into node creation events from Person type objects via the
|
* Common support for creating home folders This is hooked into node creation events from Person type objects via the
|
||||||
* homeFolderManager. Provider must all be wired up to the homeFolderManager.
|
* homeFolderManager. Provider must all be wired up to the homeFolderManager.
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
|
* Depreciated since 4.0. {@link AbstractHomeFolderProvider2} should now be used.
|
||||||
|
*
|
||||||
* @author Andy Hind
|
* @author Andy Hind
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractHomeFolderProvider implements HomeFolderProvider, BeanNameAware, InitializingBean
|
public abstract class AbstractHomeFolderProvider implements HomeFolderProvider, BeanNameAware, InitializingBean
|
||||||
@@ -58,40 +56,34 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
|||||||
private StoreRef storeRef;
|
private StoreRef storeRef;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service registry to get hold of public services (so taht actions are audited)
|
* Service registry to get hold of public services (so that actions are audited)
|
||||||
*/
|
*/
|
||||||
private ServiceRegistry serviceRegistry;
|
private ServiceRegistry serviceRegistry;
|
||||||
|
|
||||||
/**
|
|
||||||
* Tenant service - required for MT-enabled environment, else optional
|
|
||||||
*/
|
|
||||||
private TenantService tenantService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The path to a folder
|
* The path to a folder
|
||||||
*/
|
*/
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache the result of the path look up.
|
|
||||||
*/
|
|
||||||
private Map<String, NodeRef> pathNodeRefs; // MT-aware
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The owner to set on creation of a home folder (if unset this will be the uid).
|
* The owner to set on creation of a home folder (if unset this will be the uid).
|
||||||
*/
|
*/
|
||||||
private String ownerOnCreate;
|
private String ownerOnCreate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PermissionsManager used on creating the home folder
|
||||||
|
*/
|
||||||
private PermissionsManager onCreatePermissionsManager;
|
private PermissionsManager onCreatePermissionsManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PermissionsManager used on referencing the home folder
|
||||||
|
*/
|
||||||
private PermissionsManager onReferencePermissionsManager;
|
private PermissionsManager onReferencePermissionsManager;
|
||||||
|
|
||||||
public AbstractHomeFolderProvider()
|
/**
|
||||||
{
|
* Adaptor for this instance to be a HomeFolderProvider2
|
||||||
super();
|
*/
|
||||||
|
private V2Adaptor v2Adaptor = new V2Adaptor(this);
|
||||||
pathNodeRefs = new ConcurrentHashMap<String, NodeRef>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register with the homeFolderManagewr
|
* Register with the homeFolderManagewr
|
||||||
@@ -99,13 +91,9 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
|||||||
public void afterPropertiesSet() throws Exception
|
public void afterPropertiesSet() throws Exception
|
||||||
{
|
{
|
||||||
PropertyCheck.mandatory(this, "homeFolderManager", homeFolderManager);
|
PropertyCheck.mandatory(this, "homeFolderManager", homeFolderManager);
|
||||||
homeFolderManager.addProvider(this);
|
homeFolderManager.addProvider(v2Adaptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === //
|
|
||||||
// IOC //
|
|
||||||
// === //
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the home folder manager.
|
* Get the home folder manager.
|
||||||
*/
|
*/
|
||||||
@@ -116,7 +104,6 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the home folder manager.
|
* Set the home folder manager.
|
||||||
*
|
|
||||||
* @param homeFolderManager
|
* @param homeFolderManager
|
||||||
*/
|
*/
|
||||||
public void setHomeFolderManager(HomeFolderManager homeFolderManager)
|
public void setHomeFolderManager(HomeFolderManager homeFolderManager)
|
||||||
@@ -127,6 +114,7 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
|||||||
/**
|
/**
|
||||||
* Get the provider name
|
* Get the provider name
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public String getName()
|
public String getName()
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
@@ -135,6 +123,7 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
|||||||
/**
|
/**
|
||||||
* The provider name is taken from the bean name
|
* The provider name is taken from the bean name
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void setBeanName(String name)
|
public void setBeanName(String name)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -153,7 +142,14 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
|||||||
*/
|
*/
|
||||||
public void setPath(String path)
|
public void setPath(String path)
|
||||||
{
|
{
|
||||||
|
boolean reset = this.path != null;
|
||||||
this.path = path;
|
this.path = path;
|
||||||
|
|
||||||
|
// If a reset need to clear caches
|
||||||
|
if (reset)
|
||||||
|
{
|
||||||
|
homeFolderManager.clearCaches(v2Adaptor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -201,7 +197,7 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
|||||||
*/
|
*/
|
||||||
public void setTenantService(TenantService tenantService)
|
public void setTenantService(TenantService tenantService)
|
||||||
{
|
{
|
||||||
this.tenantService = tenantService;
|
// keep class signature but no longer use value
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -212,11 +208,27 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
|||||||
this.onCreatePermissionsManager = onCreatePermissionsManager;
|
this.onCreatePermissionsManager = onCreatePermissionsManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PermissionsManager used on creating the home folder
|
||||||
|
*/
|
||||||
|
public PermissionsManager getOnCreatePermissionsManager()
|
||||||
|
{
|
||||||
|
return onCreatePermissionsManager;
|
||||||
|
}
|
||||||
|
|
||||||
public void setOnReferencePermissionsManager(PermissionsManager onReferencePermissionsManager)
|
public void setOnReferencePermissionsManager(PermissionsManager onReferencePermissionsManager)
|
||||||
{
|
{
|
||||||
this.onReferencePermissionsManager = onReferencePermissionsManager;
|
this.onReferencePermissionsManager = onReferencePermissionsManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PermissionsManager used on referencing the home folder
|
||||||
|
*/
|
||||||
|
public PermissionsManager getOnReferencePermissionsManager()
|
||||||
|
{
|
||||||
|
return onReferencePermissionsManager;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the authority to use as the owner of all home folder nodes.
|
* Set the authority to use as the owner of all home folder nodes.
|
||||||
*/
|
*/
|
||||||
@@ -225,34 +237,28 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
|||||||
this.ownerOnCreate = ownerOnCreate;
|
this.ownerOnCreate = ownerOnCreate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the authority to use as the owner of all home folder nodes.
|
||||||
|
*/
|
||||||
|
public String getOwnerOnCreate()
|
||||||
|
{
|
||||||
|
return ownerOnCreate;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache path to node resolution
|
* Cache path to node resolution
|
||||||
*/
|
*/
|
||||||
protected NodeRef getPathNodeRef()
|
protected NodeRef getPathNodeRef()
|
||||||
{
|
{
|
||||||
String tenantDomain = (tenantService != null ? tenantService.getCurrentUserDomain() : TenantService.DEFAULT_DOMAIN);
|
return homeFolderManager.getRootPathNodeRef(v2Adaptor);
|
||||||
|
|
||||||
NodeRef pathNodeRef = pathNodeRefs.get(tenantDomain);
|
|
||||||
if (pathNodeRef == null)
|
|
||||||
{
|
|
||||||
pathNodeRef = resolvePath(path);
|
|
||||||
pathNodeRefs.put(tenantDomain, pathNodeRef);
|
|
||||||
}
|
|
||||||
return pathNodeRef;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility metho to resolve paths to nodes.
|
* Utility method to resolve paths to nodes.
|
||||||
*/
|
*/
|
||||||
protected NodeRef resolvePath(String pathToResolve)
|
protected NodeRef resolvePath(String pathToResolve)
|
||||||
{
|
{
|
||||||
List<NodeRef> refs = serviceRegistry.getSearchService().selectNodes(serviceRegistry.getNodeService().getRootNode(storeRef), pathToResolve, null,
|
return homeFolderManager.resolvePath(v2Adaptor, pathToResolve);
|
||||||
serviceRegistry.getNamespaceService(), false);
|
|
||||||
if (refs.size() != 1)
|
|
||||||
{
|
|
||||||
throw new IllegalStateException("Non-unique path: found : " + pathToResolve + " " + refs.size());
|
|
||||||
}
|
|
||||||
return refs.get(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -260,69 +266,98 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
|||||||
*/
|
*/
|
||||||
public void onCreateNode(ChildAssociationRef childAssocRef)
|
public void onCreateNode(ChildAssociationRef childAssocRef)
|
||||||
{
|
{
|
||||||
AuthenticationUtil.RunAsWork<NodeRef> action = new OnCreateNode(childAssocRef);
|
homeFolderManager.homeFolderCreateAndSetPermissions(v2Adaptor, childAssocRef.getChildRef());
|
||||||
AuthenticationUtil.runAs(action, AuthenticationUtil.getSystemUserName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract implementation to find/create the approriate home space.
|
* Abstract implementation to find/create the appropriate home space.
|
||||||
*/
|
*/
|
||||||
protected abstract HomeSpaceNodeRef getHomeFolder(NodeRef person);
|
protected abstract HomeSpaceNodeRef getHomeFolder(NodeRef person);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to encapsulate the createion settinhg permissions etc
|
* Get adaptor for this instance to be a HomeFolderProvider2
|
||||||
*
|
|
||||||
* @author Andy Hind
|
|
||||||
*/
|
*/
|
||||||
private class OnCreateNode implements AuthenticationUtil.RunAsWork<NodeRef>
|
protected V2Adaptor getV2Adaptor()
|
||||||
{
|
{
|
||||||
ChildAssociationRef childAssocRef;
|
return v2Adaptor;
|
||||||
|
|
||||||
OnCreateNode(ChildAssociationRef childAssocRef)
|
|
||||||
{
|
|
||||||
this.childAssocRef = childAssocRef;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodeRef doWork() throws Exception
|
/**
|
||||||
|
* Adaptor to the HomeFolderProvider2 interface.
|
||||||
|
*/
|
||||||
|
public class V2Adaptor implements HomeFolderProvider2
|
||||||
{
|
{
|
||||||
|
AbstractHomeFolderProvider abstractHomeFolderProvider;
|
||||||
|
|
||||||
// Find person
|
public V2Adaptor(AbstractHomeFolderProvider abstractHomeFolderProvider)
|
||||||
NodeRef personNodeRef = childAssocRef.getChildRef();
|
|
||||||
// Get home folder
|
|
||||||
HomeSpaceNodeRef homeFolder = getHomeFolder(personNodeRef);
|
|
||||||
// If it exists
|
|
||||||
if (homeFolder.getNodeRef() != null)
|
|
||||||
{
|
{
|
||||||
// Get uid and keep
|
this.abstractHomeFolderProvider = abstractHomeFolderProvider;
|
||||||
String uid = DefaultTypeConverter.INSTANCE.convert(String.class, serviceRegistry.getNodeService().getProperty(personNodeRef, ContentModel.PROP_USERNAME));
|
abstractHomeFolderProvider.v2Adaptor = this;
|
||||||
|
|
||||||
// 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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String ownerToSet = ownerOnCreate == null ? uid : ownerOnCreate;
|
@Override
|
||||||
// If created..
|
public String getName()
|
||||||
if (homeFolder.getStatus() == HomeSpaceNodeRef.Status.CREATED)
|
|
||||||
{
|
{
|
||||||
if (onCreatePermissionsManager != null)
|
return abstractHomeFolderProvider.getName();
|
||||||
{
|
|
||||||
onCreatePermissionsManager.setPermissions(homeFolder.getNodeRef(), ownerToSet, uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (onReferencePermissionsManager != null)
|
|
||||||
{
|
|
||||||
onReferencePermissionsManager.setPermissions(homeFolder.getNodeRef(), ownerToSet, uid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Override
|
||||||
return homeFolder.getNodeRef();
|
public String getStoreUrl()
|
||||||
|
{
|
||||||
}
|
return abstractHomeFolderProvider.getStoreRef().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRootPath()
|
||||||
|
{
|
||||||
|
return abstractHomeFolderProvider.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getHomeFolderPath(NodeRef person)
|
||||||
|
{
|
||||||
|
return (abstractHomeFolderProvider instanceof UIDBasedHomeFolderProvider)
|
||||||
|
? ((UIDBasedHomeFolderProvider)abstractHomeFolderProvider).getHomeFolderPath(person)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NodeRef getTemplateNodeRef()
|
||||||
|
{
|
||||||
|
return (abstractHomeFolderProvider instanceof UIDBasedHomeFolderProvider)
|
||||||
|
? ((UIDBasedHomeFolderProvider)abstractHomeFolderProvider).getTemplateNodeRef()
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOwner()
|
||||||
|
{
|
||||||
|
return abstractHomeFolderProvider.getOwnerOnCreate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PermissionsManager getOnCreatePermissionsManager()
|
||||||
|
{
|
||||||
|
return abstractHomeFolderProvider.getOnReferencePermissionsManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PermissionsManager getOnReferencePermissionsManager()
|
||||||
|
{
|
||||||
|
return abstractHomeFolderProvider.getOnReferencePermissionsManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HomeSpaceNodeRef getHomeFolder(NodeRef person)
|
||||||
|
{
|
||||||
|
return abstractHomeFolderProvider.getHomeFolder(person);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The old way to create the home folder, so must still call it in case
|
||||||
|
// the method is overridden
|
||||||
|
public void onCreateNode(ChildAssociationRef childAssocRef)
|
||||||
|
{
|
||||||
|
abstractHomeFolderProvider.onCreateNode(childAssocRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||||
|
*
|
||||||
|
* This file is part of Alfresco
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.security.person;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.util.PropertyCheck;
|
||||||
|
import org.springframework.beans.factory.BeanNameAware;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class that implements {@link HomeFolderProvider2} which
|
||||||
|
* works with the {@link HomeFolderManager} (which performs most of
|
||||||
|
* the work) to create home folders in custom locations.
|
||||||
|
*
|
||||||
|
* @author Alan Davis
|
||||||
|
*/
|
||||||
|
public abstract class AbstractHomeFolderProvider2 implements
|
||||||
|
HomeFolderProvider2, BeanNameAware, InitializingBean
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The provider name
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The home folder manager
|
||||||
|
*/
|
||||||
|
private HomeFolderManager homeFolderManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The store URL.
|
||||||
|
*/
|
||||||
|
private String storeUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to the root folder
|
||||||
|
*/
|
||||||
|
private String rootPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the authority to use as the owner of all home folder nodes.
|
||||||
|
* May be {@code null}.
|
||||||
|
*/
|
||||||
|
private String owner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PermissionsManager used on creating the home folder
|
||||||
|
*/
|
||||||
|
private PermissionsManager onCreatePermissionsManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PermissionsManager used on referencing the home folder
|
||||||
|
*/
|
||||||
|
private PermissionsManager onReferencePermissionsManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register with the homeFolderManagewr
|
||||||
|
*/
|
||||||
|
public void afterPropertiesSet() throws Exception
|
||||||
|
{
|
||||||
|
PropertyCheck.mandatory(this, "homeFolderManager", homeFolderManager);
|
||||||
|
homeFolderManager.addProvider(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the home folder manager.
|
||||||
|
*/
|
||||||
|
protected HomeFolderManager getHomeFolderManager()
|
||||||
|
{
|
||||||
|
return homeFolderManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the home folder manager.
|
||||||
|
* @param homeFolderManager
|
||||||
|
*/
|
||||||
|
public void setHomeFolderManager(HomeFolderManager homeFolderManager)
|
||||||
|
{
|
||||||
|
this.homeFolderManager = homeFolderManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the provider name
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The provider name is taken from the bean name
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setBeanName(String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path of the root folder
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getRootPath()
|
||||||
|
{
|
||||||
|
return rootPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the path of the root folder
|
||||||
|
*/
|
||||||
|
public void setRootPath(String rootPath)
|
||||||
|
{
|
||||||
|
boolean reset = this.rootPath != null;
|
||||||
|
this.rootPath = rootPath;
|
||||||
|
|
||||||
|
// If a reset need to clear caches
|
||||||
|
if (reset)
|
||||||
|
{
|
||||||
|
homeFolderManager.clearCaches(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStoreUrl()
|
||||||
|
{
|
||||||
|
return storeUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the store URL.
|
||||||
|
*/
|
||||||
|
public void setStoreUrl(String storeUrl)
|
||||||
|
{
|
||||||
|
this.storeUrl = storeUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the PermissionsManager used on creating the home folder
|
||||||
|
*/
|
||||||
|
public void setOnCreatePermissionsManager(PermissionsManager onCreatePermissionsManager)
|
||||||
|
{
|
||||||
|
this.onCreatePermissionsManager = onCreatePermissionsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PermissionsManager getOnCreatePermissionsManager()
|
||||||
|
{
|
||||||
|
return onCreatePermissionsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the PermissionsManager used on referencing the home folder
|
||||||
|
*/
|
||||||
|
public void setOnReferencePermissionsManager(PermissionsManager onReferencePermissionsManager)
|
||||||
|
{
|
||||||
|
this.onReferencePermissionsManager = onReferencePermissionsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PermissionsManager getOnReferencePermissionsManager()
|
||||||
|
{
|
||||||
|
return onReferencePermissionsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the authority to use as the owner of all home folder nodes.
|
||||||
|
*/
|
||||||
|
public void setOwner(String owner)
|
||||||
|
{
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOwner()
|
||||||
|
{
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getHomeFolderPath(NodeRef person)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NodeRef getTemplateNodeRef()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This file is part of Alfresco
|
* This file is part of Alfresco
|
||||||
*
|
*
|
||||||
@@ -23,17 +23,16 @@ import org.alfresco.service.cmr.repository.NodeRef;
|
|||||||
/**
|
/**
|
||||||
* Provider to use in the boostrap process - does nothing
|
* Provider to use in the boostrap process - does nothing
|
||||||
*
|
*
|
||||||
* Probably not required as behaviour/policies are disabled during normal import.
|
* Thought to be probably not required as behaviour/policies are
|
||||||
|
* disabled during normal import, but is used for 'admin' and 'guest'
|
||||||
*
|
*
|
||||||
* @author Andy Hind
|
* @author Andy Hind
|
||||||
*/
|
*/
|
||||||
public class BootstrapHomeFolderProvider extends AbstractHomeFolderProvider
|
public class BootstrapHomeFolderProvider extends AbstractHomeFolderProvider2
|
||||||
{
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HomeSpaceNodeRef getHomeFolder(NodeRef person)
|
public HomeSpaceNodeRef getHomeFolder(NodeRef person)
|
||||||
{
|
{
|
||||||
return new HomeSpaceNodeRef(null, HomeSpaceNodeRef.Status.VALID);
|
return new HomeSpaceNodeRef(null, HomeSpaceNodeRef.Status.VALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This file is part of Alfresco
|
* This file is part of Alfresco
|
||||||
*
|
*
|
||||||
@@ -18,35 +18,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.security.person;
|
package org.alfresco.repo.security.person;
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a home space from a simple path.
|
* HomeFolderProvider that simply uses the root path for the home folder.
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
* Depreciated since 4.0. {@link ExistingPathBasedHomeFolderProvider2} should now be used.
|
||||||
*
|
*
|
||||||
* @author Andy Hind
|
* @author Andy Hind
|
||||||
*/
|
*/
|
||||||
public class ExistingPathBasedHomeFolderProvider extends AbstractHomeFolderProvider
|
public class ExistingPathBasedHomeFolderProvider extends AbstractHomeFolderProvider
|
||||||
{
|
{
|
||||||
|
|
||||||
public ExistingPathBasedHomeFolderProvider()
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected HomeSpaceNodeRef getHomeFolder(NodeRef person)
|
protected HomeSpaceNodeRef getHomeFolder(NodeRef person)
|
||||||
{
|
{
|
||||||
NodeRef existingHomeFolder = DefaultTypeConverter.INSTANCE.convert(NodeRef.class, getServiceRegistry().getNodeService().getProperty(
|
return getHomeFolderManager().getHomeFolder(getV2Adaptor(), person, true);
|
||||||
person, ContentModel.PROP_HOMEFOLDER));
|
|
||||||
if (existingHomeFolder == null)
|
|
||||||
{
|
|
||||||
return new HomeSpaceNodeRef(getPathNodeRef(), HomeSpaceNodeRef.Status.REFERENCED);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new HomeSpaceNodeRef(existingHomeFolder, HomeSpaceNodeRef.Status.VALID);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||||
|
*
|
||||||
|
* This file is part of Alfresco
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.security.person;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HomeFolderProvider that simply uses the root path for the home folder.
|
||||||
|
* Generally it is a better idea to give each user their own home folder.
|
||||||
|
*
|
||||||
|
* @author Alan Davis
|
||||||
|
*/
|
||||||
|
public class ExistingPathBasedHomeFolderProvider2 extends AbstractHomeFolderProvider2
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public HomeSpaceNodeRef getHomeFolder(NodeRef person)
|
||||||
|
{
|
||||||
|
return getHomeFolderManager().getHomeFolder(this, person, true);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This file is part of Alfresco
|
* This file is part of Alfresco
|
||||||
*
|
*
|
||||||
@@ -18,15 +18,27 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.security.person;
|
package org.alfresco.repo.security.person;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.repo.node.NodeServicePolicies;
|
import org.alfresco.repo.node.NodeServicePolicies;
|
||||||
import org.alfresco.repo.policy.JavaBehaviour;
|
import org.alfresco.repo.policy.JavaBehaviour;
|
||||||
import org.alfresco.repo.policy.PolicyComponent;
|
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.ChildAssociationRef;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
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.cmr.repository.datatype.DefaultTypeConverter;
|
||||||
import org.alfresco.service.namespace.NamespaceService;
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
import org.alfresco.service.namespace.QName;
|
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.
|
* 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
|
public class HomeFolderManager implements NodeServicePolicies.OnCreateNodePolicy
|
||||||
{
|
{
|
||||||
|
|
||||||
private PolicyComponent policyComponent;
|
private PolicyComponent policyComponent;
|
||||||
|
|
||||||
private NodeService nodeService;
|
private NodeService nodeService;
|
||||||
|
|
||||||
private boolean enableHomeFolderCreationAsPeopleAreCreated = false;
|
private boolean enableHomeFolderCreationAsPeopleAreCreated = false;
|
||||||
|
|
||||||
|
private ServiceRegistry serviceRegistry;
|
||||||
|
|
||||||
|
private TenantService tenantService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A default provider
|
* 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
|
* Bind the class behaviour to this implementation
|
||||||
@@ -90,21 +119,65 @@ public class HomeFolderManager implements NodeServicePolicies.OnCreateNodePolicy
|
|||||||
this.nodeService = nodeService;
|
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.
|
* Register a home folder provider.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public void addProvider(HomeFolderProvider provider)
|
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)
|
* Set the default home folder provider (user which none is specified or when one is not found)
|
||||||
* @param defaultProvider
|
* @param defaultProvider
|
||||||
*/
|
*/
|
||||||
public void setDefaultProvider(HomeFolderProvider defaultProvider)
|
public void setDefaultProvider(HomeFolderProvider2 defaultProvider)
|
||||||
{
|
{
|
||||||
this.defaultProvider = defaultProvider;
|
this.defaultProvider = defaultProvider;
|
||||||
}
|
}
|
||||||
@@ -123,22 +196,302 @@ public class HomeFolderManager implements NodeServicePolicies.OnCreateNodePolicy
|
|||||||
/**
|
/**
|
||||||
* Find the provider and call.
|
* Find the provider and call.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public void makeHomeFolder(ChildAssociationRef childAssocRef)
|
public void makeHomeFolder(ChildAssociationRef childAssocRef)
|
||||||
{
|
{
|
||||||
HomeFolderProvider provider = defaultProvider;
|
HomeFolderProvider2 v2Provider = defaultProvider;
|
||||||
String providerName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(childAssocRef
|
HomeFolderProvider v1Provider = null;
|
||||||
|
String providerName = DefaultTypeConverter.INSTANCE.convert(
|
||||||
|
String.class, nodeService.getProperty(childAssocRef
|
||||||
.getChildRef(), ContentModel.PROP_HOME_FOLDER_PROVIDER));
|
.getChildRef(), ContentModel.PROP_HOME_FOLDER_PROVIDER));
|
||||||
if (providerName != null)
|
if (providerName != null)
|
||||||
{
|
{
|
||||||
provider = providers.get(providerName);
|
v2Provider = getHomeFolderProvider2(providerName);
|
||||||
if (provider == null)
|
if (v2Provider == null)
|
||||||
{
|
{
|
||||||
provider = defaultProvider;
|
v1Provider = getHomeFolderProvider1(providerName);
|
||||||
}
|
if (v1Provider == null)
|
||||||
}
|
|
||||||
if (provider != null)
|
|
||||||
{
|
{
|
||||||
provider.onCreateNode(childAssocRef);
|
v2Provider = defaultProvider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This file is part of Alfresco
|
* This file is part of Alfresco
|
||||||
*
|
*
|
||||||
@@ -23,6 +23,9 @@ import org.alfresco.repo.node.NodeServicePolicies;
|
|||||||
/**
|
/**
|
||||||
* Interface for home folder providers.
|
* Interface for home folder providers.
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
|
* Depreciated since 4.0. {@link HomeFolderProvider2} should now be used.
|
||||||
|
*
|
||||||
* @author Andy Hind
|
* @author Andy Hind
|
||||||
*/
|
*/
|
||||||
public interface HomeFolderProvider extends NodeServicePolicies.OnCreateNodePolicy
|
public interface HomeFolderProvider extends NodeServicePolicies.OnCreateNodePolicy
|
||||||
|
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||||
|
*
|
||||||
|
* This file is part of Alfresco
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.security.person;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for home folder providers. Instances work with the
|
||||||
|
* {@link HomeFolderManager} (which performs most of the work)
|
||||||
|
* to allow it to create home folders in custom locations.
|
||||||
|
*
|
||||||
|
* The home folder may be a simple structure where all users share a root folder (See
|
||||||
|
* {@link ExistingPathBasedHomeFolderProvider2}), or all home folders are in the same root
|
||||||
|
* folder (See {@link UsernameHomeFolderProvider}) or in a tree of sub folders to
|
||||||
|
* avoids any single directory containing too many home directories which might cause
|
||||||
|
* performance issues (See {@link RegexHomeFolderProvider}).<p>
|
||||||
|
*
|
||||||
|
* If the HomeFolderProvider is changed, home folders may be
|
||||||
|
* moved by using the {@link HomeFolderProviderSynchronizer} which optionally runs on
|
||||||
|
* restart.
|
||||||
|
*
|
||||||
|
* @author Andy Hind, Alan Davis (support v1 and v2 HomeFolderProviders)
|
||||||
|
*/
|
||||||
|
public interface HomeFolderProvider2
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the name of the provider (the bean name).
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the URL String of the node store that will be used.
|
||||||
|
*/
|
||||||
|
String getStoreUrl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the root path in the store under which all home folders will be located.
|
||||||
|
*/
|
||||||
|
String getRootPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a preferred path (a list of folder names) for the home folder relative to
|
||||||
|
* the root path. If all users share the root, the returned value should be an empty
|
||||||
|
* List or {@code null}. When all users have their own folder under the root
|
||||||
|
* there should be just one element in the List. Multiple elements should be returned
|
||||||
|
* when a nested folder structure is preferred.
|
||||||
|
* @param person NodeRef from which a property (normally the userName) is used as a
|
||||||
|
* hash key to create a nested directory structure.
|
||||||
|
* @return the path to be used.
|
||||||
|
*/
|
||||||
|
List<String> getHomeFolderPath(NodeRef person);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a node to copy (a template) for the home folder.
|
||||||
|
* Only used by HomeFolderProviders that create home folders rather
|
||||||
|
* than just reference existing folders.
|
||||||
|
* @return the node to copy or {@code null} if not required.
|
||||||
|
*/
|
||||||
|
NodeRef getTemplateNodeRef();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the authority to use as the owner of all home folder nodes.
|
||||||
|
* If {@code null} the {@link ContentModel.PROP_USERNAME} value of
|
||||||
|
* the person is used.
|
||||||
|
*/
|
||||||
|
String getOwner();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PermissionsManager used on creating the home folder
|
||||||
|
*/
|
||||||
|
PermissionsManager getOnCreatePermissionsManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the PermissionsManager used on referencing the home folder
|
||||||
|
*/
|
||||||
|
PermissionsManager getOnReferencePermissionsManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback from {@link HomeFolderManager} to locate or create a home folder.
|
||||||
|
* Implementations normally call {@link HomeFolderManager.getHomeFolder}.
|
||||||
|
*/
|
||||||
|
HomeSpaceNodeRef getHomeFolder(NodeRef person);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,944 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||||
|
*
|
||||||
|
* This file is part of Alfresco
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.security.person;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.transaction.Status;
|
||||||
|
import javax.transaction.UserTransaction;
|
||||||
|
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||||
|
import org.alfresco.repo.tenant.Tenant;
|
||||||
|
import org.alfresco.repo.tenant.TenantAdminService;
|
||||||
|
import org.alfresco.repo.tenant.TenantService;
|
||||||
|
import org.alfresco.service.ServiceRegistry;
|
||||||
|
import org.alfresco.service.cmr.model.FileFolderService;
|
||||||
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
|
import org.alfresco.service.cmr.repository.ContentData;
|
||||||
|
import org.alfresco.service.cmr.repository.ContentService;
|
||||||
|
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
|
import org.alfresco.service.cmr.repository.Path;
|
||||||
|
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||||
|
import org.alfresco.service.cmr.security.AuthorityService;
|
||||||
|
import org.alfresco.service.cmr.security.PersonService;
|
||||||
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
|
import org.alfresco.util.ApplicationContextHelper;
|
||||||
|
import org.alfresco.util.PropertyMap;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.ComparisonFailure;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration test for HomeFolderProviderSynchronizer.
|
||||||
|
*
|
||||||
|
* @author Alan Davis
|
||||||
|
*/
|
||||||
|
public class HomeFolderProviderSynchronizerTest
|
||||||
|
{
|
||||||
|
private static final QName PROP_PARENT_PATH = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "parentPath");
|
||||||
|
|
||||||
|
private static ApplicationContext applicationContext;
|
||||||
|
private static ServiceRegistry serviceRegistry;
|
||||||
|
private static TransactionService transactionService;
|
||||||
|
private static FileFolderService fileFolderService;
|
||||||
|
private static PersonService personService;
|
||||||
|
private static NodeService nodeService;
|
||||||
|
private static ContentService contentService;
|
||||||
|
private static AuthorityService authorityService;
|
||||||
|
private static TenantAdminService tenantAdminService;
|
||||||
|
private static TenantService tenantService;
|
||||||
|
private static HomeFolderManager homeFolderManager;
|
||||||
|
private static Properties properties;
|
||||||
|
private static RegexHomeFolderProvider largeHomeFolderProvider;
|
||||||
|
private static String largeHomeFolderProviderName;
|
||||||
|
private static RegexHomeFolderProvider testHomeFolderProvider;
|
||||||
|
private static String testHomeFolderProviderName;
|
||||||
|
private static String storeUrl;
|
||||||
|
private static String origRootPath;
|
||||||
|
private static NodeRef rootNodeRef;
|
||||||
|
private static HomeFolderProviderSynchronizer homeFolderProviderSynchronizer;
|
||||||
|
private static boolean firstTest = true;
|
||||||
|
|
||||||
|
private UserTransaction trans;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void classSetup() throws Exception
|
||||||
|
{
|
||||||
|
applicationContext = ApplicationContextHelper.getApplicationContext();
|
||||||
|
serviceRegistry = (ServiceRegistry) applicationContext.getBean("ServiceRegistry");
|
||||||
|
transactionService = (TransactionService) applicationContext.getBean("transactionService");
|
||||||
|
fileFolderService = (FileFolderService) applicationContext.getBean("fileFolderService");
|
||||||
|
personService = (PersonService) applicationContext.getBean("personService");
|
||||||
|
nodeService = (NodeService) applicationContext.getBean("nodeService");
|
||||||
|
contentService = (ContentService) applicationContext.getBean("contentService");
|
||||||
|
authorityService = (AuthorityService) applicationContext.getBean("authorityService");
|
||||||
|
tenantAdminService = (TenantAdminService) applicationContext.getBean("tenantAdminService");
|
||||||
|
tenantService = (TenantService) applicationContext.getBean("tenantService");
|
||||||
|
homeFolderManager = (HomeFolderManager) applicationContext.getBean("homeFolderManager");
|
||||||
|
largeHomeFolderProvider = (RegexHomeFolderProvider) applicationContext.getBean("largeHomeFolderProvider");
|
||||||
|
largeHomeFolderProviderName = largeHomeFolderProvider.getName();
|
||||||
|
storeUrl = largeHomeFolderProvider.getStoreUrl();
|
||||||
|
origRootPath = largeHomeFolderProvider.getRootPath();
|
||||||
|
properties = (Properties) applicationContext.getBean("global-properties");
|
||||||
|
|
||||||
|
personService.setCreateMissingPeople(true);
|
||||||
|
|
||||||
|
// Create test home folder provider that gets its path from a property and the username
|
||||||
|
testHomeFolderProvider = new RegexHomeFolderProvider()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public List<String> getHomeFolderPath(NodeRef person)
|
||||||
|
{
|
||||||
|
String parentPath = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(person, PROP_PARENT_PATH));
|
||||||
|
String propPath = ((parentPath == null || parentPath.length() == 0) ? "" : parentPath+'/')+
|
||||||
|
homeFolderManager.getPersonProperty(person, ContentModel.PROP_USERNAME);
|
||||||
|
return Arrays.asList(propPath.split("/"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
testHomeFolderProvider.setPropertyName(ContentModel.PROP_USERNAME.getLocalName());
|
||||||
|
testHomeFolderProvider.setPattern("(..)");
|
||||||
|
testHomeFolderProvider.setBeanName("testHomeFolderProvider");
|
||||||
|
testHomeFolderProvider.setHomeFolderManager(homeFolderManager);
|
||||||
|
testHomeFolderProvider.setRootPath(origRootPath);
|
||||||
|
testHomeFolderProvider.setStoreUrl(storeUrl);
|
||||||
|
testHomeFolderProvider.setOnCreatePermissionsManager((PermissionsManager)applicationContext.getBean("defaultOnCreatePermissionsManager"));
|
||||||
|
testHomeFolderProvider.setOnCreatePermissionsManager((PermissionsManager)applicationContext.getBean("defaultOnCreatePermissionsManager"));
|
||||||
|
testHomeFolderProvider.setOnReferencePermissionsManager((PermissionsManager)applicationContext.getBean("defaultOnReferencePermissionsManager"));
|
||||||
|
testHomeFolderProviderName = testHomeFolderProvider.getName();
|
||||||
|
homeFolderManager.addProvider(testHomeFolderProvider);
|
||||||
|
|
||||||
|
homeFolderProviderSynchronizer = new HomeFolderProviderSynchronizer(
|
||||||
|
properties, transactionService, authorityService,
|
||||||
|
personService, fileFolderService, nodeService,
|
||||||
|
homeFolderManager, tenantAdminService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception
|
||||||
|
{
|
||||||
|
properties.setProperty("home_folder_provider_synchronizer.enabled", "true");
|
||||||
|
properties.remove("home_folder_provider_synchronizer.override_provider");
|
||||||
|
properties.remove("home_folder_provider_synchronizer.keep_empty_parents");
|
||||||
|
|
||||||
|
largeHomeFolderProvider.setPattern("^(..)");
|
||||||
|
testHomeFolderProvider.setRootPath(origRootPath);
|
||||||
|
largeHomeFolderProvider.setRootPath(origRootPath);
|
||||||
|
|
||||||
|
// Just in case we killed a test last time - tidy up
|
||||||
|
if (firstTest)
|
||||||
|
{
|
||||||
|
firstTest = false;
|
||||||
|
|
||||||
|
AuthenticationUtil.setRunAsUserSystem();
|
||||||
|
trans = transactionService.getUserTransaction();
|
||||||
|
trans.begin();
|
||||||
|
rootNodeRef = homeFolderManager.getRootPathNodeRef(largeHomeFolderProvider);
|
||||||
|
trans.commit();
|
||||||
|
trans = null;
|
||||||
|
|
||||||
|
tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthenticationUtil.setRunAsUserSystem();
|
||||||
|
trans = transactionService.getUserTransaction();
|
||||||
|
trans.begin();
|
||||||
|
// System.out.println(NodeStoreInspector.dumpNode(nodeService, rootNodeRef));
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception
|
||||||
|
{
|
||||||
|
if (trans != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
trans.commit();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if ((trans.getStatus() == Status.STATUS_ACTIVE) ||
|
||||||
|
(trans.getStatus() == Status.STATUS_MARKED_ROLLBACK))
|
||||||
|
{
|
||||||
|
trans.rollback();
|
||||||
|
trans = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trans = transactionService.getUserTransaction();
|
||||||
|
trans.begin();
|
||||||
|
Set<NodeRef> adminGuestUserHomeFolders = deleteNonAdminGuestUsers();
|
||||||
|
deleteNonAdminGuestFolders(adminGuestUserHomeFolders);
|
||||||
|
deleteAllTenants();
|
||||||
|
trans.commit();
|
||||||
|
trans = null;
|
||||||
|
AuthenticationUtil.clearCurrentSecurityContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<NodeRef> deleteNonAdminGuestUsers()
|
||||||
|
{
|
||||||
|
final Set<NodeRef> adminGuestUserHomeFolders = new HashSet<NodeRef>();
|
||||||
|
for (final NodeRef nodeRef : personService.getAllPeople())
|
||||||
|
{
|
||||||
|
final String username = DefaultTypeConverter.INSTANCE.convert(String.class,
|
||||||
|
nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME));
|
||||||
|
final String domainUsername = tenantService.getBaseNameUser(username);
|
||||||
|
String tenantDomain = tenantService.getUserDomain(username);
|
||||||
|
String systemUser = tenantAdminService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantDomain);
|
||||||
|
boolean disabled = !TenantService.DEFAULT_DOMAIN.equals(tenantDomain) &&
|
||||||
|
!tenantAdminService.isEnabledTenant(tenantDomain);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (disabled)
|
||||||
|
{
|
||||||
|
tenantAdminService.enableTenant(tenantDomain);
|
||||||
|
}
|
||||||
|
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||||
|
{
|
||||||
|
public Object doWork() throws Exception
|
||||||
|
{
|
||||||
|
deleteUser(adminGuestUserHomeFolders, nodeRef, username, domainUsername);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, systemUser);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (disabled)
|
||||||
|
{
|
||||||
|
tenantAdminService.disableTenant(tenantDomain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return adminGuestUserHomeFolders;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete users other than admin and guest. The home folders of
|
||||||
|
// admin and guest are added to internalUserHomeFolders.
|
||||||
|
private void deleteUser(final Set<NodeRef> adminGuestUserHomeFolders,
|
||||||
|
NodeRef person, String username, String domainUsername)
|
||||||
|
{
|
||||||
|
if (!domainUsername.equals("admin") && !domainUsername.equals("guest"))
|
||||||
|
{
|
||||||
|
personService.deletePerson(person);
|
||||||
|
System.out.println("deleted user "+username);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NodeRef homeFolder = DefaultTypeConverter.INSTANCE.convert(
|
||||||
|
NodeRef.class, nodeService.getProperty(person,
|
||||||
|
ContentModel.PROP_HOMEFOLDER));
|
||||||
|
adminGuestUserHomeFolders.add(homeFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteNonAdminGuestFolders(final Set<NodeRef> adminGuestUserHomeFolders)
|
||||||
|
{
|
||||||
|
// Delete folders from under the home folder root path in case they have been left over
|
||||||
|
// from another test. Admin and Guest home folder should not be under here, but lets
|
||||||
|
// double check.
|
||||||
|
for (ChildAssociationRef childAssocs: nodeService.getChildAssocs(rootNodeRef))
|
||||||
|
{
|
||||||
|
NodeRef nodeRef = childAssocs.getChildRef();
|
||||||
|
if (!adminGuestUserHomeFolders.contains(nodeRef))
|
||||||
|
{
|
||||||
|
System.out.println("TearDown remove '"+childAssocs.getQName().getLocalName()+
|
||||||
|
"' from under the home folder root.");
|
||||||
|
nodeService.deleteNode(nodeRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private NodeRef createUser(String parentPath, String username) throws Exception
|
||||||
|
{
|
||||||
|
return createUser(TenantService.DEFAULT_DOMAIN, parentPath, username);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NodeRef createUser(String parentPath,
|
||||||
|
String username, String homeFolderProviderName, boolean createHomeDirectory) throws Exception
|
||||||
|
{
|
||||||
|
return createUser(TenantService.DEFAULT_DOMAIN, parentPath, username,
|
||||||
|
homeFolderProviderName, createHomeDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NodeRef createUser(String tenantDomain, String parentPath, String username) throws Exception
|
||||||
|
{
|
||||||
|
return createUser(tenantDomain, parentPath, username, largeHomeFolderProviderName, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NodeRef createUser(String tenantDomain, final String parentPath,
|
||||||
|
final String username, final String homeFolderProviderName,
|
||||||
|
final boolean createHomeDirectory) throws Exception
|
||||||
|
{
|
||||||
|
final String domainUsername = tenantService.getDomainUser(username, tenantDomain);
|
||||||
|
String systemUser = tenantAdminService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantDomain);
|
||||||
|
return AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
|
||||||
|
{
|
||||||
|
public NodeRef doWork() throws Exception
|
||||||
|
{
|
||||||
|
String firstName = username;
|
||||||
|
String lastName = "Smith";
|
||||||
|
String emailAddress = String.format("%s.%s@xyz.com", firstName,
|
||||||
|
lastName);
|
||||||
|
PropertyMap properties = new PropertyMap();
|
||||||
|
properties.put(ContentModel.PROP_USERNAME, domainUsername);
|
||||||
|
properties.put(ContentModel.PROP_FIRSTNAME, firstName);
|
||||||
|
properties.put(ContentModel.PROP_LASTNAME, lastName);
|
||||||
|
properties.put(ContentModel.PROP_EMAIL, emailAddress);
|
||||||
|
properties.put(ContentModel.PROP_HOME_FOLDER_PROVIDER, testHomeFolderProviderName);
|
||||||
|
properties.put(PROP_PARENT_PATH, parentPath);
|
||||||
|
homeFolderManager.setEnableHomeFolderCreationAsPeopleAreCreated(createHomeDirectory);
|
||||||
|
NodeRef person = personService.createPerson(properties);
|
||||||
|
assertNotNull("The person nodeRef for "+domainUsername+" should have been created", person);
|
||||||
|
NodeRef homeFolder = DefaultTypeConverter.INSTANCE.convert(
|
||||||
|
NodeRef.class, nodeService.getProperty(person,
|
||||||
|
ContentModel.PROP_HOMEFOLDER));
|
||||||
|
if (createHomeDirectory)
|
||||||
|
{
|
||||||
|
assertNotNull("The homeFolder for "+domainUsername+" should have been created", homeFolder);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assertNull("The homeFolder for "+domainUsername+" should NOT have been created", homeFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!testHomeFolderProviderName.equals(homeFolderProviderName))
|
||||||
|
{
|
||||||
|
if (homeFolderProviderName == null)
|
||||||
|
{
|
||||||
|
nodeService.removeProperty(person, ContentModel.PROP_HOME_FOLDER_PROVIDER);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nodeService.setProperty(person, ContentModel.PROP_HOME_FOLDER_PROVIDER,
|
||||||
|
homeFolderProviderName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return person;
|
||||||
|
}
|
||||||
|
}, systemUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NodeRef createFolder(String path) throws Exception
|
||||||
|
{
|
||||||
|
NodeRef parent = rootNodeRef;
|
||||||
|
if (path.length() > 0)
|
||||||
|
{
|
||||||
|
StringBuilder currentPath = new StringBuilder();
|
||||||
|
for (String pathElement: path.split("/"))
|
||||||
|
{
|
||||||
|
if (currentPath.length() > 0)
|
||||||
|
{
|
||||||
|
currentPath.append("/");
|
||||||
|
}
|
||||||
|
currentPath.append(pathElement);
|
||||||
|
NodeRef nodeRef = nodeService.getChildByName(parent,
|
||||||
|
ContentModel.ASSOC_CONTAINS, pathElement);
|
||||||
|
if (nodeRef == null)
|
||||||
|
{
|
||||||
|
parent = fileFolderService.create(parent, pathElement,
|
||||||
|
ContentModel.TYPE_FOLDER).getNodeRef();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assertTrue("Expected "+currentPath+" to be a folder",
|
||||||
|
fileFolderService.getFileInfo(nodeRef).isFolder());
|
||||||
|
parent = nodeRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private NodeRef createContent(String parentPath, String name) throws Exception
|
||||||
|
{
|
||||||
|
NodeRef parent = createFolder(parentPath);
|
||||||
|
PropertyMap propertyMap = new PropertyMap();
|
||||||
|
propertyMap.put(ContentModel.PROP_CONTENT, new ContentData(null, "text/plain",
|
||||||
|
0L, "UTF-16", Locale.ENGLISH));
|
||||||
|
propertyMap.put(ContentModel.PROP_NAME, name);
|
||||||
|
NodeRef content = nodeService.createNode(
|
||||||
|
parent,
|
||||||
|
ContentModel.ASSOC_CONTAINS,
|
||||||
|
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name),
|
||||||
|
ContentModel.TYPE_CONTENT,
|
||||||
|
propertyMap).getChildRef();
|
||||||
|
ContentWriter writer = contentService.getWriter(content, ContentModel.TYPE_CONTENT, true);
|
||||||
|
writer.putContent("The cat sat on the mat.");
|
||||||
|
|
||||||
|
// System.out.println(NodeStoreInspector.dumpNode(nodeService, rootNodeRef));
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toPath(NodeRef root, NodeRef homeFolder)
|
||||||
|
{
|
||||||
|
if (root == null || homeFolder == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path rootPath = nodeService.getPath(root);
|
||||||
|
Path homeFolderPath = nodeService.getPath(homeFolder);
|
||||||
|
int rootSize = rootPath.size();
|
||||||
|
int homeFolderSize = homeFolderPath.size();
|
||||||
|
if (rootSize >= homeFolderSize)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder("");
|
||||||
|
|
||||||
|
// Check homeFolder is under root
|
||||||
|
for (int i=0; i < rootSize; i++)
|
||||||
|
{
|
||||||
|
if (!rootPath.get(i).equals(homeFolderPath.get(i)))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build up path of sub folders
|
||||||
|
for (int i = rootSize; i < homeFolderSize; i++)
|
||||||
|
{
|
||||||
|
Path.Element element = homeFolderPath.get(i);
|
||||||
|
if (!(element instanceof Path.ChildAssocElement))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
QName folderQName = ((Path.ChildAssocElement) element).getRef().getQName();
|
||||||
|
if (sb.length() > 0)
|
||||||
|
{
|
||||||
|
sb.append('/');
|
||||||
|
}
|
||||||
|
sb.append(folderQName.getLocalName());
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createTenant(final String tenantDomain)
|
||||||
|
{
|
||||||
|
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||||
|
{
|
||||||
|
public Object doWork() throws Exception
|
||||||
|
{
|
||||||
|
if (!tenantAdminService.existsTenant(tenantDomain))
|
||||||
|
{
|
||||||
|
tenantAdminService.createTenant(tenantDomain,
|
||||||
|
("admin "+tenantDomain).toCharArray(), null);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, AuthenticationUtil.getSystemUserName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteAllTenants() throws Exception
|
||||||
|
{
|
||||||
|
List<Tenant> tenants = tenantAdminService.getAllTenants();
|
||||||
|
for (Tenant tenant : tenants)
|
||||||
|
{
|
||||||
|
deleteTenant(tenant.getTenantDomain());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// DbNodeServiceImpl does not support deleteStore() at the moment,
|
||||||
|
// even though it supports createStore(), so just disable them for now.
|
||||||
|
private void deleteTenant(final String tenantDomain) throws Exception
|
||||||
|
{
|
||||||
|
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||||
|
{
|
||||||
|
public Object doWork() throws Exception
|
||||||
|
{
|
||||||
|
if (tenantAdminService.existsTenant(tenantDomain))
|
||||||
|
{
|
||||||
|
// Can't delete so disable
|
||||||
|
// tenantAdminService.deleteTenant(tenantDomain);
|
||||||
|
|
||||||
|
if (tenantAdminService.isEnabledTenant(tenantDomain))
|
||||||
|
{
|
||||||
|
tenantAdminService.disableTenant(tenantDomain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, AuthenticationUtil.getSystemUserName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertHomeFolderLocation(String username, String expectedPath) throws Exception
|
||||||
|
{
|
||||||
|
assertHomeFolderLocation(TenantService.DEFAULT_DOMAIN, username, expectedPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertHomeFolderLocation(String tenantDomain, final String username,
|
||||||
|
final String expectedPath) throws Exception
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final String domainUsername = tenantService.getDomainUser(username, tenantDomain);
|
||||||
|
String systemUser = tenantAdminService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantDomain);
|
||||||
|
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||||
|
{
|
||||||
|
public NodeRef doWork() throws Exception
|
||||||
|
{
|
||||||
|
NodeRef person = personService.getPerson(domainUsername, false);
|
||||||
|
NodeRef homeFolder = DefaultTypeConverter.INSTANCE.convert(NodeRef.class,
|
||||||
|
nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER));
|
||||||
|
assertNotNull("User: "+domainUsername+" home folder should exist", homeFolder);
|
||||||
|
|
||||||
|
NodeRef rootPath = homeFolderManager.getRootPathNodeRef(largeHomeFolderProvider);
|
||||||
|
String actualPath = toPath(rootPath, homeFolder);
|
||||||
|
assertEquals("User: "+domainUsername+" home folder location", expectedPath, actualPath);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, systemUser);
|
||||||
|
}
|
||||||
|
catch (RuntimeException e)
|
||||||
|
{
|
||||||
|
final Throwable cause = e.getCause();
|
||||||
|
if (cause instanceof ComparisonFailure || cause instanceof AssertionError)
|
||||||
|
{
|
||||||
|
throw (ComparisonFailure)cause;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean exists(String path) throws Exception
|
||||||
|
{
|
||||||
|
NodeRef parent = rootNodeRef;
|
||||||
|
boolean exists = true;
|
||||||
|
for (String pathElement: path.split("/"))
|
||||||
|
{
|
||||||
|
NodeRef nodeRef = nodeService.getChildByName(parent,
|
||||||
|
ContentModel.ASSOC_CONTAINS, pathElement);
|
||||||
|
if (nodeRef == null)
|
||||||
|
{
|
||||||
|
exists = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent = nodeRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void moveUserHomeFolders() throws Exception
|
||||||
|
{
|
||||||
|
trans.commit();
|
||||||
|
trans = null;
|
||||||
|
|
||||||
|
homeFolderProviderSynchronizer.onBootstrap(null);
|
||||||
|
|
||||||
|
trans = transactionService.getUserTransaction();
|
||||||
|
trans.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCorrectLocation() throws Exception
|
||||||
|
{
|
||||||
|
createUser("te", "tess");
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("tess", "te/tess");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateParentFolder() throws Exception
|
||||||
|
{
|
||||||
|
createUser("", "fred");
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fred", "fr/fred");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotEnabled() throws Exception
|
||||||
|
{
|
||||||
|
createUser("", "fred");
|
||||||
|
properties.remove("home_folder_provider_synchronizer.enabled");
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
// If performed, the home folder will have been moved to fr/fred
|
||||||
|
// We must force the creation of the home folder as it will not
|
||||||
|
// have been done
|
||||||
|
personService.getPerson("fred");
|
||||||
|
assertHomeFolderLocation("fred", "fred");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHomeFolderNotYetCreated() throws Exception
|
||||||
|
{
|
||||||
|
NodeRef person = createUser("", "fred", largeHomeFolderProviderName, false);
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
NodeRef homeFolder = DefaultTypeConverter.INSTANCE.convert(NodeRef.class,
|
||||||
|
nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER));
|
||||||
|
assertNull("The homeFolder should NOT have been created", homeFolder);
|
||||||
|
|
||||||
|
person = personService.getPerson("fred");
|
||||||
|
homeFolder = DefaultTypeConverter.INSTANCE.convert(NodeRef.class,
|
||||||
|
nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER));
|
||||||
|
assertNotNull("The homeFolder should have been created", homeFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateMultipleParentFolders() throws Exception
|
||||||
|
{
|
||||||
|
largeHomeFolderProvider.setPattern("^(.?)(.?)(.?)(.?)(.?)");
|
||||||
|
|
||||||
|
createUser("", "fred");
|
||||||
|
createUser("", "peter");
|
||||||
|
createUser("", "tess");
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fred", "f/r/e/d/fred");
|
||||||
|
assertHomeFolderLocation("peter", "p/e/t/e/r/peter");
|
||||||
|
assertHomeFolderLocation("tess", "t/e/s/s/tess");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveToRoot() throws Exception
|
||||||
|
{
|
||||||
|
// i.e. there are no parent folders after the sync
|
||||||
|
largeHomeFolderProvider.setPattern("");
|
||||||
|
|
||||||
|
createUser("fr", "fred");
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fred", "fred");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveEmptyParents() throws Exception
|
||||||
|
{
|
||||||
|
createUser("a/bb/ccc", "peter");
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("peter", "pe/peter");
|
||||||
|
assertFalse("Expected the empty parent 'a' to have been removed.", exists("a"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKeepEmptyParents() throws Exception
|
||||||
|
{
|
||||||
|
createUser("a/bb/ccc", "peter");
|
||||||
|
properties.put("home_folder_provider_synchronizer.keep_empty_parents", "true");
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("peter", "pe/peter");
|
||||||
|
assertTrue("Expected the empty parent 'a/bb/ccc' to still exist as global " +
|
||||||
|
"property was set.", exists("a/bb/ccc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKeepNonEmptyParents() throws Exception
|
||||||
|
{
|
||||||
|
createUser("a/bb/ccc", "peter");
|
||||||
|
createFolder("a/bb/ddd");
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("peter", "pe/peter");
|
||||||
|
assertFalse("Expected the empty parent 'a/bb/ccc' to have been removed.", exists("a/bb/ccc"));
|
||||||
|
assertTrue("Expected the non empty parent 'a/bb' to have been kept.", exists("a/bb/ddd"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPathAlreadyInUseByFolder() throws Exception
|
||||||
|
{
|
||||||
|
createUser("", "fred");
|
||||||
|
createFolder("fr");
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fred", "fr/fred");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPathAlreadyInUseByContent() throws Exception
|
||||||
|
{
|
||||||
|
createUser("", "fred");
|
||||||
|
createContent("", "fr");
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fred", "fred"); // unchanged
|
||||||
|
assertFalse("Did not expect there to be a folder in the prefered location.", exists("fr/fred"));
|
||||||
|
assertTrue("Expected the content to still exist.", exists("fr"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPathInUseByUser() throws Exception
|
||||||
|
{
|
||||||
|
// i.e. test clash between home folder names and parent folders
|
||||||
|
// which requires a temporary folder to be created
|
||||||
|
createUser("", "fr");
|
||||||
|
createUser("", "fred");
|
||||||
|
createUser("", "peter");
|
||||||
|
createUser("", "pe");
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fr", "fr/fr");
|
||||||
|
assertHomeFolderLocation("fred", "fr/fred");
|
||||||
|
assertHomeFolderLocation("peter", "pe/peter");
|
||||||
|
assertHomeFolderLocation("pe", "pe/pe");
|
||||||
|
|
||||||
|
assertFalse("The Temporary1 folder should have been removed", exists("Temporary1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUseFirstAvailableTemporaryFolder() throws Exception
|
||||||
|
{
|
||||||
|
createUser("", "fr");
|
||||||
|
createUser("", "fred");
|
||||||
|
createFolder("Temporary1");
|
||||||
|
createFolder("Temporary2");
|
||||||
|
createFolder("Temporary3");
|
||||||
|
|
||||||
|
// Don't delete the temporary folder
|
||||||
|
properties.put("home_folder_provider_synchronizer.keep_empty_parents", "true");
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertTrue("The existing Temporary1 folder should still exist", exists("Temporary1"));
|
||||||
|
assertTrue("The existing Temporary2 folder should still exist", exists("Temporary2"));
|
||||||
|
assertTrue("The existing Temporary3 folder should still exist", exists("Temporary3"));
|
||||||
|
assertTrue("The existing Temporary4 folder should still exist", exists("Temporary4"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testException() throws Exception
|
||||||
|
{
|
||||||
|
// Force the need for a temporary folder
|
||||||
|
createUser("", "fr");
|
||||||
|
createUser("", "fred");
|
||||||
|
|
||||||
|
// Use up all possible temporary folder names
|
||||||
|
for (int i=1; i<=100; i++)
|
||||||
|
{
|
||||||
|
createFolder("Temporary"+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
// normally would have changed to fr/fred if there had not been an exception
|
||||||
|
assertHomeFolderLocation("fred", "fred");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleRoots() throws Exception
|
||||||
|
{
|
||||||
|
createFolder("root");
|
||||||
|
String rootPath = origRootPath + "/cm:root";
|
||||||
|
testHomeFolderProvider.setRootPath(rootPath);
|
||||||
|
|
||||||
|
createUser("a/b/c", "tess", testHomeFolderProviderName, true);
|
||||||
|
createUser("a/b/c", "fred", largeHomeFolderProviderName, true);
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fred", "fr/fred");
|
||||||
|
assertHomeFolderLocation("tess", "root/a/b/c/tess");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPathNotUnderRoot() throws Exception
|
||||||
|
{
|
||||||
|
createUser("a/b/c", "fred");
|
||||||
|
|
||||||
|
createFolder("root");
|
||||||
|
String rootPath = origRootPath + "/cm:root";
|
||||||
|
largeHomeFolderProvider.setRootPath(rootPath);
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fred", null);
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fred", "fr/fred");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleUsers() throws Exception
|
||||||
|
{
|
||||||
|
// Tried 2000 users and the HomeFolderProviderSynchronizer.onBootstrap(null)
|
||||||
|
// took 33 seconds. The setup and tear down takes a while too.
|
||||||
|
|
||||||
|
// Use a value larger than the batch size of 20 and log every 100.
|
||||||
|
int userCount = 110;
|
||||||
|
for (int i=1; i<=userCount; i++)
|
||||||
|
{
|
||||||
|
String name = "f"+i+"red";
|
||||||
|
createUser("", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
for (int i=1; i<=userCount; i++)
|
||||||
|
{
|
||||||
|
String name = "f"+i+"red";
|
||||||
|
assertHomeFolderLocation(name, name.substring(0,2)+'/'+name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverrideProvider() throws Exception
|
||||||
|
{
|
||||||
|
NodeRef person = createUser("a/b/c", "fred");
|
||||||
|
moveUserHomeFolders();
|
||||||
|
assertHomeFolderLocation("fred", "fr/fred");
|
||||||
|
|
||||||
|
properties.put("home_folder_provider_synchronizer.override_provider",
|
||||||
|
testHomeFolderProviderName);
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fred", "a/b/c/fred");
|
||||||
|
String providerName = (String) nodeService.getProperty(person,
|
||||||
|
ContentModel.PROP_HOME_FOLDER_PROVIDER);
|
||||||
|
assertEquals(testHomeFolderProviderName , providerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoOriginalProvider() throws Exception
|
||||||
|
{
|
||||||
|
createUser("a/b/c", "fred", null, true);
|
||||||
|
properties.put("home_folder_provider_synchronizer.override_provider",
|
||||||
|
largeHomeFolderProviderName);
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fred", "fr/fred"); // unchanged
|
||||||
|
assertTrue("Expected the empty parent 'a/b/c' to still exist as original " +
|
||||||
|
"root was unknown, because the original home folder provider was not set.",
|
||||||
|
exists("a/b/c"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public void testVersion1HomeFolderProvider() throws Exception
|
||||||
|
{
|
||||||
|
// Should just log a message to say it can't do anything
|
||||||
|
final String name = "v1Provider";
|
||||||
|
HomeFolderProvider v1Provider = new HomeFolderProvider()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onCreateNode(ChildAssociationRef childAssocRef)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
homeFolderManager.addProvider(v1Provider);
|
||||||
|
|
||||||
|
createUser("a/b/c", "fred");
|
||||||
|
|
||||||
|
properties.put("home_folder_provider_synchronizer.override_provider", name);
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fred", "a/b/c/fred");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public void testExtendsAbstractHomeFolderProvider() throws Exception
|
||||||
|
{
|
||||||
|
// Should work through the V2Adaptor
|
||||||
|
final String name = "v1Provider";
|
||||||
|
AbstractHomeFolderProvider v1Provider = new UIDBasedHomeFolderProvider();
|
||||||
|
v1Provider.setBeanName(name);
|
||||||
|
v1Provider.setHomeFolderManager(homeFolderManager);
|
||||||
|
v1Provider.setOnCreatePermissionsManager(largeHomeFolderProvider.getOnCreatePermissionsManager());
|
||||||
|
v1Provider.setOnReferencePermissionsManager(largeHomeFolderProvider.getOnReferencePermissionsManager());
|
||||||
|
v1Provider.setOwnerOnCreate(largeHomeFolderProvider.getOwner());
|
||||||
|
v1Provider.setPath(largeHomeFolderProvider.getRootPath());
|
||||||
|
v1Provider.setServiceRegistry(serviceRegistry);
|
||||||
|
v1Provider.setStoreUrl(largeHomeFolderProvider.getStoreUrl());
|
||||||
|
v1Provider.setTenantService(tenantService);
|
||||||
|
v1Provider.afterPropertiesSet();
|
||||||
|
|
||||||
|
createUser("a/b/c", "fred");
|
||||||
|
|
||||||
|
properties.put("home_folder_provider_synchronizer.override_provider", name);
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fred", "fred");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTenantService() throws Exception
|
||||||
|
{
|
||||||
|
// Only test if running multi-tenant
|
||||||
|
if (tenantAdminService.isEnabled())
|
||||||
|
{
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
final String tenant1 = time+".tenant1";
|
||||||
|
final String tenant2 = time+".tenant2";
|
||||||
|
|
||||||
|
createTenant(tenant1);
|
||||||
|
createTenant(tenant2);
|
||||||
|
|
||||||
|
createUser("", "fred");
|
||||||
|
createUser(tenant1, "", "fred");
|
||||||
|
createUser(tenant2, "", "fred");
|
||||||
|
|
||||||
|
moveUserHomeFolders();
|
||||||
|
|
||||||
|
assertHomeFolderLocation("fred", "fr/fred");
|
||||||
|
assertHomeFolderLocation(tenant1, "fred", "fr/"+tenantService.getDomainUser("fred", tenant1));
|
||||||
|
assertHomeFolderLocation(tenant2, "fred", "fr/"+tenantService.getDomainUser("fred", tenant2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||||
|
*
|
||||||
|
* This file is part of Alfresco
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.security.person;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.alfresco.util.FileNameValidator;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation that returns a tree structure for a home folder based on a property (typically userName)
|
||||||
|
* from the supplied person. The parent folder names are derived from regular expression groups matched
|
||||||
|
* against the property value. The final folder name is the full property value.<p>
|
||||||
|
*
|
||||||
|
* For example, given the value "adavis" and the regular expression <tt>"^(..)"</tt> the
|
||||||
|
* resulting home folder path would be {@code "/ad/adavis"}. However with the regular expression
|
||||||
|
* <tt>"^(.)(.?)"</tt> the home folder path would be {@code "/a/d/adavis"}. If any group matches a zero
|
||||||
|
* length string, it is just ignored.<p>
|
||||||
|
*
|
||||||
|
* Note: In order to choose an efficient distribution scheme, be aware that, when m users are
|
||||||
|
* distributed into n leaf folders, when m >> n log n the statistical maximum load is
|
||||||
|
* m/n + O( sqrt((m log n)/n)), w.h.p
|
||||||
|
*
|
||||||
|
* @author Romain Guinot, Alan Davis
|
||||||
|
*/
|
||||||
|
public class RegexHomeFolderProvider extends UsernameHomeFolderProvider
|
||||||
|
{
|
||||||
|
private static Log logger = LogFactory.getLog(RegexHomeFolderProvider.class);
|
||||||
|
|
||||||
|
private QName propertyName;
|
||||||
|
private Pattern pattern;
|
||||||
|
private List<Integer> groupOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param propertyName String the cm:person property used as the key, such as userName
|
||||||
|
* or organizationId.
|
||||||
|
*/
|
||||||
|
public void setPropertyName(String propertyName)
|
||||||
|
{
|
||||||
|
this.propertyName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param patternString the regex pattern against the cm:person property value. Regex
|
||||||
|
* groups define the parent folder structure.
|
||||||
|
*/
|
||||||
|
public void setPattern(String patternString)
|
||||||
|
{
|
||||||
|
pattern = getPattern(patternString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param groupOrderString String the order (as a comma separated list) in which the
|
||||||
|
* regex pattern groups should be assembled into folders (such as {@code 2,1}).
|
||||||
|
* The default ordering is as they appear.
|
||||||
|
*/
|
||||||
|
public void setGroupOrder(String groupOrderString)
|
||||||
|
{
|
||||||
|
groupOrder = getGroupOrder(groupOrderString);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pattern getPattern(String patternString)
|
||||||
|
{
|
||||||
|
if (patternString == null || patternString.trim().length() == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Pattern pattern;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pattern = Pattern.compile(patternString);
|
||||||
|
logger.debug("Successfully compiled patternString : " + patternString);
|
||||||
|
} catch (PatternSyntaxException pse)
|
||||||
|
{
|
||||||
|
throw new PersonException("Pattern string :" + patternString + " does not compile", pse);
|
||||||
|
}
|
||||||
|
return pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Integer> getGroupOrder(String groupOrderString)
|
||||||
|
{
|
||||||
|
if (groupOrderString == null || groupOrderString.trim().length() == 0)
|
||||||
|
return Collections.emptyList();
|
||||||
|
|
||||||
|
String[] groupOrderStrings = groupOrderString.split(",");
|
||||||
|
List<Integer>groupOrder = new ArrayList<Integer>(groupOrderStrings.length);
|
||||||
|
for (String group : groupOrderStrings)
|
||||||
|
{
|
||||||
|
Integer i;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
i = Integer.valueOf(group);
|
||||||
|
}
|
||||||
|
catch (NumberFormatException nfe)
|
||||||
|
{
|
||||||
|
throw new PersonException("groupOrdering value " + groupOrderString + " is invalid.", nfe);
|
||||||
|
}
|
||||||
|
if (groupOrder.contains(i) || i < 0)
|
||||||
|
{
|
||||||
|
throw new PersonException("groupOrdering value " + groupOrderString + " is invalid.");
|
||||||
|
}
|
||||||
|
groupOrder.add(i);
|
||||||
|
}
|
||||||
|
return groupOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getHomeFolderPath(NodeRef person)
|
||||||
|
{
|
||||||
|
List<String> path = new ArrayList<String>();
|
||||||
|
String key = FileNameValidator.getValidFileName(
|
||||||
|
getHomeFolderManager().getPersonProperty(person, propertyName));
|
||||||
|
if (pattern != null)
|
||||||
|
{
|
||||||
|
Matcher matcher = pattern.matcher(key);
|
||||||
|
|
||||||
|
if (matcher.find())
|
||||||
|
{
|
||||||
|
int groupCount = matcher.groupCount();
|
||||||
|
if (!groupOrder.isEmpty())
|
||||||
|
{
|
||||||
|
for (int group : groupOrder)
|
||||||
|
{
|
||||||
|
if (group > groupCount)
|
||||||
|
{
|
||||||
|
throw new PersonException("groupOrdering value "
|
||||||
|
+ group + " is out of range.");
|
||||||
|
}
|
||||||
|
addFolderToPath(path, matcher, group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // "natural" group ordering, i.e as they appear in the regex
|
||||||
|
{
|
||||||
|
for (int group = 1; group <= groupCount; group++)
|
||||||
|
{
|
||||||
|
addFolderToPath(path, matcher, group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path.add(key);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("returning "+path+" for key: "+key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFolderToPath(List<String> path, Matcher matcher, int group)
|
||||||
|
{
|
||||||
|
String folder = matcher.group(group);
|
||||||
|
if (folder.length() > 0)
|
||||||
|
{
|
||||||
|
path.add(folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This file is part of Alfresco
|
* This file is part of Alfresco
|
||||||
*
|
*
|
||||||
@@ -18,19 +18,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.security.person;
|
package org.alfresco.repo.security.person;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.service.cmr.model.FileFolderService;
|
|
||||||
import org.alfresco.service.cmr.model.FileInfo;
|
|
||||||
import org.alfresco.service.cmr.model.FileNotFoundException;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
|
||||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
|
||||||
import org.alfresco.util.FileNameValidator;
|
import org.alfresco.util.FileNameValidator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create home spaces based on the UID of the user.
|
* Creates home folders directly under the root path, based on the username of the user.
|
||||||
*
|
*
|
||||||
* If a suitable space is found it is reused, if not it will be made.
|
* @deprecated
|
||||||
|
* Depreciated since 4.0. {@link UsernameHomeFolderProvider} should now be used.
|
||||||
*
|
*
|
||||||
* @author Andy Hind
|
* @author Andy Hind
|
||||||
*/
|
*/
|
||||||
@@ -40,86 +39,30 @@ public class UIDBasedHomeFolderProvider extends ExistingPathBasedHomeFolderProvi
|
|||||||
|
|
||||||
private NodeRef templateNodeRef;
|
private NodeRef templateNodeRef;
|
||||||
|
|
||||||
public UIDBasedHomeFolderProvider()
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTemplatePath(String templatePath)
|
public void setTemplatePath(String templatePath)
|
||||||
{
|
{
|
||||||
this.templatePath = templatePath;
|
this.templatePath = templatePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HomeSpaceNodeRef getHomeFolder(NodeRef person)
|
|
||||||
{
|
|
||||||
FileFolderService fileFolderService = getServiceRegistry().getFileFolderService();
|
|
||||||
NodeService nodeService = getServiceRegistry().getNodeService();
|
|
||||||
|
|
||||||
NodeRef existingHomeFolder = DefaultTypeConverter.INSTANCE.convert(
|
|
||||||
NodeRef.class, nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER));
|
|
||||||
if (existingHomeFolder == null)
|
|
||||||
{
|
|
||||||
String uid = DefaultTypeConverter.INSTANCE.convert(
|
|
||||||
String.class,
|
|
||||||
nodeService.getProperty(person, ContentModel.PROP_USERNAME));
|
|
||||||
|
|
||||||
if((uid == null) || (uid.length() == 0))
|
|
||||||
{
|
|
||||||
throw new PersonException("Can not create a home space when the uid is null or empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
// ETHREEOH-1612: Convert the username to file- and folder-safe names
|
|
||||||
String homeFolderName = FileNameValidator.getValidFileName(uid);
|
|
||||||
|
|
||||||
FileInfo fileInfo;
|
|
||||||
|
|
||||||
// Test if it already exists
|
|
||||||
|
|
||||||
NodeRef exising = fileFolderService.searchSimple(getPathNodeRef(), homeFolderName);
|
|
||||||
if (exising != null)
|
|
||||||
{
|
|
||||||
fileInfo = fileFolderService.getFileInfo(exising);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (templatePath == null)
|
|
||||||
{
|
|
||||||
fileInfo = fileFolderService.create(
|
|
||||||
getPathNodeRef(),
|
|
||||||
homeFolderName,
|
|
||||||
ContentModel.TYPE_FOLDER);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
fileInfo = fileFolderService.copy(
|
|
||||||
getTemplateNodeRef(),
|
|
||||||
getPathNodeRef(),
|
|
||||||
homeFolderName);
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException e)
|
|
||||||
{
|
|
||||||
throw new PersonException("Invalid template to create home space");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NodeRef homeFolderNodeRef = fileInfo.getNodeRef();
|
|
||||||
return new HomeSpaceNodeRef(homeFolderNodeRef, HomeSpaceNodeRef.Status.CREATED);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new HomeSpaceNodeRef(existingHomeFolder, HomeSpaceNodeRef.Status.VALID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected synchronized NodeRef getTemplateNodeRef()
|
protected synchronized NodeRef getTemplateNodeRef()
|
||||||
{
|
{
|
||||||
if (templateNodeRef == null)
|
if (templateNodeRef == null && templatePath != null)
|
||||||
{
|
{
|
||||||
templateNodeRef = resolvePath(templatePath);
|
templateNodeRef = resolvePath(templatePath);
|
||||||
}
|
}
|
||||||
return templateNodeRef;
|
return templateNodeRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getHomeFolderPath(NodeRef person)
|
||||||
|
{
|
||||||
|
List<String> path = new ArrayList<String>(1);
|
||||||
|
path.add(FileNameValidator.getValidFileName(
|
||||||
|
getHomeFolderManager().getPersonProperty(person, ContentModel.PROP_USERNAME)));
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HomeSpaceNodeRef getHomeFolder(NodeRef person)
|
||||||
|
{
|
||||||
|
return getHomeFolderManager().getHomeFolder(getV2Adaptor(), person, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||||
|
*
|
||||||
|
* This file is part of Alfresco
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.security.person;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.util.FileNameValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates home folders directly under the root path, based on the username of the user.
|
||||||
|
*
|
||||||
|
* @author Alan Davis (based on UIDBasedHomeFolderProvider)
|
||||||
|
*/
|
||||||
|
public class UsernameHomeFolderProvider extends AbstractHomeFolderProvider2
|
||||||
|
{
|
||||||
|
private String templatePath;
|
||||||
|
|
||||||
|
private NodeRef templateNodeRef;
|
||||||
|
|
||||||
|
public void setTemplatePath(String templatePath)
|
||||||
|
{
|
||||||
|
this.templatePath = templatePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized NodeRef getTemplateNodeRef()
|
||||||
|
{
|
||||||
|
if (templateNodeRef == null && templatePath != null)
|
||||||
|
{
|
||||||
|
templateNodeRef = getHomeFolderManager().resolvePath(this, templatePath);
|
||||||
|
}
|
||||||
|
return templateNodeRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getHomeFolderPath(NodeRef person)
|
||||||
|
{
|
||||||
|
List<String> path = new ArrayList<String>(1);
|
||||||
|
path.add(FileNameValidator.getValidFileName(
|
||||||
|
getHomeFolderManager().getPersonProperty(person, ContentModel.PROP_USERNAME)));
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HomeSpaceNodeRef getHomeFolder(NodeRef person)
|
||||||
|
{
|
||||||
|
return getHomeFolderManager().getHomeFolder(this, person, false);
|
||||||
|
}
|
||||||
|
}
|
@@ -87,7 +87,7 @@ public class AlfrescoAssignment extends JBPMSpringAssignmentHandler
|
|||||||
if (actorValStr.startsWith("#{"))
|
if (actorValStr.startsWith("#{"))
|
||||||
{
|
{
|
||||||
String expression = actorValStr.substring(2, actorValStr.length() -1);
|
String expression = actorValStr.substring(2, actorValStr.length() -1);
|
||||||
Object eval = AlfrescoJavaScript.executeScript(executionContext, services, expression, null);
|
Object eval = AlfrescoJavaScript.executeScript(executionContext, services, expression, null, null);
|
||||||
if (eval == null)
|
if (eval == null)
|
||||||
{
|
{
|
||||||
throw new WorkflowException("actor expression '" + actorValStr + "' evaluates to null");
|
throw new WorkflowException("actor expression '" + actorValStr + "' evaluates to null");
|
||||||
@@ -128,7 +128,7 @@ public class AlfrescoAssignment extends JBPMSpringAssignmentHandler
|
|||||||
if (pooledactorValStr.startsWith("#{"))
|
if (pooledactorValStr.startsWith("#{"))
|
||||||
{
|
{
|
||||||
String expression = pooledactorValStr.substring(2, pooledactorValStr.length() -1);
|
String expression = pooledactorValStr.substring(2, pooledactorValStr.length() -1);
|
||||||
Object eval = AlfrescoJavaScript.executeScript(executionContext, services, expression, null);
|
Object eval = AlfrescoJavaScript.executeScript(executionContext, services, expression, null, null);
|
||||||
if (eval == null)
|
if (eval == null)
|
||||||
{
|
{
|
||||||
throw new WorkflowException("pooledactors expression '" + pooledactorValStr + "' evaluates to null");
|
throw new WorkflowException("pooledactors expression '" + pooledactorValStr + "' evaluates to null");
|
||||||
|
@@ -20,16 +20,17 @@ package org.alfresco.repo.workflow.jbpm;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.repo.model.Repository;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||||
import org.alfresco.service.ServiceRegistry;
|
import org.alfresco.service.ServiceRegistry;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
import org.alfresco.service.cmr.repository.ScriptService;
|
import org.alfresco.service.cmr.repository.ScriptService;
|
||||||
import org.alfresco.service.cmr.workflow.WorkflowException;
|
import org.alfresco.service.cmr.workflow.WorkflowException;
|
||||||
import org.dom4j.Element;
|
import org.dom4j.Element;
|
||||||
@@ -65,16 +66,19 @@ public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
|||||||
|
|
||||||
private static JpdlXmlReader jpdlReader = new JpdlXmlReader((InputSource)null);
|
private static JpdlXmlReader jpdlReader = new JpdlXmlReader((InputSource)null);
|
||||||
private ServiceRegistry services;
|
private ServiceRegistry services;
|
||||||
|
private NodeRef companyHome;
|
||||||
private Element script;
|
private Element script;
|
||||||
private String runas;
|
private String runas;
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/**
|
||||||
* @see org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler#initialiseHandler(org.springframework.beans.factory.BeanFactory)
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void initialiseHandler(BeanFactory factory)
|
protected void initialiseHandler(BeanFactory factory)
|
||||||
{
|
{
|
||||||
services = (ServiceRegistry)factory.getBean(ServiceRegistry.SERVICE_REGISTRY);
|
this.services = (ServiceRegistry)factory.getBean(ServiceRegistry.SERVICE_REGISTRY);
|
||||||
|
Repository repositoryHelper = (Repository)factory.getBean("repositoryHelper");
|
||||||
|
this.companyHome = repositoryHelper.getCompanyHome();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -122,7 +126,7 @@ public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
|||||||
String user = AuthenticationUtil.getFullyAuthenticatedUser();
|
String user = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||||
if (runas == null && user !=null)
|
if (runas == null && user !=null)
|
||||||
{
|
{
|
||||||
return executeScript(executionContext, services, expression, variableAccesses);
|
return executeScript(executionContext, services, expression, variableAccesses, companyHome);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -134,21 +138,20 @@ public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
|||||||
{
|
{
|
||||||
validateRunAsUser();
|
validateRunAsUser();
|
||||||
}
|
}
|
||||||
return executeScriptAs(runAsUser, expression, executionContext, services, variableAccesses);
|
return executeScriptAs(runAsUser, expression, executionContext, variableAccesses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object executeScriptAs(String runAsUser,
|
private Object executeScriptAs(String runAsUser,
|
||||||
final String expression,
|
final String expression,
|
||||||
final ExecutionContext executionContext,
|
final ExecutionContext executionContext,
|
||||||
final ServiceRegistry services,
|
|
||||||
final List<VariableAccess> variableAccesses) {
|
final List<VariableAccess> variableAccesses) {
|
||||||
// execute as specified runAsUser
|
// execute as specified runAsUser
|
||||||
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
|
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
|
||||||
{
|
{
|
||||||
public Object doWork() throws Exception
|
public Object doWork() throws Exception
|
||||||
{
|
{
|
||||||
return executeScript(executionContext, services, expression, variableAccesses);
|
return executeScript(executionContext, services, expression, variableAccesses,companyHome);
|
||||||
}
|
}
|
||||||
}, runAsUser);
|
}, runAsUser);
|
||||||
}
|
}
|
||||||
@@ -252,11 +255,12 @@ public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
|||||||
* @param services Alfresco service registry
|
* @param services Alfresco service registry
|
||||||
* @param expression script to execute
|
* @param expression script to execute
|
||||||
* @param variableAccesses (optional) list of jBPM variables to map into script (all, if not supplied)
|
* @param variableAccesses (optional) list of jBPM variables to map into script (all, if not supplied)
|
||||||
|
* @param companyHome TODO
|
||||||
* @return script result
|
* @return script result
|
||||||
*/
|
*/
|
||||||
public static Object executeScript(ExecutionContext context, ServiceRegistry services, String expression, List<VariableAccess> variableAccesses)
|
public static Object executeScript(ExecutionContext context, ServiceRegistry services, String expression, List<VariableAccess> variableAccesses, NodeRef companyHome)
|
||||||
{
|
{
|
||||||
Map<String, Object> inputMap = createInputMap(context, services, variableAccesses);
|
Map<String, Object> inputMap = createInputMap(services, companyHome, context, variableAccesses);
|
||||||
ScriptService scriptService = services.getScriptService();
|
ScriptService scriptService = services.getScriptService();
|
||||||
scriptService.buildCoreModel(inputMap);
|
scriptService.buildCoreModel(inputMap);
|
||||||
Object result = scriptService.executeScriptString(expression, inputMap);
|
Object result = scriptService.executeScriptString(expression, inputMap);
|
||||||
@@ -329,26 +333,25 @@ public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
|||||||
* Construct map of arguments to pass to script
|
* Construct map of arguments to pass to script
|
||||||
*
|
*
|
||||||
* Based on the <variable> elements of the action configuration.
|
* Based on the <variable> elements of the action configuration.
|
||||||
*
|
* @param companyHome TODO
|
||||||
* @param executionContext the execution context
|
* @param executionContext the execution context
|
||||||
* @param variableAccesses the variable configuration
|
* @param variableAccesses the variable configuration
|
||||||
|
*
|
||||||
* @return the map of script arguments
|
* @return the map of script arguments
|
||||||
*/
|
*/
|
||||||
private static Map<String, Object> createInputMap(ExecutionContext executionContext, ServiceRegistry services, List<VariableAccess> variableAccesses)
|
private static Map<String, Object> createInputMap(ServiceRegistry services, NodeRef companyHome, ExecutionContext executionContext, List<VariableAccess> variableAccesses)
|
||||||
{
|
{
|
||||||
Map<String, Object> inputMap = new HashMap<String, Object>();
|
ScriptService scriptService = services.getScriptService();
|
||||||
|
|
||||||
// initialise global script variables
|
// initialise global script variables
|
||||||
JBPMNode personNode = getPersonNode(executionContext, services);
|
NodeRef person = getPersonNode(services);
|
||||||
if (personNode != null)
|
NodeRef userHome = null;
|
||||||
|
if (person != null)
|
||||||
{
|
{
|
||||||
inputMap.put("person", personNode );
|
NodeService nodeService = services.getNodeService();
|
||||||
NodeRef homeSpace = (NodeRef)services.getNodeService().getProperty(personNode.getNodeRef(), ContentModel.PROP_HOMEFOLDER);
|
userHome = (NodeRef)nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER);
|
||||||
if (homeSpace != null)
|
|
||||||
{
|
|
||||||
inputMap.put("userhome", new JBPMNode(homeSpace, services));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Map<String, Object> inputMap = scriptService.buildDefaultModel(person, companyHome, userHome, null, null, null);
|
||||||
|
|
||||||
// initialise process variables
|
// initialise process variables
|
||||||
Token token = executionContext.getToken();
|
Token token = executionContext.getToken();
|
||||||
@@ -405,15 +408,12 @@ public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static JBPMNode getPersonNode(ExecutionContext executionContext, ServiceRegistry services) {
|
private static NodeRef getPersonNode(ServiceRegistry services) {
|
||||||
String userName = AuthenticationUtil.getFullyAuthenticatedUser();
|
String userName = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||||
if(userName != null)
|
if(userName != null)
|
||||||
{
|
{
|
||||||
NodeRef person = services.getPersonService().getPerson(userName);
|
NodeRef person = services.getPersonService().getPerson(userName);
|
||||||
if(person !=null)
|
return person;
|
||||||
{
|
|
||||||
return new JBPMNode(person, services);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,16 @@
|
|||||||
package org.alfresco.repo.workflow.jbpm;
|
package org.alfresco.repo.workflow.jbpm;
|
||||||
|
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.repo.jscript.ScriptNode;
|
||||||
import org.alfresco.repo.model.Repository;
|
import org.alfresco.repo.model.Repository;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.scripts.ScriptException;
|
import org.alfresco.scripts.ScriptException;
|
||||||
@@ -30,6 +34,8 @@ import org.jbpm.context.exe.ContextInstance;
|
|||||||
import org.jbpm.graph.exe.ExecutionContext;
|
import org.jbpm.graph.exe.ExecutionContext;
|
||||||
import org.jbpm.graph.exe.Token;
|
import org.jbpm.graph.exe.Token;
|
||||||
import org.jbpm.taskmgmt.exe.TaskInstance;
|
import org.jbpm.taskmgmt.exe.TaskInstance;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
public class AlfrescoJavaScriptIntegrationTest extends BaseAlfrescoSpringTest
|
public class AlfrescoJavaScriptIntegrationTest extends BaseAlfrescoSpringTest
|
||||||
{
|
{
|
||||||
@@ -193,6 +199,39 @@ public class AlfrescoJavaScriptIntegrationTest extends BaseAlfrescoSpringTest
|
|||||||
assertEquals(docLibB, nodeService.getPrimaryParent(doc).getParentRef());
|
assertEquals(docLibB, nodeService.getPrimaryParent(doc).getParentRef());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testScopeVariables() throws Exception
|
||||||
|
{
|
||||||
|
String admin = AuthenticationUtil.getAdminUserName();
|
||||||
|
AuthenticationUtil.setFullyAuthenticatedUser(admin);
|
||||||
|
NodeRef person = personService.getPerson(admin);
|
||||||
|
Serializable userHome = nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER);
|
||||||
|
|
||||||
|
AlfrescoJavaScript scriptHandler = new AlfrescoJavaScript();
|
||||||
|
String key = "result";
|
||||||
|
|
||||||
|
// Check person node set.
|
||||||
|
Element script = buildScript("executionContext.setVariable('" + key + "', person)");
|
||||||
|
scriptHandler.setScript(script);
|
||||||
|
scriptHandler.execute(context);
|
||||||
|
ScriptNode value = (ScriptNode) variables.get(key);
|
||||||
|
assertEquals(person, value.getNodeRef());
|
||||||
|
|
||||||
|
// Check user home set.
|
||||||
|
script = buildScript("executionContext.setVariable('" + key + "', userhome)");
|
||||||
|
scriptHandler.setScript(script);
|
||||||
|
scriptHandler.execute(context);
|
||||||
|
value = (ScriptNode) variables.get(key);
|
||||||
|
assertEquals(userHome, value.getNodeRef());
|
||||||
|
|
||||||
|
// Check company home set.
|
||||||
|
NodeRef companyHome = repository.getCompanyHome();
|
||||||
|
script = buildScript("executionContext.setVariable('" + key + "', companyhome)");
|
||||||
|
scriptHandler.setScript(script);
|
||||||
|
scriptHandler.execute(context);
|
||||||
|
value = (ScriptNode) variables.get(key);
|
||||||
|
assertEquals(companyHome, value.getNodeRef());
|
||||||
|
}
|
||||||
|
|
||||||
private Element buildScript(String expression) {
|
private Element buildScript(String expression) {
|
||||||
Element script = DocumentHelper.createElement("script");
|
Element script = DocumentHelper.createElement("script");
|
||||||
script.setText(expression);
|
script.setText(expression);
|
||||||
@@ -203,7 +242,8 @@ public class AlfrescoJavaScriptIntegrationTest extends BaseAlfrescoSpringTest
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
protected void onSetUp() throws Exception {
|
protected void onSetUp() throws Exception {
|
||||||
super.onSetUp();
|
super.onSetUp();
|
||||||
services = (ServiceRegistry) applicationContext.getBean("ServiceRegistry");
|
|
||||||
|
this.services = (ServiceRegistry) applicationContext.getBean("ServiceRegistry");
|
||||||
repository = (Repository) applicationContext.getBean("repositoryHelper");
|
repository = (Repository) applicationContext.getBean("repositoryHelper");
|
||||||
personService = services.getPersonService();
|
personService = services.getPersonService();
|
||||||
createUser(BASIC_USER);
|
createUser(BASIC_USER);
|
||||||
@@ -214,7 +254,25 @@ public class AlfrescoJavaScriptIntegrationTest extends BaseAlfrescoSpringTest
|
|||||||
when(context.getContextInstance()).thenReturn(contextInstance);
|
when(context.getContextInstance()).thenReturn(contextInstance);
|
||||||
variables = new HashMap<String, Object>();
|
variables = new HashMap<String, Object>();
|
||||||
when(contextInstance.getVariables()).thenReturn(variables);
|
when(contextInstance.getVariables()).thenReturn(variables);
|
||||||
when(contextInstance.getVariables((Token) any())).thenReturn(variables);
|
when(contextInstance.getVariables( any(Token.class))).thenReturn(variables);
|
||||||
|
when(context.getVariable(anyString())).thenAnswer(new Answer<Object>()
|
||||||
|
{
|
||||||
|
public Object answer(InvocationOnMock invocation) throws Throwable
|
||||||
|
{
|
||||||
|
String key = (String)invocation.getArguments()[0];
|
||||||
|
return variables.get(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
doAnswer(new Answer<Void>()
|
||||||
|
{
|
||||||
|
public Void answer(InvocationOnMock invocation) throws Throwable
|
||||||
|
{
|
||||||
|
String key = (String)invocation.getArguments()[0];
|
||||||
|
Object value= invocation.getArguments()[1];
|
||||||
|
variables.put(key, value);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).when(context).setVariable(anyString(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createUser(String userName)
|
private void createUser(String userName)
|
||||||
@@ -236,9 +294,9 @@ public class AlfrescoJavaScriptIntegrationTest extends BaseAlfrescoSpringTest
|
|||||||
public static class TestUserStore {
|
public static class TestUserStore {
|
||||||
private String runAsUser;
|
private String runAsUser;
|
||||||
private String fullUser;
|
private String fullUser;
|
||||||
private JBPMNode person = null;
|
private ScriptNode person = null;
|
||||||
|
|
||||||
public void storeUsers(JBPMNode user)
|
public void storeUsers(ScriptNode user)
|
||||||
{
|
{
|
||||||
fullUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
fullUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||||
runAsUser = AuthenticationUtil.getRunAsUser();
|
runAsUser = AuthenticationUtil.getRunAsUser();
|
||||||
|
@@ -148,7 +148,7 @@ public class ForEachFork extends JBPMSpringActionHandler
|
|||||||
private Collection<?> evaluateForEachExpression(final ExecutionContext executionContext, String forEachText)
|
private Collection<?> evaluateForEachExpression(final ExecutionContext executionContext, String forEachText)
|
||||||
{
|
{
|
||||||
String expression = forEachText.substring(2, forEachText.length() -1);
|
String expression = forEachText.substring(2, forEachText.length() -1);
|
||||||
Object result = AlfrescoJavaScript.executeScript(executionContext, services, expression, null);
|
Object result = AlfrescoJavaScript.executeScript(executionContext, services, expression, null, null);
|
||||||
if (result == null)
|
if (result == null)
|
||||||
{
|
{
|
||||||
throw new WorkflowException("forEach expression '" + forEachText + "' evaluates to null");
|
throw new WorkflowException("forEach expression '" + forEachText + "' evaluates to null");
|
||||||
|
152
source/java/org/alfresco/wcm/WCMAspectTest.java
Normal file
152
source/java/org/alfresco/wcm/WCMAspectTest.java
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||||
|
*
|
||||||
|
* This file is part of Alfresco
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.alfresco.wcm;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.alfresco.repo.dictionary.DictionaryDAO;
|
||||||
|
import org.alfresco.repo.dictionary.M2Aspect;
|
||||||
|
import org.alfresco.repo.dictionary.M2Model;
|
||||||
|
import org.alfresco.repo.dictionary.M2Property;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
|
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||||
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.alfresco.wcm.asset.AssetInfo;
|
||||||
|
import org.alfresco.wcm.asset.AssetService;
|
||||||
|
import org.alfresco.wcm.sandbox.SandboxInfo;
|
||||||
|
import org.alfresco.wcm.sandbox.SandboxService;
|
||||||
|
import org.alfresco.wcm.webproject.WebProjectInfo;
|
||||||
|
import org.alfresco.wcm.webproject.WebProjectService;
|
||||||
|
|
||||||
|
public class WCMAspectTest extends AbstractWCMServiceImplTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private AssetService assetService = null;
|
||||||
|
private WebProjectService wpService = null;
|
||||||
|
private SandboxService sbService = null;
|
||||||
|
private DictionaryDAO dictionaryDAO = null;
|
||||||
|
|
||||||
|
private final static int SIZE = 1000;
|
||||||
|
private final static String ADMIN = "admin";
|
||||||
|
|
||||||
|
private static String TEST_TYPE_NAMESPACE = "http://www.alfresco.org/model/testaspectmodel/1.0";
|
||||||
|
private static QName TEST_ASPECT_QNAME = QName.createQName(TEST_TYPE_NAMESPACE, "Aspect");
|
||||||
|
private static QName PROP_QNAME = QName.createQName(TEST_TYPE_NAMESPACE, "applications");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
wpService = (WebProjectService) ctx.getBean("WebProjectService");
|
||||||
|
sbService = (SandboxService) ctx.getBean("SandboxService");
|
||||||
|
assetService = (AssetService) ctx.getBean("AssetService");
|
||||||
|
dictionaryDAO = (DictionaryDAO) ctx.getBean("dictionaryDAO");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAspect() throws Exception
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AuthenticationUtil.setFullyAuthenticatedUser(ADMIN);
|
||||||
|
|
||||||
|
WebProjectInfo wpInfo = wpService.createWebProject(TEST_WEBPROJ_DNS + "-aspectSimple", TEST_WEBPROJ_NAME + "-aspectSimple", TEST_WEBPROJ_TITLE,
|
||||||
|
TEST_WEBPROJ_DESCRIPTION, TEST_WEBPROJ_DEFAULT_WEBAPP, TEST_WEBPROJ_DONT_USE_AS_TEMPLATE, null);
|
||||||
|
|
||||||
|
String wpStoreId = wpInfo.getStoreId();
|
||||||
|
String defaultWebApp = wpInfo.getDefaultWebApp();
|
||||||
|
|
||||||
|
SandboxInfo sbInfo = sbService.getAuthorSandbox(wpStoreId);
|
||||||
|
String authorSandboxId = sbInfo.getSandboxId();
|
||||||
|
|
||||||
|
String authorSandboxPath = sbInfo.getSandboxRootPath() + "/" + defaultWebApp;
|
||||||
|
|
||||||
|
assetService.createFile(authorSandboxId, authorSandboxPath, "myFile", null);
|
||||||
|
|
||||||
|
AssetInfo assetInfo = assetService.getAsset(authorSandboxId, authorSandboxPath + "/" + "myFile");
|
||||||
|
attachAspect(assetInfo);
|
||||||
|
checkAspect(assetInfo);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
AuthenticationUtil.clearCurrentSecurityContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void checkAspect(AssetInfo assetInfo)
|
||||||
|
{
|
||||||
|
assertTrue(assetService.hasAspect(assetInfo, TEST_ASPECT_QNAME));
|
||||||
|
|
||||||
|
Map<QName, Serializable> properties = assetService.getAssetProperties(assetInfo);
|
||||||
|
|
||||||
|
List<String> list = (List<String>) properties.get(PROP_QNAME);
|
||||||
|
assertEquals(list.size(), SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void attachAspect(final AssetInfo assetInfo)
|
||||||
|
{
|
||||||
|
M2Model model = M2Model.createModel("custom:custom");
|
||||||
|
model.createNamespace(TEST_TYPE_NAMESPACE, "custom");
|
||||||
|
model.createImport(NamespaceService.DICTIONARY_MODEL_1_0_URI, NamespaceService.DICTIONARY_MODEL_PREFIX);
|
||||||
|
model.createImport(NamespaceService.SYSTEM_MODEL_1_0_URI, NamespaceService.SYSTEM_MODEL_PREFIX);
|
||||||
|
model.createImport(NamespaceService.CONTENT_MODEL_1_0_URI, NamespaceService.CONTENT_MODEL_PREFIX);
|
||||||
|
|
||||||
|
M2Aspect testMandatoryAspect = model.createAspect("custom:" + TEST_ASPECT_QNAME.getLocalName());
|
||||||
|
|
||||||
|
M2Property prop = testMandatoryAspect.createProperty("custom:" + PROP_QNAME.getLocalName());
|
||||||
|
prop.setType("d:" + DataTypeDefinition.TEXT.getLocalName());
|
||||||
|
prop.setMultiValued(true);
|
||||||
|
prop.setIndexed(true);
|
||||||
|
|
||||||
|
dictionaryDAO.putModel(model);
|
||||||
|
|
||||||
|
final Map<QName, Serializable> aspectValues = new HashMap<QName, Serializable>();
|
||||||
|
List<String> applications = new ArrayList<String>();
|
||||||
|
|
||||||
|
for (int i = 0; i < SIZE; i++)
|
||||||
|
{
|
||||||
|
applications.add("Adding " + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
aspectValues.put(PROP_QNAME, (Serializable) applications);
|
||||||
|
|
||||||
|
// takes about 150 milliseconds to commit
|
||||||
|
transactionService.getRetryingTransactionHelper().doInTransaction(
|
||||||
|
new RetryingTransactionCallback<Object>()
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object execute() throws Throwable
|
||||||
|
{
|
||||||
|
assetService.addAspect(assetInfo, TEST_ASPECT_QNAME, aspectValues);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -43,6 +43,7 @@ public class WCMTestSuite extends TestSuite
|
|||||||
{
|
{
|
||||||
TestSuite suite = new TestSuite();
|
TestSuite suite = new TestSuite();
|
||||||
|
|
||||||
|
suite.addTestSuite(WCMAspectTest.class);
|
||||||
suite.addTestSuite(WebProjectServiceImplTest.class);
|
suite.addTestSuite(WebProjectServiceImplTest.class);
|
||||||
suite.addTestSuite(AssetServiceImplTest.class);
|
suite.addTestSuite(AssetServiceImplTest.class);
|
||||||
suite.addTestSuite(SandboxServiceImplTest.class);
|
suite.addTestSuite(SandboxServiceImplTest.class);
|
||||||
|
Reference in New Issue
Block a user