Today I wanted to create a Spring configured client / server application. The server listens on a configured queue for incoming messages. The client sends a message to the message queue which the server will display.

Configure the Gradle project structure

  • we start with a project name, let us choose spring-jms referenced as PROJECT_HOME. Open a terminal window or command prompt and create the directory “spring-jms”.
mkdir spring-jms
cd spring-jms
  • Create 3 submodules server, client and core.
mkdir server
mkdir client
mkdir core
  • Create a lib directory for libraries not allowed to be resolved from mavencentral. The JMS jar files are not allowed to be distributed via mavencentral, they are shipped with an installation of OpenMQ et al. We will use the lib directory in our gradle dependency configuration.
mkdir lib
  • Create a settings.gradle file with the following content, it includes our three submodules into our gradle project.
include 'core', 'server', 'client'
  • Create a build.gradle file containing configurations for all our (sub)projects. The project core is a dependency for the modules client and server as it defines the connection factory to the JMS server. It is not included in the this gradle configuration - otherwise it would be a dependency to itself.

Install and Start Oracle OpenMQ-5.1

  • Download the binaries for your operating system from mq.java.net
  • unpack the downloaded zip file to a directory, and export it as a variable OPENMQ_HOME.
  • start a message broker on port 7676 with name jms_test.
$OPENMQ_HOME/mq/bin/imqbrokerd -name jms_test -port 7676 > /tmp/imqbrokerd.out 2>&1 &
  • Now we need a Java Naming Directory. Create a directory jms and inside create a new directory jms_test. This directory will contain our JNDI Binding file holding the connection information to the JMS server.
mkdir -p jms/jms_test
Administration Console
  • Start the Administration Console
$OPENMQ_HOME/mq/bin/imqadmin
  • Create a new Broker jms_test in the Broker store with Host localhost and Port 7676.
  • Connect to the broker
  • Add a new Destination for importQueue and exportQueue with unlimited active Consumers.
  • Add a new Object Store ConnectionFactory.
  • Set Property java.naming.factory.initial to com.sun.jndi.fscontext.RefFSContextFactory.
  • Set Property java.naming.provider.url to file:<PROJECT_HOME>/jms/jms_test. This is where the .bindings file was written by imqadmin.
  • Set Property java.naming.security.principal to guest.
  • Set Property java.naming.security.credentials to guest.
  • Add a Connection Factory with Lookup-Name ConnectionFactory of Factory-Typ Connection Factory.
  • Click through the tabs and change user, password, JMSX properties, Connection Type, Host, Port and so on.
Copy JMS Jar files
  • change to $OPENMQ_HOME/mq/lib
  • copy fscontext.jar, imq.jar, jms.jar into <PROJECT_HOME>/lib directory.

The “core” Module

The core module contains only a JndiConfiguration class. The JndiConfiguration provides a ConnectionFactory based on the properties of default.properties file from the dependents. The JNDI Environment will setup the JMS Connection and the required importQueue. As both, the server and client need to access the JMS Server they will share this configuration.

  • Change into the core directory and create a java package directory.
cd core
mkdir -p src/main/java/com/schremser/spring/jms/core

In this case com.schremser.spring.jms.core is the package name for the JndiConfiguration class. The @Configuration uses the default.properties file to inject values for the @Value annotated class variables. The property jms.connection.factory reuses the configured JNDI Connection Lookup-Name ConnectionFactory of the Object Store. jms.queue.import creates an object of type Destination which is in our case importQueue. The JndiConfiguration class exposes our beans annotated with @Bean annotation to our application.

  • Create a new Java Class JndiConfiguration That’s it, well done.

The “server” Module

The server module is a submodule, that spawns a server for listening on a configured Queue (importQueue) for new messages. The JmsApplication, which is our server, exposes one bean, the queueMessageListener which reuses the JndiConfiguration from the core module. The Configuration gives access to the connectionFactory and the importQueue beans, that hold the objects for communication. Once the listener bean is started it will process each message in the queue using the customized queueMessageReceiver bean. The receiver has a little job, it logs the message to our logback configuration.

  • Change into the server directory and create a java package directory.
cd server
mkdir -p src/main/java/com/schremser/spring/jms/server

In this case com.schremser.spring.jms.server is the package name for the JmsServer class. The @Configuration JndiConfiguration is @Autowired to the Spring Boot Application.

  • Create a new build.gradle file, declaring module core as a dependency and adding the application plugin with main class JmsServer.

  • The JmsServer class starts the beans of the spring context in order to run(). The server starts the messageListener on the configured importQueue using the connectionFactory. The connectionFactory needs a default.properties file to lookup the JNDI Object. So let’s create default.properties file first:

cd server
mkdir -p src/main/resources

Within the resources directory create a default.properties file. To see how your JMS Server is secured take a look into your products documentation.

And the JmsServer class, it starts the message listener on the configured Destination queue using the connection factory.

  • Start your JmsServer using gradle’s run task.
gradle -q server:run

The “client” Module

The client module is a submodule, that reads your message from standard input and adds it to the queue. You can put messages into the queues without a server being started. Out JMS Server application will read the messages from the queue and process them in their order. The JmsClient sends messages using Spring’s JmsTemplate helper class to send messages to the queue.

  • Change into the client directory and create a java package directory.
cd server
mkdir -p src/main/java/com/schremser/spring/jms/client

In this case com.schremser.spring.jms.client is the package name for the JmsClient class. The @Configuration JndiConfiguration is @Autowired to the Spring Boot Application, just as in the server module.

  • Create a new build.gradle file, declaring module core as a dependency and adding the application plugin with main class JmsClient. Change gradle’s standardInput property for the run task to be able to read the messages from standard input.

  • The JmsClient class starts the beans of the spring context in order to run(). The client uses the JmsTemplate helper class from the spring framework. The connectionFactory needs a default.properties file to lookup the JNDI Object. So let’s create default.properties file first:

cd client
mkdir -p src/main/resources

Within the resources directory create a default.properties file.

  • The JmsClient class.

  • Start your JmsClient using gradle’s run task.

gradle -q client:run

The whole project is hosted under GitHub

Additional Documentation:


Maximilian Schremser

Survivalist, Developer, Naturalist