Activiti REST Client Example

Activiti REST Client

package com.nuke.activiti.client;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.MediaType;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ClientResource;
import org.slf4j.Logger;

/**
 * @author tmichels
 */
public class ActivitiClient {

	private static final Logger logger = org.slf4j.LoggerFactory.getLogger(NucleusClient.class);
	
	private static final String REST_URI = "http://activiti-dev.com:8090/api/activiti/v1";
	private static final String LDAP_USERNAME="xxxx";
	private static final String LDAP_PASSWORD="xxxx";
	
	private static ClientResource getClientResource(String uri) throws IOException{
		ClientResource clientResource = new ClientResource(uri);
		clientResource.setChallengeResponse(ChallengeScheme.HTTP_BASIC, LDAP_USERNAME, LDAP_PASSWORD);
        return clientResource;
	}
	
	public static List<String> getQueueNames(String username) throws JSONException, IOException{
		String authenticateUserUri = REST_URI + "/identity/users/"+username;
		Representation authenticateUserJSON = getClientResource(authenticateUserUri).get(MediaType.APPLICATION_JSON);
		JSONObject authenticateObject = new JSONObject(authenticateUserJSON.getText());
		logger.info("Get Queue Name: " + authenticateObject);
		if (!authenticateObject.opt("id").equals(null)) {
			List<String> queueForUser = new ArrayList<String>();
			String uri = REST_URI +"/repository/process-definitions";
			Representation response = getClientResource(uri).get(MediaType.APPLICATION_JSON);
			JSONObject object = new JSONObject(response.getText());
			JSONArray arr = (JSONArray) object.get("data");
			for (int i = 0; i < arr.length(); i++) {
				JSONObject ob = (JSONObject) arr.get(i);
				queueForUser.add(ob.get("name").toString());
			}
			return queueForUser;
		}
		return null;
	}

