Passing variables to Activities using Parse Handlers

In an Activiti project I’m working on, we need to pass some variables in/out through the call activities. But there was a problem. We have too many processes and call activities in them. So managing those variables in all of them was a tedious task. Also missing one in or out tag will cause error in our execution.

The solution to this is adding in and out parameters on deploy. We’ve created some parse handlers extending from org.activiti.engine.parse.BpmnParseHandler and register it to the org.activiti.engine.ProcessEngineConfiguration. We are using org.activiti.spring.SpringProcessEngineConfiguration so I will go on with that but stand alone configuration will be similar.

You can learn how to define SpringProcessEngineConfiguration bean in your application using that guide.

First you need to define process configuration and process engine beans like this:

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

The dots will be filled soon.
If you are able to deploy and run your processes then we are ready to go. We need to implement our parser classes that will help us to register in and out parameters. Here I’ll implement a custom call activity parse handler for this, namely ParameterRegisteringCallActivityParseHandler.

The mechanism is simple:

package org.activiti.engine.impl.bpmn.parser.handler;
public class CallActivityParseHandler extends AbstractActivityBpmnParseHandler<CallActivity> {
  public Class< ? extends BaseElement> getHandledType() {
    return CallActivity.class;
  }
  
  protected void executeParse(BpmnParse bpmnParse, CallActivity callActivity) {    
    ActivityImpl activity = createActivityOnCurrentScope(bpmnParse, callActivity, BpmnXMLConstants.ELEMENT_CALL_ACTIVITY);
    activity.setScope(true);
    activity.setActivityBehavior(bpmnParse.getActivityBehaviorFactory().createCallActivityBehavior(callActivity));
  }

}

Our code will be like this:

public class ParameterRegisteringCallActivityParseHandler extends CallActivityParseHandler {
	@Override
	protected void executeParse(BpmnParse bpmnParse, CallActivity callActivity) {
		//super.executeParse(bpmnParse, callActivity);
		ActivityImpl activity = createActivityOnCurrentScope(bpmnParse, callActivity, BpmnXMLConstants.ELEMENT_CALL_ACTIVITY);
		activity.setScope(true);
		ProcessDefinitionEntity currentProcessDefinition = bpmnParse.getCurrentProcessDefinition();
		initDefaultInOutParameters(currentProcessDefinition, callActivity);
		activity.setActivityBehavior(bpmnParse.getActivityBehaviorFactory().createCallActivityBehavior(callActivity));
	}
}

I will come to initDefaultInOutParameters later but I want you to notice commenting out super call. The trick here, Activiti does not let us to add in or out parameter passing definitions after calling super. You can check out the conversation between me and Joram Barrez here. We’ve just stepped in while the call activity is being constructed.

So what is about initDefaultInOutParameters? Here is the details:

private void initDefaultInOutParameters(ProcessDefinition processDefinition, CallActivity callActivity) {
	final Set<IOParameter> defaultInParameters = getDefaultInParameters();
	final List<IOParameter> activityInParameters = callActivity.getInParameters();
	activityInParameters.addAll(defaultInParameters);

	final Set<IOParameter> defaultOutParameters = getDefaultOutParameters();
	final List<IOParameter> activityOutParameters = callActivity.getOutParameters();
	activityOutParameters.addAll(defaultOutParameters);
}

private Set<IOParameter> getDefaultInParameters() {
	final Set<IOParameter> ioParameters = new HashSet<IOParameter>();

	final IOParameter currentCallActivityIdParameter = getCurrentCallActivityIdParameter();
	ioParameters.add(currentCallActivityIdParameter);

	final IOParameter someCustomParameter = getCustomParameter();
	ioParameters.add(someCustomParameter);

	return ioParameters;
}

private Set<IOParameter> getDefaultOutParameters() {
	final Set<IOParameter> ioParameters = new HashSet<IOParameter>();

	final IOParameter someCustomParameter = getCustomParameter();
	ioParameters.add(someCustomParameter);

	return ioParameters;
}

As you can see I’ve defined 2 default in parameters and 1 out. One of the in parameters is same with the out one. That means that parameter will be passed in and out for each call activity in the process definition. If you have nested call activities, then it will be passed to and from them too. You can update the value of it and then set to the execution, this parameter will passed out up and up until root execution and you will have the updated value on your root execution.

Implementation of those methods, getCurrentCallActivityIdParameter, getCustomParameter are like this:

private IOParameter getCurrentCallActivityIdParameter() {
	final String sourceExpression = "${execution.currentActivityId}";
	final String target = "CALL_ACTIVITY_ID_VARIABLE_NAME";
	return getIoParameterForSourceExpression(sourceExpression, target);
}

private IOParameter getCustomParameter() {
	final String sourceExpression = "${SOME_VARIABLE_NAME_WHOSE_VALUE_WILL_BE_UPDATED}";
	final String target = "SOME_VARIABLE_NAME_WHOSE_VALUE_WILL_BE_UPDATED";
	return getIoParameterForSourceExpression(sourceExpression, target);
}

protected IOParameter getIoParameterForSourceExpression(final String sourceExpression, final String target) {
	final IOParameter ioParameter = new IOParameter();
	ioParameter.setSourceExpression(sourceExpression);
	ioParameter.setTarget(target);
	return ioParameter;
}

First method, getCurrentCallActivityIdParameter, adds to your call activity definition this:

<activiti:in sourceExpression="${execution.currentActivityId}" target="CALL_ACTIVITY_ID_VARIABLE_NAME"/>

So when you deploy your process definition, it is added to the call activity definition. When the execution reaches to your call activity, this call activity’s id is got and written to the call activity’s execution context. That can be useful for logging.

Second method, notice it is called for in and out, adds to your call activity definition this:

<activiti:in sourceExpression="${SOME_VARIABLE_NAME_WHOSE_VALUE_WILL_BE_UPDATED}" target="SOME_VARIABLE_NAME_WHOSE_VALUE_WILL_BE_UPDATED"/>
<activiti:out sourceExpression="${SOME_VARIABLE_NAME_WHOSE_VALUE_WILL_BE_UPDATED}" target="SOME_VARIABLE_NAME_WHOSE_VALUE_WILL_BE_UPDATED"/>

When the execution hits to your call activity, a new execution context is created. There are 2 execution context at this time, one parent and one child(call activity). Activiti will try to find the variable named SOME_VARIABLE_NAME_WHOSE_VALUE_WILL_BE_UPDATED and get its value. Beware, you should have a variable named SOME_VARIABLE_NAME_WHOSE_VALUE_WILL_BE_UPDATED even if its value is null, otherwise you will get NullPointerException. After getting its value, Activiti writes the value to child execution context with same name. After completing call activity, same is done but in reverse direction. You can update it in call activity or just leave as it is.

The final touch, org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl, which org.activiti.spring.SpringProcessEngineConfiguration is extending from has a property definition that lets us to register our parsers: customDefaultBpmnParseHandlers

So bean definition becomes this:

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

<bean id="parameterRegisteringCallActivityParseHandler" class="my.pkg.ParameterRegisteringCallActivityParseHandler"/>

Hope this helps if you face with something similar.

Advertisements

Flex – Java Real Time Chart With BlazeDS

In my previous post I’ve explained how to create a line chart populated with real time data.

In this post I’ve moved real time data generating to Java project and push that data to client using BlazeDS. The rest is same as the previous flex project.

I’ll simply put sources here so you can take a look at it. You need to modify build.xml in java project according to your system. Also right click on your flex project in your Flash Builder  and select properties. Flex Compiler->Additional Compiler Arguments then modify path. You will be able to deploy the java project war file to tomcat and run your flex project from Flash Builder.

You will see the live data in line chart generated and pushed from the server.

There are 2 projects(RealTimeDataServer, RealTimeLineChart) one for server-side with BlazeDS and the other for client with Flex:

GitHub

Java Serial Programming – Checking Ports

I’m developing an application on android and I need to read from my tablet’s usb port. I’m using a rs232 to usb  chip because  my other device sends data from its serial port and my tablet has no serial port. As you already know whenever you unplug your usb/serial device from your computer and then plug it again, usually its port number changes. For example before unplugging your device the port number was ttyUSB1 but re-plugging it makes the number ttyUSB7 or whatever. I couldn’t find anyway to stop that. If you know a solution for this, please inform me.

