1. Trang chủ
  2. » Công Nghệ Thông Tin

Java 2 Bible Enterprise Edition phần 9 doc

71 325 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 71
Dung lượng 126,7 KB

Nội dung

// Step 6 // Create a simple text message and send it out Message msg = qsession.createTextMessage("Simple text message"); // Step 7 // Send the message out qsender.send(msg); Step 1. Before you can do anything else, you need to establish a connection with the JMS provider. You do this with administered objects, as described in the section "Administered Objects." In this preliminary step, you retrieve the connection factory that has been placed into the JNDI namespace. First create an initial context (using default JNDI parameters from a jndi.properties file). Once you have created the initial context, you can look up an object that is bound to the name "ConnectionFactory". Finally, cast the object to the appropriate type — in this case QueueConnectionFactory. Step 2. Once you have retrieved the QueueConnectionFactory object from the JNDI namespace, you can use it to create a connection to the JMS provider. Note that this connection factory is specific to the JMS provider. It knows how to establish a connection — what protocols to use, what steps are required, and so on. But since it implements the ConnectionFactory interface, all you have to do is call the appropriate routine — in this case createQueueConnection. Step 3. The next step is to create a session from the connection. You do this with the createQueueSession method, which takes two arguments. The first is a Boolean flag that indicates whether the session is to be transacted or not. (See the later section "Use transactions with JMS" for more details.) The second argument is the acknowledgement mode to be used for this session. Notice that there are predefined constants that you should use in specifying the mode. Step 4. In this step, you retrieve another administered object – the queue. This example assumes you have previously placed a queue object into the JNDI name− space as described in the administered objects section. You can use the same context you created in Step 1. Look up the queue object that has been bound to the name "testQueue", cast it to a Queue object, and assign it to the handle queue. You can perform this step at any time before the next step. It is not dependent on any of the first three steps (apart from the setting up of the initial context). Step 5. Once you have the Queue object, you are ready to create a QueueSender object that you will use to send messages to the queue. The session has a method called createQueueSender that takes a Queue object as a parameter. It creates the sender and connects it to the specified queue. Step 6. This is where you create the message to be sent. In this case you are creating an instance of TextMessage. Use the session to create an object that will hold a text message by calling the createTextMessage method. If you want to send other types of messages, you can call one of the other methods on the QueueSession object (createObjectMessage, createStreamMessage, and so on). Step 7. Finally, you can send the message to the destination queue. You do this by invoking the send method of the QueueSender, passing as an argument the message object to be sent. Point−to−point — receiving messages The following code excerpt shows how to receive a simple JMS message using the point−to−point model of JMS: Chapter 22: JMS 560 // Step 1 // Look up an administered QueueConnectionFactory object Context ctx = new InitialContext(); Object obj = ctx.lookup("ConnectionFactory"); QueueConnectionFactory qcf = (QueueConnectionFactory) obj; // Step 2 // Create a connection with the factory QueueConnectionFactory qcon = qcf.createQueueConnection(); // Step 3 // With the connection we can create a QueueSession QueueSession qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); // Step 4 // Before creating the receiver we need a queue Queue queue = (Queue) ctx.lookup("testQueue"); // Step 5 // Create the QueueReceiver object QueueReceiver qreceiver = qsession.createReceiver(queue); // Step 6 // Start the delivery of messages qcon.start(); // Step 7 // Receive the message from the queue − blocking call TextMessage tm = (TextMessage) qreceiver.receive(); // receive() may return null on closed connection if (tm != null) System.out.println("Message received: " + tm.getText()); Steps 1–4. These steps are identical to the steps for sending a message. You are just establishing a connection with the JMS provider. Step 5. Once you have the Queue object you are ready to create a QueueReceiver object that you will use to receive messages from the queue. The session has a method called createReceiver that takes a Queue object as a parameter. It creates the receiver and connects it to the specified queue. Step 6. Enable the connection to deliver messages. By default, the connection's message delivery is disabled in order to allow you to set everything up before dealing with incoming messages. Once you are ready to handle incoming messages, call the method on the Connection object. Step 7. Call the receive method on the QueueReceiver. This method will block while waiting for a message to be delivered into the queue. Once you receive the message, cast it directly to a TextMessage. (In a real application you would have to be much more cautious before casting objects). Once you have the TextMessage, retrieve the text of the message with the getText method. Finally, print out the text from the message. Chapter 22: JMS 561 Publish/subscribe — sending messages The following code excerpt shows how to send a simple JMS message using the publish/subscribe model of JMS: // Step 1 // Look up an administered TopicConnectionFactory object Context ctx = new InitialContext(); Object obj = ctx.lookup("ConnectionFactory"); TopicConnectionFactory tcf = (TopicConnectionFactory) obj; // Step 2 // Create a connection with the factory TopicConnectionFactory tcon = tcf.createTopicConnection(); // Step 3 // With the connection we can create a TopicSession TopicSession tsession = tcon.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); // Step 4 // Before creating the sender, look up the topic Topic topic = (Topic) ctx.lookup("testTopic"); // Step 5 // Create the TopicPublisher object TopicPublisher tpub = tsession.createPublisher(topic); // Step 6 // Create a simple text message and send it out Message msg = tsession.createTextMessage("Simple text message"); // Step 7 // Send the message out tpub.send(msg); Step 1. Before you can do anything else, you need to establish a connection with the JMS provider. You do this with administered objects, as described in the administered objects section. In this preliminary step, you retrieve the connection factory that has been placed into the JNDI namespace. First, create an initial context (using default JNDI parameters from a jndi.properties file). Once you have created the initial context you can look up an object that is bound to the name "ConnectionFactory". Finally, cast the object to the appropriate type — in this case TopicConnectionFactory. Step 2. Once you have retrieved the TopicConnectionFactory object from the JNDI namespace you can use it to create a connection to the JMS provider. Note that this connection factory is specific to the JMS provider. It knows how to establish a connection — what protocols to use, what steps are required, and so on. But since it implements the ConnectionFactory interface, all you have to do is call the appropriate routine — in this case createTopicConnection. Step 3. The next step is to create a session from the connection. You do this with the createTopicSession method, which takes two arguments. The first is a Boolean flag that indicates whether the session is to be transacted or not. (See the later section on JMS transactions for more details.) The second argument is the acknowledgement mode to be used for this session. Notice that there are predefined constants that you should use in specifying the mode. Chapter 22: JMS 562 Step 4. In this step you retrieve another administered object — the topic. This example assumes you have previously placed a topic object into the JNDI name− space as described in the section "Administered Objects." You can use the same context you created in Step 1. Look up the topic that has been bound to the name "testTopic", cast it to a Topic object, and assign it to the handle topic. You can perform this step at any time before the next step. It is not dependent on any of the first three steps (apart from the setting up of the initial context). Step 5. Once you have the Topic object, you are ready to create a TopicPublisher object that you will use to send messages to the topic. The session has a method called createTopicPublisher that takes a Topic object as a parameter. It creates the sender and connects it to the specified topic. Step 6. This is where you create the message to be sent. In this case you are creating an instance of TextMessage. Use the session to create the message object by calling the createTextMessage method. If you want to send other types of messages, you can call one of the other methods on the session object (createObjectMessage, createStreamMessage, and so on). Step 7. Finally, you can send the message to the destination topic. You do this by invoking the send method of the TopicPublisher, passing as an argument the message object to be sent. Publish/subscribe — receiving messages The following code excerpt shows how to receive a simple JMS message using the publish/subscribe model of JMS: // Step 1 // Look up an administered TopicConnectionFactory object Context ctx = new InitialContext(); Object obj = ctx.lookup("ConnectionFactory"); TopicConnectionFactory tcf = (TopicConnectionFactory) obj; // Step 2 // Create a connection with the factory TopicConnectionFactory tcon = tcf.createTopicConnection(); // Step 3 // With the connection we can create a TopicSession TopicSession tsession = tcon.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); // Step 4 // Before creating the sender, look up the topic Topic topic = (Topic) ctx.lookup("testTopic"); // Step 5 // Create the TopicSubscriber object TopicSubscriber tsub = tsession.createSubscriber(topic); // Step 6 // Start the delivery of messages tcon.start(); // Step 7 // Receive the message from the queue − blocking call Chapter 22: JMS 563 TextMessage tm = (TextMessage) tsub.receive(); // receive() may return null on closed connection if (tm != null) System.out.println("Message received: " + tm.getText()); Steps 1–4. These steps are identical to the steps for sending a message. You are just establishing a connection with the JMS provider. Step 5. Once you have the Topic object, you are ready to create a TopicSubscriber object that you will use to receive messages from the topic. The session has a method called createSubscriber that takes a Topic object as a parameter. It creates the subscriber and connects it to the specified topic. Step 6. Enable the connection to deliver messages. By default, the connection's message delivery is disabled in order to allow you to set everything up before dealing with incoming messages. Once you are ready to handle incoming messages, call the start method on the Connection object. Step 7. Call the receive method on the TopicSubscriber. This method will block while waiting for a message to be delivered to the topic. Once you receive the message, cast it directly to a TextMessage. (In a real application, you would have to be much more cautious before casting objects.) Once you have the TextMessage, retrieve the text of the message with the getText method. Finally, print out the text of the message. MessageListeners Both the point−to−point and publish/subscribe models can deliver messages to your application asynchronously. All that you need to do is create a MessageListener and register it with the QueueReceiver or the TopicSubscriber. The MessageListener interface is very simple. It contains a single method to be implemented: void onMessage(Message message); You can create a standalone class shown below that contains the onMessage method, or you can add the method to an existing class: public class Receiver implements MessageListener { public void onMessage(Message message) { TextMessage tm = (TextMessage) message; if (tm != null) System.out.println( "Msg rcvd: " + tm.getText()); } } Once you have defined this class, register it with the QueueReceiver or the TopicSubscriber. In the point−to−point example, you would insert this code between steps 5 and 6: // Step 5.5 // Create a message listener and register it MessageListener ml = new Receiver(); qreceiver.setMessageListener(ml); In the publish/subscribe example, you would insert this code between steps 5 and 6: Chapter 22: JMS 564 // Step 5.5 // Create a message listener and register it MessageListener ml = new Receiver(); tsub.setMessageListener(ml); Step 7 is not necessary in either case, because the MessageListener processes the incoming messages as required. Connections and sessions Connections allow you to interact with a JMS provider in the same way that database connections allow you to interact with a database. Before you can send or receive any messages, you must establish a connection with the JMS provider and create one or more sessions. In the process of establishing a connection, the JMS provider typically allocates some system resources outside the JVM. As a result, connections are fairly heavy objects and should be reused whenever possible. The most common approach is to create a single connection within the JVM or application and then use it for multiple purposes. Since the process of creating a connection with a JMS provider varies from provider to provider, it is abstracted into a standard ConnectionFactory interface. Depending on the messaging model you use, publish/subscribe or point−to−point, you will use either the TopicConnectionFactory or a QueueConnectionFactory. You place the appropriate connection factory into the namespace and retrieve it at runtime by looking it up. This removes any provider−dependency from your application. The following code samples show how to look up a connection factory. They assume that a connection factory (whether it is a QueueConnectionFactory or a TopicConnectionFactory) has been placed into the JNDI namespace under the name "ConnectionFactory". You can retrieve a queue connection factory in the point−to−point messaging model as follows: // Establish an initial jndi context Context ctx = new InitialContext(); // Look up a queue connection factory qcf = (QueueConnectionFactory) ctx.lookup("ConnectionFactory"); Likewise, you can retrieve a topic connection factory in the publish/subscribe model as follows: // Look up a topic connection factory tcf = (TopicConnectionFactory) ctx.lookup("ConnectionFactory"); Create a connection Once you have the connection factory, you can use it to create the actual connection to the JMS provider. Depending on the type of connection factory you have, you will use either the createQueueConnection or the createTopicConnection method. Assuming you have the QueueConnectionFactory described earlier, you can create a QueueConnection as follows: Chapter 22: JMS 565 // Use the factory to create a queue connection QueueConnection qcon = null; qcon = qcf.createQueueConnection(); Similarly, if you have the TopicConnectionFactory described earlier, you can create a TopicConnection as follows: // Use the factory to create a topic connection. TopicConnection tcon = null; tcon = tcf.createTopicConnection(); As I mentioned at the beginning of this section, connections are fairly heavy objects that should be created once and then reused whenever necessary. As a result, you may want to keep a reference to your connection as a member of your class, or somewhere else where it can be retrieved on demand. Create sessions Sessions serve as the middleman between a connection and the client application. You typically use your connections only during setup and cleanup. All other access to the provider is by means of a Session object. Using the Session object, you can create producers or consumers, create a temporary destination, create message objects, and control transactions. Sessions also manage other things for you behind the scenes. They hold messages until they have been acknowledged, distribute messages to registered listeners, and more. Once you have a connection, creating a session is easy — just invoke the createQueueSession or createTopicSession method (depending on the type of session you have). Session objects are lightweight objects, and you can create multiple sessions from a single connection. You can create a queue session as follows: // With the connection, create a QueueSession QueueSession qsession = null; qsession = qcon.createQueueSession( false, Session.AUTO_ACKNOWLEDGE); Creating a topic session is similar to creating a queue session: // With the connection, create a TopicSession TopicSession tsession = null; tsession = tcon.createTopicSession( false, Session.AUTO_ACKNOWLEDGE); Notice that constants are defined in the Session interface for the various acknowledgement modes. Use these constants as parameters, and you will cut down on runtime errors and maintenance problems. Sessions are intended to be single−threaded. It doesn't matter how many threads use a session, but only one thread should use it at a time. Since no code is provided to guarantee single−thread access, you must provide it yourself. The session guarantees that all registered MessageListener objects will be invoked serially, so you aren't required to provide code to handle that. Create producers and consumers In order to send or receive messages, you use producer or consumer objects, respectively. Again, according to the model you are using, you will obtain the appropriate producer or consumer from the session. Chapter 22: JMS 566 For point−to−point messaging, you will create a QueueSender for sending messages to a queue, and a QueueReceiver for receiving messages from a queue. The following code shows how you do this: // Create the QueueSender object from the session QueueSender qsender = null; qsender = qsession.createSender(queue); // Create the QueueReceiver object from the session QueueReceiver qreceiver = null; qreceiver = qsession.createReceiver(queue); The situation is similar for the publish/subscribe model. You will create a TopicPublisher for publishing messages to a topic, and a TopicSubscriber for receiving messages from a topic. The following code shows how you do this: // Create the TopicPublisher object from the session TopicPublisher tpublisher = null; tpublisher = tsession.createPublisher(topic); // Create the TopicSubscriber object from the session TopicSubscriber tsubscriber = null; tsubscriber = tsession.createSubscriber(topic); Messages in Detail So now that you know how to send and receive messages, how do you go about creating messages with your data? This section focuses on the message objects themselves, including the message header and the various types of message bodies. If you look at the Message interface, you will see that messages have three main components: a header, a body, and a set of properties. Let's take a look at each of these. Message header The message header is the envelope of the message. It provides all the information required for the message to reach its destination. You directly control the value of some of the header fields, while the JMS provider fills in others. Note that in the simplest of JMS applications, none of these fields must be explicitly set or read by the application. They exist to help in the routing of messages and provide the capability for writing certain types of applications. Take a look at each field and think about the conditions under which you might use that information. Table 22−4 describes each field — what it is used for and how it is set. Table 22−4: Message header fields Field Name Set By Description JMSDestination Send method Chapter 22: JMS 567 Specifies where this message should be sent. Filled in by the JMS provider. JMSDeliveryMode Send method Identifies the mode used to deliver this message — either persistent or non−persistent. The JMS provider fills this field in after sending the message. JMSMessageID Send method Contains a unique identifier for the message. Filled in by the JMS provider as part of the send process. JMSTimestamp Send method Contains the time that this message was passed to the Send method. Set by the JMS provider as part of the send process. JMSCorrelationID Client Contains an ID for linking messages together. The client will typically set this to the message ID of the referenced message. JMSReplyTo Client May contain a destination to which replies should be sent. The client will specify the value for this field if it is expecting a response. JMSRedelivered Provider Contains an indication that this message may have been delivered previously. JMSType Client Contains a message−type identifier supplied by the client. The requirements for this field may vary from provider to provider. JMSExpiration Send method A calculated value from the client−supplied time−to−live value. If GMT is later than this expiration time, the message is destroyed. JMSPriority Send method Contains the value the client specified when sending the message. Message properties In addition to the preceding properties, you can define your own properties to a message. The primary reason for assigning your own properties is to facilitate message selection. Once you have a message object, you define a property for the message simply by calling one of the setXXXProperty methods, where XXX is one of the following: Boolean, Byte, Double, Float, Int, Long, Object, Short, and String. As you can see, the JMS API supports a variety of datatypes for use as message properties. Each property consists of a string name and an associated value. As an example, the following code sets a customer name property as a string, and an order ID as an integer: TextMessage msg = tsession.createTextMessage(); msg.setStringProperty("CUSTOMER_NAME", "MyCustomer"); msg.setIntProperty("ORDER_ID", 12345); You can read a property value from an incoming message in a similar manner by using the getXXXProperty methods. Following the same example, once you have received the preceding message, you can read the properties with the following code: String customer = msg.getStringProperty("CUSTOMER_NAME"); int ordered = msg.getIntProperty("ORDER_ID"); Chapter 22: JMS 568 The message selection section later in the chapter demonstrates the use of properties for filtering incoming messages. Note Properties should mainly be used for holding message−selection criteria. While you can create simple messages with the data entirely in properties, it is not a good idea. JMS providers may not handle data in properties as efficiently as data in the body of a message. However, having appropriate properties defined for message selection can be a very efficient use of resources since it might prevent a JMS provider from sending messages across the wire unnecessarily. Message body The message body holds the core data of the message. You can place any type of data into the body of a message by selecting the appropriate message type. JMS identifies five different message types: TextMessage, MapMessage, BytesMessage, StreamMessage, and ObjectMessage. By selecting the most appropriate type of message, you allow the JMS provider to handle the message in the most efficient way. Text messages Text messages store data in the body as a simple string. You will typically use this format whenever your information can be represented most efficiently as a string. You can also use it to send XML messages as strings. This example shows how to use a TextMessage object: // Creating a text message String text = "Sample text for TextMessage"; TextMessage msg = session.createTextMessage(); Message.setText(text); // Reading a text message String txt = message.getText(); Note Some providers include an XML−specific message type. It's a bit more convenient and provides some additional benefit. However, it is not an official JMS message type, and by using it you make your code less portable. Map messages A MapMessage stores the body of its message using a map, which is made up of a set of name/value pairs. The datatypes allowed in properties are allowed here as well. Here the name is a String, and the value is one of the defined datatypes. You add name/value pairs to the message using the setXXX methods and retrieve them using the getXXX methods. This example shows how to use a MapMessage object: // Creating a MapMessage object MapMessage msg = session.createMapMessage(); String custName = "John Doe"; int custAge = 40; long orderDate = new Date().getTime(); msg.setString("CUSTOMER_NAME", custName); msg.setInt("CUSTOMER_AGE", custAge); msg.setLong("ORDER_DATE", orderDate); Chapter 22: JMS 569 [...]... JMSPublish2 JMSPublish2 JMSPublish2 JMSPublish2 JMSPublish2 JMSPublish2 JMSPublish2 JMSPublish2 JMSPublish2 JMSPublish2 The JMSSubscribe3 output is shown here: >java JMSSubscribe3 TopicConnectionFactory topic/testTopic "(message_count = '3') OR (message_count = '8')" JMSSubscribe − beginning press enter to exit − creating an instance of JMSSubscribe Msg rcvd: Test message from JMSPublish2 message_count:... cleaning up JMSPublish JMSPublish − exiting > topic/testTopic "Test JMSPublish2 JMSPublish2 JMSPublish2 JMSPublish2 JMSPublish2 The JMSSubscribe2 output is as follows: >java −cp JMSSubscribe2 TopicConnectionFactory topic/testTopic JMSSubscribe − beginning press enter to exit − creating an instance of JMSSubscribe 581 Chapter 22 : JMS Msg rcvd: Test message_count: Msg rcvd: Test message_count: Msg rcvd:... It registers as a message listener to the given topic and then prints out each message it receives import import import import import javax.jms.*; javax.naming.Context; javax.naming.InitialContext; javax.naming.NamingException; java. io.IOException; /** 576 Chapter 22 : JMS * JMSSubscribe is an example application that will * subscribe to the given topic and will print out any * messages that it receives... JMSPublish2 message_count: 8 − cleaning up JMSSubscribe JMSSubscriber − exiting > 583 Chapter 22 : JMS JMS and J2EE JMS is a very useful tool in enterprise applications Up until the recent changes to the EJB specification, its use in J2EE applications has been somewhat limited You could send and receive messages, but there was no asynchronous way of calling EJBs upon receipt of a message The EJB 2. 0 specification... "−−Receiver.onMessage: JMSException caught"); System.out.println(e.toString()); } } Applying these changes and renaming the files to JMSPublish2 and JMSSubscribe2 yield a slightly different output The JMSPublish2 output is as follows: >java JMSPublish2 TopicConnectionFactory message from JMSPublish2" 5 JMSPublish − beginning − creating an instance of JMSPublish − sending message: Test message from − sending message: Test... message_count: Msg rcvd: Test message_count: Msg rcvd: Test message_count: Msg rcvd: Test message_count: Msg rcvd: Test message_count: message 1 message 2 message 3 message 4 message 5 from JMSPublish2 from JMSPublish2 from JMSPublish2 from JMSPublish2 from JMSPublish2 − cleaning up JMSSubscribe JMSSubscriber − exiting > Add message selection To filter incoming messages, you will use the message−selection feature... (JMSException e) { System.out.println( "−−Receiver.onMessage: JMSException" 5 79 Chapter 22 : JMS + " caught\n" + e); } } } } Running JMSPublish as shown previously produces the following output, which is based on the JBoss 2. 4.1 implementation of JBossMQ, using the default setup and default connection factories and topic: >java JMSPublish TopicConnectionFactory topic/testTopic "Test message from JMSPublish"... put in * properties for: * java. naming.provider.url * java. naming.factory.initial * java. naming.factory.url.pkgs */ Context ctx = new InitialContext(); tcf = (TopicConnectionFactory) ctx.lookup(tcfName); // Create a connection with the factory tcon = tcf.createTopicConnection(); // Create a TopicSession with the connection tsession = tcon.createTopicSession( 578 Chapter 22 : JMS false, Session.AUTO_ACKNOWLEDGE);... undo changes they have made In this chapter, we will look at transaction−processing basics and, more formally, at transaction processing in J2EE We will also look at how to use the Java Transaction API (JTA) and Java Transaction Service (JTS) with Enterprise JavaBeans in your applications To help you understand the history behind JTS and JTA, we will also briefly touch on a couple of distributed transaction–processing... changes are shown) JMSPublish Here is the complete listing for JMSPublish It sends the specified message to the given topic a number of times import import import import javax.jms.*; javax.naming.InitialContext; javax.naming.Context; javax.naming.NamingException; /** * JMSPublish is a simple example of an application that * publishes a number of messages to a given topic It * uses the publish/subscribe . receives. import javax.jms.*; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import java. io.IOException; /** Chapter 22 : JMS 576 * JMSSubscribe. that information. Table 22 −4 describes each field — what it is used for and how it is set. Table 22 −4: Message header fields Field Name Set By Description JMSDestination Send method Chapter 22 : JMS 567 Specifies. message to the given topic a number of times. import javax.jms.*; import javax.naming.InitialContext; import javax.naming.Context; import javax.naming.NamingException; /** * JMSPublish is a

Ngày đăng: 12/08/2014, 19:21