	public static String claimAndCompleteTaskByProcessIdAndActorName(String processInstanceId, String actorName) throws JSONException, IOException {
        try {
            String authenticateUserUri = REST_URI + "/identity/users/"+actorName;
            Representation authenticateUserJSON = getClientResource(authenticateUserUri).get(MediaType.APPLICATION_JSON);
            JSONObject authenticateObject = new JSONObject(authenticateUserJSON.getText());
            logger.info("AuthenticateObject: " + authenticateObject);
            if (!authenticateObject.opt("id").equals(null)) {
                String getTaskUri = REST_URI + "/runtime/tasks?candidate=" + actorName + "&size=1&order=asc&taskDefinitionKey=UnassignedLoan";
                Representation response = getClientResource(getTaskUri).get(MediaType.APPLICATION_JSON);
                JSONObject object = new JSONObject(response.getText());
                if (object != null) {
                    JSONArray arr = (JSONArray) object.get("data");
                    for (int i = 0; i < arr.length(); i++) {
                        JSONObject ob = (JSONObject) arr.get(i);
                        if (processInstanceId != null) {
                            if (ob.get("processDefinitionId").equals(processInstanceId)) {
                                logger.info("Returned task: " + ob);
                                if (ob.get("id") != null) {
                                    String claimUri = REST_URI + "/runtime/tasks/" + ob.get("id");
                                    logger.info("Claim URI: " + claimUri);
                                    JSONStringer jsAssignee = new JSONStringer();
                                    jsAssignee.object().key("assignee").value(actorName);
                                    jsAssignee.key("owner").value(actorName);
                                    jsAssignee.endObject();
                                    logger.info("jsAssignee: " + jsAssignee.toString());
                                    
                                    JSONStringer jsClaim = new JSONStringer();
                                    jsClaim.object().key("action").value("claim");
                                    jsClaim.endObject();
                                    logger.info("jsClaim: " + jsClaim.toString());
                                    
                                    JsonRepresentation jsonAssigneeRepresentation = new JsonRepresentation(jsAssignee);
                                    logger.info("jsonAssigneeRepresentation: " + jsonAssigneeRepresentation.getText());
                                    
                                    JsonRepresentation jsonClaimRepresentation = new JsonRepresentation(jsClaim);
                                    logger.info("jsonClaimRepresentation: " + jsonClaimRepresentation.getText());
                                    
                                    Representation assigneeResponse = getClientResource(claimUri).put(jsonAssigneeRepresentation);
                                    Representation claimResponse = getClientResource(claimUri).post(jsonClaimRepresentation);
                                    	
                                    logger.info("Assignee Response: " + assigneeResponse.getText());
                                    
                                    if (claimResponse.getText() == null) {
                                    	boolean completeTask = NucleusClient.completeTaskByIdWithVariables(ob.getString("description").toString(), actorName, null);
                                        logger.info("Complete Response: "  + completeTask);
                                        if (completeTask) {
                                        	 JSONObject taskByLoan = getTaskByLoanId(ob.getString("description").toString());
                                        	 JSONArray taskByLoanArray = (JSONArray) taskByLoan.get("data");
                                        	 if (!taskByLoanArray.isNull(0)) {
                                        		 JSONObject obTask = (JSONObject) taskByLoanArray.get(0);
                                            	 JSONStringer jsAssigneeAfterComplete = new JSONStringer();
                                            	 jsAssigneeAfterComplete.object().key("assignee").value(actorName);
                                            	 jsAssigneeAfterComplete.key("owner").value(actorName);
                                            	 jsAssigneeAfterComplete.endObject();
                                                 JsonRepresentation jsonAssigneeAfterCompleteRepresentation = new JsonRepresentation(jsAssigneeAfterComplete);
                                                 String claimAfterCompleteUri = REST_URI + "/runtime/tasks/" + obTask.get("id");
                                                 getClientResource(claimAfterCompleteUri).put(jsonAssigneeAfterCompleteRepresentation);
                                        	 }
                                            return ob.getString("description");
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                return null;
            }
            return null;
        }catch (Exception e){
        	logger.error("claimAndCompleteTaskByProcessIdAndActorName", e);
            return null;
        }
	}
	
	public static JSONObject getTaskByLoanId(String loanId) throws JSONException, IOException {
		String getTaskByLoanId = REST_URI +"/runtime/tasks?description=" + loanId + "&size=1";
        Representation response = getClientResource(getTaskByLoanId).get(MediaType.APPLICATION_JSON);
        JSONObject object = new JSONObject(response.getText());
        return object;
	}
	
	public static boolean completeTaskByIdWithVariables(String loanId, String actorName, Map<String, String> completeVariables) throws Exception {
        try {
            JSONObject loanjsonObjs = getTaskByLoanId(loanId);
            JSONArray loanArr = (JSONArray) loanjsonObjs.get("data");
            logger.info("LoanArr: " + loanArr);
            if (!loanArr.isNull(0) && loanArr.getJSONObject(0).has("id")) {
              JSONObject loanjsonObj = loanArr.getJSONObject(0);
          	  String uri = REST_URI + "/runtime/tasks/" + loanjsonObj.get("id").toString();

                JSONStringer jsComplete = new JSONStringer();
                jsComplete.object().key("action").value("complete");
              
                if (completeVariables!=null){
                    jsComplete.key("variables").array().object();
                    for (String completeVariable : completeVariables.keySet()) {
                        jsComplete.key("name").value(completeVariable).key("value").value(completeVariables.get(completeVariable));
                    }
                    jsComplete.endObject().endArray();
                }

                jsComplete.endObject();

                JsonRepresentation jsonCompleteRepresentation = new JsonRepresentation(jsComplete);
                logger.info("jsonCompleteRepresentation: " + jsonCompleteRepresentation.getText());
                if(completeVariables==null || !(loanArr.getJSONObject(0).getString("taskDefinitionKey").equals("SaveForLater") && completeVariables.get("disposition").equals("saveforlater"))) {
                	Representation completeResponse = getClientResource(uri).post(jsonCompleteRepresentation, MediaType.APPLICATION_JSON);
                	logger.info("Complete Response: " + completeResponse.getText());
                    if (completeResponse.getText()==null){
                    	if (completeVariables!=null && !completeVariables.get("disposition").equals("incomplete")) {
                    		 JSONObject taskByLoan = getTaskByLoanId(loanId);
                        	 JSONArray taskByLoanArray = (JSONArray) taskByLoan.get("data");
                        	 
                        	 if (!taskByLoanArray.isNull(0)) {
                        		 JSONObject obTask = (JSONObject) taskByLoanArray.get(0);
                         
                            	 JSONStringer jsAssigneeAfterComplete = new JSONStringer();
                            	 jsAssigneeAfterComplete.object().key("assignee").value(actorName);
                            	 jsAssigneeAfterComplete.key("owner").value(actorName);
                            	 jsAssigneeAfterComplete.endObject();
                                
                                 JsonRepresentation jsonAssigneeAfterCompleteRepresentation = new JsonRepresentation(jsAssigneeAfterComplete);
                                 String claimAfterCompleteUri = REST_URI + "/runtime/tasks/" + obTask.get("id");
                                 getClientResource(claimAfterCompleteUri).put(jsonAssigneeAfterCompleteRepresentation);
                        	 }
                    	}
                        return true;
                    }
                } else {
                	return true;
                }
            }
        }catch (Exception e){
          	e.printStackTrace();
              
        }
        return false;
	}
	
	public static String getProcessIdByName(String queueName) throws IOException, JSONException {
		String uri = REST_URI + "/repository/process-definitions";
		Representation response = getClientResource(uri).get(MediaType.APPLICATION_JSON);
		JSONObject object = new JSONObject(response.getText());
		if (object != null) {
			JSONArray arr = (JSONArray) object.get("data");
			for (int i = 0; i < arr.length(); i++) {
				JSONObject jsonObject = (JSONObject) arr.get(i);
				if (jsonObject.get("key").equals(queueName)) {
					logger.info("Returning processDefinitionId " + jsonObject.get("id"));
					return (String) jsonObject.get("id");
				}
			}
		}
		return null;
	}

	public static String createTaskByProcessId(String processDefinitionId, Map<String, String> taskVariables) throws Exception {
		String uri = REST_URI + "/runtime/process-instances";
		JSONStringer jsRequest = new JSONStringer();
		jsRequest.object().key("processDefinitionId").value(processDefinitionId).key("variables").array().object();
		for (String taskVariable : taskVariables.keySet()) {
			jsRequest.key("name").value(taskVariable).key("value").value(taskVariables.get(taskVariable));
		}
		jsRequest.endObject().endArray();
		jsRequest.endObject();
		Representation rep = new StringRepresentation(jsRequest.toString(), MediaType.APPLICATION_JSON);
		JSONObject jsObj = new JSONObject(getClientResource(uri).post(rep).getText());
		logger.info("Returned process: " + jsObj);
		if (jsObj.has("id")) {
			return  jsObj.getString("id");
		} else {
			return null;
		}
	}

	public static String getTaskIdByProcessIdAndActorName(String processInstanceId, String actorName) throws Exception {
		String uri = REST_URI + "/runtime/tasks?candidate=" +actorName;
		Representation response = getClientResource(uri).get(MediaType.APPLICATION_JSON);
		JSONObject object = new JSONObject(response.getText());
		if (object != null) {
			JSONArray arr = (JSONArray) object.get("data");
			for (int i = 0; i < arr.length(); i++) {
				JSONObject ob = (JSONObject) arr.get(i);
				if (ob.get("processDefinitionId").equals(processInstanceId)) {
					logger.info("Returned task: " + ob);
					logger.info("Returning taskId " + ob.get("id"));
					return (String) ob.get("id");
				}
			}
		}
		return null;
	}

	public static boolean claimTaskByIdAndActorName(String taskId, String actorName) throws Exception {
		String uri = REST_URI + "/runtime/tasks/" + taskId;

        JSONStringer jsClaim = new JSONStringer();
        jsClaim.object().key("action").value("claim");
        jsClaim.endObject();
        logger.info("jsClaim: " + jsClaim.toString());

        JsonRepresentation jsonClaimRepresentation = new JsonRepresentation(jsClaim);
        logger.info("jsonClaimRepresentation: " + jsonClaimRepresentation.getText());
		Representation claimResponse = getClientResource(uri).post(jsonClaimRepresentation, MediaType.APPLICATION_JSON);

        JSONStringer jsAssignee = new JSONStringer();
        jsAssignee.object().key("assignee").value(actorName);
        jsAssignee.key("owner").value(actorName);
        jsAssignee.endObject();
        logger.info("jsAssignee: " + jsAssignee.toString());
        
        JsonRepresentation jsonAssignRepresentation = new JsonRepresentation(jsAssignee);

        getClientResource(uri).put(jsonAssignRepresentation, MediaType.APPLICATION_JSON);

        return claimResponse.getText()==null;
	}


	@SuppressWarnings("unused")
	public static int getTaskCountByActorNameAndStatus(String actorName, String status) throws Exception {
		String uri = REST_URI + "/runtime/tasks?candidate=" + actorName + "&status=" + status;
		Representation response = getClientResource(uri).get(MediaType.APPLICATION_JSON);
		JSONObject object = new JSONObject(response.getText());
		if (object != null) {
			JSONArray arr = (JSONArray) object.get("data");
			logger.info("Tasklist " + actorName + " " + status + " size "	+ arr.length());
			return arr.length();
		}
		return -1;
	}
	
	public static List<String> taskQueryByActorNameBySizeAndOrder(String actorName,int size, String order, String status) throws Exception {
		List<String> taskForActor = new ArrayList<String>();
		String url = REST_URI + "/runtime/tasks?assignee="+ actorName +"&size=" + size + "&order="+order +"&status="+status;
		Representation response = getClientResource(url).get(MediaType.APPLICATION_JSON);
		if (response != null) {
			JSONObject object = new JSONObject(response.getText());
			if (object != null) {
				JSONArray arr = (JSONArray) object.get("data");
				for (int i = 0; i < arr.length(); i++) {
					JSONObject ob = (JSONObject) arr.get(i);
					taskForActor.add(ob.toString());
				}
			}
		}
		return taskForActor;
	}
}

Activiti REST Client Test

package com.nuke.activiti.client;

import static org.junit.Assert.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.json.JSONException;
import org.junit.Test;

import com.nuke.activiti.common.AbstractTest;

/**
 * @author tmichels
 */
public class ActivitiClientTest extends AbstractTest {
	
	@Test
	public void testGetQueueNamesAdmin() throws IOException, JSONException {
        List<String> queueNames = NucleusClient.getQueueNames("qatester_tools");
        for (String queueName : queueNames) {
            System.out.println(queueName);
        }
        assertNotNull(queueNames);
	}
	
	
	@Test
	public void testGetQueueNames() throws JSONException, IOException {
		List<String> queueNames = NucleusClient.getQueueNames("qatester_tools");
		for (String queueName : queueNames) {
			System.out.println(queueName);
		}
		assertNotNull(queueNames);
	}
	
	@Test
	public void testGetQueueTestEdgarNames() throws JSONException, IOException {
		List<String> queueNames = NucleusClient.getQueueNames("qatester_tools");
		for (String queueName : queueNames) {
			System.out.println(queueName);
		}
		assertNotNull(queueNames);
	}
	
	@Test
	public void testNewDiagram() throws IOException, JSONException {
		assertNotNull(NucleusClient.getProcessIdByName("underwritingQueue"));
		System.out.println("OUTPUT: " + NucleusClient.getProcessIdByName("bankVerificationQueue"));
		assertNotNull(NucleusClient.getProcessIdByName("bankVerificationQueue"));
	}
	
	
	@Test
	public void testWithUserInSameLDAPGroup() throws Exception {
		assertNotNull(NucleusClient.getTaskIdByProcessIdAndActorName(NucleusClient.getProcessIdByName("underwritingQueue"), "qatester_tools"));
	}
	
	@Test
	public void testGetQueueNamesNonReturn() throws JSONException, IOException {
		List<String> queueNames = NucleusClient.getQueueNames("dummy");
		assertNull(queueNames);
	}

    @Test
    public void testLoanComplete() throws Exception {
        String underwritingQueueProcessId = NucleusClient.getProcessIdByName("underwritingQueue");
        Map<String, String> processVariables = new HashMap<String, String>();
        processVariables.put("LoanId", "1");
        String processInstanceId = NucleusClient.createTaskByProcessId(underwritingQueueProcessId, processVariables);
        assertNotNull(processInstanceId);
        assertNotNull(NucleusClient.taskQueryByActorNameBySizeAndOrder("qatester_admin", 1, "asc", "open"));
        Map<String, String> completeVariables = new HashMap<String, String>();
        completeVariables.put("disposition", "complete");
        assertTrue(NucleusClient.completeTaskByIdWithVariables("1", "qatester_tools",completeVariables));
    }

 
    @Test
    public void testLoanInComplete() throws Exception{
        String underwritingQueueProcessId = NucleusClient.getProcessIdByName("underwritingQueue");
        Map<String, String> processVariables = new HashMap<String, String>();
        processVariables.put("LoanId", "2");
        NucleusClient.createTaskByProcessId(underwritingQueueProcessId, processVariables);
        assertTrue(NucleusClient.completeTaskByIdWithVariables("2", "qatester_admin", null));
        assertNotNull(NucleusClient.taskQueryByActorNameBySizeAndOrder("qatester_admin", 1, "asc", "open"));
        Map<String, String> completeVariables = new HashMap<String, String>();
        completeVariables.put("disposition", "incomplete");
        assertTrue(NucleusClient.completeTaskByIdWithVariables("2","qatester_tools", completeVariables));
        assertNotNull(NucleusClient.taskQueryByActorNameBySizeAndOrder("qatester_admin", 1, "asc", "open"));
    }

    @Test
    public void testSaveForLater() throws Exception{
        String underwritingQueueProcessId = NucleusClient.getProcessIdByName("underwritingQueue");
        Map<String, String> processVariables = new HashMap<String, String>();
        processVariables.put("LoanId", "3");
        String processInstanceId = NucleusClient.createTaskByProcessId(underwritingQueueProcessId, processVariables);
        System.out.println(processInstanceId);
        assertTrue(NucleusClient.completeTaskByIdWithVariables("3","qatester_tools", null));
        assertNotNull(NucleusClient.taskQueryByActorNameBySizeAndOrder("qatester_admin", 1, "asc", "open"));
        Map<String, String> completeVariables = new HashMap<String, String>();
        completeVariables.put("disposition", "saveforlater");
        assertTrue(NucleusClient.completeTaskByIdWithVariables("3", "qatester_tools",completeVariables));
    }


	@Test
	public void endToEndTest() throws Exception {
		String underwritingQueueProcessId = NucleusClient.getProcessIdByName("underwritingQueue");
		assertNotNull(underwritingQueueProcessId);
		Map<String, String> processVariables = new HashMap<String, String>();
		processVariables.put("LoanId", "00000000000");
		String processInstanceId = NucleusClient.createTaskByProcessId(underwritingQueueProcessId, processVariables);
		System.out.println("processInstanceId: " + underwritingQueueProcessId);
		assertNotNull(processInstanceId);
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(NucleusClient.getProcessIdByName("underwritingQueue"), "qatester_tools");
		assertNotNull(taskId);
		assertNotNull(NucleusClient.claimTaskByIdAndActorName(taskId, "qatester_tools"));

		assertNotNull(NucleusClient.completeTaskByIdWithVariables(taskId,"qatester_tools", null));

		assertNotNull(NucleusClient.getTaskCountByActorNameAndStatus("qatester_tools", "closed"));

        Map<String, String> completeVariables = new HashMap<String, String>();
        completeVariables.put("disposition", "saveforlater");
        NucleusClient.completeTaskByIdWithVariables(taskId,"qatester_tools", completeVariables);
        assertNotNull(NucleusClient.getTaskCountByActorNameAndStatus("qatester_tools", "closed"));
	}
	
	
	@Test
	public void testUserInSameLDAPGroup() throws Exception {
		assertNotNull(NucleusClient.getTaskIdByProcessIdAndActorName(NucleusClient.getProcessIdByName("underwritingQueue"), "qatester_tools"));
	}
	
	
	@Test
	public void testGetProcessIdByName() throws Exception {
		String queueProcessId = NucleusClient.getProcessIdByName("underwritingQueue");
		assertNotNull(queueProcessId);
	}
	
	@Test
	public void testCreateTaskByProcessId() throws Exception {
		String underwritingQueueProcessId = NucleusClient.getProcessIdByName("underwritingQueue");
		assertNotNull(underwritingQueueProcessId);
		Map<String, String> processVariables = new HashMap<String, String>();
		processVariables.put("LoanId", "332233555");
		String createComplete = NucleusClient.createTaskByProcessId(underwritingQueueProcessId, processVariables);
		System.out.println("CREATE COMPLETE: " + createComplete);
		assertNotNull(createComplete);
	}
	
	@Test
	public void testTaskByActorName() throws Exception {
		String processId = NucleusClient.getProcessIdByName("underwritingQueue");
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(processId, "qatester_tools");
		assertNotNull(taskId);
	}
	
	@Test
	public void testClaimTaskById() throws Exception {
		String processId = NucleusClient.getProcessIdByName("underwritingQueue");
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(processId, "qatester_tools");
		assertNotNull(NucleusClient.claimTaskByIdAndActorName(taskId, "qatester_tools"));
	}
	
	@Test
	public void testCompleteTaskById() throws Exception {
		String processId = NucleusClient.getProcessIdByName("underwritingQueue");
		Map<String, String> processVariables = new HashMap<String, String>();
		processVariables.put("LoanId", "3333333333");
		NucleusClient.createTaskByProcessId(processId, processVariables);
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(processId, "qatester_tools");
		Map<String, String> completeVariables = new HashMap<String, String>();
		completeVariables.put("disposition", "complete");
		assertNotNull(NucleusClient.completeTaskByIdWithVariables(taskId,"qatester_tools", completeVariables));
	}
	
	@Test
	public void testIncompleteTaskById() throws Exception{
		String processId = NucleusClient.getProcessIdByName("underwritingQueue");
		Map<String, String> processVariables = new HashMap<String, String>();
		processVariables.put("LoanId", "4444444444");
		NucleusClient.createTaskByProcessId(processId, processVariables);
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(processId, "qatester_tools");
		Map<String, String> completeVariables = new HashMap<String, String>();
		completeVariables.put("disposition", "incomplete");
		assertNotNull(NucleusClient.completeTaskByIdWithVariables(taskId,"qatester_tools", completeVariables));
	}
	
	@Test
	public void testSaveForLaterTaskById() throws Exception {
		String processId = NucleusClient.getProcessIdByName("underwritingQueue");
		Map<String, String> processVariables = new HashMap<String, String>();
		processVariables.put("LoanId", "5555555555");
		String creatProcessId = NucleusClient.createTaskByProcessId(processId, processVariables);
		System.out.println("CreatedProcessId: " + creatProcessId);
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(processId, "qatester_tools");
		Map<String, String> completeVariables = new HashMap<String, String>();
		completeVariables.put("disposition", "saveforlater");
		assertNotNull(NucleusClient.completeTaskByIdWithVariables(taskId,"qatester_tools", completeVariables));
	}
	
	@Test
	public void testGetTaskCountByActorNameAndStatus() throws Exception {
		int taskCount = NucleusClient.getTaskCountByActorNameAndStatus("qatester_tools", "open");
		assertNotNull(taskCount);
	}
	
	@Test
	public void testTaskQueryForActorNameBySizeAndOrder() throws Exception {
		List<String> taskIds = NucleusClient.taskQueryByActorNameBySizeAndOrder("qatester_tools", 5, "asc", "open");
		for (String taskId : taskIds) {
			System.out.println("TASKID: " + taskId);
		}
		assertNotNull(taskIds);
	}
	
	@Test
	public void testGetTaskClaimAndCompleteTaskByProcessIdAndActorName() throws JSONException, IOException {
		assertNotNull(NucleusClient.claimAndCompleteTaskByProcessIdAndActorName(NucleusClient.getProcessIdByName("underwritingQueue"), "qatester_tools"));
	}

    @Test
    public void testGetTaskClaimAndCompleteTaskByProcessIdAndActorNameWithWrongActorName() throws Exception{
        assertNull(NucleusClient.claimAndCompleteTaskByProcessIdAndActorName(NucleusClient.getProcessIdByName("underwritingQueue"), "dummy"));
    }

    @Test
    public void testGetTaskClaimAndCompleteTaskByProcessIdAndActorNameWithWrongProcessName() throws Exception{
        assertNull(NucleusClient.claimAndCompleteTaskByProcessIdAndActorName(NucleusClient.getProcessIdByName("dummy"), "dummy"));
    }


    @Test
    public void testProccessIdReturnNullWhenInvalid() throws IOException, JSONException {
        assertNull(NucleusClient.getProcessIdByName("dummy"));
    }

	@Test
	public void testGetTaskByLoanId() throws JSONException, IOException {
		assertNotNull(NucleusClient.getTaskByLoanId("259190367").getJSONArray("data"));
	}
	
	@Test
	public void testSaveForlater() throws Exception {
		Map<String, String> completeVariables = new HashMap<String, String>();
		completeVariables.put("disposition", "complete");
		NucleusClient.completeTaskByIdWithVariables("685363", "qatester_tools", completeVariables);
	}
	
	@Test
	public void testSaveForLaterIfAlreadySaveForLater() throws Exception {
		String processId = NucleusClient.getProcessIdByName("underwritingQueue");
		String taskId = NucleusClient.getTaskIdByProcessIdAndActorName(processId, "qatester_tools");
		System.out.println("TaskId: " + taskId);
		Map<String, String> completeVariables = new HashMap<String, String>();
		completeVariables.put("disposition", "incomplete");
		assertNotNull(NucleusClient.completeTaskByIdWithVariables("1111111111","qatester_tools", completeVariables));
	}
}

Integrating Activiti with Active Directory

Integrating Activiti with LDAP can be tricky. Through trail and error I got Active Directory working with Activit. The configuration may not be exactly the same for your organization, all depends on how your LDAP is setup.

package com.nuke.ldap;

import java.util.HashMap;
import java.util.Map;

import org.activiti.ldap.LDAPConfigurator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import com.nuke.activiti.annotations.ActivitiProd;

@Configuration
@ActivitiProd
public class LDAPProdConfiguration {

	@Value("${LDAP_URL:}")
	private String ldapUrl;

	@Value("${LDAP_SERVICE_ACCOUNT_NAME:}")
    private String ldapServiceAccountUserName;

	@Value("${LDAP_SERVICE_ACCOUNT_CN:}")
    private String ldapServiceAccountUserNameCn;
    
	@Value("${LDAP_SERVICE_ACCOUNT_PASSWORD:}")
    private String ldapServiceAccountPassword;

	@Value("${LDAP_SEARCH_FILTER:}")
    private String ldapSearchFilter;

	@Bean(name="ldapProd")
	public LDAPConfigurator LDAProdPConfig(){
		LDAPConfigurator ldapProdConfig = new LDAPConfigurator();
		ldapProdConfig.setServer(ldapUrl);
		ldapProdConfig.setUser(ldapServiceAccountUserNameCn);
		ldapProdConfig.setPassword(ldapServiceAccountPassword);
		
		ldapProdConfig.setBaseDn("OU=Security Groups,DC=Corp,DC=internal,DC=us"); 
		ldapProdConfig.setUserBaseDn("OU=Service Accounts,DC=Corp,DC=internal,DC=us");
		ldapProdConfig.setGroupBaseDn("OU=Security Groups,DC=Corp,DC=internal,DC=us");
		
		ldapProdConfig.setQueryUserByUserId("(&(objectClass=user)(sAMAccountName={0}))");
		ldapProdConfig.setQueryUserByFullNameLike("(&(objectClass=user)(|({0}=*{1}*)({2}=*{3}*)))");
		ldapProdConfig.setQueryGroupsForUser("(&(objectClass=group)(member={0}))");
		
		Map<String, String> connectionMap = new HashMap<String, String>();
		connectionMap.put("InitialDirContext", "Context.REFERRAL");
		ldapProdConfig.setCustomConnectionParameters(connectionMap);
		
		ldapProdConfig.setUserIdAttribute("cn");
		ldapProdConfig.setUserFirstNameAttribute("givenName");
		ldapProdConfig.setUserLastNameAttribute("sn");
		
		ldapProdConfig.setGroupIdAttribute("sAMAccountName");
		ldapProdConfig.setGroupNameAttribute("sAMAccountName");
		
		return ldapProdConfig;
	}
}

Activiti BPM Tutorial – Web Services

Start Activiti REST Server in Main

package com.nuke.main;

import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.identity.User;
import org.activiti.rest.service.application.ActivitiRestServicesApplication;
import org.restlet.Component;
import org.restlet.data.Protocol;

import com.nuke.activiti.CustomProcessEngineConfig;

public class ExpenseProcessRESTMain {
	
	private static final String filename = "/Users/tmichels/Documents/workspace-sts-3.5.0.M21/nucleus-workflow/src/main/resources/diagrams/expense_process.bpmn";
	
	public static void main(String[] args) throws Exception {
		ProcessEngineConfiguration engineConfig = CustomProcessEngineConfig.createStandaloneInMemProcessEngineConfiguration();
	    ProcessEngine processEngine = engineConfig.buildProcessEngine();
	    
	    User newUser = processEngine.getIdentityService().newUser("kermit");
	    newUser.setPassword("kermit");
	    processEngine.getIdentityService().saveUser(newUser);

	    processEngine.getRepositoryService().createDeployment()
	    	.addInputStream("expense_process.bpmn",
				new FileInputStream(filename)).deploy();
	    
	    Map variableMap1 = new HashMap();
		variableMap1.put("employee", "Jack");
		variableMap1.put("amount", 111);
		
		processEngine.getRuntimeService().startProcessInstanceByKey("expenseProcess", variableMap1);
		
		Component component = new Component();
	    component.getServers().add(Protocol.HTTP, 8182);
	    ActivitiRestServicesApplication restApplication = new ActivitiRestServicesApplication();
	    // Attach the Activiti REST-application and start
	    component.getDefaultHost().attach("/activiti-rest",
	    		restApplication);
	    component.start();
	}
}

Create Activiti REST Server in web.xml

<?xml version="1.0" encoding="UTF-8"?>  
<web-app id="WebApp_ID" version="2.4"  
            xmlns="http://java.sun.com/xml/ns/j2ee"  
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
            xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee  
                 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  
  
  <display-name>Activiti REST</display-name>
   
  <listener>
    <listener-class>org.activiti.rest.common.servlet.ActivitiServletContextListener</listener-class>
  </listener> 
  
  <!-- Restlet adapter -->  
  <servlet>  
    <servlet-name>RestletServlet</servlet-name>  
    <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
    <init-param>
      <!-- Application class name -->
      <param-name>org.restlet.application</param-name>
      <param-value>org.activiti.rest.service.application.ActivitiRestServicesApplication</param-value>
    </init-param>
  </servlet>
  
  <!-- Catch all requests -->  
  <servlet-mapping>  
    <servlet-name>RestletServlet</servlet-name>  
    <url-pattern>/service/*</url-pattern>  
  </servlet-mapping>  
</web-app>

Activiti REST Client

package com.nuke.activiti.client;

import java.io.IOException;

import org.apache.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.MediaType;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ClientResource;

public class ActivitiRestClient {

	private static String REST_URI = "http://localhost:8081/activiti-rest-api/service";
	private static Logger logger = Logger.getLogger(ActivitiRestClient.class);

	private static ClientResource getClientResource(String uri) {
		ClientResource clientResource = new ClientResource(uri);
		clientResource.setChallengeResponse(ChallengeScheme.HTTP_BASIC,
				"kermit", "kermit");
		return clientResource;
	}

	public static String getUnderwritingQueueProcessId() throws IOException,
			JSONException {
		String uri = REST_URI + "/repository/process-definitions";
		System.out.println("URI: " + uri);
		Representation response = getClientResource(uri).get(
				MediaType.APPLICATION_JSON);
		JSONObject object = new JSONObject(response.getText());
		if (object != null) {
			JSONArray arr = (JSONArray) object.get("data");
			for (int i = 0; i < arr.length(); i++) {
				JSONObject jsonObject = (JSONObject) arr.get(i);
				if (jsonObject.get("key").equals("underwritingQueue")) {
					logger.info("Returning processDefinitionId "
							+ jsonObject.get("id"));
					return (String) jsonObject.get("id");
				}
			}
		}
		return null;
	}

	public static String addLoanToUnderwritingQueue(String processDefinitionId)
			throws Exception {
		String uri = REST_URI + "/runtime/process-instances";
		JSONStringer jsRequest = new JSONStringer();
		jsRequest.object().key("processDefinitionId")
				.value(processDefinitionId).key("variables").array().object()
				.key("name").value("LoanId").key("value").value("132312")
				.endObject().endArray();
		jsRequest.endObject();
		Representation rep = new StringRepresentation(jsRequest.toString(),
				MediaType.APPLICATION_JSON);
		System.out.println("REP: " + rep.toString());
		JSONObject jsObj = new JSONObject(getClientResource(uri).post(rep)
				.getText());
		logger.info("Returning processId " + jsObj.getString("id"));
		return jsObj.getString("id");
	}

	public static String getQueueTask(String processInstanceId)
			throws Exception {
		String uri = REST_URI + "/tasks?candidate=kermit";
		Representation response = getClientResource(uri).get(
				MediaType.APPLICATION_JSON);
		JSONObject object = new JSONObject(response.getText());
		if (object != null) {
			JSONArray arr = (JSONArray) object.get("data");
			for (int i = 0; i < arr.length(); i++) {
				JSONObject ob = (JSONObject) arr.get(i);
				if (ob.get("processInstanceId").equals(processInstanceId)) {
					logger.info("Returning taskId " + ob.get("id"));
					return (String) ob.get("id");
				}
			}
		}
		return null;
	}

	public static String claimQueueTask(String taskId) throws Exception {
		String uri = REST_URI + "/task/" + taskId + "/claim";
		Representation response = getClientResource(uri).put("{}",
				MediaType.APPLICATION_JSON);
		JSONObject object = new JSONObject(response.getText());
		System.out.println("OBJECT: " + object.toString());
		logger.info("Claimed task " + taskId + " " + object.get("success"));
		return object.get("success").toString();
	}
	
	public static String completeTask(String taskId)
			throws Exception {
		String uri = REST_URI + "/task/" + taskId + "/complete";
		Representation response = getClientResource(uri).put(
				"{disposition:complete}", MediaType.APPLICATION_JSON);
		JSONObject object = new JSONObject(response.getText());
		logger.info("Completed task " + taskId + " " + object.getString("success"));
		return object.getString("success");
	}
	
	@SuppressWarnings("unused")
	public static int getTasks(String status, String candidate)
			throws Exception {
		String uri = REST_URI + "/tasks?" + status + "=" + candidate;
		Representation response = getClientResource(uri).get(
				MediaType.APPLICATION_JSON);
		JSONObject object = new JSONObject(response.getText());
		if (object != null) {
			JSONArray arr = (JSONArray) object.get("data");
			logger.info("Tasklist " + candidate + " " + status + " size " + arr.length());
			return arr.length();
		}
		return -1;
	}
}

Activiti REST Client Test

package com.nuke.activiti.client;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import org.junit.Test;

import com.nuke.activiti.common.AbstractTest;


public class ActivitiRestClientTest extends AbstractTest {
	
	@Test
	public void restAPITest() throws Exception {
		String underwritingLoanDefinitionId = ActivitiRestClient.getUnderwritingQueueProcessId();
		assertNotNull(underwritingLoanDefinitionId);
		String processInstanceId = ActivitiRestClient.addLoanToUnderwritingQueue(underwritingLoanDefinitionId);
		assertNotNull(processInstanceId);
		String taskId = ActivitiRestClient.getQueueTask(processInstanceId);
		assertNotNull(taskId);
		assertEquals("true", ActivitiRestClient.claimQueueTask(taskId));
		assertEquals(4, ActivitiRestClient.getTasks("candidate","kermit"));
		assertEquals(6, ActivitiRestClient.getTasks("assignee","kermit"));
		assertEquals("true", ActivitiRestClient.completeTask(taskId));
		assertEquals(0, ActivitiRestClient.getTasks("assignee","kermit"));
	}
}

Activiti BPM Tutorial – LDAP

1.1 LDAP Configuration using XML
1.2 LDAP Configuration XML User Test
1.3 LDAP Configuration XML Group Test
2.1 LDAP Configuration using Annotations
2.2 LDAP Configuration Annotations User Test
2.3 LDAP Configuration Annotations Group Test

1.1 LDAP Configuration using XML

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://www.springframework.org/schema/beans
				http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
  
    <property name="jdbcUrl" value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000" />
    <property name="jdbcDriver" value="org.h2.Driver" />
    <property name="jdbcUsername" value="sa" />
    <property name="jdbcPassword" value="" />
    <property name="history" value="full" />
    <property name="databaseSchemaUpdate" value="true" />
    
    <property name="jobExecutorActivate" value="true" />
    
    <property name="configurators">
          <list>
              <bean class="org.activiti.ldap.LDAPConfigurator">
              
                <!-- Server connection params -->
                <property name="server" value="ldap://localhost" />
                <property name="port" value="10389" />
                <property name="user" value="uid=admin,ou=system" />
                <property name="password" value="secret" />
                
                <!-- Query params -->
                <property name="baseDn" value="" /> 
                <property name="queryUserByUserId" value="(&amp;(objectClass=inetOrgPerson)(uid={0}))" />
                <property name="queryUserByFullNameLike" value="(&amp;(objectClass=inetOrgPerson)(|({0}=*{1}*)({2}=*{3}*)))" />
                <property name="queryGroupsForUser" value="(&amp;(objectClass=groupOfUniqueNames)(uniqueMember={0}))" />
                
                <!-- Attribute config -->
                <property name="userIdAttribute" value="uid" />
                <property name="userFirstNameAttribute" value="cn" />
                <property name="userLastNameAttribute" value="sn" />
                
                <property name="groupIdAttribute" value="cn" />
                <property name="groupNameAttribute" value="cn" />
                
              </bean>
          </list>
      </property>
  </bean>
  
</beans>

1.2 LDAP Configuration XML Test

package com.nuke.activiti.ldap;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import org.activiti.engine.identity.User;
import org.activiti.engine.test.ActivitiRule;
import org.junit.Rule;
import org.junit.Test;

import com.nuke.activiti.common.AbstractTest;

public class LDAPUserTest extends AbstractTest {

	@Rule
	public ActivitiRule activitiRule = new ActivitiRule("activiti.cfg.xml");

	@Test
	public void testCheckLogin() {
		boolean validated = activitiRule.getIdentityService().checkPassword("kermit", "kermit");
		assertTrue(validated);
	}
	
	@Test
	public void testCheckLoginFailure() {
		boolean validated = activitiRule.getIdentityService().checkPassword("kermit", "kermit2");
		assertFalse(validated);
	}
	
	@Test
	public void findUserById() throws Exception {
		User user = activitiRule.getIdentityService().createUserQuery().userId("kermit").singleResult();
		assertNotNull(user);
		assertEquals("kermit", user.getId());
		assertEquals("kermit", user.getLastName());
	}
}

1.3 LDAP Configuration XML Group Test

package com.nuke.activiti.ldap;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.util.List;

import org.activiti.engine.identity.Group;
import org.activiti.engine.test.ActivitiRule;
import org.junit.Rule;
import org.junit.Test;

import com.nuke.activiti.common.AbstractTest;

public class LDAPGroupTest extends AbstractTest {

	@Rule
	public ActivitiRule activitiRule = new ActivitiRule("activiti.cfg.xml");
		
	@Test
	public void findGroupByMember() throws Exception {
		List<Group> groupList = activitiRule.getIdentityService().createGroupQuery().groupMember("kermit").list();
		for (Group group : groupList){
			System.out.println(group.getName());
		}
		assertNotNull(groupList);
		assertEquals(3, groupList.size());
	}

}

2.1 LDAP Configuration using Annotations

package com.nuke.ldap;

import org.activiti.ldap.LDAPConfigurator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
public class LDAPConfiguration {

	@Bean
	public LDAPConfigurator LDAPConfig(){
		LDAPConfigurator ldapConfig = new LDAPConfigurator();
		
		ldapConfig.setServer("localhost");
		ldapConfig.setPort(10389);
		ldapConfig.setUser("uid=admin,ou=system");
		ldapConfig.setPassword("secret");
		
		ldapConfig.setBaseDn("");
		ldapConfig.setQueryUserByUserId("(&(objectClass=inetOrgPerson)(uid={0}))");
		ldapConfig.setQueryUserByFullNameLike("(&(objectClass=inetOrgPerson)(|({0}=*{1}*)({2}=*{3}*)))");
		ldapConfig.setQueryGroupsForUser("(&(objectClass=groupOfUniqueNames)(uniqueMember={0}))");
		
		ldapConfig.setUserIdAttribute("uid");
		ldapConfig.setUserFirstNameAttribute("cn");
		ldapConfig.setUserLastNameAttribute("sn");
		
		ldapConfig.setGroupIdAttribute("cn");
		ldapConfig.setGroupNameAttribute("cn");
		
		return ldapConfig;
	}
}
package com.nuke.config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.cfg.ProcessEngineConfigurator;
import org.activiti.engine.impl.HistoryServiceImpl;
import org.activiti.engine.impl.IdentityServiceImpl;
import org.activiti.engine.impl.ManagementServiceImpl;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.RuntimeServiceImpl;
import org.activiti.engine.impl.TaskServiceImpl;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.history.HistoryLevel;
import org.activiti.engine.test.ActivitiRule;
import org.activiti.ldap.LDAPConfigurator;
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.activiti.spring.annotations.AbstractActivitiConfigurer;
import org.activiti.spring.annotations.EnableActiviti;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import com.nuke.ldap.LDAPConfiguration;

@Configuration
@EnableActiviti
@EnableTransactionManagement(proxyTargetClass = true)
@Import({LDAPConfiguration.class})
//@PropertySource("file:conf/lc-merged.properties")
public class ActivitConfiguration {
 
	@Autowired
	LDAPConfigurator ldapConfigurator;
	
    @Bean
    public DataSource inMemoryDataSource() {
        BasicDataSource basicDataSource = new BasicDataSource();
        basicDataSource.setUsername("sa");
        basicDataSource.setUrl("jdbc:h2:mem:activiti");
        basicDataSource.setDefaultAutoCommit(false);
        basicDataSource.setDriverClassName(org.h2.Driver.class.getName());
        basicDataSource.setPassword("");
        return basicDataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource inMemoryDataSource) {
	  LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
      localContainerEntityManagerFactoryBean.setDataSource(inMemoryDataSource);
      localContainerEntityManagerFactoryBean.setPackagesToScan(new String[]{"com.nuke.model"});
      localContainerEntityManagerFactoryBean.setPersistenceUnitName("nuke");
      HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
      
      jpaVendorAdapter.setGenerateDdl(false);
      jpaVendorAdapter.setShowSql(false);
      jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.H2Dialect");
      localContainerEntityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter);
      return localContainerEntityManagerFactoryBean;
    }

    @Bean
    public PlatformTransactionManager jpaTransactionManager(EntityManagerFactory entityManagerFactoryBean) {
        return new JpaTransactionManager(entityManagerFactoryBean);
    } 
    
       
	@Value("${LC_NUKE_MAIL_HOST}")
	private String mailHost;
	@Value("${LC_NUKE_MAIL_USERNAME}")
	private String mailUsername;
	@Value("${LC_NUKE_MAIL_PASSWORD}")
	private String mailServerPassword;
	
    @Bean
    public AbstractActivitiConfigurer abstractActivitiConfigurer(final EntityManagerFactory entityManagerFactoryBean, final PlatformTransactionManager jpaTransactionManager) {
        return new AbstractActivitiConfigurer() {
            @Override
            public void postProcessSpringProcessEngineConfiguration(SpringProcessEngineConfiguration engine) {
            	engine.setDatabaseType("h2");
            	engine.setDataSource(inMemoryDataSource());
                engine.setTransactionManager(jpaTransactionManager);
                engine.setJpaEntityManagerFactory(entityManagerFactoryBean);
                engine.setJpaHandleTransaction(true);
                engine.setJobExecutorActivate(true);
                engine.setJpaCloseEntityManager(false);
                engine.setMailServerDefaultFrom("nucleus@lc.com");
                engine.setMailServerHost(mailHost);
                engine.setMailServerPort(587);
                engine.setMailServerUsername(mailUsername);
                engine.setMailServerPassword(mailServerPassword);
                engine.setMailServerUseSSL(true);
                engine.setMailServerUseTLS(true);
                engine.setRepositoryService(repositoryService());
                engine.setTaskService(taskService());
                engine.setManagementService(managementService());
                engine.setRuntimeService(runtimeService());
                engine.setIdentityService(identityService());
                engine.setHistoryService(historyService());
                engine.setHistoryLevel(HistoryLevel.AUDIT);
                Resource[] processResources = new Resource[1] ;
                Resource underwritingQueueProcess = new ClassPathResource("diagrams/underwriting_queue.bpmn");
                processResources[0]=underwritingQueueProcess;
                engine.setDeploymentResources(processResources);
                engine.setConfigurators(new ArrayList<ProcessEngineConfigurator>(Arrays.asList(ldapConfigurator)));
                engine.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
            }
        };
    }
    
    @Bean
    public RepositoryServiceImpl repositoryService(){
    	RepositoryServiceImpl repositoryService = new RepositoryServiceImpl();
    	return repositoryService;
    }
    
    @Bean
    public TaskServiceImpl taskService(){
    	TaskServiceImpl taskService = new TaskServiceImpl();
    	return taskService;
    }
    
    @Bean
    public ManagementServiceImpl managementService(){
    	ManagementServiceImpl managementService = new ManagementServiceImpl();
    	return managementService;
    }
    
    @Bean
    public RuntimeServiceImpl runtimeService(){
    	RuntimeServiceImpl runtimeService = new RuntimeServiceImpl();
    	return runtimeService;
    }
    
    @Bean
    public HistoryServiceImpl historyService(){
    	HistoryServiceImpl historyService = new HistoryServiceImpl();
    	return historyService;
    }
    
    @Bean
    public IdentityServiceImpl identityService(){
    	IdentityServiceImpl identityService = new IdentityServiceImpl();
    	return identityService;
    }
    
    @Bean
    public ActivitiRule activityRule(ProcessEngineConfigurationImpl abstractActivitiConfigurer){
    	ActivitiRule activityRule = new ActivitiRule();
    	activityRule.setProcessEngineConfiguration(abstractActivitiConfigurer);
    	return activityRule;
    }
}

2.2 LDAP Configuration Annotations User Test

package com.nuke.activiti.ldap;

import static org.junit.Assert.*;

import org.activiti.engine.identity.User;
import org.activiti.engine.test.ActivitiRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.nuke.config.ActivitConfiguration;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=ActivitConfiguration.class)
public class SpringLDAPUserTest {

	@Autowired
	@Rule
	public ActivitiRule activitiSpringRule;
	
	@Test
	public void testCheckLogin() {
		boolean validated = activitiSpringRule.getIdentityService().checkPassword("kermit", "kermit");
		assertTrue(validated);
	}
	
	@Test
	public void testCheckLoginFailure() {
		boolean validated = activitiSpringRule.getIdentityService().checkPassword("kermit", "kermit2");
		assertFalse(validated);
	}
	
	@Test
	public void findUserById() throws Exception {
		User user = activitiSpringRule.getIdentityService().createUserQuery().userId("kermit").singleResult();
		assertNotNull(user);
		assertEquals("kermit", user.getId());
		assertEquals("kermit", user.getLastName());
	}

}

2.3 LDAP Configuration Annotations Group Test

package com.nuke.activiti.ldap;

import static org.junit.Assert.*;

import java.util.List;

import org.activiti.engine.identity.Group;
import org.activiti.engine.test.ActivitiRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.nuke.config.ActivitConfiguration;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=ActivitConfiguration.class)
public class SpringLDAPGroupTest {

	@Autowired
	@Rule
	public ActivitiRule activitiSpringRule;
	
	@Test
	public void findGroupByMember() throws Exception {
		List<Group> groupList = activitiSpringRule.getIdentityService().createGroupQuery().groupMember("kermit").list();
		for (Group group : groupList){
			System.out.println(group.getName());
		}
		assertNotNull(groupList);
		assertEquals(3, groupList.size());
	}
}

Activiti BPM Tutorial – Spring Configuration

Activiti Spring Configuration
1. Activiti Configuration using XML
1.1 Activiti Configuration XML Test
2. Activiti Configuration using Annotations
2.1 Activiti Configuration Annotation Test

1. Activiti Configuration using XML

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans    
                           http://www.springframework.org/schema/beans/spring-beans.xsd 
                           http://www.springframework.org/schema/context  
                           http://www.springframework.org/schema/context/spring-context-2.5.xsd 
                           http://www.springframework.org/schema/tx       
                           http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

	<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
			<property name="driverClass" value="org.h2.Driver" />
			<property name="url" value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000" />
			<property name="username" value="sa" />
			<property name="password" value="" />
	</bean>

	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
		<property name="databaseType" value="h2" />
		<property name="dataSource" ref="dataSource" />
		<property name="transactionManager" ref="transactionManager" />
		<property name="databaseSchemaUpdate" value="true" />
		<property name="deploymentResources"
			value="classpath*:diagrams/underwriting_queue.bpmn" />
		<property name="history" value="audit" />
		<property name="jobExecutorActivate" value="false" />
	</bean>

	<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
		<property name="processEngineConfiguration" ref="processEngineConfiguration" />
	</bean>

	<bean id="repositoryService" factory-bean="processEngine"
		factory-method="getRepositoryService" />
	<bean id="runtimeService" factory-bean="processEngine"
		factory-method="getRuntimeService" />
	<bean id="taskService" factory-bean="processEngine"
		factory-method="getTaskService" />
	<bean id="historyService" factory-bean="processEngine"
		factory-method="getHistoryService" />
	<bean id="managementService" factory-bean="processEngine"
		factory-method="getManagementService" />
</beans>

1.1 Activiti Configuration XML Test

package com.nuke.activiti.spring;

import static org.junit.Assert.assertEquals;

import java.util.HashMap;
import java.util.Map;

import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.nuke.activiti.common.AbstractTest;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-test-application-context.xml")
public class SpringTest extends AbstractTest {

	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private TaskService taskService;

	@Test
	public void simpleProcessTest() {
		Map<String, Object> variableMap = new HashMap<String, Object>();
		variableMap.put("LoanId", 123456789);
		runtimeService.startProcessInstanceByKey("underwritingQueue", variableMap);
		Task task = taskService.createTaskQuery().singleResult();
		assertEquals("Unassigned Loan", task.getName());
		taskService.complete(task.getId());
		assertEquals(1, runtimeService.createProcessInstanceQuery().count());
	}
}

2. Activiti Configuration using Annotations

package com.nuke.config;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.impl.HistoryServiceImpl;
import org.activiti.engine.impl.ManagementServiceImpl;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.RuntimeServiceImpl;
import org.activiti.engine.impl.TaskServiceImpl;
import org.activiti.engine.impl.history.HistoryLevel;
import org.activiti.engine.impl.interceptor.SessionFactory;
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.activiti.spring.annotations.AbstractActivitiConfigurer;
import org.activiti.spring.annotations.EnableActiviti;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import com.nuke.ldap.LDAPConnectionParams;
import com.nuke.ldap.LDAPGroupManagerFactory;
import com.nuke.ldap.LDAPUserManagerFactory;

@Configuration
@EnableActiviti
@EnableTransactionManagement(proxyTargetClass = true)
//@PropertySource("file:conf/lc-merged.properties")
public class ActivitConfiguration {
 
    @Bean
    public DataSource inMemoryDataSource() {
        BasicDataSource basicDataSource = new BasicDataSource();
        basicDataSource.setUsername("sa");
        basicDataSource.setUrl("jdbc:h2:mem:activiti");
        basicDataSource.setDefaultAutoCommit(false);
        basicDataSource.setDriverClassName(org.h2.Driver.class.getName());
        basicDataSource.setPassword("");
        return basicDataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource inMemoryDataSource) {
	  LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
      localContainerEntityManagerFactoryBean.setDataSource(inMemoryDataSource);
      localContainerEntityManagerFactoryBean.setPackagesToScan(new String[]{"com.nuke.model"});
      localContainerEntityManagerFactoryBean.setPersistenceUnitName("nuke");
      HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
      
      jpaVendorAdapter.setGenerateDdl(false);
      jpaVendorAdapter.setShowSql(false);
      jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.H2Dialect");
      localContainerEntityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter);
      return localContainerEntityManagerFactoryBean;
    }

    @Bean
    public PlatformTransactionManager jpaTransactionManager(EntityManagerFactory entityManagerFactoryBean) {
        return new JpaTransactionManager(entityManagerFactoryBean);
    } 
    
    @Value("${LC_NUKE_LDAP_URL:localhost}")
	private String ldapServer;
	@Value("${LC_NUKE_LDAP_PORT}")
	private String ldapPort;
	@Value("${LC_NUKE_LDAP_USERNAME:uid=admin,ou=system}")
	private String ldapUser;
	@Value("${LC_NUKE_LDAP_PASSWORD:secret}")
	private String ldapPassword;
	
	@Bean
	public LDAPConnectionParams ldapConnection(){
		LDAPConnectionParams ldapConnection = new LDAPConnectionParams();
		ldapConnection.setLdapServer(ldapServer);
		ldapConnection.setLdapPort(10389);
		ldapConnection.setLdapUser(ldapUser);
		ldapConnection.setLdapPassword(ldapPassword);
		return ldapConnection;
	}
    
    
	@Value("${LC_NUKE_MAIL_HOST}")
	private String mailHost;
	@Value("${LC_NUKE_MAIL_USERNAME}")
	private String mailUsername;
	@Value("${LC_NUKE_MAIL_PASSWORD}")
	private String mailServerPassword;
	
    @Bean
    public AbstractActivitiConfigurer abstractActivitiConfigurer(final EntityManagerFactory entityManagerFactoryBean, final PlatformTransactionManager jpaTransactionManager) {
        return new AbstractActivitiConfigurer() {
            @Override
            public void postProcessSpringProcessEngineConfiguration(SpringProcessEngineConfiguration engine) {
            	engine.setDatabaseType("h2");
            	engine.setDataSource(inMemoryDataSource());
                engine.setTransactionManager(jpaTransactionManager);
                engine.setJpaEntityManagerFactory(entityManagerFactoryBean);
                engine.setJpaHandleTransaction(true);
                engine.setJobExecutorActivate(true);
                engine.setJpaCloseEntityManager(false);
                engine.setMailServerDefaultFrom("nucleus@lc.com");
                engine.setMailServerHost(mailHost);
                engine.setMailServerPort(587);
                engine.setMailServerUsername(mailUsername);
                engine.setMailServerPassword(mailServerPassword);
                engine.setMailServerUseSSL(true);
                engine.setMailServerUseTLS(true);
                engine.setRepositoryService(repositoryService());
                engine.setTaskService(taskService());
                engine.setManagementService(managementService());
                engine.setRuntimeService(runtimeService());
                engine.setHistoryService(historyService());
                engine.setHistoryLevel(HistoryLevel.AUDIT);
                Resource[] processResources = new Resource[1] ;
                Resource underwritingQueueProcess = new ClassPathResource("diagrams/underwriting_queue.bpmn");
                processResources[0]=underwritingQueueProcess;
                engine.setDeploymentResources(processResources);
                List<SessionFactory> customSessionFactories = new ArrayList<SessionFactory>();
                customSessionFactories.add(new LDAPGroupManagerFactory(ldapConnection()));
                customSessionFactories.add(new LDAPUserManagerFactory(ldapConnection()));
        		engine.setCustomSessionFactories(customSessionFactories);
                
                engine.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
            }
        };
    }
    
    @Bean
    public RepositoryServiceImpl repositoryService(){
    	RepositoryServiceImpl repositoryService = new RepositoryServiceImpl();
    	return repositoryService;
    }
    
    @Bean
    public TaskServiceImpl taskService(){
    	TaskServiceImpl taskService = new TaskServiceImpl();
    	return taskService;
    }
    
    @Bean
    public ManagementServiceImpl managementService(){
    	ManagementServiceImpl managementService = new ManagementServiceImpl();
    	return managementService;
    }
    
    @Bean
    public RuntimeServiceImpl runtimeService(){
    	RuntimeServiceImpl runtimeService = new RuntimeServiceImpl();
    	return runtimeService;
    }
    
    @Bean
    public HistoryServiceImpl historyService(){
    	HistoryServiceImpl historyService = new HistoryServiceImpl();
    	return historyService;
    }    
}

2.1 Activiti Configuration Annotation Test

package com.nuke.activiti.spring;

import static org.junit.Assert.assertEquals;

import java.util.HashMap;
import java.util.Map;

import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.nuke.config.ActivitConfiguration;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=ActivitConfiguration.class)
public class SpringWithAnnotations {

	@Autowired
	private RuntimeService runtimeService;
	
	@Autowired
	private TaskService taskService;

	@Test
	public void simpleProcessTest() {
		Map<String, Object> variableMap = new HashMap<String, Object>();
		variableMap.put("LoanId", 123456789);
		runtimeService.startProcessInstanceByKey("underwritingQueue", variableMap);
		Task task = taskService.createTaskQuery().singleResult();
		assertEquals("Unassigned Loan", task.getName());
		taskService.complete(task.getId());
		assertEquals(1, runtimeService.createProcessInstanceQuery().count());
	}
}

Activiti BPM Tutorial – Process Engine

Expense Process Diagram

expense_process

Expense Process BPMN20

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="expenseProcess" name="The new and shiny expense process" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="Request Refund" activiti:assignee="kermit">
      <documentation>[Employee:${employee}, 
Amount: ${amount}]</documentation>
    </userTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <userTask id="usertask2" name="Handle Request" activiti:candidateGroups="accountancy">
      <documentation>${employee} has requested a refund amount ${amount}</documentation>
    </userTask>
    <userTask id="usertask3" name="Handle Request" activiti:candidateGroups="management">
      <documentation>${employee} has requested a refund of ${amount}</documentation>
    </userTask>
    <serviceTask id="mailtask1" name="Mail Task" activiti:type="mail">
      <extensionElements>
        <activiti:field name="to">
          <activiti:string><![CDATA[thysmichels@gmail.com]]></activiti:string>
        </activiti:field>
        <activiti:field name="from">
          <activiti:string><![CDATA[lc@lc.com]]></activiti:string>
        </activiti:field>
        <activiti:field name="subject">
          <activiti:string><![CDATA[Activity Mail]]></activiti:string>
        </activiti:field>
        <activiti:field name="html">
          <activiti:expression>${employee} has requested refund</activiti:expression>
        </activiti:field>
      </extensionElements>
    </serviceTask>
    <sequenceFlow id="flow6" sourceRef="mailtask1" targetRef="usertask3"></sequenceFlow>
    <endEvent id="endevent1" name="End"></endEvent>
    <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>
    <exclusiveGateway id="exclusivegateway2" name="Exclusive Gateway"></exclusiveGateway>
    <sequenceFlow id="flow7" sourceRef="usertask3" targetRef="exclusivegateway2"></sequenceFlow>
    <sequenceFlow id="flow8" sourceRef="usertask2" targetRef="exclusivegateway2"></sequenceFlow>
    <sequenceFlow id="flow9" sourceRef="exclusivegateway2" targetRef="endevent1"></sequenceFlow>
    <sequenceFlow id="flow10" sourceRef="usertask1" targetRef="exclusivegateway1"></sequenceFlow>
    <sequenceFlow id="flow11" name="${employeeVerification==&quot;true&quot;}" sourceRef="exclusivegateway1" targetRef="mailtask1">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${employeeVerification=="true"}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow12" name="${employeeVerification==&quot;false&quot;}" sourceRef="exclusivegateway1" targetRef="usertask2">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${employeeVerification=="false"}]]></conditionExpression>
    </sequenceFlow>
    <boundaryEvent id="boundarytimer1" name="Timer" attachedToRef="usertask2" cancelActivity="true">
      <timerEventDefinition>
        <timeDuration>PT1S</timeDuration>
      </timerEventDefinition>
    </boundaryEvent>
    <sequenceFlow id="flow15" sourceRef="boundarytimer1" targetRef="startevent1"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_expenseProcess">
    <bpmndi:BPMNPlane bpmnElement="expenseProcess" id="BPMNPlane_expenseProcess">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="132.0" y="290.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds height="55.0" width="105.0" x="240.0" y="280.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
        <omgdc:Bounds height="55.0" width="105.0" x="462.0" y="390.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="boundarytimer1" id="BPMNShape_boundarytimer1">
        <omgdc:Bounds height="30.0" width="30.0" x="500.0" y="430.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
        <omgdc:Bounds height="55.0" width="105.0" x="640.0" y="180.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="mailtask1" id="BPMNShape_mailtask1">
        <omgdc:Bounds height="55.0" width="105.0" x="450.0" y="180.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="890.0" y="297.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="BPMNShape_exclusivegateway1">
        <omgdc:Bounds height="40.0" width="40.0" x="413.0" y="287.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="exclusivegateway2" id="BPMNShape_exclusivegateway2">
        <omgdc:Bounds height="40.0" width="40.0" x="810.0" y="294.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="167.0" y="307.0"></omgdi:waypoint>
        <omgdi:waypoint x="240.0" y="307.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6">
        <omgdi:waypoint x="555.0" y="207.0"></omgdi:waypoint>
        <omgdi:waypoint x="640.0" y="207.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
        <omgdi:waypoint x="745.0" y="207.0"></omgdi:waypoint>
        <omgdi:waypoint x="830.0" y="207.0"></omgdi:waypoint>
        <omgdi:waypoint x="830.0" y="294.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">
        <omgdi:waypoint x="567.0" y="417.0"></omgdi:waypoint>
        <omgdi:waypoint x="830.0" y="417.0"></omgdi:waypoint>
        <omgdi:waypoint x="830.0" y="334.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9">
        <omgdi:waypoint x="850.0" y="314.0"></omgdi:waypoint>
        <omgdi:waypoint x="890.0" y="314.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10">
        <omgdi:waypoint x="345.0" y="307.0"></omgdi:waypoint>
        <omgdi:waypoint x="413.0" y="307.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow11" id="BPMNEdge_flow11">
        <omgdi:waypoint x="433.0" y="287.0"></omgdi:waypoint>
        <omgdi:waypoint x="432.0" y="225.0"></omgdi:waypoint>
        <omgdi:waypoint x="450.0" y="207.0"></omgdi:waypoint>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="36.0" width="100.0" x="443.0" y="287.0"></omgdc:Bounds>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow12" id="BPMNEdge_flow12">
        <omgdi:waypoint x="433.0" y="327.0"></omgdi:waypoint>
        <omgdi:waypoint x="433.0" y="417.0"></omgdi:waypoint>
        <omgdi:waypoint x="462.0" y="417.0"></omgdi:waypoint>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="36.0" width="100.0" x="443.0" y="327.0"></omgdc:Bounds>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow15" id="BPMNEdge_flow15">
        <omgdi:waypoint x="500.0" y="445.0"></omgdi:waypoint>
        <omgdi:waypoint x="149.0" y="444.0"></omgdi:waypoint>
        <omgdi:waypoint x="149.0" y="325.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

Expense Process Test

package org.activiti.designer.test;

import static org.junit.Assert.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.FileInputStream;

import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.test.ActivitiRule;
import org.junit.Rule;
import org.junit.Test;

public class ProcessTestExpenseProcess {

	private String filename = "/Users/tmichels/Documents/workspace-sts-3.5.0.M21/nucleus-business-process/src/main/resources/diagrams/expense_process.bpmn";

	@Rule
	public ActivitiRule activitiRule = new ActivitiRule();
	
	@Test
	public void startProcess() throws Exception {
		ProcessEngine processEngine = ProcessEngineConfiguration
			.createStandaloneInMemProcessEngineConfiguration()
			.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE)
			.setMailServerHost("smtp.gmail.com")
			.setMailServerPort(587)
			.setMailServerUsername("youremail@gmail.com")
			.setMailServerPassword("password")
			.setMailServerUseSSL(true)
			.setMailServerUseTLS(true)
		    .buildProcessEngine();
		
		RuntimeService runtimeService = activitiRule.getRuntimeService();
		
		RepositoryService repositoryService = activitiRule.getRepositoryService();
		repositoryService.createDeployment().addInputStream("expense_process.bpmn",
				new FileInputStream(filename)).deploy();
		
		Map<String, Object> variableMap1 = new HashMap<String, Object>();
		variableMap1.put("employee", "Jack");
		variableMap1.put("amount", 111);
		Map<String, Object> variableMap2 = new HashMap<String, Object>();
		variableMap2.put("employee", "Jonny");
		variableMap2.put("amount", 222);
		Map<String, Object> variableMap3 = new HashMap<String, Object>();
		variableMap3.put("employee", "Pete");
		variableMap3.put("amount", 333);
		
		ProcessInstance processInstance1 = runtimeService.startProcessInstanceByKey("expenseProcess", variableMap1);
		ProcessInstance processInstance2 = runtimeService.startProcessInstanceByKey("expenseProcess", variableMap2);
		ProcessInstance processInstance3 = runtimeService.startProcessInstanceByKey("expenseProcess", variableMap3);
		System.out.println("**** ProcessInstance1 ID *** " + processInstance1.getId());
		
		assertNotNull(processInstance1.getId());
		assertNotNull(processInstance2.getId());
		assertNotNull(processInstance3.getId());
		

		Map<String, Object> processVariables = runtimeService.getVariables(processInstance1.getId());
		for (String processVariable : processVariables.keySet()){
			System.out.println("PROCESS KEY : " + processVariable + " VALUE: " + processVariables.get(processVariable));
		}
		
		TaskService taskService = processEngine.getTaskService();
		
		//Query Task Available for Kermit
		 List<Task> availableTasksForKermit = taskService.createTaskQuery().taskAssignee("kermit").list();
		 for (Task task : availableTasksForKermit) {
		      System.out.println(" *******AVAILABLE TASK**********" + "\n" 
		      		+ 	" Task Name: " + task.getName() + "\n Owner: " + task.getOwner() + "\n" +
		    		  	" Assignee: " + task.getAssignee() +"\n "+ "Description: " + task.getDescription());
		 }
		
		List<Task> tasks = activitiRule.getTaskService().createTaskQuery().list();
		for (Task task : tasks){
			System.out.println("*******LIST TASKS************" + "\n" +
					"Get Task:" + task.getAssignee());
		}

		List<Task> kermitTasks = taskService.createTaskQuery()
		         .taskAssignee("kermit")
		         .processVariableValueEquals("amount", 111)
		         .orderByDueDate().asc()
		         .list();
		
		for (Task kermitTask: kermitTasks){
			System.out.println("*******QUERY FOR ASSIGNEE TASKS************" + "\n" + kermitTask.getAssignee());
		}
		
		 //Can't Claim Task as this task already has an assignee
		 if (availableTasksForKermit.get(0).getAssignee()==null)
			 taskService.claim(availableTasksForKermit.get(0).getId(), "rocky");
	     
	     //Verify Task - No Tasks for Rocky cause Kermit has it
	     tasks = taskService.createTaskQuery().taskAssignee("rocky").list();
	     for (Task task : tasks) {
	       System.out.println("Task for rocky: " + task.getName());
	     }
	     
	     //Ok kermit claims a tasks
	     taskService.claim(availableTasksForKermit.get(0).getId(), "kermit");
	     
	     List<Task> claimedTasks = taskService.createTaskQuery().taskCandidateOrAssigned("kermit").list();
	     for (Task claimedTask : claimedTasks){
	    	 System.out.println("Task claimed by Kermit: " + claimedTask.getDescription());
	     }
	     
	     Map<String, Object> taskCompleteVariables = new HashMap<String, Object>();
	     taskCompleteVariables.put("employeeVerification", false);
	     taskCompleteVariables.put("amountVerificaion", true);
	     taskService.complete(availableTasksForKermit.get(0).getId(),taskCompleteVariables);
	     
	     System.out.println("Number of tasks for kermit: " 
	             + taskService.createTaskQuery().taskAssignee("kermit").count());
	     
	     List<Task> accountancyTasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();
	     for (Task accountancyTask : accountancyTasks){
	    	 System.out.println("Accountancy Task: " +accountancyTask.getDescription());
	     }
	     
	     taskService.claim(accountancyTasks.get(0).getId(), "sandy");
	     
	     System.out.println("Number of tasks for Sandy: " 
	             + taskService.createTaskQuery().taskAssignee("sandy").count());
	     
	     System.out.println("BreakPoint Timeout");
	     
	     System.out.println("Number of tasks for Sandy: " 
	             + taskService.createTaskQuery().taskAssignee("sandy").count());
	     
	   //Query Task Available for Kermit
		 List<Task> availableTasksForKermit2 = taskService.createTaskQuery().taskAssignee("kermit").list();
		 for (Task task : availableTasksForKermit2) {
		      System.out.println(" *******AVAILABLE TASK**********" + "\n" 
		      		+ 	" Task Name: " + task.getName() + "\n Owner: " + task.getOwner() + "\n" +
		    		  	" Assignee: " + task.getAssignee() +"\n "+ "Description: " + task.getDescription());
		 }
		 
		 taskService.claim(accountancyTasks.get(0).getId(), "sandy");
		 taskService.complete(accountancyTasks.get(0).getId());
	      
	     HistoryService historyService = processEngine.getHistoryService();
	     HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstance1.getId()).singleResult();
	     System.out.println("Process instance end time: " + historicProcessInstance.getEndTime());
	}
}

Output

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/tmichels/.m2/repository/org/slf4j/slf4j-log4j12/1.7.7/slf4j-log4j12-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/tmichels/.m2/repository/org/slf4j/slf4j-jdk14/1.7.2/slf4j-jdk14-1.7.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
23 May 2014 09:08:57,461 [main]  INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader:315 - Loading XML bean definitions from class path resource [activiti.cfg.xml]
23 May 2014 09:08:59,874 [main]  INFO org.activiti.engine.impl.db.DbSqlSession:975 - performing create on engine with resource org/activiti/db/create/activiti.h2.create.engine.sql
23 May 2014 09:08:59,955 [main]  INFO org.activiti.engine.impl.db.DbSqlSession:975 - performing create on history with resource org/activiti/db/create/activiti.h2.create.history.sql
23 May 2014 09:08:59,973 [main]  INFO org.activiti.engine.impl.db.DbSqlSession:975 - performing create on identity with resource org/activiti/db/create/activiti.h2.create.identity.sql
23 May 2014 09:08:59,986 [main]  INFO org.activiti.engine.impl.ProcessEngineImpl:79 - ProcessEngine default created
23 May 2014 09:08:59,989 [main]  INFO org.activiti.engine.impl.jobexecutor.JobExecutor:76 - Starting up the JobExecutor[org.activiti.engine.impl.jobexecutor.DefaultJobExecutor].
23 May 2014 09:08:59,994 [Thread-1]  INFO org.activiti.engine.impl.jobexecutor.AcquireJobsRunnable:51 - JobExecutor[org.activiti.engine.impl.jobexecutor.DefaultJobExecutor] starting to acquire jobs
23 May 2014 09:09:00,847 [main]  INFO org.activiti.engine.impl.ProcessEngineImpl:79 - ProcessEngine default created
23 May 2014 09:09:00,853 [main]  INFO org.activiti.engine.impl.bpmn.deployer.BpmnDeployer:81 - Processing resource expense_process.bpmn
**** ProcessInstance1 ID *** 5
PROCESS KEY : amount VALUE: 111
PROCESS KEY : employee VALUE: Jack
 *******AVAILABLE TASK**********
 Task Name: Request Refund
 Owner: null
 Assignee: kermit
 Description: [Employee:Jack, 
Amount: 111]
 *******AVAILABLE TASK**********
 Task Name: Request Refund
 Owner: null
 Assignee: kermit
 Description: [Employee:Jonny, 
Amount: 222]
 *******AVAILABLE TASK**********
 Task Name: Request Refund
 Owner: null
 Assignee: kermit
 Description: [Employee:Pete, 
Amount: 333]
*******LIST TASKS************
Get Task:kermit
*******LIST TASKS************
Get Task:kermit
*******LIST TASKS************
Get Task:kermit
*******QUERY FOR ASSIGNEE TASKS************
kermit
23 May 2014 09:09:02,320 [main]  INFO org.activiti.engine.impl.bpmn.deployer.BpmnDeployer:81 - Processing resource expense_process.bpmn
23 May 2014 09:09:02,442 [main]  INFO org.activiti.engine.impl.bpmn.deployer.BpmnDeployer:81 - Processing resource expense_process.expenseProcess.png
Number of tasks for kermit: 2
Accountancy Task: Jack has requested a refund amount 111
Number of tasks for Sandy: 1
BreakPoint Timeout
Number of tasks for Sandy: 1
 *******AVAILABLE TASK**********
 Task Name: Request Refund
 Owner: null
 Assignee: kermit
 Description: [Employee:Jonny, 
Amount: 222]
 *******AVAILABLE TASK**********
 Task Name: Request Refund
 Owner: null
 Assignee: kermit
 Description: [Employee:Pete, 
Amount: 333]
Process instance end time: Fri May 23 09:09:02 PDT 2014