You can list plugged devices’ port using Java. I’ll provide sample code for this:

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.Iterator;
import java.util.Vector;

public class PortFinder
{
 public class Driver
 {
 public Driver(String name, String root)
 {
 mDriverName = name;
 mDeviceRoot = root;
 }

 private String mDriverName;
 private String mDeviceRoot;
 Vector<File> mDevices = null;

 public Vector<File> getDevices()
 {
 if (mDevices == null)
 {
 mDevices = new Vector<File>();
 File dev = new File("/dev");
 File[] files = dev.listFiles();
 int i;
 for (i = 0; i < files.length; i++)
 {
 if (files[i].getAbsolutePath().startsWith(mDeviceRoot))
 {
 System.out.println("Found new device: " + files[i]);
 mDevices.add(files[i]);
 }
 }
 }
 return mDevices;
 }

 public String getName()
 {
 return mDriverName;
 }
 }

 private Vector<Driver> mDrivers = null;

 Vector<Driver> getDrivers() throws IOException
 {
 if (mDrivers == null)
 {
 mDrivers = new Vector<Driver>();
 LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));
 String l;
 while ((l = r.readLine()) != null)
 {
 // Issue 3:
 // Since driver name may contain spaces, we do not extract
 // driver name with split()
 String drivername = l.substring(0, 0x15).trim();
 String[] w = l.split(" +");
 if ((w.length >= 5) && (w[w.length - 1].equals("serial")))
 {
 System.out.println("Found new driver " + drivername + " on " + w[w.length - 4]);
 mDrivers.add(new Driver(drivername, w[w.length - 4]));
 }
 }
 r.close();
 }
 return mDrivers;
 }

 public String[] getAllDevices()
 {
 Vector<String> devices = new Vector<String>();
 // Parse each driver
 Iterator<Driver> itdriv;
 try
 {
 itdriv = getDrivers().iterator();
 while (itdriv.hasNext())
 {
 Driver driver = itdriv.next();
 Iterator<File> itdev = driver.getDevices().iterator();
 while (itdev.hasNext())
 {
 String device = itdev.next().getName();
 String value = String.format("%s (%s)", device, driver.getName());
 devices.add(value);
 }
 }
 }
 catch (IOException e)
 {
 e.printStackTrace();
 }
 return devices.toArray(new String[devices.size()]);
 }

 public String[] getAllDevicesPath()
 {
 Vector<String> devices = new Vector<String>();
 // Parse each driver
 Iterator<Driver> itdriv;
 try
 {
 itdriv = getDrivers().iterator();
 while (itdriv.hasNext())
 {
 Driver driver = itdriv.next();
 Iterator<File> itdev = driver.getDevices().iterator();
 while (itdev.hasNext())
 {
 String device = itdev.next().getAbsolutePath();
 devices.add(device);
 }
 }
 }
 catch (IOException e)
 {
 e.printStackTrace();
 }
 return devices.toArray(new String[devices.size()]);
 }

 public static void main(String args[])
 {
 PortFinder portFinder = new PortFinder();
 String[] devices = portFinder.getAllDevices();
 String[] devicePaths = portFinder.getAllDevicesPath();
 for (int i = 0; i < devices.length; i++)
 {
 System.out.println("Device:->" + devices[i] + " Path:->" + devicePaths[i]);
 }
 }
}
 

Using this you will be able to operate (change permission, close, open, write, read etc) on your correct port without looking at /dev.

And the output is(Pay attention to Device:->ttyUSB0 (usbserial) Path:->/dev/ttyUSB0)

