Chapter 9. Java EE Application Server Facilities

The present chapter describes the facilities offered by jBPM to leverage the Java EE infrastructure.

9.1. Enterprise Beans

CommandServiceBean is a stateless session bean that executes jBPM commands by calling it's execute method within a separate jBPM context. The environment entries and resources available for customization are summarized in the table below.

Table 9.1. Command service bean environment

NameTypeDescription
JbpmCfgResourceEnvironment EntryThe classpath resource from which to read the jBPM configuration. Optional, defaults to jbpm.cfg.xml.
ejb/LocalTimerEntityBeanEJB ReferenceLink to the local entity bean that implements the scheduler service. Required for processes that contain timers.
jdbc/JbpmDataSourceResource Manager ReferenceLogical name of the data source that provides JDBC connections to the jBPM persistence service. Must match the hibernate.connection.datasource property in the Hibernate configuration file.
jms/JbpmConnectionFactoryResource Manager ReferenceLogical name of the factory that provides JMS connections to the jBPM message service. Required for processes that contain asynchronous continuations.
jms/JobQueueMessage Destination ReferenceThe jBPM message service sends job messages to the queue referenced here. To ensure this is the same queue from which the job listener bean receives messages, the message-destination-link points to a common logical destination, JobQueue.

CommandListenerBean is a message-driven bean that listens on the JbpmCommandQueue for command messages. This bean delegates command execution to the CommandServiceBean.

The body of the message must be a Java object that implements the org.jbpm.Command interface. The message properties, if any, are ignored. If the message does not match the expected format, it is forwarded to the DeadLetterQueue. No further processing is done on the message. If the destination reference is absent, the message is rejected.

In case the received message specifies a replyTo destination, the result of the command execution is wrapped into an object message and sent there. The command connection factory environment reference indicates the resource manager that supplies JMS connections.

Conversely, JobListenerBean is a message-driven bean that listens on the JbpmJobQueue for job messages to support asynchronous continuations.

The message must have a property called jobId of type long which references a pending Job in the database. The message body, if any, is ignored.

This bean extends the CommandListenerBean and inherits its environment entries and resource references available for customization.

Table 9.2. Command/Job listener bean environment

NameTypeDescription
ejb/LocalCommandServiceBeanEJB ReferenceLink to the local session bean that executes commands on a separate jBPM context.
jms/JbpmConnectionFactoryResource Manager ReferenceLogical name of the factory that provides JMS connections for producing result messages. Required for command messages that indicate a reply destination.
jms/DeadLetterQueueMessage Destination ReferenceMessages which do not contain a command are sent to the queue referenced here. Optional; if absent, such messages are rejected, which may cause the container to redeliver.

The TimerEntityBean interacts with the EJB timer service to schedule jBPM timers. Upon expiration, execution of the timer is actually delegated to the command service bean.

The timer entity bean requires access to the jBPM data source for reading timer data. The EJB deployment descriptor does not provide a way to define how an entity bean maps to a database. This is left off to the container provider. In JBoss AS, the jbosscmp-jdbc.xml descriptor defines the data source JNDI name and the relational mapping data (table and column names, among others). Note that the JBoss CMP descriptor uses a global JNDI name (java:JbpmDS), as opposed to a resource manager reference (java:comp/env/jdbc/JbpmDataSource).

Earlier versions of jBPM used a stateless session bean called TimerServiceBean to interact with the EJB timer service. The session approach had to be abandoned because there is an unavoidable bottleneck at the cancelation methods. Because session beans have no identity, the timer service is forced to iterate through all the timers for finding the ones it has to cancel. The bean is still around for backwards compatibility. It works under the same environment as the TimerEntityBean, so migration is easy.

Table 9.3. Timer entity/service bean environment

NameTypeDescription
ejb/LocalCommandServiceBeanEJB ReferenceLink to the local {@linkplain CommandServiceBean session bean} that executes timers on a separate jBPM context.

9.2. jBPM Enterprise Configuration

jbpm.cfg.xml includes the following configuration items:

<jbpm-context>
  <service name="persistence"
           factory="org.jbpm.persistence.jta.JtaDbPersistenceServiceFactory" />
  <service name="message"
           factory="org.jbpm.msg.jms.JmsMessageServiceFactoryImpl" />
  <service name="scheduler"
           factory="org.jbpm.scheduler.ejbtimer.EntitySchedulerServiceFactory" />
</jbpm-context>

