Quarkus IronJacamar

This extension allows you to deploy JCA Resource Adapters in Quarkus. IronJacamar is a Jakarta Connector Architecture (JCA) implementation.

Installation

If you want to use this extension, you need to add the io.quarkiverse.ironjacamar:quarkus-ironjacamar extension first to your build file.

For instance, with Maven, add the following dependency to your POM file:

<dependency>
    <groupId>io.quarkiverse.ironjacamar</groupId>
    <artifactId>quarkus-ironjacamar</artifactId>
    <version>1.3.0</version>
</dependency>

Integration

We recommend you to create a Quarkus extension dedicated for your Resource Adapter. This will allow you to build your Resource Adapter to native and perform the optimizations needed to run in Quarkus. If you don’t want to create a Quarkus extension for your Resource Adapter, just implement the ResourceAdapterFactory in your application code and you’ll be fine.

Implementing a ResourceAdapterFactory

A ResourceAdapterFactory is an SPI that the IronJacamar extension introduces to create ResourceAdapter, ManagedConnectionFactory and ActivationSpec instances. You must use the @ResourceAdapterKind annotation on it to specify the resource adapter kind that will be used to identify the factory in the application code.

@ResourceAdapterKind(value = "artemis") (1)
@ResourceAdapterTypes(connectionFactoryTypes = { jakarta.jms.ConnectionFactory.class }) (2)
public class ArtemisResourceAdapterFactory implements ResourceAdapterFactory {...} (3)
1 The value is the name of the resource adapter kind. Because a Quarkus application can manage multiple resource adapters, this is used in the configuration to select the proper resource adapter to be configured and started.
2 The connection factory types that this resource adapter supports. This must be the types that the object returned in the jakarta.resource.spi.ManagedConnectionFactory.createConnectionFactory(jakarta.resource.spi.ConnectionManager) has. That will allow you to @Inject this object in your application code (eg. @Inject ConnectionFactory in this example).
3 The implementation of the ResourceAdapterFactory interface. This is the class that will be instantiated by the IronJacamar extension to create the resource adapter instance.

Using a ResourceEndpoint

Resource endpoints are activated in the ResourceAdapter (think EJB’s @MessageDriven annotation) and are declared using the @ResourceEndpoint annotation.

import io.quarkiverse.ironjacamar.ResourceEndpoint;

@ResourceEndpoint(activationSpecConfigKey = "myqueue") (1)
public class MyResourceEndpoint implements jakarta.jms.MessageListener {...} (2)
1 An optional activation spec configuration key. The activationSpecConfigKey is the key that will be consumed from the configuration (see the application.properties example below)
2 The resource endpoint implementation. Because the Artemis ResourceAdapter implementation expects a jakarta.jms.MessageListener instance, you must implement this interface.

The configuration may vary according to what the chosen ResourceAdapterFactory implementation expects.

Important

The required interface may vary according to the resource adapter used. If you are unsure of what to use, look at your resource adapter documentation.

Configuration

In your application

quarkus.ironjacamar.ra.kind=artemis (1)

quarkus.ironjacamar.ra.config.connection-parameters=host=localhost;port=5445;protocols=HORNETQ (2)
quarkus.ironjacamar.ra.config.protocol-manager-factory=org.apache.activemq.artemis.core.protocol.hornetq.client.HornetQClientProtocolManagerFactory
quarkus.ironjacamar.ra.config.user=guest
quarkus.ironjacamar.ra.config.password=guest

quarkus.ironjacamar.activation-spec.myqueue.config.destination-type=jakarta.jms.Queue (3)
quarkus.ironjacamar.activation-spec.myqueue.config.destination=jms.queue.MyQueue
quarkus.ironjacamar.activation-spec.myqueue.config.max-session=2
quarkus.ironjacamar.activation-spec.myqueue.config.rebalance-connections=true
1 This is the resource adapter kind. It must match the value of the @ResourceAdapterKind annotation in the ResourceAdapterFactory implementation.
2 (Optional) You can specify the resource adapter configuration that will be passed to your ResourceAdapterFactory#createResourceAdapter implementation method.
3 (Optional) You can specify optional activation spec configuration ResourceAdapterFactory#createActivationSpec implementation method.

