Raible's Wiki
Raible Designs AppFuseHomepage- Korean - Chinese - Italian - Japanese QuickStart Guide User Guide Tutorials Other ApplicationsStruts ResumeSecurity Example Struts Menu
Set your name in
UserPreferences
Referenced by
JSPWiki v2.2.33
Hide Menu |
This is version 4.
It is not the current version, and thus it cannot be edited. Part I: Integrating jBPM into AppFuse - A HowTo for integrating jBPM Support (via Spring-Modules) into AppFuse. About this tutorialThis tutorial will show you how to configure jBPM 3.1 into AppFuse. It will also show you how to create process definitions and use them in the appfuse application context.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 if the integration is working. 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.
Font Conventions (work in progress)
Table of Contents
[#1] Download jBPM package and install jBPM databaseDownload 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 processCreate the following directories under your appfuse's lib folder: appfuse/lib/jbpm-3.1.2 appfuse/lib/springmodules-0.5Copy 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 jBPMDownload 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="mappingResources"> <list> <value>org/jbpm/graph/action/Script.hbm.xml</value> <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> <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> <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> <value>org/jbpm/context/def/ContextDefinition.hbm.xml</value> <value>org/jbpm/context/def/VariableAccess.hbm.xml</value> <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> <value>org/jbpm/module/def/ModuleDefinition.hbm.xml</value> <value>org/jbpm/bytes/ByteArray.hbm.xml</value> <value>org/jbpm/file/def/FileDefinition.hbm.xml</value> <value>org/jbpm/scheduler/def/CreateTimerAction.hbm.xml</value> <value>org/jbpm/scheduler/def/CancelTimerAction.hbm.xml</value> <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> <value>org/jbpm/module/exe/ModuleInstance.hbm.xml</value> <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/NullInstance.hbm.xml</value> <value>org/jbpm/context/exe/variableinstance/StringInstance.hbm.xml</value> <value>org/jbpm/msg/Message.hbm.xml</value> <value>org/jbpm/msg/db/TextMessage.hbm.xml</value> <value>org/jbpm/command/ExecuteActionCommand.hbm.xml</value> <value>org/jbpm/command/ExecuteNodeCommand.hbm.xml</value> <value>org/jbpm/command/SignalCommand.hbm.xml</value> <value>org/jbpm/command/TaskInstanceEndCommand.hbm.xml</value> <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> <value>org/jbpm/scheduler/exe/Timer.hbm.xml</value> <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> <!-- The property below is commented out b/c it doesn't work when run via Ant in Eclipse. It works fine for individual JUnit tests and in IDEA ?? <property name="mappingJarLocations"> <list><value>file:dist/appfuse-dao.jar</value></list> </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> Apparently there is another way to reference the mapping files(.hbm.xml) using " [#4] Test basic configurationNow that you have all the pieces setup, its time to write a little test case which will do the following:
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 dive into creating more real-life like (tasks, variables, scheduling, custom queries) process defintions using the graphical plugin tool for Eclipse. We will also cover how to avoid reploying process defintions across server restarts, and finally we will inject some spring beans into our jBPM actions to demonstrate what a poweful and easy workflow mechanism jBPM really is!
|