diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties
index aa06ff15d3..8fdbf91cbd 100644
--- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties
+++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties
@@ -51,6 +51,11 @@ rm.autocompletesuggestion.nodeParameterSuggester.aspectsAndTypes=rma:record,cm:c
#
rm.dispositionlifecycletrigger.cronexpression=0 0/5 * * * ?
+#
+# Global RM notify of records due for review cron job expression
+#
+rm.notifyOfRecordsDueForReview.cronExpression=0 0/15 * * * ?
+
#
# Records contributors group
#
diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/records-model.properties b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/records-model.properties
index ab689a6057..a55d29cf8d 100644
--- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/records-model.properties
+++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/records-model.properties
@@ -174,8 +174,6 @@ rma_recordsmanagement.aspect.rma_vitalRecord.title=Vital Record
rma_recordsmanagement.aspect.rma_vitalRecord.decription=Vital Record
rma_recordsmanagement.property.rma_reviewAsOf.title=Next Review
rma_recordsmanagement.property.rma_reviewAsOf.decription=Next Review
-rma_recordsmanagement.property.rma_notificationIssued.title=Indicates that a due for review notification has been issued for this record
-rma_recordsmanagement.property.rma_notificationIssued.decription=Indicates that a due for review notification has been issued for this record
rma_recordsmanagement.aspect.rma_scheduled.title=Scheduled
rma_recordsmanagement.aspect.rma_scheduled.decription=Scheduled
diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml
index d0103fb842..7d90248df9 100644
--- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml
+++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml
@@ -885,13 +885,6 @@
d:date
false
-
- Indicates whether a notification that this record is due for review has been issued
- d:boolean
- true
- false
- false
-
rma:filePlanComponent
diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-job-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-job-context.xml
index 607fd1d9ec..c8cb9b668f 100644
--- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-job-context.xml
+++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-job-context.xml
@@ -47,7 +47,7 @@
- 0 0/15 * * * ?
+ ${rm.notifyOfRecordsDueForReview.cronExpression}
diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/security/rm-method-security.properties b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/security/rm-method-security.properties
index 4da32d8bef..1cc4f3e5c2 100644
--- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/security/rm-method-security.properties
+++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/security/rm-method-security.properties
@@ -121,14 +121,15 @@ rm.methodsecurity.org.alfresco.service.cmr.search.CategoryService.*=RM_DENY
## Lock Service
-rm.methodsecurity.org.alfresco.service.cmr.lock.LockService.lock=RM_ABSTAIN
-rm.methodsecurity.org.alfresco.service.cmr.lock.LockService.unlock=RM_ABSTAIN
+rm.methodsecurity.org.alfresco.service.cmr.lock.LockService.lock=RM.Create.0
+rm.methodsecurity.org.alfresco.service.cmr.lock.LockService.unlock=RM.Create.0
rm.methodsecurity.org.alfresco.service.cmr.lock.LockService.getLockStatus=RM.Read.0
rm.methodsecurity.org.alfresco.service.cmr.lock.LockService.getLockType=RM.Read.0
rm.methodsecurity.org.alfresco.service.cmr.lock.LockService.checkForLock=RM.Read.0
rm.methodsecurity.org.alfresco.service.cmr.lock.LockService.getLocks=RM.Read.0
rm.methodsecurity.org.alfresco.service.cmr.lock.LockService.isLockedAndReadOnly=RM.Read.0
rm.methodsecurity.org.alfresco.service.cmr.lock.LockService.isLocked=RM.Read.0
+rm.methodsecurity.org.alfresco.service.cmr.lock.LockService.getLockState=RM.Read.0
rm.methodsecurity.org.alfresco.service.cmr.lock.LockService.*=RM_DENY
## Multilingual Content Service
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/job/NotifyOfRecordsDueForReviewJobExecuter.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/job/NotifyOfRecordsDueForReviewJobExecuter.java
index aa659f6a84..61a04ca070 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/job/NotifyOfRecordsDueForReviewJobExecuter.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/job/NotifyOfRecordsDueForReviewJobExecuter.java
@@ -91,12 +91,8 @@ public class NotifyOfRecordsDueForReviewJobExecuter extends RecordsManagementJob
// Query is for all records that are due for review and for which
// notification has not been sent.
StringBuilder queryBuffer = new StringBuilder();
- queryBuffer.append("+ASPECT:\"rma:vitalRecord\" ");
+ queryBuffer.append("ASPECT:\"rma:vitalRecord\" ");
queryBuffer.append("AND @rma\\:reviewAsOf:[MIN TO NOW] ");
- queryBuffer.append("AND ( ");
- queryBuffer.append("@rma\\:notificationIssued:false ");
- queryBuffer.append("OR ISNULL:\"rma:notificationIssued\" ");
- queryBuffer.append(") ");
String query = queryBuffer.toString();
ResultSet results = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_FTS_ALFRESCO, query);
@@ -124,27 +120,12 @@ public class NotifyOfRecordsDueForReviewJobExecuter extends RecordsManagementJob
}
};
- RetryingTransactionCallback txUpdateNodesCallback = new RetryingTransactionCallback()
- {
- // Set the notification issued property.
- public Boolean execute()
- {
- for (NodeRef node : resultNodes)
- {
- nodeService.setProperty(node, RecordsManagementModel.PROP_NOTIFICATION_ISSUED, "true");
- }
- return Boolean.TRUE;
- }
- };
-
/**
* Now do the work, one action in each transaction
*/
// don't retry the send email
retryingTransactionHelper.setMaxRetries(0);
retryingTransactionHelper.doInTransaction(txCallbackSendEmail);
- retryingTransactionHelper.setMaxRetries(10);
- retryingTransactionHelper.doInTransaction(txUpdateNodesCallback);
}
return null;
}
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java
index a99f75cbab..d7c0308e9c 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java
@@ -136,7 +136,6 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel
// Vital record aspect
QName ASPECT_VITAL_RECORD = QName.createQName(RM_URI, "vitalRecord");
QName PROP_REVIEW_AS_OF = QName.createQName(RM_URI, "reviewAsOf");
- QName PROP_NOTIFICATION_ISSUED = QName.createQName(RM_URI, "notificationIssued");
// Cut off aspect
QName ASPECT_CUT_OFF = QName.createQName(RM_URI, "cutOff");
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java
index a862d6f892..21b2393885 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java
@@ -92,6 +92,7 @@ import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
+import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -128,6 +129,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
RecordsManagementModel,
RecordsManagementCustomModel,
NodeServicePolicies.OnCreateChildAssociationPolicy,
+ NodeServicePolicies.OnRemoveAspectPolicy,
NodeServicePolicies.OnUpdatePropertiesPolicy,
ContentServicePolicies.OnContentUpdatePolicy
{
@@ -416,6 +418,29 @@ public class RecordServiceImpl extends BaseBehaviourBean
*/
@Override
@Behaviour
+ (
+ kind = BehaviourKind.CLASS,
+ type = "sys:noContent"
+ )
+ public void onRemoveAspect(NodeRef nodeRef, QName aspect)
+ {
+ if (nodeService.hasAspect(nodeRef, ASPECT_RECORD))
+ {
+ ContentData contentData = (ContentData) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
+ if (ContentData.hasContent(contentData) && contentData.getSize() > 0)
+ {
+ renameRecord(nodeRef);
+ }
+ }
+ }
+
+ /**
+ * Behaviour executed when a new item is added to a record folder.
+ *
+ * @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean)
+ */
+ @Override
+ @Behaviour
(
kind = ASSOCIATION,
type = "rma:recordFolder",
@@ -1765,7 +1790,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
)
public void onContentUpdate(NodeRef nodeRef, boolean newContent)
{
- if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_HIDDEN))
+ if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_HIDDEN) && !nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE))
{
renameRecord(nodeRef);
}
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/vital/ReviewedAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/vital/ReviewedAction.java
index 1cdd507c73..51c3fd8e33 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/vital/ReviewedAction.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/vital/ReviewedAction.java
@@ -30,6 +30,7 @@ package org.alfresco.module.org_alfresco_module_rm.vital;
import java.util.Date;
import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase;
+import org.alfresco.repo.dictionary.types.period.Immediately;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
@@ -44,56 +45,72 @@ public class ReviewedAction extends RMActionExecuterAbstractBase
{
private static Log logger = LogFactory.getLog(ReviewedAction.class);
- /**
- *
- * @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action,
- * org.alfresco.service.cmr.repository.NodeRef)
- */
- @Override
- protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
- {
- VitalRecordDefinition vrDef = getVitalRecordService().getVitalRecordDefinition(actionedUponNodeRef);
+ /**
+ *
+ * @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action,
+ * org.alfresco.service.cmr.repository.NodeRef)
+ */
+ @Override
+ protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
+ {
+ VitalRecordDefinition vrDef = getVitalRecordService().getVitalRecordDefinition(actionedUponNodeRef);
if (vrDef != null && vrDef.isEnabled())
{
- if (getRecordService().isRecord(actionedUponNodeRef))
- {
- reviewRecord(actionedUponNodeRef, vrDef);
- }
- else if (getRecordFolderService().isRecordFolder(actionedUponNodeRef))
- {
- for (NodeRef record : getRecordService().getRecords(actionedUponNodeRef))
+ if (getRecordService().isRecord(actionedUponNodeRef))
+ {
+ reviewRecord(actionedUponNodeRef, vrDef);
+ }
+ else if (getRecordFolderService().isRecordFolder(actionedUponNodeRef))
+ {
+ for (NodeRef record : getRecordService().getRecords(actionedUponNodeRef))
{
reviewRecord(record, vrDef);
}
- }
- }
- }
+ }
+ }
+ }
- /**
- * Make record as reviewed.
- *
- * @param nodeRef
- * @param vrDef
- */
- private void reviewRecord(NodeRef nodeRef, VitalRecordDefinition vrDef)
- {
+ /**
+ * Make record as reviewed.
+ *
+ * @param nodeRef
+ * @param vrDef
+ */
+ private void reviewRecord(NodeRef nodeRef, VitalRecordDefinition vrDef)
+ {
// Calculate the next review date
- Date reviewAsOf = vrDef.getNextReviewDate();
- if (reviewAsOf != null)
+ if (vrDef.getReviewPeriod().getPeriodType().equals(Immediately.PERIOD_TYPE))
{
// Log
if (logger.isDebugEnabled())
{
StringBuilder msg = new StringBuilder();
+ msg.append("Removing reviewAsOf property from")
+ .append(nodeRef);
+ logger.debug(msg.toString());
+ }
+
+ this.getNodeService().removeProperty(nodeRef, PROP_REVIEW_AS_OF);
+ }
+ else
+ {
+ Date reviewAsOf = vrDef.getNextReviewDate();
+ if (reviewAsOf != null)
+ {
+ // Log
+ if (logger.isDebugEnabled())
+ {
+ StringBuilder msg = new StringBuilder();
msg.append("Setting new reviewAsOf property [")
.append(reviewAsOf)
.append("] on ")
.append(nodeRef);
- logger.debug(msg.toString());
+ logger.debug(msg.toString());
+ }
+
+ this.getNodeService().setProperty(nodeRef, PROP_REVIEW_AS_OF, reviewAsOf);
+ // TODO And record previous review date, time, user
}
-
- this.getNodeService().setProperty(nodeRef, PROP_REVIEW_AS_OF, reviewAsOf);
- //TODO And record previous review date, time, user
}
- }
+ }
}
diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/vital/ReviewedActionUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/vital/ReviewedActionUnitTest.java
new file mode 100644
index 0000000000..8b28cc049a
--- /dev/null
+++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/vital/ReviewedActionUnitTest.java
@@ -0,0 +1,140 @@
+/*
+ * #%L
+ * Alfresco Records Management Module
+ * %%
+ * Copyright (C) 2005 - 2017 Alfresco Software Limited
+ * %%
+ * This file is part of the Alfresco software.
+ * -
+ * If the software was purchased under a paid Alfresco license, the terms of
+ * the paid license agreement will prevail. Otherwise, the software is
+ * provided under the following open source license terms:
+ * -
+ * 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 .
+ * #L%
+ */
+package org.alfresco.module.org_alfresco_module_rm.vital;
+
+import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
+import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
+import org.alfresco.repo.dictionary.types.period.Days;
+import org.alfresco.repo.dictionary.types.period.Immediately;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Date;
+
+import static org.mockito.Mockito.verify;
+
+import org.alfresco.service.cmr.repository.Period;
+import org.alfresco.service.cmr.repository.StoreRef;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.springframework.extensions.webscripts.GUID;
+
+/**
+ * Unit test for {@link ReviewedAction} class
+ *
+ * @author Ana Bozianu
+ * @sincev 2.6
+ */
+public class ReviewedActionUnitTest implements RecordsManagementModel
+{
+ private @Mock VitalRecordService mockedVitalRecordService;
+ private @Mock RecordService mockedRecordService;
+ private @Mock NodeService mockedNodeService;
+
+ private @InjectMocks ReviewedAction reviewedAction;
+
+ @Before
+ public void testSetup()
+ {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ /**
+ * Given a record having the vital record definition of immediately
+ * When I mark the record as reviewed
+ * Then review as of date is removed from the record
+ */
+ @Test
+ public void testReviewRecordWithAdHocReviewPeriod()
+ {
+ /*
+ * Given
+ */
+ NodeRef mockedRecord = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, GUID.generate());
+ when(mockedRecordService.isRecord(mockedRecord)).thenReturn(true);
+
+ VitalRecordDefinition mockedVRDef = mock(VitalRecordDefinition.class);
+ when(mockedVRDef.isEnabled()).thenReturn(true);
+ when(mockedVitalRecordService.getVitalRecordDefinition(mockedRecord)).thenReturn(mockedVRDef);
+
+ Period mockedReviewPeriod = mock(Period.class);
+ when(mockedReviewPeriod.getPeriodType()).thenReturn(Immediately.PERIOD_TYPE);
+ when(mockedVRDef.getReviewPeriod()).thenReturn(mockedReviewPeriod);
+
+ /*
+ * When
+ */
+ reviewedAction.executeImpl(null, mockedRecord);
+
+ /*
+ * Then
+ */
+ verify(mockedNodeService).removeProperty(mockedRecord, PROP_REVIEW_AS_OF);
+ }
+
+ /**
+ * Given a record having a recurent vital record definition
+ * When I mark the record as reviewed
+ * Then the review as of date is updated according to the next review period computed by the vital record definition
+ */
+ @Test
+ public void testReviewRecordWithRecurentReviewPeriod()
+ {
+ /*
+ * Given
+ */
+ NodeRef mockedRecord = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, GUID.generate());
+ when(mockedRecordService.isRecord(mockedRecord)).thenReturn(true);
+
+ VitalRecordDefinition mockedVRDef = mock(VitalRecordDefinition.class);
+ when(mockedVRDef.isEnabled()).thenReturn(true);
+ when(mockedVitalRecordService.getVitalRecordDefinition(mockedRecord)).thenReturn(mockedVRDef);
+
+ Date mockedNextReviewDate = mock(Date.class);
+ when(mockedVRDef.getNextReviewDate()).thenReturn(mockedNextReviewDate);
+
+ Period mockedReviewPeriod = mock(Period.class);
+ when(mockedReviewPeriod.getPeriodType()).thenReturn(Days.PERIOD_TYPE);
+ when(mockedVRDef.getReviewPeriod()).thenReturn(mockedReviewPeriod);
+
+ /*
+ * When
+ */
+ reviewedAction.executeImpl(null, mockedRecord);
+
+ /*
+ * Then
+ */
+ verify(mockedNodeService).setProperty(mockedRecord, PROP_REVIEW_AS_OF, mockedNextReviewDate);
+ }
+}