Wednesday, November 17, 2010

Uploading jBPM .par files (from a repository)

Once you've passed the testing cycles during development, you want to make sure that the processes that get deployed onto the production environment are indeed versions that were released according to your formal build procedure - if you have such in place of course.

In our case, that means that the officially released processes are available from a Maven repository. Now there's nothing wrong with retrieving a newly released process archive and using e.g. the jBPM console to upload it. That is, if there's just one such .par file to upload.

My current project produces no less than 16 process archives, one of which is referenced in multiple locations - so it is not uncommon to have more than 20 process instances started during the course of a single request we're processing.

Now regardless of the question whether we chose the right granularity for our processes (which I think we did, of course), this turned into quite some work for each deployment cycle, keeping track of which .par file was deployed and whether it was in the correct sequence (we're not using late binding for sub-processes). Performing this task had become too error-prone to allow it for the production environment.

Ant to the rescue?

The user guide states that there are three ways to deploy the process archives (they forget about the jBPM console altogether there):
  • The process designer tool; an Eclipse plug-in that is part of JBoss Tools. This is of course not a real option, since we want to be able to deploy process archives without having to start up an IDE.
  • The org.jbpm.ant.DeployProcessTask; an Ant task available from the regular jBPM jar file. While an Ant build actually is a good option for a command-line alternative, this particular task is simply too much: it starts up a complete jBPM context for uploading the process directly to the database, and as such requires all of the applicable configuration. I prefer to have as little direct database access from external hosts as possible (e.g. for security considerations), and this approach doesn't accomplish that.
  • Programmatically; using the jBPM API directly. That is basically just more complex than using the Ant task, so that's not the way to go either (in this case).
So unfortunately these suggestions don't give us the ease-of-use that the jBPM console did, just selecting the .par file and clicking the 'Deploy' button, and we had to search a little further.

Reuse the input method of the designer

A closer look at the GPD designer plug-in shows that its upload functionality is little more than an HTTP client, calling the POST method of the ProcessUploadServlet of the jBPM console. This servlet then uses the functionality of the jBPM API (as mentioned above for the Ant task and the programmatic approach). This entrance into the jBPM deployment is exactly what we need: it's simple in just requiring the .par file to be entered, any database interaction is taken care of by the servlet, any security issues can be addressed by the deployment of the console (see e.g. how that's done in the SOA platform).

So, using Apache's HttpClient library I finally came up with something like the following:
package org.jbpm.par;

import java.io.InputStream;
import java.net.URL;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.impl.client.DefaultHttpClient;

public class ProcessUploader {
    public static void main(String[] args) {
        HttpClient client = null;
        try {
            // Get the input parms: first the file name, then the URL String for its location (in the repo).
            String fileName = args[0];
            URL url = new URL(args[1]);

            // Prepare the request.
            HttpPost request = new HttpPost("http://localhost:8080/jbpm-console/upload");
            ContentBody body = new InputStreamBody(url.openStream(), "application/x-zip-compressed", fileName);
            MultipartEntity entity = new MultipartEntity();
            entity.addPart("bin", body);
            request.setEntity(entity);

            // Execute the request.
            client = new DefaultHttpClient();
            HttpResponse response = client.execute(request);

            // You can examine the the response further by looking at its contents:
            InputStream is = response.getEntity().getContent(); // And e.g. print it to screen...
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (client != null) {
                // Clean up after yourself.
                client.getConnectionManager().shutdown();
            }
        }
    }
}
While this simple example takes a single URL for a .par file (along with the corresponding file name) on the command line, we'll be using the same principle with a standard properties file listing all of the URLs for our process archives and looping through that list executing a request for each file. And these URLs will be pointing to our Maven repository, of course, allowing us to configure the correct versions for each release.

Note that the URL for the upload servlet is hard-coded in the example; if you're uploading your .par files from a different host, you'd want to configure the host on which jBPM runs differently than 'localhost', of course.

3 comments:

  1. Hi Maurice, thanks for your post.

    I try to deploy par file,but http://localhost:8080/jbpm-console/upload, no request for me. I get HTTP 404

    Please help me, I using jbpm4.4 at jboss 5. I no using GPD designer plug-in.

    ReplyDelete
  2. José,

    Sorry for the (very!) late response.

    As you may have figured out by now, this article addresses jBPM version 3 (and has been tested on 3.2.7 specifically). Version 4 has a different deployment scheme, not sure whether it would take a lot of effort to migrate the approach, or that it would make more sense to come up with a specific approach altogether...

    ReplyDelete
  3. I appreciate for your post, and learn much from it. It’s really an excellent work. I really enjoy reading most of your articles and your thoughts about JBPM Development

    Outsource JBPM Development includes more powerful business rules and event integration as well as more support for highly advanced, flexible and latest business processes that are around. It is a result obtained by merging of jBPM project with Drools Flow which is a sub-project of Drools system.

    ReplyDelete