Multiple Resource Adapters

You can configure more than one ResourceAdapter instance in your application. Just name the resource adapter in the configuration:

quarkus.ironjacamar.main.ra.kind=artemis (1)
quarkus.ironjacamar.other.ra.kind=artemis

To reference in the code, you must use the @io.smallrye.common.annotation.Identifier annotation:

import io.quarkiverse.ironjacamar.ResourceEndpoint;
import io.smallrye.common.annotation.Identifier;

import jakarta.inject.Inject;

import jakarta.jms.ConnectionFactory;
import jakarta.jms.Message;
import jakarta.jms.MessageListener;

@ResourceEndpoint
@Identifier("other") (1)
public class MyResourceEndpoint implements MessageListener {

    @Inject
    @Identifier("main")
    ConnectionFactory connectionFactory; (2)

    @Override
    public void onMessage(Message message) {
        //...
    }
}
1 This MessageListener will be activated by the other resource adapter configured above.
2 This ConnectionFactory will be the one configured in the main resource adapter.

Transactions

Quarkus IronJacamar supports the @Transactional annotation on ResourceEndpoint implementations to automatically enlist the connection in the current transaction:

import io.quarkiverse.ironjacamar.ResourceEndpoint;

import jakarta.inject.Inject;
import jakarta.jms.ConnectionFactory;
import jakarta.jms.Message;
import jakarta.jms.MessageListener;
import javax.transaction.Transactional;

@ResourceEndpoint
public class MyResourceEndpoint implements MessageListener {

    @Inject
    ConnectionFactory connectionFactory;

    @Override
    @Transactional
    public void onMessage(Message message) {
        //...
    }
}

It also supports the @Transactional annotation on methods consuming the managed connection factories produced by the ResourceAdapterFactory implementation:

@Path("/jca")
@ApplicationScoped
public class JcaResource {

        @Inject
        ConnectionFactory connectionFactory;

        @GET
        @Path("/send")
        @Transactional
        public void send() {
            try (Connection connection = connectionFactory.createConnection()) {
                //...
            }
        }
}

Some adapter implementations may require additional configuration to enable transaction support. Check the adapter documentation for more details.

NOTE

if running in a XA transaction, it is recommended to enable recovery by using quarkus.transaction-manager.enable-recovery=true. Check the guide on Using Transactions in Quarkus for more details.

Metrics

If you are using the quarkus-micrometer or quarkus-smallrye-metrics extension, quarkus-ironjacamar can contribute some connection pool-related metrics to the metric registry.

This can be activated by setting the quarkus.ironjacamar.metrics.enabled property to true.

Alternatively, you can disable the pool metrics for a specific resource adapter by setting the quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.enable-metrics property to false.

Listening to lifecycle events

You can listen to lifecycle events of the ResourceAdapter instances by having an @ApplicationScoped bean implementing the ResourceAdapterLifecycleListener interface. Here is an example:

@ApplicationScoped
public class WaitUntilServiceIsReady implements ResourceAdapterLifecycleListener {

    @Override
    public void preStartup(String id, ResourceAdapter resourceAdapter) {
        // Using the org.awaitility.Awaitility library
        await().atMost(10, SECONDS).until(() -> {
            // Check if a dependent service is ready
            return true;
        });
    }

}

Extension Configuration Reference

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

Whether IronJacamar (pool) metrics are published in case a metrics extension is present.

This is a global setting and is not specific to a resource adapter.

Environment variable: QUARKUS_IRONJACAMAR_METRICS_ENABLED

boolean

false

The kind of resource adapter.

Environment variable: QUARKUS_IRONJACAMAR_RA_KIND

string

