Skip to main content

Creating a Process Server based on OpenSource Technologies using REST

Posted by edgars on August 4, 2008 at 6:01 PM PDT

This is a post where I will try share some thoughts about where
REST could be useful inside a SOA architecture using Business Process
Management, in that case we will be using jBPM and RESTEasy, which is
the JBoss's implementation for JSR311
- Java Restful WebServices
.


RESTEasy


RestEasy is a project that is getting a good relevance in terms of
integration with some projects inside JBoss.ORG and even other
projects. If you are trying use a simple REST implementation you
should take a look on this projects, basically there are few steps
you must to do to put RestEasy working for your Application, so see
the following Steps:



  1. Download the RESTEasy
    from JBoss.ORG


  2. There is a worth documentation in RESTEasy
    Wiki
    , which I strongly recommend you read it first, in addition
    to this, in order to see some foundation for practical REST
    application, you can read this great
    blog entry
    written by Carol
    McDonald


  3. To make the things works, I recomend you read this link:
    http://wiki.jboss.org/wiki/RESTeasyInstall
    , RESTEasy is pretty easy to understand and apply in even legacy
    Java applications, where you can expose some methods simply putting
    some annotations into your pojos. Basically the steps are:




  • RESTeasy is deployed as a WAR archive and thus depends on a
    Servlet container. When you download RESTeasy and unzip it you will
    see that it contains an exploded WAR. Make a deep copy of the WAR
    archive for your particular application. Place your JAX-RS annotated
    class resources and providers within one or more jars within
    /WEB-INF/lib or your raw class files within /WEB-INF/classes.
    RESTeasy is configured by default to scan jars and classes within
    these directories for JAX-RS annotated classes and deploy and
    register them within the system:



Custom configuration


RESTeasy is implemented as a
ServletContextListener?
and a Servlet and deployed within a WAR file. If you open up the
WEB-INF/web.xml in your RESTeasy download you will see this:

