Category Archives: Uncategorized

How to Get and Update Process Variable in jBPM 6 via REST API – Part 1

The GET part is fairly simple, you just need to form a URL with the right values.

So assuming you have a BPM process running on a remote server (business-central) and you would like to get/read the Process Variables, lets see how.

JBPM has published REST APIs to interact with it and get mostĀ of the information.

For our case, the REST URL to get the process variable information has this pattern:

/runtime/{deploymentId}/process/instance/{procInstanceID}/variable/{varId}

It’s HTTP GET which returns the variable from a given process instance.

A complete URL may look like below:

http://localhost:8080/business-central/rest/runtime/com.prashantp.demo:bpm-sample:0.1.0/process/instance/4545/variable/person

The above would return the XML value of the variable (person), so if you had a POJO then this can be thought of as the XML version of the same. (JAXB at play).

Writing code to fetch the information can be in plain Java without any BPM libraries, after all its just a REST API which returns XML, the only complexity could be about BASIC AUTH.

Here’s a sample code for retrieving the variable value.


import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.logging.Logger;

import org.apache.commons.codec.binary.Base64;

/**
 * A general Helper class that once configured would return the XML value of a given Variable
 * under a process instance.
 *
 * Sample URL used for REST API of JBPM 6:
 * http://localhost:8080/business-central/rest/runtime
 * /com.infibeam.sapphire:bpm-order-activation:0.3.9
 * /process/instance/4545
 * /variable/person
 *
 * @author prashantp.org
 *
 */
public class BPMGetVariable {
	private Logger logger = Logger.getLogger(BPMGetVariable.class.getName());

	private String variableName;
	private String bpmUrl;
	private String username;
	private String password;

	public BPMGetVariable(long processId, String variableName, String bpmUrl,
			String username, String password, String deploymentId) {
		this.variableName = variableName;
		this.bpmUrl = bpmUrl + deploymentId + "/process/instance/" + processId + "/variable/" + variableName;
		this.username = username;
		this.password = password;
	}

	public static void main(String[] args) throws Exception {
		long processId = 4545;
		String variableName = "person";
		String name = "bpmsAdmin";
		String password = "bpmspasswordhere";
		String deploymentId = "com.prashantp.demo:bpm-sample:0.1.0";

		BPMGetVariable bpmGetVariable = BPMGetVariable.builder()
				.bpmUrl("http://localhost:38080/business-central")
				.credentials(name, password).addDeploymentId(deploymentId)
				.processId(processId).variableName(variableName).build();
		//Save as XML
		Files.write(Paths.get("./" + processId + "_" + variableName + ".xml"),
				bpmGetVariable.getValue().getBytes());
	}

	public String getValue()
			throws MalformedURLException, IOException {

		String variableValue = getFromSecureRESTUrl(bpmUrl, username, password);
		logger.info("Variable Name=" + variableName + ", value=" + variableValue);

		return variableValue;
	}

	private String getFromSecureRESTUrl(String webpageUrl, String username,
			String password) throws MalformedURLException, IOException {
		logger.info(webpageUrl);
		URL url = new URL(webpageUrl);
		URLConnection urlConnection = url.openConnection();
		setSecurityCredentials(urlConnection, username, password);
		return readResponse(urlConnection);
	}

	private void setSecurityCredentials(URLConnection toSecure,
			String username, String password) {
		String authString = username + ":" + password;
		byte[] authEncBytes = Base64.encodeBase64(authString.getBytes());

		toSecure.setRequestProperty("Authorization", "Basic "
				+ new String(authEncBytes));
	}

	private String readResponse(URLConnection urlConnection) throws IOException {
		InputStream is = urlConnection.getInputStream();
		InputStreamReader isr = new InputStreamReader(is);

		int numCharsRead;
		char[] charArray = new char[1024];
		StringBuffer sb = new StringBuffer();
		while ((numCharsRead = isr.read(charArray)) > 0) {
			sb.append(charArray, 0, numCharsRead);
		}
		return sb.toString();
	}

	public static BPMGetVariableBuilder builder() {
		return new BPMGetVariableBuilder();
	}

	static class BPMGetVariableBuilder {
		private long processId;
		private String variableName;
		private String bpmUrl;
		private String username;
		private String password;
		private String deploymentId;

		public BPMGetVariableBuilder processId(long processId) {
			this.processId = processId;
			return this;
		}

		public BPMGetVariableBuilder variableName(String variableName) {
			this.variableName = variableName;
			return this;
		}

		public BPMGetVariableBuilder bpmUrl(String bpmUrl) {
			this.bpmUrl = bpmUrl;
			if (this.bpmUrl.endsWith("/")) {
				this.bpmUrl = this.bpmUrl + "rest/runtime/";
			} else {
				this.bpmUrl = this.bpmUrl + "/rest/runtime/";
			}
			return this;
		}

		public BPMGetVariableBuilder credentials(String name, String password) {
			this.username = name;
			this.password = password;
			return this;
		}

		public BPMGetVariableBuilder addDeploymentId(String deploymentId) {
			this.deploymentId = deploymentId;
			return this;
		}

		public BPMGetVariable build() {
			if (processId == 0 || Objects.isNull(variableName)
					|| Objects.isNull(bpmUrl) || Objects.isNull(username)
					|| Objects.isNull(password) || Objects.isNull(deploymentId)) {
				throw new IllegalStateException();
			}
			return new BPMGetVariable(processId,variableName,bpmUrl,username,password,deploymentId);
		}

	}

}

Now that we have done the GET part how about updating the same Process Variable via the REST API, lets see how.

That’s coming in Part 2 soon.

 

Dealing with Sun JDK related NoClassDefFoundError under Jboss

On a recent server upgrade from Tomcat to Jboss 7 we kept facing issues related to code that made use of sun jdk classes.

Few of Exceptions were:
java.lang.NoClassDefFoundError: com/sun/net/ssl/internal/ssl/Provider
java.lang.NoClassDefFoundError: sun/net/www/protocol/http/Handler

JBoss was not kind enough to allow such references which tomcat or prior Jboss servers were happy to serve!

The solution:

JBoss has a module “sun.jdk” which is used to load the jdk classes. For some reason not all classes are referenced.

In order to allow for the sun or com related jdk packages which are not getting loaded we need to register them under the “sun.jdk” module.

So, first step is to register the various sun/jdk packages that your application is going to depend upon.

This is done by adding few entries into the module.xml found here:

Eg: jboss-as-7.1.1.Final/modules/sun/jdk/main/module.xml

The complete module.xml for reference:

<module xmlns="urn:jboss:module:1.1" name="sun.jdk">
    <resources>
        <!-- currently jboss modules has not way of importing services from
        classes.jar so we duplicate them here -->
        <resource-root path="service-loader-resources"/>
    </resources>
    <dependencies>
        <system export="true">
            <paths>
                <path name="com/sun/script/javascript"/>
                <path name="com/sun/jndi/dns"/>
                <path name="com/sun/jndi/ldap"/>
                <path name="com/sun/jndi/url"/>
                <path name="com/sun/jndi/url/dns"/>
                <path name="com/sun/security/auth"/>
                <path name="com/sun/security/auth/login"/>
                <path name="com/sun/security/auth/module"/>
                <path name="sun/misc"/>
                <path name="sun/io"/>
                <path name="sun/nio"/>
                <path name="sun/nio/ch"/>
                <path name="sun/security"/>
                <path name="sun/security/krb5"/>
                <path name="sun/util"/>
                <path name="sun/util/calendar"/>
                <path name="sun/util/locale"/>
                <path name="sun/security/provider"/>
		<!-- Registered additional packages below which are not enabled by default -->
		<path name="sun/net/www/protocol/https"/>
		<path name="sun/net/www/protocol/http"/>
		<path name="com/sun/net/ssl/internal/ssl"/>
		<!-- Additional package additions ends here -->

                <path name="META-INF/services"/>
            </paths>
            <exports>
                <include-set>
                    <path name="META-INF/services"/>
                </include-set>
            </exports>
        </system>
    </dependencies>
</module>

Note: In this example I have added the below three packages only:

<path name="sun/net/www/protocol/https"/>
<path name="sun/net/www/protocol/http"/>
<path name="com/sun/net/ssl/internal/ssl"/>

Ok, do not rush off to start the server yet, there is one more part remaining to get rid off that nasty NoClassDefFoundError.
Now, we need to reference the “sun.jdk” module.
There are two options we have now:

Approach 1
Reference the module (“sun.jdk”) from your web application by creating a jboss-deployment-structure.xml under your applications WEB-INF/ folder.
Sample:

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.1">
    <deployment>
        <dependencies>
                <module name="sun.jdk"/>
        </dependencies>
    </deployment>
</jboss-deployment-structure>

Approach 2
Reference the module (“sun.jdk”) globally which makes it available to any application deployed on the server. With this you can ignore the custom jboss-deployment-structure.xml (No longer required to be put in each of your web applications).
For this you have to edit the standalone.xml and register the module globally.
Find the tag:

<subsystem xmlns="urn:jboss:domain:ee:1.0"/>

Then change it with this:

<subsystem xmlns="urn:jboss:domain:ee:1.0">
   <global-modules>
      <module name="sun.jdk" slot="main" /> 
   </global-modules> 
</subsystem>

With either of the above two approaches done, you can go ahead and start up your server.
You should no longer see the NoClassDefFoundError for the packages that you have registered.

References that helped me arrive at this solution:
http://www.mastertheboss.com/jboss-server/jboss-as-7/how-to-install-a-module-on-jboss-as-7
https://developer.jboss.org/thread/171932?tstart=0