diff --git a/README.md b/README.md
index 5e74249c..6bc51ba9 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,7 @@ Java EE samples:
- Websocket
- REST service over HTTPS
- Logging with JUL and KumuluzEE
+- JMS
KumuluzEE extensions - samples:
- KumuluzEE Config
diff --git a/jms/README.md b/jms/README.md
new file mode 100644
index 00000000..dd462789
--- /dev/null
+++ b/jms/README.md
@@ -0,0 +1,335 @@
+# KumuluzEE JMS ActiveMQ sample
+
+> Develop a basic JMS client within a REST service and pack it as a KumuluzEE microservice.
+
+The objective of this sample is to demonstrate how to use KumuluzEE JMS module. The tutorial guides you through the development of a simple JMS client and will show how to send an object to a queue and how to retrieve it. The methods that will send and receive messages will be exposed via a REST service. Required knowledge: basic familiarity with JMS and basic concepts of REST and JSON.
+
+## Requirements
+
+In order to run this example you will need the following:
+
+1. Java 8 (or newer), you can use any implementation:
+ * If you have installed Java, you can check the version by typing the following in a command line:
+
+ ```
+ java -version
+ ```
+
+2. Maven 3.2.1 (or newer):
+ * If you have installed Maven, you can check the version by typing the following in a command line:
+
+ ```
+ mvn -version
+ ```
+3. Git:
+ * If you have installed Git, you can check the version by typing the following in a command line:
+
+ ```
+ git --version
+ ```
+4. ActiveMQ:
+ * ActiveMQ can be downloaded on the following
+ [link](http://activemq.apache.org/download.html)
+
+
+## Prerequisites
+
+This sample does not contain any prerequisites and can be started on its own.
+
+## Usage
+
+This sample uses ActiveMQ implementation of JMS.
+
+1. Run ActiveMQ
+* Unix/Linux:
+ ```bash
+ $ cd path_to_activemq/bin
+ $ activemq start
+ ```
+* Windows:
+ ```batch
+ cd "path_to_activemq\bin"
+ activemq start
+ ```
+Default location for ActiveMQ console should be http://localhost:8161/admin
+
+2. The example uses maven to build and run the microservice. Build the sample using maven:
+
+ ```bash
+ $ cd jms
+ $ mvn clean package
+ ```
+
+3. Run the sample:
+* Uber-jar:
+
+ ```bash
+ $ java -jar target/${project.build.finalName}.jar
+ ```
+
+ in Windows environemnt use the command
+ ```batch
+ java -jar target/${project.build.finalName}.jar
+ ```
+
+* Exploded:
+
+ ```bash
+ $ java -cp target/classes:target/dependency/* com.kumuluz.ee.EeApplication
+ ```
+
+ in Windows environment use the command
+ ```batch
+ java -cp target/classes;target/dependency/* com.kumuluz.ee.EeApplication
+ ```
+
+
+The application/service can be accessed on the following URL:
+* JAX-RS REST resource - http://localhost:8080/v1/customers
+
+
+To shut down the example simply stop the processes in the foreground.
+
+## Tutorial
+
+This tutorial will guide you through the steps required to create a simple JMS client using ActiveMQ and pack it as a KumuluzEE microservice.
+We will develop a simple Customer REST service with the following resources:
+* GET http://localhost:8080/v1/customers – get customer from ActiveMQ
+* POST http://localhost:8080/v1/customers – add a customer to ActiveMQ
+
+We will follow these steps:
+* Create a Maven project in the IDE of your choice (Eclipse, IntelliJ, etc.)
+* Add Maven dependencies to KumuluzEE and include KumuluzEE components (Core, JMS and JAX-RS)
+* Implement the JMS client
+* Implement the service using standard JAX-RS 2 API
+* Build the microservice
+* Run it
+
+### Add Maven dependencies
+
+Add the KumuluzEE BOM module dependency to your `pom.xml` file:
+```xml
+
+
+
+ com.kumuluz.ee
+ kumuluzee-bom
+ ${kumuluz.version}
+ pom
+ import
+
+
+
+```
+
+Add the `kumuluzee-core`, `kumuluzee-servlet-jetty`, `kumuluzee-jax-rs-jersey` and `kumuluzee-jms-activemq` dependencies:
+```xml
+
+
+ com.kumuluz.ee
+ kumuluzee-core
+
+
+ com.kumuluz.ee
+ kumuluzee-servlet-jetty
+
+
+ com.kumuluz.ee
+ kumuluzee-jax-rs-jersey
+
+
+ com.kumuluz.ee
+ kumuluzee-jms-activemq
+
+
+```
+
+Add the `kumuluzee-maven-plugin` build plugin to package microservice as uber-jar:
+
+```xml
+
+
+
+ com.kumuluz.ee
+ kumuluzee-maven-plugin
+ ${kumuluzee.version}
+
+
+ package
+
+ repackage
+
+
+
+
+
+
+```
+
+or exploded:
+
+Add the `kumuluzee-maven-plugin` build plugin to package microservice as exploded:
+
+```xml
+
+
+
+ com.kumuluz.ee
+ kumuluzee-maven-plugin
+ ${kumuluzee.version}
+
+
+ package
+
+ copy-dependencies
+
+
+
+
+
+
+```
+
+### Implement the REST service
+
+Register your module as JAX-RS service and define the application path. You could do that in web.xml or for example with `@ApplicationPath` annotation:
+
+```java
+@ApplicationPath("v1")
+public class CustomerApplication extends Application {
+}
+```
+
+Implement JAX-RS resource, for example, to implement resource `customers`. The POST method is going to send the input customer directly to JMS queue while the GET method is going to retrieve the next pending `Customer` object from queue:
+
+```java
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Path("customers")
+public class CustomerResource {
+
+ @POST
+ public Response addCustomerToQueue(Customer customer) {
+ QueueHandler.addToQueue(customer);
+ return Response.noContent().build();
+ }
+
+ @GET
+ public Response readCustomerFromQueue() {
+ Customer customer = QueueHandler.readFromQueue();
+ return customer != null
+ ? Response.ok(customer).build()
+ : Response.noContent().build();
+ }
+}
+```
+
+Implement the `Customer` Java class, which is a POJO. The class must implement the Serializable interface so we can send this object directly in queue:
+```java
+public class Customer implements Serializable {
+
+ private String id;
+
+ private String firstName;
+
+ private String lastName;
+
+ // TODO: implement get and set methods
+}
+```
+
+The JMS client logic will be implemented in `QueueHandler`. A sample implementation of this client, can be implemented as follows:
+
+```java
+public class QueueHandler {
+
+ private static Logger LOG = Logger.getLogger(QueueHandler.class.getName());
+
+ private static String url = ActiveMQConnection.DEFAULT_BROKER_URL;
+
+ private static String queueName = "KUMULUZ_QUEUE";
+
+ private static int timeout = 1000;
+
+ public static void addToQueue(Customer customer) {
+
+ // Create connection factory and allow all packages for test purpose
+ ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
+ // Not recommended to trust all packages, only use for testing purposes
+ connectionFactory.setTrustAllPackages(true);
+ Connection connection;
+
+ try {
+ // Create connection
+ connection = connectionFactory.createConnection();
+ connection.start();
+
+ // create session and producer
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Destination destination = session.createQueue(queueName);
+ MessageProducer producer = session.createProducer(destination);
+
+ // Create an serializable object to send to queue
+ ObjectMessage msg = session.createObjectMessage();
+ msg.setObject(customer);
+ msg.setJMSType(Customer.class.getName());
+
+ // Sending to queue
+ producer.send(msg);
+
+ connection.close();
+ } catch (JMSException e) {
+ LOG.log(Level.SEVERE ,"JMS threw an error.", e);
+ }
+
+ }
+
+ public static Customer readFromQueue() {
+
+ // Create connection factory and allow all packages for test purpose
+ ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
+ // Not recommended to trust all packages, only use for testing purposes
+ connectionFactory.setTrustAllPackages(true);
+ Connection connection;
+
+ Customer customer = null;
+
+ try {
+ // Create connection
+ connection = connectionFactory.createConnection();
+ connection.start();
+
+ // create session and consumer
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Destination destination = session.createQueue(queueName);
+ MessageConsumer consumer = session.createConsumer(destination);
+
+ // retrieve message
+ Message message = consumer.receive(timeout);
+
+ // check if correct type and cast message to Customer
+ if (message instanceof ObjectMessage && Customer.class.getName().equals(message.getJMSType())) {
+ ObjectMessage msg = (ObjectMessage) message;
+ customer = (Customer) msg.getObject();
+ } else if (message == null) {
+ LOG.log(Level.INFO ,"Queue " + queueName +" is empty.");
+ } else {
+ LOG.log(Level.INFO ,"Message was not the right type.");
+ }
+
+ connection.close();
+ } catch (JMSException e) {
+ LOG.log(Level.SEVERE ,"JMS threw an error.", e);
+ }
+
+ return customer;
+ }
+}
+```
+
+Method `addToQueue` takes the input customer object and sends it to queue while the `readFromQueue` read the next pending object from queue.
+
+
+### Build the microservice and run it
+
+To build the microservice and run the example, use the commands as described in previous sections.
diff --git a/jms/pom.xml b/jms/pom.xml
new file mode 100644
index 00000000..74e1a865
--- /dev/null
+++ b/jms/pom.xml
@@ -0,0 +1,68 @@
+
+
+
+ kumuluzee-samples
+ com.kumuluz.ee.samples
+ 2.5.0-SNAPSHOT
+
+ 4.0.0
+
+ jms
+
+ KumuluzEE JMS sample
+ JMS usage sample with KumuluzEE
+
+
+
+
+ com.kumuluz.ee
+ kumuluzee-bom
+ ${kumuluzee.version}
+ pom
+ import
+
+
+
+
+
+
+ com.kumuluz.ee
+ kumuluzee-core
+
+
+ com.kumuluz.ee
+ kumuluzee-servlet-jetty
+
+
+
+ com.kumuluz.ee
+ kumuluzee-jax-rs-jersey
+
+
+
+ com.kumuluz.ee
+ kumuluzee-jms-activemq
+
+
+
+
+
+
+ com.kumuluz.ee
+ kumuluzee-maven-plugin
+ ${kumuluzee.version}
+
+
+ package
+
+ repackage
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jms/src/main/java/com/kumuluz/ee/samples/jms/Customer.java b/jms/src/main/java/com/kumuluz/ee/samples/jms/Customer.java
new file mode 100644
index 00000000..716c4df5
--- /dev/null
+++ b/jms/src/main/java/com/kumuluz/ee/samples/jms/Customer.java
@@ -0,0 +1,39 @@
+package com.kumuluz.ee.samples.jms;
+
+import java.io.Serializable;
+
+/**
+ * @author Dejan Ognjenović
+ * @since 2.4.0
+ */
+public class Customer implements Serializable {
+
+ private String id;
+
+ private String firstName;
+
+ private String lastName;
+
+ public String getId() { return id; }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+}
diff --git a/jms/src/main/java/com/kumuluz/ee/samples/jms/CustomerApplication.java b/jms/src/main/java/com/kumuluz/ee/samples/jms/CustomerApplication.java
new file mode 100644
index 00000000..d8b221af
--- /dev/null
+++ b/jms/src/main/java/com/kumuluz/ee/samples/jms/CustomerApplication.java
@@ -0,0 +1,12 @@
+package com.kumuluz.ee.samples.jms;
+
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.core.Application;
+
+/**
+ * @author Dejan Ognjenović
+ * @since 2.4.0
+ */
+@ApplicationPath("v1")
+public class CustomerApplication extends Application {
+}
\ No newline at end of file
diff --git a/jms/src/main/java/com/kumuluz/ee/samples/jms/CustomerResource.java b/jms/src/main/java/com/kumuluz/ee/samples/jms/CustomerResource.java
new file mode 100644
index 00000000..44242a8c
--- /dev/null
+++ b/jms/src/main/java/com/kumuluz/ee/samples/jms/CustomerResource.java
@@ -0,0 +1,32 @@
+package com.kumuluz.ee.samples.jms;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+/**
+ * @author Dejan Ognjenović
+ * @since 2.4.0
+ */
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Path("customers")
+public class CustomerResource {
+
+ @POST
+ public Response addCustomerToQueue(Customer customer) {
+ QueueHandler.addToQueue(customer);
+ return Response.noContent().build();
+ }
+
+ @GET
+ public Response readCustomerFromQueue() {
+ Customer customer = QueueHandler.readFromQueue();
+ return customer != null
+ ? Response.ok(customer).build()
+ : Response.noContent().build();
+ }
+
+}
+
diff --git a/jms/src/main/java/com/kumuluz/ee/samples/jms/QueueHandler.java b/jms/src/main/java/com/kumuluz/ee/samples/jms/QueueHandler.java
new file mode 100644
index 00000000..4094ab39
--- /dev/null
+++ b/jms/src/main/java/com/kumuluz/ee/samples/jms/QueueHandler.java
@@ -0,0 +1,99 @@
+package com.kumuluz.ee.samples.jms;
+
+import org.apache.activemq.ActiveMQConnection;
+import org.apache.activemq.ActiveMQConnectionFactory;
+
+import javax.jms.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author Dejan Ognjenović
+ * @since 2.4.0
+ */
+public class QueueHandler {
+
+ private static Logger LOG = Logger.getLogger(QueueHandler.class.getName());
+
+ private static String url = ActiveMQConnection.DEFAULT_BROKER_URL;
+
+ private static String queueName = "KUMULUZ_QUEUE";
+
+ private static int timeout = 1000;
+
+ public static void addToQueue(Customer customer) {
+
+ // Create connection factory and allow all packages for test purpose
+ ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
+ // Not recommended to trust all packages, only use for testing purposes
+ connectionFactory.setTrustAllPackages(true);
+ Connection connection;
+
+ try {
+ // Create connection
+ connection = connectionFactory.createConnection();
+ connection.start();
+
+ // create session and producer
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Destination destination = session.createQueue(queueName);
+ MessageProducer producer = session.createProducer(destination);
+
+ // Create an serializable object to send to queue
+ ObjectMessage msg = session.createObjectMessage();
+ msg.setObject(customer);
+ msg.setJMSType(Customer.class.getName());
+
+ // Sending to queue
+ producer.send(msg);
+
+ connection.close();
+ } catch (JMSException e) {
+ LOG.log(Level.SEVERE ,"JMS threw an error.", e);
+ }
+
+ }
+
+ public static Customer readFromQueue() {
+
+ // Create connection factory and allow all packages for test purpose
+ ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
+ // Not recommended to trust all packages, only use for testing purposes
+ connectionFactory.setTrustAllPackages(true);
+ Connection connection;
+
+ Customer customer = null;
+
+ try {
+ // Create connection
+ connection = connectionFactory.createConnection();
+ connection.start();
+
+ // create session and consumer
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Destination destination = session.createQueue(queueName);
+ MessageConsumer consumer = session.createConsumer(destination);
+
+ // retrieve message
+ Message message = consumer.receive(timeout);
+
+ // check if correct type and cast message to Customer
+ if (message instanceof ObjectMessage && Customer.class.getName().equals(message.getJMSType())) {
+ ObjectMessage msg = (ObjectMessage) message;
+ customer = (Customer) msg.getObject();
+ } else if (message == null) {
+ LOG.log(Level.INFO ,"Queue " + queueName +" is empty.");
+ } else {
+ LOG.log(Level.INFO ,"Message was not the right type.");
+ }
+
+ connection.close();
+ } catch (JMSException e) {
+ LOG.log(Level.SEVERE ,"JMS threw an error.", e);
+ }
+
+ return customer;
+ }
+}
diff --git a/jms/src/main/resources/webapp/WEB-INF/web.xml b/jms/src/main/resources/webapp/WEB-INF/web.xml
new file mode 100644
index 00000000..0e4d4db2
--- /dev/null
+++ b/jms/src/main/resources/webapp/WEB-INF/web.xml
@@ -0,0 +1,5 @@
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 5002c13e..7179bfd8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,6 +16,7 @@
jsf
jsp
jul
+ jms
kumuluzee-config
kumuluzee-config-mp
kumuluzee-config-consul
@@ -41,6 +42,7 @@
kumuluzee-microProfile-1.2
kumuluzee-blog-samples
kumuluzee-reactive-vertx
+ jms
pom