Chapter 8. About Java connector architecture

The JCA specification was created to (among other things) generalize the scenarios that have these three participants:

  • An external system such as a database or generally an EIS system
  • A JavaEE application server
  • A deployed application

8.1. Simple JDBC analogy

In the simplest scenario, where there is only an application and database, you have:

diag c0119ca1c6730be208f7cc89d769d54b

Adding an application server that exposes javax.sql.DataSource, you have the following (without recalling different aspects of data sources like XA):

diag 436a38fd23a0dbd93854268606a797ff

8.2. Overview of using JCA

JCA generalizes the concept of a database driver by adding two-way communication between the driver and the application server. The driver becomes a resource adapter that is represented by javax.resource.spi.ResourceAdapter.

There are two important interfaces:

  • javax.resource.spi.ManagedConnectionFactory implemented by a resource adapter.
  • javax.resource.spi.ConnectionManager implemented by an application server.

The ManagedConnectionFactory interface serves two purposes:

  • The Object createConnectionFactory(ConnectionManager cxManager) method may be used to produce a connection factory for a given EIS (or database or message broker) that can be used by application code. The returned Object may be:

    • A generic javax.resource.cci.ConnectionFactory (not described here further, see JCA 1.6, chapter 17: Common Client Interface)
    • EIS specific connection factory like the well-known javax.sql.DataSource or javax.jms.ConnectionFactory. That is the type of connection factory that is used by the pax-transx-jdbc and pax-transx-jms bundles.
  • The javax.resource.spi.ManagedConnection ManagedConnectionFactory.createManagedConnection() method used by an application server, creates actual physical connections to the EIS/database/broker.

ConnectionManager is implemented by an application server and used by a resource adapter. It is the application server that first performs QoS operations (pooling, security, transaction management) and finally delegates to the ManagedConnectionFactory of the resource adapter to create ManagedConnection instances. The flow looks like this:

  1. Application code uses connection factory created and exposed by application server using object returned from ManagedConnectionFactory.createConnectionFactory(). It may be generic CCI interface or e.g., javax.sql.DataSource.
  2. this connection factory doesn’t create connections on its own, instead it delegates to ConnectionManager.allocateConnection() passing resource adapter-specific ManagedConnectionFactory
  3. ConnectionManager implemented by application server creates supporting objects, manages transactions, pooling, etc. and eventually obtains physical (managed) connection from passed ManagedConnectionFactory.
  4. Application code gets connection which is usually a wrapper/proxy created by application server which eventually delegates to resource adapter's specific physical connection.

Following is the diagram, where application server created non-CCI connection factory which is EIS-specific. Simply - access to EIS (here: database) is done using javax.sql.DataSource interface, the driver’s task is to provide physical connection, while application server will wrapp it inside (typically) a proxy that does pooling/enlisting/security.

diag d19ebefefdbf2bac343521fa48cab709

8.3. About the pax-transx project

The pax-transx project provides support for JTA/JTS transaction management in OSGi, as well as resource pooling for JDBC and JMS. It closes the gap between pax-jdbc and pax-jms.

  • pax-jdbc adds configuration options and discovery for javax.sql.(XA)ConnectionFactory services and ships some JDBC pooling implementations
  • pax-jms does the same for javax.jms.(XA)ConnectionFactory services and ships some JMS pooling implementations
  • pax-transx adds configuration options and discovery for javax.transaction.TransactionManager implementations and (finally) provides JCA-based JDBC/JMS connection management with pooling and tranasction support.

The sections about JDBC connection pools and about JMS connection pools are still valid. The only change needed to use JCA-based pools is to use pool=transx properties when registering JDBC data sources and JMS connection factories.

  • pax-jdbc-pool-transx uses org.ops4j.pax.transx.jdbc.ManagedDataSourceBuilder from pax-transx-jdbc
  • pax-jms-pool-transx uses org.ops4j.pax.transx.jms.ManagedConnectionFactoryBuilder from pax-transx-jms

While the pooled data sources/connection factories are created in builder style (no Java™ bean properties), these properties are supported for JDBC:

  • name
  • userName
  • password
  • commitBeforeAutocommit
  • preparedStatementCacheSize
  • transactionIsolationLevel
  • minIdle
  • maxPoolSize
  • aliveBypassWindow
  • houseKeepingPeriod
  • connectionTimeout
  • idleTimeout
  • maxLifetime

These properties are supported for JMS:

  • name
  • userName
  • password
  • clientID
  • minIdle
  • maxPoolSize
  • aliveBypassWindow
  • houseKeepingPeriod
  • connectionTimeout
  • idleTimeout
  • maxLifetime

userName and password properties are needed for XA recovery to work (just like it was with aries.xa.username and aries.xa.password properties in Fuse 6.x).

With this JDBC configuration in Blueprint (mind pool=transx):

<!--
    Database-specific, non-pooling, non-enlisting javax.sql.XADataSource
-->
<bean id="postgresql" class="org.postgresql.xa.PGXADataSource">
    <property name="url" value="jdbc:postgresql://localhost:5432/reportdb" />
    <property name="user" value="fuse" />
    <property name="password" value="fuse" />
    <property name="currentSchema" value="report" />
    <property name="connectTimeout" value="5" />
</bean>

<!--
    Expose database-specific data source with service properties
    No need to expose pooling, enlisting, non database-specific javax.sql.DataSource - it'll be registered
    automatically by pax-jdbc-config with the same properties as this <service>, but with higher service.ranking
-->
<service id="pool" ref="postgresql" interface="javax.sql.XADataSource">
    <service-properties>
        <!-- "pool" key is needed for pax-jdbc-config to wrap database-specific data source inside connection pool -->
        <entry key="pool" value="transx" />
        <!-- <service>/@id attribute doesn't propagate, but name of the datasource is required using one of: -->
        <entry key="osgi.jndi.service.name" value="jdbc/postgresql" />
        <!-- or: -->
        <!--<entry key="dataSourceName" value="jdbc/postgresql" />-->
        <!-- Other properties, that normally are needed by e.g., pax-jdbc-pool-transx -->
        <entry key="pool.maxPoolSize" value="13" />
        <entry key="pool.userName" value="fuse" />
        <entry key="pool.password" value="fuse" />
    </service-properties>
</service>

And with this JMS configuration in Blueprint (mind pool=transx):

<!--
    Broker-specific, non-pooling, non-enlisting javax.jms.XAConnectionFactory
-->
<bean id="artemis" class="org.apache.activemq.artemis.jms.client.ActiveMQXAConnectionFactory">
    <argument index="0" value="tcp://localhost:61616" />
    <!-- credentials needed for JCA-based XA-recovery -->
    <argument index="1" value="admin" />
    <argument index="2" value="admin" />
    <property name="callTimeout" value="2000" />
    <property name="initialConnectAttempts" value="3" />
</bean>

<!--
    Expose broker-specific connection factory with service properties
    No need to expose pooling, enlisting, non broker-specific javax.jms.XAConnectionFactory - it'll be registered
    automatically by pax-jms-config with the same properties as this <service>, but with higher service.ranking
-->
<service id="pool" ref="artemis" interface="javax.jms.XAConnectionFactory">
    <service-properties>
        <!-- "pool" key is needed for pax-jms-config to wrap broker-specific connection factory inside connection pool -->
        <entry key="pool" value="transx" />
        <!-- <service>/@id attribute doesn't propagate, but name of the connection factory is required using one of: -->
        <entry key="osgi.jndi.service.name" value="jms/artemis" />
        <!-- or: -->
        <!--<entry key="name" value="jms/artemis" />-->
        <!-- Other properties, that normally are needed e.g., pax-jms-pool-transx -->
        <entry key="pool.maxPoolSize" value="13" />
        <entry key="pool.userName" value="admin" />
        <entry key="pool.password" value="admin" />
    </service-properties>
</service>

You have a JDBC data source and a JMS connection factory registered that leverage JCA-based resource management. transx-based pools will properly integrate with pax-transx-tm-narayana with respect to XA recovery.

The features that are needed are:

  • pax-jdbc-pool-tranx
  • pax-jms-pool-tranx
  • pax-transx-jdbc
  • pax-transx-jms
  • pax-jms-artemis (when using A-MQ 7)