Enable pool metrics collection. If unspecified, collecting metrics will be enabled by default if a metrics extension is active.

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_ENABLE_METRICS

boolean

The configuration for this resource adapter

Environment variable: QUARKUS_IRONJACAMAR_RA_CONFIG

Map<String,String>

The transaction support level for the Connection Manager

See the TransactionSupportLevel Javadoc for more information

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_TRANSACTION_SUPPORT_LEVEL

no-transaction, local-transaction, xa-transaction

xa-transaction

The number of times to retry the allocation of a connection

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_ALLOCATION_RETRY

int

5

The time to wait between retries of the allocation of a connection

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_ALLOCATION_RETRY_WAIT

Duration

1S

The transaction timeout for the XAResource

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_XA_RESOURCE_TIMEOUT

Duration

120S

The flush strategy for the Connection Manager

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_FLUSH_STRATEGY

unknown, failing-connection-only, invalid-idle-connections, idle-connections, gracefully, entire-pool, all-invalid-idle-connections, all-idle-connections, all-gracefully, all-connections

failing-connection-only

Whether the connection manager is sharable

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_SHARABLE

boolean

true

Whether the connection manager should enlist connections

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_ENLISTMENT

boolean

true

Whether the connection manager should be connectable

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_CONNECTABLE

boolean

false

Whether the connection manager should track connections

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_TRACKING

boolean

Whether the connection manager should use CCM

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_USE_CCM

boolean

true

Whether the connection manager should use interleaving

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_INTERLEAVING

boolean

false

Whether the connection manager should use same RM override

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_IS_SAME_RM_OVERRIDE

boolean

Whether the connection manager should wrap the XAResource

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_WRAP_XA_RESOURCE

boolean

true

Whether the connection manager should pad the XID

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_PAD_XID

boolean

false

The recovery username for the Connection Manager

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_RECOVERY_USERNAME

string

The recovery password for the Connection Manager

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_RECOVERY_PASSWORD

string

The recovery security domain for the Connection Manager

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_RECOVERY_SECURITY_DOMAIN

string

The pool strategy

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_STRATEGY

pool-by-cri, pool-by-subject, pool-by-subject-and-cri, one-pool, reauth

pool-by-cri

Minimum size of the pool

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_MIN_SIZE

int

0

Initial size of the pool

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_INITIAL_SIZE

int

Maximum size of the pool

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_MAX_SIZE

int

20

Blocking timeout

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_BLOCKING_TIMEOUT

Duration

30000MS

Idle timeout period. Default 30 mins

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_IDLE_TIMEOUT_MINUTES

Duration

30M

Validate on match validation

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_VALIDATE_ON_MATCH

boolean

false

Background validation

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_BACKGROUND_VALIDATION

boolean

false

Background validation - millis

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_BACKGROUND_VALIDATION_MILLIS

Duration

Prefill pool

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_PREFILL

boolean

false

Strict minimum, default false

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_STRICT_MIN

boolean

false

Do we want to immediately break when a connection cannot be matched and not evaluate the rest of the pool?

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_USE_FAST_FAIL

boolean

false

Fairness of semaphore permits, default true

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_FAIR

boolean

true

Whether the pool is sharable

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_SHARABLE

boolean

true

Should the pool be created without a separate pool for non-transactional connections?

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_NO_TX_SEPARATE_POOL

boolean

false

The configuration for this resource adapter

Environment variable: QUARKUS_IRONJACAMAR_ACTIVATION_SPEC_CONFIG

Map<String,String>

About the Duration format

To write duration values, use the standard java.time.Duration format. See the Duration#parse() Java API documentation for more information.

You can also use a simplified format, starting with a number:

  • If the value is only a number, it represents time in seconds.

  • If the value is a number followed by ms, it represents time in milliseconds.

In other cases, the simplified format is translated to the java.time.Duration format for parsing:

  • If the value is a number followed by h, m, or s, it is prefixed with PT.

  • If the value is a number followed by d, it is prefixed with P.