34.

previous chapter table of contents next chapter
  

Room-Booking Example

The IDL for a room-booking problem was briefly discussed in the introductory "CORBA" section in this chapter. This room-booking example has a few more complexities than the previous example. The problem here is to have a set of rooms, and for each room have a set of bookings that can be made for that room. The bookings may be made on the hour , from 9 a.m. until 4 p.m. (this only covers the bookings for one day). Bookings may be cancelled after they are made. A room can be queried for the set of bookings it has: it returns an array of meetings, which are null if no booking has been made, or non-null including the details of the participants and the purpose of the meeting.

There are other things to consider in this example:

  • Each room is implemented as a separate CORBA object. There is also a "meeting factory" that produces more objects. This is a system with multiple CORBA objects residing on many CORBA servers. There are several possibilities for implementing a system with multiple objects.
  • Some of the methods return CORBA objects, and these may need to be exposed to clients. This is not a problem if the client is a CORBA client, but here we will have Jini clients .
  • Some of the methods throw user -defined exceptions, in addition to CORBA-defined exceptions. Both of these need to be handled appropriately.

CORBA Objects

CORBA defines a set of "primitive" types in the IDL, such as integers of various sizes, chars, etc. The language bindings specify the primitive types in each language that they are converted into. For example, the CORBA wide character ( wchar ) becomes a Java Unicode char . Things are different for non-primitive objects, which depend on the target language. For example, an IDL object turns into a Java interface.

The room-booking IDL defines CORBA interfaces for Meeting , MeetingFactory , and Room . These can be implemented in any suitable language and need not be in Java ”the Java binding will convert these into Java interfaces. A CORBA client written in Java will get objects that implement these interfaces, but these objects will essentially be references to remote CORBA objects. Two things are certain about these references:

  • CORBA interfaces generate Java interfaces, such as Hello . These inherit from org.omg.CORBA.portable.IDLEntity , which implements Serializable . As a result, the references can be moved around like Jini objects, but they lose their link to the CORBA ORB that created them and may end up in a different namespace, where the reference makes no sense. Therefore, CORBA references cannot be usefully moved around. At present, the best way to move them around is to convert them to "stringified" form and move that around, though this may change when CORBA pass- by-value objects become common. Note that the serialization method that gives a string representation of a CORBA object is not the same as the Java one: the CORBA method serializes the remote reference, whereas the Java method serializes the object's instance data.
  • The references do not subclass from UnicastRemoteObject or Activatable . The Java runtime will not use an RMI stub for them.

If a Jini client gets local references to these objects and keeps them local, then it can use them via their Java interfaces. If they need to be moved around the network, then appropriate "mobile" classes will need to be defined and the information copied across to them from the local objects. For example, the CORBA Meeting interface generates the following Java interface:

 /*  * File: ./corba/RoomBooking/Meeting.java  * From: RoomBooking.idl  * Date: Wed Aug 25 11:30:25 1999  *   By: idltojava Java IDL 1.2 Aug 11 1998 02:00:18  */ package corba.RoomBooking; public interface Meeting     extends org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity {     String purpose();     String participants();     void destroy() ; } 

To make the information from a CORBA Meeting available as a mobile Jini object, we would need an interface like this:

 /**  * JavaMeeting.java  */ package corba.common; import java.io.Serializable; import org.omg.CORBA.*; import corba.RoomBooking.*; import java.rmi.RemoteException; public interface JavaMeeting extends Serializable {     String getPurpose();     String getParticipants();     Meeting getMeeting(ORB orb); } // JavaMeeting 

