Showing posts with label JMS. Show all posts
Showing posts with label JMS. Show all posts
In the How to either publish or consume message using STOMP in ActiveMQ entry i talked about how to use STOMP protocol for both publishing and consuming messages. I wanted to check if i can mix JMS + STOMP together, so i changed the sample application to use JMS API for publishing a message and use the STOMP for consuming messages, this works because no matter which API you use for communicating with the broker the message gets stored in the same messaging provider same this while consuming messages. You can download the sample code from here First configure your ActiveMQ so that it supports both JMS and STOMP connectors like this

<transportConnectors>
 <transportConnector name="openwire" uri="tcp://localhost:61616?trace=true"/>
 <transportConnector name="stomp" uri="stomp://localhost:61613?trace=true"/>
</transportConnectors>
Then create a jndi.properties file that defines the ConnectionFactory and Queue in the JNDI context for your application like this

java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
java.naming.provider.url = tcp://localhost:61616
java.naming.security.principal=system
java.naming.security.credentials=manager
connectionFactoryNames = QueueCF
queue.stomptest=stomptest
This jndi.properties file makes sure that the objects of ConnectionFactory and Queue and bound in the JNDI context so that your java code remains JMS compliant with no reference to ActiveMQ. Then create OpenWireMessagePublisher.java like this

package com.webspherenotes.stomp;

import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class OpenWireMessagePublisher {
  public static void main(String[] argv){
    try {
      InitialContext context = new InitialContext();
      QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory)context.lookup("QueueCF");
      QueueConnection queueConnection = queueConnectionFactory.createQueueConnection();
      QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
      Queue queue = (Queue)context.lookup("stomptest");
      TextMessage textMessage = queueSession.createTextMessage();
      textMessage.setText("This is sample message for stomp queue");
      QueueSender queueSender = queueSession.createSender(queue);
      queueSender.send(textMessage);
      queueConnection.close();
    } catch (NamingException e) {
      e.printStackTrace();
    } catch (JMSException e) {
      e.printStackTrace();
    }
  }
}
The OpenWireMessagePublisher.java is using JMS API to publish a message to stomptest queue. Now lets create a StompMessageConsumer.java like this

package com.webspherenotes.stomp;
import java.io.IOException;
import java.net.UnknownHostException;
import org.apache.activemq.transport.stomp.StompConnection;
import org.apache.activemq.transport.stomp.StompFrame;
import org.apache.activemq.transport.stomp.Stomp.Headers.Subscribe;

