Java/Design Pattern/Transaction Pattern
Transaction Pattern Demo
<source lang="java">
//[C] 2002 Sun Microsystems, Inc.--- import java.io.IOException; import java.io.Serializable; import java.rmi.Naming; import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; public class RunTransactionPattern {
private static Calendar dateCreator = Calendar.getInstance(); public static void main(String[] arguments) { System.out.println("Example for the Transaction pattern"); System.out.println("This code example shows how a Transaction can"); System.out .println(" be applied to support change across a distributed"); System.out.println(" system. In ths case, a distributed transaction"); System.out.println(" is used to coordinate the change of dates in"); System.out.println(" appointment books."); System.out.println("Running the RMI compiler (rmic)"); System.out.println(); try { Process p1 = Runtime.getRuntime().exec("rmic AppointmentBook"); p1.waitFor(); } catch (IOException exc) { System.err .println("Unable to run rmic utility. Exiting application."); System.exit(1); } catch (InterruptedException exc) { System.err .println("Threading problems encountered while using the rmic utility."); } System.out.println("Starting the rmiregistry"); System.out.println(); try { Process rmiProcess = Runtime.getRuntime().exec("rmiregistry"); Thread.sleep(15000); } catch (IOException exc) { System.err .println("Unable to start the rmiregistry. Exiting application."); System.exit(1); } catch (InterruptedException exc) { System.err .println("Threading problems encountered when starting the rmiregistry."); } System.out.println("Creating three appointment books"); System.out.println(); AppointmentBook apptBookOne = new AppointmentBook(); AppointmentBook apptBookTwo = new AppointmentBook(); AppointmentBook apptBookThree = new AppointmentBook(); System.out.println("Creating appointments"); System.out.println(); Appointment apptOne = new AppointmentImpl( "Swim relay to Kalimantan (or Java)", new ArrayList(), new LocationImpl("Sidney, Australia"), createDate(2001, 11, 5, 11, 0)); Appointment apptTwo = new AppointmentImpl( "Conference on World Patternization", new ArrayList(), new LocationImpl("London, England"), createDate(2001, 11, 5, 14, 0)); Appointment apptThree = new AppointmentImpl( "Society for the Preservation of Java - Annual Outing", new ArrayList(), new LocationImpl("Kyzyl, Tuva"), createDate( 2001, 11, 5, 10, 0)); System.out.println("Adding appointments to the appointment books"); System.out.println(); apptBookOne.addAppointment(apptThree); apptBookTwo.addAppointment(apptOne); apptBookOne.addAppointment(apptTwo); apptBookTwo.addAppointment(apptTwo); apptBookThree.addAppointment(apptTwo); System.out.println("AppointmentBook contents:"); System.out.println(); System.out.println(apptBookOne); System.out.println(apptBookTwo); System.out.println(apptBookThree); System.out.println(); System.out.println("Rescheduling an appointment"); System.out.println(); System.out.println(); boolean result = apptBookThree.changeAppointment(apptTwo, getDates( 2001, 11, 5, 10, 3), lookUpParticipants(new String[] { apptBookOne.getUrl(), apptBookTwo.getUrl(), apptBookThree.getUrl() }), 20000L); System.out.println("Result of rescheduling was " + result); System.out.println("AppointmentBook contents:"); System.out.println(); System.out.println(apptBookOne); System.out.println(apptBookTwo); System.out.println(apptBookThree); } private static AppointmentTransactionParticipant[] lookUpParticipants( String[] remoteUrls) { AppointmentTransactionParticipant[] returnValues = new AppointmentTransactionParticipant[remoteUrls.length]; for (int i = 0; i < remoteUrls.length; i++) { try { returnValues[i] = (AppointmentTransactionParticipant) Naming .lookup(remoteUrls[i]); } catch (Exception exc) { System.out .println("Error using RMI to look up a transaction participant"); } } return returnValues; } private static Date[] getDates(int year, int month, int day, int hour, int increment) { Date[] returnDates = new Date[increment]; for (int i = 0; i < increment; i++) { returnDates[i] = createDate(year, month, day, hour + i, 0); } return returnDates; } public static Date createDate(int year, int month, int day, int hour, int minute) { dateCreator.set(year, month, day, hour, minute); return dateCreator.getTime(); }
} interface Location extends Serializable {
public String getLocation(); public void setLocation(String newLocation);
} class LocationImpl implements Location {
private String location; public LocationImpl() { } public LocationImpl(String newLocation) { location = newLocation; } public String getLocation() { return location; } public void setLocation(String newLocation) { location = newLocation; } public String toString() { return location; }
} interface Contact extends Serializable {
public static final String SPACE = " "; public String getFirstName(); public String getLastName(); public String getTitle(); public String getOrganization(); public void setFirstName(String newFirstName); public void setLastName(String newLastName); public void setTitle(String newTitle); public void setOrganization(String newOrganization);
} class ContactImpl implements Contact {
private String firstName; private String lastName; private String title; private String organization; public ContactImpl() { } public ContactImpl(String newFirstName, String newLastName, String newTitle, String newOrganization) { firstName = newFirstName; lastName = newLastName; title = newTitle; organization = newOrganization; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public String getTitle() { return title; } public String getOrganization() { return organization; } public void setFirstName(String newFirstName) { firstName = newFirstName; } public void setLastName(String newLastName) { lastName = newLastName; } public void setTitle(String newTitle) { title = newTitle; } public void setOrganization(String newOrganization) { organization = newOrganization; } public String toString() { return firstName + SPACE + lastName; }
} interface Appointment extends Serializable {
public static final String EOL_STRING = System .getProperty("line.separator"); public Date getStartDate(); public String getDescription(); public ArrayList getAttendees(); public Location getLocation(); public void setDescription(String newDescription); public void setLocation(Location newLocation); public void setStartDate(Date newStartDate); public void setAttendees(ArrayList newAttendees); public void addAttendee(Contact attendee); public void removeAttendee(Contact attendee);
} class AppointmentImpl implements Appointment {
private Date startDate; private String description; private ArrayList attendees = new ArrayList(); private Location location; public AppointmentImpl(String newDescription, ArrayList newAttendees, Location newLocation, Date newStartDate) { description = newDescription; attendees = newAttendees; location = newLocation; startDate = newStartDate; } public Date getStartDate() { return startDate; } public String getDescription() { return description; } public ArrayList getAttendees() { return attendees; } public Location getLocation() { return location; } public void setDescription(String newDescription) { description = newDescription; } public void setLocation(Location newLocation) { location = newLocation; } public void setStartDate(Date newStartDate) { startDate = newStartDate; } public void setAttendees(ArrayList newAttendees) { if (newAttendees != null) { attendees = newAttendees; } } public void addAttendee(Contact attendee) { if (!attendees.contains(attendee)) { attendees.add(attendee); } } public void removeAttendee(Contact attendee) { attendees.remove(attendee); } public int hashCode() { return description.hashCode() ^ startDate.hashCode(); } public boolean equals(Object object) { if (!(object instanceof AppointmentImpl)) { return false; } if (object.hashCode() != hashCode()) { return false; } return true; } public String toString() { return " Description: " + description + EOL_STRING + " Start Date: " + startDate + EOL_STRING + " Location: " + location + EOL_STRING + " Attendees: " + attendees; }
} class AppointmentBook implements AppointmentTransactionParticipant {
private static final String TRANSACTION_SERVICE_PREFIX = "transactionParticipant"; private static final String TRANSACTION_HOSTNAME = "localhost"; private static int index = 1; private String serviceName = TRANSACTION_SERVICE_PREFIX + index++; private HashMap appointments = new HashMap(); private long currentTransaction; private Appointment currentAppointment; private Date updateStartDate; public AppointmentBook() { try { UnicastRemoteObject.exportObject(this); Naming.rebind(serviceName, this); } catch (Exception exc) { System.err .println("Error using RMI to register the AppointmentBook " + exc); } } public String getUrl() { return "//" + TRANSACTION_HOSTNAME + "/" + serviceName; } public void addAppointment(Appointment appointment) { if (!appointments.containsValue(appointment)) { if (!appointments.containsKey(appointment.getStartDate())) { appointments.put(appointment.getStartDate(), appointment); } } } public void removeAppointment(Appointment appointment) { if (appointments.containsValue(appointment)) { appointments.remove(appointment.getStartDate()); } } public boolean join(long transactionID) { if (currentTransaction != 0) { return false; } else { currentTransaction = transactionID; return true; } } public void commit(long transactionID) throws TransactionException { if (currentTransaction != transactionID) { throw new TransactionException("Invalid TransactionID"); } else { removeAppointment(currentAppointment); currentAppointment.setStartDate(updateStartDate); appointments.put(updateStartDate, currentAppointment); } } public void cancel(long transactionID) { if (currentTransaction == transactionID) { currentTransaction = 0; appointments.remove(updateStartDate); } } public boolean changeDate(long transactionID, Appointment appointment, Date newStartDate) throws TransactionException { if ((appointments.containsValue(appointment)) && (!appointments.containsKey(newStartDate))) { appointments.put(newStartDate, null); updateStartDate = newStartDate; currentAppointment = appointment; return true; } return false; } public boolean changeAppointment(Appointment appointment, Date[] possibleDates, AppointmentTransactionParticipant[] participants, long transactionID) { try { for (int i = 0; i < participants.length; i++) { if (!participants[i].join(transactionID)) { return false; } } for (int i = 0; i < possibleDates.length; i++) { if (isDateAvailable(transactionID, appointment, possibleDates[i], participants)) { try { commitAll(transactionID, participants); return true; } catch (TransactionException exc) { } } } } catch (RemoteException exc) { } try { cancelAll(transactionID, participants); } catch (RemoteException exc) { } return false; } private boolean isDateAvailable(long transactionID, Appointment appointment, Date date, AppointmentTransactionParticipant[] participants) { try { for (int i = 0; i < participants.length; i++) { try { if (!participants[i].changeDate(transactionID, appointment, date)) { return false; } } catch (TransactionException exc) { return false; } } } catch (RemoteException exc) { return false; } return true; } private void commitAll(long transactionID, AppointmentTransactionParticipant[] participants) throws TransactionException, RemoteException { for (int i = 0; i < participants.length; i++) { participants[i].rumit(transactionID); } } private void cancelAll(long transactionID, AppointmentTransactionParticipant[] participants) throws RemoteException { for (int i = 0; i < participants.length; i++) { participants[i].cancel(transactionID); } } public String toString() { return serviceName + " " + appointments.values().toString(); }
} interface AppointmentTransactionParticipant extends Remote {
public boolean join(long transactionID) throws RemoteException; public void commit(long transactionID) throws TransactionException, RemoteException; public void cancel(long transactionID) throws RemoteException; public boolean changeDate(long transactionID, Appointment appointment, Date newStartDate) throws TransactionException, RemoteException;
} class TransactionException extends Exception {
public TransactionException(String msg) { super(msg); }
}
</source>