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

Half-Object Plus Protocol (HOPP)

A Personal Information Manager should be available everywhere, but its data should only be stored in one place. This example uses RMI and the HOPP pattern to hold a personal calendar on a server, while making its information available to remote callers.

The Calendar interface defines all methods that will be available remotely. This interface extends

java.rmi.Remote and all its methods throw java.rmi.RemoteException. In this case, Calendar defines three methods: getHost, getAppointments, and addAppointment.

Example A.181 Calendar.java

1.import java.rmi.Remote;

2.import java.rmi.RemoteException;

3.import java.util.Date;

4.import java.util.ArrayList;

5.public interface Calendar extends Remote{

6.public String getHost() throws RemoteException;

7.public ArrayList getAppointments(Date date) throws RemoteException;

8.public void addAppointment(Appointment appointment, Date date) throws RemoteException;

9.}

Calendar is implemented by two classes—the RMI remote object and its stub, or proxy. (See “ Proxy ” on page 492.) The remote object class, CalendarImpl, provides method implementations, while the stub manages communication to the remote object. The Java RMI compiler (rmic) needs to be run on the CalendarImpl to generate a stub and a skeleton class. The skeleton class is provided for backward compatibility, but, as of Java 1.2, is no longer necessary.

Example A.182 CalendarImpl.java

1.import java.rmi.Naming;

2.import java.rmi.server.UnicastRemoteObject;

3.import java.io.File;

4.import java.util.Date;

5.import java.util.ArrayList;

6.import java.util.HashMap;

7.public class CalendarImpl implements Calendar{

8.private static final String REMOTE_SERVICE = "calendarimpl";

9.private static final String DEFAULT_FILE_NAME = "calendar.ser";

10.private HashMap appointmentCalendar = new HashMap();

11.

12.public CalendarImpl(){

13.this(DEFAULT_FILE_NAME);

14.}

15.public CalendarImpl(String filename){

16.File inputFile = new File(filename);

17.appointmentCalendar = (HashMap)FileLoader.loadData(inputFile);

18.if (appointmentCalendar == null){

19. appointmentCalendar = new HashMap();

20.}

21.try {

22.

UnicastRemoteObject.exportObject(this);

23.

Naming.rebind(REMOTE_SERVICE, this);

24.}

25.catch (Exception exc){

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

27.}

28.}

29.

30.public String getHost(){ return ""; }

31.public ArrayList getAppointments(Date date){

32.ArrayList returnValue = null;

33.Long appointmentKey = new Long(date.getTime());

34.if (appointmentCalendar.containsKey(appointmentKey)){

35. returnValue = (ArrayList)appointmentCalendar.get(appointmentKey);

36.}

37.return returnValue;

38.}

39.

40.public void addAppointment(Appointment appointment, Date date){

41.Long appointmentKey = new Long(date.getTime());

42.if (appointmentCalendar.containsKey(appointmentKey)){

43. ArrayList appointments = (ArrayList)appointmentCalendar.get(appointmentKey);

316

44. appointments.add(appointment);

45.}

46.else {

47. ArrayList appointments = new ArrayList();

48. appointments.add(appointment);

49. appointmentCalendar.put(appointmentKey, appointments);

50.}

51.}

52.}

The CalendarImpl object must use the RMI support class UnicastRemoteObject so that it can handle incoming communication requests. In this case, the CalendarImpl constructor exports itself using the static method

UnicastRemoteObject.exportObject.

CalendarImpl also needs to have some way of publishing itself to the outside world. In RMI, the naming service is called the rmiregistry. It must be running before the CalendarImpl object is created. The rmiregistry is like a telephone book, providing a connection between a name and an object. When the CalendarImpl object registers itself with the rmiregistry through the rebind method it binds the name "calendarimpl" to the stub of this remote object.

For a client to use the remote object it has to do a lookup in the rmiregistry of the host machine and receive the stub to the remote object. You can compare the stub to a telephone number. You can use that number from anywhere, on any phone, and you get connected to someone answering the number you’re calling. In this example, the CalendarHOPP class acts as the client for the CalendarImpl object.

Example A.183 CalendarHOPP.java

1.import java.rmi.Naming;

2.import java.rmi.RemoteException;

3.import java.util.Date;

4.import java.util.ArrayList;

