Monday, January 3, 2011

Drools 5.1 Human Task Example

It has been a while seen my last post. Lately I have been working on BPMS and Drools. I try to create a simple app using Drools Flow and Human task and now have some small success.
While learning and creating my simple app, looking for example online was difficult. Try google "Drools 5.1 Human Task Example" and see what you will get. So I decide to put more example online for reference. It may not be as complete but I'll show the parts that is working.

What I try to do is like this.
I start a flow, then it will run Action 1, then the Human Task, where it need human/external interaction, then Action 2 and finish.
Action 1 and Action 2 will just print some text on the screen. (System.out.println(...))
Human Task has these properties:
The ActorId "mina" is just a value. I think (haven't try) we can either set it at design time or run time.

I use eclipse (with Drools plugin (core and task)) to create a new drools project. I end up having these libraries in the project. Can still be clean up a bit but... let's continue.



[tricky part: Error is main-1.4.jar is missing.]
Ok. now we start with a simple java class with a main function. In the class, we have:

 private static KnowledgeBase readKnowledgeBase() throws Exception {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("human_task_flow.bpmn"), ResourceType.BPMN2);
return kbuilder.newKnowledgeBase();
}
In the main function,


  try {
// load up the knowledge base
KnowledgeBase kbase = readKnowledgeBase();

EntityManagerFactory emf =
Persistence.createEntityManagerFactory( "org.drools.task" );
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, emf );

SystemEventListener systemEventListener = SystemEventListenerFactory.getSystemEventListener();

TaskService taskService = new TaskService(emf, systemEventListener);

TaskServiceSession taskSession = taskService.createSession();

taskSession.addUser(new User("Administrator"));
taskSession.addUser(new User("mina"));

MinaTaskServer server = new MinaTaskServer( taskService );
Thread thread = new Thread( server );
thread.start();

StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

WSHumanTaskHandler handler = new WSHumanTaskHandler();

ksession.getWorkItemManager().registerWorkItemHandler("Human Task", handler);

KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
// start a new process instance
ksession.startProcess("HumanTaskSample");

// ksession.fireAllRules();

logger.close();
} catch (Throwable t) {
t.printStackTrace();
}

Now we run the app and you will notice a lot of stuff printed out in the console. Hopefully there is no error. :p
[tricky part: You need to create the default user "Administrator", OR ELSE...]

To know what is happening, use the Drools Audit View to view the log.

You can see that Action 1 and Human Task were triggered.
At this stage, a Task is created and saved in the database. (lazy to explain how)
Now we use Human Task View (from Drools Task plugin) to lookup for the task using UserId "mina". You will see the task with Status Reserved.

You can now select the task and complete it (click the "Complete" button).

Stage 1 works, but what if I want to programmaticly complete the task? So I also written some task client code.

package com.geneoz.drools;

import java.util.List;

import org.drools.SystemEventListenerFactory;
import org.drools.task.User;
import org.drools.task.query.TaskSummary;
import org.drools.task.service.TaskClient;
import org.drools.task.service.mina.MinaTaskClientConnector;
import org.drools.task.service.mina.MinaTaskClientHandler;
import org.drools.task.service.responsehandlers.BlockingTaskOperationResponseHandler;
import org.drools.task.service.responsehandlers.BlockingTaskSummaryResponseHandler;

public class GeneozTaskClient {

public static void main(String... args) {
TaskClient client = new TaskClient(new MinaTaskClientConnector("mina",
new MinaTaskClientHandler(
SystemEventListenerFactory.getSystemEventListener())));
try {
client.connect("127.0.0.1", 9123);
BlockingTaskSummaryResponseHandler summaryHandler = new BlockingTaskSummaryResponseHandler();
client.getTasksAssignedAsPotentialOwner("mina", "en-UK",
summaryHandler);
List tasks = summaryHandler.getResults();
TaskSummary task = null;
for (TaskSummary taskSummary : tasks) {
System.out.println(taskSummary.getId() + " : "
+ taskSummary.getName());
task = taskSummary;
}
   if (task != null) {
BlockingTaskOperationResponseHandler operationHandler = new BlockingTaskOperationResponseHandler();
client.release(task.getId(), "mina", operationHandler);
client.claim(task.getId(), "Administrator", operationHandler);
operationHandler.waitTillDone(10000);

operationHandler = new BlockingTaskOperationResponseHandler();
client.start(task.getId(), "Administrator", operationHandler);
operationHandler.waitTillDone(10000);

operationHandler = new BlockingTaskOperationResponseHandler();
client.complete(task.getId(), "Administrator", null, operationHandler);
operationHandler.waitTillDone(10000);

}

} catch (Exception e) {
e.printStackTrace();
} finally {
try {
client.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
System.exit(0);

}
}
}
Some explanation:
1. Create a Mina Task Client
2. Connect to default MinaTaskServer
3. Find tasks belong to "mina"
4. Release the task (from "Reserved" state to "Ready" state) so that it can be claimed by other user.
5. Start and complete the task.

And now you will have Human Task completed and Action 2 triggered.

So this is where I am currently at for the moment. Hope to discover more stuff as I move on.
Hope this example can be helpful. Sorry for the bad English. :p


11 comments:

Rick said...

Thanks much! The Human Task explanation was good and very direct. (We need more examples like this, I wish others would post similar things.) Good luck with your next work, and please post again.

Best Regards,

Rick

Jw0rmC said...

very nice, thanks it's wondeful

Jw0rmC said...

thanks : - ) it's wonderful

Unknown said...

This is a very good one for beginners like me. Thanks very much

iostream said...

Can you explain me regarding how to save the drools flow state to database ? i try sometimes and ended with failure.

Ramkumar Tulswani said...

Where we can see that H2 databse where it is saving Process Instance.

Tony said...

Hello,
At the end, when I used "client.disconnect()", many TCP connections are not closed (netstat -an) but stay at "ESTABLISHED".

I think there is a problem with "client.disconnect()".

Do you know this problem ?

Best Regards,

Thanveer said...

In the main function code you have not explained about the impoerts to be used. Its confusing

Drools said...

But whenever i run my program , and see the database , there is only one row in task table ?? Why?

Eliezer said...

liked very much.
Where can I download the source code or pom?

Thank you.

Unknown said...

but for making dependency it is very difficult.