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

Pattern Variants

Two-phase commit – The transaction manager wants to be sure that all participants can commit before it calls commit on them. So before calling commit, it first performs a voting round where each participant tells the manager if it can commit (first phase). If one of the participants fails to be able to commit, the transaction will be cancelled and cancel will be called on all the participants (roll-back is performed). When all participants agree, commit will be called (second phase).

The difference is the pre-commit phase, which checks if everybody can commit and which signals all the participants that the next signal will either be a cancel or a commit.

Optimistic versus conservative transactions – There are two approaches to implementing transactions: optimistic and conservative. This choice has to be made at almost every point in the implementation. Pure forms only rarely exist.

The basic difference is that in the optimistic approach, the participants can always join, but may not always be able to commit. While in the conservative approach, the join may fail, but when joined, the participant can always commit.

One of the other differences is in the way these approaches join transactions. In the conservative approach, the client first has to call join on the participant to join in a specific transaction before any sensitive methods can be called. In the optimistic way the participant will do the join for the client if this has not been done yet.

Related Patterns

None.

Example

Note:

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

The Personal Information Manager stores appointments based on their date. Naturally, since users lead active lives, appointments change all the time. A user’s appointment book is constantly being updated with new or changing appointments.

If a number of users need to agree on a date for an appointment, it would be helpful if their appointment books could coordinate, arriving at a date that would work for everybody. That’s what this example demonstrates—how the Transaction pattern can be used to allow address books to reschedule a date for an appointment.

The basic interface that supports transactions is AppointmentTransactionParticipant. It defines three methods to manage transactions (join, commit, and cancel) and the business method changeDate. This class is a Remote class, since it is used to communicate between transaction participants that might reside on different Java Virtual Machines.

Example 4.29 AppointmentTransactionParticipant.java

1.import java.util.Date;

2.import java.rmi.Remote;

3.import java.rmi.RemoteException;

4.public interface AppointmentTransactionParticipant extends Remote{

5.public boolean join(long transactionID) throws RemoteException;

6.public void commit(long transactionID) throws TransactionException, RemoteException;

7.public void cancel(long transactionID) throws RemoteException;

8.public boolean changeDate(long transactionID, Appointment appointment,

9.Date newStartDate) throws TransactionException, RemoteException;

10.}

The class AppointmentBook represents a user’s calendar, and implements the

AppointmentTransactionParticipant interface. In addition to providing support to change an Appointment

date, the AppointmentBook can initiate a change of an Appointment. Its method changeAppointment accepts a

transaction ID, an Appointment object, an array of other AppointmentBooks that should be transaction

180

participants, and an array of possible alternate dates for the appointment. The changeAppointment method allows one of the AppointmentBook objects to communicate with the others using RMI, calling the changeDate method on every one of the participants until all agree on an alternate date for the Appointment.

Example 4.30 AppointmentBook.java

1.import java.util.ArrayList;

2.import java.util.HashMap;

3.import java.util.Date;

4.import java.rmi.Naming;

5.import java.rmi.server.UnicastRemoteObject;

6.import java.rmi.RemoteException;

7.public class AppointmentBook implements AppointmentTransactionParticipant{

8.private static final String TRANSACTION_SERVICE_PREFIX = "transactionParticipant";

9.private static final String TRANSACTION_HOSTNAME = "localhost";

10.private static int index = 1;

11.private String serviceName = TRANSACTION_SERVICE_PREFIX + index++;

12.private HashMap appointments = new HashMap();

13.private long currentTransaction;

14.private Appointment currentAppointment;

15.private Date updateStartDate;

16.

17.public AppointmentBook(){

18.try {

19.

UnicastRemoteObject.exportObject(this);

20.

Naming.rebind(serviceName, this);

21.}

22.catch (Exception exc){

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

24.}

25.}

26.

27.public String getUrl(){

28.return "//" + TRANSACTION_HOSTNAME + "/" + serviceName;

29.}

30.

public void addAppointment(Appointment appointment){

31.

32.

if (!appointments.containsValue(appointment)){

33.

if (!appointments.containsKey(appointment.getStartDate())){

34.

}

appointments.put(appointment.getStartDate(),Y appointment);

35.

 

 

L

36.

}

 

M

 

A

F

37.

}

 

 

38.

public void removeAppointment( ppointment appointment){

39.

if (appointments.containsValue(appointment)){

40.

appointments.remove(appointmentE

.getStartDate());

41.

}

T

 

 

42.

}

 

 

 

43.

 

 

 

 

44.public boolean join(long transactionID){

45.if (currentTransaction != 0){

46.

return false;

47.} else {

48.

currentTransaction = transactionID;

49.

return true;

50.}

51.}

52.public void commit(long transactionID) throws TransactionException{

53.if (currentTransaction != transactionID){

54. throw new TransactionException("Invalid TransactionID");

55.} else {

56.

removeAppointment(currentAppointment);

57.

currentAppointment.setStartDate(updateStartDate);

58.

appointments.put(updateStartDate, currentAppointment);

59.}

60.}

61.public void cancel(long transactionID){

62.if (currentTransaction == transactionID){

63. currentTransaction = 0;

64. appointments.remove(updateStartDate);

65.}

66.}

67.public boolean changeDate(long transactionID, Appointment appointment,

68.Date newStartDate) throws

69.

if ((appointments.

&& (!appointments.

70.

containsKey(newStartDate))){TEAM FLY PRESENTS

 

appointments.put(newStartDate, null);

 

181

71.

updateStartDate = newStartDate;

72.

currentAppointment = appointment;

73.

return true;

74.}

75.return false;

76.}

77.

78.public boolean changeAppointment(Appointment appointment, Date[] possibleDates,

79.AppointmentTransactionParticipant[] participants, long transactionID){

80.try{

81.

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

82.

if (!participants[i].join(transactionID)){

83.

return false;

84.

}

85.

}

86.

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

87.

if (isDateAvailable(transactionID, appointment, possibleDates[i],

88.

participants)){

try{

89.

commitAll(transactionID, participants);

90.

return true;

91.

}

92.

catch(TransactionException exc){ }

93.

}

94.

}

95.}

