diff --git a/build.xml b/build.xml index 326ea9708b..9b1a065d48 100644 --- a/build.xml +++ b/build.xml @@ -114,4 +114,7 @@ - \ No newline at end of file + + + + diff --git a/rm-server/build.xml b/rm-server/build.xml index 85e3ad8c55..d4ecc2401f 100644 --- a/rm-server/build.xml +++ b/rm-server/build.xml @@ -1,28 +1,29 @@ - + - - - - + + + + - - - - - - - - - - + + + + + + + + + + - - - - - + + + + + + + - \ No newline at end of file diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/messages/actions.properties b/rm-server/config/alfresco/module/org_alfresco_module_rm/messages/actions.properties index 3a8f03b462..1d32068d9c 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/messages/actions.properties +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/messages/actions.properties @@ -78,7 +78,7 @@ unfreeze.description=Unfreezes a record. fileTo.title=File to fileTo.description=Files a record to the specified record folder. fileTo.path.display-label=Path to Record Folder -fileTo.createRecordFolder.display-label=Create Record Folder +fileTo.createRecordPath.display-label=Create Record Path # Reject reject.title=Reject reject.description=Rejects a record and moves the document to its original location diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml index 4d964f0686..9d786a52df 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml @@ -566,4 +566,11 @@ + + + + + \ No newline at end of file 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 e2ccffcc00..9a88255d2c 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 @@ -15,6 +15,7 @@ import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.search.CategoryService; import org.apache.commons.lang.ArrayUtils; import org.springframework.util.StringUtils; @@ -32,14 +33,14 @@ public class FileToAction extends RMActionExecuterAbstractBase /** action parameters */ public static final String PARAM_DESTINATION_RECORD_FOLDER = "destinationRecordFolder"; public static final String PARAM_PATH = "path"; - public static final String PARAM_CREATE_RECORD_FOLDER = "createRecordFolder"; + public static final String PARAM_CREATE_RECORD_PATH = "createRecordPath"; /** file folder service */ private FileFolderService fileFolderService; /** file plan service */ private FilePlanService filePlanService; - + /** * @param fileFolderService file folder service */ @@ -63,7 +64,7 @@ public class FileToAction extends RMActionExecuterAbstractBase protected void addParameterDefinitions(List paramList) { paramList.add(new ParameterDefinitionImpl(PARAM_PATH, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_PATH))); - paramList.add(new ParameterDefinitionImpl(PARAM_CREATE_RECORD_FOLDER, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_CREATE_RECORD_FOLDER))); + paramList.add(new ParameterDefinitionImpl(PARAM_CREATE_RECORD_PATH, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_CREATE_RECORD_PATH))); } /** @@ -141,7 +142,7 @@ public class FileToAction extends RMActionExecuterAbstractBase // look for the creation strategy boolean create = false; - Boolean createValue = (Boolean)action.getParameterValue(PARAM_CREATE_RECORD_FOLDER); + Boolean createValue = (Boolean)action.getParameterValue(PARAM_CREATE_RECORD_PATH); if (createValue != null) { create = createValue.booleanValue(); @@ -155,7 +156,7 @@ public class FileToAction extends RMActionExecuterAbstractBase if (create == true) { // get the parent into which we are going to create the new record folder - NodeRef parent = resolveParent(context, pathValues); + NodeRef parent = resolveParent(context, pathValues, create); if (parent == null) { throw new AlfrescoRuntimeException("Unable to create new record folder, because destination parent could not be found."); @@ -187,12 +188,43 @@ public class FileToAction extends RMActionExecuterAbstractBase * @return */ private NodeRef resolvePath(final NodeRef context, final String[] pathValues) + { + return resolvePath(context, pathValues, false); + } + + /** + * + * @param context + * @param pathValues + * @param create Create any missing path elements + * @return + */ + private NodeRef resolvePath(final NodeRef context, final String[] pathValues, boolean create) { NodeRef result = null; FileInfo fileInfo = null; try { - fileInfo = fileFolderService.resolveNamePath(context, new ArrayList(Arrays.asList(pathValues)), false); + List pathValueList = new ArrayList(Arrays.asList(pathValues)); + fileInfo = fileFolderService.resolveNamePath(context, pathValueList, false); + if((fileInfo == null) && create) + { + NodeRef parent = this.filePlanService.getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID); + for(int i = 1; i <= pathValueList.size(); i++) + { + List partialPathValueList = pathValueList.subList(0, i); + fileInfo = fileFolderService.resolveNamePath(context, partialPathValueList, false); + if(fileInfo == null) + { + parent = this.filePlanService.createRecordCategory(parent, partialPathValueList.get(partialPathValueList.size() - 1)); + } + else + { + parent = fileInfo.getNodeRef(); + } + } + result = parent; + } } catch (FileNotFoundException e) { @@ -212,6 +244,18 @@ public class FileToAction extends RMActionExecuterAbstractBase * @return */ private NodeRef resolveParent(NodeRef context, String[] pathValues) + { + return resolveParent(context, pathValues, false); + } + + /** + * + * @param context + * @param pathValues + * @param create Create any missing path elements + * @return + */ + private NodeRef resolveParent(NodeRef context, String[] pathValues, boolean create) { NodeRef result = null; @@ -229,7 +273,7 @@ public class FileToAction extends RMActionExecuterAbstractBase else { pathValues = (String[])ArrayUtils.remove(pathValues, pathValues.length-1); - result = resolvePath(context, pathValues); + result = resolvePath(context, pathValues, create); } return result; 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 index 45eb13f38f..3810258297 100644 --- a/rm-server/source/java/org/alfresco/repo/action/parameter/DateParameterProcessor.java +++ b/rm-server/source/java/org/alfresco/repo/action/parameter/DateParameterProcessor.java @@ -19,7 +19,9 @@ package org.alfresco.repo.action.parameter; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.service.cmr.repository.NodeRef; @@ -30,7 +32,7 @@ import org.alfresco.service.cmr.repository.NodeRef; * @author Roy Wetherall * @since 2.1 */ -public class DateParameterProcessor extends ParameterProcessor +public class DateParameterProcessor extends ParameterProcessor implements ParameterSubstitutionSuggester { private static final String DAY = "day"; private static final String WEEK = "week"; @@ -39,6 +41,27 @@ public class DateParameterProcessor extends ParameterProcessor private static final String SHORT = "short"; private static final String LONG = "long"; private static final String NUMBER = "number"; + + private static final String SEP = "."; + + private static final String[] ALL_FIELDS_FOR_SUBSTITUTION_QUERY = { + DAY, + DAY + SEP + SHORT, + DAY + SEP + LONG, + DAY + SEP + NUMBER, + WEEK, + WEEK + SEP + SHORT, + WEEK + SEP + LONG, + WEEK + SEP + NUMBER, + MONTH, + MONTH + SEP + SHORT, + MONTH + SEP + LONG, + MONTH + SEP + NUMBER, + YEAR, + YEAR + SEP + SHORT, + YEAR + SEP + LONG, + YEAR + SEP + NUMBER + }; /** * @see org.alfresco.repo.action.parameter.ParameterProcessor#process(java.lang.String, org.alfresco.service.cmr.repository.NodeRef) @@ -172,4 +195,28 @@ public class DateParameterProcessor extends ParameterProcessor return style; } + + @Override + public List getSubstitutionSuggestions(String substitutionFragment) + { + List suggestions = new ArrayList(); + String namePrefix = this.getName() + "."; + if(this.getName().toLowerCase().contains(substitutionFragment.toLowerCase())) + { + for(String field: ALL_FIELDS_FOR_SUBSTITUTION_QUERY) { + suggestions.add(namePrefix + field); + } + } + else + { + for(String field: ALL_FIELDS_FOR_SUBSTITUTION_QUERY) { + String prefixFieldName = namePrefix + field; + if(prefixFieldName.toLowerCase().contains(substitutionFragment.toLowerCase())) + { + suggestions.add(namePrefix + field); + } + } + } + return suggestions; + } } 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 index dff8451d11..91e28c0afa 100644 --- a/rm-server/source/java/org/alfresco/repo/action/parameter/ParameterProcessorComponent.java +++ b/rm-server/source/java/org/alfresco/repo/action/parameter/ParameterProcessorComponent.java @@ -19,7 +19,9 @@ package org.alfresco.repo.action.parameter; import java.io.Serializable; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -28,6 +30,7 @@ import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.service.cmr.action.ParameterizedItem; import org.alfresco.service.cmr.action.ParameterizedItemDefinition; import org.alfresco.service.cmr.repository.NodeRef; +import org.apache.commons.lang.StringUtils; /** * Parameter processor component @@ -35,13 +38,15 @@ import org.alfresco.service.cmr.repository.NodeRef; * @author Roy Wetherall * @since 2.1 */ -public class ParameterProcessorComponent +public class ParameterProcessorComponent implements ParameterSubstitutionSuggester { /** regex used to parse parameters */ - private static final String REG_EX = "\\$\\{([^\\$\\{]+)\\}"; + private static final String REG_EX_OLD = "\\$\\{([^\\$\\{]+)\\}"; + private static final String REG_EX = "\\{([^\\{]+)\\}"; /** registry of parameter processors */ private Map processors = new HashMap(5); + private List subtitutionSuggesterProcessors = new ArrayList(5); /** * Register parameter processor @@ -51,6 +56,10 @@ public class ParameterProcessorComponent public void register(ParameterProcessor processor) { this.processors.put(processor.getName(), processor); + if(processor instanceof ParameterSubstitutionSuggester) + { + this.subtitutionSuggesterProcessors.add((ParameterSubstitutionSuggester)processor); + } } /** @@ -83,9 +92,14 @@ public class ParameterProcessorComponent * @return String resulting value */ public String process(String value, NodeRef nodeRef) + { + return process(process(value, nodeRef, REG_EX_OLD), nodeRef, REG_EX); + } + + public String process(String value, NodeRef nodeRef, String regExp) { // match the substitution pattern - Pattern patt = Pattern.compile(REG_EX); + Pattern patt = Pattern.compile(regExp); Matcher m = patt.matcher(value); StringBuffer sb = new StringBuffer(value.length()); @@ -112,6 +126,25 @@ public class ParameterProcessorComponent return sb.toString(); } + /** + * Return a list of substitution suggestions for the passed string fragment. + * + * @param subtitutionFragment Text fragment to search on. + * @return A list of substitutions that match the substitution fragment. + */ + public List getSubstitutionSuggestions(final String substitutionFragment) + { + List suggestions = new ArrayList(); + if (StringUtils.isNotBlank(substitutionFragment)) + { + for (ParameterSubstitutionSuggester suggestor : this.subtitutionSuggesterProcessors) + { + suggestions.addAll(suggestor.getSubstitutionSuggestions(substitutionFragment.toLowerCase())); + } + } + return suggestions; + } + /** * Look up parameter processor * diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/AllTestSuite.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/AllTestSuite.java index 0a3a9e7273..897357ab5f 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/AllTestSuite.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/AllTestSuite.java @@ -18,6 +18,7 @@ */ package org.alfresco.module.org_alfresco_module_rm.test; +import org.alfresco.repo.ParameterProcessorTestSuite; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @@ -36,7 +37,8 @@ import org.junit.runners.Suite.SuiteClasses; CapabilitiesTestSuite.class, ServicesTestSuite.class, WebScriptTestSuite.class, - IssueTestSuite.class + IssueTestSuite.class, + ParameterProcessorTestSuite.class }) public class AllTestSuite { diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/WebScriptTestSuite.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/WebScriptTestSuite.java index cb3163fbc5..0c8cc7289a 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/WebScriptTestSuite.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/WebScriptTestSuite.java @@ -31,6 +31,7 @@ import org.alfresco.module.org_alfresco_module_rm.test.webscript.RmAuthoritiesRe import org.alfresco.module.org_alfresco_module_rm.test.webscript.RmClassesRestApiTest; import org.alfresco.module.org_alfresco_module_rm.test.webscript.RmPropertiesRestApiTest; import org.alfresco.module.org_alfresco_module_rm.test.webscript.RoleRestApiTest; +import org.alfresco.repo.web.scripts.SubstitutionSuggestionsRestApiTest; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @@ -56,7 +57,8 @@ import org.junit.runners.Suite.SuiteClasses; ActionDefinitionsRestApiTest.class, RmClassesRestApiTest.class, RmPropertiesRestApiTest.class, - RmAuthoritiesRestApiTest.class + RmAuthoritiesRestApiTest.class, + SubstitutionSuggestionsRestApiTest.class }) public class WebScriptTestSuite { 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 e540e905b7..e0456dec54 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 @@ -46,6 +46,7 @@ public class FileToActionTest extends BaseRMTestCase private static final String PATH2 = "/rmcontainer/rmfolder"; private static final String PATH_BAD = "monkey/rmfolder"; private static final String PATH_CREATE = "rmcontainer/newrmfolder"; + private static final String LONG_PATH_CREATE = "/rmcontainer/one/two/three/four/newrmfolder"; private static final String PATH_SUB1 = "rmcontainer/${node.cm:title}"; @@ -189,6 +190,12 @@ public class FileToActionTest extends BaseRMTestCase createRecord(PATH_SUB1, "mytestvalue", "rmcontainer/mytestvalue"); } + public void testCreatePath() throws Exception + { + initRecord(); + createRecord(LONG_PATH_CREATE, "newrmfolder", "rmcontainer/one/two/three/four/newrmfolder"); + } + private void createRecord(String path, String name) { createRecord(path, name, path); @@ -209,7 +216,7 @@ public class FileToActionTest extends BaseRMTestCase // set parameters Map params = new HashMap(1); params.put(FileToAction.PARAM_PATH, path); - params.put(FileToAction.PARAM_CREATE_RECORD_FOLDER, true); + params.put(FileToAction.PARAM_CREATE_RECORD_PATH, true); // execute file-to action rmActionService.executeRecordsManagementAction(dmDocument, FileToAction.NAME, params);