Wednesday, February 18, 2009

Adding Custom Events using JBoss JBPM - JPDL

Adding Custom Events



Goal: Provide a mechanism to suspend a task for a period of time, and automatically resume the task after the time period is up.

Solution: Add custom Events for task suspend and task resume, override the suspend and resume methods in a custom task instance to fire the suspend and resume events.

1) Optional - Add two new EVENTTYPEs for suspend and resume to the org.jbpm.graph.def.Event class. (not necessary however, just a convenience)

public static final String EVENTTYPE_TASK_SUSPEND = "task-suspend";
public static final String EVENTTYPE_TASK_RESUME = "task-resume";

2) Optional - Add these to the supported EventTypes in the org.jbpm.graph.def.Task class. (not necessary since jBPM determines event-types dynamically).

static final String[] supportedEventTypes = new String[]{
Event.EVENTTYPE_TASK_CREATE,
Event.EVENTTYPE_TASK_ASSIGN,
Event.EVENTTYPE_TASK_START,
Event.EVENTTYPE_TASK_END,
Event.EVENTTYPE_TASK_SUSPEND,
Event.EVENTTYPE_TASK_RESUME

2) Subclass .jbpm.graph.exe.TaskInstance

Override Suspend and Resume

public void suspend(String date) {
super.suspend();
if ( (task!=null)
&& (token!=null)
) {
ExecutionContext executionContext = new ExecutionContext(token);
// the TASK_SUSPEND event is fired
executionContext.setTaskInstance(this);
executionContext.setTask(task);
executionContext.getTaskInstance().setVariable("suspendUntilDate", date);
task.fireEvent(Event.EVENTTYPE_TASK_SUSPEND, executionContext);
}
}

public void resume() {
super.resume();
if ( (task!=null)
&& (token!=null)
) {
ExecutionContext executionContext = new ExecutionContext(token);
// the TASK_RESUME event is fired
executionContext.setTaskInstance(this);
executionContext.setTask(task);
task.fireEvent(Event.EVENTTYPE_TASK_RESUME, executionContext);
}
}

3) Configure the timer on the task

<process-definition
xmlns="urn:jbpm.org:jpdl-3.1"
name="simple">
<action name="resume" class="com.sample.action.ResumeActionHander" />

<start-state name="start">
<transition name="" to="Create Order"></transition>
</start-state>
<end-state name="end"></end-state>
<task-node name="Approve Order" create-tasks="true">
<task name="approve" description="Review order">
<assignment class="com.sample.assignment.SomeAssignmentHandler"
</assignment>
<event type='task-suspend'>
<action name="Suspend Timer" class="com.sample.action.CreateTimerActionHandler">
<action>resume</action>
</action>
</event>
<event type="task-resume">
<action name="SendMessage" class="com.sample.action.MessageActionHandler">
<message>resumed the task instance</message>
</action>
</event>
<controller class="com.sample.taskinstance.CustomTaskControllerHandler"></controller>
</task>
<transition name="" to="end"></transition>
</task-node>
...
</process-definition>

4) Implement CreateTimerActionHandler

public class CreateTimerActionHandler implements ActionHandler {

private String action;

private static final long serialVersionUID = 1L;

/** {@inheritDoc} */
public void execute(ExecutionContext executionContext) throws Exception {
Timer timer = new Timer(executionContext.getToken());
timer.setName(executionContext.getAction().getName());

TaskInstance taskInstance = executionContext.getTaskInstance();
String dueDate = (String)taskInstance.getVariable("suspendUntilDate");

// parse the due date
DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT,
DateFormat.SHORT);
Date date = format.parse(dueDate);
timer.setDueDate(date);

// retrieve a named action from the process definition
Action action = executionContext.getProcessDefinition().getAction(
this.action);
timer.setAction(action);
// set the TaskInstance so the resume action knows what taskInstance to resume
timer.setTaskInstance(taskInstance);

SchedulerService schedulerService = (SchedulerService) Services
.getCurrentService(Services.SERVICENAME_SCHEDULER);
schedulerService.createTimer(timer);
}
}

5) Implement ResumeActionHandler

public class Resume implements ActionHandler {
public class ResumeActionHandler implements ActionHandler {

private static final long serialVersionUID = 1L;

public void execute(ExecutionContext executionContext) throws Exception {
System.out.println("resuming taskInstance");

TaskInstance taskInstance = executionContext.getTaskInstance();
System.out.println("TaskInstance is " + taskInstance);

CustomTaskInstance cti = (CustomTaskInstance) executionContext.getJbpmContext().getSession().load(CustomTaskInstance.class, new Long(taskInstance.getId()));
cti.resume();
}
}

Print this post

0 comments: