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" />
|
||||
</property>
|
||||
<property name="enableHomeFolderCreationAsPeopleAreCreated">
|
||||
<!--<value>false</value> -->
|
||||
<value>${home.folder.creation.eager}</value>
|
||||
</property>
|
||||
<!-- Requests services via ServiceRegistry for audit -->
|
||||
<property name="serviceRegistry">
|
||||
<ref bean="ServiceRegistry" />
|
||||
</property>
|
||||
<property name="tenantService">
|
||||
<ref bean="tenantService" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean name="baseHomeFolderProvider" class="org.alfresco.repo.security.person.AbstractHomeFolderProvider" abstract="true">
|
||||
<!-- Requests services via ServiceRegistry for auditability -->
|
||||
<!-- deprecated use baseHomeFolderProvider2 -->
|
||||
<bean name="baseHomeFolderProvider"
|
||||
class="org.alfresco.repo.security.person.AbstractHomeFolderProvider"
|
||||
abstract="true">
|
||||
<!-- Requests services via ServiceRegistry for audit -->
|
||||
<property name="serviceRegistry">
|
||||
<ref bean="ServiceRegistry" />
|
||||
</property>
|
||||
@@ -393,8 +402,47 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean name="companyHomeFolderProvider" class="org.alfresco.repo.security.person.ExistingPathBasedHomeFolderProvider" parent="baseHomeFolderProvider">
|
||||
<property name="path">
|
||||
<bean name="baseHomeFolderProvider2"
|
||||
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>
|
||||
</property>
|
||||
<property name="storeUrl">
|
||||
@@ -402,7 +450,8 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean name="guestHomeFolderProviderPermissionsManager" class="org.alfresco.repo.security.person.PermissionsManagerImpl">
|
||||
<bean name="guestHomeFolderProviderPermissionsManager"
|
||||
class="org.alfresco.repo.security.person.PermissionsManagerImpl">
|
||||
<property name="permissionService">
|
||||
<ref bean="permissionServiceImpl" />
|
||||
</property>
|
||||
@@ -417,12 +466,8 @@
|
||||
</bean>
|
||||
|
||||
|
||||
<bean name="guestHomeFolderProvider" class="org.alfresco.repo.security.person.ExistingPathBasedHomeFolderProvider" parent="baseHomeFolderProvider">
|
||||
<!-- Requests services via ServiceRegistry for auditability -->
|
||||
<property name="serviceRegistry">
|
||||
<ref bean="ServiceRegistry" />
|
||||
</property>
|
||||
<property name="path">
|
||||
<bean name="guestHomeFolderProvider" parent="existingHomeFolderProvider">
|
||||
<property name="rootPath">
|
||||
<value>/${spaces.company_home.childname}/${spaces.guest_home.childname}</value>
|
||||
</property>
|
||||
<property name="storeUrl">
|
||||
@@ -436,9 +481,12 @@
|
||||
</property>
|
||||
</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">
|
||||
<ref bean="permissionServiceImpl" />
|
||||
</property>
|
||||
@@ -460,7 +508,8 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean name="defaultOnReferencePermissionsManager" class="org.alfresco.repo.security.person.PermissionsManagerImpl" >
|
||||
<bean name="defaultOnReferencePermissionsManager"
|
||||
class="org.alfresco.repo.security.person.PermissionsManagerImpl" >
|
||||
<property name="permissionService">
|
||||
<ref bean="permissionServiceImpl" />
|
||||
</property>
|
||||
@@ -474,40 +523,32 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean name="personalHomeFolderProvider" class="org.alfresco.repo.security.person.UIDBasedHomeFolderProvider" parent="baseHomeFolderProvider">
|
||||
<!-- Requests services via ServiceRegistry for auditability -->
|
||||
<property name="serviceRegistry">
|
||||
<ref bean="ServiceRegistry" />
|
||||
</property>
|
||||
<property name="path">
|
||||
<bean name="personalHomeFolderProvider" parent="usernameHomeFolderProvider">
|
||||
<property name="rootPath">
|
||||
<value>/${spaces.company_home.childname}</value>
|
||||
</property>
|
||||
<property name="storeUrl">
|
||||
<value>${spaces.store}</value>
|
||||
</property>
|
||||
<property name="onCreatePermissionsManager">
|
||||
<ref bean="defaultOnCreatePermissionsManager" />
|
||||
</property>
|
||||
<property name="onReferencePermissionsManager">
|
||||
<ref bean="defaultOnReferencePermissionsManager" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean name="userHomesHomeFolderProvider" class="org.alfresco.repo.security.person.UIDBasedHomeFolderProvider" parent="baseHomeFolderProvider">
|
||||
<property name="path">
|
||||
<bean name="userHomesHomeFolderProvider" parent="usernameHomeFolderProvider">
|
||||
<property name="rootPath">
|
||||
<value>/${spaces.company_home.childname}/${spaces.user_homes.childname}</value>
|
||||
</property>
|
||||
<property name="storeUrl">
|
||||
<value>${spaces.store}</value>
|
||||
</property>
|
||||
<property name="onCreatePermissionsManager">
|
||||
<ref bean="defaultOnCreatePermissionsManager" />
|
||||
</property>
|
||||
<property name="onReferencePermissionsManager">
|
||||
<ref bean="defaultOnReferencePermissionsManager" />
|
||||
</property>
|
||||
</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. -->
|
||||
|
@@ -687,6 +687,18 @@
|
||||
</property>
|
||||
</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) -->
|
||||
<bean id="Synchronization" class="org.alfresco.repo.management.subsystems.ChildApplicationContextFactory" parent="abstractPropertyBackedBean">
|
||||
<property name="autoStart">
|
||||
|
@@ -175,7 +175,7 @@
|
||||
<title>Can this resource be enabled/disabled.</title>
|
||||
<properties>
|
||||
<property name="trx:enabled">
|
||||
<title>Is this enabled.</title>
|
||||
<title>Enabled</title>
|
||||
<type>d:boolean</type>
|
||||
<mandatory>true</mandatory>
|
||||
</property>
|
||||
|
@@ -384,6 +384,9 @@ spaces.wcm.childname=app:wcm
|
||||
spaces.wcm_content_forms.childname=app:wcm_forms
|
||||
spaces.content_forms.childname=app:forms
|
||||
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.templates.email.invite.childname=cm:invite
|
||||
spaces.templates.email.activities.childname=cm:activities
|
||||
@@ -399,6 +402,7 @@ spaces.extension_webscripts.childname=cm:extensionwebscripts
|
||||
spaces.models.childname=app:models
|
||||
spaces.workflow.definitions.childname=app:workflow_defs
|
||||
|
||||
|
||||
# ADM VersionStore Configuration
|
||||
version.store.deprecated.lightWeightVersionStore=workspace://lightWeightVersionStore
|
||||
version.store.version2Store=workspace://version2Store
|
||||
|
@@ -99,7 +99,7 @@ ldap.synchronization.userEmailAttributeName=mail
|
||||
ldap.synchronization.userOrganizationalIdAttributeName=company
|
||||
|
||||
# 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
|
||||
ldap.synchronization.groupIdAttributeName=cn
|
||||
|
@@ -105,7 +105,7 @@ ldap.synchronization.userEmailAttributeName=mail
|
||||
ldap.synchronization.userOrganizationalIdAttributeName=o
|
||||
|
||||
# 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
|
||||
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.domain.qname.QNameDAO;
|
||||
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.NodeRef;
|
||||
import org.alfresco.service.cmr.rule.RuleService;
|
||||
@@ -110,18 +111,22 @@ public class FixUserQNamesPatch extends AbstractPatch implements ApplicationEven
|
||||
20,
|
||||
this.applicationEventPublisher, logger, 1000);
|
||||
|
||||
final String runAsUser = AuthenticationUtil.getRunAsUser();
|
||||
|
||||
int updated = batchProcessor.process(new BatchProcessWorker<ChildAssociationRef>()
|
||||
{
|
||||
public void beforeProcess() throws Throwable
|
||||
{
|
||||
// Disable rules
|
||||
ruleService.disableRules();
|
||||
AuthenticationUtil.setRunAsUser(runAsUser);
|
||||
}
|
||||
|
||||
public void afterProcess() throws Throwable
|
||||
{
|
||||
// Enable rules
|
||||
ruleService.enableRules();
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
}
|
||||
|
||||
public String getIdentifier(ChildAssociationRef entry)
|
||||
|
@@ -480,7 +480,14 @@ public class AlfrescoImapFolder extends AbstractImapFolder implements Serializab
|
||||
{
|
||||
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();
|
||||
|
||||
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))
|
||||
{
|
||||
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);
|
||||
|
@@ -100,6 +100,8 @@ import org.springframework.extensions.surf.util.AbstractLifecycleBean;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import com.icegreen.greenmail.imap.ImapConstants;
|
||||
|
||||
/**
|
||||
* @author Dmitry Vaserin
|
||||
* @author Arseny Kovalchuk
|
||||
@@ -216,6 +218,11 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol
|
||||
this.foldersCache = foldersCache;
|
||||
}
|
||||
|
||||
public SimpleCache<Serializable, Object> getFoldersCache()
|
||||
{
|
||||
return foldersCache;
|
||||
}
|
||||
|
||||
public FileFolderService getFileFolderService()
|
||||
{
|
||||
return fileFolderService;
|
||||
@@ -792,11 +799,13 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol
|
||||
/**
|
||||
* Check whether resultFolder is stale
|
||||
*/
|
||||
/*
|
||||
if(resultFolder.isStale())
|
||||
{
|
||||
logger.debug("folder is stale");
|
||||
resultFolder = null;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if (resultFolder == null)
|
||||
@@ -841,7 +850,7 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol
|
||||
|
||||
NodeRef targetNode = fileFolderService.searchSimple(nodeRef, folderNames[i]);
|
||||
|
||||
if (targetNode == null)
|
||||
if (i == 0 && targetNode == null)
|
||||
{
|
||||
resultFolder = new AlfrescoImapFolder(user.getQualifiedMailboxName(), serviceRegistry);
|
||||
if (logger.isDebugEnabled())
|
||||
@@ -1294,6 +1303,20 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -2202,7 +2257,7 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol
|
||||
}
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("UIDVALIDITY was modified");
|
||||
logger.debug("UIDVALIDITY was modified for " + folderNodeRef);
|
||||
}
|
||||
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
|
||||
*/
|
||||
|
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
|
||||
model.put("companyhome", companyHome);
|
||||
if (userHome!= null)
|
||||
{
|
||||
model.put("userhome", userHome);
|
||||
}
|
||||
if (person != null)
|
||||
{
|
||||
model.put("person", person);
|
||||
}
|
||||
if (script != null)
|
||||
{
|
||||
model.put("script", script);
|
||||
|
@@ -18,9 +18,11 @@
|
||||
*/
|
||||
package org.alfresco.repo.security;
|
||||
|
||||
import junit.framework.JUnit4TestAdapter;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.alfresco.repo.audit.access.AccessAuditorTest;
|
||||
import org.alfresco.repo.ownable.impl.OwnableServiceTest;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationBootstrapTest;
|
||||
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.FilteringResultSetTest;
|
||||
import org.alfresco.repo.security.permissions.impl.model.PermissionModelTest;
|
||||
import org.alfresco.repo.security.person.HomeFolderProviderSynchronizerTest;
|
||||
import org.alfresco.repo.security.person.PersonTest;
|
||||
|
||||
/**
|
||||
@@ -74,6 +77,8 @@ public class SecurityTestSuite extends TestSuite
|
||||
suite.addTestSuite(OwnableServiceTest.class);
|
||||
suite.addTestSuite(ReadPermissionTest.class);
|
||||
|
||||
suite.addTest(new JUnit4TestAdapter(HomeFolderProviderSynchronizerTest.class));
|
||||
|
||||
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
|
||||
*
|
||||
@@ -19,17 +19,12 @@
|
||||
package org.alfresco.repo.security.person;
|
||||
|
||||
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.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
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
|
||||
* homeFolderManager. Provider must all be wired up to the homeFolderManager.
|
||||
*
|
||||
* @deprecated
|
||||
* Depreciated since 4.0. {@link AbstractHomeFolderProvider2} should now be used.
|
||||
*
|
||||
* @author Andy Hind
|
||||
*/
|
||||
public abstract class AbstractHomeFolderProvider implements HomeFolderProvider, BeanNameAware, InitializingBean
|
||||
@@ -58,40 +56,34 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
||||
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;
|
||||
|
||||
/**
|
||||
* Tenant service - required for MT-enabled environment, else optional
|
||||
*/
|
||||
private TenantService tenantService;
|
||||
|
||||
/**
|
||||
* The path to a folder
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
private String ownerOnCreate;
|
||||
|
||||
/**
|
||||
* PermissionsManager used on creating the home folder
|
||||
*/
|
||||
private PermissionsManager onCreatePermissionsManager;
|
||||
|
||||
/**
|
||||
* PermissionsManager used on referencing the home folder
|
||||
*/
|
||||
private PermissionsManager onReferencePermissionsManager;
|
||||
|
||||
public AbstractHomeFolderProvider()
|
||||
{
|
||||
super();
|
||||
|
||||
pathNodeRefs = new ConcurrentHashMap<String, NodeRef>();
|
||||
}
|
||||
/**
|
||||
* Adaptor for this instance to be a HomeFolderProvider2
|
||||
*/
|
||||
private V2Adaptor v2Adaptor = new V2Adaptor(this);
|
||||
|
||||
/**
|
||||
* Register with the homeFolderManagewr
|
||||
@@ -99,13 +91,9 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
PropertyCheck.mandatory(this, "homeFolderManager", homeFolderManager);
|
||||
homeFolderManager.addProvider(this);
|
||||
homeFolderManager.addProvider(v2Adaptor);
|
||||
}
|
||||
|
||||
// === //
|
||||
// IOC //
|
||||
// === //
|
||||
|
||||
/**
|
||||
* Get the home folder manager.
|
||||
*/
|
||||
@@ -116,7 +104,6 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
||||
|
||||
/**
|
||||
* Set the home folder manager.
|
||||
*
|
||||
* @param homeFolderManager
|
||||
*/
|
||||
public void setHomeFolderManager(HomeFolderManager homeFolderManager)
|
||||
@@ -127,6 +114,7 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
||||
/**
|
||||
* Get the provider name
|
||||
*/
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
@@ -135,6 +123,7 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
||||
/**
|
||||
* The provider name is taken from the bean name
|
||||
*/
|
||||
@Override
|
||||
public void setBeanName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
@@ -153,7 +142,14 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
||||
*/
|
||||
public void setPath(String path)
|
||||
{
|
||||
boolean reset = this.path != null;
|
||||
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)
|
||||
{
|
||||
this.tenantService = tenantService;
|
||||
// keep class signature but no longer use value
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,11 +208,27 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
||||
this.onCreatePermissionsManager = onCreatePermissionsManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the PermissionsManager used on creating the home folder
|
||||
*/
|
||||
public PermissionsManager getOnCreatePermissionsManager()
|
||||
{
|
||||
return onCreatePermissionsManager;
|
||||
}
|
||||
|
||||
public void setOnReferencePermissionsManager(PermissionsManager 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.
|
||||
*/
|
||||
@@ -225,34 +237,28 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
||||
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
|
||||
*/
|
||||
protected NodeRef getPathNodeRef()
|
||||
{
|
||||
String tenantDomain = (tenantService != null ? tenantService.getCurrentUserDomain() : TenantService.DEFAULT_DOMAIN);
|
||||
|
||||
NodeRef pathNodeRef = pathNodeRefs.get(tenantDomain);
|
||||
if (pathNodeRef == null)
|
||||
{
|
||||
pathNodeRef = resolvePath(path);
|
||||
pathNodeRefs.put(tenantDomain, pathNodeRef);
|
||||
}
|
||||
return pathNodeRef;
|
||||
return homeFolderManager.getRootPathNodeRef(v2Adaptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility metho to resolve paths to nodes.
|
||||
* Utility method to resolve paths to nodes.
|
||||
*/
|
||||
protected NodeRef resolvePath(String pathToResolve)
|
||||
{
|
||||
List<NodeRef> refs = serviceRegistry.getSearchService().selectNodes(serviceRegistry.getNodeService().getRootNode(storeRef), pathToResolve, null,
|
||||
serviceRegistry.getNamespaceService(), false);
|
||||
if (refs.size() != 1)
|
||||
{
|
||||
throw new IllegalStateException("Non-unique path: found : " + pathToResolve + " " + refs.size());
|
||||
}
|
||||
return refs.get(0);
|
||||
return homeFolderManager.resolvePath(v2Adaptor, pathToResolve);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,69 +266,98 @@ public abstract class AbstractHomeFolderProvider implements HomeFolderProvider,
|
||||
*/
|
||||
public void onCreateNode(ChildAssociationRef childAssocRef)
|
||||
{
|
||||
AuthenticationUtil.RunAsWork<NodeRef> action = new OnCreateNode(childAssocRef);
|
||||
AuthenticationUtil.runAs(action, AuthenticationUtil.getSystemUserName());
|
||||
homeFolderManager.homeFolderCreateAndSetPermissions(v2Adaptor, childAssocRef.getChildRef());
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract implementation to find/create the approriate home space.
|
||||
* Abstract implementation to find/create the appropriate home space.
|
||||
*/
|
||||
protected abstract HomeSpaceNodeRef getHomeFolder(NodeRef person);
|
||||
|
||||
/**
|
||||
* Helper class to encapsulate the createion settinhg permissions etc
|
||||
*
|
||||
* @author Andy Hind
|
||||
* Get adaptor for this instance to be a HomeFolderProvider2
|
||||
*/
|
||||
private class OnCreateNode implements AuthenticationUtil.RunAsWork<NodeRef>
|
||||
protected V2Adaptor getV2Adaptor()
|
||||
{
|
||||
ChildAssociationRef childAssocRef;
|
||||
|
||||
OnCreateNode(ChildAssociationRef childAssocRef)
|
||||
{
|
||||
this.childAssocRef = childAssocRef;
|
||||
return v2Adaptor;
|
||||
}
|
||||
|
||||
public NodeRef doWork() throws Exception
|
||||
/**
|
||||
* Adaptor to the HomeFolderProvider2 interface.
|
||||
*/
|
||||
public class V2Adaptor implements HomeFolderProvider2
|
||||
{
|
||||
AbstractHomeFolderProvider abstractHomeFolderProvider;
|
||||
|
||||
// Find person
|
||||
NodeRef personNodeRef = childAssocRef.getChildRef();
|
||||
// Get home folder
|
||||
HomeSpaceNodeRef homeFolder = getHomeFolder(personNodeRef);
|
||||
// If it exists
|
||||
if (homeFolder.getNodeRef() != null)
|
||||
public V2Adaptor(AbstractHomeFolderProvider abstractHomeFolderProvider)
|
||||
{
|
||||
// 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());
|
||||
this.abstractHomeFolderProvider = abstractHomeFolderProvider;
|
||||
abstractHomeFolderProvider.v2Adaptor = this;
|
||||
}
|
||||
|
||||
String ownerToSet = ownerOnCreate == null ? uid : ownerOnCreate;
|
||||
// If created..
|
||||
if (homeFolder.getStatus() == HomeSpaceNodeRef.Status.CREATED)
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
if (onCreatePermissionsManager != null)
|
||||
{
|
||||
onCreatePermissionsManager.setPermissions(homeFolder.getNodeRef(), ownerToSet, uid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (onReferencePermissionsManager != null)
|
||||
{
|
||||
onReferencePermissionsManager.setPermissions(homeFolder.getNodeRef(), ownerToSet, uid);
|
||||
}
|
||||
return abstractHomeFolderProvider.getName();
|
||||
}
|
||||
|
||||
}
|
||||
return homeFolder.getNodeRef();
|
||||
|
||||
}
|
||||
@Override
|
||||
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
|
||||
*
|
||||
@@ -23,17 +23,16 @@ import org.alfresco.service.cmr.repository.NodeRef;
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public class BootstrapHomeFolderProvider extends AbstractHomeFolderProvider
|
||||
public class BootstrapHomeFolderProvider extends AbstractHomeFolderProvider2
|
||||
{
|
||||
|
||||
@Override
|
||||
protected HomeSpaceNodeRef getHomeFolder(NodeRef person)
|
||||
public HomeSpaceNodeRef getHomeFolder(NodeRef person)
|
||||
{
|
||||
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
|
||||
*
|
||||
@@ -18,35 +18,20 @@
|
||||
*/
|
||||
package org.alfresco.repo.security.person;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
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
|
||||
*/
|
||||
public class ExistingPathBasedHomeFolderProvider extends AbstractHomeFolderProvider
|
||||
{
|
||||
|
||||
public ExistingPathBasedHomeFolderProvider()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
protected HomeSpaceNodeRef getHomeFolder(NodeRef person)
|
||||
{
|
||||
NodeRef existingHomeFolder = DefaultTypeConverter.INSTANCE.convert(NodeRef.class, getServiceRegistry().getNodeService().getProperty(
|
||||
person, ContentModel.PROP_HOMEFOLDER));
|
||||
if (existingHomeFolder == null)
|
||||
{
|
||||
return new HomeSpaceNodeRef(getPathNodeRef(), HomeSpaceNodeRef.Status.REFERENCED);
|
||||
return getHomeFolderManager().getHomeFolder(getV2Adaptor(), person, true);
|
||||
}
|
||||
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
|
||||
*
|
||||
@@ -18,15 +18,27 @@
|
||||
*/
|
||||
package org.alfresco.repo.security.person;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.node.NodeServicePolicies;
|
||||
import org.alfresco.repo.policy.JavaBehaviour;
|
||||
import org.alfresco.repo.policy.PolicyComponent;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileFolderUtil;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.model.FileNotFoundException;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
@@ -34,26 +46,43 @@ import org.alfresco.service.namespace.QName;
|
||||
/**
|
||||
* Manage home folder creation by binding to events from the cm:person type.
|
||||
*
|
||||
* @author Andy Hind
|
||||
* @author Andy Hind,
|
||||
* Alan Davis (support v1 and v2 HomeFolderProviders - code from
|
||||
* v1 HomeFolderProviders moved into HomeFolderManager).
|
||||
*/
|
||||
public class HomeFolderManager implements NodeServicePolicies.OnCreateNodePolicy
|
||||
{
|
||||
|
||||
private PolicyComponent policyComponent;
|
||||
|
||||
private NodeService nodeService;
|
||||
|
||||
private boolean enableHomeFolderCreationAsPeopleAreCreated = false;
|
||||
|
||||
private ServiceRegistry serviceRegistry;
|
||||
|
||||
private TenantService tenantService;
|
||||
|
||||
/**
|
||||
* A default provider
|
||||
*/
|
||||
private HomeFolderProvider defaultProvider;
|
||||
private HomeFolderProvider2 defaultProvider;
|
||||
|
||||
/**
|
||||
* Providers that have registered and are looken up by name (== bean name)
|
||||
* Original Providers (now depreciated) that have registered and are looked up by bean name.
|
||||
*/
|
||||
private Map<String, HomeFolderProvider> providers = new HashMap<String, HomeFolderProvider>();
|
||||
@SuppressWarnings("deprecation")
|
||||
private Map<String, HomeFolderProvider> v1Providers = new HashMap<String, HomeFolderProvider>();
|
||||
|
||||
/**
|
||||
* Providers that have registered and are looked up by bean name.
|
||||
*/
|
||||
private Map<String, HomeFolderProvider2> v2Providers = new HashMap<String, HomeFolderProvider2>();
|
||||
|
||||
/**
|
||||
* Cache the result of the path look up.
|
||||
*/
|
||||
private Map<String, Map<String, NodeRef>> rootPathNodeRefMaps =
|
||||
new ConcurrentHashMap<String, Map<String, NodeRef>>();
|
||||
|
||||
/**
|
||||
* Bind the class behaviour to this implementation
|
||||
@@ -90,21 +119,65 @@ public class HomeFolderManager implements NodeServicePolicies.OnCreateNodePolicy
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the service registry.
|
||||
*/
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tenant service
|
||||
*/
|
||||
public void setTenantService(TenantService tenantService)
|
||||
{
|
||||
this.tenantService = tenantService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a home folder provider.
|
||||
*
|
||||
* @param provider
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void addProvider(HomeFolderProvider provider)
|
||||
{
|
||||
providers.put(provider.getName(), provider);
|
||||
v1Providers.put(provider.getName(), provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a home folder provider.
|
||||
*
|
||||
* @param provider
|
||||
*/
|
||||
public void addProvider(HomeFolderProvider2 provider)
|
||||
{
|
||||
v2Providers.put(provider.getName(), provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version 1 HomeFolderProvider with the given name.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public HomeFolderProvider getHomeFolderProvider1(String providerName)
|
||||
{
|
||||
return v1Providers.get(providerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version 2 HomeFolderProvider2 with the given name.
|
||||
*/
|
||||
public HomeFolderProvider2 getHomeFolderProvider2(String providerName)
|
||||
{
|
||||
return v2Providers.get(providerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default home folder provider (user which none is specified or when one is not found)
|
||||
* @param defaultProvider
|
||||
*/
|
||||
public void setDefaultProvider(HomeFolderProvider defaultProvider)
|
||||
public void setDefaultProvider(HomeFolderProvider2 defaultProvider)
|
||||
{
|
||||
this.defaultProvider = defaultProvider;
|
||||
}
|
||||
@@ -123,22 +196,302 @@ public class HomeFolderManager implements NodeServicePolicies.OnCreateNodePolicy
|
||||
/**
|
||||
* Find the provider and call.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void makeHomeFolder(ChildAssociationRef childAssocRef)
|
||||
{
|
||||
HomeFolderProvider provider = defaultProvider;
|
||||
String providerName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(childAssocRef
|
||||
HomeFolderProvider2 v2Provider = defaultProvider;
|
||||
HomeFolderProvider v1Provider = null;
|
||||
String providerName = DefaultTypeConverter.INSTANCE.convert(
|
||||
String.class, nodeService.getProperty(childAssocRef
|
||||
.getChildRef(), ContentModel.PROP_HOME_FOLDER_PROVIDER));
|
||||
if (providerName != null)
|
||||
{
|
||||
provider = providers.get(providerName);
|
||||
if (provider == null)
|
||||
v2Provider = getHomeFolderProvider2(providerName);
|
||||
if (v2Provider == null)
|
||||
{
|
||||
provider = defaultProvider;
|
||||
v1Provider = getHomeFolderProvider1(providerName);
|
||||
if (v1Provider == null)
|
||||
{
|
||||
v2Provider = defaultProvider;
|
||||
}
|
||||
}
|
||||
if (provider != null)
|
||||
}
|
||||
else
|
||||
{
|
||||
provider.onCreateNode(childAssocRef);
|
||||
providerName = defaultProvider.getName();
|
||||
nodeService.setProperty(childAssocRef.getChildRef(),
|
||||
ContentModel.PROP_HOME_FOLDER_PROVIDER, providerName);
|
||||
}
|
||||
if (v2Provider != null)
|
||||
{
|
||||
// If a V2Adaptor we still must call onCreateNode just like a
|
||||
// v1 HomeFolderProvider in case it has been overridden
|
||||
if (v2Provider instanceof AbstractHomeFolderProvider.V2Adaptor)
|
||||
{
|
||||
((AbstractHomeFolderProvider.V2Adaptor)v2Provider).onCreateNode(childAssocRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
homeFolderCreateAndSetPermissions(v2Provider, childAssocRef.getChildRef());
|
||||
}
|
||||
}
|
||||
else if (v1Provider != null)
|
||||
{
|
||||
v1Provider.onCreateNode(childAssocRef);
|
||||
}
|
||||
}
|
||||
|
||||
void homeFolderCreateAndSetPermissions(HomeFolderProvider2 provider, NodeRef personNodeRef)
|
||||
{
|
||||
AuthenticationUtil.RunAsWork<NodeRef> action =
|
||||
new RunAsCreateAndSetPermissions(provider, personNodeRef);
|
||||
AuthenticationUtil.runAs(action, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to encapsulate the creation and setting permissions etc
|
||||
*/
|
||||
private class RunAsCreateAndSetPermissions implements AuthenticationUtil.RunAsWork<NodeRef>
|
||||
{
|
||||
NodeRef personNodeRef;
|
||||
HomeFolderProvider2 provider;
|
||||
|
||||
RunAsCreateAndSetPermissions(HomeFolderProvider2 provider, NodeRef personNodeRef)
|
||||
{
|
||||
this.personNodeRef = personNodeRef;
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public NodeRef doWork() throws Exception
|
||||
{
|
||||
// Get home folder
|
||||
HomeSpaceNodeRef homeFolder = provider.getHomeFolder(personNodeRef);
|
||||
|
||||
// If it exists
|
||||
if (homeFolder.getNodeRef() != null)
|
||||
{
|
||||
// Get uid and keep
|
||||
String uid = DefaultTypeConverter.INSTANCE.convert(String.class,
|
||||
serviceRegistry.getNodeService().getProperty(
|
||||
personNodeRef, ContentModel.PROP_USERNAME));
|
||||
|
||||
// If created or found then set (other wise it was already set correctly)
|
||||
if (homeFolder.getStatus() != HomeSpaceNodeRef.Status.VALID)
|
||||
{
|
||||
serviceRegistry.getNodeService().setProperty(
|
||||
personNodeRef, ContentModel.PROP_HOMEFOLDER, homeFolder.getNodeRef());
|
||||
}
|
||||
|
||||
final String providerSuppliedOwner = provider.getOwner();
|
||||
String owner = (providerSuppliedOwner == null) ? uid : providerSuppliedOwner;
|
||||
// If created..
|
||||
if (homeFolder.getStatus() == HomeSpaceNodeRef.Status.CREATED)
|
||||
{
|
||||
PermissionsManager onCreatePermissionsManager =
|
||||
provider.getOnCreatePermissionsManager();
|
||||
if (onCreatePermissionsManager != null)
|
||||
{
|
||||
onCreatePermissionsManager.setPermissions(
|
||||
homeFolder.getNodeRef(), owner, uid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PermissionsManager onReferencePermissionsManager =
|
||||
provider.getOnReferencePermissionsManager();
|
||||
if (onReferencePermissionsManager != null)
|
||||
{
|
||||
onReferencePermissionsManager.setPermissions(
|
||||
homeFolder.getNodeRef(), owner, uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
return homeFolder.getNodeRef();
|
||||
}
|
||||
}
|
||||
|
||||
private StoreRef getStoreRef(HomeFolderProvider2 provider)
|
||||
{
|
||||
// Could check to see if provider is a V2Adaptor to avoid
|
||||
// object creation, but there is little point.
|
||||
return new StoreRef(provider.getStoreUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for {@link HomeFolderProvider2.getHomeFolder} (so that it
|
||||
* does not need its own NodeService) that returns a person property value.
|
||||
*/
|
||||
public String getPersonProperty(NodeRef person, QName name)
|
||||
{
|
||||
String value = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(person, name));
|
||||
|
||||
if(value == null || value.length() == 0)
|
||||
{
|
||||
throw new PersonException("Can not create a home folder when the "+name+" property is null or empty");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void clearCaches(HomeFolderProvider2 provider)
|
||||
{
|
||||
getRootPathNodeRefMap(provider).clear();
|
||||
}
|
||||
|
||||
NodeRef getRootPathNodeRef(HomeFolderProvider2 provider)
|
||||
{
|
||||
String rootPath = provider.getRootPath();
|
||||
String tenantDomain = (tenantService != null ? tenantService.getCurrentUserDomain() : TenantService.DEFAULT_DOMAIN);
|
||||
Map<String, NodeRef> rootPathNodeRefMap = getRootPathNodeRefMap(provider);
|
||||
NodeRef rootPathNodeRef = rootPathNodeRefMap.get(tenantDomain);
|
||||
if (rootPathNodeRef == null)
|
||||
{
|
||||
// ok with race condition for initial construction
|
||||
rootPathNodeRef = resolvePath(provider, rootPath);
|
||||
rootPathNodeRefMap.put(tenantDomain, rootPathNodeRef);
|
||||
}
|
||||
return rootPathNodeRef;
|
||||
}
|
||||
|
||||
private Map<String, NodeRef> getRootPathNodeRefMap(HomeFolderProvider2 provider)
|
||||
{
|
||||
String name = provider.getName();
|
||||
Map<String, NodeRef> rootPathNodeRefMap = rootPathNodeRefMaps.get(name);
|
||||
if (rootPathNodeRefMap == null)
|
||||
{
|
||||
// ok with race condition for initial construction
|
||||
rootPathNodeRefMap = new ConcurrentHashMap<String, NodeRef>();
|
||||
rootPathNodeRefMaps.put(name, rootPathNodeRefMap);
|
||||
}
|
||||
return rootPathNodeRefMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to resolve paths to nodes.
|
||||
*/
|
||||
NodeRef resolvePath(HomeFolderProvider2 provider, String pathToResolve)
|
||||
{
|
||||
List<NodeRef> refs = serviceRegistry.getSearchService().selectNodes(
|
||||
serviceRegistry.getNodeService().getRootNode(getStoreRef(provider)),
|
||||
pathToResolve, null,
|
||||
serviceRegistry.getNamespaceService(), false);
|
||||
if (refs.size() != 1)
|
||||
{
|
||||
throw new IllegalStateException("Non-unique path: found : " +
|
||||
pathToResolve + " " + refs.size());
|
||||
}
|
||||
return refs.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for {@link HomeFolderProvider2.getHomeFolder(NodeRef)}
|
||||
* implementations to return a {@link HomeSpaceNodeRef}
|
||||
* @param referenceRootNode indicates that a reference to the root node
|
||||
* should be returned if the home folder property on the person
|
||||
* has not yet been set.
|
||||
*/
|
||||
public HomeSpaceNodeRef getHomeFolder(HomeFolderProvider2 provider, NodeRef person, boolean referenceRootNode)
|
||||
{
|
||||
HomeSpaceNodeRef homeSpaceNodeRef = null;
|
||||
NodeRef existingHomeFolder = DefaultTypeConverter.INSTANCE.convert(
|
||||
NodeRef.class, serviceRegistry.getNodeService().getProperty(
|
||||
person, ContentModel.PROP_HOMEFOLDER));
|
||||
if (existingHomeFolder != null)
|
||||
{
|
||||
homeSpaceNodeRef = new HomeSpaceNodeRef(existingHomeFolder,
|
||||
HomeSpaceNodeRef.Status.VALID);
|
||||
}
|
||||
else if (referenceRootNode)
|
||||
{
|
||||
homeSpaceNodeRef = new HomeSpaceNodeRef(getRootPathNodeRef(provider),
|
||||
HomeSpaceNodeRef.Status.REFERENCED);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileFolderService fileFolderService = serviceRegistry.getFileFolderService();
|
||||
List<String> homeFolderPath = provider.getHomeFolderPath(person);
|
||||
|
||||
FileInfo fileInfo;
|
||||
|
||||
// Test if it already exists
|
||||
NodeRef existing = getExisting(provider, fileFolderService, homeFolderPath);
|
||||
if (existing != null)
|
||||
{
|
||||
fileInfo = fileFolderService.getFileInfo(existing);
|
||||
}
|
||||
else
|
||||
{
|
||||
fileInfo = createTree(provider, getRootPathNodeRef(provider), homeFolderPath,
|
||||
provider.getTemplateNodeRef(), fileFolderService);
|
||||
}
|
||||
NodeRef homeFolderNodeRef = fileInfo.getNodeRef();
|
||||
return new HomeSpaceNodeRef(homeFolderNodeRef, HomeSpaceNodeRef.Status.CREATED);
|
||||
}
|
||||
return homeSpaceNodeRef;
|
||||
}
|
||||
|
||||
private NodeRef getExisting(HomeFolderProvider2 provider, FileFolderService fileFolderService,
|
||||
List<String> homeFolderPath)
|
||||
{
|
||||
NodeRef existing;
|
||||
try
|
||||
{
|
||||
FileInfo existingFileInfo = fileFolderService.resolveNamePath(getRootPathNodeRef(provider), homeFolderPath);
|
||||
existing = existingFileInfo.getNodeRef();
|
||||
}
|
||||
catch (FileNotFoundException fnfe)
|
||||
{
|
||||
existing = null;// home folder noderef doesn't exist yet
|
||||
}
|
||||
return existing;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a tree of folder nodes based on the path elements provided.
|
||||
*/
|
||||
private FileInfo createTree(HomeFolderProvider2 provider, NodeRef root,
|
||||
List<String> homeFolderPath, NodeRef templateNodeRef,
|
||||
FileFolderService fileFolderService)
|
||||
{
|
||||
NodeRef newParent = createNewParentIfRequired(root, homeFolderPath, fileFolderService);
|
||||
String homeFolderName = homeFolderPath.get(homeFolderPath.size()-1);
|
||||
FileInfo fileInfo;
|
||||
if (templateNodeRef == null)
|
||||
{
|
||||
fileInfo = fileFolderService.create(
|
||||
newParent,
|
||||
homeFolderName,
|
||||
ContentModel.TYPE_FOLDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
fileInfo = fileFolderService.copy(
|
||||
templateNodeRef,
|
||||
newParent,
|
||||
homeFolderName);
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
throw new PersonException("Invalid template to create home space");
|
||||
}
|
||||
}
|
||||
return fileInfo;
|
||||
}
|
||||
|
||||
private NodeRef createNewParentIfRequired(NodeRef root,
|
||||
List<String> homeFolderPath, FileFolderService fileFolderService)
|
||||
{
|
||||
if (homeFolderPath.size() > 1)
|
||||
{
|
||||
List<String> parentPath = new ArrayList<String>(homeFolderPath);
|
||||
parentPath.remove(parentPath.size()-1);
|
||||
return FileFolderUtil.makeFolders(fileFolderService, root,
|
||||
parentPath, ContentModel.TYPE_FOLDER).getNodeRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -23,6 +23,9 @@ import org.alfresco.repo.node.NodeServicePolicies;
|
||||
/**
|
||||
* Interface for home folder providers.
|
||||
*
|
||||
* @deprecated
|
||||
* Depreciated since 4.0. {@link HomeFolderProvider2} should now be used.
|
||||
*
|
||||
* @author Andy Hind
|
||||
*/
|
||||
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
|
||||
*
|
||||
@@ -18,19 +18,18 @@
|
||||
*/
|
||||
package org.alfresco.repo.security.person;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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.NodeService;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
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
|
||||
*/
|
||||
@@ -40,86 +39,30 @@ public class UIDBasedHomeFolderProvider extends ExistingPathBasedHomeFolderProvi
|
||||
|
||||
private NodeRef templateNodeRef;
|
||||
|
||||
public UIDBasedHomeFolderProvider()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public void setTemplatePath(String 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()
|
||||
{
|
||||
if (templateNodeRef == null)
|
||||
if (templateNodeRef == null && templatePath != null)
|
||||
{
|
||||
templateNodeRef = resolvePath(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;
|
||||
}
|
||||
|
||||
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("#{"))
|
||||
{
|
||||
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)
|
||||
{
|
||||
throw new WorkflowException("actor expression '" + actorValStr + "' evaluates to null");
|
||||
@@ -128,7 +128,7 @@ public class AlfrescoAssignment extends JBPMSpringAssignmentHandler
|
||||
if (pooledactorValStr.startsWith("#{"))
|
||||
{
|
||||
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)
|
||||
{
|
||||
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.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
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.RunAsWork;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
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.workflow.WorkflowException;
|
||||
import org.dom4j.Element;
|
||||
@@ -65,16 +66,19 @@ public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
||||
|
||||
private static JpdlXmlReader jpdlReader = new JpdlXmlReader((InputSource)null);
|
||||
private ServiceRegistry services;
|
||||
private NodeRef companyHome;
|
||||
private Element script;
|
||||
private String runas;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler#initialiseHandler(org.springframework.beans.factory.BeanFactory)
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
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)
|
||||
@@ -122,7 +126,7 @@ public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
||||
String user = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
if (runas == null && user !=null)
|
||||
{
|
||||
return executeScript(executionContext, services, expression, variableAccesses);
|
||||
return executeScript(executionContext, services, expression, variableAccesses, companyHome);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -134,21 +138,20 @@ public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
||||
{
|
||||
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 ExecutionContext executionContext,
|
||||
final ServiceRegistry services,
|
||||
final List<VariableAccess> variableAccesses) {
|
||||
// execute as specified runAsUser
|
||||
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
|
||||
{
|
||||
public Object doWork() throws Exception
|
||||
{
|
||||
return executeScript(executionContext, services, expression, variableAccesses);
|
||||
return executeScript(executionContext, services, expression, variableAccesses,companyHome);
|
||||
}
|
||||
}, runAsUser);
|
||||
}
|
||||
@@ -252,11 +255,12 @@ public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
||||
* @param services Alfresco service registry
|
||||
* @param expression script to execute
|
||||
* @param variableAccesses (optional) list of jBPM variables to map into script (all, if not supplied)
|
||||
* @param companyHome TODO
|
||||
* @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.buildCoreModel(inputMap);
|
||||
Object result = scriptService.executeScriptString(expression, inputMap);
|
||||
@@ -329,26 +333,25 @@ public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
||||
* Construct map of arguments to pass to script
|
||||
*
|
||||
* Based on the <variable> elements of the action configuration.
|
||||
*
|
||||
* @param companyHome TODO
|
||||
* @param executionContext the execution context
|
||||
* @param variableAccesses the variable configuration
|
||||
*
|
||||
* @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
|
||||
JBPMNode personNode = getPersonNode(executionContext, services);
|
||||
if (personNode != null)
|
||||
NodeRef person = getPersonNode(services);
|
||||
NodeRef userHome = null;
|
||||
if (person != null)
|
||||
{
|
||||
inputMap.put("person", personNode );
|
||||
NodeRef homeSpace = (NodeRef)services.getNodeService().getProperty(personNode.getNodeRef(), ContentModel.PROP_HOMEFOLDER);
|
||||
if (homeSpace != null)
|
||||
{
|
||||
inputMap.put("userhome", new JBPMNode(homeSpace, services));
|
||||
}
|
||||
NodeService nodeService = services.getNodeService();
|
||||
userHome = (NodeRef)nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER);
|
||||
}
|
||||
Map<String, Object> inputMap = scriptService.buildDefaultModel(person, companyHome, userHome, null, null, null);
|
||||
|
||||
// initialise process variables
|
||||
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();
|
||||
if(userName != null)
|
||||
{
|
||||
NodeRef person = services.getPersonService().getPerson(userName);
|
||||
if(person !=null)
|
||||
{
|
||||
return new JBPMNode(person, services);
|
||||
}
|
||||
return person;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@@ -1,12 +1,16 @@
|
||||
package org.alfresco.repo.workflow.jbpm;
|
||||
|
||||
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.when;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.jscript.ScriptNode;
|
||||
import org.alfresco.repo.model.Repository;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
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.Token;
|
||||
import org.jbpm.taskmgmt.exe.TaskInstance;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
public class AlfrescoJavaScriptIntegrationTest extends BaseAlfrescoSpringTest
|
||||
{
|
||||
@@ -193,6 +199,39 @@ public class AlfrescoJavaScriptIntegrationTest extends BaseAlfrescoSpringTest
|
||||
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) {
|
||||
Element script = DocumentHelper.createElement("script");
|
||||
script.setText(expression);
|
||||
@@ -203,7 +242,8 @@ public class AlfrescoJavaScriptIntegrationTest extends BaseAlfrescoSpringTest
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void onSetUp() throws Exception {
|
||||
super.onSetUp();
|
||||
services = (ServiceRegistry) applicationContext.getBean("ServiceRegistry");
|
||||
|
||||
this.services = (ServiceRegistry) applicationContext.getBean("ServiceRegistry");
|
||||
repository = (Repository) applicationContext.getBean("repositoryHelper");
|
||||
personService = services.getPersonService();
|
||||
createUser(BASIC_USER);
|
||||
@@ -214,7 +254,25 @@ public class AlfrescoJavaScriptIntegrationTest extends BaseAlfrescoSpringTest
|
||||
when(context.getContextInstance()).thenReturn(contextInstance);
|
||||
variables = new HashMap<String, Object>();
|
||||
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)
|
||||
@@ -236,9 +294,9 @@ public class AlfrescoJavaScriptIntegrationTest extends BaseAlfrescoSpringTest
|
||||
public static class TestUserStore {
|
||||
private String runAsUser;
|
||||
private String fullUser;
|
||||
private JBPMNode person = null;
|
||||
private ScriptNode person = null;
|
||||
|
||||
public void storeUsers(JBPMNode user)
|
||||
public void storeUsers(ScriptNode user)
|
||||
{
|
||||
fullUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
runAsUser = AuthenticationUtil.getRunAsUser();
|
||||
|
@@ -148,7 +148,7 @@ public class ForEachFork extends JBPMSpringActionHandler
|
||||
private Collection<?> evaluateForEachExpression(final ExecutionContext executionContext, String forEachText)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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();
|
||||
|
||||
suite.addTestSuite(WCMAspectTest.class);
|
||||
suite.addTestSuite(WebProjectServiceImplTest.class);
|
||||
suite.addTestSuite(AssetServiceImplTest.class);
|
||||
suite.addTestSuite(SandboxServiceImplTest.class);
|
||||
|
Reference in New Issue
Block a user