blob: 5706bab5f1450b39902d3dbe249844d0adea5671 [file] [log] [blame]
= JMS and JPA: A Camel Quarkus example
:cq-example-description: An example that shows how to run a Camel Quarkus application that supports JTA transactions on three external transactional resources: a database (MySQL), a messaging broker (Artemis) and a simulated XAResource which can demonstrate the commit, rollback and crash recovery.
{cq-description}
We use Narayana as the standalone JTA Transaction Manager implementation, and Hibernate as the JPA Adapter.
This example will connect to a database with the connection details defined in `application.properties`.
If the example is run on Development mode and no database exists, Quarkus will create a matching database
https://quarkus.io/guides/datasource#dev-services[as described here].
TIP: Check the https://camel.apache.org/camel-quarkus/latest/first-steps.html[Camel Quarkus User guide] for prerequisites
and other general information.
NOTE: The Narayana `node.identifier` is very important when you scale up in the cloud environment. It must be unique for each node. You can set it by using `quarkus.transaction-manager.node-name` property which the default value is `quarkus`.
== Start in the Development mode
[source,shell]
----
$ mvn clean compile quarkus:dev
----
The above command compiles the project, starts the application and lets the Quarkus tooling watch for changes in your
workspace. Any modifications in your project will automatically take effect in the running application.
TIP: Please refer to the Development mode section of
https://camel.apache.org/camel-quarkus/latest/first-steps.html#_development_mode[Camel Quarkus User guide] for more details.
== Package and run the application
Once you are done with developing you may want to package and run the application.
TIP: Find more details about the JVM mode and Native mode in the Package and run section of
https://camel.apache.org/camel-quarkus/latest/first-steps.html#_package_and_run_the_application[Camel Quarkus User guide]
==== External systems
Start MySQL:
[source, shell]
----
docker run --name db-mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d -p 3306:3306 mysql
docker exec -it db-mysql mysql -uroot -proot -e \
"CREATE DATABASE testdb CHARACTER SET utf8mb4;
CREATE USER 'admin'@'%' IDENTIFIED WITH mysql_native_password BY 'admin';
GRANT ALL ON testdb.* TO 'admin'@'%';
GRANT XA_RECOVER_ADMIN on *.* to 'admin'@'%';
FLUSH PRIVILEGES;"
----
Create `audit_log` if it is needed:
[source, shell]
----
docker exec -it db-mysql mysql -uadmin -padmin testdb -e \
"CREATE TABLE audit_log ( \
id bigint NOT NULL AUTO_INCREMENT, \
message varchar(255) DEFAULT NULL, \
PRIMARY KEY (id) \
);"
----
Start Artemis:
[source, shell]
----
docker run --name artemis \
-e AMQ_USER=admin -e AMQ_PASSWORD=admin \
-d -p 61616:61616 \
quay.io/artemiscloud/activemq-artemis-broker
----
==== Prerequisites
- Make sure `io.quarkus:quarkus-jdbc-mysql` has been added to the project `pom.xml`
- Make sure `db-mysql` and `artemis` has been started and are ready for servicing
- Edit `src/main/resource/application.properties` to uncomment all `%prod` lines
[source, properties]
----
# Production Datasource
%prod.quarkus.datasource.db-kind=mysql
%prod.quarkus.datasource.username=admin
$prod.quarkus.datasource.password=admin
%prod.quarkus.datasource.jdbc.url=mysql://localhost:3306/testdb
%prod.quarkus.datasource.jdbc.transactions=xa
%prod.quarkus.hibernate-orm.database.generation=none
%prod.quarkus.artemis.url=tcp://localhost:61616
%prod.quarkus.artemis.username=admin
%prod.quarkus.artemis.password=admin
----
==== JVM mode
[source,shell]
----
$ mvn clean package
$ java -jar target/quarkus-app/quarkus-run.jar
...
[io.quarkus] (main) camel-quarkus-examples-... started in 0.570s.
----
==== Native mode
IMPORTANT: Native mode requires having GraalVM and other tools installed. Please check the Prerequisites section
of https://camel.apache.org/camel-quarkus/latest/first-steps.html#_prerequisites[Camel Quarkus User guide].
To prepare a native executable using GraalVM, run the following command:
[source,shell]
----
$ mvn clean package -Pnative
$ ./target/*-runner
...
[io.quarkus] (main) camel-quarkus-examples-... started in 0.011s.
...
----
==== How to run
Test the service endpoint from another terminal:
[source,shell]
----
ADDRESS="http://localhost:8080"
curl -X POST $ADDRESS/api/messages/hello
curl $ADDRESS/api/messages
----
Test with normal "hello" content:
[source,shell]
----
curl -X POST $ADDRESS/api/messages/hello
----
Check the audit_log:
[source,shell]
----
curl $ADDRESS/api/messages
----
You should get some results like:
[source]
----
[{message=hello}, {message=hello-ok}]
----
Test rollback by calling the service with "fail" content:
[source,shell]
----
curl -X POST $ADDRESS/api/messages/fail
----
You should not find any trace of the message in the audit_log table. And some failures like:
[source]
----
2022-07-01 11:03:10,257 INFO [route2] (executor-thread-0) Forced exception
2022-07-01 11:03:10,257 ERROR [org.apa.cam.pro.err.DefaultErrorHandler] (executor-thread-0) Failed delivery for (MessageId: 0BE5920FE20C353-0000000000000001 on ExchangeId: 0BE5920FE20C353-0000000000000001). Exhausted after delivery attempt: 1 caught: java.lang.RuntimeException: fail
Message History (source location and message history is disabled)
---------------------------------------------------------------------------------------------------------------------------------------
Source ID Processor Elapsed (ms)
route5/route5 from[platform-http:///api/messages/%7Bmessage%7D?h 4
...
route2/process1 Processor@0x60941009 0
Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------: java.lang.RuntimeException: fail
----
Test crash recovery by calling the service with "crash" content:
[source,shell]
----
curl -X POST $ADDRESS/api/messages/crash
----
The application should be crashed, and you can not see any response.
[source]
----
curl: (52) Empty reply from server
----
Now restart the application, and wait about 10 seconds, then you can see the following messages that the application has recovered the transaction.
[source]
----
2022-09-16 12:35:39,994 INFO [io.quarkus] (main) camel-quarkus-examples-jta-jpa 2.13.0-SNAPSHOT on JVM (powered by Quarkus 2.13.0.CR1) started in 1.755s. Listening on: http://0.0.0.0:8080
2022-09-16 12:35:39,994 INFO [io.quarkus] (main) Profile prod activated.
2022-09-16 12:35:39,994 INFO [io.quarkus] (main) Installed features: [agroal, camel-attachments, camel-bean, camel-core, camel-direct, camel-jpa, camel-jta, camel-log, camel-microprofile-health, camel-platform-http, camel-rest, cdi, hibernate-orm, jdbc-h2, jdbc-mysql, narayana-jta, smallrye-context-propagation, smallrye-health, vertx]
2022-09-16 12:35:49,251 INFO [org.acm.DummyXAResourceRecovery] (Periodic Recovery) DummyXAResourceRecovery returning list of resources: [org.acme.DummyXAResource@35cdbf7a]
2022-09-16 12:35:49,270 INFO [org.acm.DummyXAResource] (Periodic Recovery) Committing DummyXAResource
----
check the audit_log table, you should see the message "crash" in the table.
== Feedback
Please report bugs and propose improvements via https://github.com/apache/camel-quarkus/issues[GitHub issues of Camel Quarkus] project.