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.4.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 maximum amount of time the worker thread can be blocked. If not specified it assumes the same value as defined by the quarkus.vertx.max-worker-execute-time configuration.

Environment variable: QUARKUS_IRONJACAMAR_MAX_WORKER_EXECUTE_TIME

Duration

${QUARKUS.VERTX.MAX-WORKER-EXECUTE-TIME:60}

quarkus.ironjacamar."resource-adapter-name".ra.kind

The kind of resource adapter.

Environment variable: QUARKUS_IRONJACAMAR_RA_KIND

string

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.enable-metrics

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

quarkus.ironjacamar."resource-adapter-name".ra.config."config"

The configuration for this resource adapter

Environment variable: QUARKUS_IRONJACAMAR_RA_CONFIG__CONFIG_

Map<String,String>

quarkus.ironjacamar."resource-adapter-name".ra.cm.transaction-support-level

The transaction support level for the Connection Manager

See the TransactionSupportLevel Javadoc for more information

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_TRANSACTION_SUPPORT_LEVEL

TransactionSupportLevel

xa-transaction

quarkus.ironjacamar."resource-adapter-name".ra.cm.allocation-retry

The number of times to retry the allocation of a connection

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_ALLOCATION_RETRY

int

5

quarkus.ironjacamar."resource-adapter-name".ra.cm.allocation-retry-wait

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

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_ALLOCATION_RETRY_WAIT

Duration

1S

quarkus.ironjacamar."resource-adapter-name".ra.cm.xa-resource-timeout

The transaction timeout for the XAResource

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_XA_RESOURCE_TIMEOUT

Duration

120S

quarkus.ironjacamar."resource-adapter-name".ra.cm.flush-strategy

The flush strategy for the Connection Manager

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_FLUSH_STRATEGY

FlushStrategy

failing-connection-only

quarkus.ironjacamar."resource-adapter-name".ra.cm.sharable

Whether the connection manager is sharable

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_SHARABLE

boolean

true

quarkus.ironjacamar."resource-adapter-name".ra.cm.enlistment

Whether the connection manager should enlist connections

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_ENLISTMENT

boolean

true

quarkus.ironjacamar."resource-adapter-name".ra.cm.connectable

Whether the connection manager should be connectable

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_CONNECTABLE

boolean

false

quarkus.ironjacamar."resource-adapter-name".ra.cm.tracking

Whether the connection manager should track connections

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_TRACKING

boolean

quarkus.ironjacamar."resource-adapter-name".ra.cm.use-ccm

Whether the connection manager should use CCM

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_USE_CCM

boolean

true

quarkus.ironjacamar."resource-adapter-name".ra.cm.interleaving

Whether the connection manager should use interleaving

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_INTERLEAVING

boolean

false

quarkus.ironjacamar."resource-adapter-name".ra.cm.is-same-rm-override

Whether the connection manager should use same RM override

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_IS_SAME_RM_OVERRIDE

boolean

quarkus.ironjacamar."resource-adapter-name".ra.cm.wrap-xa-resource

Whether the connection manager should wrap the XAResource

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_WRAP_XA_RESOURCE

boolean

true

quarkus.ironjacamar."resource-adapter-name".ra.cm.pad-xid

Whether the connection manager should pad the XID

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_PAD_XID

boolean

false

quarkus.ironjacamar."resource-adapter-name".ra.cm.recovery.username

The recovery username for the Connection Manager

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_RECOVERY_USERNAME

string

quarkus.ironjacamar."resource-adapter-name".ra.cm.recovery.password

The recovery password for the Connection Manager

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_RECOVERY_PASSWORD

string

quarkus.ironjacamar."resource-adapter-name".ra.cm.recovery.security-domain

The recovery security domain for the Connection Manager

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_RECOVERY_SECURITY_DOMAIN

string

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.strategy

The pool strategy

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_STRATEGY

PoolStrategy

pool-by-cri

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.config.min-size

Minimum size of the pool

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_MIN_SIZE

int

0

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.config.initial-size

Initial size of the pool

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_INITIAL_SIZE

int

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.config.max-size

Maximum size of the pool

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_MAX_SIZE

int

20

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.config.blocking-timeout

Blocking timeout

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_BLOCKING_TIMEOUT

Duration

30000MS

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.config.idle-timeout-minutes

Idle timeout period. Default 30 mins

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_IDLE_TIMEOUT_MINUTES

int

30

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.config.validate-on-match

Validate on match validation

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_VALIDATE_ON_MATCH

boolean

false

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.config.background-validation

Background validation

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_BACKGROUND_VALIDATION

boolean

false

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.config.background-validation-millis

Background validation - millis

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_BACKGROUND_VALIDATION_MILLIS

long

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.config.prefill

Prefill pool

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_PREFILL

boolean

false

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.config.strict-min

Strict minimum, default false

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_STRICT_MIN

boolean

false

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.config.use-fast-fail

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

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.config.fair

Fairness of semaphore permits, default true

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_CONFIG_FAIR

boolean

true

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.sharable

Whether the pool is sharable

Environment variable: QUARKUS_IRONJACAMAR_RA_CM_POOL_SHARABLE

boolean

true

quarkus.ironjacamar."resource-adapter-name".ra.cm.pool.no-tx-separate-pool

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

quarkus.ironjacamar.activation-spec."activation-spec-name".config."config"

The configuration for this resource adapter

Environment variable: QUARKUS_IRONJACAMAR_ACTIVATION_SPEC_CONFIG__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.