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: |
boolean |
|
The maximum amount of time the worker thread can be blocked. If not specified it assumes the same value as defined by the Environment variable: |
|
|
The kind of resource adapter. Environment variable: |
string |
|
Enable pool metrics collection. If unspecified, collecting metrics will be enabled by default if a metrics extension is active. Environment variable: |
boolean |
|
The configuration for this resource adapter Environment variable: |
Map<String,String> |
|
The transaction support level for the Connection Manager See the TransactionSupportLevel Javadoc for more information Environment variable: |
TransactionSupportLevel |
|
The number of times to retry the allocation of a connection Environment variable: |
int |
|
The time to wait between retries of the allocation of a connection Environment variable: |
|
|
The transaction timeout for the XAResource Environment variable: |
|
|
The flush strategy for the Connection Manager Environment variable: |
FlushStrategy |
|
Whether the connection manager is sharable Environment variable: |
boolean |
|
Whether the connection manager should enlist connections Environment variable: |
boolean |
|
Whether the connection manager should be connectable Environment variable: |
boolean |
|
Whether the connection manager should track connections Environment variable: |
boolean |
|
Whether the connection manager should use CCM Environment variable: |
boolean |
|
Whether the connection manager should use interleaving Environment variable: |
boolean |
|
Whether the connection manager should use same RM override Environment variable: |
boolean |
|
Whether the connection manager should wrap the XAResource Environment variable: |
boolean |
|
Whether the connection manager should pad the XID Environment variable: |
boolean |
|
The recovery username for the Connection Manager Environment variable: |
string |
|
The recovery password for the Connection Manager Environment variable: |
string |
|
The recovery security domain for the Connection Manager Environment variable: |
string |
|
The pool strategy Environment variable: |
PoolStrategy |
|
Minimum size of the pool Environment variable: |
int |
|
Initial size of the pool Environment variable: |
int |
|
Maximum size of the pool Environment variable: |
int |
|
Blocking timeout Environment variable: |
|
|
Idle timeout period. Default 30 mins Environment variable: |
int |
|
Validate on match validation Environment variable: |
boolean |
|
Background validation Environment variable: |
boolean |
|
Background validation - millis Environment variable: |
long |
|
Prefill pool Environment variable: |
boolean |
|
Strict minimum, default false Environment variable: |
boolean |
|
Do we want to immediately break when a connection cannot be matched and not evaluate the rest of the pool? Environment variable: |
boolean |
|
Fairness of semaphore permits, default true Environment variable: |
boolean |
|
Whether the pool is sharable Environment variable: |
boolean |
|
Should the pool be created without a separate pool for non-transactional connections? Environment variable: |
boolean |
|
The configuration for this resource adapter Environment variable: |
Map<String,String> |
About the Duration format
To write duration values, use the standard You can also use a simplified format, starting with a number:
In other cases, the simplified format is translated to the
|