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

Mastering Enterprise JavaBeans™ and the Java 2 Platform, Enterprise Edition - Roman E

..pdf
Скачиваний:
41
Добавлен:
24.05.2014
Размер:
6.28 Mб
Скачать

Understanding Java Remote Method Invocation (RMI) 543

*/

Registry reg = LocateRegistry.createRegistry(port);

/*

* Bind our Message Queue object to the registry */

reg.rebind("MessageQueue", this);

System.out.println("MessageQueue now in ready mode.");

}

/**

*Creates a new channel (queue) for a particular client.

*@return The new channel

*/

public Channel createChannel(String name) throws MessageQueueException { try {

Channel channel = new Channel(name);

/*

*Create the queue for the channel, and store it

*in the hashtable.

*/

Queue queue = new Queue(); dataHash.remove(channel); dataHash.put(channel, queue);

System.out.println("Channel " + channel.getName() + " created.");

return channel;

}

catch (Exception e) {

throw new MessageQueueException(e);

}

}

/**

* Call to close channel */

public void destroyChannel(Channel channel) throws MessageQueueException { System.out.println("Channel " + channel.getName() +

" is now closed.");

try { /*

* Take the channel off the hashtable */

Object obj = dataHash.remove(channel);

Source A.7 MessageQueue.java (continues).

Go back to the first page for a quick link to buy this book online!

544 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

/*

*Signal any threads that were

*waiting on that channel

*/

if (obj instanceof Queue) { Queue queue = (Queue) obj; synchronized (queue) {

queue.notifyAll();

}

}

}

catch (Exception e) {

throw new MessageQueueException(e);

}

}

/**

*Gets a message off the queue. Blocks until one arrives.

*@param channel Channel name to get messages from

*@param timeout How long to block for max

*

* @return the next message, or null if time out */

public Object getMessage(Channel channel, long timeout) throws MessageQueueException {

try { /*

* Get the right queue off the hashtable */

Queue queue = Channel2Queue(channel);

/*

*Wait around until someone has a message for me.

*We synchronize threads in case other clients

*are trying to read/write to the channel. By

*synchronizing, they each have to wait their turn.

*We synchronize on the queue object rather than the

*entire class, so that other channels aren't

*affected by our activity.

*/

synchronized (queue) {

if (queue.isEmpty()) { queue.wait(timeout);

}

Source A.7 MessageQueue.java (continues).

Go back to the first page for a quick link to buy this book online!

Understanding Java Remote Method Invocation (RMI) 545

/*

* In case channel was destroyed.. */

if (queue.isEmpty()) { return null;

}

}

/*

* Pop the message off the queue, and return it. */

return queue.pop();

}

catch (Exception e) {

throw new MessageQueueException(e);

}

}

/**

*Puts a message onto the queue for a certain channel.

*@param channel Channel to put message on.

*@param message Message to put on the channel.

*/

public void putMessage(Channel channel, Object message) throws MessageQueueException {

try {

// Get the queue for this channel Queue queue = Channel2Queue(channel);

/*

*Stick the message in the queue.

*We synchronize threads in case other clients

*are trying to read/write to the channel. By

*synchronizing, they each have to wait their turn.

*We synchronize on the queue object rather than the

*entire class, so that other channels aren't

*affected by our activity.

*/

synchronized (queue) {

/*

* Push the message onto the queue. */

queue.push(message);

Source A.7 MessageQueue.java (continues).

Go back to the first page for a quick link to buy this book online!

546 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

/*

*There's a new message, so signal

*any waiting threads. Of course, if

*multiple threads are waiting, only one

*of them will acquire the new lock

*because they're all waiting inside of

*critical sections.

*/

queue.notifyAll();

}

}

catch (Exception e) {

throw new MessageQueueException(e);

}

}

/*

*Gets a queue based upon a channel. Used internally.

*@param channel The channel for the queue you want to get

*/

private Queue Channel2Queue(Channel channel) throws Exception {

/*

* Get the queue off the hashtable and return it. */

Object obj = dataHash.get(channel); if (obj instanceof Queue) {

return (Queue) obj;

}

else {

throw new Exception("Error: No such channel: " + channel.getName() + ".");

}

}

}

Source A.7 MessageQueue.java (continued).

The QueueClient Class

Finally, we write a sample piece of code that uses the Message Queue, embodied in the QueueClient class. The client code starts up three threads: Two threads write to a channel, and the third reads data from the channel. This is shown in Source A.8.

Go back to the first page for a quick link to buy this book online!

Understanding Java Remote Method Invocation (RMI) 547

Objectspace’s JGL and the Java Collections Framework

If you noticed, we used Objectspace’s Generic Collections Library (JGL) 3.1.0 for our Message Queue’s internal queue. JGL is an example of a collections framework. A collections framework is useful for representing and manipulating collections, or groups of objects, in a very object-oriented fashion.

Collections frameworks have three main notions:

■■The interface to a collection of objects

■■Specific data structure implementations of interfaces

■■Specific algorithms that can be applied to a collection

For example, by using the JGL, you can create a data structure such as a queue and then apply an iterator to iterate over the items in the queue. But just as easily, you could apply an iterator to a stack instead. You could also apply a sorting algorithm on a doubly linked list structure. The possibilities are endless.

In fact, you get a free collections framework built into the Java 2 platform: the Java Collections Framework. Java Collections have the advantage that they’re very easy to understand and use. But JGL is much more powerful. In fact, we could have implemented our entire Message Queue very simply by combining Objectspace’s powerful networking technology, Voyager, with JGL.

This book’s Web site provides links for more information about both JGL and Java Collections.

package com.wiley.compBooks.roman.rmi.mq;

import java.rmi.Remote;

import java.rmi.RemoteException; import java.rmi.Naming;

public class QueueClient extends Thread {

public static void main (String[] args) {

IMessageQueue queue = null;

if (args.length != 2) {

System.err.println("Usage: Queue <hostname of MessageQueue" + " remote object> <port to connect to>");

System.exit(-1);

}

Source A.8 QueueClient.java (continues).

Go back to the first page for a quick link to buy this book online!

548 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

/*

* Set the security manager */

try {

System.setSecurityManager(new java.rmi.RMISecurityManager());

}

catch (java.rmi.RMISecurityException exc) { System.err.println("Security violation " + exc.toString()); System.exit(-1);

}

/*

*Get a handle to a remote MessageQueue object.

*We name this handle as an RMI URL.

*/ try {

String targetMachine = "rmi://" + args[0] + ":" + args[1] + "/MessageQueue";

System.out.println("Attempting to contact " + targetMachine);

/*

* Get the object from the remote RMI Registry */

Remote remoteObject = Naming.lookup(targetMachine);

/*

*Perform a quick check to make sure the object

*is of the expected IMessageQueue interface type

*/

if (remoteObject instanceof IMessageQueue) { queue = (IMessageQueue) remoteObject;

}

else {

throw new Exception(

"Bad object returned from remote machine");

}

}

catch (Exception e) {

System.err.println("Error in lookup() " + e.toString());

System.exit(-1);

}

try { /*

* Create a channel on the queue */

Channel channel = queue.createChannel("Log");

Source A.8 QueueClient.java (continues).

Go back to the first page for a quick link to buy this book online!

Understanding Java Remote Method Invocation (RMI) 549

/*

*Start up two senders and a logger. The senders

*will send messages to the queue, and the logger

*will receive messages from the queue.

*/

QueueClient sender1 = new QueueClient(queue, channel, true, "Sender #1", 333);

QueueClient sender2 = new QueueClient(queue, channel, true, "Sender #2", 1000);

QueueClient logger = new QueueClient(queue, channel, false, "Logger", 0);

/*

*Let the clients run for 10 seconds, then kill

*the channel.

*/

Thread.sleep(10000);

queue.destroyChannel(channel);

}

catch (Exception e) { System.err.println(e.toString());

}

}

/*

* Per-client local variables */

private Channel channel; private boolean sendMessages; private IMessageQueue queue; private String name;

private int delay;

/**

*Starts up a client to hit the queue.

*@param queue The queue to use.

*@param channel The channel to communicate on the queue

*@param sendMessages

*TRUE: Send messages to the channel.

*FALSE: Receive messages from the channel.

*@param name The name of this client.

*@param delay If sending, delay between sending messages

*/

public QueueClient(IMessageQueue queue, Channel channel, boolean sendMessages, String name, int delay) {

this.channel = channel; this.sendMessages = sendMessages;

Source A.8 QueueClient.java (continues).

Go back to the first page for a quick link to buy this book online!

550 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

this.queue = queue; this.name = name; this.delay = delay;

/*

* Start the client thread up */

start();

}

/**

*This method actually starts the client. This is

*automatically called from the constructor.

*/

public void run() { try {

/*

*If I'm a sender, then send messages to the queue.

*The message content is the name of this client,

*plus an incrementing variable.

*/

if (sendMessages) {

int i = 0;

while (true) { /*

*Remember that strings are auto-

*converted to Objects by the compiler! */

queue.putMessage(channel, name + ": " + i++); sleep(delay);

}

}

/*

*Otherwise, retrieve and log messages from

*the queue

*/ else {

while (true) {

String msg = (String) queue.getMessage(channel, 5000); if (msg != null) System.out.println(msg);

}

}

}

Source A.8 QueueClient.java (continues).

Go back to the first page for a quick link to buy this book online!

Understanding Java Remote Method Invocation (RMI) 551

catch (Exception e) {

System.err.println(e);

}

}

}