<web-app>
   <display-name>Archetype Created Web Application</display-name>
   <context-param>
      <param-name>resteasy.scan</param-name>
      <param-value>true</param-value>
   </context-param>

   <listener>
      <listener-class>org.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
   </listener>

   <servlet>
      <servlet-name>Resteasy</servlet-name>
      <servlet-class>org.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
   </servlet>

   <servlet-mapping>
      <servlet-name>Resteasy</servlet-name>
      <url-pattern>/*</url-pattern>
   </servlet-mapping>

</web-app>


The ResteasyBootstrap listener is responsible for
initializing some basic components of RESTeasy as well as scanning
for annotation classes you have in your WAR file. It receives
configuration options from <context-param> elements. Here's a
list of what options are available



  • And that's all! Everything you need is ready to run your REST
    Services in any JEE App Server.



Proof of Concept of a “Process Server”


We have several open source BPM Engines , I am using JBoss jBPM
because I wanna show you a Web-Console where the process are running
on, in addition a graphical tool to design my processes.


First of all I have a really simple “Controller” based on REST
principles, nothing too complex or beautiful so far, but is useful,
so I created a simple class called RestService.java where
you can find many useful methods to operate business process using
jBPM. Based on my own experience could be considered a “best
practice” you design your URLs first, who knows some day we could
create a tool (ant or maven), that could based on a text file
containing one URL per line, where after reading it could create an
abstract class with the methods. (Maybe a good way to forget any
XML). Based on this practice I wanna give the ability for PHP, .net
or even HTML interact with my “Process Server”, to do that I can
have the following URLs:



  1. /start/process/{some
    process}/{some user to be associated to my Swilanes}, it I can pass
    via a GET method and I can keep the process id as my return


  2. /signal/process/{the process id I
    must have stored somewhere}/{user} , via a GET I can navigate into
    my process


  3. /process/{process id}/add/var ,
    via a GET I can get a way to add some variables for my process
    execution




    Based on these 4 actions I defined
    above, I can show you now how implement them:



1- Start a new Process Instance



  • For jBPM you must have access to
    Context, which is the key object to operate processes using jBPM.


  • The following code shows this
    method in action:




@GET


@Path("/start/process/{processdefinition}/{user}")


@ProduceMime("text/plain")


public
String startProcesInstance(


@PathParam("processdefinition")String
processDefintion,


@PathParam("user")String
user) {


JbpmContext
ctx = JbpmConfiguration.getInstance().createJbpmContext();


try
{


ProcessInstance
instance = ctx.newProcessInstance(processDefintion);


instance.getContextInstance().setVariable("user",
user);


Token
t = instance.getRootToken();


t.signal();



ctx.save(instance);





return
new
Long(instance.getId()).toString();


}


catch
(Exception e) {


e.printStackTrace();


}


finally
{


ctx.close();


}


return
"ERROR";







      }




2 - Signaling your Process


Once you have your Process Id, you can operate it and do whatever
you want, this is one of the “Key-benefits” in jBPM, the ability
to keep everything related to the process stored in the database, and
not in the memory, it allow you have several application interacting
with your Process Engine, for my testing, I have jBPM Server
(jBPM+JBoss [could be any other AppServer]) in one IP address, and a
TomCat with my simple REST application based in RESTEasy. Keep in
mind, that having your process stored in regular tables in many
Databases supported by Java, you shall create many kinds of
applications, you may use Hibernate for persistence, query and cache
as well as JDBC or even Spring helpers. See the following source code
to allow this action:


@GET


@Path("/signal/process/{id}/{user}")


@ProduceMime("text/plain")


public
String signalProcess(


@PathParam("id")String
id,


@PathParam("user")String
user) {



JbpmContext ctx =
JbpmConfiguration.getInstance().createJbpmContext();






try{



GraphSession graphSession = ctx.getGraphSession();



ProcessInstance processInstance =
graphSession.loadProcessInstance((
new
Long(id)).longValue());






processInstance.signal();






ctx.save(processInstance);









return
processInstance.getRootToken().getNode().getName();






}
catch
(Exception e ) {



e.printStackTrace();



return
"ERROR";



}



finally
{



ctx.close();



}


}






3 – Adding variables to your processes via a simple URL



  • For many reasons, you might need some
    variables for your processes, maybe for a decision taken or for
    anything else, so the following source shows how you can get the
    HttpServletRequest using the injection executed by the REST
    implementation. This method shows you how you can use contextual
    http objects, besides your variables from URL.


  • This could be really useful to capture
    other information, or even process some files not using GET method,
    but the POST method for instance, see the following implementation:



@GET


@Path("/process/{id}/add/var")


@ProduceMime("text/plain")


public
String addVariables(


@PathParam("id")String
id,


@Context
HttpServletRequest request) {



JbpmContext ctx =
JbpmConfiguration.getInstance().createJbpmContext();






try{



GraphSession graphSession = ctx.getGraphSession();



ProcessInstance processInstance =
graphSession.loadProcessInstance((
new
Long(id)).longValue());






Enumeration params = request.getParameterNames();



String param;



StringBuilder b =
new
StringBuilder();



while
(params.hasMoreElements()) {





param = (String) params.nextElement();



processInstance.getContextInstance().setVariable(param,
request.getParameter(param));



b.append(String.format(
"Param:%s=%s
is Stored in BPM Context\n"
,param,request.getParameter(param)));



}









ctx.save(processInstance);









return
b.toString();






}
catch
(Exception e ) {



e.printStackTrace();



return
"ERROR";



}



finally
{



ctx.close();



}


}


Time for Testing


As far you can see, everything on our
example just returns basic “plain texts” as results, so we can
use those everywhere, in The Developers
Conference
(A Brazilian Java Conference) I did an examples really
“old school”, I used a Borland Delphi 5 client, in terms of
integration, I can get an existing Delphi or Visual Basic Application
and integrate them with my “Process Server”, than for our Proof
of Concept. My process for testing is really easy, as far you can see
in the following image:







This is a simple “Buying Process”, where
could be used for many different scenarios, on our case, we try
simulate a simple Delphi client interacting with this process. On
Delphi's side, I need just a component to interact with HTTP requests
and nothing else, so in my case I used TidHTTP object for it.


My Process Server in Action


When we execute the following URL:
http://192.168.161.1:8080/flowlet/start/process/buyticket/edgar
, we are informing the process name: buyticket and
the user ir
edgar ,
and the result we can expect is a text with process id as the text
returned via Http, see the following image:







After execute our
method, the process instance id is 124,
this id might be used for this process interaction, at this moment,
my application is used a process which was deployed in my Process
Server, and then we can create a new instance from the process called
buyticket , so
everything is stored in the database, and we can create any kind of
information based on database tables about our process instances,
such as: “Execution time”, “Troubleshooting” and so on.


Now,
it's time to see our JBoss jBPM Console in action, take a look on my
process listing and you can see the process instance id: 124







And
you can see where in the process, you process instance actually is
stopped:







Now, it's time to navigate through the
process instance, so I will execute the following rest URL:
http://192.168.161.1:8080/flowlet/signal/process/124/edgar
, the result are the following screen shots:







This method, basically execute the signal
into the process instance, and
move the process to the next node, as far you can in the result and
in the following image in the jBPM Console:







Adding the
variables based on HttpServletRequest shall be executed using the
following URL:
http://192.168.161.1:8080/flowlet/process/124/add/var?payment=Yes&blog=Edgar
, so based on the Java Web technologies, you can assume that you have
2 variables: payment and blog, so what we wanna do now
is to transfer these variables from http context, which are durable
just while the server is running or some clustering replication in
really durable information stored in the database as process
variables.
In addition to this capacity, imagine that we need
some variable to define some execution path in the process instance
handling, like a decision handler based on some expression(EL) based
on some variable, for instance:
expression='#{payment=="No"}';
this expression can decide in the decision-node
“Is
Payment Approved?”
which
path(direction) the process will go as the next execution node and
transitions. See the results in the following images:







Now,
we can signal the process again, and the results in our jBPM
Server
could be as the
following
:







Conclusion


Basically,
as far you can see Process Server is
something beyond a product, can be a concept that
you can apply in many different ways, and one of that, for sure could
be using Open-Source technologies, such as we had shown here on this
entry.

















Related Topics >>