diff --git a/docs/src/main/asciidoc/artemis-jms-guide.adoc b/docs/src/main/asciidoc/artemis-jms-guide.adoc new file mode 100644 index 0000000000000..5873f05e33fe3 --- /dev/null +++ b/docs/src/main/asciidoc/artemis-jms-guide.adoc @@ -0,0 +1,287 @@ +//// +This guide is maintained in the main Quarkus repository +and pull requests should be submitted there: +https://github.com/quarkusio/quarkus/tree/master/docs/src/main/asciidoc +//// += Quarkus - Using Artemis JMS extension +include::./attributes.adoc[] + +This guide demonstrates how your Quarkus application can use Artemis JMS messaging. + +== Prerequisites + +To complete this guide, you need: + +* less than 15 minutes +* an IDE +* JDK 1.8+ installed with `JAVA_HOME` configured appropriately +* Apache Maven 3.5.3+ +* A running Artemis server, or Docker Compose to start one +* GraalVM installed if you want to run in native mode. + +== Architecture + +In this guide, we are going to generate (random) prices in one component. +These prices are written in an JMS queue (`prices`). +Another component reads from the `prices` queue and stores the last price. +The data can be fetch from a browser using a fetch button from a JAX-RS resource. + +== Solution + +We recommend that you follow the instructions in the next sections and create the application step by step. +However, you can go right to the completed example. + +Clone the Git repository: `git clone {quickstarts-clone-url}`, or download an {quickstarts-archive-url}[archive]. + +The solution is located in the `artemis-jms` {quickstarts-tree-url}/artemis-jms[directory]. + +== Creating the Maven Project + +First, we need a new project. Create a new project with the following command: + +[source, subs=attributes+] +---- +mvn io.quarkus:quarkus-maven-plugin:{quarkus-version}:create \ + -DprojectGroupId=org.acme \ + -DprojectArtifactId=artemis-jms \ + -Dextensions="artemis-jms" +---- + +This command generates a Maven project, importing the Artemis JMS extension. + +== Starting an Artemis server + +Then, we need an Artemis server. +You can follow the instructions from the https://activemq.apache.org/components/artemis/[Apache Artemis web site] or via docker: + +[source] +---- +docker run -it --rm -p 8161:8161 -p 61616:61616 -e ARTEMIS_USERNAME=quarkus -e ARTEMIS_PASSWORD=quarkus vromero/activemq-artemis:2.9.0-alpine +---- + +== The price producer + +Create the `src/main/java/org/acme/quarkus/sample/PriceProducer.java` file, with the following content: + +[source, java] +---- +package org.acme.artemis; + +import java.util.Random; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.event.Observes; +import javax.inject.Inject; +import javax.jms.ConnectionFactory; +import javax.jms.JMSContext; +import javax.jms.Session; + +import io.quarkus.runtime.ShutdownEvent; +import io.quarkus.runtime.StartupEvent; + +/** + * A bean producing random prices every 5 seconds and sending them to the prices JMS queue. + */ +@ApplicationScoped +public class PriceProducer implements Runnable { + + @Inject + ConnectionFactory connectionFactory; + + private final Random random = new Random(); + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + + void onStart(@Observes StartupEvent ev) { + scheduler.scheduleWithFixedDelay(this, 0L, 5L, TimeUnit.SECONDS); + } + + void onStop(@Observes ShutdownEvent ev) { + scheduler.shutdown(); + } + + @Override + public void run() { + try (JMSContext context = connectionFactory.createContext(Session.AUTO_ACKNOWLEDGE)) { + context.createProducer().send(context.createQueue("prices"), Integer.toString(random.nextInt(100))); + } + } +} +---- + +== The price consumer + +The price consumer reads the prices from JMS, and stores the last one. +Create the `src/main/java/org/acme/quarkus/sample/PriceConsumer.java` file with the following content: + +[source, java] +---- +package org.acme.artemis; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.event.Observes; +import javax.inject.Inject; +import javax.jms.ConnectionFactory; +import javax.jms.JMSConsumer; +import javax.jms.JMSContext; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Session; + +import io.quarkus.runtime.ShutdownEvent; +import io.quarkus.runtime.StartupEvent; + +/** + * A bean consuming prices from the JMS queue. + */ +@ApplicationScoped +public class PriceConsumer implements Runnable { + + @Inject + ConnectionFactory connectionFactory; + + private final ExecutorService scheduler = Executors.newSingleThreadExecutor(); + + private volatile String lastPrice; + + public String getLastPrice() { + return lastPrice; + } + + void onStart(@Observes StartupEvent ev) { + scheduler.submit(this); + } + + void onStop(@Observes ShutdownEvent ev) { + scheduler.shutdown(); + } + + @Override + public void run() { + try (JMSContext context = connectionFactory.createContext(Session.AUTO_ACKNOWLEDGE)) { + JMSConsumer consumer = context.createConsumer(context.createQueue("prices")); + while (true) { + Message message = consumer.receive(); + if (message == null) return; + lastPrice = message.getBody(String.class); + } + } catch (JMSException e) { + throw new RuntimeException(e); + } + } +} +---- + +== The price resource + +Finally, let's create a simple JAX-RS resource to show the last price. +Creates the `src/main/java/org/acme/quarkus/sample/PriceResource.java` file with the following content: + +[source, java] +---- +package org.acme.artemis; + +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/** + * A simple resource showing the last price. + */ +@Path("/prices") +public class PriceResource { + + @Inject + PriceConsumer consumer; + + @GET + @Path("last") + @Produces(MediaType.TEXT_PLAIN) + public String last() { + return consumer.getLastPrice(); + } +} +---- + +== Configuring the Artemis properties + +We need to configure the Artemis connection properties. +This is done in the `application.properties` file. + +[source] +---- +# Configures the Artemis properties. +quarkus.artemis.url=tcp://localhost:61616 +quarkus.artemis.username=quarkus +quarkus.artemis.password=quarkus +---- + +== The HTML page + +Final touch, the HTML page reading the converted prices using SSE. + +Create the `src/main/resources/META-INF/resources/prices.html` file, with the following content: + +[source, html] +---- + + +
+ +The last price is N/A €.
+