The Hello World application consists of a publisher application that publishes a "Hello World" message to a topic. This message will be received by all topic subscribers that are connected to the topic in question. In other words, the message is broadcast to all listeners.
There are three sample programs for this applications:
As was the case with the P2P examples, none of the source code here handlings
exceptions. Although this improves the readability of the example code,
application programmers should notice that almost all methods in the JMS
API's may raise a JMSException
if the JMS provider fails.
A topic publisher must perform the usual steps to initialize before it can start to send messages:
Obtain an InitialContext
object for the JMS server.
Use the context object to lookup a specific topic, in this case,
topic0
.
Use the context object to lookup the topic connection factory. You only
need to specify the topic/connectionFactory
with the lookup because
the batch file that you run this sample from has set the system
properties to point to the appropriate root context for the system
namespace. If you were using the JMS server with the
Novell exteNd Application Server, you would have to specify the lookup
as follows:
TopicConnectionFactory connFactory = (TopicConnectionFactory) ctx. lookup("iiop://localhost:53506/topic/connectionFactory");
Use the TopicConnectionFactory
to create a TopicConnection
. The
TopicConnection
represents a physical connection to the JMS
server.
Create a topic session. The first parameter in the createTopicSession
method decides whether or not the session is transacted. Here, we
use a non-transacted session. The second parameter decided the
delivery mode, which is never used for sending applications.
Create a topic publisher for topic0
and create a message.
Publish the "Hello World" message to topic0
.
Finally, close the topic connection. This will in turn close both
the session and the TopicPublisher
.
The source code for the Publisher
class is shown below:
package pubSub; import javax.naming.InitialContext; import javax.jms.Topic; import javax.jms.Session; import javax.jms.TextMessage; import javax.jms.TopicPublisher; import javax.jms.DeliveryMode; import javax.jms.TopicSession; import javax.jms.TopicConnection; import javax.jms.TopicConnectionFactory; public class Publisher { public static void main(String[] args) throws Exception { | // get the initial context | InitialContext ctx = new InitialContext(); | | // lookup the topic object | Topic topic = (Topic) ctx.lookup("topic/topic0"); | | // lookup the topic connection factory | TopicConnectionFactory connFactory = (TopicConnectionFactory) ctx. | lookup("topic/connectionFactory"); | | // create a topic connection | TopicConnection topicConn = connFactory.createTopicConnection(); | | // create a topic session | TopicSession topicSession = topicConn.createTopicSession(false, | Session.AUTO_ACKNOWLEDGE); | | // create a topic publisher | TopicPublisher topicPublisher = topicSession.createPublisher(topic); | topicPublisher.setDeliveryMode(DeliveryMode.NON_PERSISTENT); | | // create the "Hello World" message | TextMessage message = topicSession.createTextMessage(); | message.setText("Hello World"); | | // publish the messages | topicPublisher.publish(message); | | // print what we did | System.out.println("published: " + message.getText()); | | // close the topic connection | topicConn.close(); } }
Note that although the message is sent with default delivery mode set to
PERSISTENT
, the JMS server will only persist topic messages when
a topic has durable subscribers. In pub/sub messaging, persistent messages
only make sense with durable subscribers because transient subscribers
are lost if the server or subscriber crashes.
As described in the P2P Hello example, a
synchronous receiver must actively retrieve messages by using on of the
receive
methods. The receive
method blocks until the connection
has been started and a message is available at the topic.
A topic subscriber performs the same initial steps as the topic publisher listed above to get a session. Then it creates a topic receiver and starts the connection. Finally, a message is consumer from the topic after which the connection is closed:
package pubSub; import javax.naming.InitialContext; import javax.jms.Topic; import javax.jms.Session; import javax.jms.TextMessage; import javax.jms.TopicSession; import javax.jms.TopicSubscriber; import javax.jms.TopicConnection; import javax.jms.TopicConnectionFactory; public class Subscriber { public static void main(String[] args) throws Exception { | // get the initial context | InitialContext ctx = new InitialContext(); | | // lookup the topic object | Topic topic = (Topic) ctx.lookup("topic/topic0"); | | // lookup the topic connection factory | TopicConnectionFactory connFactory = (TopicConnectionFactory) ctx. | lookup("topic/connectionFactory"); | | // create a topic connection | TopicConnection topicConn = connFactory.createTopicConnection(); | | // create a topic session | TopicSession topicSession = topicConn.createTopicSession(false, | Session.AUTO_ACKNOWLEDGE); | | // create a topic subscriber | TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic); | | // start the connection | topicConn.start(); | | // receive the message | TextMessage message = (TextMessage) topicSubscriber.receive(); | | // print the message | System.out.println("received: " + message.getText()); | | // close the topic connection | topicConn.close(); } }
Note that if you run the Subscriber application after running the Publisher application, the subscriber will not receive a message. This happens because topic subscribers will only receive messages that were sent to the topic after the subscription was made.
An asynchronous topic subscriber is very similar to an asynchronous queue receiver. It registers a message listener, which will be invoked automatically and asynchronously by the JMS provider as and when messages arrive at the subscribed topic.
As described earlier, asynchronous message listener are encouraged to also register an exception listener with the connection to be able to receive a notification if an exception occurs while JMS processes the message. The exception listener is this example merely prints out the exception.
package pubSub; import javax.naming.InitialContext; import javax.jms.Topic; import javax.jms.Session; import javax.jms.Message; import javax.jms.TextMessage; import javax.jms.MessageListener; import javax.jms.JMSException; import javax.jms.ExceptionListener; import javax.jms.TopicSession; import javax.jms.TopicSubscriber; import javax.jms.TopicConnection; import javax.jms.TopicConnectionFactory; public class AsyncSubscriber implements MessageListener, ExceptionListener { public static void main(String[] args) throws Exception { | // get the initial context | InitialContext ctx = new InitialContext(); | | // lookup the topic object | Topic topic = (Topic) ctx.lookup("topic/topic0"); | | // lookup the topic connection factory | TopicConnectionFactory connFactory = (TopicConnectionFactory) ctx. | lookup("topic/connectionFactory"); | | // create a topic connection | TopicConnection topicConn = connFactory.createTopicConnection(); | | // create a topic session | TopicSession topicSession = topicConn.createTopicSession(false, | Session.AUTO_ACKNOWLEDGE); | | // create a topic subscriber | TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic); | | // set an asynchronous message listener | AsyncSubscriber asyncSubscriber = new AsyncSubscriber(); | topicSubscriber.setMessageListener(asyncSubscriber); | | // set an asynchronous exception listener on the connection | topicConn.setExceptionListener(asyncSubscriber); | | // start the connection | topicConn.start(); | | // wait for messages | System.out.print("waiting for messages"); | for (int i = 0; i < 10; i++) { | | Thread.sleep(1000); | | System.out.print("."); | } | System.out.println(); | | // close the topic connection | topicConn.close(); } /** This method is called asynchronously by JMS when a message arrives at the topic. Client applications must not throw any exceptions in the onMessage method. @param message A JMS message. */ public void onMessage(Message message) { | TextMessage msg = (TextMessage) message; | try { | | System.out.println("received: " + msg.getText()); | } catch (JMSException ex) { | | ex.printStackTrace(); | } } /** This method is called asynchronously by JMS when some error occurs. When using an asynchronous message listener it is recommended to use an exception listener also since JMS have no way to report errors otherwise. @param exception A JMS exception. */ public void onException(JMSException exception) { | System.err.println("something bad happended: " + exception); } }
This example uses automatic acknowledge, which means that JMS will acknowledge
the message right after onMessage successfully returns. If a subscriber uses
CLIENT_ACKNOWLEDGE
, it must acknowledge messages manually during the
onMessage
method.
Although messages are not required to be acknowledged each time onMessage
is
called with CLIENT_ACKNOWLEDGE
, it is recommended that applications acknowledge
messages as quickly as possible to avoid a large build-up of un-acknowledged
messages on the client.
Copyright © 2003, 2004 Novell, Inc. All rights reserved. Copyright © 2001, 2002, 2003 SilverStream Software, LLC. All rights reserved.