Java/Design Pattern/Transaction Pattern

Материал из Java эксперт
Перейти к: навигация, поиск

Transaction Pattern Demo

//[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);
  }
}