bpm-3 advanced workflow deep dive

26
Advanced Workflow: Deeper Dive Nick Smith Senior Software Engineer, Services Team, Alfresco

Upload: alfresco-software

Post on 25-May-2015

3.047 views

Category:

Technology


9 download

DESCRIPTION

Get ready to dive into the details of Alfresco’s advanced workflow engine with members of the core Activiti team. Everything you ever wanted to know about Activiti but were afraid to ask. Stand back, because code will be slung. You may want to attend the Introduction to Advanced Workflows session before this one if you are new to the advanced workflow engine.

TRANSCRIPT

Advanced Workflow: Deeper Dive!

Nick Smith!Senior Software Engineer, Services Team, Alfresco!

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!

•  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!

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!

•  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!

•  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}" />

Questions ?!