RM-4293: prevent filePlan and unfiled Record container from behaviour

beans, also removed deleteNode method from RMNodesImpl and some unit
tests
This commit is contained in:
Silviu Dinuta
2016-11-15 19:00:48 +02:00
parent 411c14a93b
commit 51f99f1846
6 changed files with 116 additions and 144 deletions

View File

@@ -76,6 +76,7 @@
<property name="filePlanService" ref="FilePlanService" /> <property name="filePlanService" ref="FilePlanService" />
<property name="recordFolderService" ref="RecordFolderService" /> <property name="recordFolderService" ref="RecordFolderService" />
<property name="filePlanRoleService" ref="FilePlanRoleService" /> <property name="filePlanRoleService" ref="FilePlanRoleService" />
<property name="unfilerRecordContainerType" ref="rma.unfiledRecordsContainer" />
</bean> </bean>
<bean id="rma.holdContainer" class="org.alfresco.module.org_alfresco_module_rm.model.rma.type.HoldContainerType" parent="rm.baseBehaviour"> <bean id="rma.holdContainer" class="org.alfresco.module.org_alfresco_module_rm.model.rma.type.HoldContainerType" parent="rm.baseBehaviour">
@@ -112,6 +113,7 @@
<property name="recordsManagementSearchService" ref="RecordsManagementSearchService" /> <property name="recordsManagementSearchService" ref="RecordsManagementSearchService" />
<property name="capabilityService" ref="CapabilityService" /> <property name="capabilityService" ref="CapabilityService" />
<property name="authorityService" ref="AuthorityService" /> <property name="authorityService" ref="AuthorityService" />
<property name="filePlanType" ref="rma.filePlan" />
</bean> </bean>
<!-- rma model aspects --> <!-- rma model aspects -->

View File

