Resin 4 Java EE Java Application Server JMS Support Tutorial
From Resin 4.0 Wiki
Contents
|
JMS Tutorials
JMS Listener with EJB message bean
Introduces receiving a message using an EJB message bean.
Files in this tutorial
File | Description |
---|---|
WEB-INF/web.xml |
Configures the Queue, MessageSender, MessageListener. |
WEB-INF/classes/example/MyListener.java |
The message listener. |
WEB-INF/classes/example/MessageServlet.java |
The message servlet |
Overview
Messaging decouples a sending task from a receiving/processing task, allowing for batch processing or load balancing of tasks to another machine. The original task can respond immediately to the user without waiting for the task complete. The servlet creates a message and sends it to a queue. The servlet immediately completes and when the batch process is ready, it processes the message.
Messaging is therefore comprised of three main components:
- A Producer creates messages and sends them to a Queue. The Producer could be something like a Servlet.
- A Queue stores the messages from the Produces and provides them to a Consumer when ready. The Queue is implemented by the messaging provider.
- A Consumer processes messages as they become
available in the Queue. The Consumer is typically a bean
implementing the
MessageListener
interface.
Producer (MessageServlet)
In this example, the Producer is a Servlet which sends a simple message.
To simplify the example, we'll use the BlockingQueue
API instead
of the JMS producers. The functionality is the same without the extra
housekeeping of the JMS API.
The servlet uses [../../doc/resin-ioc.xtp CDI]
dependency injection to get the BlockingQueue
. The
dependency injection cleans the code by decoupling it from the implementation.
For example, the actual BlockingQueue
could be facade around
another JMS implementation's queue.
Example: MessageServlet
import javax.inject.Inject; import java.util.concurrent.BlockingQueue; public class MessageServlet extends GenericServlet { @Inject BlockingQueue _sender; ... String message = "sample message"; _sender.put(message); }
In this configuration, the BlockingQueue
is a
java.util.concurrent.BlockingQueue
. It's also possible
to use the full JMS MessageProducer
which is more verbose.
The put
method completes as soon as
the message is stored in the queue. Later, when a thread is available, the
Queue will send the message to the Consumer.
Consumer (MyListener)
The Queue delivers messages to the Consumer at the consumer's rate. When the Consumer finishes processing a message the Queue will deliver the next available message.
The Consumer implements javax.jms.MessageListener
, and
will therefore be identical code in any application server. The
Consumer might even be on a different server or use a different
application server.
In this example, the Consumer just logs the message, but more realistic applications might use Java Persistence to store results in a database. The listener instance has full access to Resin-IoC capabilities, including dependency injection, standard aspects like @TransactionAttribute, interceptors, and WebBeans event processing.
Example: MyListener.java implementation
package example; import java.util.logging.Logger; import java.util.logging.Level; import javax.jms.Message; import javax.jms.TextMessage; import javax.jms.MessageListener; public class MyListener implements MessageListener { private static final Logger log = Logger.getLogger(MyListener.class.getName()); public void onMessage(Message message) { try { ObjectMessage objMessage = (ObjectMessage) message; log.info("received: " + objMessage.getValue()); _lastMessage = textMessage.getValue(); } catch (Exception e) { log.log(Level.WARNING, e.toString(), e); } } }
Configuration
Since Resin is an inversion of control container (IoC), it can configure the JMS resources in the standard Resin configuration file. The [../../doc/resin-ioc.xtp Resin IoC] documentation gives more information.
The configuration is responsible for three things:
- Configuring the Queue
- Configuring the MessageListener
The Queue
is configured directly in a <resin:FileQueue>
tag, together with any configuration setters. This example uses a
local file store.
Because the listener and sender need a reference to the queue, the jms-queue stores it in the "my_queue" variable.
Example: Queue configuration in WEB-INF/resin-web.xml
<web-app xmlns="http://caucho.com/ns/resin" xmlns:ee="urn:java:ee" xmlns:resin="urn:java:com.caucho.resin"> <resin:FileQueue ee:Named="my_queue"> <path>WEB-INF/db</path> </resin:FileQueue> </web-app>
JMS also needs a configured ConnectionFactory, so the sender and listener can create JMS connections.
Example: ConnectionFactory in resin-web.xml
<web-app xmlns="http://caucho.com/ns/resin" xmlns:resin="urn:java:com.caucho.resin"> <resin:JmsConnectionFactory/> </web-app>
The MessageListener is configured as an EJB message bean. Resin's EJB support instantiates the listeners and receives messages from the queue.
Example: message bean configuration resin-web.xml
<web-app xmlns="http://caucho.com/ns/resin"> <resin:FileQueue ee:Named="my_queue"> <path>WEB-INF/db</path> </resin:FileQueue> <ejb-message-bean class="example.MyListener"> <destination>${my_queue}</destination> </ejb-message-bean> </web-app>
JMS Messaging in Quercus - Sending messages
Files in this tutorial
File | Description |
---|---|
WEB-INF/resin-web.xml |
resin-web.xml configuration |
WEB-INF/classes/META-INF/beans.xml |
Java Injection marker file to start bean scanning |
send-message.php |
PHP script sending the message. |
WEB-INF/classes/example/MyListener.java |
Java message bean listener receiving the message. |
WEB-INF/classes/example/MessageStore.java |
Singleton service bean storing the received messages. |
Using JMS in Quercus
Quercus offers a simplified messaging interface built upon JMS. This functionality makes it possible to send and receive messages using either the Resin JMS implementation or any other messaging service with a JMS implementation. Many features of JMS are designed for message-driven services which make sense in the Java world, but are not appropriate for PHP. This tutorial focuses on sending messages.
Sending JMS messages from a PHP script
In this example, the script checks a POST variable "message" and if it is set, sends the value of that variable to a JMS queue. A Message Driven Bean (MDB) receives these messages and records them. The record is displayed by a servlet.
Example: PHP sending script
<?php if (isset($_POST["message"])) { $queue = java_bean("Queue"); if (! $queue) { echo "Unable to get message queue!\n"; } else { if ($queue->offer($_POST["message"]) == TRUE) { echo "Successfully sent message '" . $_POST["message"] . "'"; } else { echo "Unable to send message '" . $_POST["message"] . "'"; } } } ?>
The programming model of the Quercus JMS interface is first to
get access to the queue using the java_bean()
call.
java_bean
will look for the named bean in the
resin-web.xml, in this case our queue. Since the Queue implements
the java.util.concurrent.BlockingQueue
API, the PHP script
can send data to the queue directly using offer()
and
receive messages with poll()
.
Configuring JMS for PHP and Java
JMS requires two resources: A Queue
and a
ConnectionFactory
. Both are
configured in WEB-INF/resin-web.xml
.
The ConnectionFactory
is used to connect to all the
Queue
s and only one of them needs to be set up.
MemoryQueue configuration
The example uses the queue named Queue
.
Example: Queue configuration in resin-web.xml
<web-app xmlns="http://caucho.com/ns/resin" xmlns:resin="urn:java:com.caucho.resin"> <jms:MemoryQueue> <Named>Queue</Named> </jms:MemoryQueue> </web-app>
ConnectionFactory configuration
Example: ConnectionFactory configuration in resin-web.xml
<web-app xmlns="http://caucho.com/ns/resin" xmlns:resin="urn:java:com.caucho.resin"> <resin:JmsConnectionFactory/> </web-app>
The complete configuration is in
WEB-INF/resin-web.xml
.
Message Bean configuration
Example: MyListener configuration in resin-web.xml
<web-app xmlns="http://caucho.com/ns/resin" xmlns:resin="urn:java:com.caucho.resin"> <ejb-message-bean class="example.MyListener"> <destination>#{Queue}</destination> </ejb-message-bean> </web-app>
JMS Messaging in Quercus - Receiving messages
Files in this tutorial
File | Description |
---|---|
WEB-INF/resin-web.xml |
resin-web.xml configuration |
display-ad.php |
PHP script displaying the advertisement. |
WEB-INF/classes/example/AdProducer.java |
Java listener that fills the advertisement queue. |
Using JMS in Quercus
Quercus offers a simplified messaging interface built upon JMS. This functionality makes it possible to send and receive messages using either the Resin JMS implementation or any other messaging service with a JMS implementation. Many features of JMS are designed for message-driven services which make sense in the Java world, but are not appropriate for PHP. This tutorial focuses receiving messages in a non-blocking way.
Receiving JMS messages from a PHP script
This example uses two queues: an "ad queue" and a "control queue".
The PHP script removes advertisements from the ad queue using the
poll()
method. This method is non-blocking -
if there are no advertisements, the method will return FALSE
instead of waiting for a new advertisement. Whenever the PHP script
removes an advertisement from the ad queue, it signals a Java message
driven bean (MDB) to add another ad by sending an empty message to the
control queue.
==
$ad_queue = java_bean("AdQueue"); $control_queue = java_bean("ControlQueue"); if (! $ad_queue) { echo "Unable to get ad queue!\n"; } elseif (! $control_queue) { echo "Unable to get control queue!\n"; } else { $ad = $ad_queue->poll(); if ($ad == null) { echo "No ads available on the queue\n"; } else { echo "$ad"; } if (! $control_queue->offer(0)) { echo "Unable to send control message\n"; } }
The programming model of the Quercus JMS interface is first to
get access to the queue using java_bean
to get the
named queue. To create a JMSQueue
object, pass in
the name of the JMS queue to be used. Since the JMS Queue implements
the BlockingQueue
API, the PHP script can use
offer()
and poll()
. The example above shows
how to use both methods.
Configuring JMS for PHP and Java
JMS requires that two resources be set up: A
ConnectionFactory
and a Queue
. Both are
configured in WEB-INF/resin-web.xml
.
The ConnectionFactory
is used to connect to all the
Queue
s and only one of them needs to be set up.
Example: connection factory configuration in resin-web.xml
<web-app xmlns="http://caucho.com/ns/resin"> <jms-connection-factory uri="resin:"/> </web-app>
This example uses two queues, AdQueue
and
ControlQueue
.
Example: Queue configuration in resin-web.xml
<web-app xmlns="http://caucho.com/ns/resin"> <jms-queue name="AdQueue" uri="memory:"/> <jms-queue name="ControlQueue" uri="memory:"/> </web-app>
The complete configuration is in WEB-INF/resin-web.xml
.