From 81806ae2f9f95b13ead3735abd53331534c262f8 Mon Sep 17 00:00:00 2001 From: Roy Wetherall Date: Thu, 28 Feb 2013 07:21:26 +0000 Subject: [PATCH] RM-591: A records manager can define a rule that creates folders based on a creation strategy * RM actions can be configured to allow parmater level substitution * Paramater processor component added .. resposibile for processing parameters of an RM action and selecting the correct processor * Parameter processor framework added .. new processors can be sprung in using the usual pattern * 'node' processor added .. allows simple property value substitution based on the actioned upon node * 'date' processor added .. allows simple date value substituation * 'message' processor added .. allows message bundle value substitution * an example substitution parameter could be .. "/${message.my-company.name}/invoices/${date.month.short}" * fileTo action is configured to allow parameter substitution .. with the relative path and auto create features as well it is possible to define a rule that creates records folders based on a simple creation strategy .. for example always file into a record folder for this month git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@47262 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../extended-repository-context.xml | 21 +++ .../rm-action-context.xml | 2 + ...PropertySubActionExecuterAbstractBase.java | 58 ++++++++ .../action/RMActionExecuterAbstractBase.java | 20 +-- .../action/impl/FileToAction.java | 59 +++------ .../parameter/DateParameterProcessor.java | 113 ++++++++++++++++ .../parameter/MessageParameterProcessor.java | 55 ++++++++ .../parameter/NodeParameterProcessor.java | 121 +++++++++++++++++ .../action/parameter/ParameterProcessor.java | 94 +++++++++++++ .../ParameterProcessorComponent.java | 124 ++++++++++++++++++ .../test/action/FileToActionTest.java | 97 +++++--------- .../service/ExtendedActionServiceTest.java | 27 ++++ .../test/util/TestActionParams.java | 4 +- .../test/util/TestActionPropertySubs.java | 76 +++++++++++ rm-server/test/resources/test-context.xml | 24 +++- rm-server/test/resources/test.properties | 1 + 16 files changed, 770 insertions(+), 126 deletions(-) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/PropertySubActionExecuterAbstractBase.java create mode 100644 rm-server/source/java/org/alfresco/repo/action/parameter/DateParameterProcessor.java create mode 100644 rm-server/source/java/org/alfresco/repo/action/parameter/MessageParameterProcessor.java create mode 100644 rm-server/source/java/org/alfresco/repo/action/parameter/NodeParameterProcessor.java create mode 100644 rm-server/source/java/org/alfresco/repo/action/parameter/ParameterProcessor.java create mode 100644 rm-server/source/java/org/alfresco/repo/action/parameter/ParameterProcessorComponent.java create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/TestActionPropertySubs.java create mode 100644 rm-server/test/resources/test.properties diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/extended-repository-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/extended-repository-context.xml index f36ff9f590..b130fa9090 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/extended-repository-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/extended-repository-context.xml @@ -157,6 +157,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml index 07e1a009aa..e7cd48c8af 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml @@ -32,6 +32,7 @@ + + \ No newline at end of file diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/PropertySubActionExecuterAbstractBase.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/PropertySubActionExecuterAbstractBase.java new file mode 100644 index 0000000000..fa242308e3 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/PropertySubActionExecuterAbstractBase.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2005-2013 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.module.org_alfresco_module_rm.action; + +import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; +import org.alfresco.repo.action.parameter.ParameterProcessorComponent; +import org.alfresco.service.cmr.action.Action; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Extension to action implementation hierarchy to insert parameter substitution processing. + * + * @author Roy Wetherall + * @since 2.1 + */ +public abstract class PropertySubActionExecuterAbstractBase extends ActionExecuterAbstractBase +{ + private ParameterProcessorComponent parameterProcessorComponent; + + protected boolean allowParameterSubstitutions = false; + + public void setParameterProcessorComponent(ParameterProcessorComponent parameterProcessorComponent) + { + this.parameterProcessorComponent = parameterProcessorComponent; + } + + public void setAllowParameterSubstitutions(boolean allowParameterSubstitutions) + { + this.allowParameterSubstitutions = allowParameterSubstitutions; + } + + @Override + public void execute(Action action, NodeRef actionedUponNodeRef) + { + if (allowParameterSubstitutions == true) + { + parameterProcessorComponent.process(action, getActionDefinition(), actionedUponNodeRef); + } + + super.execute(action, actionedUponNodeRef); + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/RMActionExecuterAbstractBase.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/RMActionExecuterAbstractBase.java index 948348f79b..36269d40d1 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/RMActionExecuterAbstractBase.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/RMActionExecuterAbstractBase.java @@ -69,7 +69,7 @@ import org.springframework.util.StringUtils; * * @author Roy Wetherall */ -public abstract class RMActionExecuterAbstractBase extends ActionExecuterAbstractBase +public abstract class RMActionExecuterAbstractBase extends PropertySubActionExecuterAbstractBase implements RecordsManagementAction, RecordsManagementModel, BeanNameAware @@ -392,8 +392,6 @@ public abstract class RMActionExecuterAbstractBase extends ActionExecuterAbstra */ public RecordsManagementActionResult execute(NodeRef filePlanComponent, Map parameters) { - //isExecutableImpl(filePlanComponent, parameters, true); - // Create the action Action action = this.actionService.createAction(name); action.setParameterValues(parameters); @@ -440,22 +438,6 @@ public abstract class RMActionExecuterAbstractBase extends ActionExecuterAbstra // No parameters } -// /** -// * @see org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementAction#isExecutable(org.alfresco.service.cmr.repository.NodeRef, java.util.Map) -// */ -// public boolean isExecutable(NodeRef filePlanComponent, Map parameters) -// { -// return isExecutableImpl(filePlanComponent, parameters, false); -// } -// -// /** -// * @param filePlanComponent -// * @param parameters -// * @param throwException -// * @return -// */ -// protected abstract boolean isExecutableImpl(NodeRef filePlanComponent, Map parameters, boolean throwException); - /** * By default, rmActions do not provide an implicit target nodeRef. */ diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/FileToAction.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/FileToAction.java index d1675aeffa..28f767d845 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/FileToAction.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/FileToAction.java @@ -6,9 +6,7 @@ import java.util.List; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase; -import org.alfresco.repo.action.ActionImpl; import org.alfresco.repo.action.ParameterDefinitionImpl; -import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ParameterDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; @@ -83,25 +81,15 @@ public class FileToAction extends RMActionExecuterAbstractBase { // TODO .. what if a record of the same name already exists in the destination record folder?? - final NodeRef finalRecordFolder = recordFolder; - // AuthenticationUtil.runAsSystem(new RunAsWork() - // { - // @Override - // public Void doWork() throws Exception - // { - try - { - // TODO .. why do I have to execute this as system .. I should have permission to do this!!! - fileFolderService.move(actionedUponNodeRef, finalRecordFolder, null); - } - catch (FileNotFoundException fileNotFound) - { - throw new AlfrescoRuntimeException("Unable to execute file to action, because the move operation failed.", fileNotFound); - } - // - // return null; - // } - // }); + final NodeRef finalRecordFolder = recordFolder; + try + { + fileFolderService.move(actionedUponNodeRef, finalRecordFolder, null); + } + catch (FileNotFoundException fileNotFound) + { + throw new AlfrescoRuntimeException("Unable to execute file to action, because the move operation failed.", fileNotFound); + } } else { @@ -138,6 +126,7 @@ public class FileToAction extends RMActionExecuterAbstractBase // look for the path parameter String path = (String)action.getParameterValue(PARAM_PATH); String[] pathValues = ArrayUtils.EMPTY_STRING_ARRAY; + if (path != null && path.isEmpty() == false) { pathValues = StringUtils.tokenizeToStringArray(path, "/", false, true); @@ -193,25 +182,15 @@ public class FileToAction extends RMActionExecuterAbstractBase private NodeRef resolvePath(final NodeRef context, final String[] pathValues) { NodeRef result = null; - - //FileInfo fileInfo = AuthenticationUtil.runAsSystem(new RunAsWork() - //{ - // @Override - // public FileInfo doWork() throws Exception - // { - FileInfo fileInfo = null; - try - { - fileInfo = fileFolderService.resolveNamePath(context, new ArrayList(Arrays.asList(pathValues)), false); - } - catch (FileNotFoundException e) - { - // ignore, checking for null - } - // return fileInfo; - // } - //}); - + FileInfo fileInfo = null; + try + { + fileInfo = fileFolderService.resolveNamePath(context, new ArrayList(Arrays.asList(pathValues)), false); + } + catch (FileNotFoundException e) + { + // ignore, checking for null + } if (fileInfo != null) { result = fileInfo.getNodeRef(); diff --git a/rm-server/source/java/org/alfresco/repo/action/parameter/DateParameterProcessor.java b/rm-server/source/java/org/alfresco/repo/action/parameter/DateParameterProcessor.java new file mode 100644 index 0000000000..03cb0a0815 --- /dev/null +++ b/rm-server/source/java/org/alfresco/repo/action/parameter/DateParameterProcessor.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005-2013 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.action.parameter; + +import java.util.Calendar; +import java.util.Locale; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Date parameter processor. + * + * @author Roy Wetherall + * @since 2.1 + */ +public class DateParameterProcessor extends ParameterProcessor +{ + private static final String MONTH = "month"; + private static final String YEAR = "year"; + private static final String SHORT = "short"; + private static final String LONG = "long"; + + /** + * @see org.alfresco.repo.action.parameter.ParameterProcessor#process(java.lang.String, org.alfresco.service.cmr.repository.NodeRef) + */ + @Override + public String process(String value, NodeRef actionedUponNodeRef) + { + // the default position is to return the value un-changed + String result = value; + + // strip the processor name from the value + value = stripName(value); + if (value.isEmpty() == false) + { + String[] values = value.split("\\.", 2); + Calendar calendar = Calendar.getInstance(); + int field = getField(values); + if (Calendar.YEAR == field) + { + result = Integer.toString(calendar.get(field)); + } + else + { + result = calendar.getDisplayName(field, getStyle(values), Locale.getDefault()); + } + } + + return result; + } + + private int getField(String[] values) + { + int result = 0; + String field = values[0]; + + if (MONTH.equals(field) == true) + { + result = Calendar.MONTH; + } + else if (YEAR.equals(field) == true) + { + result = Calendar.YEAR; + } + else + { + throw new AlfrescoRuntimeException("Date component " + field + " is not supported by parameter substitution."); + } + + return result; + } + + private int getStyle(String[] values) + { + int result = Calendar.SHORT; + + if (values.length == 2) + { + String style = values[1]; + if (LONG.equals(style) == true) + { + result = Calendar.LONG; + } + else if (SHORT.equals(style) == true) + { + result = Calendar.SHORT; + } + else + { + throw new AlfrescoRuntimeException("Style component " + style + " is not supported by parameter substitution."); + } + } + + return result; + } +} diff --git a/rm-server/source/java/org/alfresco/repo/action/parameter/MessageParameterProcessor.java b/rm-server/source/java/org/alfresco/repo/action/parameter/MessageParameterProcessor.java new file mode 100644 index 0000000000..9e954ed2ec --- /dev/null +++ b/rm-server/source/java/org/alfresco/repo/action/parameter/MessageParameterProcessor.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005-2013 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.action.parameter; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.springframework.extensions.surf.util.I18NUtil; + +/** + * Message parameter processor. + * + * @author Roy Wetherall + * @since 2.1 + */ +public class MessageParameterProcessor extends ParameterProcessor +{ + /** + * @see org.alfresco.repo.action.parameter.ParameterProcessor#process(java.lang.String, org.alfresco.service.cmr.repository.NodeRef) + */ + @Override + public String process(String value, NodeRef actionedUponNodeRef) + { + // the default position is to return the value un-changed + String result = value; + + // strip the processor name from the value + value = stripName(value); + if (value.isEmpty() == false) + { + result = I18NUtil.getMessage(value); + if (result == null) + { + throw new AlfrescoRuntimeException("The message parameter processor could not resolve the message for the id " + value); + } + } + + return result; + } +} diff --git a/rm-server/source/java/org/alfresco/repo/action/parameter/NodeParameterProcessor.java b/rm-server/source/java/org/alfresco/repo/action/parameter/NodeParameterProcessor.java new file mode 100644 index 0000000000..d5fa6a2135 --- /dev/null +++ b/rm-server/source/java/org/alfresco/repo/action/parameter/NodeParameterProcessor.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2005-2013 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.action.parameter; + +import java.io.Serializable; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.apache.commons.lang.ArrayUtils; + +/** + * Node parameter processor. + * + * @author Roy Wetherall + * @since 2.1 + */ +public class NodeParameterProcessor extends ParameterProcessor +{ + /** Supported data types */ + private QName[] supportedDataTypes = + { + DataTypeDefinition.TEXT, + DataTypeDefinition.BOOLEAN, + DataTypeDefinition.DATE, + DataTypeDefinition.DATETIME, + DataTypeDefinition.DOUBLE, + DataTypeDefinition.FLOAT, + DataTypeDefinition.INT + }; + + /** Node service */ + private NodeService nodeService; + + /** Namespace service */ + private NamespaceService namespaceService; + + /** Dictionary service */ + private DictionaryService dictionaryService; + + /** + * @param nodeService node service + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * @param namespaceService namespace service + */ + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + /** + * @param dictionaryService dictionary service + */ + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + + /** + * @see org.alfresco.repo.action.parameter.ParameterProcessor#process(java.lang.String, org.alfresco.service.cmr.repository.NodeRef) + */ + @Override + public String process(String value, NodeRef actionedUponNodeRef) + { + // the default position is to return the value un-changed + String result = value; + + // strip the processor name from the value + value = stripName(value); + if (value.isEmpty() == false) + { + QName qname = QName.createQName(value, namespaceService); + + PropertyDefinition propertyDefinition = dictionaryService.getProperty(qname); + if (propertyDefinition == null) + { + throw new AlfrescoRuntimeException("The property " + value + " does not have a property definition."); + } + + QName type = propertyDefinition.getDataType().getName(); + if (ArrayUtils.contains(supportedDataTypes, type) == true) + { + Serializable propertyValue = nodeService.getProperty(actionedUponNodeRef, qname); + result = propertyValue.toString(); + } + else + { + throw new AlfrescoRuntimeException("The property " + value + " is of type " + type.toString() + " which is not supported by parameter substitution."); + } + } + + return result; + } +} diff --git a/rm-server/source/java/org/alfresco/repo/action/parameter/ParameterProcessor.java b/rm-server/source/java/org/alfresco/repo/action/parameter/ParameterProcessor.java new file mode 100644 index 0000000000..47b01f7fa5 --- /dev/null +++ b/rm-server/source/java/org/alfresco/repo/action/parameter/ParameterProcessor.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2005-2013 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.action.parameter; + +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Abstract parameter processor implementation. + * + * @author Roy Wetherall + * @since 2.1 + */ +public abstract class ParameterProcessor +{ + /** Processor name */ + private String name; + + /** Parameter processor component */ + private ParameterProcessorComponent parameterProcessorComponent; + + /** + * @return parameter processor name + */ + public String getName() + { + return name; + } + + /** + * @param name parameter processor name + */ + public void setName(String name) + { + this.name = name; + } + + /** + * @param parameterProcessorComponent parameter processor component + */ + public void setParameterProcessorComponent(ParameterProcessorComponent parameterProcessorComponent) + { + this.parameterProcessorComponent = parameterProcessorComponent; + } + + /** + * Init method + */ + public void init() + { + parameterProcessorComponent.register(this); + } + + /** + * Process the parameter value. + * + * @param value substitution value + * @param actionedUponNodeRef actioned upon node reference + * @return String processed string, original string if subs string invalid + */ + public abstract String process(String value, NodeRef actionedUponNodeRef); + + /** + * Strips the name of the processor from the subs value. + * + * @param value subs value + * @return String subs value with the name and '.' delimiter removed + */ + protected String stripName(String value) + { + String result = ""; + String[] values = value.split("\\.", 2); + if (values.length == 2) + { + result = values[1]; + } + return result; + } +} diff --git a/rm-server/source/java/org/alfresco/repo/action/parameter/ParameterProcessorComponent.java b/rm-server/source/java/org/alfresco/repo/action/parameter/ParameterProcessorComponent.java new file mode 100644 index 0000000000..e58bfa3bdb --- /dev/null +++ b/rm-server/source/java/org/alfresco/repo/action/parameter/ParameterProcessorComponent.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2005-2013 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.action.parameter; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.cmr.action.ParameterDefinition; +import org.alfresco.service.cmr.action.ParameterizedItem; +import org.alfresco.service.cmr.action.ParameterizedItemDefinition; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * + * + * @author Roy Wetherall + * @since 2.1 + */ +public class ParameterProcessorComponent +{ + private static final String REG_EX = "\\$\\{([^\\$\\{]+)\\}"; + + private Map processors = new HashMap(5); + + /** + * + * @param processor + */ + public void register(ParameterProcessor processor) + { + this.processors.put(processor.getName(), processor); + } + + /** + * + * @param ruleItem + * @param ruleItemDefinition + * @param actionedUponNodeRef + */ + public void process(ParameterizedItem ruleItem, ParameterizedItemDefinition ruleItemDefinition, NodeRef actionedUponNodeRef) + { + for (Map.Entry entry : ruleItem.getParameterValues().entrySet()) + { + String parameterName = entry.getKey(); + + // get the parameter definition + ParameterDefinition def = ruleItemDefinition.getParameterDefintion(parameterName); + if (def != null) + { + if (DataTypeDefinition.TEXT.equals(def.getType()) == true) + { + String parameterValue = (String)entry.getValue(); + + // match the substitution pattern + Pattern patt = Pattern.compile(REG_EX); + Matcher m = patt.matcher(parameterValue); + StringBuffer sb = new StringBuffer(parameterValue.length()); + + while (m.find()) + { + String text = m.group(1); + + // lookup parameter processor to use + ParameterProcessor processor = lookupProcessor(text); + if (processor == null) + { + throw new AlfrescoRuntimeException("A parameter processor has not been found for the substitution string " + text); + } + else + { + // process each substitution value + text = processor.process(text, actionedUponNodeRef); + } + + // append new value + m.appendReplacement(sb, Matcher.quoteReplacement(text)); + } + m.appendTail(sb); + + // set the updated parameter value + ruleItem.setParameterValue(parameterName, sb.toString()); + } + } + } + } + + private ParameterProcessor lookupProcessor(String value) + { + ParameterProcessor result = null; + + if (value != null && value.isEmpty() == false) + { + String[] values = value.split("\\.", 2); + if (values.length != 0) + { + // get the processor from the registered map + result = processors.get(values[0]); + } + } + + return result; + } +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/action/FileToActionTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/action/FileToActionTest.java index f23b2babf9..4cdf2505b5 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/action/FileToActionTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/action/FileToActionTest.java @@ -47,6 +47,8 @@ public class FileToActionTest extends BaseRMTestCase private static final String PATH_BAD = "monkey/rmfolder"; private static final String PATH_CREATE = "rmcontainer/newrmfolder"; + private static final String PATH_SUB1 = "rmcontainer/${node.name}"; + protected ActionService dmActionService; @Override @@ -70,24 +72,7 @@ public class FileToActionTest extends BaseRMTestCase public void testFileToNodeRef() { - doTestInTransaction(new Test() - { - public Void run() - { - // create record from document - recordService.createRecord(filePlan, dmDocument); - - // check things have gone according to plan - assertTrue(recordService.isRecord(dmDocument)); - assertFalse(recordService.isFiled(dmDocument)); - - // is the unfiled container the primary parent of the filed record - NodeRef parent = nodeService.getPrimaryParent(dmDocument).getParentRef(); - assertEquals(filePlanService.getUnfiledContainer(filePlan), parent); - - return null; - } - }, dmCollaborator); + initRecord(); doTestInTransaction(new Test() { @@ -118,14 +103,13 @@ public class FileToActionTest extends BaseRMTestCase return null; } - }, rmAdminName); - + }, rmAdminName); } - public void testFileToPath() + private void initRecord() { doTestInTransaction(new Test() - { + { public Void run() { // create record from document @@ -142,6 +126,11 @@ public class FileToActionTest extends BaseRMTestCase return null; } }, dmCollaborator); + } + + public void testFileToPath() + { + initRecord(); doTestInTransaction(new Test() { @@ -169,24 +158,7 @@ public class FileToActionTest extends BaseRMTestCase public void testFileToPath2() { - doTestInTransaction(new Test() - { - public Void run() - { - // create record from document - recordService.createRecord(filePlan, dmDocument); - - // check things have gone according to plan - assertTrue(recordService.isRecord(dmDocument)); - assertFalse(recordService.isFiled(dmDocument)); - - // is the unfiled container the primary parent of the filed record - NodeRef parent = nodeService.getPrimaryParent(dmDocument).getParentRef(); - assertEquals(filePlanService.getUnfiledContainer(filePlan), parent); - - return null; - } - }, dmCollaborator); + initRecord(); doTestInTransaction(new Test() { @@ -214,38 +186,36 @@ public class FileToActionTest extends BaseRMTestCase public void testCreate() throws Exception { - doTestInTransaction(new Test() - { - public Void run() - { - // create record from document - recordService.createRecord(filePlan, dmDocument); - - // check things have gone according to plan - assertTrue(recordService.isRecord(dmDocument)); - assertFalse(recordService.isFiled(dmDocument)); - - // is the unfiled container the primary parent of the filed record - NodeRef parent = nodeService.getPrimaryParent(dmDocument).getParentRef(); - assertEquals(filePlanService.getUnfiledContainer(filePlan), parent); - - return null; - } - }, dmCollaborator); - + initRecord(); + createRecord(PATH_CREATE, "newrmfolder"); + } + + public void testCreateSub() throws Exception + { + initRecord(); + createRecord(PATH_SUB1, "collabDocument.txt", "rmcontainer/collabDocument.txt"); + } + + private void createRecord(String path, String name) + { + createRecord(path, name, path); + } + + private void createRecord(final String path, final String name, final String resolvedPath) + { doTestInTransaction(new Test() { public Void run() throws Exception { - String[] pathValues = StringUtils.tokenizeToStringArray(PATH_CREATE, "/"); + String[] pathValues = StringUtils.tokenizeToStringArray(resolvedPath, "/"); - // show the folder doesn' exist to begin with + // show the folder doesn't exist to begin with FileInfo createdRecordFolder = fileFolderService.resolveNamePath(filePlan, new ArrayList(Arrays.asList(pathValues)), false); assertNull(createdRecordFolder); // set parameters Map params = new HashMap(1); - params.put(FileToAction.PARAM_PATH, PATH_CREATE); + params.put(FileToAction.PARAM_PATH, path); params.put(FileToAction.PARAM_CREATE_RECORD_FOLDER, true); // execute file-to action @@ -254,7 +224,7 @@ public class FileToActionTest extends BaseRMTestCase // show the folder has now been created createdRecordFolder = fileFolderService.resolveNamePath(filePlan, new ArrayList(Arrays.asList(pathValues)), false); assertNotNull(createdRecordFolder); - assertEquals("newrmfolder", createdRecordFolder.getName()); + assertEquals(name, createdRecordFolder.getName()); NodeRef createdRecordFolderNodeRef = createdRecordFolder.getNodeRef(); // check things have gone according to plan @@ -268,7 +238,6 @@ public class FileToActionTest extends BaseRMTestCase return null; } }, rmAdminName); - } public void failureTests() throws Exception diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/ExtendedActionServiceTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/ExtendedActionServiceTest.java index 3221803611..423f60e98f 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/ExtendedActionServiceTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/ExtendedActionServiceTest.java @@ -21,6 +21,8 @@ package org.alfresco.module.org_alfresco_module_rm.test.service; import java.util.List; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.module.org_alfresco_module_rm.test.util.TestActionPropertySubs; +import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ActionDefinition; import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.security.PermissionService; @@ -142,4 +144,29 @@ public class ExtendedActionServiceTest extends BaseRMTestCase return result; } + + public void testActionPropertySubstitution() throws Exception + { + doTestInTransaction(new Test() + { + public Void run() + { + Action action = dmActionService.createAction(TestActionPropertySubs.NAME); + + action.setParameterValue("longMonth", "${date.month.long}"); + action.setParameterValue("shortMonth", "${date.month}"); + action.setParameterValue("year", "${date.year}"); + + action.setParameterValue("name", "${node.cm:name}"); + + action.setParameterValue("company", "${message.test.company}"); + + action.setParameterValue("combo", "${date.year}/${date.month.short}/${node.cm:name}-${message.test.company}.txt"); + + dmActionService.executeAction(action, rmFolder); + + return null; + } + }); + } } diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/TestActionParams.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/TestActionParams.java index 4c61d9a542..4ae2342ce3 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/TestActionParams.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/TestActionParams.java @@ -34,7 +34,7 @@ public class TestActionParams extends RMActionExecuterAbstractBase Object dateValue = action.getParameterValue(PARAM_DATE); if ((dateValue instanceof java.util.Date) == false) { - throw new AlfrescoRuntimeException("Param we not a Date as expected."); + throw new AlfrescoRuntimeException("Param was not a Date as expected."); } - } + } } diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/TestActionPropertySubs.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/TestActionPropertySubs.java new file mode 100644 index 0000000000..2d93d90e0e --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/TestActionPropertySubs.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005-2011 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.module.org_alfresco_module_rm.test.util; + +import java.util.Calendar; +import java.util.List; +import java.util.Locale; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase; +import org.alfresco.repo.action.ParameterDefinitionImpl; +import org.alfresco.service.cmr.action.Action; +import org.alfresco.service.cmr.action.ParameterDefinition; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.repository.NodeRef; +import org.springframework.extensions.surf.util.I18NUtil; + +public class TestActionPropertySubs extends RMActionExecuterAbstractBase +{ + public static final String NAME = "testActionPropertySubs"; + + @Override + protected void addParameterDefinitions(List paramList) + { + paramList.add(new ParameterDefinitionImpl("shortMonth", DataTypeDefinition.TEXT, false, "")); + paramList.add(new ParameterDefinitionImpl("longMonth", DataTypeDefinition.TEXT, false, "")); + paramList.add(new ParameterDefinitionImpl("year", DataTypeDefinition.TEXT, false, "")); + paramList.add(new ParameterDefinitionImpl("name", DataTypeDefinition.TEXT, false, "")); + paramList.add(new ParameterDefinitionImpl("company", DataTypeDefinition.TEXT, false, "")); + paramList.add(new ParameterDefinitionImpl("combo", DataTypeDefinition.TEXT, false, "")); + } + + @Override + protected void executeImpl(Action action, NodeRef actionedUponNodeRef) + { + Calendar myToday = Calendar.getInstance(); + + String shortMonth = myToday.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault()); + String longMonth = myToday.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault()); + String year = Integer.toString(myToday.get(Calendar.YEAR)); + String name = (String)nodeService.getProperty(actionedUponNodeRef, ContentModel.PROP_NAME); + String company = I18NUtil.getMessage("test.company"); + + assertEquals(shortMonth, (String)action.getParameterValue("shortMonth")); + assertEquals(longMonth, (String)action.getParameterValue("longMonth")); + assertEquals(year, (String)action.getParameterValue("year")); + assertEquals(name, (String)action.getParameterValue("name")); + assertEquals(company, (String)action.getParameterValue("company")); + assertEquals(year + "/" + shortMonth + "/" + name + "-" + company +".txt", (String)action.getParameterValue("combo")); + } + + private void assertEquals(String expected, String actual) + { + if (expected.equals(actual) == false) + { + throw new AlfrescoRuntimeException("Expected value " + expected + " does not match actual value " + actual); + } + } +} diff --git a/rm-server/test/resources/test-context.xml b/rm-server/test/resources/test-context.xml index 606232ce30..2b85c6d225 100644 --- a/rm-server/test/resources/test-context.xml +++ b/rm-server/test/resources/test-context.xml @@ -4,13 +4,23 @@ - + test-model.xml + + + + + + + test + + + @@ -19,6 +29,7 @@ + @@ -27,12 +38,23 @@ + + + + + + + + + + + diff --git a/rm-server/test/resources/test.properties b/rm-server/test/resources/test.properties new file mode 100644 index 0000000000..171c908c91 --- /dev/null +++ b/rm-server/test/resources/test.properties @@ -0,0 +1 @@ +test.company=Alfresco \ No newline at end of file