Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Professional Java.JDK.5.Edition (Wrox)

.pdf
Скачиваний:
31
Добавлен:
29.02.2016
Размер:
12.07 Mб
Скачать

Chapter 12

3.

4.

Create a message publisher.

Explicitly send the message.

The code that follows will walk you through each step in the process of sending a message.

To be able to send or receive messages, you need to create a Session with the JMS server. The Session object allows you to create the Message, MessageConsumer, and MessagePublisher objects for the specific send and receive tasks. The session object is created with the sequence of method calls found in Figure 12-1.

JMSClient

Context

ConnectionFactory

Connection

Session

lookup factory, queue

create connection

create

create session

create

Figure 12-1

The following is the code for creating a session as described in Figure 12-1:

connection.createSession(boolean transaction, int acknowledgement);

The previous code for creating a session is very important because it defines transaction support and message acknowledgment. The first parameter defines transaction support. If the session supports transactional messages and the second specifies how the client will acknowledge receipt of the messages sent. Message acknowledgment can either be done automatically per message or by client request (in a large batch). Once you have a reference to a Session object, you can use it to create a Message and a Message Publisher. Figure 12-2 shows the UML for sending a message once a session object has been created.

546

Distributed Processing with JMS and JMX

JMSClient

Session

MessagePublisher

create publisher

 

 

 

create

send message

Figure 12-2

The code for creating a publisher that was described in UML by Figure 12-2 is listed here for clarification:

MessagePublisher publisher = session.createPublisher();

publisher.send( session.createTextMessage(“message body”));

It is important to note from the code above that the publisher sent the message, not the session. This allows you to send and receive messages from the same session. By using the same session, the message can exist in the same transaction, which is important for fault-tolerant applications.

A JMS client can be notified when a message arrives at a JMS queue. The client must implement the

MessageListener interface from the javax.jms package.

The next section walks through this process, starting with Figure 12-3, which shows the conceptual process for registering to receive messages from a JMS system.

JMSClient

Session

MessageConsumer

Connection

create consumer

 

 

 

 

create

called for each

 

 

message in the queue

 

 

 

 

register

 

 

 

 

start

 

 

 

on message

 

Figure 12-3

547

Chapter 12

Now, take a look at the specific code that is involved with the collaboration described in Figure 12-3. The class that registers with the JMS server must implement the MessageListener interface found in the javax.jms.* package. You pass a reference to a message listener to the Consumer and the consumer will call back the messageListener as messages become available. The callback is specified by the Messagelistener interface by the method onMessage(Message m). The code for registering as a message consumer follows. Please note the start() method. This method is used to tell the JMS server to start sending messages to the registered client class. This will be covered in detail in the example application:

MessageConsumer consumer = session.createConsumer(queue); consumer.addListener( this );

consumer.start();

From this section, you have learned the important conceptual differences between a queue and a topic, as well as how to send and receive messages using a JMS system. That is a large percentage of the JMS object model. The next section looks at the overview of JMX architecture and the capabilities it provides to the application developer.

JMX Fundamentals

In this section of the chapter, the fundamentals of the JMX architecture will be looked at. After reading this section, you will understand the capabilities that JMX provides the application developer, an overview of the architecture, and how to create your own JMX components that can leverage these management capabilities.

Java Management Extensions (JMX) is a framework that allows you to expose the methods of a Java object to other application. The Java objects that you expose are called MBeans. MBeans are the building blocks of JMX. An MBean is deployed to a JMX Agent where it is managed. The Agent provides a common set of services to interact with the MBean. These common services provide the application developer with a large number of capabilities.

Some of the capabilities available to an MBean follow:

The agent allows the properties of an MBean to be read as well as changed remotely at run time.

The agent allows the methods of an MBean to be invoked at run time.

The agent allows the MBeans to be deployed and undeployed at run time.

Hopefully, these capabilities will give you some insight into how powerful JMX can be for building a distributed processing system. The application built in the upcoming section will consist of MBeans that can be managed remotely. By taking advantage of these capabilities you can remotely deploy additional processing components across several servers at runtime. Before moving to the example in this chapter, there ought to be a further investigation of the JMX architecture and the naming convention an MBean must adhere to in order to comply with the architecture.

Figure 12-4 is a logical depiction of the JMX architecture.

The architecture is logically divided into an Agent layer and an Instrumentation layer. The instrumentation layer is a collection of MBeans that provide the functionality that your application requires. This is supported by the Agent layer providing a common set of services for each component. These services handle component registration, event notification, and monitoring.