The first two methods in the preceding interface allow information about a meeting to be accessible to applications that do not want to contact the CORBA service. The third allows a CORBA object reference to be reconstructed within a new ORB. A suitable implementation is as follows :

 /**  * JavaMeetingImpl.java  */ package corba.RoomBookingImpl; import corba.RoomBooking.*; import org.omg.CORBA.*; import corb.common.*; /**  * A portable Java object representing a CORBA object.  */ public class JavaMeetingImpl implements JavaMeeting {     protected String purpose;     protected String participants;     protected String corbaObj;     /**      * get the purpose of a meeting for a Java client      * unaware of CORBA      */     public String getPurpose() {         return purpose;     }     /**      * get the participants of a meeting for a Java client      * unaware of CORBA      */     public String getParticipants() {         return participants;     }     /**      * reconstruct a meeting using a CORBA orb in the target JVM      */     public Meeting getMeeting(ORB orb) {         org.omg.CORBA.Object obj = orb.string_to_object(corbaObj);         Meeting m = MeetingHelper.narrow(obj);         return m;     }     /**      * construct a portable Java representation of the CORBA      * Meeting using the CORBA orb on the source JVM      */     public JavaMeetingImpl(Meeting m, ORB orb) {         purpose = m.purpose();         participants = m.participants();         corbaObj = orb.object_to_string(m);     } } // JavaMeetingImpl 

Multiple Objects

