From 3cf1cfd1332b5e85ba33cdc410ed19beeb410f46 Mon Sep 17 00:00:00 2001 From: ramunteanu Date: Tue, 3 Aug 2021 18:05:15 +0300 Subject: [PATCH] feature/APPS-1004 (#624) * APPS-1004/APPS-1005: Retention steps are not updated when moving from another category with a different retention schedule * APPS-1004/APPS-1005: [AGS] Retention steps are not updated when moving from another category with a different retention schedule - Added test for APPS-1004 and changed fix to solve another isuue RM-7106 * APPS-1004/APPS-1005: [AGS] Retention steps are not updated when moving from another category with a different retention schedule - Added common method to be used by both categoryType and folderType * APPS-1004/APPS-1005: [AGS] Retention steps are not updated when moving from another category with a different retention schedule - Added change to reinitialize folders recursively, for the case where there are multiple subcategories * APPS-1004/APPS-1005: [AGS] Retention steps are not updated when moving from another category with a different retention schedule - Added changes suggested at review --- .../rm-model-context.xml | 2 + .../behaviour/AbstractDisposableItem.java | 59 +++++- .../model/rma/type/RecordCategoryType.java | 69 +++++-- .../model/rma/type/RecordFolderType.java | 49 +---- .../DispositionScheduleInheritanceTest.java | 175 ++++++++++++++++++ .../test/util/CommonRMTestUtils.java | 2 + 6 files changed, 292 insertions(+), 64 deletions(-) diff --git a/amps/ags/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml b/amps/ags/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml index 8218bd49d0..23b950f2ea 100644 --- a/amps/ags/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml +++ b/amps/ags/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml @@ -102,9 +102,11 @@ + + diff --git a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/AbstractDisposableItem.java b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/AbstractDisposableItem.java index bd0d9e17dd..a064d97c38 100644 --- a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/AbstractDisposableItem.java +++ b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/behaviour/AbstractDisposableItem.java @@ -30,6 +30,10 @@ package org.alfresco.module.org_alfresco_module_rm.model.behaviour; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionAction; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; +import org.alfresco.module.org_alfresco_module_rm.record.RecordService; +import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService; +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.repository.NodeService; import org.alfresco.service.namespace.QName; @@ -52,7 +56,13 @@ public abstract class AbstractDisposableItem extends BaseBehaviourBean /** disposition service */ protected DispositionService dispositionService; - + + /** record service */ + protected RecordService recordService; + + /** record folder service */ + protected RecordFolderService recordFolderService; + /** * @param dispositionService disposition service */ @@ -60,6 +70,22 @@ public abstract class AbstractDisposableItem extends BaseBehaviourBean { this.dispositionService = dispositionService; } + + /** + * @param recordService record service + */ + public void setRecordService(RecordService recordService) + { + this.recordService = recordService; + } + + /** + * @param recordFolderService record folder service + */ + public void setRecordFolderService(RecordFolderService recordFolderService) + { + this.recordFolderService = recordFolderService; + } /** * Removes unwanted aspects @@ -86,4 +112,35 @@ public abstract class AbstractDisposableItem extends BaseBehaviourBean } } + /** + * Cleans and re-initiates the containing records + * + * @param childAssociationRef + */ + protected void reinitializeRecordFolder(ChildAssociationRef childAssociationRef) + { + + NodeRef newNodeRef = childAssociationRef.getChildRef(); + + AuthenticationUtil.runAs(() -> { + // clean record folder + cleanDisposableItem(nodeService, newNodeRef); + + // re-initialise the record folder + recordFolderService.setupRecordFolder(newNodeRef); + + // sort out the child records + for (NodeRef record : recordService.getRecords(newNodeRef)) + { + // clean record + cleanDisposableItem(nodeService, record); + + // Re-initiate the records in the new folder. + recordService.file(record); + } + + return null; + }, AuthenticationUtil.getSystemUserName()); + } + } diff --git a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryType.java b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryType.java index 500aec6f6d..9a09513f15 100644 --- a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryType.java +++ b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryType.java @@ -27,13 +27,14 @@ package org.alfresco.module.org_alfresco_module_rm.model.rma.type; +import static org.alfresco.model.ContentModel.TYPE_CONTENT; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.alfresco.model.ContentModel; -import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; -import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService; +import org.alfresco.module.org_alfresco_module_rm.model.behaviour.AbstractDisposableItem; import org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService; import org.alfresco.module.org_alfresco_module_rm.vital.VitalRecordService; import org.alfresco.repo.copy.CopyBehaviourCallback; @@ -49,6 +50,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.RegexQNamePattern; /** * rma:recordCategory behaviour bean @@ -60,9 +62,10 @@ import org.alfresco.service.namespace.QName; ( defaultType = "rma:recordCategory" ) -public class RecordCategoryType extends BaseBehaviourBean +public class RecordCategoryType extends AbstractDisposableItem implements NodeServicePolicies.OnCreateChildAssociationPolicy, - NodeServicePolicies.OnCreateNodePolicy + NodeServicePolicies.OnCreateNodePolicy, + NodeServicePolicies.OnMoveNodePolicy { private final static List ACCEPTED_UNIQUE_CHILD_TYPES = new ArrayList<>(); private final static List ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_RECORD_CATEGORY, TYPE_RECORD_FOLDER); @@ -73,9 +76,6 @@ public class RecordCategoryType extends BaseBehaviourBean /** file plan permission service */ protected FilePlanPermissionService filePlanPermissionService; - /** record folder service */ - private RecordFolderService recordFolderService; - /** * @param vitalRecordService vital record service */ @@ -92,14 +92,6 @@ public class RecordCategoryType extends BaseBehaviourBean this.filePlanPermissionService = filePlanPermissionService; } - /** - * @param recordFolderService record folder service - */ - public void setRecordFolderService(RecordFolderService recordFolderService) - { - this.recordFolderService = recordFolderService; - } - /** * On every event * @@ -204,6 +196,53 @@ public class RecordCategoryType extends BaseBehaviourBean } + /** + * Record Category move behaviour + * + * @see org.alfresco.repo.node.NodeServicePolicies.OnMoveNodePolicy#onMoveNode(org.alfresco.service.cmr.repository.ChildAssociationRef, org.alfresco.service.cmr.repository.ChildAssociationRef) + */ + @Override + @Behaviour + ( + kind = BehaviourKind.CLASS, + notificationFrequency = NotificationFrequency.FIRST_EVENT + ) + public void onMoveNode(ChildAssociationRef oldChildAssocRef, ChildAssociationRef newChildAssocRef) + { + // clean the child folders and records only if the old parent category has a disposition schedule set + // if it doesn't, then there are no old properties on the child nodes that have to be cleaned in order + // for new ones to be set + if (nodeService.getType(newChildAssocRef.getChildRef()).equals(TYPE_RECORD_CATEGORY) + && dispositionService.getDispositionSchedule(oldChildAssocRef.getParentRef()) != null) + { + reinitializeRecordFolders(newChildAssocRef); + } + } + + /** + * Recursively reinitialize each folder in a structure of categories + * Unwanted aspects will be removed from the child records and the records will be re-filed + * Disposition schedule aspects and properties will be inherited from the new parent category + * + * @param childAssociationRef + */ + private void reinitializeRecordFolders(ChildAssociationRef childAssociationRef) + { + for (ChildAssociationRef newChildRef : nodeService.getChildAssocs(childAssociationRef.getChildRef(), + ContentModel.ASSOC_CONTAINS, + RegexQNamePattern.MATCH_ALL)) + { + if (nodeService.getType(newChildRef.getChildRef()).equals(TYPE_RECORD_CATEGORY)) + { + reinitializeRecordFolders(newChildRef); + } + else if (!nodeService.getType(newChildRef.getChildRef()).equals(TYPE_CONTENT)) + { + reinitializeRecordFolder(newChildRef); + } + } + } + /** * Copy callback for record category */ diff --git a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderType.java b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderType.java index f9eb29dbfb..f6dee11ea2 100644 --- a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderType.java +++ b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordFolderType.java @@ -34,8 +34,6 @@ import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.model.behaviour.AbstractDisposableItem; -import org.alfresco.module.org_alfresco_module_rm.record.RecordService; -import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService; import org.alfresco.module.org_alfresco_module_rm.vital.VitalRecordService; import org.alfresco.repo.copy.CopyBehaviourCallback; import org.alfresco.repo.copy.CopyDetails; @@ -68,11 +66,6 @@ public class RecordFolderType extends AbstractDisposableItem implements NodeServicePolicies.OnMoveNodePolicy, NodeServicePolicies.OnCreateChildAssociationPolicy { - /** record service */ - private RecordService recordService; - - /** record folder service */ - private RecordFolderService recordFolderService; /** vital record service */ protected VitalRecordService vitalRecordService; @@ -85,22 +78,6 @@ public class RecordFolderType extends AbstractDisposableItem private static final String MSG_CANNOT_CREATE_CHILDREN_IN_CLOSED_RECORD_FOLDER = "rm.service.add-children-to-closed-record-folder"; - /** - * @param recordService record service - */ - public void setRecordService(RecordService recordService) - { - this.recordService = recordService; - } - - /** - * @param recordFolderService record folder service - */ - public void setRecordFolderService(RecordFolderService recordFolderService) - { - this.recordFolderService = recordFolderService; - } - /** * @param vitalRecordService vital record service */ @@ -131,31 +108,7 @@ public class RecordFolderType extends AbstractDisposableItem { if (!oldChildAssocRef.getParentRef().equals(newChildAssocRef.getParentRef())) { - final NodeRef newNodeRef = newChildAssocRef.getChildRef(); - - AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() - { - public Object doWork() - { - // clean record folder - cleanDisposableItem(nodeService, newNodeRef); - - // re-initialise the record folder - recordFolderService.setupRecordFolder(newNodeRef); - - // sort out the child records - for (NodeRef record : recordService.getRecords(newNodeRef)) - { - // clean record - cleanDisposableItem(nodeService, record); - - // Re-initiate the records in the new folder. - recordService.file(record); - } - - return null; - } - }, AuthenticationUtil.getSystemUserName()); + reinitializeRecordFolder(newChildAssocRef); } } else diff --git a/amps/ags/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/DispositionScheduleInheritanceTest.java b/amps/ags/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/DispositionScheduleInheritanceTest.java index e55fe0e7b6..2427227972 100644 --- a/amps/ags/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/DispositionScheduleInheritanceTest.java +++ b/amps/ags/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/DispositionScheduleInheritanceTest.java @@ -28,6 +28,8 @@ package org.alfresco.module.org_alfresco_module_rm.test.integration.disposition; import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.DEFAULT_DISPOSITION_DESCRIPTION; import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.DEFAULT_DISPOSITION_INSTRUCTIONS; +import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.DEFAULT_EVENT_NAME; +import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.SEPARATION_EVENT_NAME; import static org.alfresco.util.GUID.generate; import java.io.Serializable; @@ -37,6 +39,7 @@ import java.util.List; import java.util.Map; import org.alfresco.module.org_alfresco_module_rm.action.impl.CutOffAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.DestroyAction; import org.alfresco.module.org_alfresco_module_rm.action.impl.RetainAction; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionAction; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; @@ -190,6 +193,162 @@ public class DispositionScheduleInheritanceTest extends BaseRMTestCase }); } + /** + * Given a root record category A with a retention schedule set to retain and destroy after 1 day + * and another root record category B with a retention schedule set to cut off and destroy after 1 day containing a + * subcategory + * When moving the subcategory into the first root category + * Then records under the subcategory inherit the retention schedule of the parent record category + * The events list contain the retain event step inherited from the new parent category + *

+ * Please see https://alfresco.atlassian.net/browse/APPS-1004 + */ + public void testRetentionScheduleInheritance_APPS_1004() + { + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + NodeRef category1; + NodeRef subcategory2; + NodeRef record; + Date asOfDateBeforeMove; + + @Override + public void given() + { + // create root category1 + category1 = filePlanService.createRecordCategory(filePlan, generate()); + + // create record level disposition schedule for category1 + createDispositionScheduleRetainAndCutOffOneDay(category1); + + // create root category2 + NodeRef category2 = filePlanService.createRecordCategory(filePlan, generate()); + + // create record level disposition schedule for category2 + createDispositionScheduleCutOffAndDestroyOneDay(category2); + + // create subcategory2 under category2 + subcategory2 = filePlanService.createRecordCategory(category2, generate()); + + // create folder under subcategory2 + folder = recordFolderService.createRecordFolder(subcategory2, generate()); + + // file record in folder and complete it + record = utils.createRecord(folder, generate(), generate()); + utils.completeRecord(record); + + //store the date to check if it was updated + asOfDateBeforeMove = dispositionService.getNextDispositionAction(record).getAsOfDate(); + } + + @Override + public void when() throws Exception + { + // move subcategory2 under category1 + fileFolderService.move(subcategory2, category1, null); + } + + @Override + public void then() throws Exception + { + dispositionService.getDispositionSchedule(record); + // check the next disposition action + DispositionAction dispositionActionAfterMove = dispositionService.getNextDispositionAction(record); + assertNotNull(dispositionActionAfterMove); + assertEquals(RetainAction.NAME, dispositionActionAfterMove.getName()); + assertNotNull(dispositionActionAfterMove.getAsOfDate()); + assertTrue(dispositionActionAfterMove.getAsOfDate().after(asOfDateBeforeMove)); + + // check the search aspect details + assertTrue(nodeService.hasAspect(record, ASPECT_RM_SEARCH)); + assertEquals(RetainAction.NAME, nodeService.getProperty(record, PROP_RS_DISPOSITION_ACTION_NAME)); + assertNotNull(nodeService.getProperty(record, PROP_RS_DISPOSITION_ACTION_AS_OF)); + assertNull((List) nodeService.getProperty(record, PROP_RS_DISPOSITION_EVENTS)); + assertNotNull(nodeService.getProperty(record, PROP_RS_DISPOITION_INSTRUCTIONS)); + assertNotNull(nodeService.getProperty(record, PROP_RS_DISPOITION_AUTHORITY)); + assertTrue((Boolean) nodeService.getProperty(record, PROP_RS_HAS_DISPOITION_SCHEDULE)); + } + }); + } + + /** + * Given a root record category A with a retention schedule set to cut off on event 'case closed' + * and another root record category B with a retention schedule set to cut off on event 'separation' + * When moving the subcategory into the first root category + * Then records under the subcategory inherit the retention schedule of the parent record category + * The events list contain the case closed event step inherited from the new parent category + *

+ * Please see https://alfresco.atlassian.net/browse/APPS-1005 + */ + public void testRetentionScheduleInheritance_APPS_1005() + { + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + NodeRef category1; + NodeRef subcategory2; + NodeRef record; + Date asOfDateBeforeMove; + + @Override + public void given() + { + // create root category1 + category1 = filePlanService.createRecordCategory(filePlan, generate()); + + utils.createDispositionSchedule(category1, DEFAULT_DISPOSITION_INSTRUCTIONS, + DEFAULT_DISPOSITION_DESCRIPTION, true, true, false, DEFAULT_EVENT_NAME); + + // create root category2 + NodeRef category2 = filePlanService.createRecordCategory(filePlan, generate()); + + // create record level disposition schedule for category2 + utils.createDispositionSchedule(category2, DEFAULT_DISPOSITION_INSTRUCTIONS, + DEFAULT_DISPOSITION_DESCRIPTION, true, true, false, SEPARATION_EVENT_NAME); + + // create subcategory2 under category2 + subcategory2 = filePlanService.createRecordCategory(category2, generate()); + + // create folder under subcategory2 + folder = recordFolderService.createRecordFolder(subcategory2, generate()); + + // file record in folder and complete it + record = utils.createRecord(folder, generate(), generate()); + utils.completeRecord(record); + + //store the date to check if it was updated + asOfDateBeforeMove = dispositionService.getNextDispositionAction(record).getAsOfDate(); + } + + @Override + public void when() throws Exception + { + // move subcategory2 under category1 + fileFolderService.move(subcategory2, category1, null); + } + + @Override + public void then() throws Exception + { + // check the next disposition action + DispositionAction dispositionActionAfterMove = dispositionService.getNextDispositionAction(record); + assertNotNull(dispositionActionAfterMove); + assertEquals(CutOffAction.NAME, dispositionActionAfterMove.getName()); + + // check the search aspect details + assertTrue(nodeService.hasAspect(record, ASPECT_RM_SEARCH)); + assertEquals(CutOffAction.NAME, nodeService.getProperty(record, PROP_RS_DISPOSITION_ACTION_NAME)); + assertNotNull((List) nodeService.getProperty(record, PROP_RS_DISPOSITION_EVENTS)); + assertEquals(((List) ((List) nodeService.getProperty(record, + PROP_RS_DISPOSITION_EVENTS))).size(), 1); + assertEquals(DEFAULT_EVENT_NAME, ((List) ((List) nodeService.getProperty(record, + PROP_RS_DISPOSITION_EVENTS))).get(0)); + assertNotNull(nodeService.getProperty(record, PROP_RS_DISPOITION_INSTRUCTIONS)); + assertNotNull(nodeService.getProperty(record, PROP_RS_DISPOITION_AUTHORITY)); + assertTrue((Boolean) nodeService.getProperty(record, PROP_RS_HAS_DISPOITION_SCHEDULE)); + } + }); + } + private void createDispositionScheduleCutOff(NodeRef category, String action, String period) { DispositionSchedule ds = utils.createDispositionSchedule(category, DEFAULT_DISPOSITION_INSTRUCTIONS, DEFAULT_DISPOSITION_DESCRIPTION, true, false, false); @@ -205,6 +364,22 @@ public class DispositionScheduleInheritanceTest extends BaseRMTestCase createDispositionScheduleStep(ds, RetainAction.NAME, CommonRMTestUtils.PERIOD_IMMEDIATELY); } + private void createDispositionScheduleRetainAndCutOffOneDay(NodeRef category) + { + DispositionSchedule ds = utils.createDispositionSchedule(category, DEFAULT_DISPOSITION_INSTRUCTIONS, DEFAULT_DISPOSITION_DESCRIPTION, true, false, false); + + createDispositionScheduleStep(ds, RetainAction.NAME, CommonRMTestUtils.PERIOD_ONE_DAY); + createDispositionScheduleStep(ds, DestroyAction.NAME, CommonRMTestUtils.PERIOD_ONE_DAY); + } + + private void createDispositionScheduleCutOffAndDestroyOneDay(NodeRef category) + { + DispositionSchedule ds = utils.createDispositionSchedule(category, DEFAULT_DISPOSITION_INSTRUCTIONS, DEFAULT_DISPOSITION_DESCRIPTION, true, false, false); + + createDispositionScheduleStep(ds, CutOffAction.NAME, CommonRMTestUtils.PERIOD_ONE_DAY); + createDispositionScheduleStep(ds, DestroyAction.NAME, CommonRMTestUtils.PERIOD_ONE_DAY); + } + private void createDispositionScheduleStep(DispositionSchedule ds, String action, String period) { Map step = new HashMap(3); diff --git a/amps/ags/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java b/amps/ags/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java index 2543f63225..7d9dc3d0ae 100644 --- a/amps/ags/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java +++ b/amps/ags/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java @@ -82,8 +82,10 @@ public class CommonRMTestUtils implements RecordsManagementModel public static final String DEFAULT_DISPOSITION_INSTRUCTIONS = "disposition instructions"; public static final String DEFAULT_DISPOSITION_DESCRIPTION = "disposition action description"; public static final String DEFAULT_EVENT_NAME = "case_closed"; + public static final String SEPARATION_EVENT_NAME = "separation"; public static final String PERIOD_NONE = "none|0"; public static final String PERIOD_IMMEDIATELY = "immediately|0"; + public static final String PERIOD_ONE_DAY = "day|1"; public static final String PERIOD_FIVE_DAYS = "day|5"; public static final String PERIOD_TEN_DAYS = "day|10"; public static final String PERIOD_ONE_WEEK = "week|1";