548

Distributed Processing with JMS and JMX

HTTPAdaptor

RmiAdaptor

CustomConnector

 

 

 

Agent Layer

 

MBean Server

 

 

 

Monitoring

Notification

Registration

CustomMBean

 

Instrumentation

 

Layer

CustomMBean

 

 

 

 

 

 

JVM

Figure 12-4

In order to use an MBean, it must be deployed to an MBeanServer. All communication with an MBean is done indirectly through the server. This server has a standard interface for manipulating MBeans. This standard communication is extended one step further with the use of MBean Adaptors and Connectors. An Adaptor communicates with an MBeanServer using a standard protocol. In the example later in this chapter, an HTTPAdaptor will be used to communicate with deployed MBeans using a standard Web browser.

The next three sections will describe the specifics of the JMX architecture, including using standard MBeans, deploying an MBean for management, and using Adaptors and Connectors.

Using Standard MBeans

An MBean is made up of an interface and an implementing class. The interface and class must subscribe to a specific standard so that it can be managed by an MBeanServer. The following are the standard rules to which an MBean must subscribe:

The Interface must have the same name as the implementing class plus an MBean Suffix.

The Interface must reside in the same package as the implementing class.

The following code is an example of a standard MBean interface. In this example, the MBean interface exposes one read-only property, isRunning, and two operations, stop() and start(), to the MBeanServer:

package wrox.processing.jmx; public interface ExampleMBean {

public boolean isRunning();

public void stop(); public void start();

}

549

Chapter 12

The next section of code shows the implementing class. Note the class names and package declarations:

package wrox.processing.jmx;

public class Example implements ExampleMBean { private Boolean running;

public Boolean isRunning() { return running;

}

}

In the example that will be created, four more MBeans provide various applications logic in support of the business process. This section provided an example of a standard MBean; there are other types of MBeans that are beyond the scope of this chapter, however, the same principles apply by complying with the standard common services and management that are available through the JMX architecture. The next section will describe the process of deploying an MBean to an MBeanServer.

Deploying MBean for Management

The MBeanServer is the heart of the Agent layer of the JMX Architecture. It provides the ability to register an MBean. This makes them available to other components that can connect to the MBeanServer.

The interaction with the server takes place through the MBeanServer interface. The next code listing shows an abbreviated version of the methods available in the MBeanServer. This interface allows you to invoke methods on an MBean that has been deployed through the server. Methods of an MBean are invoked indirectly via the MBeanServer:

public Object getAttribute(ObjectName on, String name); public void setAttribute(ObjectName on, Attribute att);

public Object invoke(ObjectName on, String method, Object[] param, String[] sig); public ObjectInstance registerMBean(Object obj, ObjectName on);

public Set queryMBeans(ObjectName on, QueryExp qe);

The server identifies each MBean through a unique name assigned when it is registered with the server. This is called the objectName. It is made up of two parts: the domain and the keys separated by a colon (:). In the example that follows, the domain is processing and the key is name=message-processor. An object name can have any number of keys separated by a comma (,):

BeanServer server= MBeanServerFactory.createMBeanServer();

ObjectName objectname = new ObjectName( “processing:name=message-processor”); server.register( new MessageProcessor(), objectName );

Once an MBean has been registered with the MBeanServer, it is possible to get and set attributes, invoke methods, and query for an MBean using the ObjectName. For example, to invoke the method public void read(String file) on an MBean registered with the name processing:name=message-processor, you would execute the following line of code:

ObjectName on = new ObjectName(“processing:name=message-processor”); Object[] args = { “file.txt”};

String [] sig = { “java.lang.String”}; server.invoke( on, “read”, args,sig);

550

Distributed Processing with JMS and JMX

The previous code is fairly long-winded for the invocation of a single method. Fortunately, there are several adaptors available that make interacting with an MBean easier. This is discussed in the next section on adaptors and connectors.

Using Adaptors and Connectors

An adaptor exposes the MBeanServer to other applications external to the JMX Agent. The adaptor communicates via a defined protocol. The MBeanServer is exposing MBean to external applications using the adaptor. Every JMX agent needs to deploy at least one adaptor.

