mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
First cut of hooking Alfresco JavaScript into jBPM process definition.
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@3486 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -38,6 +38,7 @@ import org.alfresco.service.namespace.QName;
|
|||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.mozilla.javascript.Context;
|
import org.mozilla.javascript.Context;
|
||||||
import org.mozilla.javascript.ImporterTopLevel;
|
import org.mozilla.javascript.ImporterTopLevel;
|
||||||
|
import org.mozilla.javascript.NativeJavaObject;
|
||||||
import org.mozilla.javascript.Scriptable;
|
import org.mozilla.javascript.Scriptable;
|
||||||
import org.mozilla.javascript.ScriptableObject;
|
import org.mozilla.javascript.ScriptableObject;
|
||||||
|
|
||||||
@@ -252,6 +253,12 @@ public class RhinoScriptService implements ScriptService
|
|||||||
// execute the script
|
// execute the script
|
||||||
Object result = cx.evaluateReader(scope, reader, "AlfrescoScript", 1, null);
|
Object result = cx.evaluateReader(scope, reader, "AlfrescoScript", 1, null);
|
||||||
|
|
||||||
|
// extract java object result if wrapped by rhinoscript
|
||||||
|
if (result != null && result.getClass().equals(NativeJavaObject.class))
|
||||||
|
{
|
||||||
|
result = Context.jsToJava(result, Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (Throwable err)
|
catch (Throwable err)
|
||||||
@@ -260,7 +267,7 @@ public class RhinoScriptService implements ScriptService
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
cx.exit();
|
Context.exit();
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
|
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005 Alfresco, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Mozilla Public License version 1.1
|
||||||
|
* with a permitted attribution clause. You may obtain a
|
||||||
|
* copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.alfresco.org/legal/license.txt
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||||
|
* either express or implied. See the License for the specific
|
||||||
|
* language governing permissions and limitations under the
|
||||||
|
* License.
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.workflow.jbpm;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.service.ServiceRegistry;
|
||||||
|
import org.alfresco.service.cmr.repository.ScriptService;
|
||||||
|
import org.dom4j.Element;
|
||||||
|
import org.jbpm.context.def.VariableAccess;
|
||||||
|
import org.jbpm.context.exe.ContextInstance;
|
||||||
|
import org.jbpm.graph.exe.ExecutionContext;
|
||||||
|
import org.jbpm.graph.exe.Token;
|
||||||
|
import org.jbpm.jpdl.xml.JpdlXmlReader;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A jBPM Action Handler for executing Alfresco Script
|
||||||
|
*
|
||||||
|
* The configuration of this action is as follows:
|
||||||
|
* <script language="javascript">
|
||||||
|
* <expression>
|
||||||
|
* the script to execute
|
||||||
|
* </expression>
|
||||||
|
* <variable name="watcha" access="write"/>
|
||||||
|
* </script>
|
||||||
|
*
|
||||||
|
* It's exactly the same as jBPM's own script configuration.
|
||||||
|
*
|
||||||
|
* @author davidc
|
||||||
|
*/
|
||||||
|
public class AlfrescoJavaScript extends JBPMSpringActionHandler
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = -2908748080671212745L;
|
||||||
|
|
||||||
|
private static JpdlXmlReader jpdlReader = new JpdlXmlReader((InputSource)null);
|
||||||
|
private ScriptService scriptService;
|
||||||
|
private Element script;
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler#initialiseHandler(org.springframework.beans.factory.BeanFactory)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initialiseHandler(BeanFactory factory)
|
||||||
|
{
|
||||||
|
scriptService = (ScriptService)factory.getBean(ServiceRegistry.SCRIPT_SERVICE.getLocalName());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void execute(ExecutionContext executionContext) throws Exception
|
||||||
|
{
|
||||||
|
// extract action configuration
|
||||||
|
String expression = null;
|
||||||
|
List<VariableAccess> variableAccesses = null;
|
||||||
|
if (script.isTextOnly())
|
||||||
|
{
|
||||||
|
expression = script.getTextTrim();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
variableAccesses = jpdlReader.readVariableAccesses(script);
|
||||||
|
expression = script.element("expression").getTextTrim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct script arguments and execute
|
||||||
|
Map<String, Object> inputMap = createInputMap(executionContext, variableAccesses);
|
||||||
|
Object result = scriptService.executeScriptString(expression, inputMap);
|
||||||
|
|
||||||
|
// map script return variable to process context
|
||||||
|
VariableAccess returnVariable = getWritableVariable(variableAccesses);
|
||||||
|
if (returnVariable != null)
|
||||||
|
{
|
||||||
|
ContextInstance contextInstance = executionContext.getContextInstance();
|
||||||
|
Token token = executionContext.getToken();
|
||||||
|
contextInstance.setVariable(returnVariable.getVariableName(), result, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct map of arguments to pass to script
|
||||||
|
*
|
||||||
|
* Based on the <variable> elements of the action configuration.
|
||||||
|
*
|
||||||
|
* @param executionContext the execution context
|
||||||
|
* @param variableAccesses the variable configuration
|
||||||
|
* @return the map of script arguments
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Map<String, Object> createInputMap(ExecutionContext executionContext, List<VariableAccess> variableAccesses)
|
||||||
|
{
|
||||||
|
Map<String, Object> inputMap = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
// initialise process variables
|
||||||
|
Token token = executionContext.getToken();
|
||||||
|
inputMap.put("executionContext", executionContext);
|
||||||
|
inputMap.put("token", token);
|
||||||
|
if (executionContext.getNode() != null)
|
||||||
|
{
|
||||||
|
inputMap.put("node", executionContext.getNode());
|
||||||
|
}
|
||||||
|
if (executionContext.getTask() != null)
|
||||||
|
{
|
||||||
|
inputMap.put("task", executionContext.getTask());
|
||||||
|
}
|
||||||
|
if (executionContext.getTaskInstance() != null)
|
||||||
|
{
|
||||||
|
inputMap.put("taskInstance", executionContext.getTaskInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no readable variableInstances are specified,
|
||||||
|
ContextInstance contextInstance = executionContext.getContextInstance();
|
||||||
|
if (!hasReadableVariable(variableAccesses))
|
||||||
|
{
|
||||||
|
// copy all the variableInstances of the context into the interpreter
|
||||||
|
Map<String, Object> variables = contextInstance.getVariables(token);
|
||||||
|
if (variables != null)
|
||||||
|
{
|
||||||
|
for (Map.Entry entry : variables.entrySet())
|
||||||
|
{
|
||||||
|
String variableName = (String) entry.getKey();
|
||||||
|
Object variableValue = entry.getValue();
|
||||||
|
inputMap.put(variableName, variableValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// copy the specified variableInstances into the interpreterz
|
||||||
|
for (VariableAccess variableAccess : variableAccesses)
|
||||||
|
{
|
||||||
|
if (variableAccess.isReadable())
|
||||||
|
{
|
||||||
|
String variableName = variableAccess.getVariableName();
|
||||||
|
String mappedName = variableAccess.getMappedName();
|
||||||
|
Object variableValue = contextInstance.getVariable(variableName, token);
|
||||||
|
inputMap.put(mappedName, variableValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if there are variables to read from the process context
|
||||||
|
*
|
||||||
|
* @param variableAccesses the variables configuration
|
||||||
|
* @return true => there are variables to read
|
||||||
|
*/
|
||||||
|
private boolean hasReadableVariable(List<VariableAccess> variableAccesses)
|
||||||
|
{
|
||||||
|
if (variableAccesses != null)
|
||||||
|
{
|
||||||
|
for (VariableAccess variableAccess : variableAccesses)
|
||||||
|
{
|
||||||
|
if (variableAccess.isReadable())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if there is a variable to write back to the process context
|
||||||
|
*
|
||||||
|
* @param variableAccesses the variables configuration
|
||||||
|
* @return true => there is a variable to write
|
||||||
|
*/
|
||||||
|
private VariableAccess getWritableVariable(List<VariableAccess> variableAccesses)
|
||||||
|
{
|
||||||
|
if (variableAccesses != null)
|
||||||
|
{
|
||||||
|
for (VariableAccess variableAccess : variableAccesses)
|
||||||
|
{
|
||||||
|
if (variableAccess.isWritable())
|
||||||
|
{
|
||||||
|
return variableAccess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -59,7 +59,7 @@ public class JBPMEngineTest extends BaseSpringTest
|
|||||||
WorkflowDefinition testWorkflowDef;
|
WorkflowDefinition testWorkflowDef;
|
||||||
NodeRef testNodeRef;
|
NodeRef testNodeRef;
|
||||||
|
|
||||||
|
|
||||||
//@Override
|
//@Override
|
||||||
protected void onSetUpInTransaction() throws Exception
|
protected void onSetUpInTransaction() throws Exception
|
||||||
{
|
{
|
||||||
@@ -308,6 +308,7 @@ public class JBPMEngineTest extends BaseSpringTest
|
|||||||
WorkflowDefinition workflowDef = getTestDefinition();
|
WorkflowDefinition workflowDef = getTestDefinition();
|
||||||
Map<QName, Serializable> parameters = new HashMap<QName, Serializable>();
|
Map<QName, Serializable> parameters = new HashMap<QName, Serializable>();
|
||||||
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "reviewer"), "admin");
|
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "reviewer"), "admin");
|
||||||
|
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "testNode"), testNodeRef);
|
||||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters);
|
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters);
|
||||||
assertNotNull(path);
|
assertNotNull(path);
|
||||||
assertNotNull(path);
|
assertNotNull(path);
|
||||||
@@ -331,6 +332,7 @@ public class JBPMEngineTest extends BaseSpringTest
|
|||||||
WorkflowDefinition workflowDef = getTestDefinition();
|
WorkflowDefinition workflowDef = getTestDefinition();
|
||||||
Map<QName, Serializable> parameters = new HashMap<QName, Serializable>();
|
Map<QName, Serializable> parameters = new HashMap<QName, Serializable>();
|
||||||
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "reviewer"), "admin");
|
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "reviewer"), "admin");
|
||||||
|
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "testNode"), testNodeRef);
|
||||||
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters);
|
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters);
|
||||||
assertNotNull(path);
|
assertNotNull(path);
|
||||||
assertNotNull(path);
|
assertNotNull(path);
|
||||||
@@ -359,7 +361,22 @@ public class JBPMEngineTest extends BaseSpringTest
|
|||||||
assertEquals(WorkflowTaskState.IN_PROGRESS, tasks1.get(0).state);
|
assertEquals(WorkflowTaskState.IN_PROGRESS, tasks1.get(0).state);
|
||||||
WorkflowTask updatedTask = taskComponent.endTask(tasks1.get(0).id, null);
|
WorkflowTask updatedTask = taskComponent.endTask(tasks1.get(0).id, null);
|
||||||
assertNotNull(updatedTask);
|
assertNotNull(updatedTask);
|
||||||
assertEquals(WorkflowTaskState.COMPLETED, updatedTask.state);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testScript()
|
||||||
|
{
|
||||||
|
WorkflowDefinition workflowDef = getTestDefinition();
|
||||||
|
Map<QName, Serializable> parameters = new HashMap<QName, Serializable>();
|
||||||
|
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "reviewer"), "admin");
|
||||||
|
parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "testNode"), testNodeRef);
|
||||||
|
WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters);
|
||||||
|
assertNotNull(path);
|
||||||
|
List<WorkflowTask> tasks1 = workflowComponent.getTasksForWorkflowPath(path.id);
|
||||||
|
assertNotNull(tasks1);
|
||||||
|
assertEquals(1, tasks1.size());
|
||||||
|
WorkflowTask updatedTask = taskComponent.endTask(tasks1.get(0).id, path.node.transitions[0]);
|
||||||
|
assertNotNull(updatedTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -9,8 +9,22 @@
|
|||||||
<variable name="testNode" access="write,required" />
|
<variable name="testNode" access="write,required" />
|
||||||
</controller>
|
</controller>
|
||||||
</task>
|
</task>
|
||||||
<transition name="" to="Review"></transition>
|
<transition name="" to="Review">
|
||||||
<transition name="end" to="end"></transition>
|
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
|
||||||
|
<script>
|
||||||
|
<expression>
|
||||||
|
function result()
|
||||||
|
{
|
||||||
|
return ("Process instance = " + executionContext.processInstance.id + ", testNode children = " + testNode.children.length);
|
||||||
|
}
|
||||||
|
result();
|
||||||
|
</expression>
|
||||||
|
<variable name="scriptResult" access="write"/>
|
||||||
|
</script>
|
||||||
|
</action>
|
||||||
|
</transition>
|
||||||
|
<transition name="end" to="end">
|
||||||
|
</transition>
|
||||||
</start-state>
|
</start-state>
|
||||||
<swimlane name="Reviewer">
|
<swimlane name="Reviewer">
|
||||||
<assignment actor-id="#{reviewer}"></assignment>
|
<assignment actor-id="#{reviewer}"></assignment>
|
||||||
@@ -20,6 +34,7 @@
|
|||||||
<script>
|
<script>
|
||||||
System.out.println("the reviewer is " + reviewer);
|
System.out.println("the reviewer is " + reviewer);
|
||||||
System.out.println("node " + testNode.name + " contains " + testNode.children.length + " children");
|
System.out.println("node " + testNode.name + " contains " + testNode.children.length + " children");
|
||||||
|
System.out.println("scriptResult = " + scriptResult);
|
||||||
</script>
|
</script>
|
||||||
</event>
|
</event>
|
||||||
<task name="Review" duedate="1 business day" blocking="true" swimlane="Reviewer">
|
<task name="Review" duedate="1 business day" blocking="true" swimlane="Reviewer">
|
||||||
@@ -27,7 +42,7 @@
|
|||||||
<variable name="comment" access="read,write,required"></variable>
|
<variable name="comment" access="read,write,required"></variable>
|
||||||
</controller>
|
</controller>
|
||||||
</task>
|
</task>
|
||||||
<transition name="" to="publish"></transition>
|
<transition name="" to="end"></transition>
|
||||||
</task-node>
|
</task-node>
|
||||||
<end-state name="end"></end-state>
|
<end-state name="end"></end-state>
|
||||||
</process-definition>
|
</process-definition>
|
Reference in New Issue
Block a user