Java/Design Pattern/Successive Update Pattern

Материал из Java эксперт
Версия от 18:01, 31 мая 2010; (обсуждение)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

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