Raible's Wiki

Raible Designs
Wiki Home
News
Recent Changes

AppFuse

Homepage
  - Korean
  - Chinese
  - Italian
  - Japanese

QuickStart Guide
  - Chinese
  - French
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish
  - Japanese

User Guide
  - Korean
  - Chinese

Tutorials
  - Chinese
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish

FAQ
  - Korean

Latest Downloads

Other Applications

Struts Resume
Security Example
Struts Menu

Set your name in
UserPreferences

Edit this page


Referenced by
AmeerAhmed
Articles
IntegratingJBPMIntoA...
IntegratingJBPMIntoA...




JSPWiki v2.2.33

[RSS]


Hide Menu

IntegratingJBPMIntoAppFuse


Part I: Integrating jBPM into AppFuse - Integrate jBPM Support (via Spring-Modules) into AppFuse.
Part II: Integrating jBPM into AppFuse Part Deux - Setup AppFuse/jBPM in Eclipse, model defintions using the Jbpm Process Designer.
Part III: Integrating jBPM into AppFuse Part Trois - Enhance defintions to support tasks, users, schedule and injecting spring beans into actions (Under Construction).

About this tutorial

This is the 1st tutorial of a 3 part series. The tutorial covers how to configure jBPM 3.1 into AppFuse.

You will use the jbpm-db package to create the jbpm tables in your database for workflow persistence and will author process definitions in Eclispe. And finally you will write some JUnit classes to test the integration.

AppFuse uses Hibernate for its default persistence layer. jBPM also uses Hibernate for its persistence layer. It can be configured to either use the same session factory as AppFuse or use its own dedicated session factory.

I use Oracle 10g for persistence, please see RunningOnOracle to configure appfuse for Oracle.

Font Conventions (work in progress)

Literal strings intended to be executed at the command prompt look like this: ant test-all.
References to files, directories and packages which exist in your source tree: build.xml.
And suggestions for how to do stuff in the "Real World" are in blue italics.

Table of Contents

  • [1] Download jBPM package and install jBPM database
  • [2] Add classpath references to the appfuse build process
  • [3] Download and configure Spring Modules for jBPM
  • [4] Test basic configuration

