RM permission inheritance behaviour clarified

* read permissions not inherited to root categories, holds or items in the root of the unfiled record container .. this matches 
   the current behaviour of the file plan and is a partial work around for the issue of inheriting "path" read permissions vs actual read permissions.
 * consolidation of permission initialisation code (there is only one route now)
 * resolved RM-1317
 * unit tests
 * update server integration tests
 * knock on minor simplifications on the file plan and transfer service 
 * moved more frequently used methods into the service base to reduce unessesary service interlinking



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@67030 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2014-04-09 06:59:44 +00:00
parent 5f3802fa27
commit b8aa355a00
10 changed files with 505 additions and 247 deletions

View File

@@ -424,11 +424,8 @@
<bean id="filePlanService" <bean id="filePlanService"
parent="baseService" parent="baseService"
class="org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanServiceImpl"> class="org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanServiceImpl">
<!-- NOTE: for some reason we need to grab these references within the class to avoid cyclic Spring issues! --> <property name="nodeDAO" ref="nodeDAO"/>
<!-- <property name="permissionService" ref="permissionService"/> --> <property name="filePlanPermissionService" ref="FilePlanPermissionService" />
<!-- <property name="nodeDAO" ref="nodeDAO"/> -->
<!-- <property name="internalNodeService" ref="nodeService"/> -->
<!-- <property name="siteService" ref="SiteService" /> -->
</bean> </bean>
<bean id="FilePlanService" class="org.springframework.aop.framework.ProxyFactoryBean"> <bean id="FilePlanService" class="org.springframework.aop.framework.ProxyFactoryBean">
@@ -489,6 +486,7 @@
init-method="init"> init-method="init">
<property name="permissionService" ref="PermissionService"/> <property name="permissionService" ref="PermissionService"/>
<property name="policyComponent" ref="policyComponent"/> <property name="policyComponent" ref="policyComponent"/>
<property name="ownableService" ref="ownableService" />
</bean> </bean>
<bean id="FilePlanPermissionService" class="org.springframework.aop.framework.ProxyFactoryBean"> <bean id="FilePlanPermissionService" class="org.springframework.aop.framework.ProxyFactoryBean">
@@ -532,6 +530,7 @@
<value> <value>
<![CDATA[ <![CDATA[
org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService.setupRecordCategoryPermissions=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService.setupRecordCategoryPermissions=RM_ALLOW
org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService.setupPermissions=RM_ALLOW
org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService.setPermission=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService.setPermission=RM_ALLOW
org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService.deletePermission=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService.deletePermission=RM_ALLOW
org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService.*=RM_DENY org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService.*=RM_DENY

View File

@@ -29,18 +29,12 @@ import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService;
import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.transfer.TransferService;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl; import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
@@ -77,156 +71,34 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
/** RM site file plan container */ /** RM site file plan container */
private static final String FILE_PLAN_CONTAINER = "documentLibrary"; private static final String FILE_PLAN_CONTAINER = "documentLibrary";
/** node DAO */
private NodeDAO nodeDAO;
/** file plan permission service */
private FilePlanPermissionService filePlanPermissionService;
/** /**
* NOTE: for some reason spring couldn't cope with the circular references between these two * @param nodeDAO node DAO
* beans so we need to grab this one manually.
*
* @return file plan role service
*/ */
protected FilePlanRoleService getFilePlanRoleService() public void setNodeDAO(NodeDAO nodeDAO)
{ {
return (FilePlanRoleService)applicationContext.getBean("FilePlanRoleService"); this.nodeDAO = nodeDAO;
} }
/** /**
* @return permission service * @return site service
*/
protected PermissionService getPermissionService()
{
return (PermissionService)applicationContext.getBean("permissionService");
}
/**
* @return node DAO
*/
protected NodeDAO getNodeDAO()
{
return (NodeDAO)applicationContext.getBean("nodeDAO");
}
/**
* @return site service
*/ */
protected SiteService getSiteService() protected SiteService getSiteService()
{ {
return (SiteService)applicationContext.getBean("SiteService"); return (SiteService)applicationContext.getBean("siteService");
} }
/** /**
* @return record folder service * @param filePlanPermissionService file plan permission service
*/ */
protected RecordFolderService getRecordFolderService() public void setFilePlanPermissionService(FilePlanPermissionService filePlanPermissionService)
{ {
return (RecordFolderService)applicationContext.getBean("RecordFolderService"); this.filePlanPermissionService = filePlanPermissionService;
}
/**
* @return transfer service
*/
protected TransferService getTransferService()
{
return (TransferService)applicationContext.getBean("RmTransferService");
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#getFilePlanComponentKind(org.alfresco.service.cmr.repository.NodeRef)
*/
public FilePlanComponentKind getFilePlanComponentKind(NodeRef nodeRef)
{
FilePlanComponentKind result = null;
if (isFilePlanComponent(nodeRef))
{
result = FilePlanComponentKind.FILE_PLAN_COMPONENT;
if (isFilePlan(nodeRef))
{
result = FilePlanComponentKind.FILE_PLAN;
}
else if (isRecordCategory(nodeRef))
{
result = FilePlanComponentKind.RECORD_CATEGORY;
}
else if (getRecordFolderService().isRecordFolder(nodeRef))
{
result = FilePlanComponentKind.RECORD_FOLDER;
}
else if (isRecord(nodeRef))
{
result = FilePlanComponentKind.RECORD;
}
else if (instanceOf(nodeRef, TYPE_HOLD_CONTAINER))
{
result = FilePlanComponentKind.HOLD_CONTAINER;
}
else if (isHold(nodeRef))
{
result = FilePlanComponentKind.HOLD;
}
else if (getTransferService().isTransfer(nodeRef))
{
result = FilePlanComponentKind.TRANSFER;
}
else if (instanceOf(nodeRef, TYPE_DISPOSITION_SCHEDULE) || instanceOf(nodeRef, TYPE_DISPOSITION_ACTION_DEFINITION))
{
result = FilePlanComponentKind.DISPOSITION_SCHEDULE;
}
else if (instanceOf(nodeRef, TYPE_UNFILED_RECORD_CONTAINER))
{
result = FilePlanComponentKind.UNFILED_RECORD_CONTAINER;
}
else if (instanceOf(nodeRef, TYPE_UNFILED_RECORD_FOLDER))
{
result = FilePlanComponentKind.UNFILED_RECORD_FOLDER;
}
}
return result;
}
/**
* @see FilePlanService#getFilePlanComponentKindFromType(QName)
*/
@Override
public FilePlanComponentKind getFilePlanComponentKindFromType(QName type)
{
FilePlanComponentKind result = null;
if (ASPECT_FILE_PLAN_COMPONENT.equals(type))
{
result = FilePlanComponentKind.FILE_PLAN_COMPONENT;
}
else if (dictionaryService.isSubClass(type, ASPECT_RECORD))
{
result = FilePlanComponentKind.RECORD;
}
else if (dictionaryService.isSubClass(type, TYPE_FILE_PLAN))
{
result = FilePlanComponentKind.FILE_PLAN;
}
else if (dictionaryService.isSubClass(type, TYPE_RECORD_CATEGORY))
{
result = FilePlanComponentKind.RECORD_CATEGORY;
}
else if (dictionaryService.isSubClass(type, TYPE_RECORD_FOLDER))
{
result = FilePlanComponentKind.RECORD_FOLDER;
}
else if (dictionaryService.isSubClass(type, TYPE_HOLD))
{
result = FilePlanComponentKind.HOLD;
}
else if (dictionaryService.isSubClass(type, TYPE_TRANSFER))
{
result = FilePlanComponentKind.TRANSFER;
}
else if (dictionaryService.isSubClass(type, TYPE_DISPOSITION_SCHEDULE) ||
dictionaryService.isSubClass(type, TYPE_DISPOSITION_ACTION_DEFINITION))
{
result = FilePlanComponentKind.DISPOSITION_SCHEDULE;
}
return result;
} }
/** /**
@@ -249,7 +121,7 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
final Set<NodeRef> results = new HashSet<NodeRef>(); final Set<NodeRef> results = new HashSet<NodeRef>();
Set<QName> aspects = new HashSet<QName>(1); Set<QName> aspects = new HashSet<QName>(1);
aspects.add(ASPECT_RECORDS_MANAGEMENT_ROOT); aspects.add(ASPECT_RECORDS_MANAGEMENT_ROOT);
getNodeDAO().getNodesWithAspects(aspects, Long.MIN_VALUE, Long.MAX_VALUE, new NodeDAO.NodeRefQueryCallback() nodeDAO.getNodesWithAspects(aspects, Long.MIN_VALUE, Long.MAX_VALUE, new NodeDAO.NodeRefQueryCallback()
{ {
@Override @Override
public boolean handle(Pair<Long, NodeRef> nodePair) public boolean handle(Pair<Long, NodeRef> nodePair)
@@ -273,13 +145,14 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
public NodeRef getFilePlanBySiteId(String siteId) public NodeRef getFilePlanBySiteId(String siteId)
{ {
NodeRef filePlan = null; NodeRef filePlan = null;
SiteService siteService = getSiteService();
SiteInfo siteInfo = getSiteService().getSite(siteId); SiteInfo siteInfo = siteService.getSite(siteId);
if (siteInfo != null) if (siteInfo != null)
{ {
if (getSiteService().hasContainer(siteId, FILE_PLAN_CONTAINER)) if (siteService.hasContainer(siteId, FILE_PLAN_CONTAINER))
{ {
NodeRef nodeRef = getSiteService().getContainer(siteId, FILE_PLAN_CONTAINER); NodeRef nodeRef = siteService.getContainer(siteId, FILE_PLAN_CONTAINER);
if (instanceOf(nodeRef, TYPE_FILE_PLAN)) if (instanceOf(nodeRef, TYPE_FILE_PLAN))
{ {
filePlan = nodeRef; filePlan = nodeRef;
@@ -398,8 +271,6 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
throw new AlfrescoRuntimeException("Unable to create file plan root container, because passed node is not a file plan."); throw new AlfrescoRuntimeException("Unable to create file plan root container, because passed node is not a file plan.");
} }
String allRoles = getFilePlanRoleService().getAllRolesContainerGroup(filePlan);
// create the properties map // create the properties map
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(1); Map<QName, Serializable> properties = new HashMap<QName, Serializable>(1);
properties.put(ContentModel.PROP_NAME, containerName); properties.put(ContentModel.PROP_NAME, containerName);
@@ -412,18 +283,8 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
containerType, containerType,
properties).getChildRef(); properties).getChildRef();
// set inheritance to false // setup the permissions
getPermissionService().setInheritParentPermissions(container, false); filePlanPermissionService.setupPermissions(filePlan, container);
// give all roles read permissions on the container by default
getPermissionService().setPermission(container, allRoles, RMPermissionModel.READ_RECORDS, true);
// setup the extended reader permissions
getPermissionService().setPermission(container, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
getPermissionService().setPermission(container, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true);
// setup the administrator permissions
getPermissionService().setPermission(container, "Administrator", RMPermissionModel.FILING, true);
return container; return container;
} }

View File

@@ -34,6 +34,14 @@ public interface FilePlanPermissionService
*/ */
void setupRecordCategoryPermissions(NodeRef recordCategory); void setupRecordCategoryPermissions(NodeRef recordCategory);
/**
* Setup permissions for an object within a given parent.
*
* @param parent parent node to inherit permissions from
* @param nodeRef node ref to setup permissions on
*/
void setupPermissions(NodeRef parent, NodeRef nodeRef);
/** /**
* Sets a permission on a file plan object. Assumes allow is true. Cascades permission down to record folder. * Sets a permission on a file plan object. Assumes allow is true. Cascades permission down to record folder.
* Cascades ReadRecord up to file plan. * Cascades ReadRecord up to file plan.

View File

@@ -25,6 +25,7 @@ import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanComponentKind;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl; import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
@@ -38,6 +39,7 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
@@ -58,6 +60,9 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
/** Permission service */ /** Permission service */
protected PermissionService permissionService; protected PermissionService permissionService;
/** Ownable service */
protected OwnableService ownableService;
/** Policy component */ /** Policy component */
protected PolicyComponent policyComponent; protected PolicyComponent policyComponent;
@@ -95,6 +100,14 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
this.policyComponent = policyComponent; this.policyComponent = policyComponent;
} }
/**
* @param ownableService ownable service
*/
public void setOwnableService(OwnableService ownableService)
{
this.ownableService = ownableService;
}
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService#setupRecordCategoryPermissions(org.alfresco.service.cmr.repository.NodeRef) * @see org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService#setupRecordCategoryPermissions(org.alfresco.service.cmr.repository.NodeRef)
*/ */
@@ -109,44 +122,9 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
throw new AlfrescoRuntimeException("Unable to setup record category permissions, because node is not a record category."); throw new AlfrescoRuntimeException("Unable to setup record category permissions, because node is not a record category.");
} }
// init permissions // setup category permissions
initPermissions(recordCategory); NodeRef parentNodeRef = nodeService.getPrimaryParent(recordCategory).getParentRef();
setupPermissions(parentNodeRef, recordCategory);
// Pull any permissions found on the parent (ie the record category)
final NodeRef parentNodeRef = nodeService.getPrimaryParent(recordCategory).getParentRef();
if (parentNodeRef != null && nodeService.exists(parentNodeRef))
{
AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork()
{
boolean fillingOnly = isFilePlan(parentNodeRef);
// since this is not a root category, inherit from parent
Set<AccessPermission> perms = permissionService.getAllSetPermissions(parentNodeRef);
for (AccessPermission perm : perms)
{
if (!fillingOnly ||
RMPermissionModel.FILING.equals(perm.getPermission()))
{
AccessStatus accessStatus = perm.getAccessStatus();
boolean allow = false;
if (AccessStatus.ALLOWED.equals(accessStatus))
{
allow = true;
}
permissionService.setPermission(
recordCategory,
perm.getAuthority(),
perm.getPermission(),
allow);
}
}
return null;
}
});
}
} }
/** /**
@@ -225,6 +203,9 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
*/ */
public void setupPermissions(final NodeRef parent, final NodeRef nodeRef) public void setupPermissions(final NodeRef parent, final NodeRef nodeRef)
{ {
ParameterCheck.mandatory("parent", parent);
ParameterCheck.mandatory("nodeRef", nodeRef);
if (nodeService.exists(nodeRef)) if (nodeService.exists(nodeRef))
{ {
// initialise permissions // initialise permissions
@@ -232,7 +213,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
if (nodeService.exists(parent)) if (nodeService.exists(parent))
{ {
AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Object>() runAsSystem(new AuthenticationUtil.RunAsWork<Object>()
{ {
public Object doWork() public Object doWork()
{ {
@@ -240,20 +221,29 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
Set<AccessPermission> perms = permissionService.getAllSetPermissions(parent); Set<AccessPermission> perms = permissionService.getAllSetPermissions(parent);
for (AccessPermission perm : perms) for (AccessPermission perm : perms)
{ {
if (!ExtendedReaderDynamicAuthority.EXTENDED_READER.equals(perm.getAuthority()) && // only copy filling permissions if the parent is the file plan
!ExtendedWriterDynamicAuthority.EXTENDED_WRITER.equals(perm.getAuthority())) if (!inheritFillingOnly(parent, nodeRef) ||
RMPermissionModel.FILING.equals(perm.getPermission()))
{ {
AccessStatus accessStatus = perm.getAccessStatus(); // don't copy the extended reader or writer permissions as they have already been set
boolean allow = false; if (!ExtendedReaderDynamicAuthority.EXTENDED_READER.equals(perm.getAuthority()) &&
if (AccessStatus.ALLOWED.equals(accessStatus)) !ExtendedWriterDynamicAuthority.EXTENDED_WRITER.equals(perm.getAuthority()))
{ {
allow = true; // get the access status details
AccessStatus accessStatus = perm.getAccessStatus();
boolean allow = false;
if (AccessStatus.ALLOWED.equals(accessStatus))
{
allow = true;
}
// set the permission on the target node
permissionService.setPermission(
nodeRef,
perm.getAuthority(),
perm.getPermission(),
allow);
} }
permissionService.setPermission(
nodeRef,
perm.getAuthority(),
perm.getPermission(),
allow);
} }
} }
@@ -264,6 +254,30 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
} }
} }
/**
* Helper method to determine whether all or just filling permissions should be inherited.
*
* @param parent parent node
* @param child child node
* @return boolean true if inherit filling only, false otherwise
*/
private boolean inheritFillingOnly(NodeRef parent, NodeRef child)
{
boolean result = false;
// if root category or
// if in root of unfiled container or
// if in root of hold container
if ((isFilePlan(parent) && isRecordCategory(child)) ||
FilePlanComponentKind.UNFILED_RECORD_CONTAINER.equals(getFilePlanComponentKind(parent)) ||
FilePlanComponentKind.HOLD_CONTAINER.equals(getFilePlanComponentKind(parent)))
{
result = true;
}
return result;
}
/** /**
* Sets ups records permission when aspect is added. * Sets ups records permission when aspect is added.
* *
@@ -274,7 +288,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
*/ */
public void onAddRecord(final NodeRef record, final QName aspectTypeQName) public void onAddRecord(final NodeRef record, final QName aspectTypeQName)
{ {
runAs(new AuthenticationUtil.RunAsWork<Object>() runAsSystem(new AuthenticationUtil.RunAsWork<Object>()
{ {
public Object doWork() public Object doWork()
{ {
@@ -286,7 +300,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
return null; return null;
} }
}, AuthenticationUtil.getSystemUserName()); });
} }
/** /**
@@ -343,7 +357,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
} }
/** /**
* Initiliase the permissions for the given node. * Init the permissions for the given node.
* *
* @param nodeRef node reference * @param nodeRef node reference
*/ */
@@ -351,20 +365,26 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
{ {
if (nodeService.exists(nodeRef)) if (nodeService.exists(nodeRef))
{ {
runAs(new AuthenticationUtil.RunAsWork<Object>() runAsSystem(new AuthenticationUtil.RunAsWork<Object>()
{ {
public Object doWork() public Object doWork()
{ {
// break inheritance // break inheritance
permissionService.setInheritParentPermissions(nodeRef, false); permissionService.setInheritParentPermissions(nodeRef, false);
// clear all existing permissions
permissionService.clearPermission(nodeRef, null);
// set extended reader permissions // set extended reader permissions
permissionService.setPermission(nodeRef, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true); permissionService.setPermission(nodeRef, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(nodeRef, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true); permissionService.setPermission(nodeRef, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true);
// remove owner
ownableService.setOwner(nodeRef, OwnableService.NO_OWNER);
return null; return null;
} }
}, AuthenticationUtil.getSystemUserName()); });
} }
} }
@@ -383,6 +403,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
{ {
if (isFilePlan(nodeRef)) if (isFilePlan(nodeRef))
{ {
// set the permission down the file plan hierarchy
setPermissionDown(nodeRef, authority, permission); setPermissionDown(nodeRef, authority, permission);
} }
else if (isFilePlanContainer(nodeRef) || else if (isFilePlanContainer(nodeRef) ||
@@ -390,7 +411,10 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
isRecord(nodeRef) || isRecord(nodeRef) ||
isHold(nodeRef)) isHold(nodeRef))
{ {
// set read permission to the parents of the node
setReadPermissionUp(nodeRef, authority); setReadPermissionUp(nodeRef, authority);
// set the permission on the node and it's children
setPermissionDown(nodeRef, authority, permission); setPermissionDown(nodeRef, authority, permission);
} }
else else

View File

@@ -53,7 +53,8 @@ import org.springframework.extensions.surf.util.ParameterCheck;
* @author Tuna Aksoy * @author Tuna Aksoy
* @since 2.2 * @since 2.2
*/ */
public class TransferServiceImpl extends ServiceBaseImpl implements TransferService, RecordsManagementModel public class TransferServiceImpl extends ServiceBaseImpl
implements TransferService, RecordsManagementModel
{ {
/** Transfer node reference key */ /** Transfer node reference key */
public static final String KEY_TRANSFER_NODEREF = "transferNodeRef"; public static final String KEY_TRANSFER_NODEREF = "transferNodeRef";
@@ -105,16 +106,6 @@ public class TransferServiceImpl extends ServiceBaseImpl implements TransferServ
this.recordFolderService = recordFolderService; this.recordFolderService = recordFolderService;
} }
/**
* @see org.alfresco.module.org_alfresco_module_rm.transfer.TransferService#isTransfer(NodeRef)
*/
@Override
public boolean isTransfer(NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
return instanceOf(nodeRef, TYPE_TRANSFER);
}
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.transfer.TransferService#transfer(NodeRef, boolean) * @see org.alfresco.module.org_alfresco_module_rm.transfer.TransferService#transfer(NodeRef, boolean)
*/ */

View File

@@ -20,6 +20,8 @@ package org.alfresco.module.org_alfresco_module_rm.util;
import java.util.Set; import java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanComponentKind;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService; import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
@@ -77,6 +79,110 @@ public class ServiceBaseImpl implements RecordsManagementModel, ApplicationConte
this.dictionaryService = dictionaryService; this.dictionaryService = dictionaryService;
} }
/**
* Gets the file plan component kind from the given node reference
*
* @see org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService#getFilePlanComponentKind(org.alfresco.service.cmr.repository.NodeRef)
*/
public FilePlanComponentKind getFilePlanComponentKind(NodeRef nodeRef)
{
FilePlanComponentKind result = null;
if (isFilePlanComponent(nodeRef))
{
result = FilePlanComponentKind.FILE_PLAN_COMPONENT;
if (isFilePlan(nodeRef))
{
result = FilePlanComponentKind.FILE_PLAN;
}
else if (isRecordCategory(nodeRef))
{
result = FilePlanComponentKind.RECORD_CATEGORY;
}
else if (isRecordFolder(nodeRef))
{
result = FilePlanComponentKind.RECORD_FOLDER;
}
else if (isRecord(nodeRef))
{
result = FilePlanComponentKind.RECORD;
}
else if (instanceOf(nodeRef, TYPE_HOLD_CONTAINER))
{
result = FilePlanComponentKind.HOLD_CONTAINER;
}
else if (isHold(nodeRef))
{
result = FilePlanComponentKind.HOLD;
}
else if (isTransfer(nodeRef))
{
result = FilePlanComponentKind.TRANSFER;
}
else if (instanceOf(nodeRef, TYPE_DISPOSITION_SCHEDULE) || instanceOf(nodeRef, TYPE_DISPOSITION_ACTION_DEFINITION))
{
result = FilePlanComponentKind.DISPOSITION_SCHEDULE;
}
else if (instanceOf(nodeRef, TYPE_UNFILED_RECORD_CONTAINER))
{
result = FilePlanComponentKind.UNFILED_RECORD_CONTAINER;
}
else if (instanceOf(nodeRef, TYPE_UNFILED_RECORD_FOLDER))
{
result = FilePlanComponentKind.UNFILED_RECORD_FOLDER;
}
}
return result;
}
/**
* Gets the file plan component kind from the given type.
*
* @see FilePlanService#getFilePlanComponentKindFromType(QName)
*/
public FilePlanComponentKind getFilePlanComponentKindFromType(QName type)
{
FilePlanComponentKind result = null;
if (ASPECT_FILE_PLAN_COMPONENT.equals(type))
{
result = FilePlanComponentKind.FILE_PLAN_COMPONENT;
}
else if (instanceOf(type, ASPECT_RECORD))
{
result = FilePlanComponentKind.RECORD;
}
else if (instanceOf(type, TYPE_FILE_PLAN))
{
result = FilePlanComponentKind.FILE_PLAN;
}
else if (instanceOf(type, TYPE_RECORD_CATEGORY))
{
result = FilePlanComponentKind.RECORD_CATEGORY;
}
else if (instanceOf(type, TYPE_RECORD_FOLDER))
{
result = FilePlanComponentKind.RECORD_FOLDER;
}
else if (instanceOf(type, TYPE_HOLD))
{
result = FilePlanComponentKind.HOLD;
}
else if (instanceOf(type, TYPE_TRANSFER))
{
result = FilePlanComponentKind.TRANSFER;
}
else if (instanceOf(type, TYPE_DISPOSITION_SCHEDULE) ||
instanceOf(type, TYPE_DISPOSITION_ACTION_DEFINITION))
{
result = FilePlanComponentKind.DISPOSITION_SCHEDULE;
}
return result;
}
/** /**
* Indicates whether the given node is a file plan component or not. * Indicates whether the given node is a file plan component or not.
* <p> * <p>
@@ -178,6 +284,18 @@ public class ServiceBaseImpl implements RecordsManagementModel, ApplicationConte
return isHold; return isHold;
} }
/**
* Indicates whether the given node reference is a transfer or not.
*
* @see org.alfresco.module.org_alfresco_module_rm.transfer.TransferService#isTransfer(NodeRef)
*/
public boolean isTransfer(NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
return instanceOf(nodeRef, TYPE_TRANSFER);
}
/** /**
* Gets the file plan that a given file plan component resides within. * Gets the file plan that a given file plan component resides within.
* *
@@ -242,6 +360,26 @@ public class ServiceBaseImpl implements RecordsManagementModel, ApplicationConte
return result; return result;
} }
/**
* Utility method to quickly determine whether one class is equal to or sub of another.
*
* @param className class name
* @param ofClassName class name to check against
* @return boolean true if equal to or sub, false otherwise
*/
protected boolean instanceOf(QName className, QName ofClassName)
{
ParameterCheck.mandatory("className", className);
ParameterCheck.mandatory("ofClassName", ofClassName);
boolean result = false;
if (ofClassName.equals(className) ||
dictionaryService.isSubClass(className, ofClassName))
{
result = true;
}
return result;
}
/** /**
* Utility method to get the next counter for a node. * Utility method to get the next counter for a node.
* <p> * <p>

View File

@@ -155,7 +155,7 @@ public class RM1008Test extends BaseRMTestCase
Capability viewRecords = capabilityService.getCapability("ViewRecords"); Capability viewRecords = capabilityService.getCapability("ViewRecords");
assertNotNull(viewRecords); assertNotNull(viewRecords);
assertEquals(AccessStatus.ALLOWED, viewRecords.hasPermission(hold)); assertEquals(AccessStatus.DENIED, viewRecords.hasPermission(hold));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(hold, RMPermissionModel.FILING)); assertEquals(AccessStatus.DENIED, permissionService.hasPermission(hold, RMPermissionModel.FILING));
return null; return null;
@@ -173,8 +173,6 @@ public class RM1008Test extends BaseRMTestCase
} }
}, rmAdminName); }, rmAdminName);
// FIXME: After fixing RM:1315 this should be fixed
/*
doTestInTransaction(new Test<Void>() doTestInTransaction(new Test<Void>()
{ {
@Override @Override
@@ -189,7 +187,6 @@ public class RM1008Test extends BaseRMTestCase
return null; return null;
} }
}, myUser); }, myUser);
*/
doTestInTransaction(new Test<Void>() doTestInTransaction(new Test<Void>()
{ {
@@ -210,7 +207,7 @@ public class RM1008Test extends BaseRMTestCase
Capability viewRecords = capabilityService.getCapability("ViewRecords"); Capability viewRecords = capabilityService.getCapability("ViewRecords");
assertNotNull(viewRecords); assertNotNull(viewRecords);
assertEquals(AccessStatus.ALLOWED, viewRecords.hasPermission(hold)); assertEquals(AccessStatus.DENIED, viewRecords.hasPermission(hold));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(hold, RMPermissionModel.FILING)); assertEquals(AccessStatus.DENIED, permissionService.hasPermission(hold, RMPermissionModel.FILING));
return null; return null;

View File

@@ -24,15 +24,24 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import java.util.HashSet;
import java.util.Set;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
import org.alfresco.repo.security.permissions.impl.AccessPermissionImpl;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.junit.Test; import org.junit.Test;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Spy; import org.mockito.Spy;
import org.mockito.verification.VerificationMode;
/** /**
* File plan permission service implementation unit test. * File plan permission service implementation unit test.
@@ -47,6 +56,13 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
{ {
/** test authority */ /** test authority */
protected static final String AUTHORITY = "anAuthority"; protected static final String AUTHORITY = "anAuthority";
protected static final String AUTHORITY2 = "anOtherAuthority";
/** fileplan nodes */
protected NodeRef rootRecordCategory;
protected NodeRef recordCategory;
protected NodeRef newRecordFolder;
protected NodeRef newRecord;
/** unfiled nodes */ /** unfiled nodes */
protected NodeRef unfiledRecordContainer; protected NodeRef unfiledRecordContainer;
@@ -81,20 +97,36 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
holdContainer = generateContainerNodeRef(TYPE_HOLD_CONTAINER); holdContainer = generateContainerNodeRef(TYPE_HOLD_CONTAINER);
hold = generateHoldNodeRef("my test hold"); hold = generateHoldNodeRef("my test hold");
heldRecord = generateRecord(); heldRecord = generateRecord();
rootRecordCategory = generateContainerNodeRef(TYPE_RECORD_CATEGORY);
recordCategory = generateContainerNodeRef(TYPE_RECORD_CATEGORY);
newRecordFolder = generateRecordFolder();
newRecord = generateRecord();
// setup parent hierarchy // setup parent hierarchy
makePrimaryParentOf(filePlan, generateNodeRef(ContentModel.TYPE_FOLDER)); makePrimaryParentOf(filePlan, generateNodeRef(ContentModel.TYPE_FOLDER));
makePrimaryParentOf(rootRecordCategory, filePlan);
makePrimaryParentOf(recordCategory, rootRecordCategory);
makePrimaryParentOf(newRecordFolder, recordCategory);
makePrimaryParentOf(newRecord, newRecordFolder);
makePrimaryParentOf(unfiledRecordFolder, unfiledRecordContainer); makePrimaryParentOf(unfiledRecordFolder, unfiledRecordContainer);
makePrimaryParentOf(unfiledRecordContainer, filePlan); makePrimaryParentOf(unfiledRecordContainer, filePlan);
makePrimaryParentOf(hold, holdContainer); makePrimaryParentOf(hold, holdContainer);
makePrimaryParentOf(holdContainer, filePlan); makePrimaryParentOf(holdContainer, filePlan);
// setup child hierarchy // setup child hierarchy
makeChildrenOf(filePlan, rootRecordCategory);
makeChildrenOf(rootRecordCategory, recordCategory);
makeChildrenOf(recordCategory, newRecordFolder);
makeChildrenOf(newRecordFolder, newRecord);
makeChildrenOf(unfiledRecordFolder, unfiledRecordFolderChild); makeChildrenOf(unfiledRecordFolder, unfiledRecordFolderChild);
makeChildrenOf(unfiledRecordFolderChild, unfiledRecord); makeChildrenOf(unfiledRecordFolderChild, unfiledRecord);
makeChildrenOf(holdContainer, hold);
makeChildrenOf(hold, heldRecord); makeChildrenOf(hold, heldRecord);
} }
@@ -179,6 +211,7 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
/** /**
* Set read permission on hold container * Set read permission on hold container
*/ */
@Test
public void setReadPermissionOnHoldContainer() public void setReadPermissionOnHoldContainer()
{ {
// set read permission on hold // set read permission on hold
@@ -201,6 +234,7 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
/** /**
* Set filing permission on hold container * Set filing permission on hold container
*/ */
@Test
public void setFilingPermissionOnHoldContainer() public void setFilingPermissionOnHoldContainer()
{ {
// set read permission on hold // set read permission on hold
@@ -260,4 +294,206 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
verify(mockedPermissionService, never()).setPermission(eq(heldRecord), eq(AUTHORITY), anyString(), eq(true)); verify(mockedPermissionService, never()).setPermission(eq(heldRecord), eq(AUTHORITY), anyString(), eq(true));
} }
/**
* Helper method to setup permissions on mock objects
*/
private void setupPermissions(NodeRef nodeRef)
{
Set<AccessPermission> perms = new HashSet<AccessPermission>(4);
// setup basic file and read for authorities
perms.add(new AccessPermissionImpl(RMPermissionModel.READ_RECORDS, AccessStatus.ALLOWED, AUTHORITY, 0));
perms.add(new AccessPermissionImpl(RMPermissionModel.FILING, AccessStatus.ALLOWED, AUTHORITY2, 1));
// setup in-place readers and writers
perms.add(new AccessPermissionImpl(RMPermissionModel.READ_RECORDS, AccessStatus.ALLOWED, ExtendedReaderDynamicAuthority.EXTENDED_READER, 2));
perms.add(new AccessPermissionImpl(RMPermissionModel.FILING, AccessStatus.ALLOWED, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, 3));
doReturn(perms).when(mockedPermissionService).getAllSetPermissions(nodeRef);
}
/**
* Helper to verify the core permissions have been initialized correctly
*/
private void verifyInitPermissions(NodeRef nodeRef)
{
verify(mockedPermissionService, times(1)).setInheritParentPermissions(nodeRef, false);
verify(mockedPermissionService, times(1)).clearPermission(nodeRef, null);
verify(mockedPermissionService, times(1)).setPermission(nodeRef, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService, times(1)).setPermission(nodeRef, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true);
verify(mockedOwnableService, times(1)).setOwner(nodeRef, OwnableService.NO_OWNER);
}
/**
* Helper to verify that permissions have been set correctly on the child
*
* @param parent parent node
* @param child child node
* @param read verification mode relating to setting read on the child
* @param filling verification mode relating to setting filling on the child
*/
private void verifyInitPermissions(NodeRef parent, NodeRef child, VerificationMode read, VerificationMode filling)
{
// verify the core permissions are set-up correctly
verifyInitPermissions(child);
// verify the permissions came from the correct parent
verify(mockedPermissionService).getAllSetPermissions(parent);
// verify all the inherited permissions are set correctly (note read are not inherited from fileplan)
verify(mockedPermissionService, filling).setPermission(child, AUTHORITY2, RMPermissionModel.FILING, true);
verify(mockedPermissionService, read).setPermission(child, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify that there are no unaccounted for interactions with the permission service
verifyNoMoreInteractions(mockedPermissionService);
}
/**
* Test the initialisation of permissions for a new root category
*/
@Test
public void initPermissionsForNewRootRecordCategory()
{
// setup permissions for file plan
setupPermissions(filePlan);
// setup permissions
filePlanPermissionService.setupRecordCategoryPermissions(rootRecordCategory);
// verify permission init
verifyInitPermissions(filePlan, rootRecordCategory, never(), times(1));
}
/**
* Test the initialisation of permissions for a new category
*/
@Test
public void initPermissionsForNewRecordCategory()
{
// setup permissions for parent
setupPermissions(rootRecordCategory);
// setup permissions
filePlanPermissionService.setupRecordCategoryPermissions(recordCategory);
// verify permission init
verifyInitPermissions(rootRecordCategory, recordCategory, times(1), times(1));
}
/**
* Test initialisation new record folder permissions
*/
@Test
public void initPermissionsForNewRecordFolder()
{
// setup permissions for parent
setupPermissions(recordCategory);
// setup permissions
filePlanPermissionService.setupPermissions(recordCategory, newRecordFolder);
// verify permission init
verifyInitPermissions(recordCategory, newRecordFolder, times(1), times(1));
}
/**
* Test setup of new record permissions
*/
@Test
public void initPermissionsForNewRecord()
{
// setup permissions for parent
setupPermissions(newRecordFolder);
// setup permissions for record
filePlanPermissionService.setupPermissions(newRecordFolder, newRecord);
// verify permission init
verifyInitPermissions(newRecordFolder, newRecord, times(1), times(1));
}
/**
* Test setup of permissions for new hold container
*/
@Test
public void initPermnissionsForNewHoldContainer()
{
// setup permissions for parent
setupPermissions(filePlan);
// setup permissions for record
filePlanPermissionService.setupPermissions(filePlan, holdContainer);
// verify permissions are set-up correctly
verifyInitPermissions(filePlan, holdContainer, times(1), times(1));
}
/**
* Test setup of permissions for new hold
*/
@Test
public void initPermissionsForNewHold()
{
// setup permissions for parent
setupPermissions(holdContainer);
// setup permissions for record
filePlanPermissionService.setupPermissions(holdContainer, hold);
// verify permissions are set-up correctly
verifyInitPermissions(holdContainer, hold, never(), times(1));
}
/**
* Test setup of permissions for new unfiled container
*/
@Test
public void initPermissionsForNewUnfiledContainer()
{
// setup permissions for parent
setupPermissions(filePlan);
// setup permissions for record
filePlanPermissionService.setupPermissions(filePlan, unfiledRecordContainer);
// verify permissions are set-up correctly
verifyInitPermissions(filePlan, unfiledRecordContainer, times(1), times(1));
}
/**
* Test setup of permissions for new unfiled record folder
*/
@Test
public void initPermissionsForNewUnfiledRecordFolder()
{
// setup permissions for parent
setupPermissions(unfiledRecordContainer);
// setup permissions for record
filePlanPermissionService.setupPermissions(unfiledRecordContainer, unfiledRecordFolder);
// verify permissions are set-up correctly
verifyInitPermissions(unfiledRecordContainer, unfiledRecordFolder, never(), times(1));
}
/**
* Test setup of permissions for new unfiled record
*/
@Test
public void initPermissionsForNewUnfiledRecord()
{
// setup permissions for parent
setupPermissions(unfiledRecordFolder);
// setup permissions for record
filePlanPermissionService.setupPermissions(unfiledRecordFolder, unfiledRecord);
// verify permission init
verifyInitPermissions(unfiledRecordFolder, unfiledRecord, times(1), times(1));
}
} }

View File

@@ -42,8 +42,10 @@ import org.junit.runners.Suite.SuiteClasses;
@SuiteClasses( @SuiteClasses(
{ {
RecordMetadataBootstrapUnitTest.class, RecordMetadataBootstrapUnitTest.class,
RecordServiceImplUnitTest.class,
RecordsManagementTypeFormFilterUnitTest.class, RecordsManagementTypeFormFilterUnitTest.class,
// services
RecordServiceImplUnitTest.class,
HoldServiceImplUnitTest.class, HoldServiceImplUnitTest.class,
FilePlanPermissionServiceImplUnitTest.class, FilePlanPermissionServiceImplUnitTest.class,

View File

@@ -43,6 +43,7 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
@@ -82,6 +83,7 @@ public class BaseUnitTest implements RecordsManagementModel
@Mock(name="namespaceService") protected NamespaceService mockedNamespaceService; @Mock(name="namespaceService") protected NamespaceService mockedNamespaceService;
@Mock(name="identifierService") protected IdentifierService mockedIdentifierService; @Mock(name="identifierService") protected IdentifierService mockedIdentifierService;
@Mock(name="permissionService") protected PermissionService mockedPermissionService; @Mock(name="permissionService") protected PermissionService mockedPermissionService;
@Mock(name="ownableService") protected OwnableService mockedOwnableService;
/** rm service mocks */ /** rm service mocks */
@Mock(name="filePlanService") protected FilePlanService mockedFilePlanService; @Mock(name="filePlanService") protected FilePlanService mockedFilePlanService;