Found new driver usbserial on /dev/ttyUSB
Found new driver rfcomm on /dev/rfcomm
Found new driver serial on /dev/ttyS
Found new device: /dev/ttyUSB0
Found new device: /dev/ttyS31
Found new device: /dev/ttyS30
Found new device: /dev/ttyS29
Found new device: /dev/ttyS28
Found new device: /dev/ttyS27
Found new device: /dev/ttyS26
Found new device: /dev/ttyS25
Found new device: /dev/ttyS24
Found new device: /dev/ttyS23
Found new device: /dev/ttyS22
Found new device: /dev/ttyS21
Found new device: /dev/ttyS20
Found new device: /dev/ttyS19
Found new device: /dev/ttyS18
Found new device: /dev/ttyS17
Found new device: /dev/ttyS16
Found new device: /dev/ttyS15
Found new device: /dev/ttyS14
Found new device: /dev/ttyS13
Found new device: /dev/ttyS12
Found new device: /dev/ttyS11
Found new device: /dev/ttyS10
Found new device: /dev/ttyS9
Found new device: /dev/ttyS8
Found new device: /dev/ttyS7
Found new device: /dev/ttyS6
Found new device: /dev/ttyS5
Found new device: /dev/ttyS4
Found new device: /dev/ttyS3
Found new device: /dev/ttyS2
Found new device: /dev/ttyS1
Found new device: /dev/ttyS0
Device:->ttyUSB0 (usbserial) Path:->/dev/ttyUSB0
Device:->ttyS31 (serial) Path:->/dev/ttyS31
Device:->ttyS30 (serial) Path:->/dev/ttyS30
Device:->ttyS29 (serial) Path:->/dev/ttyS29
Device:->ttyS28 (serial) Path:->/dev/ttyS28
Device:->ttyS27 (serial) Path:->/dev/ttyS27
Device:->ttyS26 (serial) Path:->/dev/ttyS26
Device:->ttyS25 (serial) Path:->/dev/ttyS25
Device:->ttyS24 (serial) Path:->/dev/ttyS24
Device:->ttyS23 (serial) Path:->/dev/ttyS23
Device:->ttyS22 (serial) Path:->/dev/ttyS22
Device:->ttyS21 (serial) Path:->/dev/ttyS21
Device:->ttyS20 (serial) Path:->/dev/ttyS20
Device:->ttyS19 (serial) Path:->/dev/ttyS19
Device:->ttyS18 (serial) Path:->/dev/ttyS18
Device:->ttyS17 (serial) Path:->/dev/ttyS17
Device:->ttyS16 (serial) Path:->/dev/ttyS16
Device:->ttyS15 (serial) Path:->/dev/ttyS15
Device:->ttyS14 (serial) Path:->/dev/ttyS14
Device:->ttyS13 (serial) Path:->/dev/ttyS13
Device:->ttyS12 (serial) Path:->/dev/ttyS12
Device:->ttyS11 (serial) Path:->/dev/ttyS11
Device:->ttyS10 (serial) Path:->/dev/ttyS10
Device:->ttyS9 (serial) Path:->/dev/ttyS9
Device:->ttyS8 (serial) Path:->/dev/ttyS8
Device:->ttyS7 (serial) Path:->/dev/ttyS7
Device:->ttyS6 (serial) Path:->/dev/ttyS6
Device:->ttyS5 (serial) Path:->/dev/ttyS5
Device:->ttyS4 (serial) Path:->/dev/ttyS4
Device:->ttyS3 (serial) Path:->/dev/ttyS3
Device:->ttyS2 (serial) Path:->/dev/ttyS2
Device:->ttyS1 (serial) Path:->/dev/ttyS1
Device:->ttyS0 (serial) Path:->/dev/ttyS0

Running Shell Commands With Java As Root

For a long time I’ve been searching for running sudo commands without password prompt in Java. I’ve seen a post by Saeid Zebardast and thanks to him I solved that issue.

First you need  to edit /etc/sudoers file:

$ sudo gedit /etc/sudoers

and add that lines to this file:

# for user
YOUR_USER_NAME ALL= NOPASSWD: ALL

# for group
YOUR_GROUP_NAME ALL= NOPASSWD: ALL

Although the first line is worked for me, Saeid suggests adding both.

Anyway, after that change you can run your sudo command within Java:

String command = "sudo chmod 777 /home/gokceng/Desktop/test.my";
 Runtime runtime = Runtime.getRuntime();
 try
 {
 Process process = runtime.exec(command);
 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
 String line;
 while ((line = bufferedReader.readLine()) != null)
 {
 System.out.println(line);
 }
 }
 catch (IOException e)
 {
 e.printStackTrace();
 }