[#1] Download jBPM package and install jBPM database

Download the JBoss jBPM Starters Kit. Although you won't need all of them for integration, it is a good idea to browse through the sample code once you have the simple setup working. For this tutorial, I used v. 3.1.2.

Unzip them into a temporary folder. jBPM uses its own database, before you proceed any further you have to decide whether you will use a dedicated databse for jBPM or use the same database as AppFuse. To keep things simple we will use a dedicated db for jBPM. The following steps will create sql scripts to create/drop jBPM schema.

Create a new user in oracle with the username/pass as jbpm/jbpm. Copy file ojdbc14.jar into jbpm-db/oracle/lib/ directory (if you are not using oracle, copy the neccessary driver to jbpm-db/**database_of_choice**/lib/ directory). Modify hibernate.properties located in jbpm-db/oracle/ directory to reflect your connection information:

hibernate.dialect=org.hibernate.dialect.Oracle9Dialect
# for Oracle 8 compatibility use
#hibernate.dialect=org.hibernate.dialect.OracleDialect

hibernate.connection.driver_class=oracle.jdbc.driver.OracleDriver
hibernate.connection.url=jdbc:oracle:thin:@localhost:1521:AMEER
hibernate.connection.username=jbpm
hibernate.connection.password=jbpm

hibernate.show_sql=true
hibernate.c3p0.min_size=1
hibernate.c3p0.max_size=3

hibernate.query.substitutions=true 1, false 0

You are now ready to generate the scripts. Execute ant oracle.scripts this will generate the scripts in jbpm-db/build/oracle/scripts/ directory. Execute oracle.create.sql in your favorite database tool, I use TOAD, and voila! jBPM schema should be created and ready for use.

[#2] Add classpath references to the appfuse build process

Create the following directories under your appfuse's lib folder: appfuse/lib/jbpm-3.1.2 appfuse/lib/springmodules-0.5

Copy jbpm/lib/jboss/bsh-1.3.0.jar jbpm/build/jbpm-3.1.2.jar jbpm/build/jbpm.sar.cfg.jar jbpm/build/jbpm-identity-3.1.2.jar to appfuse/lib/jbpm-3.1.2 folder.

Modify appfuse/lib/lib.properties file to include:

jbpm.version=3.1.2
springmodules.version=0.5

jbpm.dir=${lib.dir}/jbpm-${jbpm.version}
springmodules.dir=${lib.dir}/springmodules-${springmodules.version}

Modify appfuse/properties.xml to include the classpath references:

    <path id="dao.compile.classpath">
        <path refid="hibernate.classpath"/>
        <pathelement location="${commons-lang.jar}"/>
        <pathelement location="${commons-logging.jar}"/>
        <pathelement location="${commons-collections.jar}"/>
        <fileset dir="${spring.dir}" includes="*.jar"/>
        <pathelement location="${lucene.jar}"/>
        <fileset dir="${jbpm.dir}" includes="*.jar"/>
        <fileset dir="${springmodules.dir}" includes="*.jar"/>
    </path>

[#3] Download and configure Spring Modules for jBPM

Download and unzip Spring Modules v 0.5. Copy spring-modules-jbpm31.jar to appfuse/lib/springmodules-0.5 directory. The following text is from the default jbpm.cfg.xml configuration file, this controls what services will be used by jbpm, you can comment out any service which you don't want. We will be working with the "persistence", "scheduler" and "logging" services.
<jbpm-configuration>

  <jbpm-context>
    <service name="persistence" factory="org.jbpm.persistence.db.DbPersistenceServiceFactory" />
    <service name="message" factory="org.jbpm.msg.db.DbMessageServiceFactory" />
    <service name="scheduler" factory="org.jbpm.scheduler.db.DbSchedulerServiceFactory" />
    <service name="logging" factory="org.jbpm.logging.db.DbLoggingServiceFactory" />
    <service name="authentication" factory="org.jbpm.security.authentication.DefaultAuthenticationServiceFactory" />
  </jbpm-context>
  
  <!-- configuration resource files pointing to default configuration files in jbpm-{version}.jar -->
  <string name="resource.business.calendar" value="org/jbpm/calendar/jbpm.business.calendar.properties" />
  <string name="resource.default.modules" value="org/jbpm/graph/def/jbpm.default.modules.properties" />
  <string name="resource.converter" value="org/jbpm/db/hibernate/jbpm.converter.properties" />
  <string name="resource.action.types" value="org/jbpm/graph/action/action.types.xml" />
  <string name="resource.node.types" value="org/jbpm/graph/node/node.types.xml" />
  <string name="resource.parsers" value="org/jbpm/jpdl/par/jbpm.parsers.xml" />
  <string name="resource.varmapping" value="org/jbpm/context/exe/jbpm.varmapping.xml" />

  <int name="jbpm.byte.block.size" value="1024" singleton="true" />
  <bean name="jbpm.task.instance.factory" class="org.jbpm.taskmgmt.impl.DefaultTaskInstanceFactoryImpl" singleton="true" />
  <bean name="jbpm.variable.resolver" class="org.jbpm.jpdl.el.impl.JbpmVariableResolver" singleton="true" />
  <long name="jbpm.msg.wait.timout" value="5000" singleton="true" />

</jbpm-configuration>
The file should be saved in appfuse/src/dao/org/appfuse/jbpm/ directory (or you can save it in a directory of your choice, however, you would have to update the reference in the applicationContext-hibernate.xml file).

At this point we want to ensure that all our previous steps are working so it is a good idea to test the configuration. We will dive into writing more complex definitions later on(using the process design tool in eclipse), for now write a simple process definition as:

<process-definition name="testprocess.xml">
  <start-state>
    <transition to='s' />
  </start-state>
  <state name='s'>
    <transition to='end'/>
  </state>
  <end-state name='end' />
</process-definition>
and save it as testprocess.xml into appfuse/src/dao/org/appfuse/jbpm/process directory. The last piece in this puzzle is to configure the appfuse/src/dao/org/appfuse/dao/hibernate/applicationContext-hibernate.xml file. Add the following information to complete the basic integration:
    <!-- JBPM Datasource -->
    <bean id="jbpmDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName"><value>oracle.jdbc.driver.OracleDriver</value></property>
        <property name="url"><value>jdbc:oracle:thin:@localhost:1521:AMEER</value></property>
        <property name="username"><value>jbpm</value></property>
        <property name="password"><value>jbpm</value></property>
    </bean>

    <!-- JBPM Hibernate SessionFactory -->
    <bean id="jbpmSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="jbpmDataSource"/>
        <property name="mappingLocations">
            <value>classpath*:/org/jbpm/**/*.hbm.xml</value>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
                <!-- Create/update the database tables automatically when the JVM starts up
                <prop key="hibernate.hbm2ddl.auto">update</prop> -->
                <!-- Turn batching off for better error messages under PostgreSQL 
                <prop key="hibernate.jdbc.batch_size">0</prop> -->
            </props>
        </property>
    </bean>

    <!-- jBPM Configuration -->
    <bean id="jbpmConfig" class="org.springmodules.workflow.jbpm31.LocalJbpmConfigurationFactoryBean">
	<!-- pass in existing sessionFactory -->
		<property name="sessionFactory" ref="jbpmSessionFactory"/>
		<property name="configuration" value="org/appfuse/jbpm/jbpm.cfg.xml"/>
		<property name="processDefinitions">
			<list>
				<ref local="testProcess"/>
			</list>
		</property>
		<property name="createSchema" value="false"/>
	</bean>

	<bean id="testProcess" class="org.springmodules.workflow.jbpm31.definition.ProcessDefinitionFactoryBean">
		<property name="definitionLocation" value="org/appfuse/jbpm/process/testprocess.xml"/>
	</bean>

[#4] Test basic configuration

Now that you have all the pieces setup, its time to write a little test case which will do the following:


public class ExampleProcessTest extends BaseDaoTestCase {

    JbpmConfiguration config = null;
    JbpmContext context = null;
    ProcessDefinition definition = null;
    
  protected void onSetUpBeforeTransaction() throws Exception {
  config = (JbpmConfigurationapplicationContext.getBean("jbpmConfig");
        context = config.createJbpmContext();
      definition = context.getGraphSession().findLatestProcessDefinition("testProcess");
  }

  public void testProcessDefinition() throws Exception {

      ProcessDefinition def = context.getGraphSession().findLatestProcessDefinition("testProcess");
      
      assertNotNull("Definition should not be null", def);
  }

  public void testStartState() throws Exception {
    
        // The next line creates one execution of the process definition.
        // After construction, the process execution has one main path
        // of execution (=the root token) that is positioned in the
        // start-state.
        ProcessInstance inst = definition.createProcessInstance();
        
        // Also after construction, the main path of execution is positioned
        // in the start-state of the process definition.
        assertEquals("Instance is in start state", definition.getStartState(), inst.getRootToken().getNode());
  
  }

  public void testTransitions() throws Exception {
    
        ProcessInstance inst = definition.createProcessInstance();

        // Let's start the process execution, leaving the start-state 
        // over its default transition.
        inst.signal();
        // The signal method will block until the process execution 
        // enters a wait state.

        // The process execution will have entered the first wait state
        // in state 's'. So the main path of execution is now 
        // positioned in state 's'
        assertEquals("Instance is in 's' state", inst.getRootToken().getNode().getName()"s");

        // Let's send another signal.  This will resume execution by 
        // leaving the state 's' over its default transition.
        inst.signal();
        // Now the signal method returned because the process instance 
        // has arrived in the end-state.
  
        assertEquals("Instance is in 'end' state", inst.getRootToken().getNode().getName()"end");
  }

}

A few words regarding the above code. We grab the config bean(previously configured) and use it to initialize a context. Using jBPM context we can make use of all the services defined in the jbpm.cfg file. GraphSession is used to load the latest instance of process definition by executing a hql query (defined in org/jbpm/db/hibernate.queries.hbm.xml). Once we have the defintion we can create instances from that workflow and perform transitions, tasks, adding variables, scheduling etc (more on this later).

The first time you fire up the test, jbpm will initialize and deploy your process defintion to its database. After it has been initialized you should get the green light of junit!

In the next installment we will setup appfuse/jbpm to run in Eclipse. We will also use Jbpm Process Designer to design defintions.



Go to top   Edit this page   More info...   Attach file...
This page last changed on 03-Mar-2007 07:50:31 MST by AmeerAhmed.