Version 13

    %%( font-size: 130%;)

    JBoss jBPM 3.1 with Spring 2.0 Demo

     

    Disclaimer:  This wiki entry was started by a total jBPM newbie.  This demo will evolve as the original author learns more, and as people add to it.  This app is very bare bones, and it is not necessarily for Java/Spring/Hibernate beginners, just jBPM beginners.  No, I don't think this is great code or best practices, but it's a start.

     

    History:  I am running an application on a Tomcat 5 + Spring 2.0 + Hibernate 3.1 + Spring-managed Hibernate Transactions + Oracle 10g + Java 5 application stack, and I wanted to integrate jBPM.  Apparently so did lots of other people, as I found lots of forum postings asking how to get things set up, and asking for a demo, but the demo was nowhere to be found.  So I played and tweaked and manged to get things set up!  I still don't know exactly what I'm doing, but I'm able to get the application started and if most of the people out there are like me, that's really what you need to get going and play around.  So, I'm posting a stripped down version of the app here to help people get started while I go figure out how to do things properly on my own app. 

     

    If you have comments/questions, there is a jbpm forum thread here

     

    Some notes on the app enclosed:

     

    • It's stripped down from a cms application we're building, so you may notice 'cms' in some places.

    • For similar reasons, the beans are defined in multiple files with names that might seem strange

    • For similar reasons, there are unnecessary jars included.

    • The MessageActionHandler was taken from the jBPM eclipse wizard creation, but in this app it's instantiated through Spring and injected with the first message

    • I don't have unit test classes for this demo app, sorry.

    • As noted on the Spring Modules wiki, defining the process the way I do in the app causes a new version to be created every time you restart the context.  That's OK for a demo app, but obviously not good for production.  see 6.2.3. ProcessDefinitionFactoryBean

    There's a more in depth discussion of this, and a hack around on the Spring Modules forum

    Personally, I think the proper way to do it is to not use process definition in the XML, but that is up to each developer.

    • I've included all of the jars you need to get going, and a db script below, but you should get the latest and greatest of everything when you are ready to make the switch from demo to actual development. 

    • I am not using the identity module, but I haven't implemented my own assignment handler yet... so this doesn't cover users/login/identity.

     

     

    What to do:

     

    1. Have Tomcat 5 set up on your local machine

    2. Download the zip file here

    3. Expand it into Tomcat's webapps dir, or wherever you want to put it if you know what you are doing

    4. Set up the DB vars in the application XML

    5. Run the create DB script on your database

    6. Start Tomcat

    7. go to http://localhost:8080/jbpm31Spring20Demo/workflow.htm

    8. play around

    9. look at code samples

     

    That should be everything.  Though, there's a good chance this wont work, so please give me feedback in the forums:

     

    Have Tomcat 5 set up on your machine

     

    Do it, m'kay.

     

    Download ZIP file here

     

    here's the file!

     

    I'll put some code samples at the end if you don't want to download to look.

     

    Expand it into Tomcat's webapps dir, or wherever you want to put it if you know what you are doing

     

    Just do it.  Now. Go.

     

    Set up the DB vars in the application XML

     

    At the top /WEB-INF/xml/db-config.xml you need to set up your DB url and DB login.  If you are not using Oracle you should change the other hibernate properties to match.

     

    
        <bean id="myDbUrl" class="java.lang.String">
            <constructor-arg value="jdbc:oracle:thin:@localhost:1521:devdb"></constructor-arg>
        </bean>
    
        <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
           <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" ></property>
           <property name="url" ref="myDbUrl" ></property>
           <property name="username" value="user"></property>
           <property name="password" value="pass" ></property>
           <property name="maxActive" value="40" ></property>
           <property name="initialSize" value="1" ></property>
        </bean>     
    
    

     

    Run the create DB script on your database

     

    The Oracle schema scripts have been copied into the dir /WEB-INF/dbscript/oracle

     

    When you go to production, you should rebuild this from the getting started download. 

     

    Note: createSchema=true as a parameter in the jbpmConfiguration does not work.

     

     

    Start Tomcat

     

    OK, GO.

     

    go to http://localhost:8080/jbpm31Spring20Demo/workflow.htm

     

     

    And... Voila!

     

    play around

     

    Let me know if it doesnt work.  You should be able to:

     

    • Create a new instance

    • Signal any active instances

     

    Yeah, that's it.  =)

     

    look at code samples

     

    Any questions, let me know!

     

    Most of my config-related beans:

    
         <bean id="myDbUrl" class="java.lang.String">
              <constructor-arg value="jdbc:oracle:thin:@10.118.1.151:1521:devdb" ></constructor-arg>
         </bean>
    
         <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
              destroy-method="close">
              <property name="driverClassName"
                   value="oracle.jdbc.driver.OracleDriver" ></property>
              <property name="url" ref="myDbUrl" ></property>
              <property name="username" value="user" ></property>
              <property name="password" value="pass" ></property>
              <property name="maxActive" value="40" ></property>
              <property name="initialSize" value="1" ></property>
         </bean>
    
         <bean id="oracleHibernateProperties"
              class="org.springframework.beans.factory.config.PropertiesFactoryBean">
              <property name="properties">
                   <props>
                        <prop key="hibernate.dialect">
                             org.hibernate.dialect.OracleDialect
                        </prop>
                        <prop key="hibernate.default_batch_fetch_size">30</prop>
                        <prop key="hibernate.cache.use_query_cache">false</prop>
                   </props>
              </property>
         </bean>
    
         <bean id="txManager"
              class="org.springframework.orm.hibernate3.HibernateTransactionManager">
              <property name="sessionFactory" ref="sessionFactory" ></property>
         </bean>
    
         <bean name="openSessionInViewInterceptor"
              class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"
              autowire="byName" ></bean>
    
         <!-- NativeJdbcExtractor -->
         <bean id="nativeJdbcExtractor"
              class="org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor"
              lazy-init="true" ></bean>
    
         <!-- LobHandler for Oracle JDBC drivers -->
         <bean id="oracleLobHandler"
              class="org.springframework.jdbc.support.lob.OracleLobHandler"
              lazy-init="true">
              <property name="nativeJdbcExtractor">
                   <ref local="nativeJdbcExtractor" ></ref>
              </property>
         </bean>
    
         <!-- helper for reading jBPM process definitions -->
         <bean id="simpleWorkflow"
              class="org.springmodules.workflow.jbpm31.definition.ProcessDefinitionFactoryBean">
              <property name="definitionLocation"
                   value="classpath:com/sample/jpdl/simpleWorkflow/processdefinition.xml" ></property>
         </bean>
    
         <!-- jBPM configuration -->
         <bean id="jbpmConfiguration"
              class="org.springmodules.workflow.jbpm31.LocalJbpmConfigurationFactoryBean">
              <property name="sessionFactory" ref="sessionFactory" ></property>
              <property name="configuration" value="classpath:jbpm.cfg.xml" ></property><!--
                   <property name="createSchema" value="true"></property>
              -->
              <property name="processDefinitions">
                   <list>
                        <ref local="simpleWorkflow" ></ref>
                   </list>
              </property>
              <!--
                   <property name="processDefinitionsResources">
                   <list>
                   <value>classpath:/org/springmodules/workflow/jbpm31/someOtherWorkflow.xml</value>
                   </list>
                   </property>
              -->
         </bean>
    
         <!-- jBPM template -->
         <bean id="jbpmTemplate"
              class="org.springmodules.workflow.jbpm31.JbpmTemplate">
              <constructor-arg index="0" ref="jbpmConfiguration" ></constructor-arg>
              <constructor-arg index="1" ref="simpleWorkflow" ></constructor-arg>
         </bean>
    
    
         <bean id="sessionFactory"
              class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
              <property name="mappingResources">
                   <list>
                        <!--identity mapping files -->
                        <!-- uncomment if you don't want to use the default jBPM identity mgmgt component 
                             <value>org/jbpm/identity/User.hbm.xml</value>
                             <value>org/jbpm/identity/Group.hbm.xml</value>
                             <value>org/jbpm/identity/Membership.hbm.xml</value>
                        -->
                        <value>/org/jbpm/db/hibernate.queries.hbm.xml</value>
    
                        <!-- graph.def mapping files -->
                        <value>org/jbpm/graph/def/ProcessDefinition.hbm.xml</value>
                        <value>org/jbpm/graph/def/Node.hbm.xml</value>
                        <value>org/jbpm/graph/def/Transition.hbm.xml</value>
                        <value>org/jbpm/graph/def/Event.hbm.xml</value>
                        <value>org/jbpm/graph/def/Action.hbm.xml</value>
                        <value>org/jbpm/graph/def/SuperState.hbm.xml</value>
                        <value>org/jbpm/graph/def/ExceptionHandler.hbm.xml</value>
                        <value>org/jbpm/instantiation/Delegation.hbm.xml</value>
    
                        <!-- graph.node mapping files -->
                        <value>org/jbpm/graph/node/StartState.hbm.xml</value>
                        <value>org/jbpm/graph/node/EndState.hbm.xml</value>
                        <value>org/jbpm/graph/node/ProcessState.hbm.xml</value>
                        <value>org/jbpm/graph/node/Decision.hbm.xml</value>
                        <value>org/jbpm/graph/node/Fork.hbm.xml</value>
                        <value>org/jbpm/graph/node/Join.hbm.xml</value>
                        <value>org/jbpm/graph/node/State.hbm.xml</value>
                        <value>org/jbpm/graph/node/TaskNode.hbm.xml</value>
    
                        <!-- graph.action mapping files -->
                        <value>org/jbpm/graph/action/Script.hbm.xml</value>
    
                        <!-- context.def mapping files -->
                        <value>
                             org/jbpm/context/def/ContextDefinition.hbm.xml
                        </value>
                        <value>org/jbpm/context/def/VariableAccess.hbm.xml</value>
    
                        <!-- taskmgmt.def mapping files -->
                        <value>
                             org/jbpm/taskmgmt/def/TaskMgmtDefinition.hbm.xml
                        </value>
                        <value>org/jbpm/taskmgmt/def/Swimlane.hbm.xml</value>
                        <value>org/jbpm/taskmgmt/def/Task.hbm.xml</value>
                        <value>org/jbpm/taskmgmt/def/TaskController.hbm.xml</value>
    
                        <!-- module.def mapping files -->
                        <value>org/jbpm/module/def/ModuleDefinition.hbm.xml</value>
    
                        <!-- bytes mapping files -->
                        <value>org/jbpm/bytes/ByteArray.hbm.xml</value>
    
                        <!-- file.def mapping files -->
                        <value>org/jbpm/file/def/FileDefinition.hbm.xml</value>
    
                        <!-- scheduler.def mapping files -->
                        <value>
                             org/jbpm/scheduler/def/CreateTimerAction.hbm.xml
                        </value>
                        <value>
                             org/jbpm/scheduler/def/CancelTimerAction.hbm.xml
                        </value>
    
                        <!-- graph.exe mapping files -->
                        <value>org/jbpm/graph/exe/Comment.hbm.xml</value>
                        <value>org/jbpm/graph/exe/ProcessInstance.hbm.xml</value>
                        <value>org/jbpm/graph/exe/Token.hbm.xml</value>
                        <value>org/jbpm/graph/exe/RuntimeAction.hbm.xml</value>
    
                        <!-- module.exe mapping files -->
                        <value>org/jbpm/module/exe/ModuleInstance.hbm.xml</value>
    
                        <!-- context.exe mapping files -->
                        <value>org/jbpm/context/exe/ContextInstance.hbm.xml</value>
                        <value>org/jbpm/context/exe/TokenVariableMap.hbm.xml</value>
                        <value>org/jbpm/context/exe/VariableInstance.hbm.xml</value>
                        <value>
                             org/jbpm/context/exe/variableinstance/ByteArrayInstance.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/exe/variableinstance/DateInstance.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/exe/variableinstance/DoubleInstance.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/exe/variableinstance/HibernateLongInstance.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/exe/variableinstance/HibernateStringInstance.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/exe/variableinstance/LongInstance.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/exe/variableinstance/StringInstance.hbm.xml
                        </value>
    
                        <!-- taskmgmt.exe mapping files -->
                        <value>
                             org/jbpm/taskmgmt/exe/TaskMgmtInstance.hbm.xml
                        </value>
                        <value>org/jbpm/taskmgmt/exe/TaskInstance.hbm.xml</value>
                        <value>org/jbpm/taskmgmt/exe/PooledActor.hbm.xml</value>
                        <value>
                             org/jbpm/taskmgmt/exe/SwimlaneInstance.hbm.xml
                        </value>
    
                        <!-- scheduler.exe mapping files -->
                        <value>org/jbpm/scheduler/exe/Timer.hbm.xml</value>
    
                        <!-- logging mapping files -->
                        <value>org/jbpm/logging/log/ProcessLog.hbm.xml</value>
                        <value>org/jbpm/logging/log/MessageLog.hbm.xml</value>
                        <value>org/jbpm/logging/log/CompositeLog.hbm.xml</value>
                        <value>org/jbpm/graph/log/ActionLog.hbm.xml</value>
                        <value>org/jbpm/graph/log/NodeLog.hbm.xml</value>
                        <value>
                             org/jbpm/graph/log/ProcessInstanceCreateLog.hbm.xml
                        </value>
                        <value>
                             org/jbpm/graph/log/ProcessInstanceEndLog.hbm.xml
                        </value>
                        <value>org/jbpm/graph/log/SignalLog.hbm.xml</value>
                        <value>org/jbpm/graph/log/TokenCreateLog.hbm.xml</value>
                        <value>org/jbpm/graph/log/TokenEndLog.hbm.xml</value>
                        <value>org/jbpm/graph/log/TransitionLog.hbm.xml</value>
                        <value>org/jbpm/context/log/VariableLog.hbm.xml</value>
                        <value>
                             org/jbpm/context/log/VariableCreateLog.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/log/VariableDeleteLog.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/log/VariableUpdateLog.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/log/variableinstance/ByteArrayUpdateLog.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/log/variableinstance/DateUpdateLog.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/log/variableinstance/DoubleUpdateLog.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/log/variableinstance/HibernateLongUpdateLog.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/log/variableinstance/HibernateStringUpdateLog.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/log/variableinstance/LongUpdateLog.hbm.xml
                        </value>
                        <value>
                             org/jbpm/context/log/variableinstance/StringUpdateLog.hbm.xml
                        </value>
                        <value>org/jbpm/taskmgmt/log/TaskLog.hbm.xml</value>
                        <value>org/jbpm/taskmgmt/log/TaskCreateLog.hbm.xml</value>
                        <value>org/jbpm/taskmgmt/log/TaskAssignLog.hbm.xml</value>
                        <value>org/jbpm/taskmgmt/log/TaskEndLog.hbm.xml</value>
                        <value>org/jbpm/taskmgmt/log/SwimlaneLog.hbm.xml</value>
                        <value>
                             org/jbpm/taskmgmt/log/SwimlaneCreateLog.hbm.xml
                        </value>
                        <value>
                             org/jbpm/taskmgmt/log/SwimlaneAssignLog.hbm.xml
                        </value>
                   </list>
              </property>
    
    
              <property name="lobHandler">
                   <ref local="oracleLobHandler" ></ref>
              </property>
              <property name="hibernateProperties"
                   ref="oracleHibernateProperties" ></property>
              <property name="dataSource" ref="myDataSource" ></property>
    
              <!-- caching below, comment out to turn off 
                   <property name="entityCacheStrategies" ref="entityCacheStrategyProperties" ></property>
                   <property name="collectionCacheStrategies" ref="collectionCacheStrategyProperties"></property>
                   caching above, comment out to turn off -->
    
         </bean>
    
    
    
    

     

     

    the way i'm handling transactions with Spring (yes, i can do better now with Spring 2.0) and my Service instance, and an Action getting injected:

     

    
    
        <bean id="workflowServiceTarget" class="com.sample.base.workflow.WorkflowService" autowire="byName">
        </bean>
         <bean id="workflowService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
           <property name="transactionManager" ref="txManager"></property>
           <property name="target" ref="workflowServiceTarget"></property>
           <property name="proxyTargetClass" value="true" ></property>
           <property name="transactionAttributes">
             <props>
               <prop key="*">PROPAGATION_NESTED</prop>
             </props>
           </property>
         </bean>
        
        
        <bean id="myMessageActionHandler" class="com.sample.action.MessageActionHandler">
             <property name="message" value="This Message is Spring Injected!"></property>
        </bean>