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

Callback

In the Personal Information Manager, one of the items that can vary most in size is a project. A project might consist of only a few tasks, or it could be made up of hundreds or even thousands of individual work steps. This example demonstrates how the Callback pattern could be used to retrieve a project object stored on a server machine.

The interface CallbackServer defines a single server-side method, getProject. Note that the method requires callback information—the client machine name and the name of the RMI client object—in addition to the project ID. The class CallbackServerImpl implements this interface.

Example A.227 CallbackServer.java

1.import java.rmi.Remote;

2.import java.rmi.RemoteException;

3.public interface CallbackServer extends Remote{

4.public void getProject(String projectID, String callbackMachine,

5.String callbackObjectName) throws RemoteException;

6.}

Example A.228 CallbackServerImpl.java

1.import java.rmi.Naming;

2.import java.rmi.server.UnicastRemoteObject;

3.public class CallbackServerImpl implements CallbackServer{

4.private static final String CALLBACK_SERVER_SERVICE_NAME = "callbackServer";

5.public CallbackServerImpl(){

6.try {

7.

UnicastRemoteObject.exportObject(this);

8.

Naming.rebind(CALLBACK_SERVER_SERVICE_NAME, this);

9.}

10.catch (Exception exc){

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

12.}

13.}

14.

15.public void getProject(String projectID, String callbackMachine,

16.String callbackObjectName){

17.new CallbackServerWorkThread(projectID, callbackMachine, callbackObjectName);

18.}

19.

20.}

In the getProject method, CallbackServerImpl delegates the task of retrieving the project to a worker object, CallbackServerDelegate. This object runs on its own thread and does the work of retrieving a project and sending it to a client.

Example A.229 CallbackServerDelegate.java

1.import java.net.MalformedURLException;

2.import java.rmi.Naming;

3.import java.rmi.NotBoundException;

4.import java.rmi.RemoteException;

5.public class CallbackServerDelegate implements Runnable{

6.private Thread processingThread;

7.private String projectID;

8.private String callbackMachine;

9.private String callbackObjectName;

10.

11.public CallbackServerDelegate(String newProjectID, String newCallbackMachine,

12.String newCallbackObjectName){

13.projectID = newProjectID;

14.callbackMachine = newCallbackMachine;

15.callbackObjectName = newCallbackObjectName;

16.processingThread = new Thread(this);

17.processingThread.start();

18.}

19.

20.public void run(){

21.Project result = getProject();

22.sendProjectToClient(result);

23.}

24.

25. private Project getProject(){

344

26.return new Project(projectID, "Test project");

27.}

28.

29.private void sendProjectToClient(Project project){

30.try{

31.

String url = "//" +

callbackMachine + "/" + callbackObjectName;

32.

Object remoteClient

= Naming.lookup(url);

33.

if (remoteClient instanceof CallbackClient){

34.

((CallbackClient)remoteClient).receiveProject(project);

35.

}

 

36.}

37.catch (RemoteException exc){}

38.catch (NotBoundException exc){}

39.catch (MalformedURLException exc){}

40.}

41.}

In the CallbackServerDelegaterun method, the object retrieves a project by calling the getProject method, then sends it to a client with the send-ProjectToClient method. The latter method represents the callback to the client; the CallbackServerDelegate makes a call to an RMI object of type CallbackClient on the client machine. The interface CallbackClient also defines a single RMI method, receiveProject.

Example A.230 CallbackClient.java

1.import java.rmi.Remote;

2.import java.rmi.RemoteException;

3.public interface CallbackClient extends Remote{

4.public void receiveProject(Project project) throws RemoteException;

5.}

The implementer of CallbackClient, CallbackClientImpl, is both a client and a server. Its method requestProject looks up the CallbackServer and calls the remote method getProject. The class also defines the remote method receiveProject, which is called by the server work thread when the project is ready for the client. CallbackClientImpl has a boolean variable, projectAvailable, to allow a client program to determine when the project is ready for display.

Example A.231 CallbackClientImpl.java

1.import java.net.InetAddress;

2.import java.net.MalformedURLException;

3.import java.net.UnknownHostException;

4.import java.rmi.Naming;

5.import java.rmi.server.UnicastRemoteObject;

6.import java.rmi.NotBoundException;

7.import java.rmi.RemoteException;

8.public class CallbackClientImpl implements CallbackClient{

9.private static final String CALLBACK_CLIENT_SERVICE_NAME = "callbackClient";

10.private static final String CALLBACK_SERVER_SERVICE_NAME = "callbackServer";

11.private static final String CALLBACK_SERVER_MACHINE_NAME = "localhost";

12.

13.private Project requestedProject;

14.private boolean projectAvailable;

16.public CallbackClientImpl(){

17.try {

18.

UnicastRemoteObject.exportObject(this);

19.

Naming.rebind(CALLBACK_CLIENT_SERVICE_NAME, this);

20.}

21.catch (Exception exc){

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

23.}

24.}

26.public void receiveProject(Project project){

27.requestedProject = project;

28.projectAvailable = true;

29.}

30.

31.public void requestProject(String projectName){

32.try{

33. String url = "//" + CALLBACK_SERVER_MACHINE_NAME + "/" + CALLBACK_SERVER_SERVICE_NAME;

34. Object remoteServer = Naming.lookup(url);

35. if (remoteServer instanceof CallbackServer){

36. ((CallbackServer)remoteServer).getProject(projectName,

345

37.

InetAddress.getLocalHost().getHostName(),

38.

CALLBACK_CLIENT_SERVICE_NAME);

39.

}

40.

projectAvailable = false;

41.}

42.catch (RemoteException exc){}

43.catch (NotBoundException exc){}

44.catch (MalformedURLException exc){}

45.catch (UnknownHostException exc){}

46.}

47.

48.public Project getProject(){ return requestedProject; }

49.public boolean isProjectAvailable(){ return projectAvailable; }

50.}

