diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/action.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/action.lib.ftl
new file mode 100644
index 0000000000..3fafe5550d
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/action.lib.ftl
@@ -0,0 +1,40 @@
+<#import "condition.lib.ftl" as conditionLib/>
+
+<#macro actionJSON action>
+ <#escape x as jsonUtils.encodeJSONString(x)>
+ {
+ "id" : "${action.id}",
+ "actionDefinitionName" : "${action.actionDefinitionName}",
+ "title" : "${action.title}",
+ "description" : "${action.description}",
+ "executeAsync" : "${action.executeAsychronously?string("true", "false")}",
+ "parameterValues" :
+ {
+ <#list action.parameterValues.keySet() as parameterKey>
+ "${parameterKey}" : "${action.getParameterValue(parameterKey)}"
+ <#if parameterKey_has_next>,#if>
+ #list>
+ },
+ "actions" :
+ {
+ <#list action.actions as nestedAction>
+ "${nestedAction.id}" : <@actionJSON action=nestedAction/>
+ <#if nestedAction_has_next>,#if>
+ #list>
+ },
+ "conditions" :
+ {
+ <#list action.actionConditions as condition>
+ "${condition.id}" : <@conditionLib.conditionJSON condition=condition/>
+ <#if condition_has_next>,#if>
+ #list>
+ },
+ <#if action.compensatingAction?exists>
+ "compensatingAction" : <@actionJSON action=action.compensatingAction/>,
+ #if>,
+ "url" : "${url.serviceContext + "/api/rule/" + rule.nodeRef.storeRef.protocol + "/"
+ + rule.nodeRef.storeRef.identifier + "/" + rule.nodeRef.id + "/actions/"
+ + action.id}"
+ }
+ #escape>
+#macro>
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actiondef.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actiondef.lib.ftl
new file mode 100644
index 0000000000..ee0e1041d1
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actiondef.lib.ftl
@@ -0,0 +1,27 @@
+<#import "paramdef.lib.ftl" as paramDefLib/>
+
+<#macro actionDefJSON actiondef>
+ <#escape x as jsonUtils.encodeJSONString(x)>
+ {
+ "name" : "${actiondef.name}",
+ "title" : "${actiondef.title},
+ "description" : "${actiondef.description}",
+ "adhocPropertiesAllowed" : "${actiondef.adhocPropertiesAllowed?string("true", "false")}",
+ "applicableTypes" :
+ [
+ <#list actiondef.applicableTypes as applicableType>
+ "${applicableType.getLocalName()}"
+ <#if applicableType_has_next>,#if>
+ #list>
+ ],
+ "parameterDefinitions" :
+ [
+ <#list actiondef.parameterDefinitions as paramDef>
+ <@paramDefLib.paramDefJSON paramDef=paramDef/>
+ <#if paramDef_has_next>,#if>
+ #list>
+ ],
+ "url" : "${url.serviceContext + "/api/rules/actiondefs/" + actiondef.name}"
+ }
+ #escape>
+#macro>
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actiondefs.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actiondefs.get.desc.xml
new file mode 100644
index 0000000000..3b3e9bc948
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actiondefs.get.desc.xml
@@ -0,0 +1,10 @@
+
+ Get Action Definitions
+ Get the collection of action definitions, optionally scoped by node reference or path
+ /api/rules/actiondefs
+ /api/node/{store_type}/{store_id}/{id}/actiondefs
+ /api/path/{store_type}/{store_id}/{id}/actiondefs
+
+ user
+ required
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actiondefs.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actiondefs.get.json.ftl
new file mode 100644
index 0000000000..58ce3fbe19
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actiondefs.get.json.ftl
@@ -0,0 +1,8 @@
+<#import "actiondef.lib.ftl" as actionDefLib/>
+
+[
+ <#list actiondefs as actiondef>
+ <@actionDefLib.actionDefJSON actiondef=actiondef/>
+ <#if actiondef_has_next>,#if>
+ #list>
+]
\ 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 100644
index 0000000000..ced548fe75
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionqueue.post.desc.xml
@@ -0,0 +1,8 @@
+
+ Add to Action Queue
+ Add an Action Queue Item to the Action Queue for execution
+ /api/actionqueue
+
+ user
+ required
+
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 100644
index 0000000000..ca79ae0516
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionqueue.post.json.ftl
@@ -0,0 +1,3 @@
+<#import "actionqueueitemstatus.lib.ftl" as actionQItemStatusLib/>
+
+<@actionQItemStatusLib.actionQItemStatusJSON actionQItemStatus=actionQItemStatus/>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionqueueitemstatus.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionqueueitemstatus.lib.ftl
new file mode 100644
index 0000000000..9c337a12c3
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/actionqueueitemstatus.lib.ftl
@@ -0,0 +1,11 @@
+<#macro actionQItemStatusJSON actionQItemStatus>
+ <#escape x as jsonUtils.encodeJSONString(x)>
+ {
+ "actionQueueItemStatusUrl" : "${url.serviceContext + "/api/actionqueue/items/"
+ + actionQItemStatus.actionQueueItemId + "/status"}",
+ "actionQueueItemId" : "{actionQItemStatus.actionQueueItemId}",
+ "status" : "${actionQItemStatus.status}",
+ "actionId" : "${actionQItemStatus.actionId}"
+ }
+ #escape>
+#macro>
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/condition.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/condition.lib.ftl
new file mode 100644
index 0000000000..08433d5482
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/condition.lib.ftl
@@ -0,0 +1,19 @@
+<#macro conditionJSON condition>
+ <#escape x as jsonUtils.encodeJSONString(x)>
+ {
+ "id" : "${condition.id}",
+ "conditionDefinitionName" : "${condition.actionConditionDefinitionName}",
+ "invertCondition" : "${condition.invertCondition?string("true", "false")}",
+ "parameterValues" :
+ {
+ <#list condition.parameterValues.keySet() as parameterKey>
+ "${parameterKey}" : "${condition.getParameterValue(parameterKey)}"
+ <#if parameterKey_has_next>,#if>
+ #list>
+ },
+ "url" : "${url.serviceContext + "/api/rule/" + rule.nodeRef.storeRef.protocol + "/"
+ + rule.nodeRef.storeRef.identifier + "/" + rule.nodeRef.id + "/conditions/"
+ + condition.id}"
+ }
+ #escape>
+#macro>
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/conditiondef.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/conditiondef.lib.ftl
new file mode 100644
index 0000000000..db4cf490d2
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/conditiondef.lib.ftl
@@ -0,0 +1,20 @@
+<#import "paramdef.lib.ftl" as paramDefLib/>
+
+<#macro conditionDefJSON conditiondef>
+ <#escape x as jsonUtils.encodeJSONString(x)>
+ {
+ "name" : "${conditiondef.name}",
+ "title" : "${conditiondef.title},
+ "description" : "${conditiondef.description}",
+ "adhocPropertiesAllowed" : "${conditiondef.adhocPropertiesAllowed?string("true", "false")}",
+ "parameterDefinitions" :
+ [
+ <#list conditiondef.parameterDefinitions as paramDef>
+ <@paramDefLib.paramDefJSON paramDef=paramDef/>
+ <#if paramDef_has_next>,#if>
+ #list>
+ ],
+ "url" : "${url.serviceContext + "/api/rules/conditiondefs/" + conditiondef.name}"
+ }
+ #escape>
+#macro>
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/conditiondefs.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/conditiondefs.get.desc.xml
new file mode 100644
index 0000000000..955fdf07fa
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/conditiondefs.get.desc.xml
@@ -0,0 +1,8 @@
+
+ Get Condition Definitions
+ Get the collection of condition definitions
+ /api/rules/conditiondefs
+
+ user
+ required
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/conditiondefs.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/conditiondefs.get.json.ftl
new file mode 100644
index 0000000000..296f33a61d
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/conditiondefs.get.json.ftl
@@ -0,0 +1,8 @@
+<#import "conditiondef.lib.ftl" as conditionDefLib/>
+
+[
+ <#list conditiondefs as conditiondef>
+ <@conditionDefLib.conditionDefJSON conditiondef=conditiondef/>
+ <#if conditiondef_has_next>,#if>
+ #list>
+]
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/paramdef.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/paramdef.lib.ftl
new file mode 100644
index 0000000000..8d61063700
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/paramdef.lib.ftl
@@ -0,0 +1,12 @@
+<#macro paramDefJSON paramDef>
+ <#escape x as jsonUtils.encodeJSONString(x)>
+ {
+ "name" : "${paramDef.name}",
+ "displayLabel" : "${paramDef.displayLabel}",
+ "type" : "${paramDef.type}",
+ "multiValued" : ${paramDef.multiValued?string("true", "false")},
+ "mandatory" : "${paramDef.mandatory}",
+ "url" : "${url.serviceContext + "/api/rules/parameterdefs/" + paramDef.name}"
+ }
+ #escape>
+#macro>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.get.desc.xml
new file mode 100644
index 0000000000..42d0e3ddc5
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.get.desc.xml
@@ -0,0 +1,10 @@
+
+ Get Rule
+ Get the rule identified by the specified rule node reference.
+ /api/rules/{store_type}/{store_id}/{id}
+ /api/node/{store_type}/{store_id}/{id}/rules/{id}
+ /api/path/{store_type}/{store_id}/{id}/rules/{id}
+
+ user
+ required
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.get.json.ftl
new file mode 100644
index 0000000000..ce2f3f4bdd
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.get.json.ftl
@@ -0,0 +1,2 @@
+<#import "rule.lib.ftl" as ruleLib/>
+<@ruleLib.ruleJSON rule=rule/>
\ No newline at end of file
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
new file mode 100644
index 0000000000..989ffa8705
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.lib.ftl
@@ -0,0 +1,25 @@
+<#import "action.lib.ftl" as actionLib/>
+
+<#macro ruleJSON rule>
+ <#escape x as jsonUtils.encodeJSONString(x)>
+ {
+ "url" : "${url.serviceContext + "/api/rules/" + rule.nodeRef.storeRef.protocol + "/"
+ + rule.nodeRef.storeRef.identifier + "/" + rule.nodeRef.id}",
+ "ruleNodeRef" : "${rule.nodeRef}",
+ "title" : "${rule.title}",
+ "description" : "${rule.description}",
+ "ruleTypes" :
+ [
+ <#list rule.ruleTypes as ruleType>
+ "${ruleType}"
+ <#if ruleType_has_next>,#if>
+ #list>
+ ],
+ "action" : <@actionLib.actionJSON action=rule.action/>,
+ "actionableNodeRef" : "${actionableNodeRef}",
+ "executeAsynchronously" : ${rule.executeAsynchronously?string("true", "false")},
+ "ruleDisabled" : ${rule.ruleDisabled?string("true", "false")},
+ "appliedToChildren" : ${rule.appliedToChildren?string("true", "false")}
+ }
+ #escape>
+#macro>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.put.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.put.desc.xml
new file mode 100644
index 0000000000..9634e3f60a
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.put.desc.xml
@@ -0,0 +1,10 @@
+
+ Put Rule
+ Update the rule identified by the specified rule node reference.
+ /api/rules/{store_type}/{store_id}/{id}
+ /api/node/{store_type}/{store_id}/{id}/rules/{id}
+ /api/path/{store_type}/{store_id}/{id}/rules/{id}
+
+ user
+ required
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.put.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.put.json.ftl
new file mode 100644
index 0000000000..ce2f3f4bdd
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rule.put.json.ftl
@@ -0,0 +1,2 @@
+<#import "rule.lib.ftl" as ruleLib/>
+<@ruleLib.ruleJSON rule=rule/>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rules.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rules.get.desc.xml
new file mode 100644
index 0000000000..bfe5c2c4a1
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rules.get.desc.xml
@@ -0,0 +1,10 @@
+
+ Get Rules
+ Get the collection of rules which have been applied to the given (actionable) node. If the optional 'includeInherited' parameter is not provided, then rules inherited from the given node's parents are included by default. If the optional 'ruleTypeName' parameter is provided, then only rules of that specific given rule type are returned
+ /api/node/{store_type}/{store_id}/{id}/rules?includeInherited={includeInherited?}&ruleTypeName={ruleTypeName?}
+ /api/path/{store_type}/{store_id}/{id}/rules?includeInherited={includeInherited?}&ruleTypeName={ruleTypeName?}
+ /api/rules/appliedtonode/{store_type}/{store_id}/{id}?includeInherited={includeInherited?}&ruleTypeName={ruleTypeName?}
+
+ user
+ required
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rules.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rules.get.json.ftl
new file mode 100644
index 0000000000..56b18201ff
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rules.get.json.ftl
@@ -0,0 +1,8 @@
+<#import "rule.lib.ftl" as ruleLib/>
+
+[
+ <#list rules as rule>
+ <@ruleLib.ruleJSON rule=rule/>
+ <#if rule_has_next>,#if>
+ #list>
+]
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rules.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rules.post.desc.xml
new file mode 100644
index 0000000000..2db4e0dcc6
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rules.post.desc.xml
@@ -0,0 +1,10 @@
+
+ Create Rule
+ Creates a rule in the rule collection associated with the given actionable node
+ /api/node/{store_type}/{store_id}/{id}/rules
+ /api/path/{store_type}/{store_id}/{id}/rules
+ /api/rules/appliedtonode/{store_type}/{store_id}/{id}
+
+ user
+ required
+
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rules.post.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rules.post.json.ftl
new file mode 100644
index 0000000000..ce2f3f4bdd
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rule/rules.post.json.ftl
@@ -0,0 +1,2 @@
+<#import "rule.lib.ftl" as ruleLib/>
+<@ruleLib.ruleJSON rule=rule/>
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/web/scripts/rule/ActionDefsGet.java b/source/java/org/alfresco/repo/web/scripts/rule/ActionDefsGet.java
new file mode 100644
index 0000000000..79812ce312
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/rule/ActionDefsGet.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2005-2007 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 received 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.List;
+import java.util.Map;
+
+import org.alfresco.service.cmr.action.ActionDefinition;
+import org.alfresco.service.cmr.action.ActionService;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.web.scripts.DeclarativeWebScript;
+import org.alfresco.web.scripts.Status;
+import org.alfresco.web.scripts.WebScriptRequest;
+
+/**
+ * Web Script to GET the action definition collection
+ * This can optionally be scoped by by either
+ * - a node reference in the form /api/node/{store_type}/{store_id}/{id} on the URL
+ * - a node path in the form /api/path/{store_type}/{store_id}/{id} on the URL
+ *
+ * @author glen johnson at alfresco dot com
+ */
+public class ActionDefsGet extends DeclarativeWebScript
+{
+ // private constants
+ private static final String REQ_URL_TEMPL_VAR_STORE_TYPE = "store_type";
+ private static final String REQ_URL_TEMPL_VAR_STORE_ID = "store_id";
+ private static final String REQ_URL_TEMPL_VAR_ID = "id";
+
+ // model property keys
+ private static final String MODEL_PROP_KEY_ACTION_DEFS = "actiondefs";
+
+ // properties for services & dependencies
+ private ActionService actionService;
+ private RulesHelper rulesHelper;
+
+ /**
+ * Set the actionService property.
+ *
+ * @param actionService The action service instance to set
+ */
+ public void setActionService(ActionService actionService)
+ {
+ this.actionService = actionService;
+ }
+
+ /**
+ * Set the rules helper
+ *
+ * @param rulesHelper the rulesHelper to set
+ */
+ public void setRulesHelper(RulesHelper rulesHelper)
+ {
+ this.rulesHelper = rulesHelper;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(
+ * org.alfresco.web.scripts.WebScriptRequest,
+ * org.alfresco.web.scripts.WebScriptResponse)
+ */
+ @Override
+ protected Map executeImpl(WebScriptRequest req,
+ Status status)
+ {
+ // initialise model to pass on for template to render
+ Map model = new HashMap();
+
+ // get the template variables for store_type, store_id and id
+ String storeType = req.getServiceMatch().getTemplateVars().get(REQ_URL_TEMPL_VAR_STORE_TYPE);
+ String storeId = req.getServiceMatch().getTemplateVars().get(REQ_URL_TEMPL_VAR_STORE_ID);
+ String id = req.getServiceMatch().getTemplateVars().get(REQ_URL_TEMPL_VAR_ID);
+
+ // work out which of storeType, storeId, id template variables have been given
+ boolean storeTypeGiven = (storeType != null) && (storeType.length() > 0);
+ boolean storeIdGiven = (storeId != null) && (storeId.length() > 0);
+ boolean idGiven = (id != null) && (id.length() > 0);
+
+ List actionDefs = null;
+
+ //
+ // if either a node reference or path are provided to scope the action
+ // definition collection by, then obtain a reference to that node
+ //
+ if ((storeTypeGiven && storeIdGiven && idGiven))
+ {
+ // get the node reference to scope the action definitions by
+ NodeRef scopeByNodeRef = this.rulesHelper.getNodeRefFromWebScriptUrl(req, storeType, storeId, id);
+
+ // get all the action definitions that are applicable for the node reference
+ actionDefs = this.actionService.getActionDefinitions(scopeByNodeRef);
+ }
+ // else not scoped by noderef, so get all the condition definitions
+ else
+ {
+ actionDefs = this.actionService.getActionDefinitions();
+ }
+
+ // add objects to model for the template to render
+ model.put(MODEL_PROP_KEY_ACTION_DEFS, actionDefs);
+
+ return model;
+ }
+}
diff --git a/source/java/org/alfresco/repo/web/scripts/rule/ActionQueueItemStatus.java b/source/java/org/alfresco/repo/web/scripts/rule/ActionQueueItemStatus.java
new file mode 100644
index 0000000000..9b35a7c355
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/rule/ActionQueueItemStatus.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2005-2007 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 received 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;
+
+/**
+ * This class defines a bean that encapsulates the
+ * properties present in ActionQueueItemStatus Details
+ * returned from the Action Queue resource
+ *
+ * @author glen johnson at alfresco com
+ */
+public class ActionQueueItemStatus
+{
+ // bean property member variables
+
+ /**
+ * ID allocated to the action queue item when it is added to the action queue resource
+ */
+ private String actionQueueItemId;
+
+ /**
+ * Execution status for the respective action queue item
+ * Value is one of "PENDING", "COMPLETE"
+ */
+ private String status = null;
+
+ /**
+ * ID of the action (associated with this status) which is part of the action queue item
+ */
+ private String actionId;
+
+ /**
+ * Return the ID of the action queue item
+ *
+ * @return the action queue item ID
+ */
+ public String getActionQueueItemId()
+ {
+ return actionQueueItemId;
+ }
+
+ /**
+ * Sets the ID of the action queue item
+ *
+ * @param actionQueueItemId the action queue item id to set
+ */
+ public void setActionQueueItemId(String actionQueueItemId)
+ {
+ this.actionQueueItemId = actionQueueItemId;
+ }
+
+ /**
+ * Get the status
+ *
+ * @return the status
+ */
+ public String getStatus()
+ {
+ return status;
+ }
+
+ /**
+ * Set the status
+ *
+ * @param status the status to set
+ */
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+ /**
+ * Get the action id
+ *
+ * @return the actionId
+ */
+ public String getActionId()
+ {
+ return actionId;
+ }
+
+ /**
+ * Set the action ID
+ *
+ * @param actionId the actionId to set
+ */
+ public void setActionId(String actionId)
+ {
+ this.actionId = actionId;
+ }
+}
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 100644
index 0000000000..3cd57bd6bf
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/rule/ActionQueuePost.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2005-2007 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 received 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 org.alfresco.service.cmr.action.Action;
+import org.alfresco.service.cmr.action.ActionService;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.web.scripts.DeclarativeWebScript;
+import org.alfresco.web.scripts.Status;
+import org.alfresco.web.scripts.WebScriptException;
+import org.alfresco.web.scripts.WebScriptRequest;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Web Script to POST an Action Queue Item onto the Action Queue
+ *
+ * @author glen johnson at alfresco dot com
+ */
+public class ActionQueuePost extends DeclarativeWebScript
+{
+ // model property keys
+ private static final String MODEL_PROP_KEY_ACTION_Q_ITEM_STATUS = "actionQItemStatus";
+
+ // properties for services
+ private ActionService actionService;
+
+ // properties for dependencies
+ private RulesHelper rulesHelper;
+
+ /**
+ * @param actionService the actionService to set
+ */
+ public void setActionService(ActionService actionService)
+ {
+ this.actionService = actionService;
+ }
+
+ /**
+ * Set the rules helper property
+ *
+ * @param rulesHelper the rulesHelper to set
+ */
+ public void setRulesHelper(RulesHelper rulesHelper)
+ {
+ this.rulesHelper = rulesHelper;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(
+ * org.alfresco.web.scripts.WebScriptRequest,
+ * org.alfresco.web.scripts.WebScriptResponse)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Map executeImpl(WebScriptRequest req,
+ Status status)
+ {
+ // initialise model to pass on to template for rendering
+ Map model = new HashMap();
+
+ // get the posted action queue item JSON object by parsing request content
+ Object contentObj = req.parseContent();
+ if (contentObj == null || !(contentObj instanceof JSONObject))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Web Script request content must be a JSON Object. "
+ + "Request content is either a JSON Array or not of MIME-type application/json");
+ }
+
+ JSONObject actionJson = null;
+ Action action = null;
+ boolean checkConditions = true;
+ boolean executeAsynchronously = false;
+ NodeRef actionedUponNodeRef = null;
+ try
+ {
+ // get action queue item JSON object cast from contentObj
+ JSONObject actionQueueItemJson = (JSONObject)contentObj;
+
+ // get action JSON object from actionQueueItem JSON
+ actionJson = actionQueueItemJson.getJSONObject("action");
+
+ // get the action from the action JSON object
+ action = this.rulesHelper.getActionFromJson(actionJson);
+
+ // Get 'checkConditions' and 'executeAsynchronously' properties off action queue item
+ checkConditions = actionQueueItemJson.optBoolean("checkConditions", true);
+ executeAsynchronously = actionQueueItemJson.optBoolean(
+ "executeAsynchronously", action.getExecuteAsychronously());
+
+ // get the actioned-upon node reference
+ String nodeRefStr = actionQueueItemJson.getString("nodeRef");
+ actionedUponNodeRef = new NodeRef(nodeRefStr);
+ }
+ catch (JSONException je)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "Problem retrieving properties from ActionQueueItem Details sent in the request content.", je);
+ }
+
+ // apply rule to actionable node
+ this.actionService.executeAction(action, actionedUponNodeRef, checkConditions, executeAsynchronously);
+
+ // create the action queue item status bean
+ // to be rendered by the template
+ ActionQueueItemStatus actionQItemStatus = new ActionQueueItemStatus();
+
+ //
+ // set the action queue item id on the action queue item status bean
+ //
+
+ String actionedUponNodeId = actionedUponNodeRef.getId();
+ String actionId = action.getId();
+ String actionQItemId = actionId + ":" + actionedUponNodeId;
+ actionQItemStatus.setActionQueueItemId(actionQItemId);
+
+ // set the action id on the action queue item status bean
+ actionQItemStatus.setActionId(actionId);
+
+ // set the status on the action queue item status bean
+ actionQItemStatus.setStatus(RulesHelper.ACTION_QUEUE_ITEM_STATUS_COMPLETE);
+
+ // add objects to model for the template to render
+ model.put(MODEL_PROP_KEY_ACTION_Q_ITEM_STATUS, actionQItemStatus);
+
+ return model;
+ }
+}
diff --git a/source/java/org/alfresco/repo/web/scripts/rule/ConditionDefsGet.java b/source/java/org/alfresco/repo/web/scripts/rule/ConditionDefsGet.java
new file mode 100644
index 0000000000..21331bd689
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/rule/ConditionDefsGet.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2005-2007 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 received 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.List;
+import java.util.Map;
+
+import org.alfresco.service.cmr.action.ActionConditionDefinition;
+import org.alfresco.service.cmr.action.ActionService;
+import org.alfresco.web.scripts.DeclarativeWebScript;
+import org.alfresco.web.scripts.Status;
+import org.alfresco.web.scripts.WebScriptRequest;
+
+/**
+ * Web Script to GET the condition definition collection
+ *
+ * @author glen johnson at alfresco dot com
+ */
+public class ConditionDefsGet extends DeclarativeWebScript
+{
+ // model property keys
+ private static final String MODEL_PROP_KEY_CONDITION_DEFS = "conditiondefs";
+
+ // properties for services
+ private ActionService actionService;
+
+ /**
+ * Set the actionService property.
+ *
+ * @param actionService The action service instance to set
+ */
+ public void setActionService(ActionService actionService)
+ {
+ this.actionService = actionService;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(
+ * org.alfresco.web.scripts.WebScriptRequest,
+ * org.alfresco.web.scripts.WebScriptResponse)
+ */
+ @Override
+ protected Map executeImpl(WebScriptRequest req,
+ Status status)
+ {
+ // initialise model to pass on for template to render
+ Map model = new HashMap();
+
+ // get all the condition definitions
+ List conditionDefs = this.actionService.getActionConditionDefinitions();
+
+ // add objects to model for the template to render
+ model.put(MODEL_PROP_KEY_CONDITION_DEFS, conditionDefs);
+
+ return model;
+ }
+}
diff --git a/source/java/org/alfresco/repo/web/scripts/rule/RuleGet.java b/source/java/org/alfresco/repo/web/scripts/rule/RuleGet.java
new file mode 100644
index 0000000000..eefefa3855
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/rule/RuleGet.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2005-2007 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 received 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 org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.rule.Rule;
+import org.alfresco.service.cmr.rule.RuleService;
+import org.alfresco.web.scripts.DeclarativeWebScript;
+import org.alfresco.web.scripts.Status;
+import org.alfresco.web.scripts.WebScriptException;
+import org.alfresco.web.scripts.WebScriptRequest;
+
+/**
+ * Web Script to GET the rule identified by the given rule node reference.
+ *
+ * @author glen johnson at alfresco dot com
+ */
+public class RuleGet extends DeclarativeWebScript
+{
+ // private constants
+ private static final String REQ_TEMPL_VAR_STORE_TYPE = "store_type";
+ private static final String REQ_TEMPL_VAR_STORE_ID = "store_id";
+ private static final String REQ_TEMPL_VAR_RULE_NODE_ID = "id";
+
+ // model property keys
+ private static final String MODEL_PROP_KEY_RULE = "rule";
+
+ // properties for services
+ private RuleService ruleService;
+
+ // dependencies
+ private RulesHelper rulesHelper;
+
+ /**
+ * Set the ruleService property.
+ *
+ * @param ruleService The rule service instance to set
+ */
+ public void setRuleService(RuleService ruleService)
+ {
+ this.ruleService = ruleService;
+ }
+
+ /**
+ * Set the rules helper property
+ *
+ * @param rulesHelper the rulesHelper to set
+ */
+ public void setRulesHelper(RulesHelper rulesHelper)
+ {
+ this.rulesHelper = rulesHelper;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(
+ * org.alfresco.web.scripts.WebScriptRequest,
+ * org.alfresco.web.scripts.WebScriptResponse)
+ */
+ @Override
+ protected Map executeImpl(WebScriptRequest req,
+ Status status)
+ {
+ // initialise model to pass on for template to render
+ Map model = new HashMap();
+
+ String storeType = req.getServiceMatch().getTemplateVars().get(REQ_TEMPL_VAR_STORE_TYPE);
+ // Handle if 'store_type' URL template token not provided
+ if ((storeType == null) || (storeType.length() == 0))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "The 'store_type' URL template token has not been provided in URL");
+ }
+
+ String storeId = req.getServiceMatch().getTemplateVars().get(REQ_TEMPL_VAR_STORE_ID);
+ // Handle if 'storeId' URL template token not provided
+ if ((storeId == null) || (storeId.length() == 0))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "The 'storeId' URL template token has not been provided in URL");
+ }
+
+ String ruleNodeId = req.getServiceMatch().getTemplateVars().get(REQ_TEMPL_VAR_RULE_NODE_ID);
+ // Handle if 'ruleNodeId' URL template token not provided
+ if ((ruleNodeId == null) || (ruleNodeId.length() == 0))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "The 'ruleNodeId' URL template token has not been provided in URL");
+ }
+
+ // create the rule node reference from the given
+ // URL template tokens
+ NodeRef ruleNodeRef = this.rulesHelper.getNodeRefFromWebScriptUrl(req, storeType, storeId, ruleNodeId);
+
+ // get rule identified by the given rule node reference
+ Rule rule = this.ruleService.getRule(ruleNodeRef);
+
+ // add objects to model for the template to render
+ model.put(MODEL_PROP_KEY_RULE, rule);
+
+ return model;
+ }
+}
diff --git a/source/java/org/alfresco/repo/web/scripts/rule/RulePut.java b/source/java/org/alfresco/repo/web/scripts/rule/RulePut.java
new file mode 100644
index 0000000000..62617302c6
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/rule/RulePut.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2005-2007 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 received 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 org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.rule.Rule;
+import org.alfresco.service.cmr.rule.RuleService;
+import org.alfresco.web.scripts.DeclarativeWebScript;
+import org.alfresco.web.scripts.Status;
+import org.alfresco.web.scripts.WebScriptException;
+import org.alfresco.web.scripts.WebScriptRequest;
+import org.json.JSONObject;
+
+/**
+ * Web Script to PUT (update) the rule identified by the given rule node reference.
+ *
+ * @author glen johnson at alfresco dot com
+ */
+public class RulePut extends DeclarativeWebScript
+{
+ // private constants
+ private static final String REQ_TEMPL_VAR_STORE_TYPE = "store_type";
+ private static final String REQ_TEMPL_VAR_STORE_ID = "store_id";
+ private static final String REQ_TEMPL_VAR_RULE_NODE_ID = "id";
+
+ // model property keys
+ private static final String MODEL_PROP_KEY_RULE = "rule";
+
+ // properties for services
+ private RuleService ruleService;
+
+ // dependencies
+ private RulesHelper rulesHelper;
+
+ /**
+ * Set the ruleService property.
+ *
+ * @param ruleService The rule service instance to set
+ */
+ public void setRuleService(RuleService ruleService)
+ {
+ this.ruleService = ruleService;
+ }
+
+ /**
+ * Set the rules helper
+ *
+ * @param rulesHelper the rulesHelper to set
+ */
+ public void setRulesHelper(RulesHelper rulesHelper)
+ {
+ this.rulesHelper = rulesHelper;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(
+ * org.alfresco.web.scripts.WebScriptRequest,
+ * org.alfresco.web.scripts.WebScriptResponse)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Map executeImpl(WebScriptRequest req,
+ Status status)
+ {
+ // initialise model to pass on for template to render
+ Map model = new HashMap();
+
+ String storeType = req.getServiceMatch().getTemplateVars().get(REQ_TEMPL_VAR_STORE_TYPE);
+ // Handle if 'store_type' URL template token not provided
+ if ((storeType == null) || (storeType.length() == 0))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "The 'store_type' URL template token has not been provided in URL");
+ }
+
+ String storeId = req.getServiceMatch().getTemplateVars().get(REQ_TEMPL_VAR_STORE_ID);
+ // Handle if 'storeId' URL template token not provided
+ if ((storeId == null) || (storeId.length() == 0))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "The 'storeId' URL template token has not been provided in URL");
+ }
+
+ String ruleNodeId = req.getServiceMatch().getTemplateVars().get(REQ_TEMPL_VAR_RULE_NODE_ID);
+ // Handle if 'ruleNodeId' URL template token not provided
+ if ((ruleNodeId == null) || (ruleNodeId.length() == 0))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "The 'ruleNodeId' URL template token has not been provided in URL");
+ }
+
+ // create the rule node reference from the given
+ // URL template tokens
+ NodeRef ruleNodeRef = this.rulesHelper.getNodeRefFromWebScriptUrl(req, storeType, storeId, ruleNodeId);
+
+ // get the rule JSON object sent in the request content (when PUTting the Rule)
+ Object contentObj = req.parseContent();
+ if (contentObj == null || !(contentObj instanceof JSONObject))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Web Script request content must be a JSON Object. "
+ + "Request content is either a JSON Array or not of MIME-type application/json");
+ }
+ JSONObject ruleJson = (JSONObject)contentObj;
+
+ // get the rule object (identified by the rule node reference)
+ // updated by the details in the rule JSON object
+ Rule rule = this.rulesHelper.getRuleFromJson(ruleJson, ruleNodeRef);
+
+ // get owning node ref that rule was
+ // previous applied to
+ NodeRef owningNodeRef = this.ruleService.getOwningNodeRef(rule);
+
+ // re-apply rule to actionable node
+ this.ruleService.saveRule(owningNodeRef, rule);
+
+ // add objects to model for the template to render
+ model.put(MODEL_PROP_KEY_RULE, rule);
+
+ return model;
+ }
+}
diff --git a/source/java/org/alfresco/repo/web/scripts/rule/RulesGet.java b/source/java/org/alfresco/repo/web/scripts/rule/RulesGet.java
new file mode 100644
index 0000000000..d2146ad674
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/rule/RulesGet.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2005-2007 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 received 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.List;
+import java.util.Map;
+
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.rule.Rule;
+import org.alfresco.service.cmr.rule.RuleService;
+import org.alfresco.web.scripts.DeclarativeWebScript;
+import org.alfresco.web.scripts.Status;
+import org.alfresco.web.scripts.WebScriptException;
+import org.alfresco.web.scripts.WebScriptRequest;
+
+/**
+ * Web Script to GET the rule collection associated with the given actionable node.
+ * The following optional parameters can be provided:
+ *
+ * - includeInherited: if provided, then this parameter indicates whether or not to include rules
+ * inherited from the actionable node's parents. If this parameter is not provided , then rules
+ * inherited from the node's parents are included by default.
+ *
+ * - ruleTypeName: if this parameter is provided, then only rules of this given rule type are returned.
+ *
+ * @author glen johnson at alfresco dot com
+ */
+public class RulesGet extends DeclarativeWebScript
+{
+ // private constants
+ private static final String REQ_TEMPL_VAR_STORE_TYPE = "store_type";
+ private static final String REQ_TEMPL_VAR_STORE_ID = "store_id";
+ private static final String REQ_TEMPL_VAR_NODE_ID = "id";
+
+ private static final String REQ_PARAM_INCLUDE_INHERITED = "includeInherited";
+ private static final String REQ_PARAM_RULE_TYPE_NAME = "ruleTypeName";
+
+ // model property keys
+ private static final String MODEL_PROP_KEY_RULES = "rules";
+
+ // properties for services
+ private RuleService ruleService;
+
+ // properties for dependencies
+ private RulesHelper rulesHelper;
+
+ /**
+ * Set the ruleService property.
+ *
+ * @param ruleService The rule service instance to set
+ */
+ public void setRuleService(RuleService ruleService)
+ {
+ this.ruleService = ruleService;
+ }
+
+ /**
+ * @param rulesHelper the rulesHelper to set
+ */
+ public void setRulesHelper(RulesHelper rulesHelper)
+ {
+ this.rulesHelper = rulesHelper;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(
+ * org.alfresco.web.scripts.WebScriptRequest,
+ * org.alfresco.web.scripts.WebScriptResponse)
+ */
+ @Override
+ protected Map executeImpl(WebScriptRequest req,
+ Status status)
+ {
+ // initialise model to pass on for template to render
+ Map model = new HashMap();
+
+ String storeType = req.getServiceMatch().getTemplateVars().get(REQ_TEMPL_VAR_STORE_TYPE);
+ // Handle if 'store_type' URL template token not provided
+ if ((storeType == null) || (storeType.length() == 0))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "The 'store_type' URL template token has not been provided in URL");
+ }
+
+ String storeId = req.getServiceMatch().getTemplateVars().get(REQ_TEMPL_VAR_STORE_ID);
+ // Handle if 'storeId' URL template token not provided
+ if ((storeId == null) || (storeId.length() == 0))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "The 'storeId' URL template token has not been provided in URL");
+ }
+
+ String nodeId = req.getServiceMatch().getTemplateVars().get(REQ_TEMPL_VAR_NODE_ID);
+ // Handle if 'nodeId' URL template token not provided
+ if ((nodeId == null) || (nodeId.length() == 0))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "The 'nodeId' URL template token has not been provided in URL");
+ }
+
+ // get URL parameters
+ String includeInherited = req.getParameter(REQ_PARAM_INCLUDE_INHERITED);
+ boolean includeInheritedParamGiven = ((includeInherited != null) && (includeInherited.length() > 0));
+
+ String ruleTypeName = req.getParameter(REQ_PARAM_RULE_TYPE_NAME);
+ boolean ruleTypeNameParamGiven = ((ruleTypeName != null) && (ruleTypeName.length() > 0));
+
+ // create the actionable node reference from the given
+ // URL template tokens
+ NodeRef actionableNodeRef = this.rulesHelper.getNodeRefFromWebScriptUrl(req, storeType, storeId, nodeId);
+
+ // get rule collection associated with the actionable node
+ List rules = null;
+ if ((includeInheritedParamGiven == false) && (ruleTypeNameParamGiven == false))
+ {
+ rules = this.ruleService.getRules(actionableNodeRef);
+ }
+ else if ((includeInheritedParamGiven == true) && (ruleTypeNameParamGiven == false))
+ {
+ rules = this.ruleService.getRules(actionableNodeRef, Boolean.parseBoolean(includeInherited));
+ }
+ else if ((includeInheritedParamGiven == false) && (ruleTypeNameParamGiven == true))
+ {
+ rules = this.ruleService.getRules(actionableNodeRef, true, ruleTypeName);
+ }
+ else
+ // both 'includeInherited' and 'ruleTypeName' parameter values have been given
+ {
+ rules = this.ruleService.getRules(actionableNodeRef, Boolean.parseBoolean(includeInherited), ruleTypeName);
+ }
+
+ // add objects to model for the template to render
+ model.put(MODEL_PROP_KEY_RULES, rules);
+
+ return model;
+ }
+}
diff --git a/source/java/org/alfresco/repo/web/scripts/rule/RulesHelper.java b/source/java/org/alfresco/repo/web/scripts/rule/RulesHelper.java
new file mode 100644
index 0000000000..101a94143e
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/rule/RulesHelper.java
@@ -0,0 +1,652 @@
+/*
+ * Copyright (C) 2005-2007 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 received 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.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.alfresco.repo.model.Repository;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.action.Action;
+import org.alfresco.service.cmr.action.ActionCondition;
+import org.alfresco.service.cmr.action.ActionService;
+import org.alfresco.service.cmr.action.CompositeAction;
+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.dictionary.DictionaryService;
+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.cmr.rule.RuleService;
+import org.alfresco.service.cmr.rule.RuleType;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.web.scripts.Status;
+import org.alfresco.web.scripts.WebScriptException;
+import org.alfresco.web.scripts.WebScriptRequest;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Class to hold helper methods for the Rules / Actions
+ * REST API
+ *
+ * @author glen johnson at alfresco com
+ */
+public class RulesHelper
+{
+ // public constants for ActionQueueItem Statuses
+ public static final String ACTION_QUEUE_ITEM_STATUS_PENDING = "PENDING";
+ public static final String ACTION_QUEUE_ITEM_STATUS_COMPLETE = "COMPLETE";
+
+ // private constants
+ private static final String COMPOSITE_ACTION_DEF_NAME = "composite-action";
+ private static final String REQ_URL_PART_NODE_REF = "/api/node";
+ private static final String REQ_URL_PART_NODE_PATH = "/api/path";
+
+ // service dependencies
+ private ServiceRegistry serviceRegistry;
+
+ // dependencies
+ private Repository repositoryContext = null;
+
+ // list of valid rule type names
+ List validRuleTypeNames = null;
+
+ /**
+ * Set the service registry
+ *
+ * @param serviceRegistry the service registry
+ */
+ public void setServiceRegistry(ServiceRegistry serviceRegistry)
+ {
+ this.serviceRegistry = serviceRegistry;
+ }
+
+ /**
+ * Set the repository context
+ *
+ * @param repositoryContext the repositoryContext to set
+ */
+ public void setRepositoryContext(Repository repositoryContext)
+ {
+ this.repositoryContext = repositoryContext;
+ }
+
+ /**
+ * Init method.
+ */
+ public void init()
+ {
+ // Register a list of valid rule type names
+ RuleService ruleService = this.serviceRegistry.getRuleService();
+ validRuleTypeNames = new ArrayList();
+
+ List validRuleTypes = ruleService.getRuleTypes();
+ for (RuleType ruleType : validRuleTypes)
+ {
+ validRuleTypeNames.add(ruleType.getName());
+ }
+ }
+
+ /**
+ * Return if the given rule type name is a valid rule type
+ *
+ * @param ruleTypeName The rule type for which we want to test validity
+ *
+ * @return Whether or not the given rule type name is valid
+ */
+ public boolean isValidRuleTypeName(String ruleTypeName)
+ {
+ return validRuleTypeNames.contains(ruleTypeName);
+ }
+
+ /**
+ * Return a Rule object created/updated from a given rule JSON object.
+ *
+ * If a node reference is passed into the ruleNodeRefToUpdate
parameter,
+ * then this indicates that an existing rule (identified by that node
+ * reference) is to be updated from the given rule JSON object. If a 'null'
+ * node reference is passed in, then this indicates that a new rule is to
+ * be created from scratch.
+ *
+ * @param ruleJson the rule JSON object to create/update the rule from
+ * @param ruleNodeRefToUpdate The node reference of the rule to update.
+ * Set to null
if a new rule is to be created from scratch.
+ *
+ * @return The rule created from the given rule JSON object
+ */
+ public Rule getRuleFromJson(JSONObject ruleJson, NodeRef ruleNodeRefToUpdate)
+ {
+ // get a reference to the rule service
+ RuleService ruleService = this.serviceRegistry.getRuleService();
+
+ // set a boolean flag indicating whether or not to update an existing rule
+ boolean update = (ruleNodeRefToUpdate != null);
+
+ //
+ // update/create a rule object from the given rule JSON object
+ //
+ Rule rule = null;
+ if (update == true)
+ {
+ // we are doing an update of an existing rule so get
+ // the rule identified by the given rule node reference
+ // so that it can be updated with the rule details
+ // in the given rule JSON object
+ rule = ruleService.getRule(ruleNodeRefToUpdate);
+ }
+ else
+ {
+ // we are not doing an update, so create a new rule from scratch
+ rule = new Rule();
+ }
+
+ try
+ {
+ //
+ // set rule properties
+ //
+
+ if ((ruleJson.isNull("title") == true) && (update == true))
+ {
+ // this field is 'null' and we are doing an update
+ // so don't do anything
+ }
+ else
+ {
+ String ruleTitle = ruleJson.getString("title");
+ rule.setTitle(ruleTitle);
+ }
+
+ if ((ruleJson.isNull("description") == true) && (update == true))
+ {
+ // this field is 'null' and we are doing an update
+ // so don't do anything
+ }
+ else
+ {
+ rule.setDescription(ruleJson.optString("description", ""));
+ }
+
+ if ((ruleJson.isNull("executeAsync") == true) && (update == true))
+ {
+ // this field is 'null' and we are doing an update
+ // so don't do anything
+ }
+ else
+ {
+ rule.setExecuteAsynchronously(ruleJson.optBoolean("executeAsync", false));
+ }
+
+
+ if ((ruleJson.isNull("ruleDisabled") == true) && (update == true))
+ {
+ // this field is 'null' and we are doing an update
+ // so don't do anything
+ }
+ else
+ {
+ rule.setRuleDisabled(ruleJson.optBoolean("ruleDisabled", false));
+ }
+
+
+ if ((ruleJson.isNull("appliedToChildren") == true) && (update == true))
+ {
+ // this field is 'null' and we are doing an update
+ // so don't do anything
+ }
+ else
+ {
+ rule.applyToChildren(ruleJson.optBoolean("appliedToChildren", false));
+ }
+
+ //
+ // set rule types present in the rule details onto the rule
+ //
+
+ if ((ruleJson.isNull("ruleTypes") == true) && (update == true))
+ {
+ // this field is 'null' and we are doing an update
+ // so don't do anything
+ }
+ else
+ {
+ List ruleTypes = new ArrayList();
+ JSONArray ruleTypesJson = ruleJson.getJSONArray("ruleTypes");
+ int numRuleTypes = ruleTypesJson.length();
+
+ // make sure that at least one rule type has been sent in the rule details
+ if (numRuleTypes < 1)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "At least one rule type needs to be present in "
+ + "in the rule details sent in the request content.");
+ }
+
+ // add to the rule the rule type names sent in the rule details
+ for (int i=0; i < numRuleTypes; i++)
+ {
+ String ruleTypeNameJson = ruleTypesJson.getString(i);
+ if (isValidRuleTypeName(ruleTypeNameJson))
+ {
+ ruleTypes.add(ruleTypeNameJson);
+ }
+ else
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "An invalid rule type name was given in the "
+ + "rule details sent in the request content. Invalid rule type name given is: '"
+ + ruleTypeNameJson + "'");
+ }
+ }
+ rule.setRuleTypes(ruleTypes);
+ }
+
+ if ((ruleJson.isNull("action") == true) && (update == true))
+ {
+ // this field is 'null' and we are doing an update
+ // so don't do anything
+ }
+ else
+ {
+ // set the action supplied in the rule details onto the rule
+ JSONObject actionJson = ruleJson.getJSONObject("action");
+ Action action = getActionFromJson(actionJson);
+ rule.setAction(action);
+ }
+ }
+ catch (JSONException je)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "Problem creating rule from Rule Details sent in the request content.", je);
+ }
+
+ return rule;
+ }
+
+ /**
+ * Create and return an Action object from a given action JSON object
+ *
+ * @param actionJson the action JSON object to create the action from
+ *
+ * @return The action object created from the given action JSON object
+ */
+ @SuppressWarnings("unchecked")
+ public Action getActionFromJson(JSONObject actionJson)
+ {
+ Action action = null;
+ ActionService actionService = this.serviceRegistry.getActionService();
+
+ try
+ {
+ //
+ // create an action object from an "action" JSON object
+ //
+
+ String actionDefinitionName = actionJson.getString("actionDefinitionName");
+ JSONObject nestedActionsJson = actionJson.optJSONObject("actions");
+
+ // if action's definition name denotes that it is a composite action and the
+ // action JSON object has nested actions, then treat it as a composite action
+ if ((actionDefinitionName.equals(COMPOSITE_ACTION_DEF_NAME)) == true && (nestedActionsJson != null))
+ {
+ // create composite action object
+ action = actionService.createCompositeAction();
+
+ // recursively add nested actions to this composite action
+ // as some of those nested actions could also be composite actions
+ Iterator nestedActionsIteractor = nestedActionsJson.keys();
+ while (nestedActionsIteractor.hasNext())
+ {
+ String nestedActionKey = nestedActionsIteractor.next();
+ JSONObject nestedActionJson = nestedActionsJson.optJSONObject(nestedActionKey);
+
+ if (nestedActionJson != null)
+ {
+ Action nestedAction = getActionFromJson(nestedActionJson);
+ ((CompositeAction)action).addAction(nestedAction);
+ }
+ }
+ }
+ // else if the action definition name denotes that this is not a composite action,
+ // but nested actions have been provided in the action JSON Object
+ // then throw a Web Script Exception
+ else if ((actionDefinitionName.equals(COMPOSITE_ACTION_DEF_NAME) == false) && (nestedActionsJson != null))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Nested actions were sent in the action details "
+ + "having Title: '" + actionJson.optString("title") + "', but the action definition "
+ + "name thereof is not '" + COMPOSITE_ACTION_DEF_NAME + "' as expected. Instead, the action's "
+ + "definition name is '" + actionDefinitionName + "'.");
+ }
+ // else the action's definition name is 'composite-action' but no nested actions were provided in the action JSON
+ // (in which case we will just treat the action as a non-composite action anyway), otherwise the action is not
+ // defined as a composite action, and no nested actions were sent in the action JSON, so just create it as a
+ // non-composite action
+ else
+ {
+ action = actionService.createAction(actionDefinitionName);
+ }
+
+ //
+ // set action properties
+ //
+
+ action.setTitle(actionJson.getString("title"));
+
+ String descriptionDefault = actionJson.getString("title");
+ action.setDescription(actionJson.optString("description", descriptionDefault));
+
+ action.setExecuteAsynchronously(actionJson.optBoolean("executeAsync", false));
+
+ // set compensating action on current action if a compensating action is present
+ // in the action JSON Object
+ JSONObject compActionJson = actionJson.optJSONObject("compensatingAction");
+ if (compActionJson != null)
+ {
+ Action compAction = getActionFromJson(compActionJson);
+ action.setCompensatingAction(compAction);
+ }
+
+ // get the action's definition
+ ParameterizedItemDefinition actionDef = actionService.getActionDefinition(actionDefinitionName);
+
+ // if there are parameter values in the action JSON object then
+ // set them onto the action object
+ //
+ JSONObject actionParamValuesJson = actionJson.optJSONObject("parameterValues");
+ if (actionParamValuesJson != null)
+ {
+ setParameterValuesOnParameterizedItemFromJson(action, actionDef, actionParamValuesJson);
+ }
+
+ //
+ // set conditions on the current action
+ //
+
+ JSONObject conditionsJson = actionJson.optJSONObject("conditions");
+ Iterator conditionIterator = conditionsJson.keys();
+
+ // get each condition and add it to the action
+ while (conditionIterator.hasNext())
+ {
+ String conditionKey = conditionIterator.next();
+ JSONObject conditionJson = conditionsJson.getJSONObject(conditionKey);
+
+ // create the condition using the given condition definition name
+ String conditionDefName = conditionJson.getString("conditionDefinitionName");
+ ActionCondition condition = actionService.createActionCondition(conditionDefName);
+
+ // get the condition definition
+ ParameterizedItemDefinition conditionDef = actionService.getActionConditionDefinition(conditionDefName);
+
+ //
+ // set the condition's properties
+ //
+
+ condition.setInvertCondition(conditionJson.optBoolean("invertCondition", false));
+
+ //
+ // if there are parameter values on the condition JSON object
+ // then apply them to the condition object
+ //
+ JSONObject condParamValuesJson = conditionJson.optJSONObject("parameterValues");
+ if (condParamValuesJson != null)
+ {
+ setParameterValuesOnParameterizedItemFromJson(condition, conditionDef, condParamValuesJson);
+ }
+
+ // add condition to action object
+ action.addActionCondition(condition);
+ }
+ }
+ catch (JSONException je)
+ {
+ throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR,
+ "Problem creating rule from JSON passed into Web Script.", je);
+ }
+
+ return action;
+ }
+
+ /**
+ * Create and return a multi-valued parameter value from the given JSON object and
+ * parameter content type (QName)
+ *
+ * @param jsonObject The JSON object we want to convert to a multi-valued parameter value
+ * @param paramName The parameter name
+ * @param paramDataTypeDef The parameter's content type definition
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ public Serializable getMultiValuedParameterValueFromJsonObject(JSONObject jsonObject, String paramName,
+ DataTypeDefinition paramDataTypeDef)
+ {
+ ArrayList multiParamValue = new ArrayList(jsonObject.length());
+
+ //
+ // convert each parameter item String value from the given JSON object to a value
+ // corresponding to the given parameter content type and add that converted value
+ // to the multi-parameter array list
+ //
+ Iterator keysIterator = jsonObject.keys();
+ while (keysIterator.hasNext())
+ {
+ String key = keysIterator.next();
+ String paramValueItem = jsonObject.optString(key);
+
+ // if this keyed object from the given JSON object
+ // is present and can be represented as a String,
+ // then convert the string to the given parameter content
+ // type and add it to the multi-parameter array list
+ if (paramValueItem != null)
+ {
+ Object paramValueItemObj = DefaultTypeConverter.INSTANCE.convert(paramDataTypeDef, paramValueItem);
+ // if the parameter value object, converted using the parameter's data type, is of type Serializable
+ // then we can go ahead and add it as one of the parameter's values
+ if (paramValueItemObj instanceof Serializable)
+ {
+ multiParamValue.add(paramValueItemObj);
+ }
+ else
+ // otherwise the converted parameter value can't be added
+ {
+ throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR,
+ "Whilst building up the multi-valued parameter with name: '"
+ + paramName + "' and type: '" + paramDataTypeDef.getName() + "' an object was encountered "
+ + "that doesn't implement Serializable. Object value is: '" + paramValueItemObj
+ + "' and is of class name '" + paramValueItemObj.getClass().getName() +"'");
+ }
+ }
+ }
+
+ return multiParamValue;
+ }
+
+ /**
+ * Sets the parameter values from the given parameter values JSON object onto the given parameterized item object
+ *
+ * @param parameterizedItem The parameterized item object onto which we want to set the parameter values from
+ * the given parameter values JSON object
+ * @param parameterizedItemDef The definition for the given parameterized item
+ * @param paramValuesJson The JSON object containing the parameter values to set into the parameterized item object
+ */
+ @SuppressWarnings("unchecked")
+ public void setParameterValuesOnParameterizedItemFromJson(ParameterizedItem parameterizedItem,
+ ParameterizedItemDefinition parameterizedItemDef, JSONObject paramValuesJson)
+ {
+ // get a reference to the dictionary service
+ DictionaryService dictionaryService = this.serviceRegistry.getDictionaryService();
+
+ Iterator paramIterator = paramValuesJson.keys();
+ while (paramIterator.hasNext())
+ {
+ String paramName = paramIterator.next();
+ ParameterDefinition paramDef = parameterizedItemDef.getParameterDefintion(paramName);
+ QName paramType = paramDef.getType();
+ DataTypeDefinition paramDataTypeDef = dictionaryService.getDataType(paramType);
+ boolean isMultiValued = paramDef.isMultiValued();
+ boolean isMandatory = paramDef.isMandatory();
+
+ // throw web script exception if mandatory parameter value not provided
+ if (paramValuesJson.isNull(paramName) && (isMandatory == true))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Mandatory parameter with name: '"
+ + paramName + "' expected in sent content, but it was not present. Parameter belongs to "
+ + "parameterized item with ID: '" + parameterizedItem.getId() + "' and definition name: '"
+ + parameterizedItemDef.getName() + "'");
+ }
+ // else if a parameter value has been provided then handle this case
+ else if (paramValuesJson.isNull(paramName) == false)
+ {
+ // Try and get the parameter value as a JSON object (multi-valued parameter value).
+ JSONObject paramValueJsonObj = paramValuesJson.optJSONObject(paramName);
+
+ // throw web script exception if parameter value is not a JSONObject (optJSONObject() returned 'null')
+ // and parameter's definition says that it should be multi-valued
+ if ((paramValueJsonObj == null) && (isMultiValued == true))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Multi-valued parameter with name: '"
+ + paramName + "' expected in sent content, but value provided was not multi-valued."
+ + "Parameter value given is: " + paramValuesJson.opt(paramName) + ". "
+ + "Parameter belongs to parameterized item with ID: '" + parameterizedItem.getId()
+ + "' and definition name: '" + parameterizedItemDef.getName() + "'");
+ }
+ // else throw web script exception if value given is a JSON object
+ // (optJSONObject(paramName) didn't return 'null'), but parameter's definition says that it shouldn't
+ // be multi-valued
+ else if ((paramValueJsonObj != null) && (isMultiValued == false))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Multi-valued parameter with name: '"
+ + paramName + "' was sent in content, but parameter's definition says that it should not "
+ + "be multi-valued. Parameter value given is: " + paramValuesJson.opt(paramName) + ". "
+ + "Parameter belongs to parameterized item with ID: '" + parameterizedItem.getId()
+ + "' and definition name: '" + parameterizedItemDef.getName() + "'");
+ }
+ // else if value given is a JSON object (optJSONObject(paramName) didn't return 'null'),
+ // and the parameter's definition says that it should be multi-valued
+ // then go ahead and add the multi-valued parameter value to the parameterized item
+ else if ((paramValueJsonObj != null) && (isMultiValued == true))
+ {
+ Serializable multiParamValue = getMultiValuedParameterValueFromJsonObject(paramValueJsonObj,
+ paramName, paramDataTypeDef);
+ parameterizedItem.setParameterValue(paramName, multiParamValue);
+ }
+ // else if parameter value provided is not a JSON Object (optJSONObject(paramName) returned 'null')
+ // and the parameter's definition says that the parameter value should not be multi-valued, try and
+ // retrieve the parameter value as a String instead
+ else if ((paramValueJsonObj == null) && (isMultiValued == false))
+ {
+ String paramValueStr = paramValuesJson.optString(paramName);
+ // if parameter value can be retrieved as a String, then add that String parameter
+ // value to the parameterized item
+ if (paramValueStr != null)
+ {
+ Object paramValueObj = DefaultTypeConverter.INSTANCE.convert(paramDataTypeDef, paramValueStr);
+ if (paramValueObj instanceof Serializable)
+ {
+ parameterizedItem.setParameterValue(paramName, (Serializable)paramValueObj);
+ }
+ else
+ {
+ throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR,
+ "Whilst adding parameters to a parameterized item (action or condition) "
+ + "with ID '" + parameterizedItem.getId() + "' the parameter with name: '"
+ + paramName + "' and type: '" + paramType + "' has a value that doesn't "
+ + "implement Serializable. Object value is: '" + paramValueObj
+ + "' and is of class name '" + paramValueObj.getClass().getName() +"'");
+ }
+ }
+ // else parameter value could not be retrieved as a String value (optString(paramName) returned 'null')
+ // so give up with trying to process it and throw a web script exception
+ else
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Parameter with name: '"
+ + paramName + "' was sent in the request content, but it could not be retrieved and "
+ + "added to the parameterized item. Parameter value given is: " + paramValuesJson.opt(paramName) + ". "
+ + "Parameter belongs to parameterized item with ID: '" + parameterizedItem.getId()
+ + "' and definition name: '" + parameterizedItemDef.getName() + "'");
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Return a node reference to the node represented on a Web Script URL
+ * by the given store type, store id and id (which is either a node id or node path)
+ *
+ * @param request The Web Script request object
+ * @param storeType The store type associated with the node
+ * @param storeId The store id associated with the node
+ * @param id The id (or path) associated with the node
+ *
+ * @return The node reference associated with the given store type, store id and id
+ */
+ NodeRef getNodeRefFromWebScriptUrl(WebScriptRequest req, String storeType, String storeId, String id)
+ {
+ // work out which of storeType, storeId, id have been passed in
+ boolean storeTypeGiven = (storeType != null) && (storeType.length() > 0);
+ boolean storeIdGiven = (storeId != null) && (storeId.length() > 0);
+ boolean idGiven = (id != null) && (id.length() > 0);
+
+ NodeRef nodeRef = null;
+ // get the node reference from the storeType, storeId, id
+ if ((storeTypeGiven && storeIdGiven && idGiven))
+ {
+ // see if given ID is part of either a node reference or a node path
+ String urlTemplateMatch = req.getServiceMatch().getPath();
+ boolean nodeRefGiven = urlTemplateMatch.startsWith(REQ_URL_PART_NODE_REF);
+ boolean nodePathGiven = urlTemplateMatch.startsWith(REQ_URL_PART_NODE_PATH);
+
+ String referenceType = null;
+ if (nodeRefGiven)
+ {
+ referenceType = "node";
+ }
+ else if (nodePathGiven)
+ {
+ referenceType = "path";
+ }
+ else
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "{store_type}/{store_id}/{id} in URL is not preceded by either "
+ + "'" + REQ_URL_PART_NODE_REF + "' or '" + REQ_URL_PART_NODE_PATH + "'");
+ }
+
+ String[] reference = new String[3];
+ reference[0] = storeType;
+ reference[1] = storeId;
+ reference[2] = id;
+
+ nodeRef = this.repositoryContext.findNodeRef(referenceType, reference);
+ }
+
+ return nodeRef;
+ }
+}
diff --git a/source/java/org/alfresco/repo/web/scripts/rule/RulesPost.java b/source/java/org/alfresco/repo/web/scripts/rule/RulesPost.java
new file mode 100644
index 0000000000..284c1cc579
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/rule/RulesPost.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2005-2007 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 received 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 org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.rule.Rule;
+import org.alfresco.service.cmr.rule.RuleService;
+import org.alfresco.web.scripts.DeclarativeWebScript;
+import org.alfresco.web.scripts.Status;
+import org.alfresco.web.scripts.WebScriptException;
+import org.alfresco.web.scripts.WebScriptRequest;
+import org.json.JSONObject;
+
+/**
+ * Web Script to POST a Rule to the rule collection associated with the given actionable node.
+ *
+ * @author glen johnson at alfresco dot com
+ */
+public class RulesPost extends DeclarativeWebScript
+{
+ // private constants
+ private static final String URL_TEMPL_VAR_STORE_TYPE = "store_type";
+ private static final String URL_TEMPL_VAR_STORE_ID = "store_id";
+ private static final String URL_TEMPL_VAR_ID = "id";
+
+ // model property keys
+ private static final String MODEL_PROP_KEY_RULE = "rule";
+ private static final String MODEL_PROP_KEY_ACTIONABLE_NODE_REF = "actionableNodeRef";
+
+ // properties for services
+ private RuleService ruleService;
+
+ // properties for dependencies
+ private RulesHelper rulesHelper;
+
+ /**
+ * Set the ruleService property.
+ *
+ * @param ruleService The rule service instance to set
+ */
+ public void setRuleService(RuleService ruleService)
+ {
+ this.ruleService = ruleService;
+ }
+
+ /**
+ * Set the rules helper property
+ *
+ * @param rulesHelper the rulesHelper to set
+ */
+ public void setRulesHelper(RulesHelper rulesHelper)
+ {
+ this.rulesHelper = rulesHelper;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(
+ * org.alfresco.web.scripts.WebScriptRequest,
+ * org.alfresco.web.scripts.WebScriptResponse)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Map executeImpl(WebScriptRequest req,
+ Status status)
+ {
+ // initialise model to pass on for template to render
+ Map model = new HashMap();
+
+ String storeType = req.getServiceMatch().getTemplateVars().get(URL_TEMPL_VAR_STORE_TYPE);
+ // Handle if 'store_type' URL template token not provided
+ if ((storeType == null) || (storeType.length() == 0))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "The 'store_type' URL template token has not been provided in URL");
+ }
+
+ String storeId = req.getServiceMatch().getTemplateVars().get(URL_TEMPL_VAR_STORE_ID);
+ // Handle if 'storeId' URL template token not provided
+ if ((storeId == null) || (storeId.length() == 0))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "The 'storeId' URL template token has not been provided in URL");
+ }
+
+ String id = req.getServiceMatch().getTemplateVars().get(URL_TEMPL_VAR_ID);
+ // Handle if 'id' URL template token not provided
+ if ((id == null) || (id.length() == 0))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "The 'id' URL template token has not been provided in URL");
+ }
+
+ // get the posted rule JSON object by parsing request content
+ Object contentObj = req.parseContent();
+ if (contentObj == null || !(contentObj instanceof JSONObject))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Web Script request content must be a JSON Object. "
+ + "Request content is either a JSON Array or not of MIME-type application/json");
+ }
+ JSONObject ruleJson = (JSONObject)contentObj;
+
+ // get the rule from the rule JSON object
+ Rule rule = this.rulesHelper.getRuleFromJson(ruleJson, null);
+
+ // create the actionable node reference from the given
+ // URL template tokens
+ NodeRef actionableNodeRef = this.rulesHelper.getNodeRefFromWebScriptUrl(req, storeType, storeId, id);
+
+ // apply rule to actionable node
+ this.ruleService.saveRule(actionableNodeRef, rule);
+
+ // add objects to model for the template to render
+ model.put(MODEL_PROP_KEY_RULE, rule);
+ model.put(MODEL_PROP_KEY_ACTIONABLE_NODE_REF, actionableNodeRef);
+
+ return model;
+ }
+}