public class StompMessageConsumer {
  public static void main(String[] args) {
    try {
      StompConnection connection = new StompConnection();
      connection.open("localhost", 61613);
      connection.connect("system", "manager");
      connection.subscribe("/queue/stomptest", Subscribe.AckModeValues.CLIENT);
      connection.begin("tx2");
      StompFrame message = connection.receive();
      System.out.println(message.getBody());
      connection.ack(message, "tx2");
      connection.commit("tx2");
      connection.disconnect();
    } catch (UnknownHostException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
The StompConsumer code does not care about if the message was published using JMS or STOMP it remains same.

How to either publish or consume message using STOMP in ActiveMQ

The ActiveMQ server supports Simple Text-oriented Messaging Protocol(STOMP) that we can use for communicating between client and server. I wanted to try out this feature so i built a sample application that has two classes one is StompMessagePublisher.java that publishes a message using STOMP and StompMessageConsumer that consumes a message. You can download the sample application from here By default the STOMP connector is disabled in the ActiveMQ so first thing that you would have to do is enable it. First open <activemq_installroot>\conf\activemq.xml file and find the transportConnectors element by default it will have only one transportConnector child element with name equal to openwire add stomp element in it like this

<transportConnectors>
 <transportConnector name="openwire" uri="tcp://localhost:61616?trace=true"/>

 <transportConnector name="stomp" uri="stomp://localhost:61613?trace=true"/>

</transportConnectors>
Then create a StompMessagePublisher.java like this

package com.webspherenotes.stomp;

import java.io.IOException;
import java.net.UnknownHostException;

import org.apache.activemq.transport.stomp.StompConnection;
public class StompMessagePublisher {

  public static void main(String[] args) {
    try {
      StompConnection connection = new StompConnection();
      connection.open("localhost", 61613);
      connection.connect("system", "manager");
       connection.begin("tx1");
      connection.send("/queue/stomptest", "This is test message 1");
      connection.commit("tx1");
      connection.disconnect();
    } catch (UnknownHostException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
In this class first we are opening a StompConnection with localhost:61613, after establishing connection we are sending message to stomptest queue in a transaction Next create StompMessageConsumer.java class which looks like this

package com.webspherenotes.stomp;

import java.io.IOException;
import java.net.UnknownHostException;

import org.apache.activemq.transport.stomp.StompConnection;
import org.apache.activemq.transport.stomp.StompFrame;
import org.apache.activemq.transport.stomp.Stomp.Headers.Subscribe;

public class StompMessageConsumer {

  public static void main(String[] args) {
    try {
      StompConnection connection = new StompConnection();
      connection.open("localhost", 61613);
      connection.connect("system", "manager");
      connection.subscribe("/queue/stomptest", Subscribe.AckModeValues.CLIENT);
      connection.begin("tx2");
      StompFrame message = connection.receive();
      System.out.println(message.getBody());
      connection.ack(message, "tx2");
      connection.commit("tx2");
      connection.disconnect();
    } catch (UnknownHostException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
In the StompMessageConsumer.java, first i am establishing STOMP connection to the localhost and then subscribing to stomptest queue, after subscribing to the queue we have to call the receive() method on the connection to receive the message from the queue.

How to use ActiveMQ in Jetty

I wanted to figure out how to use Apache ActiveMQ in a web application that is running in Jetty, Also i wanted to use the Maven Jetty Plugin so i built this sample application which contains a , when i make GET request to servelt it takes value of message query parameter and publishes it as a TextMessage to a Queue, you can download the source code for the sample application from here First thing that i did is create a pom.xml file that looks like this

<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
  http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.webspherenotes.jms</groupId>
  <artifactId>HelloJettyActiveMQ</artifactId>
  <version>1.0</version>
  <packaging>war</packaging>
  <name>HelloJettyActiveMQ</name>
  <description>Sample app to demonstrate how to use 
  ActiveMQ in Jetty</description>
  <dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.4</version>
    </dependency>
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-core</artifactId>
      <version>5.5.0</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.5.11</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jms</artifactId>
      <version>3.0.3.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.apache.xbean</groupId>
      <artifactId>xbean-spring</artifactId>
      <version>3.9</version>
    </dependency>
  </dependencies>
  <build>
    <finalName>HelloJettyActiveMQ</finalName>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
   
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>7.2.2.v20101205</version>
        <configuration>
          <scanIntervalSeconds>10</scanIntervalSeconds>
          <webAppConfig>
            <jettyEnvXml>${basedir}/src/main/resources/jetty-env.xml</jettyEnvXml>
          </webAppConfig>
        </configuration>
      </plugin>
   
    </plugins>
  </build>
</project>
I am using version 7.2.2 of Jetty server in the jetty-maven-plugin, also note that i configured a jetty-env.xml file which defines the JMS resources in the JNDI context. This is how my jetty-env.xml file looks like

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" 
"http://jetty.mortbay.org/configure.dtd">
<Configure id='jms-webapp-wac' class="org.eclipse.jetty.webapp.WebAppContext">
  <New id="connectionFactory" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg>
      <Ref id='jms-webapp-wac' />
    </Arg>
    <Arg>jms/ConnectionFactory</Arg>
    <Arg>
      <New class="org.apache.activemq.ActiveMQConnectionFactory">
        <Arg>tcp://localhost:61616</Arg>
      </New>
    </Arg>
  </New>
  <New id="fooQueue" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg>jms/FooQueue</Arg>
    <Arg>
      <New class="org.apache.activemq.command.ActiveMQQueue">
        <Arg>FOO.QUEUE</Arg>
      </New>
    </Arg>
  </New>
</Configure>
The jetty-env.xml file defines 2 resources on is the ActiveMQConnectionFactory and second is the ActiveMQQueue. After that i did declare the messaging related resources in web.xml, so my web.xml file looks like this

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
         http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  
  <display-name>HelloEmbeddedServer</display-name>
  <servlet>
    <servlet-name>MessagePublishingServlet</servlet-name>
    <servlet-class>com.webspherenotes.jms.MessagePublishingServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>MessagePublishingServlet</servlet-name>
    <url-pattern>/MessagePublishingServlet/*</url-pattern>
  </servlet-mapping>
  
  
  <resource-ref>
    <description>JMS Connection</description>
    <res-ref-name>jms/ConnectionFactory</res-ref-name>
    <res-type>javax.jms.ConnectionFactory</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
  </resource-ref>
  
  <message-destination-ref>
    <message-destination-ref-name>jms/FooQueue</message-destination-ref-name>
    <message-destination-type>javax.jms.Queue</message-destination-type>
    <message-destination-usage>Produces</message-destination-usage>
    <message-destination-link>jms/FooQueue</message-destination-link>
  </message-destination-ref>
 
 
</web-app>
This is how my MessagePublishingServlet.java looks like

package com.webspherenotes.jms;

import java.io.IOException;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MessagePublishingServlet extends HttpServlet{
  Logger logger = LoggerFactory.getLogger(MessagePublishingServlet.class);
  Connection connection;
  Queue queue;
  

  @Override
  public void init() throws ServletException {
    logger.debug("Entering MessagePublishingServlet.init()");
    try {
      InitialContext context = new InitialContext();
      ConnectionFactory connectionFactory = (ConnectionFactory)context.lookup("java:comp/env/jms/ConnectionFactory");
      logger.debug("Connection Factory " + connectionFactory);
      connection = connectionFactory.createConnection();
      queue =(Queue) context.lookup("jms/FooQueue");
      logger.debug("After looking up the queue " + queue); 
    } catch (Exception e) {
      logger.error("Error occured in MessagePublishingServlet.init() " + e.getMessage(),e);
    }
    logger.debug("Exiting MessagePublishingServlet.init()");

  }

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    logger.debug("Entering MessagePublishingServlet.doGet()");
    resp.setContentType("text/html");
    resp.getWriter().println("Hello from MessagePublishingServlet.doGet()");
    try {

      Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
      TextMessage textMessage = session.createTextMessage();
      textMessage.setText(req.getParameter("message"));
      MessageProducer queueSender = session.createProducer(queue);
      queueSender.send(textMessage); 
    } catch (JMSException e) {
      logger.error("Error occured in MessagePublishingServlet.doGet() " + e.getMessage(),e);

    }
    logger.debug("Exiting MessagePublishingServlet.doGet()");
  }

}
The init() method looks up the JMS objects from the InitialContext, in the doGet() method i am reading the value of message query parameter and using it to send a TextMessage.

Using Spring message pojo

The Spring Framework has concept of message driven pojo's which are similar to MDB that you can use for receiving messages asynchronously. I wanted to try that out so i changed the sample application that i developed in Using amq namespace for building Spring JMS application for ActiveMQ post. In my sample application i did create a simple MessageListener class that gets called whenever there is a message, you can download the source code for sample application from here First i did create a simple MessageListener POJO class like this

package com.webspherenotes.jms;

public class MessageListener {

  public void handleMessage(String message){
    System.out.println("Inside MessageListener.handleMessage() " 
 + message);
  }
}
The handleMessage() method of the MessageListener will get called whenever the message is available. Next define the message listener class in the spring configuration like this.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:jms="http://www.springframework.org/schema/jms"
  xmlns:amq="http://activemq.apache.org/schema/core"
  xsi:schemaLocation="http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.5.0.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  <amq:connectionFactory id="connectionFactory"
    brokerURL="tcp://localhost:61616" />

  <bean id="jmsTemplate" 
  class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="connectionFactory" />
    <property name="defaultDestinationName" value="queue1" />

  </bean>


  <bean id="messageListener" 
  class="com.webspherenotes.jms.MessageListener" />
  
  <jms:listener-container connection-factory="connectionFactory">
    <jms:listener destination="queue1" ref="messageListener" 
 method="handleMessage"/>
  </jms:listener-container>
</beans>

Now when you run the publisher mvn exec:java -Dexec.mainClass=com.webspherenotes.jms.MessagePublisher it will initialize the spring context and as part of that process it will create MessageListner class and attach it as listener to the destination, so when the message gets published your MessageListner will get called automatically to handle/consume the message.

Maven build file(pom.xml) for Spring Active MQ JMS application

In the Using amq namespace for building Spring JMS application for ActiveMQ entry i built a sample Spring Active MQ JMS application, this is the maven pom.xml file for it.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.webspherenotes.jms</groupId>
  <artifactId>HelloSpringActiveMQ</artifactId>
  <version>1.0</version>
  <name>HelloSpringActiveMQ</name>
  <description>Sample Spring ActiveMQ JMS application</description>
  <dependencies>
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-core</artifactId>
      <version>5.5.0</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.5.11</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jms</artifactId>
      <version>3.0.3.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.apache.xbean</groupId>
      <artifactId>xbean-spring</artifactId>
      <version>3.9</version>
    </dependency>
  </dependencies>
</project>
Once my pom.xml is ready i can use following commands to run MessagePublisher.java and MessageReceiver.java
  1. mvn exec:java -Dexec.mainClass=com.webspherenotes.jms.MessagePublisher
  2. mvn exec:java -Dexec.mainClass=com.webspherenotes.jms.MessageReceiver

Using amq namespace for building Spring JMS application for ActiveMQ

Using amq namespace makes developing Spring application for ActiveMQ very easy, i wanted to try that so i built this sample application, This is how my applicationContext.xml file looks like

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:jms="http://www.springframework.org/schema/jms"
  xmlns:amq="http://activemq.apache.org/schema/core"
  xsi:schemaLocation="http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.5.0.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  <amq:connectionFactory id="connectionFactory"
    brokerURL="tcp://localhost:61616" />

  <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="connectionFactory" />
    <property name="defaultDestinationName" value="queue1" />
  </bean>

</beans>
As you can see i have only two beans one for ConnectionFactory and other for JmsTemplate. This is how my MessagePublisher.java looks like

package com.webspherenotes.jms;

import java.util.Date;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

public class MessagePublisher {
  public static void main(String[] args)throws Exception {
    ApplicationContext context = 
 new ClassPathXmlApplicationContext("applicationContext.xml");
    JmsTemplate jmsTemplate =(JmsTemplate) context.getBean("jmsTemplate");
    MessageCreator message = new MessageCreator() {
      public Message createMessage(Session session) throws JMSException {
        TextMessage textMessage = session.createTextMessage();
        String messageStr = "This message is sent using MessageCreator" + new Date();
        textMessage.setText(messageStr);
        return textMessage;
      }
    };
    jmsTemplate.send(message);
  }
}
This is how my MessageReceiver class looks like

package com.webspherenotes.jms;

import javax.jms.TextMessage;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;

public class MessageReceiver {
  public static void main(String[] args)throws Exception {
    ApplicationContext context = 
    new ClassPathXmlApplicationContext("applicationContext.xml");
    JmsTemplate jmsTemplate =(JmsTemplate) context.getBean("jmsTemplate");
    TextMessage message = (TextMessage)jmsTemplate.receive();
    System.out.println("Message received " + message.getText());
  }
}
This is sample of how to wait for message synchronously.

Apache Maven pom.xml for activemq standalone application

I wanted to check what pom.xml should i use to create ActiveMQ publisher and consumer in standalone java application so i built a sample application, that you can download from here First i had to use the following directory structure
Then i did use the following pom.xml, only dependencies i have is on activemq-core, and slf4j-log4j and it takes care of downloading necessary jars

<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
  http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.webspherenotes.jms</groupId>
  <artifactId>HelloActiveMQMaven</artifactId>
  <version>1.0</version>
  <name>HelloActiveMQMaven</name>
  <description>How to use ActiveMQ in Maven </description>
  <dependencies>
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-core</artifactId>
      <version>5.5.0</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.6.4</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.1.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>java</goal>
            </goals>
            <configuration>
              <mainClass>
     com.webspherenotes.jms.HelloActiveMQPublisher</mainClass>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>
Then i can execute the publisher by executing mvn exec:java -Dexec.mainClass=com.webspherenotes.jms.HelloActiveMQPublisher and i can execute the consumer by executing mvn exec:java -Dexec.mainClass=com.webspherenotes.jms.HelloActiveMQConsumer

Using ActiveMQConnectionFactory for creating connection factory

When developing a messaging application for ActiveMQ, say for standalone client, normally we create a jndi.properties file like this in the source folder.

java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
java.naming.provider.url = tcp://localhost:61616
java.naming.security.principal=system
java.naming.security.credentials=manager
connectionFactoryNames = QueueCF
queue.ActiveMQ = jms.ActiveMQ
After that we can look up both QueueCF and ActiveMQ from inside the code by looking them up in the InitialContext like this

InitialContext context = new InitialContext();
  
QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory)context.lookup("QueueCF");

QueueConnection queueConnection = queueConnectionFactory.createQueueConnection();
QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

Queue queue = (Queue)context.lookup("ActiveMQ");

Using the jndi.properties option makes your code JMS compliant, but you will have to define the queues and connection factories before hand, with ActiveMQ we have another option which is to use ActiveMQConnectionFactory like this, in this example first we create object of ActiveMQConnectionFactory by passing URL to the broker then we use session.createQueue("ActiveMQ") to create the Queue, It allows us to create Queues dynamically at run time.

package com.webspherenotes.jms;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class HelloActiveMQPublisher {
  public static void main(String[] args) throws Exception{

      String brokerURL = "tcp://localhost:61616";
      ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerURL);

      Connection connection = connectionFactory.createConnection();
      connection.start();
      Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
      Queue queue = session.createQueue("ActiveMQ");
      MessageProducer messageProducer = session.createProducer(queue);
      TextMessage textMessage = session.createTextMessage();
      textMessage.setText("This is a message for dynamically create message q");
      messageProducer.send(textMessage);
      connection.close();
  }
}

package com.webspherenotes.jms;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class HelloActiveMQConsumer implements MessageListener{

  public static void main(String[] args) throws Exception{
    String brokerURL = "tcp://localhost:61616";
    ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerURL);
    Connection connection = connectionFactory.createConnection();
    connection.start();
    Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    Queue queue = session.createQueue("ActiveMQ");
    MessageConsumer messageConsumer = session.createConsumer(queue);
    messageConsumer.setMessageListener(new HelloActiveMQConsumer());
    BufferedReader stdin = new BufferedReader(new InputStreamReader(
          System.in));
    System.out.println("Press enter to quit application");
    stdin.readLine();
    connection.close();
  }
  @Override
  public void onMessage(Message message) {
    try {
      TextMessage textMessage =(TextMessage)message;
      System.out.println("Thie message is " + textMessage.getText());
    } catch (JMSException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

Request/reply messaging using TopicRequestor

In the Request/Reply messaging using QueueSender , i tried out the QueueRequestor approach for request/reply messaging, similarly i wanted to try out the TopicRequestor, so i built this sample code First create a TopicRequestor class and use it for sending message, the control blocks at the topicRequestor.request() method till it gets response, Even if there are more than one consumer the request() method would return on the first response, rest of the responses would be ignored.

package com.webspherenotes.jms;

import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicPublisher;
import javax.jms.TopicRequestor;
import javax.jms.TopicSession;
import javax.naming.InitialContext;

public class SampleTopicRequestor {

  /**
   * @param args
   */
  public static void main(String[] args)throws Exception{
    InitialContext context = new InitialContext();
    
    TopicConnectionFactory topicConnectionFactory = (TopicConnectionFactory)context.lookup("TopicCF");
    
    TopicConnection topicConnection = topicConnectionFactory.createTopicConnection();
    
    TopicSession topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
    
    Topic topic = (Topic)context.lookup("topic1");
    
    TopicPublisher topicPublisher = topicSession.createPublisher(topic);
    
    TextMessage textMessage = topicSession.createTextMessage();
    textMessage.setText("Hello how are you doing?");
    
    TopicRequestor topicRequestor = new TopicRequestor(topicSession, topic);
    topicConnection.start();
    
    TextMessage replyMessage =(TextMessage) topicRequestor.request(textMessage);
    System.out.println("Topic response " + replyMessage.getText());

    topicConnection.close();
  }

}

On the consumer side the value of the replyTo header would be a temporary topic but i wanted to try out the generic Destination and MessageProducer for sending message.

package com.webspherenotes.jms;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class SampleTopicConsumer implements MessageListener {
  
  TopicConnection topicConnection;
  TopicSession topicSession;

  public SampleTopicConsumer() {
    try {
      InitialContext context = new InitialContext();

      TopicConnectionFactory topicConnectionFactory = (TopicConnectionFactory) context
          .lookup("TopicCF");

       topicConnection = topicConnectionFactory
          .createTopicConnection();

      topicSession = topicConnection.createTopicSession(false,
          Session.AUTO_ACKNOWLEDGE);

      Topic topic = (Topic) context.lookup("topic1");
      
      TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic);
      
      topicSubscriber.setMessageListener(this);
      topicConnection.start();
    } catch (NamingException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (JMSException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
  
  

  @Override
  public void onMessage(Message message) {
    try {
      TextMessage textMessage =(TextMessage)message;
      System.out.println("The message is " + textMessage.getText());

      Destination replyToDestination = textMessage.getJMSReplyTo();
      MessageProducer messageProducer = topicSession.createProducer(replyToDestination);
      
      TextMessage replyMessage = topicSession.createTextMessage();
      replyMessage.setText("Reply message to " + textMessage.getText());
      messageProducer.send(replyMessage);
      System.out.println( textMessage.getJMSReplyTo());

    } catch (JMSException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    
  }



  /**
   * @param args
   */
  public static void main(String[] args) throws Exception {
    SampleTopicConsumer sampleTopicConsumer = new SampleTopicConsumer();
    BufferedReader stdin = new BufferedReader(new InputStreamReader(
        System.in));
    System.out.println("Press enter to quit application");
    stdin.readLine();
    sampleTopicConsumer.topicConnection.close();
  }

}

Request/Reply messaging using QueueSender

I wanted to try out this Request/Reply messaging so i developed this simple MessagePublisher class, which sends a message to Queue using QueueSender and then block control for the response to come back.

package com.webspherenotes.jms;

import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueRequestor;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;

public class MessagePublisher {

  public static void main(String[] argv){
    try {
      InitialContext context = new InitialContext();
      
      QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory)context.lookup("QueueCF");
      
      QueueConnection queueConnection = queueConnectionFactory.createQueueConnection();
      QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
      
      Queue queue = (Queue)context.lookup("LoanRequestQ");
      queueConnection.start();
      
      QueueSender queueSender = queueSession.createSender(queue);
      QueueRequestor queueRequestor = new QueueRequestor(queueSession, queue);
      
      TextMessage textMessage = queueSession.createTextMessage();
      textMessage.setText("This is sample message");
      //queueSender.send(textMessage);
      System.out.println("Before calling queueSender.request()");

      TextMessage responseMessage = (TextMessage)queueRequestor.request(textMessage);
      System.out.println("After calling queueSender.request()");

      System.out.println("Response message is " + responseMessage.getText());
      
      queueConnection.close();
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace(System.out);
    }
    
  }
}
This is how the MessageConsumer.java looks like it implements the MessageListener interface to receive the message asynchronously. In the onMessage() method, after reading the Message it creates a QueueSender to the temporary queue for sending the message and sends response to that queue.

package com.webspherenotes.jms;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class MessageConsumer implements MessageListener {
  QueueConnection queueConnection;
  QueueSession queueSession;

  public MessageConsumer() {
    try {
      InitialContext context = new InitialContext();
      QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory) context
          .lookup("QueueCF");
      queueConnection = queueConnectionFactory.createQueueConnection();
      queueSession = queueConnection.createQueueSession(false,
          Session.AUTO_ACKNOWLEDGE);
      Queue queue = (Queue) context.lookup("LoanRequestQ");
      QueueReceiver queueReceiver = queueSession.createReceiver(queue);
      queueReceiver.setMessageListener(this);
      queueConnection.start();
    } catch (NamingException e) {
      e.printStackTrace();
    } catch (JMSException e) {
      e.printStackTrace();
    }
  }

  @Override
  public void onMessage(Message message) {
    try {
      TextMessage textMessage = (TextMessage) message;
      System.out.println("Inside MessageConsumer.onMessage "
          + textMessage.getText());
      Queue replyTo = (Queue) textMessage.getJMSReplyTo();

      QueueSender replyToSender = queueSession.createSender(replyTo);
      System.out.println("Value of JMSReplyTo "
          + textMessage.getJMSReplyTo());
      TextMessage replyMessage = queueSession.createTextMessage();
      System.out.println("After creating replyMessage");
      replyMessage.setText("This is reply for " + textMessage.getText());
      System.out.println("Before calling send()");
      replyToSender.send(replyMessage);
      System.out.println("After calling send()");

    } catch (JMSException e) {
      e.printStackTrace(System.out);
    }
  }

  public static void main(String[] argv) {
    try {
      MessageConsumer messageConsumer = new MessageConsumer();
      BufferedReader stdin = new BufferedReader(new InputStreamReader(
          System.in));
      System.out.println("Press enter to quit application");
      stdin.readLine();
      messageConsumer.queueConnection.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}

J2C activation specification

This topic provides an overview about the configuration and use of J2C activation specifications, used in the deployment of message-driven beans for JCA 1.5 resources.

J2C activation specifications are part of the configuration of inbound messaging support that can be part of a JCA 1.5 resource adapter. Each JCA 1.5 resource adapter that supports inbound messaging defines one or more types of message listener in its deployment descriptor (messagelistener in the ra.xml). The message listener is the interface that the resource adapter uses to communicate inbound messages to the message endpoint. A message-driven bean (MDB) is a message endpoint and implements one of the message listener interfaces provided by the resource adapter. By allowing multiple types of message listener, a resource adapter can support a variety of different protocols. For example, the interface javax.jms.MessageListener, is a type of message listener that supports JMS messaging. For each type of message listener that a resource adapter implements, the resource adapter defines an associated activation specification (activationspec in the ra.xml). The activation specification is used to set configuration properties for a particular use of the inbound support for the receiving endpoint.

When an application containing a message-driven bean is deployed, the deployer must select a resource adapter that supports the same type of message listener that the message-driven bean implements. As part of the message-driven bean deployment, the deployer needs to specify the properties to set on the J2C activation specification. Later, during application startup, a J2C activation specification instance is created, and these properties are set and used to activate the endpoint (that is, to configure the resource adapter’s inbound support for the specific message-driven bean).

Applications with message-driven beans can also specify all, some, or none of the configuration properties needed by the ActivationSpec class, to override those defined by the resource adapter-scoped definition. These properties, specified as activation-config properties in the application’s deployment descriptor, are configured when the application is assembled. To change any of these properties requires redeploying the application. These properties are unique to this applications use and are not shared with other message-driven beans. Any properties defined in the application's deployment descriptor take precedence over those defined by the resource adapter-scoped definition. This allows application developers to choose the best defaults for their applications.

Message driven beans

WebSphere Application Server supports the use of message-driven beans as asynchronous message consumers.


A client sends messages to the destination (or endpoint) for which the message-driven bean is deployed as the message listener. When a message arrives at the destination, the EJB container invokes the message-driven bean automatically without an application having to explicitly poll the destination. The message-driven bean implements some business logic to process incoming messages on the destination.

Message-driven beans can be configured as listeners on a Java EE Connector Architecture (JCA) 1.5 resource adapter or against a listener port (as for WebSphere Application Server Version 5). With a JCA 1.5 resource adapter, message-driven beans can handle generic message types, not just JMS messages. This makes message-driven beans suitable for handling generic requests inbound to WebSphere Application Server from enterprise information systems through the resource adapter. In the JCA 1.5 specification, such message-driven beans are commonly called message endpoints or simply endpoints.

All message-driven beans must implement the MessageDrivenBean interface. For JMS messaging, a message-driven bean must also implement the message listener interface, javax.jms.MessageListener.

A message driven bean can be registered with the EJB timer service for time-based event notifications if it implements the javax.ejb.TimedObject interface in addition to the message listener interface.

You are recommended to develop a message-driven bean to delegate the business processing of incoming messages to another enterprise bean, to provide clear separation of message handling and business processing. This also enables the business processing to be invoked by either the arrival of incoming messages or, for example, from a WebSphere J2EE client.

Messages arriving at a destination being processed by a message-driven bean have no client credentials associated with them; the messages are anonymous. Security depends on the role specified by the RunAs Identity for the message-driven bean as an EJB component. For more information about EJB security, see Securing enterprise bean applications.

For JMS messaging, message-driven beans can use a JMS provider that has a JCA 1.5 resource adapter, for example the default messaging provider that is part of WebSphere Application Server. With a JCA 1.5 resource adapter, you deploy EJB 2.1 message-driven beans as JCA 1.5-compliant resources, to use a J2C activation specification. If the JMS provider does not have a JCA 1.5 resource adapter, for example the V5 Default Messaging provider and the WebSphere MQ messaging provider, you must configure JMS message-driven beans against a listener port.

When to use activiation specification vs listener port

Guidelines, related to versions of WebSphere® Application Server, to help you choose when to configure your message-driven beans to work with listener ports rather than activation specifications.
You can configure the following resources for message-driven beans:

* Activation specifications for message-driven beans that comply with Java™ EE Connector Architecture (JCA) Version 1.5.
* The message listener service, listener ports, and listeners for any message-driven beans that you want to deploy against listener ports.

If you want to use message-driven beans with a messaging provider that does not have a JCA 1.5 resource adapter (for example the WebSphere MQ messaging provider or the V5 Default Messaging provider), you cannot use activation specifications and therefore you must configure your beans against a listener port. There are also a few scenarios in which, although you could use activation specifications, you might still choose to use listener ports. For example, for compatability with existing message-driven bean applications. Here are some guidelines, related to versions of WebSphere Application Server, to help you choose when to use listener ports rather than activation specifications:

* WebSphere Application Server Version 4 does not support message-driven beans, so listener ports and activation specifications are not applicable. WebSphere Application Server Version 4 does support message beans, but these are not message-driven beans.
* WebSphere Application Server Version 5 supports EJB 2.0 (JMS only) message-driven beans that are deployed using listener ports. This deployment technology is sometimes called application server facility (ASF).
* WebSphere Application Server Version 6 continues to support message-driven beans that are deployed using listener ports, and also supports JCA, which you can use to deploy message-driven beans using activation specifications. This gives you the following options for deploying message-driven beans on WebSphere Application Server Version 6:
o You must deploy default messaging (service integration bus) message-driven beans using activation specifications.
o You must deploy WebSphere MQ message-driven beans using listener ports.
o You can deploy third-party messaging message-driven beans using either listener ports or activation specifications, depending on the facilities available from your third-party messaging provider.