@@ -37,6 +37,7 @@ import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService; 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.role.FilePlanRoleService;
import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourBean;
@@ -61,10 +62,12 @@ import org.alfresco.service.namespace.QName;
public class FilePlanType extends BaseBehaviourBean public class FilePlanType extends BaseBehaviourBean
implements NodeServicePolicies.OnCreateChildAssociationPolicy, implements NodeServicePolicies.OnCreateChildAssociationPolicy,
NodeServicePolicies.OnCreateNodePolicy, NodeServicePolicies.OnCreateNodePolicy,
NodeServicePolicies.OnDeleteNodePolicy NodeServicePolicies.OnDeleteNodePolicy,
NodeServicePolicies.BeforeDeleteNodePolicy
{ {
private final static List<QName> ACCEPTED_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_HOLD_CONTAINER, TYPE_TRANSFER_CONTAINER, TYPE_UNFILED_RECORD_CONTAINER); private final static List<QName> ACCEPTED_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_HOLD_CONTAINER, TYPE_TRANSFER_CONTAINER, TYPE_UNFILED_RECORD_CONTAINER);
private final static List<QName> ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_RECORD_CATEGORY); private final static List<QName> ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_RECORD_CATEGORY);
private static final String BEHAVIOUR_NAME = "onDeleteFilePlan";
/** file plan service */ /** file plan service */
private FilePlanService filePlanService; private FilePlanService filePlanService;
@@ -78,6 +81,8 @@ public class FilePlanType extends BaseBehaviourBean
/** file plan role service */ /** file plan role service */
private FilePlanRoleService filePlanRoleService; private FilePlanRoleService filePlanRoleService;
private UnfiledRecordContainerType unfilerRecordContainerType;
/** /**
* @return File plan service * @return File plan service
*/ */
@@ -142,6 +147,31 @@ public class FilePlanType extends BaseBehaviourBean
this.filePlanRoleService = filePlanRoleService; this.filePlanRoleService = filePlanRoleService;
} }
public void setUnfilerRecordContainerType(UnfiledRecordContainerType unfilerRecordContainerType)
{
this.unfilerRecordContainerType = unfilerRecordContainerType;
}
/**
* Disable the behaviours for this transaction
*
*/
public void disable()
{
getBehaviour(BEHAVIOUR_NAME).disable();
}
/**
* Enable behaviours for this transaction
*
*/
public void enable()
{
getBehaviour(BEHAVIOUR_NAME).enable();
}
/** /**
* @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean) * @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean)
*/ */
@@ -194,15 +224,43 @@ public class FilePlanType extends BaseBehaviourBean
/** /**
* @see org.alfresco.repo.node.NodeServicePolicies.OnDeleteNodePolicy#onDeleteNode(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean) * @see org.alfresco.repo.node.NodeServicePolicies.OnDeleteNodePolicy#onDeleteNode(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean)
*/ */
@Override
@Behaviour @Behaviour
( (
kind = BehaviourKind.CLASS, kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.FIRST_EVENT,
name = BEHAVIOUR_NAME
)
public void onDeleteNode(ChildAssociationRef childAssocRef, boolean archived)
{
unfilerRecordContainerType.enable();
throw new IntegrityException("Operation failed. Deletion of File Plan is not allowed.", null);
}
/**
* @see org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy#beforeDeleteNode(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
@Behaviour
(
kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.FIRST_EVENT
)
public void beforeDeleteNode(NodeRef nodeRef)
{
unfilerRecordContainerType.disable();
}
@Behaviour
(
kind = BehaviourKind.CLASS,
policy = "alf:onDeleteNode",
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
) )
@Override public void onDeleteNodeOnCommit(ChildAssociationRef childAssocRef, boolean archived)
public void onDeleteNode(ChildAssociationRef childAssocRef, boolean archived)
{ {
// tear down the file plan roles // tear down the file plan roles
getFilePlanRoleService().tearDownFilePlanRoles(childAssocRef.getChildRef()); getFilePlanRoleService().tearDownFilePlanRoles(childAssocRef.getChildRef());
unfilerRecordContainerType.enable();
} }
} }

View File

@@ -97,6 +97,8 @@ public class RmSiteType extends BaseBehaviourBean
/** Authority service */ /** Authority service */
private AuthorityService authorityService; private AuthorityService authorityService;
private FilePlanType filePlanType;
/** Map of file plan type's key'ed by corresponding site types */ /** Map of file plan type's key'ed by corresponding site types */
protected Map<QName, QName> mapFilePlanType = new HashMap<QName, QName>(3); protected Map<QName, QName> mapFilePlanType = new HashMap<QName, QName>(3);
@@ -133,6 +135,11 @@ public class RmSiteType extends BaseBehaviourBean
this.authorityService = authorityService; this.authorityService = authorityService;
} }
public void setFilePlanType(FilePlanType filePlanType)
{
this.filePlanType = filePlanType;
}
/** /**
* Registers a file plan type for a specific site type. * Registers a file plan type for a specific site type.
* *
@@ -302,6 +309,7 @@ public class RmSiteType extends BaseBehaviourBean
return null; return null;
} }
}); });
filePlanType.disable();
} }
} }
} }
@@ -354,4 +362,15 @@ public class RmSiteType extends BaseBehaviourBean
throw new IntegrityException(I18NUtil.getMessage(MULTIPLE_CHILDREN_TYPE_ERROR, ContentModel.TYPE_FOLDER), null); throw new IntegrityException(I18NUtil.getMessage(MULTIPLE_CHILDREN_TYPE_ERROR, ContentModel.TYPE_FOLDER), null);
} }
} }
@Behaviour
(
kind = BehaviourKind.CLASS,
policy = "alf:onDeleteNode",
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
)
public void onDeleteNodeOnCommit(ChildAssociationRef childAssocRef, boolean isNodeArchived)
{
filePlanType.enable();
}
} }

View File

@@ -33,6 +33,7 @@ import java.util.List;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean;
import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind; import org.alfresco.repo.policy.annotation.BehaviourKind;
@@ -47,9 +48,30 @@ import org.alfresco.service.namespace.QName;
*/ */
@BehaviourBean(defaultType = "rma:unfiledRecordContainer") @BehaviourBean(defaultType = "rma:unfiledRecordContainer")
public class UnfiledRecordContainerType extends BaseBehaviourBean public class UnfiledRecordContainerType extends BaseBehaviourBean
implements NodeServicePolicies.OnCreateChildAssociationPolicy implements NodeServicePolicies.OnCreateChildAssociationPolicy,
NodeServicePolicies.OnDeleteNodePolicy
{ {
private static final String BEHAVIOUR_NAME = "onDeleteUnfiledRecordContainer";
private final static List<QName> ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_UNFILED_RECORD_FOLDER, ContentModel.TYPE_CONTENT, TYPE_NON_ELECTRONIC_DOCUMENT); private final static List<QName> ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_UNFILED_RECORD_FOLDER, ContentModel.TYPE_CONTENT, TYPE_NON_ELECTRONIC_DOCUMENT);
/**
* Disable the behaviours for this transaction
*
*/
public void disable()
{
getBehaviour(BEHAVIOUR_NAME).disable();
}
/**
* Enable behaviours for this transaction
*
*/
public void enable()
{
getBehaviour(BEHAVIOUR_NAME).enable();
}
@Override @Override
@Behaviour(kind = BehaviourKind.ASSOCIATION) @Behaviour(kind = BehaviourKind.ASSOCIATION)
public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNewNode) public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNewNode)
@@ -57,4 +79,15 @@ public class UnfiledRecordContainerType extends BaseBehaviourBean
// check the created child is of an accepted type // check the created child is of an accepted type
validateNewChildAssociationSubTypesIncluded(childAssocRef.getChildRef(), ACCEPTED_NON_UNIQUE_CHILD_TYPES); validateNewChildAssociationSubTypesIncluded(childAssocRef.getChildRef(), ACCEPTED_NON_UNIQUE_CHILD_TYPES);
} }
@Override
@Behaviour
(
kind = BehaviourKind.CLASS,
name = BEHAVIOUR_NAME
)
public void onDeleteNode(ChildAssociationRef childAssocRef, boolean isNodeArchived)
{
throw new IntegrityException("Operation failed. Deletion of Unfiled Record Container is not allowed.", null);
}
} }

