4 Replies Latest reply on Sep 1, 2008 9:28 PM by oxyg3n8

    Seam + JBpm on Tomcat without microcontainer

    tynor.stynor.gmail.com

      Seam 2.0.3.CR1


      We're having a heck of a time finding a hibernate configuration for JBPM that works properly in conjunction with our already working Seam app using RESOURCE_LOCAL transactions.


      Can anyone confirm that they are successfully running Seam + JBPM (with persistence) on raw tomcat without the microcontainer? (and if so, could you share your components.xml, persistence.xml, jbpm.cfg.xml and hibernate.cfg.xml files so I can compare to our many broken variations?)


      We've followed the JPA example configuration to get a working base Seam application, but now that we are adding JBPM workflow, we can't find a jbpm.cfg.xml and hibernate.cfg.xml configuration that actually works.    We've configured JPA for seam with RESOURCE_LOCAL tranactions, and the hibernate.cfg with JDBCTransactions - but we find that hibernate is never flushing to the database -- seam.Jbpm is deploying the processdefinitions, but they are never actually flushed to the database - later, when we try to find a process definition, we can't find it (since it's not in the db). We suspect that the Seam/JBpm integratoin has never been tested outside a JTA environment?


      We've experimented with adding JOTM so that we can run with JTA transactions, but that's a whole 'nuther can of worms (JOTM and its related dependencies do not appear to be actively maintained, don't even work out of the box with Java5, etc.  With JOTM, the Seam process deploy code seems to work, but we then get other errors that appear to be related to JOTM or XAPOOL configuration errors. We don't want to spend too much energy trying to get JOTM to work if it is possible to run Seam + JBpm without it. 


      Help!?
      (and thanks :))
      Steve

        • 1. Re: Seam + JBpm on Tomcat without microcontainer
          guypardon

          Hi,


          Did you try www.atomikos.com instead? It has much less dependencies than JOTM and is actively maintained.


          Guy

          • 2. Re: Seam + JBpm on Tomcat without microcontainer
            tynor.stynor.gmail.com

            Guy Pardon wrote on Aug 25, 2008 13:48:


            Hi,

            Did you try www.atomikos.com instead? It has much less dependencies than JOTM and is actively maintained.

            Guy


            We may try that -- what I was hoping to find out is if anyone has successfully deployed a Seam app on raw Tomcat with JBpm.  It's somewhat frustrating to know that it's theoretically possible to deploy apps to a variety of containers (e.g., Tomcat), but have no clear idea of what can be expected to work and what won't.

            • 3. Re: Seam + JBpm on Tomcat without microcontainer
              pmuir

              We haven't tested Seam + jbpm + hibernate on tomcat. Report back how you make it work :-)

              • 4. Re: Seam + JBpm on Tomcat without microcontainer
                oxyg3n8

                Basically having JBPM with Seam is like having Seam alone with 1 datasource, you don't need to get involved much into the transaction manager, the trick is under jbpm.cfg.xml and hibernate.cfg.xml which I will post here:


                Hibernate; get a copy from any jdpl project, here is the important fragment:


                <!-- hibernate dialect -->
                <property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
                
                <property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
                    
                <!-- DataSource properties (begin) -->
                     <property name="hibernate.connection.datasource">java:comp/env/jdbc/jbpm</property>
                <!-- DataSource properties (end) -->
                



                jbpm.cfg.xml:


                <jbpm-configuration>
                
                  <jbpm-context>
                    <service name="persistence">
                       <factory>
                          <bean class="org.jbpm.persistence.db.DbPersistenceServiceFactory">
                             <field name="isTransactionEnabled"><false/></field>
                          </bean>
                       </factory>
                    </service>
                    <service name="tx" factory="org.jbpm.tx.TxServiceFactory" />
                    <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>
                
                </jbpm-configuration>
                



                components.xml:


                <?xml version="1.0" encoding="UTF-8"?>
                <components xmlns="http://jboss.com/products/seam/components"
                     xmlns:core="http://jboss.com/products/seam/core"
                    xmlns:bpm="http://jboss.com/products/seam/bpm"
                     xmlns:persistence="http://jboss.com/products/seam/persistence"
                     xmlns:transaction="http://jboss.com/products/seam/transaction"
                     xmlns:security="http://jboss.com/products/seam/security"
                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xmlns:theme="http://jboss.com/products/seam/theme"
                     xmlns:web="http://jboss.com/products/seam/web"
                     xmlns:mail="http://jboss.com/products/seam/mail"
                     xsi:schemaLocation="http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.0.xsd
                                 http://jboss.com/products/seam/bpm http://jboss.com/products/seam/bpm-2.0.xsd 
                                     http://jboss.com/products/seam/web http://jboss.com/products/seam/web-2.0.xsd
                                     http://jboss.com/products/seam/persistence http://jboss.com/products/seam/persistence-2.0.xsd 
                                     http://jboss.com/products/seam/transaction http://jboss.com/products/seam/transaction-2.0.xsd 
                                     http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.0.xsd
                                     http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.0.xsd
                                     http://jboss.com/products/seam/mail http://jboss.com/products/seam/mail-2.0.xsd
                                     http://jboss.com/products/seam/theme http://jboss.com/products/seam/theme-2.0.xsd">
                     
                     ...
                     ...
                     ...
                
                    <bpm:jbpm>
                        <bpm:process-definitions>
                            <value>procesos/solicitud-tutorias/processdefinition.xml</value>
                            <value>procesos/proceso-prueba/processdefinition.xml</value>
                        </bpm:process-definitions>
                    </bpm:jbpm>
                
                </components>
                



                Sample JbpmProcessManager which most be marked as @Transactional; besides this we have another datasource for our own data and is handled using JPA, an another tomcat datasource. So far is working perfectly, my problem is that I need a 2nd datasource handled by JPA and I'm force to work with JOTM since that's not possible on Seam; here is a fragment of my POM to handle JOTM properly, the connector dependency you have to download it from Sun due license stuff, then install locally, don't download the version 1.0, use the version 1.5 as specify on the following fragment:


                         <dependency>
                                <groupId>jotm</groupId>
                                <artifactId>jotm</artifactId>
                                <version>2.0.10</version>
                                <exclusions>
                                     <exclusion>
                                        <groupId>javax.resource</groupId>
                                        <artifactId>connector</artifactId>
                                   </exclusion>
                                </exclusions>
                         </dependency>
                
                         <dependency>
                              <groupId>javax.resource</groupId>
                              <artifactId>connector</artifactId>
                              <version>1.5</version>
                     </dependency>
                



                Oops, I went out of the subject; here, the JbpmManager sample:


                package ...................;
                
                import java.util.LinkedList;
                import java.util.List;
                import java.util.Map;
                import java.util.StringTokenizer;
                
                import org.apache.commons.lang.StringUtils;
                import org.jboss.seam.annotations.In;
                import org.jboss.seam.annotations.Name;
                import org.jboss.seam.annotations.Transactional;
                import org.jboss.seam.bpm.Actor;
                import org.jbpm.JbpmContext;
                import org.jbpm.context.exe.ContextInstance;
                import org.jbpm.graph.def.ProcessDefinition;
                import org.jbpm.graph.def.Transition;
                import org.jbpm.graph.exe.ProcessInstance;
                import org.jbpm.graph.exe.Token;
                import org.jbpm.taskmgmt.def.Swimlane;
                import org.jbpm.taskmgmt.exe.TaskInstance;
                import org.jbpm.taskmgmt.exe.TaskMgmtInstance;
                
                import ...........ExcepcionDatosNoEncontrados;
                
                /**
                 * @author gmedina
                 */
                @Name("jbpmProcessManager")
                @Transactional
                public class JbpmProcessManager {
                
                     @In
                     private JbpmContext jbpmContext;
                
                     /*
                      * Protected Helper Methods.
                      */
                
                     /**
                      * Helper method which returns the {@link ProcessInstance} of a process ID.
                      * 
                      * @param processInstanceId
                      *            Process ID.
                      * @return The process instance.
                      */
                     protected ProcessInstance getProcessInstance(long processInstanceId) {
                          return jbpmContext.getProcessInstance(processInstanceId);
                     }
                
                     /**
                      * Helper method which returns the {@link ContextInstance} of a process ID.
                      * 
                      * @param processInstanceId
                      *            Process ID.
                      * @return The process's context instance.
                      */
                     protected ContextInstance getContextInstance(long processInstanceId) {
                          return getProcessInstance(processInstanceId).getContextInstance();
                     }
                
                     /**
                      * Helper method which returns the {@link TaskMgmtInstance} of a process ID.
                      * 
                      * @param processInstanceId
                      *            Process ID.
                      * @return The process's task management instance.
                      */
                     protected TaskMgmtInstance getTaskMgmtInstance(long processInstanceId) {
                          return getProcessInstance(processInstanceId).getTaskMgmtInstance();
                     }
                
                     /*
                      * Process and Token variables related methods.
                      */
                
                     /**
                      * Returns a process global variable.
                      * 
                      * @param processInstanceId
                      *            Process ID.
                      * @param name
                      *            Variable name.
                      * @return Variable's value/object.
                      */
                     public Object getProcessVariable(long processInstanceId, String name) {
                          return getContextInstance(processInstanceId).getVariable(name);
                     }
                
                     /**
                      * Sets a process's global variable.
                      * 
                      * @param processInstanceId
                      *            Process ID.
                      * @param name
                      *            Variable's name.
                      * @param value
                      *            Variable's value/object.
                      */
                     public void setProcessVariable(long processInstanceId, String name,
                               Object value) {
                          getContextInstance(processInstanceId).setVariable(name, value);
                     }
                
                     /**
                      * Deletes a process's global variable.
                      * 
                      * @param processInstanceId
                      *            Process ID.
                      * @param name
                      *            Variable's name.
                      */
                     public void deleteProcessVariable(long processInstanceId, String name) {
                          getContextInstance(processInstanceId).deleteVariable(name);
                     }
                
                     /**
                      * Returns a process's token related variable.
                      * 
                      * @param processInstanceId
                      *            Process ID.
                      * @param name
                      *            Variable's name.
                      * @param token
                      *            Specific token (node).
                      * @return Variable's value/object.
                      */
                     public Object getProcessVariableForToken(long processInstanceId,
                               String name, Token token) {
                          return getContextInstance(processInstanceId).getVariable(name, token);
                     }
                
                     /**
                      * Sets a process's variable related to a token (node).
                      * 
                      * @param processInstanceId
                      *            Process ID.
                      * @param name
                      *            Variable's name.
                      * @param value
                      *            Variable's value/object.
                      * @param token
                      *            Specific token (node).
                      */
                     public void setProcessVariableForToken(long processInstanceId, String name,
                               Object value, Token token) {
                          getContextInstance(processInstanceId).setVariable(name, value, token);
                     }
                
                     /**
                      * Deletes a process's variable related to a token (node).
                      * 
                      * @param processInstanceId
                      *            Process ID.
                      * @param name
                      *            Variable's name.
                      * @param token
                      *            Variable's value/object.
                      */
                     public void deleteProcessVariableForToken(long processInstanceId,
                               String name, Token token) {
                          getContextInstance(processInstanceId).deleteVariable(name, token);
                     }
                
                     /**
                      * Returns a process's global variable.
                      * 
                      * @param processInstanceId
                      *            Process ID.
                      * @return Variable's value/object.
                      */
                     @SuppressWarnings("unchecked")
                     public Map<String, Object> getProcessVariables(long processInstanceId) {
                          return getContextInstance(processInstanceId).getVariables();
                     }
                
                     /**
                      * Returns a {@link Map} containing all the toke's related variable.
                      * 
                      * @param processInstanceId
                      *            Process ID.
                      * @param token
                      *            Specific token (node).
                      * @return {@link Map<String, Object>} with the variables names and
                      *         values/objects.
                      */
                     @SuppressWarnings("unchecked")
                     public Map<String, Object> getProcessVariablesForToken(
                               long processInstanceId, Token token) {
                          return getContextInstance(processInstanceId).getVariables(token);
                     }
                
                     /*
                      * Task assignments methods.
                      */
                
                     /**
                      * Returns the actor's assigned task's list.
                      * 
                      * @param actorId
                      *            Actor ID.
                      * @return {@link List<TaskInstance>} of the current assigned tasks list.
                      */
                     @SuppressWarnings("unchecked")
                     public List<TaskInstance> getAssignedTasks(String actorId) {
                          return jbpmContext.getTaskList(actorId);
                     }
                
                     /**
                      * Returns the actor's assignable tasks.
                      * 
                      * @param actorId
                      *            Actor ID.
                      * @return Assignable's actor tasks list.
                      */
                     @SuppressWarnings("unchecked")
                     public List<TaskInstance> getAssignableTasks(List<String> roles) {
                          return jbpmContext.getGroupTaskList(roles);
                     }
                
                     /*
                      * Tasks instances iteration methods.
                      */
                
                     /**
                      * Creates a new process.
                      * 
                      * @param processDefinitionName
                      *            The process definition name..
                      * @return The new process instance.
                      */
                     public ProcessInstance startProcess(String processDefinitionName) {
                          ProcessInstance processInstance = jbpmContext
                                    .newProcessInstance(processDefinitionName);
                          return processInstance;
                     }
                
                     /**
                      * Assigns an specific task to an actor.
                      * 
                      * @param taskInstanceId
                      *            Task Instance ID.
                      * @param actorId
                      *            Actor ID.
                      */
                     public void assignTaskToActor(long taskInstanceId, String actorId) {
                          jbpmContext.getTaskInstance(taskInstanceId).setActorId(actorId);
                     }
                
                     /**
                      * Ends an specific task and pass a {@link Map<String, Object>} with the
                      * variables for such Token..
                      * 
                      * @param taskInstanceId
                      *            Task Instance ID.
                      * @param transitionName
                      *            Transition Name.
                      */
                     public void endTaskInstance(long taskInstanceId, String transitionName,
                               Map<String, Object> variables) {
                          TaskInstance taskInstance = jbpmContext.getTaskInstance(taskInstanceId);
                          if (taskInstance != null && variables != null) {
                               getContextInstance(taskInstance.getProcessInstance().getId())
                                         .addVariables(variables, taskInstance.getToken());
                          }
                          taskInstance.end(transitionName);
                     }
                
                     /**
                      * Returns a Transition from an specific TaskInstance.
                      * 
                      * @param taskInstanceId
                      *            Task Instance ID.
                      * @param transitionId
                      *            Transition ID.
                      * @return Transition instance.
                      */
                     @SuppressWarnings("unchecked")
                     public Transition getTransition(long taskInstanceId, long transitionId) {
                          List<Transition> transitions = jbpmContext.getTaskInstance(
                                    taskInstanceId).getAvailableTransitions();
                          for (Transition transition : transitions) {
                               if (transition.getId() == transitionId) {
                                    return transition;
                               }
                          }
                          return null;
                     }
                
                     /**
                      * Returns the available processes for an specific Swimlane.
                      * 
                      * @param swimlaneName
                      *            Swimlane name.
                      * @return A process definition list.
                      */
                     @SuppressWarnings("unchecked")
                     public List<ProcessDefinition> getAvailableProcesses(String swimlaneName) {
                          List<ProcessDefinition> processesDef = jbpmContext.getGraphSession()
                                    .findLatestProcessDefinitions(), filteredDefinitions = new LinkedList<ProcessDefinition>();
                          if (StringUtils.isEmpty(swimlaneName)) {
                               return processesDef;
                          } else {
                               for (ProcessDefinition processDefinition : processesDef) {
                                    Swimlane swimlane = processDefinition.getTaskMgmtDefinition()
                                              .getStartTask().getSwimlane();
                                    if (swimlane != null && swimlaneName.equals(swimlane.getName())) {
                                         filteredDefinitions.add(processDefinition);
                                    }
                               }
                               return filteredDefinitions;
                          }
                     }
                
                     /**
                      * Returns a task instance.
                      * 
                      * @param taskInstanceId
                      *            Task Instance ID
                      * @return A Task Instance.
                      */
                     public TaskInstance getTaskInstance(long taskInstanceId) {
                          return jbpmContext.getTaskInstance(taskInstanceId);
                     }
                
                     /**
                      * Returns the current jBPM/Seam actor ID.
                      * 
                      * @return Current authenticated/set actor ID.
                      */
                     public String getCurrentActorId() {
                          return jbpmContext.getActorId();
                     }
                
                     /**
                      * Returns a process definition based on its ID.
                      * 
                      * @param processDefinitionId
                      *            Process definition ID.
                      * @return The process definition instance.
                      */
                     public ProcessDefinition getProcessDefinition(long processDefinitionId)
                               throws ExcepcionDatosNoEncontrados {
                          ProcessDefinition processDefinition = jbpmContext.getGraphSession()
                                    .getProcessDefinition(processDefinitionId);
                          if (processDefinition == null)
                               throw new ExcepcionDatosNoEncontrados();
                          else
                               return processDefinition;
                     }
                
                     /**
                      * Returns a process definition based on its name.
                      * 
                      * @param processDefinitionId
                      *            Process definition name.
                      * @return The process definition instance.
                      */
                     public ProcessDefinition findLatestProcessDefinition(String processName) {
                          return jbpmContext.getGraphSession().findLatestProcessDefinition(
                                    processName);
                     }
                
                     /**
                      * Returns the process definitions available for an actor.
                      * 
                      * @param actor
                      *            Actor.
                      * @return Process Definitions List.
                      */
                     public List<ProcessDefinitionCategory> getAvailableDefintions(Actor actor) {
                          List<ProcessDefinitionCategory> definitions = new LinkedList<ProcessDefinitionCategory>();
                          for (ProcessDefinition processDefinition : getAvailableProcesses(null)) {
                               Swimlane swimlane = processDefinition.getTaskMgmtDefinition()
                                         .getStartTask().getSwimlane();
                               if (swimlane == null) {
                                    definitions.add(new ProcessDefinitionCategory("Cualquiera",
                                              processDefinition));
                               } else {
                                    for (String role : actor.getGroupActorIds()) {
                                         StringTokenizer tokens = new StringTokenizer(swimlane
                                                   .getPooledActorsExpression(), ",");
                                         for (String token = tokens.nextToken(); tokens
                                                   .hasMoreTokens();) {
                                              if (StringUtils.isNotEmpty(token) && role.equals(token)) {
                                                   definitions.add(new ProcessDefinitionCategory(
                                                             swimlane.getName(), processDefinition));
                                              }
                                         }
                                    }
                               }
                          }
                          return definitions;
                     }
                
                }