The implementation of the room-booking problem in the Vogel and Duddy book ( Java Programming with CORBA , http://www. wiley .com/compbooks/vogel ) runs each room as a separate CORBA object, each with its own server. A meeting factory creates meeting objects that are kept within the factory server and passed around by reference. So, for a distributed application with ten rooms, there will be eleven CORBA servers running.

There are several possible ways of bringing this set of objects into the Jini world so that they are accessible to a Jini client:

  1. A Jini server may exist for each CORBA server.
    • Each Jini server may export fat proxies, which build CORBA references in the same Jini client.
    • Each Jini server may export a thin proxy, with a CORBA reference held in each of these servers.
  2. A single Jini server may be built for the federation of all the CORBA objects.
    • The single Jini server exports a fat proxy, which builds CORBA references in the Jini client.
    • The single Jini server exports a thin proxy, with all CORBA references within this single server.

The first of these pairs of options essentially isolates each CORBA service into its own Jini service. This may be appropriate in an open -ended system where there may be a large set of CORBA services, only some of which are needed by any application.

The second pair of options deals with the case where services come logically grouped together, such that one cannot exist without the other, even though they may be distributed geographically .

Intermediate schemes exist, where some CORBA services have their own Jini service, while others are grouped into a single Jini service. For example, rooms may be grouped into buildings and cannot exist without these buildings, whereas a client may only want to know about a subset of buildings , say those in New York.

Many Fat Proxies

We can have one Jini server for each of the CORBA servers. The Jini servers can be running on the same machines as the CORBA ones, but there is no necessity from either Jini or CORBA for this to be so. On the other hand, if a client is running as an applet, then applet security restrictions may force all the Jini servers to run on a single machine, the same one as an applet's HTTP server.

The Jini proxy objects exported by each Jini server may be fat ones, which connect directly to the CORBA server. Thus, each proxy becomes a CORBA client, as was the case in the "hello world" example. Within the Jini client, we do not just have one proxy, but many proxies. Because they are all running within the same address space, they can share CORBA references ”there is no need to package a CORBA reference as a portable Jini object. In addition, the Jini client can just use all of these CORBA references directly, as instance objects of interfaces. This situation is shown in Figure 18-2.

click to expand
Figure 18-2: CORBA and Jini services for fat proxies

The CORBA servers are all accessed from within the Jini client. This arrangement may be ruled out if the client is an applet and the servers are on different machines.

Many Thin Proxies

The proxies exported can be thin, such as RMI stubs. In this case, each Jini server is acting as a CORBA client. This situation is shown in Figure 18-3.

click to expand
Figure 18-3: CORBA and Jini services for thin proxies

If all the Jini servers are collocated on the same machine, then this becomes a possible architecture suitable for applets. The downside of this approach is that all the CORBA references are within different JVMs. In order to move the reference for a meeting from the Jini meeting factory to one of the Jini rooms, it may be necessary to wrap it in a portable Jini object, as discussed previously. The Jini client will also need to get information about the CORBA objects, which can be gained from these portable Jini objects.

Single Fat Proxy

An alternative to Jini servers for each CORBA server is to have a single Jini bridge server into the CORBA federation. This can be a feasible alternative when the set of CORBA objects form a complete system or module, and it makes sense to treat them as a unit. Then you have the choices again of where to locate the CORBA references ”either in the Jini server or in a proxy. Placing them in a fat proxy is shown in Figure 18-4.

click to expand
Figure 18-4: CORBA and Jini services for single fat proxy

Single Thin Proxy

Placing all the CORBA references on the server side of a Jini service means that a Jini client only needs to make one network connection to the service. This scenario is shown in Figure 18-5. This is probably the best option from a security viewpoint of a Jini client.

click to expand
Figure 18-5: CORBA and Jini services for single thin proxy

Exceptions

CORBA methods can throw exceptions of two types: system exceptions and user exceptions. System exceptions subclass from RuntimeException and so are unchecked. They do not need to have explicit try...catch clauses around them. If an exception is thrown, it will be caught by the Java runtime and will generally halt the process with an error message. This would result in a CORBA client dying, which would generally be undesirable. Many of these system exceptions will be caused by the distributed nature of CORBA objects, and probably should be caught explicitly. If they cannot be handled directly, then to bring them into line with the Jini world, they can be wrapped as "nested exceptions" within a Remote exception and thrown again.

User exceptions are declared in the IDL for the CORBA interfaces and methods. These exceptions are checked, and need to be explicitly caught (or re-thrown) by Java methods. If a user exception is thrown, this will be because of some semantic error within one of the objects and will be unrelated to any networking or remote issues. User exceptions should be treated as they are, without wrapping them in Remote exceptions.

Interfaces for Single Thin Proxy

This and the following sections build a single thin proxy for a federation of CORBA objects. The Vogel and Duddy book gives a CORBA client to interact with the CORBA federation, and this is used as the basis for the Jini services and clients.

Using a thin proxy means that all CORBA- related calls will be placed in the service object, and will be made available to Jini clients only by means of portable Jini versions of the CORBA objects. These portable objects are defined by two interfaces, the Java room interface

 /**  * JavaRoom.java  */ package corba.common; import corba.RoomBooking.*; import java.io.Serializable; import org.omg.CORBA.*; import java.rmi.RemoteException; public interface JavaRoom extends Serializable {     String getName();     Room getRoom(ORB orb); } // JavaRoom 

and the JavaMeeting interface

 /**  * JavaMeeting.java  */ package corba.common; import java.io.Serializable; import org.omg.CORBA.*; import corba.RoomBooking.*; import java.rmi.RemoteException; public interface JavaMeeting extends Serializable {     String getPurpose();     String getParticipants();     Meeting getMeeting(ORB orb); } // JavaMeeting 

The bridge interface between the CORBA federation and the Jini clients has to provide methods for making changes to objects within the CORBA federation and for obtaining information from them. For the room-booking system, this requires the ability to book and cancel meetings within rooms, and also the ability to view the current state of the system. Viewing is accomplished by three methods: updating the current state, getting a list of rooms, and getting a list of bookings for a room.

 /**  * RoomBookingBridge.java  */ package corba.common; import java.rmi.RemoteException; import corba.RoomBooking.*; import org.omg.CORBA.*; public interface RoomBookingBridge extends java.io.Serializable {     public void cancel(int selected_room, int selected_slot)         throws RemoteException, NoMeetingInThisSlot;     public void book(String purpose, String participants,                      int selected_room, int selected_slot)         throws RemoteException, SlotAlreadyTaken;     public void update()         throws RemoteException, UserException;     public JavaRoom[] getRooms()         throws RemoteException;     public JavaMeeting[] getMeetings(int room_index)         throws RemoteException; } // RoomBookingBridge 

There is a slight legacy in this interface that comes from the original "monoblock" CORBA client by Vogel and Duddy. In that client, because the GUI interface elements and the CORBA references were all in the one client, simple shareable structures, such as arrays of rooms and arrays of meetings, were used. Meetings and rooms could be identified simply by their index in the appropriate array. In splitting the client apart into multiple (and remote) classes, this is not really a good idea anymore because it assumes a commonality of implementation across objects, which may not occur. It doesn't seem worthwhile being too fussy about that here, though.

RoomBookingBridge Implementation

The room-booking Jini bridge has to perform all CORBA activities and to wrap these up as portable Jini objects. A major part of this is locating the CORBA services, which here are the meeting factory and the rooms. We do not want to get too involved in these issues here. The meeting factory can be found in essentially the same way as the hello server was earlier, by looking up its name. Finding the rooms is harder, as these are not known in advance. Essentially, the equivalent of a directory has to be set up on the name server, which is known as a "naming context." Rooms are registered within this naming context by their servers, and the client gets this context and then does a search for its contents.

The Jini component of this object is that it subclasses from UnicastRemoteObject and implements a RemoteRoomBookingBridge , which is a remote version of RoomBookingBridge . It is also worthwhile noting how CORBA exceptions are caught and wrapped in Remote exceptions.

 /**  * RoomBookingBridgeImpl.java  */ package corba.RoomBookingImpl; import org.omg.CORBA.*; import org.omg.CosNaming.*; import corba.RoomBooking.*; import corba.common.*; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.Vector; public class RoomBookingBridgeImpl extends UnicastRemoteObject implements Remote- RoomBookingBridge {     private MeetingFactory meeting_factory;     private Room[] rooms;     private Meeting[] meetings;     private ORB orb;     private NamingContext room_context;     public RoomBookingBridgeImpl(String[] args)         throws RemoteException, UserException {         try {             // initialize the ORB             orb = ORB.init(args, null);     }     catch(SystemException system_exception ) {         throw new RemoteException("constructor RoomBookingBridge: ",                                   system_exception);     }     init_from_ns();     update(); } public void init_from_ns()     throws RemoteException, UserException {     // initialize from Naming Service     try {         // get room context         String str_name = "/BuildingApplications/Rooms/";         org.omg.CORBA.Object objRef =             orb.resolve_initial_references("NameService");         NamingContext namingContext = NamingContextHelper.narrow(objRef);         NameComponent nc = new NameComponent(str_name, " ");         NameComponent path[] = {nc};         org.omg.CORBA.Object roomRef = namingContext.resolve(path);         room_context = NamingContextHelper.narrow(roomRef);         if( room_context == null ) {             System.err.println( "Room context is null," );             System.err.println( "exiting ..." );             System.exit( 1 );         }         // get MeetingFactory from Naming Service         str_name = "/BuildingApplications/MeetingFactories/MeetingFactory";         nc = new NameComponent(str_name, " ");         path[0] = nc;         meeting_factory =             MeetingFactoryHelper.narrow(namingContext.resolve(path));         if( meeting_factory == null ) {             System.err.println(                 "No Meeting Factory registered at Naming Service" );             System.err.println( "exiting ..." );             System.exit( 1 );         }     }     catch(SystemException system_exception ) {         throw new RemoteException("Initialize ORB", system_exception);     } } public void update()     throws RemoteException, UserException {     try {         // list rooms         // initialize binding list and binding iterator         // Holder objects for out parameter         BindingListHolder blHolder = new BindingListHolder();         BindingIteratorHolder biHolder = new BindingIteratorHolder();         BindingHolder bHolder = new BindingHolder();         Vector roomVector = new Vector();         Room aRoom;         // we are 2 rooms via the room list         // more rooms are available from the binding iterator         room_context.list( 2, blHolder, biHolder );         // get rooms from Room context of the Naming Service         // and put them into the roomVector         for(int i = 0; i < blHolder.value.length; i++ ) {             aRoom = RoomHelper.narrow(                 room_context.resolve( blHolder.value[i].binding_name ));             roomVector.addElement( aRoom );         }         // get remaining rooms from the iterator         if( biHolder.value != null ) {             while( biHolder.value.next_one( bHolder ) ) {                 aRoom = RoomHelper.narrow(                     room_context.resolve( bHolder.value.binding_name ) );                 if( aRoom != null ) {                     roomVector.addElement( aRoom );                 }             }         }         // convert the roomVector into a room array         rooms = new Room[ roomVector.size() ];         roomVector.copyInto( rooms );         // be friendly with system resources         if( biHolder.value != null )            biHolder.value.destroy();     }     catch(SystemException system_exception) {         throw new RemoteException("View", system_exception);         // System.err.println("View: " + system_exception);     } } public void cancel(int selected_room, int selected_slot)     throws RemoteException, NoMeetingInThisSlot {     try {         rooms[selected_room].Cancel(             Slot.from_int(selected_slot) );         System.out.println("Cancel called" );     }     catch(SystemException system_exception) {         throw new RemoteException("Cancel", system_exception);     } } public void book(String purpose, String participants,                     int selected_room, int selected_slot)     throws RemoteException, SlotAlreadyTaken {     try {         Meeting meeting =             meeting_factory.CreateMeeting(purpose, participants);         System.out.println( "meeting created" );         String p = meeting.purpose();         System.out.println("Purpose: "+p);         rooms[selected_room].Book(             Slot.from_int(selected_slot), meeting );         System.out.println( "room is booked" );     }     catch(SystemException system_exception ) {       throw new RemoteException("Booking system exception", system_exception);     } } /**  * return a list of the rooms as portable JavaRooms  */     public JavaRoom[] getRooms() {         int len = rooms.length;         JavaRoom[] jrooms = new JavaRoom[len];         for (int n = 0; n < len; n++) {             jrooms[n] = new JavaRoomImpl(rooms[n]);         }         return jrooms;     }     public JavaMeeting[] getMeetings(int room_index) {         Meeting[] meetings = rooms[room_index].View();         int len = meetings.length;         JavaMeeting[] jmeetings = new JavaMeeting[len];         for (int n = 0; n < len; n++) {             if (meetings[n] == null) {                 jmeetings[n] = null;             } else {                 jmeetings[n] = new JavaMeetingImpl(meetings[n], orb);             }         }         return jmeetings;     } } // RoomBookingBridgeImpl 

Other Classes

The Java classes and servers implementing the CORBA objects are mainly unchanged from the implementations given in the Vogel and Duddy book. They can continue to act as CORBA servers to the original clients. I replaced the "easy naming" naming service in their book with a later one with the slightly more complex standard mechanism for creating contexts and placing names within this context. This mechanism can use the tnameserv CORBA naming server, for example.

I have modified the Vogel and Duddy room-booking client a little bit, but its essential structure remains unchanged. The GUI elements, for example, were not altered . All CORBA-related code was removed from the client and placed into the bridge classes.

The Vogel and Duddy code samples can all be downloaded from a public Web site ( http://www.wiley.com/compbooks/vogel ) and come with no author attribution or copyright claim. The client is also quite lengthy since it has plenty of GUI inside, so I won't complete the code listing here. The code for all my classes, and the modified code of the Vogel and Duddy classes, is given in the subdirectory corba of the programs.zip file that can be found at http://www.apress.com .

Building the Room-Booking Example

The RoomBooking.idl IDL interface needs to be compiled to Java by a suitable IDL-to-Java compiler, such as Sun's idltojava . This produces classes in the corba.RoomBooking package. These can then all be compiled using the standard Java classes and any CORBA classes needed.

The Jini server, service, and client are also normal Java files and can be compiled like earlier Jini files, with the CLASSPATH set to include the Jini libraries.

Running the Room-Booking Example

There are a large number of elements and processes that must be set running to get this example working satisfactorily:

  1. A CORBA name server must be set running, as in the earlier example. For example, you could use the following command:
     tnameserv -ORBInitialPort 1055 

    All CORBA services and clients should also use this port number.

  2. A CORBA server should be started for each room, with the first parameter being the "name" of the room:
     java corba.RoomBookingImpl.RoomServer "freds room" -ORBInitialPort 1055 
  3. A CORBA server should be started for the meeting factory:
     java corba.RoomBookingImpl.MeetingFactoryServer -ORBInitialPort 1055 
  4. Typical Jini support services will need to be running, such as a lookup service, the RMI daemon rmid , and HTTP servers to move class definitions around.
  5. The Jini service can be started with this command:
     java corba.RoomBookingImpl.RoomBookingBridgeServer -ORBInitialPort 1055 
  6. Finally, the Jini client can be run with this command:
     java corba.RoomBookingImpl.RoomBookingClientApplication -ORBInitialPort 1055 
  


A Programmer[ap]s Guide to Jini Technology
A Programmer[ap]s Guide to Jini Technology
ISBN: 1893115801
EAN: N/A
Year: 2000
Pages: 189

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net