View File

@@ -48,8 +48,6 @@ import org.alfresco.rest.api.impl.NodesImpl;
import org.alfresco.rest.api.model.Node; import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.UserInfo; import org.alfresco.rest.api.model.UserInfo;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rm.rest.api.RMNodes; import org.alfresco.rm.rest.api.RMNodes;
import org.alfresco.rm.rest.api.model.FileplanComponentNode; import org.alfresco.rm.rest.api.model.FileplanComponentNode;
import org.alfresco.rm.rest.api.model.RecordCategoryNode; import org.alfresco.rm.rest.api.model.RecordCategoryNode;
@@ -380,22 +378,4 @@ public class RMNodesImpl extends NodesImpl implements RMNodes
return false; return false;
} }
/**
* Overridden this method just in order to use our isSpecialNode method since core method could not be overridden.
*
* TODO remove this after isSpecialNode will be made protected in core(REPO-1459).
*/
@Override
public void deleteNode(String nodeId, Parameters parameters)
{
NodeRef nodeRef = validateOrLookupNode(nodeId, null);
QName nodeType = nodeService.getType(nodeRef);
if (isSpecialNode(nodeRef, nodeType))
{
throw new PermissionDeniedException("Cannot delete: " + nodeId);
}
super.deleteNode(nodeId, parameters);
}
} }

View File

