Monday, September 19, 2011

BPMN Activiti 5.7 - Example - Using Single Delegate class for multiple tasks

In Activiti by using Expressions and Delegate Expressions we can use one class (no need to implement JavaDelegate interface) for multiple service tasks.

Example:
1. I have created a class called AccountDelegate.java this class contains all the required methods for the tasks in the BPMN work flow.

The major thing you have to remember is you need to pass a DelegateExecution parameter to the method which you are invoking through the activit work flow. This will allows you to get the access to the execution context but this DelegateExecution method parameter is not mandatory. You can have a method without this parameter also.

package com.example.delegate

import org.activiti.engine.delegate.DelegateExecution;

public class AccountDelgate {

AccountService service = AccountService.createAccountService();

public int getAccountBalance(DelegateExecution execution,
String accountNumber) {
int amount = service.getAccountBalance(accountNumber);
return amount;
}

public boolean transferMoney(DelegateExecution execution,
String accountNumber1, String accountNumber2, int transferAmount) {

int balance = (Integer) execution.getVariable("accountBalance");

boolean result = false;
if (balance > transferAmount) {
result = service.transferMoney(accountNumber1, accountNumber2,
transferAmount);
}
return result;
}

/*
* Without delegation parameter also it works but to get the access to the
* execution context variables we have to pass DelegateExecution
*/
public int getAccountBalance(String accountNumber) {
int amount = service.getAccountBalance(accountNumber);
return amount;
}
}

After creating the above class go to activiti editor (use Eclipse Indigo 3.6 or Spring Source Tool Suite 2.5.1 or above. I am using STS (spring source tool suite))

Here is the diagram for this transfer money process(please do not confuse, I merged two service tasks properties into one diagram):




After completing the activiti diagram. We need to ActivitiDelegate.class file into the activiti.cfg.xml file so that it will availble to activiti engine. Basically we are adding ActivitiDelgate.class into spring context so it will available to activiti engine.

Here is the tag where you need to add.


Utitily class which I was used for creating some dummy bank accounts.

public class BankService {

public int getNumberOfAccounts(){
return 50;
}

public boolean createDummyAccounts(){
AccountService service = AccountService.createAccountService();
service.createAccount("MALLIKARJUN", 5000);
service.createAccount("RAO", 5000);
service.createAccount("MALLI", 5000);
service.depositMoney("DBN-MA-01000", 20000);
return true;
}
}

AccountService.java which has actual logic.

package com.example.delegate.service;

import java.util.ArrayList;
import java.util.List;

import com.example.delegate.util.Account;

public class AccountService {

private static AccountService accountService= null;
List accountList = new ArrayList();


public static AccountService createAccountService(){
if(accountService == null){
accountService = new AccountService();
}
return accountService;
}

public Account createAccount(String customerName,int minBalance){
Account account = new Account(customerName,minBalance);
accountList.add(account);
return account;
}
public int getAccountBalance(String accountNumber) {

Account account = findAccount(accountNumber);
int balance = 0;
if(account!=null){
balance = account.getBalance();
}
return balance;
}

public boolean transferMoney(String accountNumber1,String accountNumber2, int transferAmount) {
System.out.println("Transferring Money from "+accountNumber1 + " to "+ accountNumber2 +" an amount of Rs."+transferAmount);
Account account1 = findAccount(accountNumber1);
Account account2 = findAccount(accountNumber2);
System.out.println("accountNumber2 balance before transfer is "+account2.getBalance());
if(account1.getBalance()>transferAmount){
account1.setBalance(account1.getBalance()-transferAmount);
account2.setBalance(account2.getBalance()+transferAmount);
}else{
return false;
}
System.out.println("accountNumber2 balance after transfer is "+account2.getBalance());
return true;
}

public boolean depositMoney(String accountNumber, int amount){
Account account = findAccount(accountNumber);
account.setBalance(account.getBalance()+amount);
System.out.println("Rs."+amount+" successfully depositted in "+accountNumber);
return true;
}

public boolean withdrawMoney(String accountNumber, int amount){
Account account = findAccount(accountNumber);
account.setBalance(account.getBalance()-amount);
return true;
}

public Account findAccount(String accountNumber){

//System.out.println("accountNumber = "+accountNumber + "Size="+accountList.size());
for(Account a:accountList){
//System.out.println("Account Number = "+a.getAccountNumber());
if(a.getAccountNumber().equalsIgnoreCase(accountNumber)){
return a;
}
}
//System.out.println("Size="+accountList.size());
return null;
}

}

Account.java (POJO):

package com.example.delegate.util;

import java.io.Serializable;

public class Account implements Serializable {

private static final long serialVersionUID = 1L;

private String accountNumber;
private String customerName;
private int balance;
private String type;
private static int num;


public Account(String customerName,int minBalance){
this.accountNumber = "DBN-"+customerName.substring(0,2)+"-0100"+(num++);
this.customerName=customerName;
this.type="SA";
balance=minBalance;
}

public String getAccountNumber() {
return accountNumber;
}

public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}

public String getCustomerName() {
return customerName;
}

public void setCustomerName(String customerName) {
this.customerName = customerName;
}

public int getBalance() {
return balance;
}

public void setBalance(int balance) {
this.balance = balance;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

}

-----------------------------------------------------------------------------------
To execute the above program you can use the below main program.

package com.delegate.example.activiti;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import org.activiti.engine.RuntimeService;

import com.example.delegate.service.BankService;

public class ActivitiEngine {

public static void main(String args[]) {

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"classpath:activiti.cfg.xml");

BankService bankService = (BankService)applicationContext.getBean("bankService");
bankService.createDummyAccounts();

RuntimeService runtimeService = (RuntimeService) applicationContext
.getBean("runtimeService");

try {
runtimeService.startProcessInstanceByKey("TransferMoneyProcess");
} catch (Exception e) {
System.out.println("Error in TransferMoney Process ");
e.printStackTrace();
}

}
}
-------------------------------------------------------------------------------------

2 comments:

  1. its a very interesting article but I am unable to fully execute it. Please provide your whole project, thanking you in anticipation

    ReplyDelete
  2. You can reference the full project example at https://code.google.com/p/activiti-spring-maven/source/browse/trunk/activiti-spring-examples-maven/activiti-spring-examples-maven/ (from main group of Activiti)

    ReplyDelete