Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Applied Java™ Patterns - Stephen Stelting, Olav Maassen.pdf
Скачиваний:
198
Добавлен:
24.05.2014
Размер:
2.84 Mб
Скачать

per InputSource. The trick here is to create a key and let that key be registered with the Router as the

InputChannel, instead of the “real” InputChannel.

The source calls the send method on the Router with two parameters: the key and the actual message. The Router looks up the key and sends the message to the OutputChannels that it has just looked up.

Related Patterns

Related patterns include the following:

Mediator (page 77) – The Router is similar to the Mediator pattern. The difference is that the Mediator makes decisions based on the content of the message and can therefore be application specific. The Router makes decisions based on the source of the message.

Observer (page 94) – The Router pattern can be made more flexible by using the Observer pattern to allow listeners to be registered.

WorkerThread (page 231) – The Worker Thread can be applied to the Router to increase the efficiency.

Example

Note:

For a full working example of this code example, with additional supporting classes and/or a RunPattern class, see “ Router ” on page 540 of the “ Full Code Examples ” appendix.

The Router can be useful at various places in the example application. In almost every situation where there is more than one interested party in any event, you can use the Router. The Router is essentially an implementation of a listener structure; you will see some similarities.

The code for the Message class is shown here. It is a container for the source (an InputChannel) and the actual message—in this case, some String.

Example 4.25 Message.java

1.import java.io.Serializable;

2.public class Message implements Serializable{

3.private InputChannel source;

4.private String message;

5.

6.public Message(InputChannel source, String message){

7.this.source = source;

8.this.message = message;

9.}

10.

11.public InputChannel getSource(){ return source; }

12.public String getMessage(){ return message; }

13.}

Example 4.26 InputChannel.java

1.import java.io.Serializable;

2.public interface InputChannel extends Serializable{}

The OutputChannel is the interface that defines the method for sending the message to the target. Since the OutputChannel can be used to communicate between machines, it is defined as a remote interface.

Example 4.27 OutputChannel.java

1.import java.rmi.Remote;

2.import java.rmi.RemoteException;

3.public interface OutputChannel extends Remote{

4.public void sendMessage(Message message) throws RemoteException;

5.}

The Router uses a hashmap to store links between the specific InputChannel and various OutputChannels. When it receives a message, it looks up the destinations in its map.

176

It loops through the collection and sends the message to each of the destinations. In this example, the Router creates a worker thread (see “ Worker Thread ” on page 231) to send a message to each of its OutputChannel objects. Thread pools are often used to improve performance in applications such as these.

Example 4.28 Router.java

1.import java.rmi.Naming;

2.import java.rmi.RemoteException;

3.import java.rmi.server.UnicastRemoteObject;

4.import java.util.HashMap;

5.public class Router implements OutputChannel{

6.private static final String ROUTER_SERVICE_NAME = "router";

7.private HashMap links = new HashMap();

8.

9.public Router(){

10.try {

11.

UnicastRemoteObject.exportObject(this);

12.

Naming.rebind(ROUTER_SERVICE_NAME, this);

13.}

14.catch (Exception exc){

15. System.err.println("Error using RMI to register the Router " + exc);

16.}

17.}

19.public synchronized void sendMessage(Message message) {

20.Object key = message.getSource();

21.OutputChannel[] destinations = (OutputChannel[])links.get(key);

22.new RouterWorkThread(message, destinations);

23.}

24.

25.public void addRoute(InputChannel source, OutputChannel[] destinations) {

26.links.put(source, destinations);

27.}

28.

29.private class RouterWorkThread implements Runnable{

30.private OutputChannel [] destinations;

31.private Message message;

32.private Thread runner;

33.

34.private RouterWorkThread(Message newMessage, OutputChannel[] newDestinations){

35.

message = newMessage;

36.

destinations = newDestinations;

37.

runner = new Thread(this);

38.

runner.start();

39.

}

40.

 

41.public void run() {

42.

for (int i = 0; i < destinations.length; i++){

43.

try{

44.

destinations[i].sendMessage(message);

45.

}

46.

catch(RemoteException exc){

47.

System.err.println("Unable to send message to " + destinations[i]);

48.

}

49.

}

50.}

51.}

52.}

When using the Router pattern, be careful about the size of message to be delivered. Generally, the message should be as small as possible. It is easy to be fooled by some Java objects, though. An object might have references to other objects, which refer to other objects, and so on—and what seemed like a small object might turn out to be very large indeed. For instance, sending a java.awt.Button is not a good idea, because the whole GUI will be serialized and sent.

It's a lot like buying your child a toy in a store. The purchase of a single Outlaw Robot Laser Geek might not seem expensive at first, but by the time you get all the accessories (extra pocket protector, laser-spitting hornrimmed glasses), you might wonder if it would just be cheaper to buy him or her a sweater.

177