There are several Adaptors available that support various protocols. These include HTTP for Web-based management, RMI for remote method invocation, and SNMP for communicating with network devices such as routers and switches. This chapter will work with an HttpAdaptor allowing the management of the example through a Web browser. The HttpAdaptor is used extensively in the “Deploying the Application” section of this chapter.

This concludes the “Basic Concepts” section of this chapter. The next section will show how to design and build an application using these two technologies and implement an order-processing system.

Building a Distributed Application

The objective of this chapter, and specifically this section, is to build a flexible distributed processing application. By now it should be clear why you are using JMS and JMX to accomplish this task. JMS allows you to partition work requests into messages and distribute these messages to numerous processing nodes seamlessly across a network of computers. Furthermore, your processing components will be built as MBeans. This allows you to monitor and communicate with them remotely at run time.

The example application will show how to perform the business process described in Figure 12-5.

 

Check

 

 

Receive

Inventory

Ship

Ready to

Order

for each

Order?

Ship

 

Item

 

 

Reject

Figure 12-5

The goal of the example is to build three components that implement the messaging behavior. The result will be an abstraction that separates the JMS messaging logic from the actual business logic specific to

551

Chapter 12

the business process. These fundamental message components can then be tied together in various ways to support different, more complex, business processes.

The three components in the JMS processing architecture example define the system responsibilities required to process messages, route messages, and split and aggregate messages. Each processing step is mapped to a messaging component. The following diagram in Figure 12-6 shows how the example messaging components are mapped to the example business process.

Message Flow

Order enters system

 

 

 

 

 

JMS Message

receive-order

 

order-items

complete-items

complete-order

ship-order

Queues

 

 

 

 

 

 

 

JMX Message

 

 

 

 

 

 

Processing

 

split

process

aggregate

route

reject-order

Components

 

 

 

 

 

 

The software components of the processing system are loosely tied together using message queues.

Figure 12-6

There are several benefits to this design. The primary benefit of this design is scalability. Any number of components running on several different physical machines can process a message from a queue. This creates a location-independent processing architecture. In addition, components have no direct dependencies. All dependencies are established by receiving and sending messages between queues. This is an example of a loose coupling of system components. There is also a significant amount of design flexibility. Changing the flow of messages between components can be done without modifying the components themselves, but by simply changing the queue.

The next section will discuss the various types of messages that are available through JMS. Once a type is selected that matches the criteria, the sections that follow will describe in the detail how to build the three types of messaging components used in the example.

Deciding on the Message Type

Before beginning the component design, it is important to select a message type appropriate to your processing requirement. Choosing a message type is important because it affects the persistence, performance, and interoperability of the application.

The three types of JMS messages are described by the contents they can transport. They include the following:

ObjectMessage allows any serialized object to be passed as the payload of a JMS message.

MapMessage provides a hashmap of properties, useful when sending flat data that can be represented as name value pairs.

Text Message can store a Java string, which lends itself to sending messages represented as XML.

ObjectMessage allows you to wrap any serializable Java object within a message and pass it between destinations.

552

Distributed Processing with JMS and JMX

Of the three message types provided by JMS, the ObjectMessage type is the easiest to implement in a pure Java environment. However, there can be issues persisting Java objects. For example, a message history needs to be saved; it will be persisted as a binary object in the underlying relational storage system. If the class definition of the object message changes over time, the older message stored would no longer be retrievable.

It’s for that reason that the text Message approach will be used in this example. Plus, by using XML text messages you gain XML’s structure and flexibility. In addition, XML text messages lend themselves well to integration with a Web service interface.

Since the focus of the application is to distribute computer processing work across several computers on a network, this application will use queue as its JMS destination. Remember, a queue is a point-to-point communication model. Once a message is taken from a queue, no other queue consumers will receive the message. This allows you to divide and conquer requests across several message consumers.

Understanding the Three-Component Architecture

The component architecture will support any business process. The application will implement an order processing example. The application itself will model the behavior of a business process. A business process is really just a collection of steps. In this example, those steps fall into one of three categories. The categories are processing, routing, and splitting and aggregating. Each category will be abstracted and modeled as a JMX component.

The design goal of this application is to create an abstract business process — for example, if you needed to process documents into a search index. It’s possible to extend the processing component described in this application to suit your specific needs. By doing that you will be able to leverage the processing scalability gained from working with queues, as well as the manageability of working with the JMX framework with very little infrastructure code.

The next three sections will describe how to build the three MBeans required to implement your application. The message components deployed as MBeans are the following:

The MessageProcessor

The MessageRouter