JtaDbPersistenceServiceFactory enables jBPM to participate in JTA transactions. If an existing transaction is underway, the JTA persistence service clings to it; otherwise it starts a new transaction. The jBPM enterprise beans are configured to delegate transaction management to the container. However, if you create a JbpmContext in an environment where no transaction is active (say, in a web application), one will be started automatically. The JTA persistence service factory has the configurable fields described below.

  • isCurrentSessionEnabled: if true, jBPM will use the "current" Hibernate session associated with the ongoing JTA transaction. This is the default setting. See the Hibernate guide, section 2.5 Contextual sessions for a description of the behavior. You can take advantage of the contextual session mechanism to use the same session used by jBPM in other parts of your application through a call to SessionFactory.getCurrentSession(). On the other hand, you might want to supply your own Hibernate session to jBPM. To do so, set isCurrentSessionEnabled to false and inject the session via the JbpmContext.setSession(session) method. This will also ensure that jBPM uses the same Hibernate session as other parts of your application. Note, the Hibernate session can be injected into a stateless session bean via a persistence context, for example.
  • isTransactionEnabled: a true value for this field means jBPM will begin a transaction through Hibernate's transaction API (section 11.2. Database transaction demarcation of the Hibernate manual shows the API) upon JbpmConfiguration.createJbpmContext(), commit the transaction and close the Hibernate session upon JbpmContext.close(). This is NOT the desired behaviour when jBPM is deployed as an ear, hence isTransactionEnabled is set to false by default.

JmsMessageServiceFactoryImpl leverages the reliable communication infrastructure exposed through JMS interfaces to deliver asynchronous continuation messages to the JobListenerBean. The JMS message service factory exposes the following configurable fields.

  • connectionFactoryJndiName: the name of the JMS connection factory in the JNDI initial context. Defaults to java:comp/env/jms/JbpmConnectionFactory.
  • destinationJndiName: the name of the JMS destination where job messages will be sent. Must match the destination from which JobListenerBean receives messages. Defaults to java:comp/env/jms/JobQueue.
  • isCommitEnabled: tells whether jBPM should commit the JMS session upon JbpmContext.close(). Messages produced by the JMS message service are never meant to be received before the current transaction commits; hence the JMS sessions created by the service are always transacted. The default value -false- is appropriate when the connection factory in use is XA capable, as the JMS session's produced messages will be controlled by the overall JTA transaction. This field should be set to true if the JMS connection factory is not XA capable so that jBPM commits the JMS session's local transaction explicitly.

EntitySchedulerServiceFactory builds on the transactional notification service for timed events provided by the EJB container to schedule business process timers. The EJB scheduler service factory has the configurable field described below.

  • timerEntityHomeJndiName: the name of the TimerEntityBean's local home interface in the JNDI initial context. Defaults to java:comp/env/ejb/LocalTimerEntityBean.

9.3. Hibernate Enterprise Configuration

hibernate.cfg.xml includes the following configuration items that may be modified to support other databases or application servers.

<!-- sql dialect -->
<property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>

<property name="hibernate.cache.provider_class">
  org.hibernate.cache.HashtableCacheProvider
</property>

<!-- DataSource properties (begin) -->
<property name="hibernate.connection.datasource">java:comp/env/jdbc/JbpmDataSource</property>
<!-- DataSource properties (end) -->

<!-- JTA transaction properties (begin) -->
<property name="hibernate.transaction.factory_class">
  org.hibernate.transaction.JTATransactionFactory
</property>
<property name="hibernate.transaction.manager_lookup_class">
  org.hibernate.transaction.JBossTransactionManagerLookup
</property>
<!-- JTA transaction properties (end) -->

<!-- CMT transaction properties (begin) ===
<property name="hibernate.transaction.factory_class">
  org.hibernate.transaction.CMTTransactionFactory
</property>
<property name="hibernate.transaction.manager_lookup_class">
  org.hibernate.transaction.JBossTransactionManagerLookup
</property>
==== CMT transaction properties (end) -->

You may replace the hibernate.dialect with one that corresponds to your database management system. The Hibernate reference guide enumerates the available database dialects in section 3.4.1 SQL dialects.

HashtableCacheProvider can be replaced with other supported cache providers. Refer to section 19.2 The second level cache of the Hibernate manual for a list of the supported cache providers.

The JBossTransactionManagerLookup may be replaced with a strategy appropriate to applications servers other than JBoss. See section 3.8.1 Transaction strategy configuration to find the lookup class that corresponds to each application server.

Note that the JNDI name used in hibernate.connection.datasource is, in fact, a resource manager reference, portable across application servers. Said reference is meant to be bound to an actual data source in the target application server at deployment time. In the included jboss.xml descriptor, the reference is bound to java:JbpmDS.

Out of the box, jBPM is configured to use the JTATransactionFactory. If an existing transaction is underway, the JTA transaction factory uses it; otherwise it creates a new transaction. The jBPM enterprise beans are configured to delegate transaction management to the container. However, if you use the jBPM APIs in a context where no transaction is active (say, in a web application), one will be started automatically.

If your own EJBs use container-managed transactions and you want to prevent unintended transaction creations, you can switch to the CMTTransactionFactory. With that setting, Hibernate will always look for an existing transaction and will report a problem if none is found.

9.4. Client Components