@@ -35,9 +35,6 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.security.InvalidParameterException; import java.security.InvalidParameterException;
@@ -52,8 +49,6 @@ import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
import org.alfresco.repo.model.Repository; import org.alfresco.repo.model.Repository;
import org.alfresco.rest.api.model.Node; import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rm.rest.api.RMNodes; import org.alfresco.rm.rest.api.RMNodes;
import org.alfresco.rm.rest.api.model.FileplanComponentNode; import org.alfresco.rm.rest.api.model.FileplanComponentNode;
import org.alfresco.rm.rest.api.model.RecordCategoryNode; import org.alfresco.rm.rest.api.model.RecordCategoryNode;
@@ -609,121 +604,6 @@ public class RMNodesImplUnitTest extends BaseUnitTest
assertEquals(nodeRef, validateOrLookupNode); assertEquals(nodeRef, validateOrLookupNode);
} }
@Test
public void testDeleteNode() throws Exception
{
NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService);
Parameters mockedParameters = mock(Parameters.class);
QName mockedType = AlfMock.generateQName();
when(mockedNodeService.getType(nodeRef)).thenReturn(mockedType);
setupCompanyHomeAndPrimaryParent(nodeRef);
rmNodesImpl.deleteNode(nodeRef.getId(), mockedParameters);
verify(mockedFileFolderService, times(1)).delete(nodeRef);
}
@Test
public void testDeleteFileplanNode() throws Exception
{
NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService);
Parameters mockedParameters = mock(Parameters.class);
QName mockedType = AlfMock.generateQName();
when(mockedNodeService.getType(nodeRef)).thenReturn(mockedType);
when(mockedFilePlanService.getFilePlanBySiteId(RM_SITE_ID)).thenReturn(nodeRef);
try
{
rmNodesImpl.deleteNode(nodeRef.getId(), mockedParameters);
fail("Expected ecxeption as filePlan can't be deleted.");
}
catch(PermissionDeniedException ex)
{
assertEquals("Cannot delete: " + nodeRef.getId(), ex.getMsgId());
}
verify(mockedFileFolderService, never()).delete(nodeRef);
}
@Test
public void testDeleteTransfersContainerNode() throws Exception
{
NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService);
Parameters mockedParameters = mock(Parameters.class);
QName mockedType = AlfMock.generateQName();
when(mockedNodeService.getType(nodeRef)).thenReturn(mockedType);
NodeRef filePlanNodeRef = AlfMock.generateNodeRef(mockedNodeService);
when(mockedFilePlanService.getFilePlanBySiteId(RM_SITE_ID)).thenReturn(filePlanNodeRef);
when(mockedFilePlanService.getTransferContainer(filePlanNodeRef)).thenReturn(nodeRef);
try
{
rmNodesImpl.deleteNode(nodeRef.getId(), mockedParameters);
fail("Expected ecxeption as Trnsfers container can't be deleted.");
}
catch(PermissionDeniedException ex)
{
assertEquals("Cannot delete: " + nodeRef.getId(), ex.getMsgId());
}
verify(mockedFileFolderService, never()).delete(nodeRef);
}
@Test
public void testDeleteHoldsContainerNode() throws Exception
{
NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService);
Parameters mockedParameters = mock(Parameters.class);
QName mockedType = AlfMock.generateQName();
when(mockedNodeService.getType(nodeRef)).thenReturn(mockedType);
NodeRef filePlanNodeRef = AlfMock.generateNodeRef(mockedNodeService);
when(mockedFilePlanService.getFilePlanBySiteId(RM_SITE_ID)).thenReturn(filePlanNodeRef);
NodeRef transferContainerNodeRef = AlfMock.generateNodeRef(mockedNodeService);
when(mockedFilePlanService.getTransferContainer(filePlanNodeRef)).thenReturn(transferContainerNodeRef);
when(mockedFilePlanService.getHoldContainer(filePlanNodeRef)).thenReturn(nodeRef);
try
{
rmNodesImpl.deleteNode(nodeRef.getId(), mockedParameters);
fail("Expected ecxeption as Holds container can't be deleted.");
}
catch(PermissionDeniedException ex)
{
assertEquals("Cannot delete: " + nodeRef.getId(), ex.getMsgId());
}
verify(mockedFileFolderService, never()).delete(nodeRef);
}
@Test
public void testDeleteUnfiledRecordsContainerNode() throws Exception
{
NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService);
Parameters mockedParameters = mock(Parameters.class);
QName mockedType = AlfMock.generateQName();
when(mockedNodeService.getType(nodeRef)).thenReturn(mockedType);
NodeRef filePlanNodeRef = AlfMock.generateNodeRef(mockedNodeService);
when(mockedFilePlanService.getFilePlanBySiteId(RM_SITE_ID)).thenReturn(filePlanNodeRef);
NodeRef transferContainerNodeRef = AlfMock.generateNodeRef(mockedNodeService);
when(mockedFilePlanService.getTransferContainer(filePlanNodeRef)).thenReturn(transferContainerNodeRef);
NodeRef holdContainerNodeRef = AlfMock.generateNodeRef(mockedNodeService);
when(mockedFilePlanService.getHoldContainer(filePlanNodeRef)).thenReturn(holdContainerNodeRef);
when(mockedFilePlanService.getUnfiledContainer(filePlanNodeRef)).thenReturn(nodeRef);
try
{
rmNodesImpl.deleteNode(nodeRef.getId(), mockedParameters);
fail("Expected ecxeption as Unfiled Records container can't be deleted.");
}
catch(PermissionDeniedException ex)
{
assertEquals("Cannot delete: " + nodeRef.getId(), ex.getMsgId());
}
verify(mockedFileFolderService, never()).delete(nodeRef);
}
private void setupCompanyHomeAndPrimaryParent(NodeRef nodeRef) private void setupCompanyHomeAndPrimaryParent(NodeRef nodeRef)
{ {
NodeRef companyHomeNodeRef = AlfMock.generateNodeRef(mockedNodeService); NodeRef companyHomeNodeRef = AlfMock.generateNodeRef(mockedNodeService);