diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionConstraint.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionConstraint.get.desc.xml new file mode 100755 index 0000000000..f370fc815a --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionConstraint.get.desc.xml @@ -0,0 +1,8 @@ + + Action Constraint Resource + Get action constraint + /api/actionConstraints/{name} + argument + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionConstraint.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionConstraint.get.json.ftl new file mode 100755 index 0000000000..b77cd9a87b --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionConstraint.get.json.ftl @@ -0,0 +1,6 @@ +<#import "rule.lib.ftl" as ruleLib/> + +{ + "data" : + <@ruleLib.actionConstraintJSON actionConstraint=actionConstraint /> +} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionConstraints.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionConstraints.get.desc.xml new file mode 100755 index 0000000000..18147ce311 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionConstraints.get.desc.xml @@ -0,0 +1,8 @@ + + Action Constraint Collection Resource + Get action constraints collection. + /api/actionConstraints?name={name?} + argument + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionConstraints.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionConstraints.get.json.ftl new file mode 100755 index 0000000000..3756174cc1 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionConstraints.get.json.ftl @@ -0,0 +1,11 @@ +<#import "rule.lib.ftl" as ruleLib/> + +{ + "data" : + [ + <#list actionConstraints as actionConstraint> + <@ruleLib.actionConstraintJSON actionConstraint=actionConstraint /> + <#if actionConstraint_has_next>, + + ] +} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionQueue.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionQueue.post.desc.xml new file mode 100755 index 0000000000..cc4ece7f92 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionQueue.post.desc.xml @@ -0,0 +1,8 @@ + + Post Action Queue + Adds a new action to the execution queue. + /api/actionQueue?async={async?} + argument + user + required + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionQueue.post.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionQueue.post.json.ftl new file mode 100755 index 0000000000..2dd9bfb91b --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionQueue.post.json.ftl @@ -0,0 +1,21 @@ +{ + "data" : + { + "status" : "${actionExecStatus}", + "actionedUponNode" : "${actionedUponNode?string}", + <#if exception??> + "exception" : + { + "message" : "${exception.message}", + "stackTrace" : + [ + <#list exception.stackTrace as stackTraceElement> + "${stackTraceElement?string}"<#if stackTraceElement_has_next>, + + ] + }, + + "action" : + ${action?string} + } +} \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionconditiondefinitions.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionconditiondefinitions.get.json.ftl index 2be8802a41..15129b1186 100755 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionconditiondefinitions.get.json.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionconditiondefinitions.get.json.ftl @@ -15,6 +15,9 @@ "name" : "${jsonUtils.encodeJSONString(parameterDefinition.name)}", "displayLabel" : <#if parameterDefinition.displayLabel??>"${jsonUtils.encodeJSONString(parameterDefinition.displayLabel)}"<#else>null, "type" : "${shortQName(parameterDefinition.type)}", + <#if parameterDefinition.parameterConstraintName??> + "constraint" : "${jsonUtils.encodeJSONString(parameterDefinition.parameterConstraintName)}", + "isMultiValued" : ${parameterDefinition.multiValued?string}, "isMandatory" : ${parameterDefinition.mandatory?string} }<#if (parameterDefinition_has_next)>, diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actiondefinitions.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actiondefinitions.get.json.ftl index 01abba521a..23662f9a4b 100755 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actiondefinitions.get.json.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actiondefinitions.get.json.ftl @@ -15,6 +15,9 @@ "name" : "${jsonUtils.encodeJSONString(parameterDefinition.name)}", "displayLabel" : <#if parameterDefinition.displayLabel??>"${jsonUtils.encodeJSONString(parameterDefinition.displayLabel)}"<#else>null, "type" : "${shortQName(parameterDefinition.type)}", + <#if parameterDefinition.parameterConstraintName??> + "constraint" : "${jsonUtils.encodeJSONString(parameterDefinition.parameterConstraintName)}", + "isMultiValued" : ${parameterDefinition.multiValued?string}, "isMandatory" : ${parameterDefinition.mandatory?string} }<#if (parameterDefinition_has_next)>, diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.lib.ftl index 4d0768817c..b4174458a5 100755 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.lib.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.lib.ftl @@ -102,4 +102,25 @@ <#if (parameterValue_has_next)>, + + +<#-- renders a action constraint object --> +<#macro actionConstraintJSON actionConstraint> +<#escape x as jsonUtils.encodeJSONString(x)> + { + "name" : "${actionConstraint.name}", + <#if actionConstraint.allowableValues?? && actionConstraint.allowableValues?size > 0> + "values" : + [ + <#list actionConstraint.allowableValues?keys as allowableValue> + <#assign val = actionConstraint.allowableValues[allowableValue]> + { + "value" : "${allowableValue}", + "displayLabel" : "${val}" + }<#if allowableValue_has_next>, + + ] + + } + \ No newline at end of file diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 35d5398403..2f9de5d7b8 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -617,4 +617,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/rule/AbstractRuleWebScript.java b/source/java/org/alfresco/repo/web/scripts/rule/AbstractRuleWebScript.java index c0816de7d0..3ae87ef6bd 100755 --- a/source/java/org/alfresco/repo/web/scripts/rule/AbstractRuleWebScript.java +++ b/source/java/org/alfresco/repo/web/scripts/rule/AbstractRuleWebScript.java @@ -24,7 +24,10 @@ */ package org.alfresco.repo.web.scripts.rule; +import java.io.Serializable; +import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -32,18 +35,31 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.servlet.http.HttpServletResponse; +import org.alfresco.repo.action.ActionConditionImpl; +import org.alfresco.repo.action.ActionImpl; +import org.alfresco.repo.action.CompositeActionImpl; +import org.alfresco.service.cmr.action.Action; +import org.alfresco.service.cmr.action.ActionCondition; import org.alfresco.service.cmr.action.ActionConditionDefinition; import org.alfresco.service.cmr.action.ActionDefinition; import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.action.ParameterDefinition; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.cmr.rule.Rule; import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import org.alfresco.util.GUID; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.springframework.extensions.webscripts.DeclarativeWebScript; +import org.springframework.extensions.webscripts.Status; import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.extensions.webscripts.WebScriptRequest; @@ -210,4 +226,218 @@ public abstract class AbstractRuleWebScript extends DeclarativeWebScript return result; } + + protected Rule parseJsonRule(JSONObject jsonRule) throws JSONException + { + Rule result = new Rule(); + + if (jsonRule.has("title") == false || jsonRule.getString("title").length() == 0) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, + "Title missing when creating rule"); + } + + result.setTitle(jsonRule.getString("title")); + + result.setDescription(jsonRule.has("description") ? jsonRule.getString("description") : ""); + + if (jsonRule.has("ruleType") == false || jsonRule.getJSONArray("ruleType").length() == 0) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, + "Rule type missing when creating rule"); + } + + JSONArray types = jsonRule.getJSONArray("ruleType"); + List ruleTypes = new ArrayList(); + + for (int i = 0; i < types.length(); i++) + { + ruleTypes.add(types.getString(i)); + } + + result.setRuleTypes(ruleTypes); + + result.applyToChildren(jsonRule.has("applyToChildren") ? jsonRule.getBoolean("applyToChildren") : false); + + result.setExecuteAsynchronously(jsonRule.has("executeAsynchronously") ? jsonRule.getBoolean("executeAsynchronously") : false); + + result.setRuleDisabled(jsonRule.has("disabled") ? jsonRule.getBoolean("disabled") : false); + + JSONObject jsonAction = jsonRule.getJSONObject("action"); + + // parse action object + Action ruleAction = parseJsonAction(jsonAction); + + result.setAction(ruleAction); + + return result; + } + + protected ActionImpl parseJsonAction(JSONObject jsonAction) throws JSONException + { + ActionImpl result = null; + + String actionId = jsonAction.has("id") ? jsonAction.getString("id") : GUID.generate(); + + if (jsonAction.getString("actionDefinitionName").equalsIgnoreCase("composite-action")) + { + result = new CompositeActionImpl(null, actionId); + } + else + { + result = new ActionImpl(null, actionId, jsonAction.getString("actionDefinitionName")); + } + + // Post Action Queue parameter + if (jsonAction.has("actionedUponNode")) + { + NodeRef actionedUponNode = new NodeRef(jsonAction.getString("actionedUponNode")); + result.setNodeRef(actionedUponNode); + } + + if (jsonAction.has("description")) + { + result.setDescription(jsonAction.getString("description")); + } + + if (jsonAction.has("title")) + { + result.setTitle(jsonAction.getString("title")); + } + + if (jsonAction.has("parameterValues")) + { + JSONObject jsonParameterValues = jsonAction.getJSONObject("parameterValues"); + result.setParameterValues(parseJsonParameterValues(jsonParameterValues)); + } + + if (jsonAction.has("executeAsync")) + { + result.setExecuteAsynchronously(jsonAction.getBoolean("executeAsync")); + } + + if (jsonAction.has("runAsUser")) + { + result.setRunAsUser(jsonAction.getString("runAsUser")); + } + + if (jsonAction.has("actions")) + { + JSONArray jsonActions = jsonAction.getJSONArray("actions"); + + for (int i = 0; i < jsonActions.length(); i++) + { + JSONObject innerJsonAction = jsonActions.getJSONObject(i); + + Action innerAction = parseJsonAction(innerJsonAction); + + // we assume that only composite-action contains actions json array, so should be no cast exception + ((CompositeActionImpl)result).addAction(innerAction); + } + } + + if (jsonAction.has("conditions")) + { + JSONArray jsonConditions = jsonAction.getJSONArray("conditions"); + + for (int i = 0; i < jsonConditions.length(); i++) + { + JSONObject jsonCondition = jsonConditions.getJSONObject(i); + + // parse action conditions + ActionCondition actionCondition = parseJsonActionCondition(jsonCondition); + + result.getActionConditions().add(actionCondition); + } + } + + if (jsonAction.has("compensatingAction")) + { + Action compensatingAction = parseJsonAction(jsonAction.getJSONObject("compensatingAction")); + result.setCompensatingAction(compensatingAction); + } + + return result; + } + + protected ActionConditionImpl parseJsonActionCondition(JSONObject jsonActionCondition) throws JSONException + { + String id = jsonActionCondition.has("id") ? jsonActionCondition.getString("id"): GUID.generate(); + + ActionConditionImpl result = new ActionConditionImpl(id, jsonActionCondition.getString("conditionDefinitionName")); + + if (jsonActionCondition.has("invertCondition")) + { + result.setInvertCondition(jsonActionCondition.getBoolean("invertCondition")); + } + + if (jsonActionCondition.has("parameterValues")) + { + JSONObject jsonParameterValues = jsonActionCondition.getJSONObject("parameterValues"); + + result.setParameterValues(parseJsonParameterValues(jsonParameterValues)); + } + + return result; + } + + protected Map parseJsonParameterValues(JSONObject jsonParameterValues) throws JSONException + { + Map parameterValues = new HashMap(); + + // get parameters names + JSONArray names = jsonParameterValues.names(); + + for (int i = 0; i < names.length(); i++) + { + String propertyName = names.getString(i); + Object propertyValue = jsonParameterValues.get(propertyName); + + // get parameter repository type + QName typeQName = getPropertyType(propertyName); + + if (typeQName == null) + { + if (propertyValue.toString().equals("true") || propertyValue.toString().equals("false")) + { + typeQName = DataTypeDefinition.BOOLEAN; + } + else + { + typeQName = DataTypeDefinition.TEXT; + } + } + + Serializable value = null; + + if (typeQName.equals(DataTypeDefinition.ANY)) + { + try + { + value = dateFormate.parse(propertyValue.toString()); + } + catch (ParseException e) + { + try + { + value = Long.valueOf(propertyValue.toString()); + } + catch (NumberFormatException e1) + { + // do nothing + } + } + } + + if (value == null) + { + // convert to correct repository type + value = (Serializable)DefaultTypeConverter.INSTANCE.convert(dictionaryService.getDataType(typeQName), propertyValue); + } + + parameterValues.put(propertyName, value); + } + + return parameterValues; + } } diff --git a/source/java/org/alfresco/repo/web/scripts/rule/ActionConstraintGet.java b/source/java/org/alfresco/repo/web/scripts/rule/ActionConstraintGet.java new file mode 100755 index 0000000000..2c9d1719d9 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/rule/ActionConstraintGet.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2005-2009 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program 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 General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.rule; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.service.cmr.action.ParameterConstraint; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.webscripts.Cache; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptException; +import org.springframework.extensions.webscripts.WebScriptRequest; + +/** + * @author unknown + * + */ +public class ActionConstraintGet extends AbstractRuleWebScript +{ + + @SuppressWarnings("unused") + private static Log logger = LogFactory.getLog(ActionConstraintGet.class); + + @Override + protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) + { + Map model = new HashMap(); + + // get request parameters + Map templateVars = req.getServiceMatch().getTemplateVars(); + String name = templateVars.get("name"); + + // get specified parameter constraint + ParameterConstraint parameterConstraint = actionService.getParameterConstraint(name); + + if (parameterConstraint == null) + { + throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find parameter constraint with name: " + + name); + } + + model.put("actionConstraint", parameterConstraint); + + return model; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/rule/ActionConstraintsGet.java b/source/java/org/alfresco/repo/web/scripts/rule/ActionConstraintsGet.java new file mode 100755 index 0000000000..f78f9086de --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/rule/ActionConstraintsGet.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2005-2009 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program 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 General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.rule; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.service.cmr.action.ParameterConstraint; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.webscripts.Cache; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptRequest; + +/** + * @author unknown + * + */ +public class ActionConstraintsGet extends AbstractRuleWebScript +{ + + @SuppressWarnings("unused") + private static Log logger = LogFactory.getLog(ActionConstraintsGet.class); + + + @Override + protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) + { + Map model = new HashMap(); + + // get request parameters + String[] names = req.getParameterValues("name"); + + List parameterConstraints = null; + + if (names != null && names.length > 0) + { + // filter is present in request + parameterConstraints = new ArrayList(); + + // find specified parameter constraints + for (String name : names) + { + ParameterConstraint parameterConstraint = actionService.getParameterConstraint(name); + + if (parameterConstraint != null) + { + parameterConstraints.add(parameterConstraint); + } + } + } + else + { + // no filter was provided, return all parameter constraints + parameterConstraints = actionService.getParameterConstraints(); + } + + model.put("actionConstraints", parameterConstraints); + + return model; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/rule/ActionQueuePost.java b/source/java/org/alfresco/repo/web/scripts/rule/ActionQueuePost.java new file mode 100755 index 0000000000..8be7ffbecf --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/rule/ActionQueuePost.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2005-2009 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program 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 General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.rule; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.repo.action.ActionImpl; +import org.alfresco.service.cmr.repository.NodeRef; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.springframework.extensions.webscripts.Cache; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptException; +import org.springframework.extensions.webscripts.WebScriptRequest; + +/** + * @author unknown + * + */ +public class ActionQueuePost extends AbstractRuleWebScript +{ + @SuppressWarnings("unused") + private static Log logger = LogFactory.getLog(ActionQueuePost.class); + + public static final String STATUS = "actionExecStatus"; + public static final String STATUS_SUCCESS = "success"; + public static final String STATUS_FAIL = "fail"; + public static final String STATUS_QUEUED = "queued"; + + @Override + protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) + { + Map model = new HashMap(); + + // get request parameters + boolean async = Boolean.parseBoolean(req.getParameter("async")); + + ActionImpl action = null; + JSONObject json = null; + + try + { + // read request json + json = new JSONObject(new JSONTokener(req.getContent().getContent())); + + // parse request json + action = parseJsonAction(json); + NodeRef actionedUponNode = action.getNodeRef(); + + // clear nodeRef for action + action.setNodeRef(null); + json.remove("actionedUponNode"); + + if (async) + { + model.put(STATUS, STATUS_QUEUED); + } + else + { + model.put(STATUS, STATUS_SUCCESS); + } + + try + { + actionService.executeAction(action, actionedUponNode, true, async); + } + catch(Throwable e) + { + model.put(STATUS, STATUS_FAIL); + model.put("exception", e); + } + + model.put("actionedUponNode", actionedUponNode.toString()); + model.put("action", json); + } + catch (IOException iox) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, + "Could not read content from req.", iox); + } + catch (JSONException je) + { + throw new WebScriptException(Status.STATUS_BAD_REQUEST, + "Could not parse JSON from req.", je); + } + + return model; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/rule/RulePost.java b/source/java/org/alfresco/repo/web/scripts/rule/RulePost.java index bf9ceb84f8..3eb9b2f54c 100755 --- a/source/java/org/alfresco/repo/web/scripts/rule/RulePost.java +++ b/source/java/org/alfresco/repo/web/scripts/rule/RulePost.java @@ -25,27 +25,13 @@ package org.alfresco.repo.web.scripts.rule; import java.io.IOException; -import java.io.Serializable; -import java.text.ParseException; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; -import org.alfresco.repo.action.ActionConditionImpl; -import org.alfresco.repo.action.ActionImpl; -import org.alfresco.repo.action.CompositeActionImpl; -import org.alfresco.service.cmr.action.Action; -import org.alfresco.service.cmr.action.ActionCondition; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.rule.Rule; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.GUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; @@ -103,211 +89,4 @@ public class RulePost extends AbstractRuleWebScript return model; } - - protected Rule parseJsonRule(JSONObject jsonRule) throws JSONException - { - Rule result = new Rule(); - - if (jsonRule.has("title") == false || jsonRule.getString("title").length() == 0) - { - throw new WebScriptException(Status.STATUS_BAD_REQUEST, - "Title missing when creating rule"); - } - - result.setTitle(jsonRule.getString("title")); - - result.setDescription(jsonRule.has("description") ? jsonRule.getString("description") : ""); - - if (jsonRule.has("ruleType") == false || jsonRule.getJSONArray("ruleType").length() == 0) - { - throw new WebScriptException(Status.STATUS_BAD_REQUEST, - "Rule type missing when creating rule"); - } - - JSONArray types = jsonRule.getJSONArray("ruleType"); - List ruleTypes = new ArrayList(); - - for (int i = 0; i < types.length(); i++) - { - ruleTypes.add(types.getString(i)); - } - - result.setRuleTypes(ruleTypes); - - result.applyToChildren(jsonRule.has("applyToChildren") ? jsonRule.getBoolean("applyToChildren") : false); - - result.setExecuteAsynchronously(jsonRule.has("executeAsynchronously") ? jsonRule.getBoolean("executeAsynchronously") : false); - - result.setRuleDisabled(jsonRule.has("disabled") ? jsonRule.getBoolean("disabled") : false); - - JSONObject jsonAction = jsonRule.getJSONObject("action"); - - // parse action object - Action ruleAction = parseJsonAction(jsonAction); - - result.setAction(ruleAction); - - return result; - } - - protected ActionImpl parseJsonAction(JSONObject jsonAction) throws JSONException - { - ActionImpl result = null; - - String actionId = jsonAction.has("id") ? jsonAction.getString("id") : GUID.generate(); - - if (jsonAction.getString("actionDefinitionName").equalsIgnoreCase("composite-action")) - { - result = new CompositeActionImpl(null, actionId); - } - else - { - result = new ActionImpl(null, actionId, jsonAction.getString("actionDefinitionName")); - } - - if (jsonAction.has("description")) - { - result.setDescription(jsonAction.getString("description")); - } - - if (jsonAction.has("title")) - { - result.setTitle(jsonAction.getString("title")); - } - - if (jsonAction.has("parameterValues")) - { - JSONObject jsonParameterValues = jsonAction.getJSONObject("parameterValues"); - result.setParameterValues(parseJsonParameterValues(jsonParameterValues)); - } - - if (jsonAction.has("executeAsync")) - { - result.setExecuteAsynchronously(jsonAction.getBoolean("executeAsync")); - } - - if (jsonAction.has("runAsUser")) - { - result.setRunAsUser(jsonAction.getString("runAsUser")); - } - - if (jsonAction.has("actions")) - { - JSONArray jsonActions = jsonAction.getJSONArray("actions"); - - for (int i = 0; i < jsonActions.length(); i++) - { - JSONObject innerJsonAction = jsonActions.getJSONObject(i); - - Action innerAction = parseJsonAction(innerJsonAction); - - // we assume that only composite-action contains actions json array, so should be no cast exception - ((CompositeActionImpl)result).addAction(innerAction); - } - } - - if (jsonAction.has("conditions")) - { - JSONArray jsonConditions = jsonAction.getJSONArray("conditions"); - - for (int i = 0; i < jsonConditions.length(); i++) - { - JSONObject jsonCondition = jsonConditions.getJSONObject(i); - - // parse action conditions - ActionCondition actionCondition = parseJsonActionCondition(jsonCondition); - - result.getActionConditions().add(actionCondition); - } - } - - if (jsonAction.has("compensatingAction")) - { - Action compensatingAction = parseJsonAction(jsonAction.getJSONObject("compensatingAction")); - result.setCompensatingAction(compensatingAction); - } - - return result; - } - - protected ActionConditionImpl parseJsonActionCondition(JSONObject jsonActionCondition) throws JSONException - { - String id = jsonActionCondition.has("id") ? jsonActionCondition.getString("id"): GUID.generate(); - - ActionConditionImpl result = new ActionConditionImpl(id, jsonActionCondition.getString("conditionDefinitionName")); - - if (jsonActionCondition.has("invertCondition")) - { - result.setInvertCondition(jsonActionCondition.getBoolean("invertCondition")); - } - - if (jsonActionCondition.has("parameterValues")) - { - JSONObject jsonParameterValues = jsonActionCondition.getJSONObject("parameterValues"); - - result.setParameterValues(parseJsonParameterValues(jsonParameterValues)); - } - - return result; - } - - protected Map parseJsonParameterValues(JSONObject jsonParameterValues) throws JSONException - { - Map parameterValues = new HashMap(); - - // get parameters names - JSONArray names = jsonParameterValues.names(); - - for (int i = 0; i < names.length(); i++) - { - String propertyName = names.getString(i); - Object propertyValue = jsonParameterValues.get(propertyName); - - // get parameter repository type - QName typeQName = getPropertyType(propertyName); - - if (typeQName == null) - { - if (propertyValue.toString().equals("true") || propertyValue.toString().equals("false")) - { - typeQName = DataTypeDefinition.BOOLEAN; - } - else - { - typeQName = DataTypeDefinition.TEXT; - } - } - - Serializable value = null; - - if (typeQName.equals(DataTypeDefinition.ANY)) - { - try - { - value = dateFormate.parse(propertyValue.toString()); - } - catch (ParseException e) - { - try - { - value = Long.valueOf(propertyValue.toString()); - } - catch (NumberFormatException e1) - { - // do nothing - } - } - } - - if (value == null) - { - // convert to correct repository type - value = (Serializable)DefaultTypeConverter.INSTANCE.convert(dictionaryService.getDataType(typeQName), propertyValue); - } - - parameterValues.put(propertyName, value); - } - - return parameterValues; - } } diff --git a/source/java/org/alfresco/repo/web/scripts/rule/RuleServiceTest.java b/source/java/org/alfresco/repo/web/scripts/rule/RuleServiceTest.java index 750cbea15e..655ee7402c 100755 --- a/source/java/org/alfresco/repo/web/scripts/rule/RuleServiceTest.java +++ b/source/java/org/alfresco/repo/web/scripts/rule/RuleServiceTest.java @@ -40,6 +40,7 @@ import org.alfresco.service.cmr.rule.Rule; import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -61,10 +62,18 @@ public class RuleServiceTest extends BaseWebScriptTest private static final String URL_RULETYPES = "/api/ruletypes"; private static final String URL_ACTIONDEFINITIONS = "/api/actiondefinitions"; private static final String URL_ACTIONCONDITIONDEFINITIONS = "/api/actionconditiondefinitions"; + + private static final String URL_ACTIONCONSTRAINTS = "/api/actionConstraints"; + private static final String URL_ACTIONCONSTRAINT = "/api/actionConstraints/{0}"; + + private static final String URL_QUEUE_ACTION = "/api/actionQueue?async={0}"; + private static final String URL_RULES = "/api/node/{0}/{1}/{2}/ruleset/rules"; private static final String URL_RULESET = "/api/node/{0}/{1}/{2}/ruleset"; private static final String URL_RULE = "/api/node/{0}/{1}/{2}/ruleset/rules/{3}"; + private static final String TEST_FOLDER = "test_folder-" + System.currentTimeMillis(); + private static final String COMPANY_HOME_PATH = "/app:company_home"; private NodeService nodeService; @@ -75,6 +84,7 @@ public class RuleServiceTest extends BaseWebScriptTest private RuleService ruleService; private NodeRef testNodeRef; + private NodeRef companyHome; @Override protected void setUp() throws Exception @@ -92,6 +102,7 @@ public class RuleServiceTest extends BaseWebScriptTest createTestFolder(); assertNotNull(testNodeRef); + assertNotNull(companyHome); } private void createTestFolder() @@ -113,6 +124,7 @@ public class RuleServiceTest extends BaseWebScriptTest else { companyHomeNodeRef = nodeRefs.get(0); + companyHome = companyHomeNodeRef; } FileInfo fileInfo = fileFolderService.create(companyHomeNodeRef, TEST_FOLDER, ContentModel.TYPE_FOLDER); @@ -136,6 +148,16 @@ public class RuleServiceTest extends BaseWebScriptTest return MessageFormat.format(URL_RULE, nodeRef.getStoreRef().getProtocol(), nodeRef.getStoreRef().getIdentifier(), nodeRef.getId(), ruleId); } + private String formateActionConstraintUrl(String name) + { + return MessageFormat.format(URL_ACTIONCONSTRAINT, name); + } + + private String formateQueueActionUrl(boolean async) + { + return MessageFormat.format(URL_QUEUE_ACTION, async); + } + @Override protected void tearDown() throws Exception { @@ -352,6 +374,128 @@ public class RuleServiceTest extends BaseWebScriptTest } } + public void testGetActionConstraints() throws Exception + { + Response response = sendRequest(new GetRequest(URL_ACTIONCONSTRAINTS), 200); + JSONObject result = new JSONObject(response.getContentAsString()); + + assertNotNull(result); + + assertTrue(result.has("data")); + + JSONArray data = result.getJSONArray("data"); + + for (int i = 0; i < data.length(); i++) + { + JSONObject actionConstraint = data.getJSONObject(i); + + assertTrue(actionConstraint.has("name")); + assertTrue(actionConstraint.has("values")); + + JSONArray values = actionConstraint.getJSONArray("values"); + + for (int j = 0; j < values.length(); j++) + { + JSONObject value = values.getJSONObject(j); + + assertTrue(value.has("value")); + assertTrue(value.has("displayLabel")); + } + } + } + + public void testGetActionConstraint() throws Exception + { + Response response = sendRequest(new GetRequest(formateActionConstraintUrl("compare-operations")), 200); + JSONObject result = new JSONObject(response.getContentAsString()); + + assertNotNull(result); + + assertTrue(result.has("data")); + + JSONObject data = result.getJSONObject("data"); + + assertTrue(data.has("name")); + assertTrue(data.has("values")); + + JSONArray values = data.getJSONArray("values"); + + for (int i = 0; i < values.length(); i++) + { + JSONObject value = values.getJSONObject(i); + + assertTrue(value.has("value")); + assertTrue(value.has("displayLabel")); + } + } + + public void testQueueAction() throws Exception + { + String url = formateQueueActionUrl(false); + + JSONObject copyAction = buildCopyAction(companyHome); + + copyAction.put("actionedUponNode", testNodeRef); + + // execute before response (should be successful) + Response successResponse = sendRequest(new PostRequest(url, copyAction.toString(), "application/json"), 200); + + JSONObject successResult = new JSONObject(successResponse.getContentAsString()); + + assertNotNull(successResult); + + assertTrue(successResult.has("data")); + + JSONObject successData = successResult.getJSONObject("data"); + + assertTrue(successData.has("status")); + assertEquals("success", successData.getString("status")); + assertTrue(successData.has("actionedUponNode")); + assertFalse(successData.has("exception")); + assertTrue(successData.has("action")); + + // execute before response (should fail) + Response failResponse = sendRequest(new PostRequest(url, copyAction.toString(), "application/json"), 200); + + JSONObject failResult = new JSONObject(failResponse.getContentAsString()); + + assertNotNull(failResult); + + assertTrue(failResult.has("data")); + + JSONObject failData = failResult.getJSONObject("data"); + + assertTrue(failData.has("status")); + assertEquals("fail", failData.getString("status")); + assertTrue(failData.has("actionedUponNode")); + assertTrue(failData.has("exception")); + JSONObject exception = failData.getJSONObject("exception"); + assertTrue(exception.has("message")); + assertTrue(exception.has("stackTrace")); + assertTrue(failData.has("action")); + + // execute after response (should fail but error should not present in response) + String asyncUrl = formateQueueActionUrl(true); + Response response = sendRequest(new PostRequest(asyncUrl, copyAction.toString(), "application/json"), 200); + + // wait while action executed + Thread.sleep(1000); + + JSONObject result = new JSONObject(response.getContentAsString()); + + assertNotNull(result); + + assertTrue(result.has("data")); + + JSONObject data = result.getJSONObject("data"); + + assertTrue(data.has("status")); + assertEquals("queued", data.getString("status")); + assertTrue(data.has("actionedUponNode")); + assertFalse(data.has("exception")); + assertTrue(data.has("action")); + } + public void testCreateRule() throws Exception { JSONObject result = createRule(); @@ -453,6 +597,28 @@ public class RuleServiceTest extends BaseWebScriptTest assertEquals(0, ruleService.getRules(testNodeRef).size()); } + private JSONObject buildCopyAction(NodeRef destination) throws JSONException + { + JSONObject result = new JSONObject(); + + // add actionDefinitionName + result.put("actionDefinitionName", "copy"); + + // build parameterValues + JSONObject parameterValues = new JSONObject(); + parameterValues.put("destination-folder", destination); + parameterValues.put("assoc-name", QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "copy")); + parameterValues.put("assoc-type", ContentModel.ASSOC_CONTAINS); + + // add parameterValues + result.put("parameterValues", parameterValues); + + // add executeAsync + result.put("executeAsync", false); + + return result; + } + private JSONObject buildTestRule() throws JSONException { JSONObject result = new JSONObject();