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