Source A.8 QueueClient.java (continued).

Compiling the Program

We compile the Message Queue using the normal javac compiler, and we then generate stubs/skeletons using rmic as follows:

rmic -d classes com.wiley.compBooks.MessageQueue.MessageQueue

This generates the needed MessageQueue_stub.class and MessageQueue_ skel.class proxies.

Running the Program

To start the Message Queue, we type:

java com.wiley.compBooks.MessageQueue.MessageQueue 5000

Here, 5000 is the port at which the RMI Registry is running.

Next, we need to run the Message Queue client program:

java com.wiley.compBooks.MessageQueue.QueueClient localhost 5000

When running the client, we need to specify the target machine where the Message Queue is running. In this example, localhost is the name of the (local) Message Queue server machine. We also need to specify the port (5000) at which it should look for the Message Queue object’s RMI registry.

The following is the output of the Message Queue:

MessageQueue starting up...

MessageQueue now in ready mode.

Channel Log created.

Channel Log is now closed.

Here is what the client program reports:

Attempting to contact rmi://foobar:5000/MessageQueue

security properties not found. using defaults.

Go back to the first page for a quick link to buy this book online!

552 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

Sender #1: 0

Sender #2: 0

Sender #1: 1

Sender #1: 2

Sender #2: 1

Sender #1: 3

Sender #1: 4

Sender #1: 5

Sender #2: 2

Sender #1: 6

Sender #1: 7

Sender #1: 8

Sender #2: 3

Sender #1: 9

Sender #1: 10

Sender #1: 11

Sender #2: 4

Sender #1: 12

Sender #1: 13

Sender #1: 14

Sender #2: 5

Sender #1: 15

Sender #1: 16

Sender #1: 17

Sender #2: 6

Sender #1: 18

Sender #1: 19

Sender #1: 20

Sender #2: 7

Sender #1: 21

Sender #1: 22

Sender #1: 23

Sender #2: 8

Sender #1: 24

Sender #1: 25

Sender #1: 26

Sender #2: 9

Sender #1: 27

Sender #1: 28

com.wiley.compBooks.MessageQueue.MessageQueueException: java.lang.Exception: Error: No such channel: Log. com.wiley.compBooks.MessageQueue.MessageQueueException: java.lang.Exception: Error: No such channel: Log. com.wiley.compBooks.MessageQueue.MessageQueueException: java.lang.Exception: Error: No such channel: Log.

What’s happened here? First, the client program created a channel on the Message Queue called “Log.” It then started three clients of the queue: Sender #1, Sender #2, and the Logger. The Senders each counted up from 0, and they put that number on the Message Queue, along with the Sender’s identifier. The messages sent

Go back to the first page for a quick link to buy this book online!