Java/Design Pattern/Successive Update Pattern
Successive Update Pattern in Java
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
public class RunSuccessiveUpdatePattern {
public static void main(String [] arguments){
System.out.println("Example for the SuccessiveUpdate pattern");
System.out.println("This code provides a basic demonstration");
System.out.println(" of how the client pull form of this pattern");
System.out.println(" could be applied.");
System.out.println("In this case, a change made by a client to a");
System.out.println(" central Task object is subsequently retrieved");
System.out.println(" and displayed by another client.");
System.out.println("Running the RMI compiler (rmic)");
System.out.println();
try{
Process p1 = Runtime.getRuntime().exec("rmic ClientPullServerImpl");
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();
Process rmiProcess = null;
try{
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 the ClientPullServer and two PullClient objects");
ClientPullServer server = new ClientPullServerImpl();
PullClient clientOne = new PullClient("Thing I");
PullClient clientTwo = new PullClient("Thing II");
clientOne.requestTask("First work step");
clientTwo.requestTask("First work step");
try{
Thread.sleep(10000);
}
catch (InterruptedException exc){ }
Task task = clientOne.getUpdatedTask();
task.setTaskDetails("Trial for task update");
clientOne.updateTask(task);
Task newTask = clientTwo.getUpdatedTask();
newTask.setTaskDetails("New details string");
clientTwo.updateTask(newTask);
}
}
class Command implements Serializable{
public static final int GET_PROJECT = 1;
public static final int GET_TASK = 2;
public static final int CREATE_CONTACT = 4;
public static final int CREATE_ADDRESS = 8;
public static final int CREATE_PHONE_NUMBER = 16;
private int command;
private Object [] arguments;
public int getCommand(){
return command;
}
public Object [] getArguments(){
return arguments;
}
public void setArguments(Object [] newArguments){
arguments = newArguments;
}
public void setCommand(int newCommand){
command = newCommand;
}
public Command(int name, Object [] argumentList){
command = name;
arguments = argumentList;
}
}
interface Task extends Serializable{
public String getTaskID();
public Date getLastEditDate();
public String getTaskName();
public String getTaskDetails();
public ArrayList getSubTasks();
public void setTaskName(String newName);
public void setTaskDetails(String newDetails);
public void addSubTask(Task task);
public void removeSubTask(Task task);
}
class TaskImpl implements Task{
private String taskID;
private Date lastEditDate;
private String taskName;
private String taskDetails;
private ArrayList subTasks = new ArrayList();
public TaskImpl(){
lastEditDate = new Date();
taskName = "";
taskDetails = "";
}
public TaskImpl(String newTaskName, String newTaskDetails,
Date newEditDate, ArrayList newSubTasks){
lastEditDate = newEditDate;
taskName = newTaskName;
taskDetails = newTaskDetails;
if (newSubTasks != null){ subTasks = newSubTasks; }
}
public String getTaskID(){
return taskID;
}
public Date getLastEditDate(){ return lastEditDate; }
public String getTaskName(){ return taskName; }
public String getTaskDetails(){ return taskDetails; }
public ArrayList getSubTasks(){ return subTasks; }
public void setLastEditDate(Date newDate){
if (newDate.after(lastEditDate)){
lastEditDate = newDate;
}
}
public void setTaskName(String newName){ taskName = newName; }
public void setTaskDetails(String newDetails){ taskDetails = newDetails; }
public void addSubTask(Task task){
if (!subTasks.contains(task)){
subTasks.add(task);
}
}
public void removeSubTask(Task task){
subTasks.remove(task);
}
public String toString(){
return taskName + " " + taskDetails;
}
}
class ClientPullRequester implements Runnable{
private static final int DEFAULT_POLLING_INTERVAL = 10000;
private Thread processingThread;
private PullClient parent;
private ClientPullServer updateServer;
private String taskID;
private boolean shutdown;
private Task currentTask = new TaskImpl();
private int pollingInterval = DEFAULT_POLLING_INTERVAL;
public ClientPullRequester(PullClient newParent, ClientPullServer newUpdateServer,
String newTaskID){
parent = newParent;
taskID = newTaskID;
updateServer = newUpdateServer;
processingThread = new Thread(this);
processingThread.start();
}
public void run(){
while (!isShutdown()){
try{
currentTask = updateServer.getTask(taskID, currentTask.getLastEditDate());
parent.setUpdatedTask(currentTask);
}
catch (RemoteException exc){ }
catch (UpdateException exc){
System.out.println(" " + parent + ": " + exc.getMessage());
}
try{
Thread.sleep(pollingInterval);
}
catch (InterruptedException exc){ }
}
}
public void updateTask(Task changedTask){
try{
updateServer.updateTask(taskID, changedTask);
}
catch (RemoteException exc){ }
catch (UpdateException exc){
System.out.println(" " + parent + ": " + exc.getMessage());
}
}
public int getPollingInterval(){ return pollingInterval; }
public boolean isShutdown(){ return shutdown; }
public void setPollingInterval(int newPollingInterval){ pollingInterval = newPollingInterval; }
public void setShutdown(boolean isShutdown){ shutdown = isShutdown; }
}
class UpdateServerDelegate{
private static HashMap tasks = new HashMap();
public static Task getTask(String taskID, Date lastUpdate) throws UpdateException{
if (tasks.containsKey(taskID)){
Task storedTask = (Task)tasks.get(taskID);
if (storedTask.getLastEditDate().after(lastUpdate)){
return storedTask;
}
else{
throw new UpdateException("Task " + taskID + " does not need to be updated", UpdateException.TASK_UNCHANGED);
}
}
else{
return loadNewTask(taskID);
}
}
public static void updateTask(String taskID, Task task) throws UpdateException{
if (tasks.containsKey(taskID)){
if (task.getLastEditDate().equals(((Task)tasks.get(taskID)).getLastEditDate())){
((TaskImpl)task).setLastEditDate(new Date());
tasks.put(taskID, task);
}
else{
throw new UpdateException("Task " + taskID + " data must be refreshed before editing", UpdateException.TASK_OUT_OF_DATE);
}
}
}
private static Task loadNewTask(String taskID){
Task newTask = new TaskImpl(taskID, "", new Date(), null);
tasks.put(taskID, newTask);
return newTask;
}
}
class PullClient{
private static final String UPDATE_SERVER_SERVICE_NAME = "updateServer";
private static final String UPDATE_SERVER_MACHINE_NAME = "localhost";
private ClientPullServer updateServer;
private ClientPullRequester requester;
private Task updatedTask;
private String clientName;
public PullClient(String newClientName){
clientName = newClientName;
try{
String url = "//" + UPDATE_SERVER_MACHINE_NAME + "/" + UPDATE_SERVER_SERVICE_NAME;
updateServer = (ClientPullServer)Naming.lookup(url);
}
catch (RemoteException exc){}
catch (NotBoundException exc){}
catch (MalformedURLException exc){}
catch (ClassCastException exc){}
}
public void requestTask(String taskID){
requester = new ClientPullRequester(this, updateServer, taskID);
}
public void updateTask(Task task){
requester.updateTask(task);
}
public Task getUpdatedTask(){
return updatedTask;
}
public void setUpdatedTask(Task task){
updatedTask = task;
System.out.println(clientName + ": received updated task: " + task);
}
public String toString(){
return clientName;
}
}
class TaskResponse implements Serializable{
private Date lastUpdate;
private Task task;
public TaskResponse(Date newUpdate, Task newTask){
lastUpdate = newUpdate;
task = newTask;
}
public Date getLastUpdate(){
return lastUpdate;
}
public Task getTask(){
return task;
}
public void setLastUpdate(Date newDate){
if (newDate.after(lastUpdate)){
lastUpdate = newDate;
}
}
}
class UpdateException extends Exception{
public static final int TASK_UNCHANGED = 1;
public static final int TASK_OUT_OF_DATE = 2;
private int errorCode;
public UpdateException(String cause, int newErrorCode){
super(cause);
errorCode = newErrorCode;
}
public UpdateException(String cause){ super(cause); }
public int getErrorCode(){ return errorCode; }
}
interface ClientPullServer extends Remote{
public Task getTask(String taskID, Date lastUpdate) throws RemoteException, UpdateException;
public void updateTask(String taskID, Task updatedTask) throws RemoteException, UpdateException;
}
class ClientPullServerImpl implements ClientPullServer{
private static final String UPDATE_SERVER_SERVICE_NAME = "updateServer";
public ClientPullServerImpl(){
try {
UnicastRemoteObject.exportObject(this);
Naming.rebind(UPDATE_SERVER_SERVICE_NAME, this);
}
catch (Exception exc){
System.err.println("Error using RMI to register the ClientPullServerImpl " + exc);
}
}
public Task getTask(String taskID, Date lastUpdate) throws UpdateException{
return UpdateServerDelegate.getTask(taskID, lastUpdate);
}
public void updateTask(String taskID, Task updatedTask) throws UpdateException{
UpdateServerDelegate.updateTask(taskID, updatedTask);
}
}