Integrating with ActiveMQ

For using ActiveMQ queues and topics with Jetty, you have two choices:

  1. Use queues and topics directly from javascript on the client browser (Ajax)
  2. Traditional server-side jms api calls

ActiveMQ with Ajax and Jetty

Due to some clever integration, you can use queues and topics directly in your client side javascript very easily and simply.

Here's an example of sending a message to a queue:

 amq.sendMessage('channel://MY.DEMO', "<message item='hello'/>");

Here's an example of setting up to receive messages from a queue. All you need do is to add a listener with a unique id, the name of the queue or topic from which you want to receive messages, and the name of a function which will be called back when a message is available.


var myHandler = 
{  
  rcvMessage: function(message) 
  {
     alert("received "+message);
  }
};

 amq.addListener(myId, 'channel://MY.DEMO', myHandler.rcvMessage);

Here's the plumbing you need to take advantage of this very convenient feature:

    <script type="text/javascript" src="amq/amq.js"></script>
    <script type="text/javascript">amq.uri='amq';</script>
    <context-param>
        <param-name>org.apache.activemq.brokerURL</param-name>
        <param-value>vm://localhost</param-value>
        <description>The URL of the Message Broker to connect to</description>
    </context-param>

    <context-param>
        <param-name>org.apache.activemq.embeddedBroker</param-name>
        <param-value>true</param-value>
        <description>Whether we should include an embedded broker or not</description>
    </context-param>

    <servlet>
      <servlet-name>AjaxServlet</servlet-name>
      <servlet-class>org.apache.activemq.web.AjaxServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>AjaxServlet</servlet-name>
        <url-pattern>/amq/*</url-pattern>
    </servlet-mapping>

    <filter>
      <filter-name>session</filter-name>
      <filter-class>org.apache.activemq.web.SessionFilter</filter-class>
    </filter>

    <filter-mapping>
      <filter-name>session</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>

    <dependency>
      <groupId>incubator-activemq</groupId>
      <artifactId>activemq-web</artifactId>
      <exclusions>
        <exclusion>
          <artifactId>commons-logging</artifactId>
          <groupId>commons-logging</groupId>
        </exclusion>
        <exclusion>
          <artifactId>org.mortbay.jetty</artifactId>
          <groupId>jetty-util</groupId>
        </exclusion>
        <exclusion>
          <artifactId>mx4j</artifactId>
          <groupId>mx4j</groupId>
        </exclusion>
      </exclusions>
    </dependency>

You will also need to make sure that jcl104-over-slf4j-1.0.1.jar and an slf4j log implementation jar are available at runtime, as ActiveMQ uses commons logging. You can move these jars out of $JETTY-HOME/lib/jsp-2.0 and into $JETTY-HOME/lib to make them generally available on the classpath.

This ActiveMQ Ajax mechanism is based on Jetty's Continuations mechanism and thus in fact works most efficiently when deployed on Jetty, however the same webapp will also run unaltered on other containers.

There is more information on available on ActiveMQ in general and the Ajax mechanism in particular.

ActiveMQ with JNDI lookups from Servlets

You can use ActiveMQ queues and topics in the traditional manner from Servlet code with Jetty. Firstly, if you are not familiar with how JNDI resources are configured with Jetty, take a look at the JNDI Feature page.

Now lets look at the steps you need to perform to be able to access queues and topics:

<New id="cf" class="org.mortbay.jetty.plus.naming.Resource">
  <Arg>jms/connectionFactory</Arg>
  <Arg>
    <New class="org.apache.activemq.ActiveMQConnectionFactory">
       <Arg>vm://localhost?broker.persistent=false</Arg>
    </New>
  </Arg>
</New>

Here's an example of a Queue:

<New id="myQueue"  class="org.mortbay.jetty.plus.naming.Resource">
  <Arg>jms/myQueue</Arg>
  <Arg>
    <New class="org.apache.activemq.command.ActiveMQQueue">
      <Arg>DEMO</Arg>
    </New>
  </Arg>
</New>
<!-- JMS  connection factory ref -->
<resource-ref>
  <description>Connection Factory</description>
  <res-ref-name>jms/connectionFactory</res-ref-name>
  <res-type>javax.jms.QueueConnectionFactory</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

<!-- Queue ref -->
<resource-env-ref>
  <resource-env-ref-name>jms/myQueue</resource-env-ref-name>
  <resource-env-ref-type>javax.jms.Queue</resource-env-ref-type>
</resource-env-ref>

    private QueueConnectionFactory connectionFactory;
    private Queue myQueue;

    public void init(ServletConfig config) throws ServletException
    {
        super.init(config);
        try
        {
            InitialContext ic = new InitialContext();
            connectionFactory = (QueueConnectionFactory)ic.lookup("java:comp/env/jms/connectionFactory");
            myQueue = (Queue)ic.lookup("java:comp/env/jms/myQueue");
        }
        catch (Exception e)
        {
          e.printStackTrace();
            throw new ServletException(e);
        }
    }
.
.
.
    public void sendMessage(String msg)
    throws Exception
    {
        QueueConnection connection = null;
        QueueSession session = null;
        MessageProducer producer = null;
        try
        {
          connection = connectionFactory.createQueueConnection();
          session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
          producer = session.createProducer(myQueue);
          TextMessage message = session.createTextMessage(msg);
          producer.send(message);
        }
        finally
        {
          try
          {
            if (producer!=null)producer.close();
            if (session!=null)session.close();
            if (connection!=null)connection.close();
          }
          catch (Exception e)
          {
            e.printStackTrace();
          }
        }
    }
java -jar start.jar etc/jetty.xml etc/jetty-plus.xml

You're done!