BPM-3 Advanced Workflow Deep Dive
-
Upload
alfresco-software -
Category
Technology
-
view
3.047 -
download
9
description
Transcript of BPM-3 Advanced Workflow Deep Dive
Agenda!
Service Tasks • Java Delegate Class!• Java Delegate Bean!• Arbitrary Expressions!
Listeners • Execution Listeners!• Task Listeners!
Scripting • Scope Variables!• Execution Variables!• Examples!
Timers
Questions
Service Tasks!
• Service Tasks allow Java code to be executed as part of a workflow!
• Allows easy unit testing and code re-use!
• Three ways to implement:!• JavaDelegate Class!
• JavaDelegate Bean:!
• Arbitrary Expression!
Service Tasks: Java Delegate Class!
• The supplied class must implement JavaDelegate interface!
• Fields can be set on the class!
• Use the ʻactiviti:classʼ attribute to specify the delegate class
<serviceTask id=“getMimetypet" name=“Get Mimetype” activiti:class="org.alfresco.examples.MimetypeGetter“ > <extensionElements> <activiti:field name=“document"> <activiti:expression>${dcwkflw_document}</activiti:expression> </activiti:field> </extensionElements> </serviceTask>
Service Tasks: Java Delegate Bean!
• The supplied bean must implement JavaDelegate interface!
• The same bean instance is used for all executions!
• The bean must be defined in Spring and registered with the activitiBeanRegistry!
• Use ʻactiviti:delegateExpressionʼ attribute to specify the delegate bean in the process definition:!
<serviceTask id=“getMimetype" name=“Get Mimetype“ activiti:delegateExpression="${mimetypeGetter}" />
Service Tasks: Java Delegate Bean!
• Recommended to extend BaseJavaDelegate class!
• Recommend extending baseJavaDelegate bean!
• If the bean class extends BaseJavaDelegate and the Spring bean definition extends baseJavaDelegate, then the bean will
automatically be registered with the activitiBeanRegistry and will have access to the serviceRegistry!
<bean id=“mimetypeGetter" parent="baseJavaDelegate" class="org.alfresco.example.MimetypeGetter" />
Service Tasks: Java Delegate Bean!
public class MimetypeGetter extends BaseJavaDelegate { @Override public void execute(DelegateExecution execution) throws Exception { ScriptNode document = (ActivitiScriptNode) execution.getVariable("dcwkflw_document"); NodeRef nodeRef = document.getNodeRef();
ServiceRegistry serviceRegistry = getServiceRegistry(); FileFolderService fileService = serviceRegistry.getFileFolderService(); FileInfo file = fileService.getFileInfo(nodeRef); String mimetype = file.getContentData().getMimetype();
execution.setVariable("dcwkflw_mimetype“, mimetype); } }
Service Tasks: Arbitrary Expression!
• Execute any arbitrary expression!
• The expression may reference any bean defined in Spring and
registered with the activitiBeanRegistry!
• A process variable can be specified for the return value using the
activiti:result attribute!
<serviceTask id=”getMimetype” name="Get Mimetype" activiti:resultVariable="dcwkflw_mimetype" activiti:expression=“${mimetypeGetter.getMimetype(dcwkflow_document)}” />!
Listeners!
• Used to react to certain events during workflow execution!
• Two types: TaskLisener and ExecutionListener!
• Three ways to configure, as with ServiceTasks:!• Listener Class:!<activiti:executionListener class="org.alfresco.example.MyExecutionListener" event=“start” />!
• Listener Bean:!<activiti:taskListener delegateExpression=“${myTaskListener}" event=“create" />!
• Arbitrary Expression <activiti:executionListener expression=“myPojo.myMethod(myVar)" event="start" />
Listeners: Execution Listener Events!• Event: Execution (Workflow) starts or ends!<extensionElements> <activiti:executionListener class=“org.alfresco.example.ExecutionEventLogger" event=“start” /> </extensionElements>!
• Event: Activiti (Workflow Node) starts or ends!<userTask id=“theTask” name=“The Task” > <extensionElements> <activiti:executionListener delegateExpression=“${executionEventLogger}" event=“end” /> </extensionElements> </userTask>!
• Event: Sequence Flow (Transition) is taken!<sequenceFlow id=“theFlow” sourceRef=“theTask” targetRef=“theEnd” > <extensionElements> <activiti:executionListener expression=“${logger.info(execution.eventName)}" /> </ sequenceFlow > </userTask>
Listeners: Execution Listener Implementation!
Execution Listener class or delegate bean must implement ExecutionListener interface:!
public class ExecutionEventLogger implements ExecutionListener { private static final Log LOGGER = LogFactory.getLog(ExecutionEventLogger.class);
@Override public void notify(DelegateExecution execution) throws Exception { String eventName = execution.getEventName(); LOGGER.info("Received event: " + eventName); }
}!
Listeners: Task Listener Events!• All Task Listeners defined inside task elements:!<userTask id=“theTask” name=“The Task” > <extensionElements> <activiti:taskListener ... [Listener Details] ... /> </extensionElements> </userTask>!
• Event: assignment is called when a task is assigned to a user,
usually called before create:!<activiti:taskListener event=“assignment” class=“org.alfresco.example.TaskEventLogger” />
• Event: create is called when the task is created, after assignment:!<activiti:taskListener event=“create” delegateExpression=“${taskEventLogger}” />
• Event: completed is called when the task is completed:!<activiti:taskListener event=“completed” expression=“${logger.info(task.eventName)}” />
Listeners: Task Listener Implementation!
Task Listener class or delegate bean must implement TaskListener interface:!
public class ExecutionEventLogger implements TaskListener { private static final Log LOGGER = LogFactory.getLog(ExecutionEventLogger.class);
@Override public void notify(DelegateTask task) { String eventName = task.getEventName(); LOGGER.info("Received event: " + eventName); }
}
Scripting!
• Scripting Lagnuage:!• JavaScript!
• Activiti Implementations:!• AlfrescoScriptDelegate!
• ScriptExecutionListener !
• ScriptTaskListener!
Scripting: Scope Variables!
• person ScriptNode, the current user!
• userhome ScriptNode, the home space of the current user!
• execution DelegateExecution, the current execution.!
• task DelegateTask, the current task (ScriptTaskListener only)!
• cancelled boolean, was the execution cancelled (ScriptExecutionListener only)!
• deleted boolean, was the execution deleted
(ScriptExecutionListener)!
Scripting: Execution Variables!
• All execution variables added to scope!
• Variable names translated from “prefix:suffix” to “prefix_suffix”!
• Associations and noderef properties converted to ScriptNodes!
• Use execution.setVariable(name, value) to modify variables!
• Check if a variable exists using:!
if (typeof <variable name> != 'undefined')
Scripting: Examples!
• Copy a task variable to a process variable:
execution.setVariable('dcwkflw_reviewOutcome', task.getVariable('dcwkflw_reviewOutcome'));
• Set a task property from a pocess variable if it exists:
if (typeof bpm_workflowDueDate != 'undefined') task.dueDate = bpm_workflowDueDate;
• Apply an aspect ʻdcwkflw:publishedʼ to a document:
var presentation = bpm_package.children[0]; // Get the presentation presentation.addAspect('dcwkflw:published'); // Apply published aspect
Timers!
• Timers are used to delay an event until a specified time/duration!
• Timers can be attached to three types of event:!• startEvent: Starts the workflow!
• intermediateCatchEvent: Between nodes/events!
• boundaryEvent: Associated with a node (e.g. a userTask)!
• Three ways to set trigger time:!• timeDate: Triggers at specified date/time!
• timeDuration: Triggers after specified delay duration!
• timeCycle: Triggers repeatedly with specified delay/interval!
• All dates/times/durations/intervals use ISO8601 format!
Timers: Start Event Date Example!
• Create a workflow which sends a Christmas Greeting
<!-- Start workflow at 12:05 on Christmas Day --> <startEvent id="start" >
<timerEventDefinition> <timeDate>2011-12-25T12:05:00</timeDate> </timerEventDefinition> </startEvent>
<sequenceFlow id='flow1' sourceRef='start' targetRef='sendGreeting' />
Timers: Intermediate Event Delay Example!
• Delay after some service task performs some asynchronous event
to wait for the job to complete:!
<sequenceFlow id='flow1' sourceRef='asyncJob' targetRef='waitForJobToFinish' />
<!-- Wait 1 hour 30 mins for the job to finish --> <intermediateEvent id="waitForJobToFinish" > <timerEventDefinition> <timeDuration>PT1H30M</timeDate> </timerEventDefinition> </intermediateEvent>
<sequenceFlow id='flow2' sourceRef='waitForJobToFinish' targetRef='nextTask' />
Timers: Repeating Boundary Event Example!
• Send a reminder email if a task isnʼt completed after 1 week.
Repeat the email every day for 3 days:! <userTask id="theTask" >
<!-- Wait 1 week, then repeat every 2 days a further 2 times --> <boundaryEvent id="repeatingNotification" cancelActivity="false" attachedToRef="theTask" /> <timerEventDefinition> <timeCycle>R3/P1W/P1D</timeDate> </timerEventDefinition> </boundaryEvent>
<sequenceFlow id='flow1' sourceRef='repeatingNotification' targetRef='sendEmail' />
<serviceTask id="sendEmail" activiti:delegateExpression="${sendEmailDelegate}" />