Client components written directly against the jBPM APIs that wish to leverage the enterprise services must ensure that their deployment descriptors have the appropriate environment references in place. The descriptor below can be regarded as typical for a client session bean.

<session>

  <ejb-name>MyClientBean</ejb-name>
  <home>org.example.RemoteClientHome</home>
  <remote>org.example.RemoteClient</remote>
  <local-home>org.example.LocalClientHome</local-home>
  <local>org.example.LocalClient</local>
  <ejb-class>org.example.ClientBean</ejb-class>
  <session-type>Stateless</session-type>
  <transaction-type>Container</transaction-type>

  <ejb-local-ref>
    <ejb-ref-name>ejb/LocalTimerEntityBean</ejb-ref-name>
    <ejb-ref-type>Entity</ejb-ref-type>
    <local-home>org.jbpm.ejb.LocalTimerEntityHome</local-home>
    <local>org.jbpm.ejb.LocalTimerEntity</local>
  </ejb-local-ref>

  <resource-ref>
    <res-ref-name>jdbc/JbpmDataSource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

  <resource-ref>
    <res-ref-name>jms/JbpmConnectionFactory</res-ref-name>
    <res-type>javax.jms.ConnnectionFactory</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

  <message-destination-ref>
    <message-destination-ref-name>jms/JobQueue</message-destination-ref-name>
    <message-destination-type>javax.jms.Queue</message-destination-type>
    <message-destination-usage>Produces</message-destination-usage>
  </message-destination-ref>

</session>

Provided the target application server was JBoss, the above environment references could be bound to resources in the target operational environment as follows. Note that the JNDI names match the values used by the jBPM enterprise beans.

<session>

  <ejb-name>MyClientBean</ejb-name>
  <jndi-name>ejb/MyClientBean</jndi-name>
  <local-jndi-name>java:ejb/MyClientBean</local-jndi-name>

  <ejb-local-ref>
    <ejb-ref-name>ejb/LocalTimerEntityBean</ejb-ref-name>
    <local-jndi-name>java:ejb/TimerEntityBean</local-jndi-name>
  </ejb-local-ref>

  <resource-ref>
    <res-ref-name>jdbc/JbpmDataSource</res-ref-name>
    <jndi-name>java:JbpmDS</jndi-name>
  </resource-ref>

  <resource-ref>
    <res-ref-name>jms/JbpmConnectionFactory</res-ref-name>
    <jndi-name>java:JmsXA</jndi-name>
  </resource-ref>

  <message-destination-ref>
    <message-destination-ref-name>jms/JobQueue</message-destination-ref-name>
    <jndi-name>queue/JbpmJobQueue</jndi-name>
  </message-destination-ref>

</session>

In case the client component is a web application, as opposed to an enterprise bean, the deployment descriptor would look like this:

<web-app>

  <servlet>
    <servlet-name>MyClientServlet</servlet-name>
    <servlet-class>org.example.ClientServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>MyClientServlet</servlet-name>
    <url-pattern>/client/servlet</url-pattern>
  </servlet-mapping>

  <ejb-local-ref>
    <ejb-ref-name>ejb/LocalTimerEntityBean</ejb-ref-name>
    <ejb-ref-type>Entity</ejb-ref-type>
    <local-home>org.jbpm.ejb.LocalTimerEntityHome</local-home>
    <local>org.jbpm.ejb.LocalTimerEntity</local>
    <ejb-link>TimerEntityBean</ejb-link>
  </ejb-local-ref>

  <resource-ref>
    <res-ref-name>jdbc/JbpmDataSource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

  <resource-ref>
    <res-ref-name>jms/JbpmConnectionFactory</res-ref-name>
    <res-type>javax.jms.ConnectionFactory</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

  <message-destination-ref>
    <message-destination-ref-name>jms/JobQueue</message-destination-ref-name>
    <message-destination-type>javax.jms.Queue</message-destination-type>
    <message-destination-usage>Produces</message-destination-usage>
    <message-destination-link>JobQueue</message-destination-link>
  </message-destination-ref>

</web-app>

The above environment references could be bound to resources in the target operational environment as follows, if the target application server was JBoss.

<jboss-web>

  <ejb-local-ref>
    <ejb-ref-name>ejb/LocalTimerEntityBean</ejb-ref-name>
    <local-jndi-name>java:ejb/TimerEntityBean</local-jndi-name>
  </ejb-local-ref>

  <resource-ref>
    <res-ref-name>jdbc/JbpmDataSource</res-ref-name>
    <jndi-name>java:JbpmDS</jndi-name>
  </resource-ref>

  <resource-ref>
    <res-ref-name>jms/JbpmConnectionFactory</res-ref-name>
    <jndi-name>java:JmsXA</jndi-name>
  </resource-ref>

  <message-destination-ref>
    <message-destination-ref-name>jms/JobQueue</message-destination-ref-name>
    <jndi-name>queue/JbpmJobQueue</jndi-name>
  </message-destination-ref>

</jboss-web>