96.catch (RemoteException exc){ }

97.try{

98. cancelAll(transactionID, participants);

99.}

100.catch (RemoteException exc){}

101.return false;

102.}

103.

104.private boolean isDateAvailable(long transactionID, Appointment appointment,

105.Date date, AppointmentTransactionParticipant[] participants){

106.try{

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

108.

try{

109.

if (!participants[i].changeDate(transactionID, appointment, date)){

110.

return false;

111.

}

112.

}

113.

catch (TransactionException exc){

114.

return false;

115.

}

116.}

117.}

118.catch (RemoteException exc){

119.return false;

120.}

121.return true;

122.}

123.private void commitAll(long transactionID, AppointmentTransactionParticipant[]

participants)

124.throws TransactionException, RemoteException{

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

126.participants[i].commit(transactionID);

127.}

128.}

129.private void cancelAll(long transactionID, AppointmentTransactionParticipant[]

participants)

130.throws RemoteException{

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

132.participants[i].cancel(transactionID);

133.}

134.}

135.public String toString(){

136.return serviceName + " " + appointments.values().toString();

137.}

138.}

182

Part II: Patterns in the Java Programming Language

Chapter 5. Introduction to Java Programming Language Patterns

In the first part of this book, a common set of patterns is discussed. The patterns are listed with descriptions of their characteristics, the benefits and drawbacks associated with them, examples of their use and code samples demonstrating the patterns in action.

The basic patterns discussed are platform and language-neutral. While it's true that Java is especially well-suited to some of these patterns, they can be implemented in languages that support the core object-oriented properties of inheritance, encapsulation, polymorphism, and abstract classes.

Now it's time to shift gears and look at pattern use in the Java APIs. Since the Java programming language and the Design Patterns movement grew up together, the developers used a number of design patterns when they created the Java APIs. The goal is to gain an understanding of how Java is put together, and to answer questions like:

How does Java as a language make use of patterns?

How does it use patterns to make its APIs more effective?

The Java APIs provide additional demonstrations of pattern use. Like the Personal Information Manager examples in Part I, these real-world patterns provide useful insight into how patterns can be effectively applied to solve problems.

At this point, it’s worth explaining what exactly is meant by “API.” It's become a somewhat vague term in recent years. These days, API is used to refer to a single class, a group of classes, a single package or a set or related packages. The important quality that defines an API is the fact that it provides a programming framework for a set of related functional capabilities.

A number of the APIs in the following chapters are actually designed as a set of related classes. To appreciate the way that an API functions as a whole, it makes sense to spend some time discussing its basic structure. This provides a perspective on how patterns support the API – how they help a specific API to better do its job. This means that this section of the book is effectively part architectural evaluation, part pattern study. This provides a few practical benefits:

It can help you appreciate some of the ways that patterns are actually used within the API. Studying the Java APIs demonstrates how patterns can be applied to achieve practical goals.

It shows how you can use patterns with the APIs. Examining a set of APIs can help you see how to effectively use a pattern to interact with an API or framework.

In the pages that follow, you’ll take a look at a number of Java APIs and see what makes them tick. This should give you new insight into their use and usefulness – perhaps even on why they're designed the way they are. With these thoughts in mind, let's begin our exploration.

Note

The APIs discussed in the following chapters are divided into several sections. First, the Packages section describes which packages contain the classes and interfaces that make up the API. Next, the Overview section provides a brief review of each API. The Overview section is not meant to teach an entire API. It is a reminder to those who know the API, and a list of highlights for those of you who plan to learn more about it as you continue to program. The final section is called Pattern Use; it presents design patterns used in the APIs, and describes how they are used.

183