The MessageSplitter and Aggregator

These three components represent the abstract behavior of most any business process. The concepts expressed are based on design patterns from Enterprise Integration Patterns by Gregor Hohpe. The following sections will show what is required to build on each of these three components. Each component section will examine the classes and interfaces required to implement the component. For each class, the code will be divided into logical units and discussed. The complete code listing can be downloaded from the publisher’s Web site.

Creating a Component to Process JMS Messages

The first component to tackle will be the message processing component. A message processing component performs three functions: It takes a message from a source queue, performs work on that message, and then puts the resulting message on a destination queue. Figure 12-7 shows the UML design of the message processor component.

553

Chapter 12

 

«interface»

 

 

 

 

 

 

 

 

MessageProcessorMBean

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

+isRunning() : boolean

 

 

 

 

 

 

 

 

+start()

 

 

 

 

 

 

 

 

 

«interface»

 

 

+stop()

 

 

 

 

 

javax.jms::MessageListener

 

 

+setProcessor(in className : String)

 

 

 

 

 

 

 

 

 

 

 

+onMessage(in message : Message)

 

 

+getProcessor() : String

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

MessageProcessor

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

«interface»

 

-processor : Processable

 

 

 

-connection : Connection

 

 

 

 

 

Processable

 

 

 

 

 

 

 

-session : Session

 

 

 

+process(in text : String) : String

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

JMX Agent used to

 

 

 

OrderProcessor

 

 

 

deploy and manage

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

the MessageProcessorMBean

 

 

 

Agent

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

+main()

 

 

 

 

 

 

 

Figure 12-7

 

 

 

 

 

 

 

The following are a few things to take away from the design:

By leveraging the JMX architecture, you expose class methods so that they can be discovered and invoked at run time.

By leveraging a simple processable interface, you are able to create a separation of concern between the JMS message logic of the MessageProcessor and the business logic of the Order Processor class. Reducing the dependences between the JMS class and the business logic class increases the reuse of the message code.

Make sure the JMX naming conventions are followed when creating standard MBeans. The MessageProcessor and the interface MessageProcessorMBean need to be named identically, except for the MBean suffix on the interface. The MBean suffix needs to have the M and the B capitalized; otherwise it will not be recognized by the MBeanServer.

The following table shows the classes and interfaces that are involved in the message processing component.

554

 

 

Distributed Processing with JMS and JMX

 

 

 

 

Component

Responsibility

 

 

 

 

MessageProcessorMBean

The MBean interface defines the operations and properties

 

 

that will be exposed for management using the JMX standard

 

 

architecture.

 

MessageProcessor

The MessageProcessor is the implementing class of the MBean

 

 

interface. This class is responsible for sending and receiving

 

 

messages by connecting and registering with the JMS server.

 

Processable

The Processable interface removes the JMS dependencies from

 

 

the specific processing task, allowing the reuse of the Message-

 

 

ProcessingMBean.

 

OrderProcessor

OrderProcessor is a specific example of a class implementing the

 

 

processable interface. By implementing Processable interface, the

 

 

OrderProcessor class can focus on the business logic of the prob-

 

 

lem domain.

 

MessageListener

Message listener declares the onMessage method to be called

 

 

when a message arrives at a queue.

 

 

 

MessageListener

The message listener interface is part of the JMS specification. Having the MessageProcessor implement MessageListener allows the MessageProcessor to be registered with the JMS server when the connection to the JMS server is established. When a message arrives at a queue, the message is sent to one of the MessageListeners registered with that queue:

package javax.jms.MessageListener;

public interface MessageListener {

public void onMessage( Message message) ;

}

MessageProcessorMBean

The MessageProcessorMBean interface complies with the standard MBean naming conventions. It defines the methods that will be exposed to the JMX Agent. In the case of the Message processing component, it will publish the isRunning(), stop(), and start() methods. These methods can then be invoked at run time via any application that has access to the management agent. You will not write any code to interact with the JMX agent, instead, you will use the standard HTTPAdapter and

interact with the agent with a common Web browser. The following section shows the code for the MessageProcessorMBean interface.

First, the code that follows is the package declaration:

package wrox.processing.jmx;

The interface declaration for the MBean must match the <class name>MBean pattern of its implementing class and be in the same package. Because you are creating the MessageProcessor class from scratch, this is an easy requirement to satisfy; however, if you are deploying a legacy application, this may not be

555

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]