Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Applied Java™ Patterns - Stephen Stelting, Olav Maassen.pdf
Скачиваний:
198
Добавлен:
24.05.2014
Размер:
2.84 Mб
Скачать

Successive Update

The example code shows a simple client pull solution for the Personal Information Manager. Clients use the server to centralize information about tasks they are working on. Each client stays up-to-date by periodically requesting updates from the server.

In the sample code, the PullClient class retrieves a task for a client. Its responsibility is to locate the RMI server so that it can request tasks on a regular basis.

Example A.236 PullClient.java

1.import java.net.MalformedURLException;

2.import java.rmi.Naming;

3.import java.rmi.NotBoundException;

4.import java.rmi.RemoteException;

5.import java.util.Date;

6.public class PullClient{

7.private static final String UPDATE_SERVER_SERVICE_NAME = "updateServer";

8.private static final String UPDATE_SERVER_MACHINE_NAME = "localhost";

9.private ClientPullServer updateServer;

10.private ClientPullRequester requester;

11.private Task updatedTask;

12.private String clientName;

13.

14.public PullClient(String newClientName){

15.clientName = newClientName;

16.try{

17. String url = "//" + UPDATE_SERVER_MACHINE_NAME + "/" + UPDATE_SERVER_SERVICE_NAME; 18. updateServer = (ClientPullServer)Naming.lookup(url);

19.}

20.catch (RemoteException exc){}

21.catch (NotBoundException exc){}

22.catch (MalformedURLException exc){}

23.catch (ClassCastException exc){}

24.}

25.

26.public void requestTask(String taskID){

27.requester = new ClientPullRequester(this, updateServer, taskID);

28.}

29.

30.public void updateTask(Task task){

31.requester.updateTask(task);

32.}

33.

34.public Task getUpdatedTask(){

35.return updatedTask;

36.}

37.

38.public void setUpdatedTask(Task task){

39.updatedTask = task;

40.System.out.println(clientName + ": received updated task: " + task);

41.}

42.

43.public String toString(){

44.return clientName;

45.}

46.}

When the client wants to receive updates on a task, it calls the method requestTask on the PullClient. The PullClient object creates a worker thread (see “ Worker Thread ” on page 517), which is the ClientPullRequester object. This object resides on the client, and regularly issues a request to the server for updated task information.

Example A.237 ClientPullRequester.java

1.import java.rmi.RemoteException;

2.public class ClientPullRequester implements Runnable{

3.private static final int DEFAULT_POLLING_INTERVAL = 10000;

4.private Thread processingThread;

5.private PullClient parent;

6.private ClientPullServer updateServer;

7.private String taskID;

8.private boolean shutdown;

9.private Task currentTask = new TaskImpl();

349

10. private int pollingInterval = DEFAULT_POLLING_INTERVAL; 11.

12.public ClientPullRequester(PullClient newParent, ClientPullServer newUpdateServer,

13. String newTaskID){

14.parent = newParent;

15.taskID = newTaskID;

16.updateServer = newUpdateServer;

17.processingThread = new Thread(this);

18.processingThread.start();

19.}

20.

21.public void run(){

22.while (!isShutdown()){

23.

try{

24.

currentTask = updateServer.getTask(taskID, currentTask.getLastEditDate());

25.

parent.setUpdatedTask(currentTask);

26.

}

27.

catch (RemoteException exc){ }

28.

catch (UpdateException exc){

29.

System.out.println(" " + parent + ": " + exc.getMessage());

30.

}

31.

try{

32.

Thread.sleep(pollingInterval);

33.

}

34.

catch (InterruptedException exc){ }

35.}

36.}

38.public void updateTask(Task changedTask){

39.try{

40. updateServer.updateTask(taskID, changedTask);

41.}

42.catch (RemoteException exc){ }

43.catch (UpdateException exc){

44. System.out.println(" " + parent + ": " + exc.getMessage());

45.}

46.}

48.public int getPollingInterval(){ return pollingInterval; }

49.public boolean isShutdown(){ return shutdown; }

50.

51.public void setPollingInterval(int newPollingInterval){ pollingInterval =

newPollingInterval; }

52.public void setShutdown(boolean isShutdown){ shutdown = isShutdown; }

53.}

The RMI server's behavior is defined by the ClientPullServer interface and managed by the ClientPullServerImpl class. Two methods allow clients to interact with a server, getTask and updateTask.

