Wednesday, March 10, 2010

Use of noLocal parameter while creating subscriber in JMS

Lets examine jms api for creating subscriber.

public TopicSubscriber createSubscriber(Topic topic, String messageSelector, boolean noLocal) throws JMSException

java doc says that third parameter is used to make a decision if subscriber want to consume message published by itself (if same connection is used to create publisher which publishes the message) or not.

Not very much clear! Lets design an experiment to see its behavior.

I will create one chat application with following details

topic: HowToEstablishPeaceInWorld

subscriber 1: Osama Bin Laden

subscriber 2: George Bush

This chat application will be based on JMS. Both these subscribers are publishers as well. One will type one's GREAT idea on one's console and it will be visible to other.

The pseudo code below shows how subscribers have subscribed the topic.

Topic chatTopic = (Topic)jndi.lookup("HowToEstablishPeaceInWorld");

TopicSubscriber OsamaBinLaden = subSession.createSubscriber(chatTopic);

TopicSubscriber GeorgeBush = subSession.createSubscriber(chatTopic);

This is Bush console
Bush: hi
Bush says: hi
osama says: hello

This is osama console

Bush says: hi
osama: hello
osama says: hello

The problem here is, the subscribers are consuming the message posted by themselves. Now lets modify the code and see the change in output

TopicSubscriber subscriber = subSession.createSubscriber(chatTopic,null,true);

This is Bush console
Bush: hi
osama says: hello

This is osama console
Bush says: hi
osama: hello

Hope you noticed the difference subscribers are no more consuming message posted by themselves(no more Bush says to Bush console).

Lets see how chat on world peace goes further.

Bush console

Bush: U still alive?

osama console

Bush says: U still alive?

Now osama thinks doesn't jms offers a way so that I don't see what Bush is typing but bush will see everything I type. He contacted software wing of al-Qaeda and they didn't let osama down.

The second argument in create Subscriber can be used to filter message.

Find below the source code for chat program. The code is in respect to jboss MQ server.


import javax.jms.*;
import javax.naming.*;
import java.io.*;
import java.io.InputStreamReader;
import java.util.Properties;

public class Chat implements javax.jms.MessageListener{
private TopicSession pubSession;
private TopicSession subSession;
private TopicPublisher publisher;
private TopicConnection connection;
private static String username;

/* Constructor. Establish JMS publisher and subscriber */
public Chat(String username)
throws Exception {
// Obtain a JNDI connection
Properties env = new Properties( );
// ... specify the JNDI properties specific to the vendor
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
env.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");



InitialContext jndi = new InitialContext(env);

// Look up a JMS connection factory
TopicConnectionFactory conFactory =
(TopicConnectionFactory)jndi.lookup("TopicConnectionFactory");

// Create a JMS connection
TopicConnection connection =
conFactory.createTopicConnection();

// Create two JMS session objects
TopicSession pubSession =
connection.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
TopicSession subSession =
connection.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);

// Look up a JMS topic
Topic chatTopic = (Topic)jndi.lookup("topic/HowToEstablishPeaceInWorld");

// Create a JMS publisher and subscriber
TopicPublisher publisher =
pubSession.createPublisher(chatTopic);
TopicSubscriber subscriber =
subSession.createSubscriber(chatTopic,null,true);

// Register the jms message listener
subscriber.setMessageListener(this);

// Intialize the Chat application
set(connection, pubSession, subSession, publisher, username);

// Start the JMS connection; allows messages to be delivered
connection.start( );

}
/* Initialize the instance variables */
public void set(TopicConnection con, TopicSession pubSess,
TopicSession subSess, TopicPublisher pub,
String username) {
this.connection = con;
this.pubSession = pubSess;
this.subSession = subSess;
this.publisher = pub;
this.username = username;
}
/* Receive message from topic subscriber */
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage) message;
String text = textMessage.getText( );
System.out.println(text);
} catch (JMSException jmse){ jmse.printStackTrace( ); }
}
/* Create and send message using topic publisher */
protected void writeMessage(String text) throws JMSException {
TextMessage message = pubSession.createTextMessage( );
message.setText(username+" says: " +text);
publisher.publish(message);
}
/* Close the JMS connection */
public void close( ) throws JMSException {
connection.close( );
}
/* Run the Chat client */
public static void main(String [] args){
try{

Chat chat = new Chat(args[0]);

// Read from command line
BufferedReader commandLine = new
java.io.BufferedReader(new InputStreamReader(System.in));

// Loop until the word "exit" is typed
while(true){
String s = commandLine.readLine( );
if (s.equalsIgnoreCase("exit")){
chat.close( ); // close down connection
System.exit(0);// exit program
} else
chat.writeMessage(s);
}
} catch (Exception e){ e.printStackTrace( ); }
}
}

2 comments: