Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
311,92 KB
Nội dung
private static class Redelivery { RemoteSubscriberIF subscriber; Serializable message; Serializable topic; long timeOfOriginalFailure; Date nextRedeliveryTime; Redelivery(RemoteSubscriberIF subscriber, Serializable message, Serializable topic) { this.subscriber = subscriber; this.message = message; this.topic = topic; this.timeOfOriginalFailure = System.currentTimeMillis(); this.nextRedeliveryTime = new Date(timeOfOriginalFailure); } // constructor } // class Redelivery Here is the RedeliveryAgent class. In order to support asynchro- nous redelivery attempts, the RedeliveryAgent class implements the Runnable interface. This allows it to have its own thread. private static class RedeliveryAgent implements Runnable { private TreeMap schedule = new TreeMap(); A RedeliveryAgent object uses a TreeMap to maintain a collec- tion of redelivery objects in the order in which their redelivery is sched- uled. The RedeliveryAgent constructor starts the thread that will be responsible for redelivery attempts. RedeliveryAgent() { new Thread(this).start(); } // constructor() Here is the method that schedules redelivery attempts. synchronized void scheduleRedelivery(Redelivery r) { long nextRedeliveryTime = System.currentTimeMillis()+REDELIVERY_INTERVAL; long elapsedTime = nextRedeliveryTime-r.timeOfOriginalFailure; if (elapsedTime>EXPIRATION_INTERVAL) { // Too much time has elapsed; give up. return; } // if r.nextRedeliveryTime.setTime(nextRedeliveryTime); schedule.put(r.nextRedeliveryTime, r); notify(); } // scheduleRedelivery(Redelivery) 192 ■ CHAPTER SIX The scheduleRedelivery method always schedules the next redeliv- ery attempt into the future by a fixed amount of time. Many applications will run more efficiently with a more sophisticated policy for determining the time of the next redelivery. Such policies typically involved strategies such as randomization and using progressively longer intervals between redelivery attempts. The run method contains the top-level logic for making redelivery attempts. It waits for the next scheduled redelivery attempt. When the time comes, it attempts to deliver the scheduled message. If the attempt fails, it calls scheduleRedelivery to schedule the next redelivery attempt. public void run() { while (!Thread.currentThread().isInterrupted()) { Redelivery r; try { r = waitForNextRedeliveryTime(); } catch (InterruptedException e) { return; } // try try { r.subscriber.deliverMessage(r.message, r.topic); } catch (RemoteException e) { scheduleRedelivery(r); } // try } // while } // run The last method in this example is called to get the next scheduled redelivery. If no message is scheduled for redelivery, it waits until there is one. If a message is scheduled for redelivery and its time for redelivery has not come yet, it waits. Otherwise, it attempts a redelivery. If the redelivery is unsuccessful, it schedules the next redelivery for the message. Then it checks again for the next redelivery. private synchronized Redelivery waitForNextRedeliveryTime() throws InterruptedException { while (true) { if (schedule.size()==0) { wait(); } else { Date when = (Date)schedule.firstKey(); long nextRedeliveryTime = when.getTime(); long now = System.currentTimeMillis(); if (nextRedeliveryTime>now) { return (Redelivery)schedule.remove(when); } else { wait(nextRedeliveryTime-now); } // if Distributed Computing Patterns ■ 193 } // if size } // while } // waitForNextRedeliveryTime() } // class RedeliveryAgent } // class ReliablePublisher RELATED PATTERNS Object Request Broker. The Retransmission pattern is often used with the Object Request Broker pattern to deliver messages to remote objects. Mailbox. The Mailbox pattern provides an alternate solution for the reliable delivery of messages. High Availability. You can use the High Availability pattern to min- imize the likelihood that a DeliveryAgent object will crash or become otherwise unavailable. Process Pair. The Process Pair pattern describes a way to ensure that a DeliveryAgent object is automatically restarted after a crash. Publish-Subscribe. The Retransmission pattern is often used with the Publish-Subscribe pattern to ensure reliable delivery of mes- sages. 194 ■ CHAPTER SIX SYNOPSIS You need to provide reliable delivery of messages to objects. Facilitate the delivery of messages by storing messages for later retrieval by each re- cipient. CONTEXT Suppose that you work for an advertising agency. One way that the adver- tising agency makes money is by buying advertising time on TV, radio, and Web pages on behalf of its customers. The agency’s customers prefer to buy advertising through the agency rather than directly for two reasons. • The agency buys advertising time on behalf of many customers. Because of that, it buys advertising time in greater quantity than any one customer would. Because of the large volume of advertising time the agency buys, it is able to negotiate better prices than its cus- tomers can by negotiating individually. • The value of advertising time to an advertiser is determined by how many people are expected to see the advertisement and how many of these people are the sort whom the advertiser expects to buy its prod- uct. For example, advertising time on a financial news TV show will be much more valuable to a manufacturer of luxury cars than to a toy manufacturer. By being able to accurately predict the quantity and type of people that will see an ad, the agency is able to get better results from ads than the advertisers themselves would be. Advertising agencies use professional negotiators to negotiate the purchase of advertising time. They often do this working face-to-face with sellers of advertising. To get the best deal for the advertisers, they use a computer program running on a portable computer. The program deter- mines the value of advertising time to each of their advertiser clients. To make this determination of value, the program requires a great deal of information. To be as accurate as possible, the information must be as up-to-date as possible. Because the computer on which it runs is mobile, the program is not always able to connect to its source of infor- mation. Distributed Computing Patterns ■ 195 Mailbox You must ensure that the program receives all information sent to it, whether or not the information source is able to connect to the program when it sends information. The architecture shown in Figure 6.10 is used to provide reliable delivery of the information to the program. The way it works is that InformationSource objects send informa- tion to a DistributionServer object. Instances of the program poll the DistributionServer object for new information when they are able to connect to the DistributionServer object. The negotiation process is specialized by advertising medium. Negotiations for TV, radio, print media, and Internet are conducted sepa- rately. For that reason, the set of information needed by each instance of the program depends on the specialization of the negotiator using it. For that reason, each piece of information is addressed only to the negotiators who will need it. When each instance of the program polls for new information, it receives only information that is addressed to the negotiator using it. FORCES ⁄ Asynchronous delivery of messages is desirable. ⁄ It is not always possible to establish a connection with the intended recipient of a message. ⁄ It is acceptable for messages to be delivered an indefinite amount of time after they are originally sent. ⁄ Messages must be delivered to remote recipients. ⁄ You want to minimize the resources required to send a message to multiple recipients. ⁄ Messages are sent at sufficiently regular intervals that when the recip- ients poll for messages, much of the time there will be messages wait- ing for them. ⁄ Communication between remote objects is less reliable than commu- nication between local objects. There is usually less bandwidth avail- able for communication between remote objects than between local 196 ■ CHAPTER SIX :DistributionServer :InformationSource :AnalysisProgram 1A: SendInformation 1B: PollForInformation FIGURE 6.10 Reliable delivery of Information. objects. In the extreme case, remote objects may be able to communi- cate only a small portion of the time. ⁄ It is more efficient of bandwidth to deliver multiple messages to a recipient as a single batch than it is to deliver them individually. ⁄ Ensuring reliable delivery means that it should be possible for a mes- sage to be delivered after the message source has stopped running. Ÿ If messages are sent at very irregular intervals, most of the time a potential recipient polls for messages there will be none, which is a waste of bandwidth. Ÿ If a large number of potential recipients poll for messages at the same time, the server polled may be overwhelmed. SOLUTION Message sources send messages to a mailbox server along with a tag indi- cating the message’s intended recipient. Potential message recipients poll the mailbox server for messages. Figure 6.11 shows the roles played by classes and interfaces in this pattern. Here are descriptions of the roles in Figure 6.11 that classes and interfaces play in the Mailbox pattern: MessageSource. Classes in this role originate messages. They pass the messages to a possibly remote object that implements the MailboxIF interface along with a list of the message’s intended recipients. MailboxIF. Classes in the MailboxServer role implement this interface. Such classes are responsible for storing messages until recipient objects poll for them. MailboxServer. Classes in this role implement the MailboxIF interface and are responsible for storing messages until a Recipient object polls for them. RecipientID. Objects in this role identify a unique Recipient object. Mailbox. MailboxServer objects maintain a collection of objects in this role. Each Mailbox is associated with a different RecipientID. Each Mailbox collects messages associated with its RecipientID. Messages associated with more than one RecipientID are collected in the mailbox associated with each of the RecipientID objects. Message. Classes in this role encapsulate messages. Recipient. Classes in this role are responsible for polling objects that implement the MailboxIF interface for messages. Distributed Computing Patterns ■ 197 RecipientID objects identify instances of these classes. When Recipient objects poll a MailboxIF object for messages, they present it with the RecipientID objects that identify them. CONSEQUENCES ⁄ The Mailbox pattern provides reliable delivery of messages. ⁄ Making message delivery the responsibility of an object dedicated to message delivery rather than the responsibility of the message source provides some important benefits. Even if it takes a long time to suc- cessfully deliver a message, the program that initiated a message is free to terminate before the message is delivered. Also, the efforts to deliver the message do not take resources away from the program that was the message source. The message source does not even have to know the quantity or identity of its message’s recipients. 198 ■ CHAPTER SIX MessageSource MailboxServer Passes-messages-to Mailbox Organizes-messages-by-recipient Message 1 * 0 * RecipientID Contains * * Identifies-recipient-for 1 * * Recipient Polls-for-messages * * Identifies 1 1 «interface» MailboxIF ▲ ▲ ▲ ▲ ▲ ▲ FIGURE 6.11 Mailbox pattern. ⁄ The use of the Mailbox pattern may consume less network bandwidth than the Publish-Subscribe pattern. The Publish-Subscribe pattern uses network bandwidth for delivery attempts that fail. The Mailbox pattern does not have this overhead. ⁄ When Recipient objects poll for messages, they may receive more than one message. By making it more likely that Recipient objects will receive multiple messages using a single connection, the use of network bandwidth is further reduced. ⁄ Changing the actual Mailbox class used is transparent to MessageSource and Recipient objects because of the way the pat- tern uses interfaces. Ÿ There is generally a delay between the time a message is sent and the time it is received. Most of the delay is attributable to the time between successful polling attempts by the recipient. IMPLEMENTATION Usually, the Mailbox pattern is implemented by buying software for that purpose rather than writing an implementation from scratch. Implementing the pattern reliably and with all of the features you want is usually more expensive to do in-house than it is to buy. In order to provide reliable delivery of messages, a MailboxServer must store messages in a reliable way until a Recipient object polls for them. To do that, messages and Mailbox objects must be stored on non- volatile storage, such as a disk file. MailboxServer classes may be implemented to accept only messages associated with RecipientID objects that it has prior knowledge of. Alternatively, MailboxServer classes may be implemented to accept mes- sages associated with any RecipientID object. This is largely a trade-off between security and the needs of the application. The security risk is that a MailboxServer object may become flooded with messages for a nonexistent RecipientID that is never polled for. There are other reasons messages may arrive at a MailboxServer object without being polled for. A common strategy to prevent such messages from becoming a problem is to delete such unpolled-for messages after a predetermined amount of time has passed. Another security consideration may be authenticating Recipient objects. In some environments, there is a risk that malicious Recipient objects will poll for messages that are not intended for them. In such environments, you will need a way to verify that a Recipient object is entitled to receive messages associated with each RecipientID that it polls for. Distributed Computing Patterns ■ 199 KNOWN USES E-mail is one of the oldest examples of the Mailbox pattern and also the source of the name. Most e-mail systems collect messages in mailboxes until people read them. Electronic Data Interchange (EDI) messages are often sent using the Mailbox pattern. IBM’s MQSeries software supports message distribution using the Mailbox pattern. CODE EXAMPLE Here are some classes that provide a very basic implementation of the Mailbox pattern. They are designed to communicate with message sources and recipients using RMI. We begin with the MailboxIF interface: public interface MailboxIF { public void sendMessage(Serializable msg, String[] recipients) throws RemoteException; public ArrayList receiveMessages(String[] recipients) throws RemoteException ; } // interface MailboxIF This MailboxIF interface has two methods. The sendMessage method is called by message sources. They pass it a message to send and an array of recipient IDs identifying the mailboxes to place the messages in. Recipient objects call the receiveMessages method and pass it an array of recipient IDs. The recipient IDs identify the mailboxes to poll for messages. This implementation of the Mailbox pattern accepts any object as a message if its class implements the Serializable interface. More sophis- ticated implementations of the Mailbox pattern impose more structure on messages. This implementation of the Mailbox pattern uses strings as recipient IDs. Here is an implementation of the MailboxServer class: public class MailboxServer extends UnicastRemoteObject implements MailboxIF { private Hashtable mailboxes; The implementation uses a Hashtable to organize its mailboxes. /** * Send a message to the given list of recipients. */ 200 ■ CHAPTER SIX TEAMFLY Team-Fly ® public void sendMessage(Serializable msg, String[] recipients) { for (int i=0; i<recipients.length; i++) { Mailbox m = (Mailbox)mailboxes.get(recipients[i]); if (m!=null) { // if recipient is registered m.addMessage(msg); } // if } // for } // sendMessage(Serializable, String[]) This implementation ignores requests to send messages to recipients that do not already have mailboxes set up. Mailboxes are set up by sepa- rate methods for administering mailboxes. Here is the method that recipients call to poll for messages. /** * Receive messages intended for a given set of recipients. * @return An array of messages. */ public ArrayList receiveMessages(String[] recipients) throws RemoteException { ArrayList outgoing = null; for (int i=0; i<recipients.length; i++) { Mailbox m = (Mailbox)mailboxes.get(recipients[i]); if (m!=null) { if (outgoing==null) { outgoing = m.getMessages(); } else { outgoing.addAll(m.getMessages()); } // if outgoing } // if m } // for if (outgoing==null) { return new ArrayList(); } else { return outgoing; } // if } // receiveMessages(String[]) Here are the administrative methods for adding and removing mail- boxes. Note that these methods are not part of the MailboxIF interface, so message sources and recipients cannot call them. /** * Register a recipient id so that it has a mailbox. */ public void registerRecipient(String recipient) { mailboxes.put(recipient, new Mailbox()); } // registerRecipient(String) /** * Unregister a recipient so that it doesn’t have a Distributed Computing Patterns ■ 201 [...]... HeartbeatException(); } // if } // try } // read(byte[], int, int) The read method uses the readInt method to read the byte counts that the server inserts into the data stream private final int readInt() throws IOException { InputStream in = this .in; int c1 = in. read(); int c2 = in. read(); int c3 = in. read(); int c4 = in. read(); if ((c1 | c2 | c3 | c4) < 0) throw new EOFException(); ... InputStream named HeartbeatInputStream In addition to handling the protocol, HeartbeatInputStream objects also monitor the arrival of heartbeat messages public InputStream getInputStream() throws IOException { if (myInputStream==null) { synchronized (this) { if (myInputStream==null) { InputStream superIn; superIn = super.getInputStream(); myInputStream = new HeartbeatInputStream(superIn); } // if } // synchronized... items It includes a KitchenSink class that contains attributes that are always needed on both the client and the server Kitchen sink attributes that clients need only occasionally are in the KitchenSinkData class On the server, instances of the KitchenSink class always have an associated instance of the KitchenSinkData class On the client, instances of the KitchenSink class download an associated instance... accessing objects behind it The Façade pattern is described in Volume 1 Distributed Computing Patterns ■ 209 Heartbeat SYNOPSIS While a remote object is performing an operation on behalf of a client, periodically send a message back to the client indicating that the remote object is still alive CONTEXT Suppose you work for a company that sells enterprise software applications You are involved in design. .. usually use into a separate object that is not downloaded unless needed You organize the classes of objects the client will be downloading as shown in Figure 6.12 Figure 6.12 shows how you organize the class for just one kind of item, a kitchen sink A similar organization applies to many other kinds of 204 ■ C HAPTER S IX KitchenSink KitchenSinkData Uses ▲ -basinCount:int 1 +getBasinCount( ):int 0 1... private static final int TIMEOUT = 30 000; private ServerIF server; private HeartbeatListener heartbeatListener; The client begins operation by getting a remote reference to the server and creating a HeartbeatListener object In this case, it does these things in its constructor Client(String serverHost) throws RemoteException, UnknownHostException, NotBoundException, MalformedURLException { String urlName... used in independent proprietary projects in four different companies that the author knows of CODE EXAMPLE Data classes usually declare only instance variables The logic that manipulates their content is in the corresponding SharedItem class Distributed Computing Patterns ■ 207 class Data implements Serializable { int dataAttribute1; String dataAttribute2; } // class Data Here is the corresponding... for a company that operates a chain of superstores that sell building materials, hardware, floor coverings, appliances, and everything else you would need to build and furnish a house To promote the sale of kitchen cabinets and appliances, you have been given the task of designing an application that customers will use to design a kitchen and then order everything in the design with the push of a button... RMI communicating over SSL.† *Section 3. 1 of the RMI specification for Java 1.2 says that the first thing a stub does when its method is invoked is that it “initiates a connection with the remote VM containing the remote object.” † Secure Sockets Layer (SSL) is a protocol that provides secure transmission of data It is designed to be transparent to application protocol layers SSL is defined by RFC 2246,... organize them into a second Data object An extreme situation is having a data attribute whose value involves so much data that it is worth managing its download individually Individually managed attributes involve download logic similar to the logic for Data objects The difference is that the client object has an instance variable that directly references the data rather than referencing a Data object . just one kind of item, a kitchen sink. A similar organization applies to many other kinds of Distributed Computing Patterns ■ 2 03 Heavyweight/Lightweight items. It includes a KitchenSink class. KitchenSink class always have an associated instance of the KitchenSinkData class. On the client, instances of the KitchenSink class download an associated in- stance of the KitchenSinkData class. they 204 ■ CHAPTER SIX KitchenSink -basinCount:int +getBasinCount( ):int 0 1 KitchenSinkData weight material Uses 1 ▲ FIGURE 6.12 Class organization. do not usually use, except for instance variables