diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java index 51275d733b..41b897f11d 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java @@ -44,6 +44,7 @@ import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.workflow.WorkflowDefinition; import org.alfresco.service.cmr.workflow.WorkflowDeployment; @@ -98,7 +99,7 @@ public class JBPMEngine extends BPMEngine protected NodeService nodeService; protected ServiceRegistry serviceRegistry; protected PersonService personService; - private JbpmTemplate jbpmTemplate; + protected JbpmTemplate jbpmTemplate; // Note: jBPM query which is not provided out-of-the-box // TODO: Check jBPM 3.2 and get this implemented in jBPM @@ -1033,10 +1034,6 @@ public class JBPMEngine extends BPMEngine @SuppressWarnings("unchecked") protected Map getTaskProperties(TaskInstance instance) { - // establish task definition - TypeDefinition taskDef = getAnonymousTaskDefinition(getTaskDefinition(instance.getTask())); - Map taskAssocs = taskDef.getAssociations(); - // map arbitrary task variables Map properties = new HashMap(10); Map vars = instance.getVariablesLocally(); @@ -1050,32 +1047,23 @@ public class JBPMEngine extends BPMEngine // // Convert Nodes to NodeRefs - if (value instanceof org.alfresco.repo.jscript.Node) + if (value instanceof JBPMNode) { - value = ((org.alfresco.repo.jscript.Node)value).getNodeRef(); + value = ((JBPMNode)value).getNodeRef(); + } + else if (value instanceof JBPMNodeList) + { + JBPMNodeList nodes = (JBPMNodeList)value; + List nodeRefs = new ArrayList(nodes.size()); + for (JBPMNode node : nodes) + { + nodeRefs.add(node.getNodeRef()); + } + value = (Serializable)nodeRefs; } - // Convert Authority name to NodeRefs - QName qname = QName.createQName(key, this.namespaceService); - AssociationDefinition assocDef = taskAssocs.get(qname); - if (assocDef != null && assocDef.getTargetClass().equals(ContentModel.TYPE_PERSON)) - { - // TODO: Also support group authorities - if (value instanceof String[]) - { - value = mapNameToAuthority((String[])value); - } - else if (value instanceof String) - { - value = mapNameToAuthority(new String[] {(String)value}); - } - else - { - throw new WorkflowException("Task variable '" + qname + "' value is invalid format"); - } - } - // place task variable in map to return + QName qname = QName.createQName(key, this.namespaceService); properties.put(qname, (Serializable)value); } @@ -1091,10 +1079,16 @@ public class JBPMEngine extends BPMEngine Set pooledActors = instance.getPooledActors(); if (pooledActors != null) { - String[] pooledActorIds = new String[pooledActors.size()]; - pooledActors.toArray(pooledActorIds); - List pooledActorNodeRefs = mapNameToAuthority(pooledActorIds); - properties.put(WorkflowModel.ASSOC_POOLED_ACTORS, (Serializable)pooledActorNodeRefs); + List pooledNodeRefs = new ArrayList(pooledActors.size()); + for (String pooledActor : (Set)pooledActors) + { + NodeRef pooledNodeRef = mapNameToAuthority(pooledActor); + if (pooledNodeRef != null) + { + pooledNodeRefs.add(pooledNodeRef); + } + } + properties.put(WorkflowModel.ASSOC_POOLED_ACTORS, (Serializable)pooledNodeRefs); } return properties; @@ -1136,6 +1130,13 @@ public class JBPMEngine extends BPMEngine continue; } + // convert property value + value = (Serializable)DefaultTypeConverter.INSTANCE.convert(propDef.getDataType(), value); + if (value instanceof NodeRef) + { + value = new JBPMNode((NodeRef)value, serviceRegistry); + } + // map property to specific jBPM task instance field if (key.equals(WorkflowModel.PROP_DUE_DATE)) { @@ -1171,28 +1172,26 @@ public class JBPMEngine extends BPMEngine AssociationDefinition assocDef = taskAssocs.get(key); if (assocDef != null) { - // if association is to people, map them to authority names - // TODO: support group authorities - if (assocDef.getTargetClass().getName().equals(ContentModel.TYPE_PERSON)) - { - String[] authorityNames = mapAuthorityToName((List)value); - if (authorityNames != null && authorityNames.length > 0) - { - value = (Serializable) (assocDef.isTargetMany() ? authorityNames : authorityNames[0]); - } - } + // convert association to JBPMNodes + value = convertAssociation(assocDef, value); // map association to specific jBPM task instance field if (key.equals(WorkflowModel.ASSOC_POOLED_ACTORS)) { String[] pooledActors = null; - if (value instanceof String[]) + if (value instanceof JBPMNodeList[]) { - pooledActors = (String[])value; + JBPMNodeList actors = (JBPMNodeList)value; + pooledActors = new String[actors.size()]; + int i = 0; + for (JBPMNode actor : actors) + { + pooledActors[i++] = actor.getName(); + } } - else if (value instanceof String) + else if (value instanceof JBPMNode) { - pooledActors = new String[] {(String)value}; + pooledActors = new String[] {((JBPMNode)value).getName()}; } else { @@ -1202,64 +1201,88 @@ public class JBPMEngine extends BPMEngine continue; } } + + // untyped value, perform minimal conversion + else + { + if (value instanceof NodeRef) + { + value = new JBPMNode((NodeRef)value, serviceRegistry); + } + } } // no specific mapping to jBPM task has been established, so place into // the generic task variable bag String name = key.toPrefixString(this.namespaceService); - if (value instanceof NodeRef) - { - value = new JBPMNode((NodeRef)value, serviceRegistry); - } instance.setVariableLocally(name, value); } } - /** - * Convert a list of Alfresco Authorities to a list of authority Names - * - * @param authorities the authorities to convert - * @return the authority names + * Convert a Repository association to JBPMNodeList or JBPMNode + * + * @param assocDef association definition + * @param value value to convert + * @return JBPMNodeList or JBPMNode */ - private String[] mapAuthorityToName(List authorities) + private Serializable convertAssociation(AssociationDefinition assocDef, Serializable value) { - String[] names = null; - if (authorities != null) + boolean isMany = assocDef.isTargetMany(); + + if (value instanceof NodeRef) { - names = new String[authorities.size()]; - int i = 0; - for (NodeRef person : authorities) + if (isMany) { - String name = (String)nodeService.getProperty(person, ContentModel.PROP_USERNAME); - names[i++] = name; + // convert single node ref to list of node refs + JBPMNodeList values = new JBPMNodeList(); + values.add(new JBPMNode((NodeRef)value, serviceRegistry)); + value = (Serializable)values; + } + else + { + value = new JBPMNode((NodeRef)value, serviceRegistry); } } - return names; + + if (value instanceof List) + { + if (isMany) + { + JBPMNodeList values = new JBPMNodeList(); + for (NodeRef nodeRef : (List)value) + { + values.add(new JBPMNode(nodeRef, serviceRegistry)); + } + value = (Serializable)values; + } + else + { + value = new JBPMNode((NodeRef)value, serviceRegistry); + } + } + + return value; } /** - * Convert a list of authority Names to Alfresco Authorities + * Convert authority name to an Alfresco Authority * * @param names the authority names to convert * @return the Alfresco authorities */ - private List mapNameToAuthority(String[] names) + private NodeRef mapNameToAuthority(String name) { - List authorities = null; - if (names != null) + NodeRef authority = null; + if (name != null) { - authorities = new ArrayList(names.length); - for (String name : names) + // TODO: Should this be an exception? + if (personService.personExists(name)) { - // TODO: Should this be an exception? - if (personService.personExists(name)) - { - authorities.add(personService.getPerson(name)); - } + authority = personService.getPerson(name); } } - return authorities; + return authority; } /** diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java index 93146132b5..77fd5765a7 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java @@ -16,6 +16,7 @@ */ package org.alfresco.repo.workflow.jbpm; +import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; @@ -79,10 +80,11 @@ public class JBPMEngineTest extends BaseSpringTest assertEquals("Test", testWorkflowDef.title); assertEquals("1", testWorkflowDef.version); assertTrue(workflowComponent.isDefinitionDeployed(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML)); - + // get valid node ref NodeService nodeService = (NodeService)applicationContext.getBean(ServiceRegistry.NODE_SERVICE.getLocalName()); testNodeRef = nodeService.getRootNode(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "spacesStore")); + nodeService.setProperty(testNodeRef, ContentModel.PROP_CREATED, new Date()); } @@ -383,7 +385,6 @@ public class JBPMEngineTest extends BaseSpringTest parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "testNode"), testNodeRef); WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters); assertNotNull(path); - assertNotNull(path); List tasks1 = workflowComponent.getTasksForWorkflowPath(path.id); assertNotNull(tasks1); assertEquals(1, tasks1.size()); @@ -393,18 +394,31 @@ public class JBPMEngineTest extends BaseSpringTest } - public void testScript() + public void testWorkflowPackageNodeRef() { - WorkflowDefinition workflowDef = getTestDefinition(); + + } + + + public void testScript() + throws IOException + { + // deploy test script definition + ClassPathResource processDef = new ClassPathResource("org/alfresco/repo/workflow/jbpm/test_script.xml"); + assertFalse(workflowComponent.isDefinitionDeployed(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML)); + WorkflowDeployment deployment = workflowComponent.deployDefinition(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML); + assertNotNull(deployment); + + WorkflowDefinition workflowDef = deployment.definition; Map parameters = new HashMap(); - 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 tasks1 = workflowComponent.getTasksForWorkflowPath(path.id); assertNotNull(tasks1); assertEquals(1, tasks1.size()); - WorkflowTask updatedTask = taskComponent.endTask(tasks1.get(0).id, path.node.transitions[0].id); + assertEquals(WorkflowTaskState.IN_PROGRESS, tasks1.get(0).state); + WorkflowTask updatedTask = taskComponent.endTask(tasks1.get(0).id, null); assertNotNull(updatedTask); } diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMNode.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMNode.java index 718c8286ed..e644692ef6 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/JBPMNode.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMNode.java @@ -19,6 +19,7 @@ package org.alfresco.repo.workflow.jbpm; import java.io.Serializable; import java.util.Date; +import org.alfresco.repo.jscript.Node; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; @@ -79,7 +80,11 @@ public class JBPMNode extends org.alfresco.repo.jscript.Node @Override public Serializable convertValueForScript(ServiceRegistry services, Scriptable scope, QName qname, Serializable value) { - if (value instanceof Date) + if (value instanceof NodeRef) + { + return new JBPMNode(((NodeRef)value), services); + } + else if (value instanceof Date) { return value; } diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMNodeList.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMNodeList.java new file mode 100644 index 0000000000..7293641f3b --- /dev/null +++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMNodeList.java @@ -0,0 +1,9 @@ +package org.alfresco.repo.workflow.jbpm; + +import java.util.ArrayList; + + +public class JBPMNodeList extends ArrayList +{ + private static final long serialVersionUID = 1376915749912156471L; +} diff --git a/source/java/org/alfresco/repo/workflow/jbpm/NodeListConverter.java b/source/java/org/alfresco/repo/workflow/jbpm/NodeListConverter.java new file mode 100644 index 0000000000..97f48d2460 --- /dev/null +++ b/source/java/org/alfresco/repo/workflow/jbpm/NodeListConverter.java @@ -0,0 +1,96 @@ +/* + * 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.ArrayList; +import java.util.List; + +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.NodeRef; +import org.jbpm.context.exe.Converter; +import org.springframework.beans.factory.access.BeanFactoryLocator; +import org.springframework.beans.factory.access.BeanFactoryReference; +import org.springmodules.workflow.jbpm31.JbpmFactoryLocator; + + +/** + * jBPM Converter for transforming Alfresco Node to string and back + * + * @author davidc + */ +public class NodeListConverter implements Converter +{ + + private static final long serialVersionUID = 1L; + private static BeanFactoryLocator jbpmFactoryLocator = new JbpmFactoryLocator(); + + + /* (non-Javadoc) + * @see org.jbpm.context.exe.Converter#supports(java.lang.Object) + */ + public boolean supports(Object value) + { + if (value == null) + { + return true; + } + return (value.getClass() == JBPMNodeList.class); + } + + /* (non-Javadoc) + * @see org.jbpm.context.exe.Converter#convert(java.lang.Object) + */ + public Object convert(Object o) + { + Object converted = null; + if (o != null) + { + JBPMNodeList nodes = (JBPMNodeList)o; + List values = new ArrayList(nodes.size()); + for (JBPMNode node : nodes) + { + values.add(node.getNodeRef()); + } + converted = values; + } + return converted; + } + + /* (non-Javadoc) + * @see org.jbpm.context.exe.Converter#revert(java.lang.Object) + */ + @SuppressWarnings("unchecked") + public Object revert(Object o) + { + Object reverted = null; + if (o != null) + { + BeanFactoryReference factory = jbpmFactoryLocator.useBeanFactory(null); + ServiceRegistry serviceRegistry = (ServiceRegistry)factory.getFactory().getBean(ServiceRegistry.SERVICE_REGISTRY); + + List nodeRefs = (List)o; + JBPMNodeList nodes = new JBPMNodeList(); + for (NodeRef nodeRef : nodeRefs) + { + nodes.add(new JBPMNode(nodeRef, serviceRegistry)); + } + reverted = nodes; + } + return reverted; + } + +} diff --git a/source/java/org/alfresco/repo/workflow/jbpm/ReviewAndApproveTest.java b/source/java/org/alfresco/repo/workflow/jbpm/ReviewAndApproveTest.java new file mode 100644 index 0000000000..2a82a02c7e --- /dev/null +++ b/source/java/org/alfresco/repo/workflow/jbpm/ReviewAndApproveTest.java @@ -0,0 +1,152 @@ +/* + * 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.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.workflow.BPMEngineRegistry; +import org.alfresco.repo.workflow.TaskComponent; +import org.alfresco.repo.workflow.WorkflowComponent; +import org.alfresco.repo.workflow.WorkflowModel; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.workflow.WorkflowDefinition; +import org.alfresco.service.cmr.workflow.WorkflowDeployment; +import org.alfresco.service.cmr.workflow.WorkflowPath; +import org.alfresco.service.cmr.workflow.WorkflowTask; +import org.alfresco.service.cmr.workflow.WorkflowTaskState; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.BaseSpringTest; +import org.springframework.core.io.ClassPathResource; + + +/** + * Review and Approve workflow specific Tests + * + * @author davidc + */ +public class ReviewAndApproveTest extends BaseSpringTest +{ + AuthenticationComponent authenticationComponent; + PersonService personService; + WorkflowComponent workflowComponent; + TaskComponent taskComponent; + WorkflowDefinition testWorkflowDef; + NodeRef testNodeRef; + + + + @Override + protected void onSetUpInTransaction() throws Exception + { + personService = (PersonService)applicationContext.getBean("personService"); + BPMEngineRegistry registry = (BPMEngineRegistry)applicationContext.getBean("bpm_engineRegistry"); + workflowComponent = registry.getWorkflowComponent("jbpm"); + taskComponent = registry.getTaskComponent("jbpm"); + + // retrieve review and approve process definition +// ClassPathResource processDef = new ClassPathResource("org/alfresco/repo/workflow/jbpm/review_and_approve_processdefinition.xml"); +// assertTrue(workflowComponent.isDefinitionDeployed(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML)); +// List definitions = workflowComponent.getDefinitions(); +// for (WorkflowDefinition definition : definitions) +// { +// if (definition.title.equals("Review & Approve")) +// { +// testWorkflowDef = definition; +// break; +// } +// } + ClassPathResource processDef = new ClassPathResource("org/alfresco/repo/workflow/jbpm/review_and_approve_processdefinition.xml"); + WorkflowDeployment deployment = workflowComponent.deployDefinition(processDef.getInputStream(), MimetypeMap.MIMETYPE_XML); + testWorkflowDef = deployment.definition; + assertNotNull(testWorkflowDef); + + // run as system + authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent"); + authenticationComponent.setSystemUserAsCurrentUser(); + + // get valid node ref + NodeService nodeService = (NodeService)applicationContext.getBean(ServiceRegistry.NODE_SERVICE.getLocalName()); + testNodeRef = nodeService.getRootNode(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "spacesStore")); + nodeService.setProperty(testNodeRef, ContentModel.PROP_CREATED, new Date()); + } + + @Override + protected void onTearDownInTransaction() + { + authenticationComponent.clearCurrentSecurityContext(); + } + + + public void testWorkflowPackage() + { + WorkflowDefinition workflowDef = testWorkflowDef; + + Map params = new HashMap(); + params.put(WorkflowModel.ASSOC_PACKAGE, testNodeRef); + NodeRef reviewer = personService.getPerson("admin"); + params.put(QName.createQName("http://www.alfresco.org/model/workflow/1.0", "reviewer"), reviewer); + + WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, params); + assertNotNull(path); + List tasks1 = workflowComponent.getTasksForWorkflowPath(path.id); + assertNotNull(tasks1); + assertEquals(1, tasks1.size()); + + WorkflowTask task = tasks1.get(0); + assertTrue(task.properties.containsKey(WorkflowModel.ASSOC_PACKAGE)); + taskComponent.endTask(task.id, null); + + List assignedTasks = taskComponent.getAssignedTasks("admin", WorkflowTaskState.IN_PROGRESS); + assertNotNull(assignedTasks); + assignedTasks = filterTasksByWorkflowInstance(assignedTasks, path.instance.id); + + assertEquals(testNodeRef, assignedTasks.get(0).properties.get(WorkflowModel.ASSOC_PACKAGE)); + } + + /** + * Filter task list by workflow instance + * + * @param tasks + * @param processInstanceId + * @return + */ + private List filterTasksByWorkflowInstance(List tasks, String workflowInstanceId) + { + List filteredTasks = new ArrayList(); + for (WorkflowTask task : tasks) + { + if (task.path.instance.id.equals(workflowInstanceId)) + { + filteredTasks.add(task); + } + } + return filteredTasks; + } + +} diff --git a/source/java/org/alfresco/repo/workflow/jbpm/jbpm.converter.properties b/source/java/org/alfresco/repo/workflow/jbpm/jbpm.converter.properties index c53f2fd949..0201847cf7 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/jbpm.converter.properties +++ b/source/java/org/alfresco/repo/workflow/jbpm/jbpm.converter.properties @@ -15,4 +15,5 @@ G org.jbpm.context.exe.converter.FloatToDoubleConverter I org.jbpm.context.exe.converter.IntegerToLongConverter R org.jbpm.context.exe.converter.SerializableToByteArrayConverter H org.jbpm.context.exe.converter.ShortToLongConverter -N org.alfresco.repo.workflow.jbpm.NodeConverter \ No newline at end of file +N org.alfresco.repo.workflow.jbpm.NodeConverter +L org.alfresco.repo.workflow.jbpm.NodeListConverter \ No newline at end of file diff --git a/source/java/org/alfresco/repo/workflow/jbpm/jbpm.varmapping.xml b/source/java/org/alfresco/repo/workflow/jbpm/jbpm.varmapping.xml index fa44ad9758..77e7f26a0d 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/jbpm.varmapping.xml +++ b/source/java/org/alfresco/repo/workflow/jbpm/jbpm.varmapping.xml @@ -119,7 +119,7 @@ - + @@ -130,6 +130,17 @@ + + + + + + + + + + + diff --git a/source/java/org/alfresco/repo/workflow/jbpm/review_and_approve_processdefinition.xml b/source/java/org/alfresco/repo/workflow/jbpm/review_and_approve_processdefinition.xml index e3b9174a3a..8518b69726 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/review_and_approve_processdefinition.xml +++ b/source/java/org/alfresco/repo/workflow/jbpm/review_and_approve_processdefinition.xml @@ -1,23 +1,26 @@ - + + - + + - + + @@ -27,6 +30,7 @@ + @@ -35,6 +39,7 @@ + diff --git a/source/java/org/alfresco/repo/workflow/jbpm/test_script.xml b/source/java/org/alfresco/repo/workflow/jbpm/test_script.xml new file mode 100644 index 0000000000..afa0e33e43 --- /dev/null +++ b/source/java/org/alfresco/repo/workflow/jbpm/test_script.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +