BPM Workflow with Camunda BPM

Hi all,In my last post we have seen how to orchestrate BPEL process,but today we are going to see how we can develop a BPMN workflow using Camunda.This is also part of SOA stack,in my upcoming posts we will discuss about SOA technologies .

Briefly the below is the BPM work flow
Untitled

Please install the BPM modeling plugin and tools, also the Camunda BPM suite from the below link
download BPM modeling tools and BPM Suite

once we have all the software are in place, lets start our tutorial.
create a maven project and put all the dependencies in pom.xml as shown below.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.spark.camunda.bpm.process</groupId>
	<artifactId>TestBpmProcess</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>TestBpmProcess</name>
	<description>TestBpmProcess</description>

	<properties>
		<jdk.version>1.6</jdk.version>
	</properties>

	<dependencies>
		<!-- camunda engine dependency -->
		<dependency>
			<groupId>org.camunda.bpm</groupId>
			<artifactId>camunda-engine</artifactId>
			<version>7.1.0-Final</version>
			<scope>provided</scope>
		</dependency>

		<!-- camunda cdi beans -->
		<!-- <dependency> <groupId>org.camunda.bpm</groupId> <artifactId>camunda-engine-cdi</artifactId> 
			<version>7.1.0-Final</version> </dependency> -->

		<!-- provides a default EjbProcessApplication -->
		<!-- <dependency> <groupId>org.camunda.bpm.javaee</groupId> <artifactId>camunda-ejb-client</artifactId> 
			<version>7.1.0-Final</version> </dependency> -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.0.1</version>
			<scope>provided</scope>
		</dependency>
		
		<!-- Mysql dependency -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.6</version>
		</dependency>


		<!-- jars for email trigger -->
		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
			<version>1.4.7</version>
		</dependency>
		<dependency>
			<groupId>org.glassfish.extras</groupId>
			<artifactId>javaee</artifactId>
			<version>3.1.1</version>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.3</version>
				<configuration>
					<failOnMissingWebXml>false</failOnMissingWebXml>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version>
				<configuration>
					<source>${jdk.version}</source>
					<target>${jdk.version}</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

once we have the dependency ready, lets start coding our logic, lets start writing the logic for initial task form as follows.


<form class="form-horizontal">
	<div class="control-group">
		<label class="control-label">Customer ID</label>
		<div class="controls">
			<input form-field type="string" name="customerId" />
		</div>
	</div>
	<div class="control-group">
		<label class="control-label">Department</label>
		<div class="controls">
			<input form-field type="string" name="deptName" />
		</div>
	</div>
	<div class="control-group">
		<label class="control-label">Amount</label>
		<div class="controls">
			<input form-field type="number" name="amount" />
		</div>
	</div>
</form>

now lets map this task form to the start task of our BPM process as shown below.
request-loan

Now lets write a class to process the request and assign it to the “ProcessRequest” “ServiceTask” as shown below.

/**
 * 
 */
package com.spark.camunda.bpm.loanapproval;

import java.util.Map;

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;

/**
 * @author Sony
 * 
 */
public class ProcessRequestDeligate implements JavaDelegate {

	@Override
	public void execute(DelegateExecution delegateExecution) throws Exception {

		Map<String, Object> variables = delegateExecution.getVariables();
		if ("dept1".equalsIgnoreCase((String) variables.get("deptName"))) {
			delegateExecution.setVariable("deptName", (String) variables.get("deptName"));
			
		} else if ("dept2".equalsIgnoreCase((String) variables.get("deptName"))) {
			delegateExecution.setVariable("deptName", (String) variables.get("deptName"));
		}
	}

}

process-req

once done we need to decide the conditional flow for the exclusive gateway. this is shown below.

cond1

cond2

once the request is forwarded to human task based on the condition. Here the condition is the loan approval for a particular department(dept1,dept2) based on this the manager will approve the request for the respective department. lets write the task form for manager to approve the request as below.


<form class="form-horizontal">
	<div class="control-group">
		<label class="control-label">Customer ID</label>
		<div class="controls">
			<input form-field type="string" name="customerId" readonly="true" />
		</div>
	</div>
	<div class="control-group">
		<label class="control-label">Amount</label>
		<div class="controls">
			<input form-field type="number" name="amount" />
		</div>
	</div>
</form>

once the manager approves the loan request the requst gets persisted into database and a event mail gets triggered to the customer. please find the below is the persistence task logic

/**
 * 
 */
package com.spark.camunda.bpm.loanapproval;

import java.sql.Connection;
import java.sql.PreparedStatement;

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;

import com.spark.camunda.bpm.factory.SqlConnectionFactory;

/**
 * @author Sony
 * 
 */
public class PersistenceRequestDeligate implements JavaDelegate {

	@Override
	public void execute(DelegateExecution delegateExecution) throws Exception {

		SqlConnectionFactory connectionFactory = SqlConnectionFactory
				.getFactoryObject();
		Connection connection = connectionFactory.getSqlConnection();
		PreparedStatement preparedStatement = null;
		String sql = "insert into loanprocess(customer_id,amount) values (?,?)";
		preparedStatement = connection.prepareStatement(sql);
		preparedStatement.setString(1,
				delegateExecution.getVariable("customerId").toString());
		preparedStatement.setString(2, delegateExecution.getVariable("amount")
				.toString());
		preparedStatement.executeUpdate();

		preparedStatement.close();
		connection.close();
	}

}

please find the below is the event mail triggering logic

/**
 * 
 */
package com.spark.camunda.bpm.loanapproval;

import java.util.Properties;
import java.util.logging.Logger;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;

/**
 * @author Sony
 * 
 */
public class SendLoanApprovalConfirmation implements JavaDelegate {

	private final static Logger LOGGER = Logger.getLogger("SendLoanApprovalConfirmation");
	
	@Override
	public void execute(DelegateExecution delegateExecution) throws Exception {

		Properties props = new Properties();
		props.put("mail.smtp.host", "smtp.gmail.com");
		props.put("mail.smtp.socketFactory.port", "465");
		props.put("mail.smtp.socketFactory.class",
				"javax.net.ssl.SSLSocketFactory");
		props.put("mail.smtp.auth", "true");
		props.put("mail.smtp.port", "465");

		Session session = Session.getDefaultInstance(props,
				new javax.mail.Authenticator() {
					protected PasswordAuthentication getPasswordAuthentication() {
						return new PasswordAuthentication("xxx@gmail.com",
								"password");
					}
				});

		try {

			Message message = new MimeMessage(session);
			message.setFrom(new InternetAddress("xxx@gmail.com"));
			message.setRecipients(Message.RecipientType.TO,
					InternetAddress.parse("xxx@gmail.com"));
			message.setSubject("Loan Approval from John");
			message.setText("Dear Applicant your loan has got approved,"
					+ "\n\n please collect your check for the requested amount of"+delegateExecution.getVariable("amount"));

			Transport.send(message);

			LOGGER.info("processing mail sent to customer ID:"+delegateExecution.getVariable("customerId"));

		} catch (MessagingException e) {
			throw new RuntimeException(e);
		}
	}

}

please run mvn clean install package, now a war gets generated. Please deploy this war into JBoss Application server deployments folder and now start the camunda cockpit application and camunda tasklist application as shown below.

cockpit

create an instance by logging with demo/demo into camunda/tasklist application as shown below, since the entered details are for dept1 the approval goes to “john”(manager of dept1).

loanapproval

now go and see the camunda/cockpit it shows the present status of the BPM work flow as shown below.
waitingforapproval

Now john needs to login into task list to approve his assigned tasks, once he approves a automated mai is triggered to the applicant as shown below.
approvebyjohn

thats all folks now you are ready to code your own BPMN processes using Camunda BPM suit and JBoss App Server.
Happy Camunda BPMN WorkFlows 🙂 Happy SOA 🙂