Resin 4 Java EE Java Application Server JMS Support Tutorial

From Resin 4.0 Wiki

Revision as of 17:00, 15 June 2012 by Rick (Talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

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 Queues 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 Queues 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.

Personal tools
TOOLBOX
LANGUAGES