Example A.238 ClientPullServer.java

1.import java.rmi.Remote;

2.import java.rmi.RemoteException;

3.import java.util.Date;

4.public interface ClientPullServer extends Remote{

5.public Task getTask(String taskID, Date lastUpdate) throws RemoteException,

UpdateException;

6.public void updateTask(String taskID, Task updatedTask) throws RemoteException,

UpdateException;

7.}

Example A.239 ClientPullServerImpl.java

1.import java.util.Date;

2.import java.rmi.Naming;

3.import java.rmi.server.UnicastRemoteObject;

4.public class ClientPullServerImpl implements ClientPullServer{

5.private static final String UPDATE_SERVER_SERVICE_NAME = "updateServer";

6.public ClientPullServerImpl(){

7.try {

8.

UnicastRemoteObject.exportObject(this);

9.

Naming.rebind(UPDATE_SERVER_SERVICE_NAME, this);

10.}

11.catch (Exception exc){

12.System.err.println("Error using RMI to register the ClientPullServerImpl " + exc);

13.}

14.}

15.

350

16.public Task getTask(String taskID, Date lastUpdate) throws UpdateException{

17.return UpdateServerDelegate.getTask(taskID, lastUpdate);

18.}

19.

20.public void updateTask(String taskID, Task updatedTask) throws UpdateException{

21.UpdateServerDelegate.updateTask(taskID, updatedTask);

22.}

23.}

The class UpdateServerDelegate performs the server-side behavior for ClientPullServerImpl. Specifically, it retrieves Task objects, and ensures that up-to-date copies of Tasks are provided to clients by comparing the last update Date.

Example A.240 UpdateServerDelegate.java

1.import java.util.Date;

2.import java.util.HashMap;

3.public class UpdateServerDelegate{

4.private static HashMap tasks = new HashMap();

6.public static Task getTask(String taskID, Date lastUpdate) throws UpdateException{

7.if (tasks.containsKey(taskID)){

8.

Task storedTask = (Task)tasks.get(taskID);

9.

if (storedTask.getLastEditDate().after(lastUpdate)){

10.

return storedTask;

11.

}

12.

else{

13.

throw new UpdateException("Task " + taskID + " does not need to be updated",

 

UpdateException.TASK_UNCHANGED);

14.

15.

16.

17.

18.

19.

20.

21.

22.

23.

24.

25.

26.

27.

28.

29.

30.

31.

32.

33.

34.

35.

36.

37.

38.}

}

}

else{

return loadNewTask(taskID);

}

}