5.public class CalendarHOPP implements Calendar, java.io.Serializable{

6.private static final String PROTOCOL = "rmi://";

7.private static final String REMOTE_SERVICE = "/calendarimpl";

8.private static final String HOPP_SERVICE = "calendar";

9.private static final String DEFAULT_HOST = "localhost";

10.private Calendar calendar;

11.private String host;

12.

13.public CalendarHOPP(){

14.this(DEFAULT_HOST);

15.}

16.public CalendarHOPP(String host){

17.try {

18. this.host = host;

19. String url = PROTOCOL + host + REMOTE_SERVICE; 20. calendar = (Calendar)Naming.lookup(url);

21. Naming.rebind(HOPP_SERVICE, this);

22.}

23.catch (Exception exc){

24.System.err.println("Error using RMI to look up the CalendarImpl or register the

CalendarHOPP " + exc);

25.}

26.}

28.public String getHost(){ return host; }

29.public ArrayList getAppointments(Date date) throws RemoteException{ return

calendar.getAppointments(date); }

30.

31.public void addAppointment(Appointment appointment, Date date) throws RemoteException

{calendar.addAppointment(appointment, date); }

32.}

The CalendarHOPP provides a key benefit over a conventional RMI client – it can locally run what would normally be remote methods. This can provide a substantial benefit in terms of communication overhead. The HOPP implements the same remote interface, but it will not export itself. It keeps a reference to the stub and forwards all the method calls to the stub that it does not (or cannot) handle. Now it can implement the methods that it wants to execute locally—in this example, the getHost method. The HOPP can be registered with the rmiregistry like a normal stub, but it now has the ability to execute methods locally.

Support classes for this example provide the ability to create Appointment objects to be stored by CalendarImpl.

317

Example A.184 Appointment.java

1.import java.io.Serializable;

2.import java.util.Date;

3.import java.util.ArrayList;

4.public class Appointment implements Serializable{

5.private String description;

6.private ArrayList contacts;

7.private Location location;

8.private Date startDate;

9.private Date endDate;

10.

11.public Appointment(String description, ArrayList contacts, Location location, Date

startDate, Date endDate){

12.this.description = description;

13.this.contacts = contacts;

14.this.location = location;

15.this.startDate = startDate;

16.this.endDate = endDate;

17.}

18.

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

20.public ArrayList getContacts(){ return contacts; }

21.public Location getLocation(){ return location; }

22.public Date getStartDate(){ return startDate; }

23.public Date getEndDate(){ return endDate; }

24.

25.public void setDescription(String description){ this.description = description; }

26.public void setContacts(ArrayList contacts){ this.contacts = contacts; }

27.public void setLocation(Location location){ this.location = location; }

28.public void setStartDate(Date startDate){ this.startDate = startDate; }

29.public void setEndDate(Date endDate){ this.endDate = endDate; }

30.

31.public String toString(){

32.

"\n

return "Appointment:" + "\n

Description: " + description +

33.

Location: " + location + "\n

Start: " +

34.

 

startDate + "\n

End: " + endDate + "\n";

35.}

36.}

Example A.185 Contact.java

1.import java.io.Serializable;

2.public interface Contact extends Serializable{

3.public static final String SPACE = " ";

4.public String getFirstName();

5.public String getLastName();

6.public String getTitle();

7.public String getOrganization();

8.

9.public void setFirstName(String newFirstName);

10.public void setLastName(String newLastName);

11.public void setTitle(String newTitle);

12.public void setOrganization(String newOrganization);

13.}

Example A.186 ContactImpl.java

1.public class ContactImpl implements Contact{

2.private String firstName;

3.private String lastName;

4.private String title;

5.private String organization;

6.

7.public ContactImpl(){}

8.public ContactImpl(String newFirstName, String newLastName,

9.String newTitle, String newOrganization){

10. firstName = newFirstName;

11. lastName = newLastName;

12. title = newTitle;

13. organization = newOrganization;

14. }

15.

16.public String getFirstName(){ return firstName; }

17.public String getLastName(){ return lastName; }

18.public String getTitle(){ return title; }

19.public String getOrganization(){ return organization; }

21.public void setFirstName(String newFirstName){ firstName = newFirstName; }

318

22.public void setLastName(String newLastName){ lastName = newLastName; }

23.public void setTitle(String newTitle){ title = newTitle; }

24.public void setOrganization(String newOrganization){ organization = newOrganization; }

26.public String toString(){

27.return firstName + SPACE + lastName;

28.}

29.}

Example A.187 Location.java

1.import java.io.Serializable;

2.public interface Location extends Serializable{

3.public String getLocation();

4.public void setLocation(String newLocation);

5.}

Example A.188 LocationImpl.java

1.public class LocationImpl implements Location{

2.private String location;

3.

4.public LocationImpl(){ }

5.public LocationImpl(String newLocation){

6.location = newLocation;

7.}

8.

9. public String getLocation(){ return location; }

10.

11. public void setLocation(String newLocation){ location = newLocation; }

12.

13.public String toString(){ return location; }

14.}

FileLoader class provides methods to load the Appointment collection from a file and save it to a file when required.

Example A.189 FileLoader.java

1.import java.io.File;

2.import java.io.FileInputStream;

3.import java.io.FileOutputStream;

4.import java.io.IOException;

5.import java.io.ObjectInputStream;

6.import java.io.ObjectOutputStream;

7.import java.io.Serializable;

8.public class FileLoader{

9.public static Object loadData(File inputFile){

10.Object returnValue = null;

11.try{

12.

if (inputFile.exists()){

13.

if (inputFile.isFile()){

14.

ObjectInputStream readIn = new ObjectInputStream(new

15.

FileInputStream(inputFile));

returnValue = readIn.readObject();

16.

readIn.close();

17.

}

18.

else {

19.

System.err.println(inputFile + " is a directory.");

20.

}

21.

}

22.

else {

23.

System.err.println("File " + inputFile + " does not exist.");

24.

}

25.}

26.catch (ClassNotFoundException exc){

27.

exc.printStackTrace();

28.

 

29.}

30.catch (IOException exc){

31.

exc.printStackTrace();

32.

 

33.}

34.return returnValue;

35.}

36.public static void storeData(File outputFile, Serializable data){

37.try{

319