The basic sequence of action is as follows. When a client requires a project, the CallbackClientImpl object

calls the method getProject on the CallbackServerImpl object. The CallbackServerImpl creates a CallbackServerWorkThread object to retrieve the project. When the CallbackServerWorkThread completes its

task, it calls the client method receiveProject, sending the Project instance to the requester, the

CallbackClientImpl object.

In this example, the interface ProjectItem and the classes Project and Task are used to represent the project resource to be retrieved by the client.

Example A.232 Project.java

1.import java.util.ArrayList;

2.public class Project implements ProjectItem{

3.private String name;

4.private String description;

5.private ArrayList projectItems = new ArrayList();

7.public Project(){ }

8.public Project(String newName, String newDescription){

9.name = newName;

10.description = newDescription;

11.}

12.

13.public String getName(){ return name; }

14.public String getDescription(){ return description; }

15.public ArrayList getProjectItems(){ return projectItems; }

17.public void setName(String newName){ name = newName; }

18.public void setDescription(String newDescription){ description = newDescription; }

20.public void addProjectItem(ProjectItem element){

21.if (!projectItems.contains(element)){

22. projectItems.add(element);

23.}

24.}

26.public void removeProjectItem(ProjectItem element){

27.projectItems.remove(element);

28.}

29.

30.public String toString(){ return name + ", " + description; }

31.}

Example A.233 ProjectItem.java

1.import java.io.Serializable;

2.import java.util.ArrayList;

3.public interface ProjectItem extends Serializable{

4.public ArrayList getProjectItems();

5.}

Example A.234 Task.java

1.import java.util.ArrayList;

2.public class Task implements ProjectItem{

3.private String name;

4.private ArrayList projectItems = new ArrayList();

5.private double timeRequired;

6.

7.public Task(){ }

8.public Task(String newName, double newTimeRequired){

346

9.name = newName;

10.timeRequired = newTimeRequired;

11.}

12.

13.public String getName(){ return name; }

14.public ArrayList getProjectItems(){ return projectItems; }

15.public double getTimeRequired(){ return timeRequired; }

17.public void setName(String newName){ name = newName; }

18.public void setTimeRequired(double newTimeRequired){ timeRequired = newTimeRequired; }

20.public void addProjectItem(ProjectItem element){

21.if (!projectItems.contains(element)){

22. projectItems.add(element);

23.}

24.}

26.public void removeProjectItem(ProjectItem element){

27.projectItems.remove(element);

28.}

29.

30.}

RunPattern creates a demonstration RMI client and server object. In the example, the main program thread uses the CallbackClientImpl object to request a project from the server, then enters a wait loop until the project is returned.

Example A.235 RunPattern.java

1.import java.io.IOException;

2.public class RunPattern{

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

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

5.System.out.println("This code will run two RMI objects to demonstrate");

6.System.out.println(" callback capability. One will be CallbackClientImpl,");

7.System.out.println(" which will request a project from the other remote");

8.System.out.println(" object, CallbackServerImpl.");

9.System.out.println("To demonstrate how the Callback pattern allows the");

10.System.out.println(" client to perform independent processing, the main");

11.System.out.println(" progam thread will go into a wait loop until the");

12.System.out.println(" server sends the object to its client.");

13.System.out.println();

14.

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

16.System.out.println();

17.try {

18.

Process

p1

=

Runtime.getRuntime().exec("rmic CallbackServerImpl");

19.

Process

p2

=

Runtime.getRuntime().exec("rmic CallbackClientImpl");

20.

p1.waitFor();

21.

p2.waitFor();

22.}

23.catch (IOException exc) {

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

25. System.exit(1);

26.}

27.catch (InterruptedException exc){

28.

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

29.

utility.");

}

30.

 

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

32.System.out.println();

33.Process rmiProcess = null;

34.try{

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

36. Thread.sleep(15000);

37.}

38.catch (IOException exc){

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

40. System.exit(1);

41.}

42.catch (InterruptedException exc){

43.System.err.println("Threading problems encountered when starting the

rmiregistry.");

44.

}

45.

 

46.System.out.println("Creating the client and server objects");

347

47.System.out.println();

48.CallbackServerImpl callbackServer = new CallbackServerImpl();

49.CallbackClientImpl callbackClient = new CallbackClientImpl();

51.System.out.println("CallbackClientImpl requesting a project");

52.callbackClient.requestProject("New Java Project");

53.

54.try {

55.

while(!callbackClient.isProjectAvailable()){

56.

System.out.println("Project not available yet; sleeping for 2 seconds");

57.

Thread.sleep(2000);

58.

}

59.}

60.catch (InterruptedException exc){}

61.System.out.println("Project retrieved: " + callbackClient.getProject());

62.}

63.}

348