public static void updateTask(String taskID, Task task) throws UpdateException{

if (tasks.containsKey(taskID)){

Y

 

 

 

 

 

L

if (task.getLastEditDate().equals(((Task)tasks.get(taskID)). getLastEditDate())){

 

((TaskImpl)task).setLastEditDate(new Date());

}

tasks.put(taskID, task);

F

else{

 

A

 

E

M

 

throw new UpdateException("Task " + taskID + " data must be refreshed before

 

 

T

 

 

 

editing", Update xception.TASK_OUT_OF_DATE);

}

}

}

private static Task loadNewTask(String taskID){

Task newTask = new TaskImpl(taskID, "", new Date(), null); tasks.put(taskID, newTask);

return newTask;

}

Any problems encountered during the periodic client pull operations are represented by the UpdateException class. The Task interface and TaskImpl class represent the business elements of the example.

Example A.241 Task.java

1.import java.util.Date;

2.import java.io.Serializable;

3.import java.util.ArrayList;

4.public interface Task extends Serializable{

5.public String getTaskID();

6.public Date getLastEditDate();

7.public String getTaskName();

8.public String getTaskDetails();

9.public ArrayList getSubTasks();

10.

 

public void setTaskName(String newName);

11.

 

12.

 

public void setTaskDetails(String

13.

 

public void addSubTask(Task

14.

 

public void removeSubTask(Task

15.

}

TEAM FLY PRESENTS

 

351

Example A.242 TaskImpl.java

1.import java.util.Date;

2.import java.io.Serializable;

3.import java.util.ArrayList;

4.public class TaskImpl implements Task{

5.private String taskID;

6.private Date lastEditDate;

7.private String taskName;

8.private String taskDetails;

9.private ArrayList subTasks = new ArrayList();

11.public TaskImpl(){

12.lastEditDate = new Date();

13.taskName = "";

14.taskDetails = "";

15.}

16.public TaskImpl(String newTaskName, String newTaskDetails,

17.Date newEditDate, ArrayList newSubTasks){

18.lastEditDate = newEditDate;

19.taskName = newTaskName;

20.taskDetails = newTaskDetails;

21.if (newSubTasks != null){ subTasks = newSubTasks; }

22.}

23.

24.public String getTaskID(){

25.return taskID;

26.}

27.public Date getLastEditDate(){ return lastEditDate; }

28.public String getTaskName(){ return taskName; }

29.public String getTaskDetails(){ return taskDetails; }

30.public ArrayList getSubTasks(){ return subTasks; }

32.public void setLastEditDate(Date newDate){

33.if (newDate.after(lastEditDate)){

34. lastEditDate = newDate;

35.}

36.}

37.public void setTaskName(String newName){ taskName = newName; }

38.public void setTaskDetails(String newDetails){ taskDetails = newDetails; }

39.public void addSubTask(Task task){

40.if (!subTasks.contains(task)){

41. subTasks.add(task);

42.}

43.}

44.public void removeSubTask(Task task){

45.subTasks.remove(task);

46.}

47.

48.public String toString(){

49.return taskName + " " + taskDetails;

50.}

51.}

Example A.243 UpdateException.java

1.public class UpdateException extends Exception{

2.public static final int TASK_UNCHANGED = 1;

3.public static final int TASK_OUT_OF_DATE = 2;

4.private int errorCode;

5.

6.public UpdateException(String cause, int newErrorCode){

7.super(cause);

8.errorCode = newErrorCode;

9.}

10.public UpdateException(String cause){ super(cause); }

11.

12.public int getErrorCode(){ return errorCode; }

13.}

RunPattern demonstrates how updates of a Task can be propagated to multiple clients. The main method creates a ClientPullServer and two PullClient objects. Both clients are used to request a common Task, then one of the PullClients makes an update to the Task. The change is reflected in the other client as its worker thread, the ClientPullRequester, polls the server for changes.

Example A.244 RunPattern.java

1. import java.io.IOException;

352

2.public class RunPattern{

3.public static void main(String [] arguments){

4.System.out.println("Example for the SuccessiveUpdate pattern");

5.System.out.println("This code provides a basic demonstration");

6.System.out.println(" of how the client pull form of this pattern");

7.System.out.println(" could be applied.");

8.System.out.println("In this case, a change made by a client to a");

9.System.out.println(" central Task object is subsequently retrieved");

10.System.out.println(" and displayed by another client.");

11.

12.System.out.println("Running the RMI compiler (rmic)");

13.System.out.println();

14.try{

15. Process p1 = Runtime.getRuntime().exec("rmic ClientPullServerImpl");

16. p1.waitFor();

17.}

18.catch (IOException exc){

19. System.err.println("Unable to run rmic utility. Exiting application.");

20. System.exit(1);

21.}

22.catch (InterruptedException exc){

23.

System.err.println("Threading problems encountered while using the rmic utility.");

24.

}

25.

 

26.System.out.println("Starting the rmiregistry");

27.System.out.println();

28.Process rmiProcess = null;

29.try{

30. rmiProcess = Runtime.getRuntime().exec("rmiregistry");

31. Thread.sleep(15000);

32.}

33.catch (IOException exc){

34. System.err.println("Unable to start the rmiregistry. Exiting application.");

35. System.exit(1);

36.}

37.catch (InterruptedException exc){

38.

System.err.println("Threading problems encountered when starting the rmiregistry.");

39.

}

40.

 

41.System.out.println("Creating the ClientPullServer and two PullClient objects");

42.ClientPullServer server = new ClientPullServerImpl();

43.PullClient clientOne = new PullClient("Thing I");

44.PullClient clientTwo = new PullClient("Thing II");

45.clientOne.requestTask("First work step");

46.clientTwo.requestTask("First work step");

47.

48.try{

49. Thread.sleep(10000);

50.}

51.catch (InterruptedException exc){ }

53.Task task = clientOne.getUpdatedTask();

54.task.setTaskDetails("Trial for task update");

55.clientOne.updateTask(task);

56.

57.Task newTask = clientTwo.getUpdatedTask();

58.newTask.setTaskDetails("New details string");

59.clientTwo.updateTask(newTask);

60.

61.

62.}

63.}

353