1. Introduction OMG's Common Object Request Broker Architecture (CORBA) has been known as one of most popular distributed object paradigms for a few years. Compare to CORBA, Sun's Jini is a fairly new one but grows really fast. Can the established CORBA services be available to the new Jini? In this paper, we will discuss the possible architectures for building a bridge to make Jini client and CORBA Server understand each other. 1.1 What is CORBA and How It Works CORBA represents for Common Object Request Broker Architecture. It was introduced and developed by the Object Management Group (OMG) to allow applications to communicate with one another regardless the location and the language used. In CORBA, the idea of accomplishment for communication is come from remote procedure call. So, CORBA is belongs to traditional distributed systems. The structure for CORBA is shown in Figure 1. Figure 1: CORBA Structure IDL (Interface Definition Language) needs to be written to define the interface that for client to understand server. ORB (Object Request Broker) is the middleware for CORBA. Communication between server and client is built through client stub, middleware ORB and server skeleton. The stub is code that implements the interface in client side. When a remote call is made in client, the stub converts the information that need to be sent to the server into form that server can understands, sends those converted information and then waits for a reply back. After the reply comes back, the stub will translate reply to internal form that used in client, and then handles translated result back to where the call is made. The skeleton is code does similar job as what the stub does, but it is happened in server side. The ORB intercepts the call from client and finds an object, which can implement that request. Once the ORB finds that object, it will then invoke the associate method and pass the results back to the client. 1.2 What is Jini and How It Works Jini is a relatively new technology, which is invented and developed by Sun. The name of "Jini" doesn't represent anything, just a name. With Jini, we gain a simple way to build networks of services available for clients. So, Jini is known as a network paradigm to provide "Plug-n-Play" network devices. Jini uses Java as implementation language. "The Jini system is a Java-centric system on the network, assuming and requiring that the communication between a client and the services used by that client are accomplished through a Java interface." (Jim, Waldo) In Jini, devices and applications are enabled to enter into a community of virtual machines on a network. A process called discovery is used to find out other services or devices. The devices will post objects to a Jini lookup service. Then other devices that want to use a service offered by the community can download the objects, device drivers or anything needed from the Jini lookup service. 1.3 Why doing this Project At introduction part, I mentioned briefly about what this project does. When we build a bridge between CORBA and Jini, why we make Jini act as client of CORBA server not versus? To make a clear answer for this question, we need to compare CORBA and Jini first. In CORBA, a client uses a single stub for communication with those available services that defined and implemented in the associate interface. Also a server uses a single stub to answer the call from a client via the same interface. Both stub and skeleton must be generated by a compiler before any communication can be made between client and server. In other words, they are static stub and skeleton. Communication between client and server is based on this pre-compiled code. This code is a sort of protocol between the client and the server. With this kind of protocol-based design, the system gains language independence. But such design brings the system rigidity for deployment. Because the stub is part of client and the skeleton is part of the server. So when services make any change, the client side of the system has to be changed simultaneously to keep that communication alive. It wasn't a serious problem when the system was not large and changes were not made quite often. But when the system moves to a large scale where all the services of the system may need to be changed quite often, protocol-based design could lead the system into terrible nightmare. On the contrast, Jini works as a Java-based system to provide more realistically networks. The major difference between CORBA and Jini, is that in Jini the stub code is used but not owned by the client. What client obtained from Lookup Services is a proxy object. It is equivalent to dynamically load a stub into the client (in some situations, client might actually load a stub into it). So when the services changed its functionality, it does not need to worry about notifying client at the same time. The client will update itself automatically when next time it calls this function. If a network system, which has Jini client, uses Jini service but that service can understand CORBA server, then when the server side make any modification, this modification does not need to be reflected at client side, instead, the modification will be happened within the Jini service. We cannot really make the CORBA client stub disappear, what we may be achieved is hiding CORBA object from Jini clients, so those Jini clients do not need to worry about whether it is a Jini server or a CORBA server. In order to achieve that goal, what we need is a bridge between CORBA and Jini. Because CORBA uses Internet Inter-ORB Protocol (IIOP)-which is a TCP protocol, and the current implementation of Jini also uses TCP. So there is possibility to make CORBA and Jini understand each other. 2. Bridging between CORBA and Jini 2.1 CORBA IDL IDL is used for defining interfaces of objects. IDL syntax is similar to C++, but not specify implementation-level constructs. It supports constants, data type declarations, attributes, operations, interfaces and modules. The following CORBA IDL example will be used through this paper. This example is taken from Client / Server Computing lecture notes, which is modified from original example that could be find in "Java Programming with CORBA" by Andreas Vogel and Keith Duddy. module corba { module RoomBooking { interface Meeting { // A meeting has two read-only attributes which describes // the purpose and the participants of that meeting. readonly attribute string purpose; readonly attribute string participants; oneway void destroy(); }; interface MeetingFactory { // A meeting factory creates meeting objects. Meeting createMeeting( in string purpose, in string participants); }; enum Slot { am9, am10, am11, pm12, pm1, pm2, pm3, pm4 }; // since IDL does not provide means to determine the // cardinality of an enum, a corresponding constant MaxSlots // is defined. const short MaxSlots = 8; // Meetings can be held between the usual business hours. // For the sake of simplicity there are 8 slots at which // meetings can take place. // Meetings associates all meetings (of a day) with time // slots for a room. exception NoMeetingInThisSlot {}; exception SlotAlreadyTaken {}; interface Room { // A Room provides operations to view, make and cancel // bookings. // Making a booking means associating a meeting with a time-// slot (for this particular room). typedef Meeting Meetings[ MaxSlots ]; // The attribute "name" names a room. readonly attribute string name; // view returns the bookings of a room. // For simplicity, the implementation handles only bookings // for one day. Meetings view(); void book( in Slot a_slot, in Meeting a_meeting ) raises(SlotAlreadyTaken); void cancel( in Slot a_slot ) raises(NoMeetingInThisSlot); }; }; ...}; In this IDL example, it specifies a room booking service. It defines an interface Meeting, an interface MeetingFactory to produce Meeting, and an interface Room. In Room, it offers book, cancel, and view Meeting function. In the next session, we will take the CORBA implementation example in Java from the book before we move to Jini. 2.2 CORBA to Java Mapping For understanding CORBA to Jini mapping, we need first have a look at how OMG IDL maps to Java, since Jini is Java-centric. In this section, we will do a review based on standard mapping published by OMG, using RoomBooking as the example. 2.2.1General Rules An IDL module is mapped to a Java package with the same name. All IDL type declarations within the module are mapped to corresponding Java class or interface declarations within the generated package. The example CORBA IDL module RoomBooking{...} will be mapped to Package RoomBooking; When doing IDL to Java mapping, first of all, there are reserved names need to know: The Java class Helper, where is the name of an IDL defined type. The Java class Holder, where is the name of an IDL defined type (with certain exceptions such as typedef aliases). The Java classes Holder, where is one of the Java primitive datatypes that is used by one of the IDL basic datatypes The Java classes Operations, POA, and POATie, where is the name of an IDL interface type. The nested scope Java package name Package, where is the name of an IDL interface The keywords in the Java language: abstract default if private Throw boolean do implements protected Throws break double import public Transient byte else instanceof return Try case extends int short Void catch final interface static Volatile char finally long super While class float native switch const for new synchronized continue goto package this The additional Java constants: true false null IDL declarations that collide with the following methods on java.lang.Object clone equals finalize getClass hashCode notify notifyAll toString wait The use of any of these names for a user defined IDL type or interface will result in the mapped name having an underscore ( _ ) prepended. In this RoomBooking example, we will do Mapping of module Mapping for Basic Types Mapping for Constant Mapping for Enum Mapping for Array Mapping for Interface Mapping for Exception Mapping for Typedef Helpers Besides above types that covered by this example, there're other types such as Mapping for struct Mapping for Union Mapping for Sequence Mapping for the Any Type Mapping for Certain Nested Types Mapping Pseudo Objects to Java Server-Side Mapping Java ORB Portability Interfaces Following is a step-by-step mapping for the RoomBooking Example. 2.2.2 Mapping for interface Meeting The following are rules for doing mapping for a non-abstract interface A non-abstract IDL interface is mapped to two public Java interfaces: a signature interface and an operations interface. The signature interface extends IDLEntity. It has the same name as the IDL interface name and is used as the signature type in method declarations when interfaces of the specified type are used in other interfaces. The operations interface has the same name as the IDL interface with the suffix Operations appended to the end and is used in the server-side mapping and as a mechanism for providing optimised calls for collocated client and servers. The Java operations interface contains the mapped operation signatures. The Java signature interface extends the operations interface, the base org.omg.CORBA.Object, also org.omg.portable.IDLEntity. Methods can be invoked on the signature interface. A helper class is generated. The helper class holds a static narrow method that allows an org.omg.CORBA.Object to be narrowed to the object reference of a more specific type. The IDL exception CORBA::BAD_PARAM is thrown if the narrow fails because the object reference does not support the requested. Trying to narrow a null will always succeed with a return value of null. There are no special "nil" object references. Java null can be passed freely wherever an object reference is expected. Attributes are mapped to a pair of Java accessor and modifier methods. There methods have the same name as the IDL attribute and are overloaded. There is no modifier method for IDL readonly attributes. The holder class for the interface is also generated. Its name is the interface's mapped Java classname with Holder appended to it as shown as beneath. package RoomBooking; public interface MeetingOperations{ String purpose; String participant; void destroy(); }// End MeetingOperations public interface Meeting extends MeetingOperations, org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity{ }// End Meeting abstract public class MeetingHelper{ public static void insert(org.omg.CORBA.Any a, Meeting m){...} public static Meeting extract (Any a) {...} public static org.omg.CORBA.TypeCode type() {...} public static String id() {...} public static Meeting read( org.omg.CORBA.portable.InputStream is) {...} public static void write( org.omg.CORBA.portable.OutputStream os, Meeting val) {...} public static Meeting narrow(org.omg.CORBA.Object obj) {...} }// End MeetingHelper final public class MeetingHolder implements org.omg.portable.Stramable{ public Meeting value; public MeetingHolder(){} public MeetingHolder(Meeting initial){ valuc = initial; public void _read(org.omg.CORBA.portable.InputStream is){...} public void _write(org.omg.CORBA.portable.OutputStream os){...} public org.omg.CORBA.TypeCode _type(){...} } }// End MeetingHolder 2.2.3 Mapping for Enum Slot An IDL enum is mapped to a Java class which implements IDLEntity with the same name as the enum type, which declares a value method. Two static data members per label, an integer conversion method, and a protected constructor. In Slot class, one of the members is a public static final that has the same name as the IDL enum label. The other has an underscore (_) prepended and is intended to be used in switch statements. The value method returns the integer value. Values are assigned sequentially starting with 0. value()method does not conflict with label named value. The Java class for the enum has an additional method from_int(). It returns the enum with the specified value. A helper class is generated. The holder class for enum is also generated. Its name is the enum's mapped Java classname with Holder appended to it. public class Slot implements org.omg.CORBA.portable.IDLEntity{ public static final int _am9 = 0; public static final Slot am9 = new Slot(_am9); public static final int _am10 = 1; public static final Slot am10 = new Slot(_am10); public static final int _am11 = 2; public static final Slot am11 = new Slot(_am11); public static final int _am12 = 3; public static final Slot am12 = new Slot(_am12); public static final int _pm1 = 4; public static final Slot pm1 = new Slot(_pm1); public static final int _pm2 = 5; public static final Slot pm2 = new Slot(_pm2); public static final int _pm3 = 6; public static final Slot pm3 = new Slot(_pm3); public static final int _pm4 = 7; public static final Slot pm4 = new Slot(_pm4); public int value(){...}; public static Slot from_int(int value){...}; //constractor protected Slot(int){...} }// End Slot abstract public class SlotHelper{ public static void insert(org.omg.CORBA.Any a, Slot s){...} public static Slot extract(Any a){...} public static org.omg.CORBA.TypeCode type(){...} public static String id(){...} public static Slot read(org.omg.CORBA.portable.InputStream is){...} public static Slot write(org.omg.CORBA.portable.InputStream os){...} public org.omg.CORBA.TypeCode _type(){...} }// End SlotHelper final public class SlotHolder implements org.omg.CORBA.portable.Streamable{ public Slot value; public SlotHolder(){} public SlotHolder(Slot initial){...} public void _read( org.omg.CORBA.portable.InputStream is){...} public void _write( org.omg.CORBA.portable.OutputStream os){...} public org.omg.CORBA.TypeCode _type(){...} }// End SlotHolder 2.2.4 Mapping for const MaxSlots Mapping for constants is depending upon the scope in which they appeared. Constants could be within or not within an interface. In our example, the constant is not within an interface. Constants that not declared within an IDL interface are mapped to a public interface with the same name as the constant and containing a field, named value. public interface MaxSlots{ short value = (short) 8; }// End MaxSlots 2.2.5 Mapping for typedef Meetings Helper classes are generated for all typedefs. Typedefs that are type declarations for simple types are mapped to the original everywhere the typedef type appears. Typedefs for types that are neither arrays nor sequences are "unwound" to their original type until a simple IDL type or user-defined IDL type is encountered. Holder classes are generated for sequence and array typedefs only. final puclic class MeetingsHolder implements org.omg.CORBA.portable.Streamable( public short[] value; public MeetingsHolder(){} public MeetingsHolder(short[] initial){...} public void _read(org.omg.CORBA.portable.InputStream is) {...} public void _write(org.omg.CORBA.portable.OutputStream os){...} public org.omg.CORBA.TypeCode _type(){...} )// End MeetingsHolder abstract public class MeetingsHelper{ public static void insert(org.omg.CORBA.Any a, short[] t){...} public static short[] extract(Any a){...} public static org.omg.CORBA.TypeCode type(){...} public static String id(){...} public short[] read(org.omg.CORBA.portable.InputStream isream){...} public static write( org.omg.CORBA.portable.OuotputStream ostream, short[] val){...} }// End MeetingsHelper 2.2.6 Mapping for Exception NoMeetingInThisSlot and SlotAlreadyTaken IDL exceptions are mapped to a Java class that provides instance variables for the fields of the exception and constructors. CORBA system exceptions are unchecked exceptions. They inherit from java.lang.RuntimeException. User defined exceptions are checked exceptions. They inherit from java.lang.Exception via org.omg.CORBA.UserException which itself extends IDLEntity. User defined exceptions are mapped to final Java classes that extend org.omg.CORBA.UserException and have a "extra full" constructor (see commence in classes below) If the exception is defined within a nested IDL scope (essentially within an interface). Then its Java class name is defined within a special scope. Otherwise, its Java class name is defined within the scope of the Java package that corresponds to the exception's enclosing IDL module. final public class NoMeetingInThisSlot extends org.omg.CORBA.UserException{ public NoMetingInThisSlot(){ super(NoMeetingInThisSlotHelper.id()); } public NoMeetingInThisSlot(String reason){ super(NoMeetingInThisSlotHelper.id() + ":" + reason); // full constructor } }// End NoMeetingInThisSlot final public class NoMeetingInThisSlotHolder implements ort.omg.CORBA.portable.Streamable{ public NoMeetingInThisSlot value; public NoMeetingInThisSlotHolder(){} public NoMeetingInThisSlotHolder(NoMeetingInThisSlot initial) {...} public void _read(org.omg.CORBA.portable.InputStream is){...} public void _write(org.omg.CORBA.portable.OutputStream os){...} public org.omg.CORBA.TypeCode _type(){...} }// End NoMeetingInThisSlotHolder final public class SlotAlreadyTaken extends org.omg.CORBA.UserException( public SlotAlreadyTaken(){ super(SlotAlreadyTakenHelper.id()); } public SlotAlreadyTaken(String reason){ super(SlotAlreadyTakenHelper.id() + ":" + reason); } }// End SlotAlreadyTaken final public class SlotAlreadyTakenHolder implements org.omg.CORBA.portable.Streamable{ public SlotAlreadyTaken value; public SlotAlreadyTakenHolder(){} public SlotAlreadyTakenHolder(SlotAlreadyTaken initial){...} public void _read(org.omg.CORBA.portable.InputStream is){...} public void _write(org.omg.CORBA.portable.OutputStream os){...} public org.omg.CORBA.TypeCode _type(){...} }// End SlotAlreadyTakenHolder 2.2.7 Mapping for interface MeetingFactory Rules are the same as Mapping for interface Meeting. public interface MeetingFactoryOperations{ Meeting CreatMeeting(String purpose, String participants); }// End MeetingFactoryOperations public interface MeetingFactory extends MeetingFactoryOperations, org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity{ }// End MeetingFactory abstract public class MeetingFactoryHelper{ public static void insert(org.omg.CORBA.Any a, MeetingFactory t){...} public static MeetingFactory extract(Any a){...} public static org.omg.CORBA.TypeCode type(){...} public static String id(){...} public static MeetingFactory read( org.omg.CORBA.portable.InputStream is) {...} public static MeetingFactory write( org.omg.CORBA.OutputStream os, MeetingFactory val){...} public static MeetingFactory narrow(org.omg.CORBA.Object obj) {...} }// End MeetingFactoryHelper final public class MeetingFactoryHolder implements org.omg.CORBA.portable.Streamable{ public MeetingFactory value; public MeetingFactoryHolder(){} public MeetingFactoryHolder(MeetingFactory initial){...} public void _read(org.omg.CORBA.portable.InputStream is){...} public void _write(org.omg.CORBA.portable.OutputStream os){...} public org.omg.CORBA.TypeCode _type(){...} }// End MeetingFactoryHolder 2.2.8 Mapping for interface Room public interface RoomOperations{ String name; void book(Slot a_slot, Meeting a_meeting) throws RoomBooking.SlotAlreadyTaken; void cancel(Slot a_slot) throws RoomBooking.NoMeetingInThisSlot; }// End RoomOperations public interface Room extends RoomOperations, org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity{ }// End Room final public class RoomHelper implements org.omg.CORBA.portable.Streamable{ public Room value; public RoomHolder(){} public RoomHolder(Room initial){...} public void _read(org.omg.CORBA.portable.InputStream is){...} public void _write(org.omg.CORBA.portable.OutputStream os){...} public org.omg.CORBA.TypeCode _type(){...} }// End RoomHelper abstract public class RoomHelper{ public static void insert(org.omg.CORBA.Any a, Room t){...} public static Room extract(Any a){...} public static org.omg.CORBA.TypeCode type(){...} public static String id(){...} public static Room read(org.omg.CORBA.portable.InputStream is) {...} public static void write( org.omg.CORBA.portable.OutputStream os, Room val){...} public static Room narrow(org.omg.CORBA.Object obj){...} }// End RoomHelper 2.3 Move RoomBooking Example from CORBA to Jini 2.3.1 4 Models The implementation of the room booking problem in the Vogel and Duddy book runs each room as a separate CORBA object, each with its own server. A meeting factory creates meeting objects, which 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, including 1.A Jini server may exist for each CORBA server 1.Each Jini server may export fat proxies, which build CORBA references in the same Jini client. In this case, we call it "many servers with fat proxies". 2.Each Jini server may export a thin proxy, with a CORBA reference held in each of these servers. In this case, we call it "many servers with thin proxies". 2.A single Jini server may be built for the federation of CORBA objects 1.The single Jini server exports fat proxies, which build CORBA references in the Jini client. In this case, we call it "single server with fat proxies". 2.The single Jini server exports thin proxies, with all CORBA references within this single server. In this case, we call it "single server with thin proxies". 2.3.1.1 Many Servers with 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 to do so. Applet security restrictions, for example, may mean that all the Jini servers are running 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 dealt with 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. Diagrammatically, this appears as Figure 3: Many Servers with Fat Proxies The CORBA servers are all accessed from within the Jini client. This may rule out this arrangement if the client is an applet, and the servers are on different machines. 2.3.1.2 Many Servers with Thin Proxies The proxies exported can be thin, such as RMI stubs. In this case each Jini server is acting as a CORBA client. Figure 4: Many Servers with 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 above. The Jini client will also need to get information about the CORBA objects, which can be gained from these portable Jini objects. 2.3.1.3 Single Server with Fat Proxies An alternative to Jini servers for each CORBA server is to have a single Jini 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. There are then 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 looks like Figure 5: Single Server with Fat Proxies 2.3.1.4 Single Server with Thin Proxies 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. Figure 6: Single Server with Thin Proxies 2.3.1.5Summery for 4 Models The following table is a summery for 4 models that are shown in previous sections from 2.3.1.1 to 2.3.1.4. 2.4 Jini Service 2.4.1Two Architectures There are two architectures could be used for representing Jini side model. The first one is above 4 models share one common Jini service, in other words, the CORBA IDL translated to Jini service is the general one that could be understand for all 4 models. But the implementation of each model may be slightly different from one to another. This is shown as Figure 7. This model is chosen for further discussion in this paper. In session 2.4.2, the rules for moving example from CORBA to Jini are also based on this model. Figure 7 one common Jini service The other architecture could be used is different Jini service for each model. In other words, they do not share a common Jini service, so how the CORBA IDL translate to Jini service is depended on which model the CORBA service is currently running. Therefore, each model has its own Jini service. This is shown as Figure 8. Figure 8: non-common Jini service 3.Moving RoomBooking from CORBA IDL to Jini Services There are some rules for mapping when the RoomBooking IDL, which is given in section 2.1, moves from CORBA to Jini under common Jini Service model. 3.1 General Rules for Mapping In this section, I will give some general rules that applied for mapping. 3.1.1 Reserved Words The reserved names for Jini mapping are those keywords in the Java language. abstract Default If private Throw boolean Do implements protected throws break Double import public transient Byte Else instanceof return Try Case Extends int short Void catch Final interface static volatile Char Finally long super While class Float native switch const For new synchronized continue Goto package this The additional Java constants: true false null IDL declarations that collide with the following methods on java.lang.Object clone equals finalize getClass hashCode notify notifyAll toString wait 3.1.2Mapping for Module An IDL model is mapped to a Java package with the same name having the "Jini" prepended. All IDL type declarations within the module are mapped to corresponding Java class or interface declarations within the generated package. The example in CORBA IDL module RoomBooking{...} will be mapped to Package JiniRoomBooking; 3.1.3 Mapping for Basic Type This part will be quite similar with what appeared in IDL to Java mapping, which is given in standard book IDL to Java Mapping. The unsigned types should be carefully used since there is not support in Java language for unsigned types. A table is given in next page to shown the mapping. IDL Type Java Type boolean boolean char Char wchar Char octet byte string java.lang.String wstring java.lang.String short short unsigned short long int unsigned long int long long long unsigned long long Long float float double double fixed java.Math.BigDecimal 3.1.4 Mapping for Attributes Attributes are mapped to Java declaration with the same name as the IDL attributes, and associative methods have the same name as the IDL attributes but with "get" prepended. All mapped methods will throw RemoteException. The example in CORBA IDL readonly attribute string purpose; will be mapped to: String purpose; public String getPurpose( ) throws RemoteException{} 3.1.5Mapping for interface Each interface that defined within the same module for CORBA IDL will be mapped to separate Java interface class in the same package, the package name is the same with CORBA module name. The example in CORBA IDL interface Meeting{...} will be mapped to: public interface Meeting{...} 3.1.6Mapping for methods Methods are mapped to Java methods have the same name as the IDL methods. Passing parameters in IDL would have "in", but it would not appeared after mapping. Name of the passing parameters will have the same name as them in IDL. All the user defined type using in the method call (it includes return type and passing parameters' type) will have "Jini" prepended. The example in CORBA IDL, which is method mapping with non-user defined type of parameters, is Meeting createMeeting(in string purpose, in string participants); will be mapped to public JiniMeeting createMeeting(String purpose, String participants) throws RemoteException{} The example in CORBA IDL, which is method mapping with user-defined type parameters, is void book(in Slot a_slot, in Meeting a_meeting) raises(SlotAlreadyTaken); will be mapped to public void book(int a_slot, JiniMeeting a_meeting) throws RemoteException, SlotAlreadyTaken; 3.1.7Mapping for enum enum appeared in IDL will be mapped to basic type int, the rest places where that appeared in IDL will be replaced by int. The example in CORBA IDL enum Slot{am9, am10, am11, am12, pm1, pm2, pm3, pm4}; ... void cancel(in Slot a_slot) When mapped to Jini, the Slot in cancel method will be replaced by int. please refer to 3.2 for further details. 3.1.8 Mapping for exception User defined exception in IDL where appeared as raises(UserDefinedException) will mapped to where throws UserDefinedException. The example in CORBA IDL void book(in Slot a_slot, in Meeting a_meeting) raises(SlotAlreadyTaken); will be mapped to public void book(int a_slot, JiniMeeting a_meeting) throws RemoteException, SlotAlreadyTaken; 3.1.9Mapping for const Constants that defined within an interface will be mapped to a public declaration for that constant with the same name in which the interface it belonged. The RoomBooking example doesn't cover this type. If we assume that const short MaxSlots = 8; appeared within interface Room, then that should be mapped to: public final short MaxSlots = 8; within the mapped interface JiniRoom. Constants that defined non-within an interface will be mapped to a separate class for that constant with the same name. The example in RoomBooking CORBA IDL const short MaxSlots = 8; will be mapped to following: package JiniRoomBooking; public interface MaxSlots{ short value = (short) 8; } 3.1.10Mapping for typedef typedef that are type declarations for simple types are mapped to the original everywhere the typedef type appears. Those typedef that are type declarations for user defined types are mapped to the everywhere that user defined type encountered with "Jini" prepended. The example in CORBA IDL typedef Meeting Meetings[Maxslots]; ... Meetings view(); will be mapped to public JiniMeeting[] view( ) throws RemoteException{} A fully mapped RoomBooking example is given in 3.2 Common Jini Service 3.2 Common Jini Service For the common Jini service, if just based on the general rules that have been discussed in 3.1, it may first looks like what shown in 3.2.1. But when we go into the implementation level in the real world, because the CORBA references may not available for calling object, especially in the separate servers model (it will be further discussed in next section 3.3), therefore, we may need get String format Meetings, MeetingFactory or even Room to transfer those objects. So, the interfaces may finally be something looks like the following interfaces, please note the getMeetingString() etc. 3.2.1Ideal Common Jini Service The following three interfaces are ideal common Jini service for the RoomBooking example. /***** * JiniMeeting.java *****/ package JiniRoomBooking; import corba.RoomBooking.*; public interface JiniMeeting { public String getPurpose() throws RemoteException; public String getParticipants() throws RemoteException; public void destroy() throws RemoteException; }// End JiniMeeting /***** * JiniMeetingFactory.java *****/ package JiniRoomBooking; import corba.RoomBooking.*; public interface JiniMeeingFactory { public JiniMeeting createMeeting(String purpose, String participants) throws RemoteException; }// End JiniMeetingFactory /***** * JiniRoom.java *****/ package JiniRoomBooking; import corba.RoomBooking.*; public interface JiniRoom { private JiniMeeting[] JiniMeetings; public String getName() throws RemoteException; public void book(int a_slot, JiniMeeting a_meeting) throws RemoteException, SlotAlreadyTaken; public void cancel(int a_slot) throws RemoteException, NoMeetingInThisSlot; public JiniMeeting[] view() throws RemoteException; } // End JiniRoom 3.2.2More Realistic Common Jini Service As mentioned before, the following three interfaces would be think as more suitable for the common Jini service. In these part, what we add is getMeetingString() getRoomString() for each associated interface. /***** * JiniMeeting.java *****/ package JiniRoomBooking; import corba.RoomBooking.*; public interface JiniMeeting { public String getPurpose()throws RemoteException; public String getParticipants()throws RemoteException; public void destroy()throws RemoteException; Meeting getMeeting()throws RemoteException; // here the Meeting is CORBA object. String getMeetingString()throws RemoteException; //then programmers can use ORB.object_to_string() method //to convert it to standard format. }// End JiniMeeting /***** * JiniMeetingFactory.java *****/ package JiniRoomBooking; import corba.RoomBooking.*; public interface JiniMeeingFactory { public JiniMeeting createJiniMeeting(String purpose, String participant); throws RemoteException; public Meeting createMeeting(String purpose, String participant); throws RemoteException; public MeetingFactory getMeetingFactory() throws RemoteException; }// End JiniMeetingFactory /***** * JiniRoom.java *****/ package JiniRoomBooking; import corba.RoomBooking.*; public interface JiniRoom { public String getName()throws RemoteException; public void book(int selected_Slot, JiniMeeting selected_Meeting) throws RemoteException, SlotAlreadyTaken; public void cancel(int selected_Slot) throws RemoteException, NoMeetingInThisSlot; public JiniMeeting[] view()throws RemoteException; Room getRoom()throws RemoteException; // here the Room is CORBA object. String getRoomString()throws RemoteException; //then programmers can use ORB.object_to_string() method //to convert it to standard format. } // End JiniRoom 3.3 Implementation for Many Thin Proxies 3.3.1 Two Cases for Running Servers: Separate Servers and Single Server For implementation of this RoomBooking example, I choose doing Many Thin Proxies first. In this model, there're still two cases: separate servers and single server. 3.3.1.1 Separate Servers In separate servers case, each JiniRoom will have its own server, they all run in different spaces. Jini Client gets all the thin proxies for each server. But how to make the JiniMeeting is known by JiniRoom the method call book(int selectedSlot, JiniMeeting jMeeting)? There are two ways for solving this problem. One is adding a JiniMeeting Server, and that JiniMeeting Server exports a thin proxy that is also available in the Jini Client spaces, therefore that JiniMeeting Server will be available for each JiniRoom Server. This is represented in Figure 9. Figure 9: Meeting server is available for all Room servers, MeetingFactory server and Jini client in separate servers for many thin proxies. The other way is JiniMeetingFactory server creates JiniMeeting and each JiniRoom server makes a call to JiniMeetingFactory server to get the created JiniMeeting. This way is shown in Figure 10. Figure 10: Meeting server is available only for Room servers and MeetingFactory server in separate servers for many thin proxies. No matter which way is used, the number of running servers will be the same. If number of rooms is n, then the total of running servers will be n + 2, the extra two servers are one JiniMeeting server plus one JiniMeetingFactory server. The little problem caused by separate servers case is that each server does not share CORBA reference, so the CORBA Meeting, CORBA MeetingFactory and CORBA Room that used in the implementation for getMeeting(), getMeetingFactory() and getRoom() has to use string format. So the programmers will use methods object_to_string() and string_to_object() for concatenation. 3.3.1.2 Single Server The second case is single server for many thin proxies. In this case, all the servers will run in same space, therefore, they will share CORBA reference for each other. So it does not need a separate JiniMeeting server; it also can pass CORBA reference to wherever it is needed. So it does not need string format for CORBA Meeting, CORBA MeetingFactory and CORBA Room. This is shown in Figure 11. Figure 11: single server for many thin proxies. 3.3.2Implementation for Separate Servers In separate servers model, as we already discussed before, the problem here is: Jini Room Server need to get Jini Meeting for either make a booking or view method. There are two cases (please refer to 3.3.1.1 Figure 9 and Figure 10) to make Jini Meeting available to Jini Room server: have Jini Meeting server registered in Jini Client, and each Jini Room server has connection to associated CORBA Meeting server; or make Jini MeetingFactory server take the job for looking after Jini Meeting to Jini Room server. No matter which case is going to be used, the point here is: we need string formatted Meeing, no matter that Meeting is got from Meeting server or created by MeetingFactory. That is why you will see getMeeting and getMeetingString() in JiniMeetingImpl.java. 3.3.2.1Jini Service for Separate Servers The following is Jini service for separate servers. /****** * JiniMeetingImpl.java // Jini service for separate servers ******/ package JiniRoomBooking; import org.omg.CORBA.*; import org.omg.CosNaming.*; import corba.RoomBooking.*; //import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class JiniMeetingImpl implements JiniMeeting{ private Meeting corbaMeeting; private String corbaMeetingString; private String purpose; private String participants; private static HashMap map = new HashMap(); private ORB orb; public JiniMeetingImpl(){ }// End JiniMeetingImpl default constructor public JiniMeetingImpl(Meeting CORBAMeeting, ORB inOrb){ corbaMeeting = CORBAMeeting; orb = inOrb; corbaMeetingString = orb.object_to_string( CORBAMeeting); map.add(corbaMeetingString, this); }// End JiniMeetingImpl constructor public String getPurpose() throws RemoteException { return corbaMeeting.getPurpose(); }// End getPurpose public String getParticipants()throws RemoteException { return corbaMeeting.getParticipants(); }// End getParticipants public Meeting getMeeting() throws RemoteException{ return MeetingHelper.narrow( orb.string_to_object(corbaMeetingString)); }// End getMeeting public String getMeetingString() throws RemoteException{ return corbaMeetingString; }// End getMeeting public static JiniMeeting getRelativeJiniMeeting( String CORBAMeetingString){ return map.get(CORBAMeetingString); }// End getCORBAMeetingString }// End JiniMeetingImpl /******* * JiniMeetingFactoryImpl.java *******/ package JiniRoomBooking; import org.omg.CORBA.*; import org.omg.CosNaming.*; import RoomBooking.*; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class JiniMeetingFactoryImpl extends UnicastRemote implements JiniMeetingFactory{ private MeetingFactory corbaMeetingFactory; private String corbaMeetingFactoryString; public JiniMeetingFactoryImpl()throws RemoteException { }// End JiniMeetingFactory default constructor public JiniMeetingFactoryImpl(MeetingFactory meetingFactory, ORB orb) throws RemoteException { corbaMeetingFactory = meetingFactory; corbaMeetingFactoryString = orb.object_to_string(meetingFactory); }// End JiniMeetingFactoryImpl constructor public JiniMeeting createMeeting(String purpose, String participants) throws RemoteException { return new JiniMeetingImpl( corbaMeetingFactory.createMeeting( purpose, participants); }// End createMeeting public MeetingFactory getMeetingFactory() throws RemoteException{ return MeetingFactoryHelper.narrow( orb.string_to_object(corbaMeetingFactoryString)); }// End getMeetingFactory }// End JiniMeetingFactoryImpl /******* * JiniRoomImpl.java *******/ package JiniRoomBooking; import org.omg.CORBA.*; import org.omg.CosNaming.*; import RoomBooking.*; //import corba.common.*; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; //import java.util.Vector; public class JiniRoomImpl implements JiniRoom{ private String name; private JiniMeeting jMeeting; private JiniMeeting[] jMeetings; private JiniMeetingFactory jMeetingFactory; private Room corbaRoom; private String corbaRoomString; private Room[] corbaRoomArray = new Vector[5]; private Meeting[] corbaMeetings = new Vector[5]; public JiniRoomImpl()throws RemoteException { }// End JiniRoom constructor public JiniRoomImpl(Room CORBARoom, ORB orb) throws RemoteException { corbaRoom = CORBARoom; corbaRoomString = orb.object_to_string(CORBARoom); }// End JiniRoomImpl constructor public Room getRoom() throws RemoteException{ return corbaRoom; }// End getRoom public String getName() throws RemoteException{ return corbaRoom.getName(); }// End getName public void book(int selectedSlot, JiniMeeting selectedMeeting) throws RemoteException, SlotAlreadyTaken{ RoomHelper.narrow(orb.string_to_object( corbaRoomString)).book(selectedSlot, MeetingHelper.narrow(orb.string_to_Object( selectedMeeting.getMeetingString()))); }// End book public void cancel(int selectedSlot) throws RemoteException, NoMeetingInThisSlot{ corbaRoom.cancel(selectedSlot); }// End cancel public JiniMeeting[] view()throws RemoteException{ corbaMeetings = corbaRoom.view(); JiniMeeting JMeetings = new JiniMeeting[corbaMeetings.length()]; for(int i = 0; i < corbaMeetings.length(); i ++){ JMeetings[i] = JiniMeetingImpl.getRelativeJiniMeeting( orb.object_to_string(corbaMeetings[i])); } return JMeetings; }// End view }// End JiniRoomImpl 3.3.2.2Serverside Implementation for Separate Servers The following part is an example for the implementation, Naming Service is used here, but it doesn't mean it's the only one that should be chosen for implementation. Other ways could be used, just depends on the conditions applied. The implementation that be given here is still not real implementation. Here the getCORBARoomRef(String argv)is been defined as abstract, therefore the real implementation will need to do work on it. But before the implementation class, I give the following method as one way to implement that abstract getCORBARoomRef(String argv) private Room getCORBARoomRef(String argv){ ORB orb = null; // Act like a CORBA client try { orb = ORB.init(argv, null); // find the CORBA name server org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(objRef); // find the CORBA Room proxy NameComponent nc = new NameComponent("Room", ""); NameComponent path[] = {nc}; org.omg.CORBA.Object obj = ncRef.resolve(path); Room corbaRoomRef = RoomHelper.narrow(obj); return corbaRoomRef; } catch(Exception e) { e.printStackTrace(); return null; } }// End getCORBARoomRef package thinProxies; //JiniRoomServer Separate Server in Many Thin //proxies import JiniRoomBooking.*; import corba.RoomBooking.*; import net.jini.lookup.JoinManager; import net.jini.core.lookup.ServiceID; import net.jini.lookup.ServiceIDListener; import net.jini.lease.LeaseRenewalManager; import net.jini.discovery.LookupDiscovery; import net.jini.discovery.LookupDiscoveryManager; /** * JiniRoomServerThinProxies.java */ public class JiniRoomServerThinProxies implements ServiceIDListener { protected static Room corbaRoomRef; protected static JiniRoom jRoom; private String argv; public static void main(String argv[]) { new JiniRoomServerThinProxies (argv); // keep server running forever to // - allow time for locator discovery and // - keep re-registering the lease Object keepAlive = new Object(); synchronized(keepAlive) { try { keepAlive.wait(); } catch(java.lang.InterruptedException e) { // do nothing } }// End JiniRoomServerThinPRoxies private abstract Room getCORBARoomRef(String argv){ }// End getCORBARoomRef public JiniRoomServerThinProxies (String[] argv) { if(corbaRoomRef == null){ corbaRoomRef = getCORBARoomRef(argv); } if(jRoom == null){ jRoom = new JiniRoomImpl(corbaRoomRef); } JoinManager joinMgr = null; try { LookupDiscoveryManager mgr = new LookupDiscoveryManager( LookupDiscovery.ALL_GROUPS, null /* unicast locators */, null /* DiscoveryListener */); joinMgr = new JoinManager(jRoom, null, this, mgr, new LeaseRenewalManager()); } catch(Exception e) { e.printStackTrace(); System.exit(1); } }// End JiniRoomServerThinProxies public void serviceIDNotify(ServiceID serviceID) { System.out.println("got service ID " + serviceID.toString()); }// End serviceIDNotify } // JiniRoomServerThinProxies *********JiniMeetingFactoryServerThinProxies********** package thinProxies; import JiniRoomBooking.*; import corba.RoomBooking; import net.jini.lookup.JoinManager; import net.jini.core.lookup.ServiceID; import net.jini.lookup.ServiceIDListener; import net.jini.lease.LeaseRenewalManager; import net.jini.discovery.LookupDiscovery; import net.jini.discovery.LookupDiscoveryManager; /** * JiniMeetingFactoryServerThinProxies.java */ public class JiniMeetingFactoryServerThinProxies implements ServiceIDListener { protected static MeetingFactory corbaMeetingFactory; protected JiniMeetingFactory jMeetingFactory; private String argv; public static void main(String argv[]) { new JiniMeetingFactoryServerThinProxies (argv); // keep server running forever to // - allow time for locator discovery and // - keep re-registering the lease Object keepAlive = new Object(); synchronized(keepAlive) { try { keepAlive.wait(); } catch(java.lang.InterruptedException e) { // do nothing } }// End main private MeetingFactory getCORBAMeetingFactoryRef( String argv){ ORB orb = null; // Act like a CORBA client try { orb = ORB.init(argv, null); // find the CORBA name server org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(objRef); // find the CORBA MeetingFactory proxy NameComponent nc = new NameComponent("MeetingFactory", ""); NameComponent path[] = {nc}; org.omg.CORBA.Object obj = ncRef.resolve(path); MeetingFactory corbaMeetingFactoryRef = MeetingFactoryHelper.narrow(obj); return corbaMeetingFactoryRef; } catch(Exception e) { e.printStackTrace(); return null; } }// End getCORBAMeetingFactoryRef public JiniMeetingFactoryServerThinProxies (String[] argv) { if(corbaMeetingFactoryRef == null){ corbaMeetingFactoryRef = getCORBAMeetingFactoryRef(argv); } if(jMeetingFactory == null){ jMeetingFactory = new JiniMeetingFactoryImpl(corbaRoomRef); } JoinManager joinMgr = null; try { LookupDiscoveryManager mgr = new LookupDiscoveryManager( LookupDiscovery.ALL_GROUPS, null /* unicast locators */, null /* DiscoveryListener */); joinMgr = new JoinManager(jMeetingFactory, null, this, mgr, new LeaseRenewalManager()); } catch(Exception e) { e.printStackTrace(); System.exit(1); } }// End JiniMeetingFactoryServerThinProxies public void serviceIDNotify(ServiceID serviceID) { System.out.println("got service ID " + serviceID.toString()); }// End serviceIDNotify } // JiniMeetingFactoryServerThinProxies *********JiniMeetingServerThinProxies********** package thinProxies; import JiniRoomBooking.*; import corba.RoomBooking; import net.jini.lookup.JoinManager; import net.jini.core.lookup.ServiceID; import net.jini.lookup.ServiceIDListener; import net.jini.lease.LeaseRenewalManager; import net.jini.discovery.LookupDiscovery; import net.jini.discovery.LookupDiscoveryManager; /** * JiniMeetingServerThinProxies.java */ public class JiniMeetingServerThinProxies implements ServiceIDListener { protected Meeting corbaMeeting; protected JiniMeeting jMeeting; private String argv; public static void main(String argv[]) { new JiniMeetingServerThinProxies (argv); // keep server running forever to // - allow time for locator discovery and // - keep re-registering the lease Object keepAlive = new Object(); synchronized(keepAlive) { try { keepAlive.wait(); } catch(java.lang.InterruptedException e) { // do nothing } }// End main private Meeting getCORBAMeetingRef(String argv){ ORB orb = null; // Act like a CORBA client try { orb = ORB.init(argv, null); // find the CORBA name server org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(objRef); // find the CORBA Meeting proxy NameComponent nc = new NameComponent("Meeting", ""); NameComponent path[] = {nc}; org.omg.CORBA.Object obj = ncRef.resolve(path); Meeting corbaMeetingRef = MeetingHelper.narrow(obj); return corbaMeetingRef; } catch(Exception e) { e.printStackTrace(); return null; } }// End getCORBAMeetingRef public JiniMeetingServerThinProxies (String[] argv) { if(corbaMeetingRef == null){ corbaMeetingRef = getCORBAMeetingRef(argv); } if(jMeeting == null){ jMeeting = new JiniMeetingImpl(corbaMeetingRef); } JoinManager joinMgr = null; try { LookupDiscoveryManager mgr = new LookupDiscoveryManager( LookupDiscovery.ALL_GROUPS, null /* unicast locators */, null /* DiscoveryListener */); joinMgr = new JoinManager(jMeeting, null, this, mgr, new LeaseRenewalManager()); } catch(Exception e) { e.printStackTrace(); System.exit(1); } }// End JiniMeetingServerThinProxies public void serviceIDNotify(ServiceID serviceID) { System.out.println("got service ID " + serviceID.toString()); }// End serviceIDNotify } // JiniMeetingServerThinProxies 3.3.3 Common Client Here we tried to build the "common client" for those different cases from separate servers case to single server case. The code here has not fully passed compiling yet. But the idea and major part should correct. package JiniRoomBookingCommonClient; import java.util.*; import java.awt.*; import java.awt.event.*; import corba.RoomBooking.*; import thinProxies.*; import java.rmi.RemoteException; import java.rmi.RMISecurityManager; import net.jini.discovery.LookupDiscovery; import net.jini.discovery.DiscoveryListener; import net.jini.discovery.DiscoveryEvent; import net.jini.core.lookup.ServiceRegistrar; import net.jini.core.lookup.ServiceTemplate; public class RoomBookingClient implements ActionListener, DiscoveryListener { // following private definition will be changed when we move to // single server case. private JiniRoomImpl jRImpl; private JiniMeetingImpl jMImpl; private JiniMeetingFactoryImpl jFImpl; public Button viewButton; public Button bookButton; public Button cancelButton; public Button[][] slotButton; private TextField participants_tf; private TextField purpose_tf; private Panel mainPanel; private Panel titlePanel; private boolean[][] booked; private int selected_meeting; private int selected_slot; // private ORB orb; private NamingContext room_context; // private EasyNaming easy_naming; // private MeetingFactory meeting_factory; private JiniRoom[] rooms; private JiniMeeting[] meetings; private String ior; Color green = new Color( 0, 94, 86 ); Color red = new Color( 255, 61, 61 ); // constructor for applets RoomBookingClient( java.applet.Applet applet ) { } // constructor for applications RoomBookingClient(String[] args) { System.setSecurityManager(new RMISecurityManager()); LookupDiscovery discover = null; try { discover = new LookupDiscovery(LookupDiscovery.ALL_GROUPS); } catch(Exception e) { System.err.println(e.toString()); System.exit(1); } discover.addDiscoveryListener(this); } public void discovered(DiscoveryEvent evt) { ServiceRegistrar[] registrars = evt.getRegistrars(); for (int n = 0; n < registrars.length; n++) { System.out.println("Service found"); ServiceRegistrar registrar = registrars[n]; new LookupThread(registrar).start(); } // System.exit(0); } public void discarded(DiscoveryEvent evt) { // empty } public int no_of_rooms() { return rooms.length; } public void init_GUI( java.awt.Container gui ) { // initialise widgets gui.setBackground( Color.white ); viewButton = new Button("Back"); viewButton.setFont(new Font("Helvetica", Font.BOLD, 14)); viewButton.setBackground( red ); viewButton.setActionCommand("View"); viewButton.addActionListener( (ActionListener) this ); bookButton = new Button("Book"); bookButton.setFont(new Font("Helvetica", Font.BOLD, 14)); bookButton.setBackground( red ); bookButton.setActionCommand("Book"); bookButton.addActionListener( (ActionListener) this ); cancelButton = new Button("Cancel"); cancelButton.setFont(new Font("Helvetica", Font.BOLD, 14)); cancelButton.setBackground( red ); cancelButton.setActionCommand("Cancel"); cancelButton.addActionListener( (ActionListener) this ); mainPanel = new Panel(); titlePanel = new Panel(); titlePanel.setLayout( new GridLayout(3,1)); titlePanel.setFont(new Font("Helvetica", Font.BOLD, 20)); titlePanel.setBackground( red ); titlePanel.add( new Label("", Label.CENTER) ); titlePanel.add( new Label("Room Booking System", Label.CENTER) ); titlePanel.add( new Label("", Label.CENTER) ); gui.setLayout(new BorderLayout()); gui.add( "North", titlePanel ); gui.add( "Center", mainPanel ); // gui.setSize( 500, 300 ); gui.validate(); } public boolean view() { System.out.println("client view1"); try { //create lables and slots according to the number of // rooms try { rooms = jRImpl.getRooms(); } catch(RemoteException e) { e.printStackTrace(); rooms = new JiniRoom[0]; } System.out.println("client got rooms, length " + rooms.length); Label[] r_label = new Label[rooms.length]; slotButton = new Button[rooms.length][MaxSlots.value]; booked = new boolean[rooms.length][MaxSlots.value]; mainPanel.removeAll(); // define layout for the table GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); mainPanel.setLayout(gridbag); c.fill = GridBagConstraints.BOTH; c.gridwidth = 2; c.gridheight = 1; Label room_label = new Label("Rooms", Label.CENTER ); room_label.setFont(new Font("Helvetica", Font.BOLD, 14)); gridbag.setConstraints( room_label, c); mainPanel.add( room_label ); c.gridwidth = 4; c.gridheight = 1; Label am_label = new Label("AM", Label.CENTER ); am_label.setFont(new Font("Helvetica", Font.BOLD, 14)); gridbag.setConstraints( am_label, c); mainPanel.add( am_label ); c.gridheight = 1; c.gridwidth = GridBagConstraints.REMAINDER; Label pm_label = new Label("PM", Label.CENTER ); pm_label.setFont(new Font("Helvetica", Font.BOLD, 14)); gridbag.setConstraints( pm_label, c); mainPanel.add( pm_label ); c.gridwidth = 2; c.gridheight = 1; Label e_label = new Label(""); gridbag.setConstraints( e_label, c); mainPanel.add( e_label ); c.gridwidth = 1; c.gridheight = 1; Label label9 = new Label(" 9", Label.CENTER ); label9.setFont(new Font("Helvetica", Font.BOLD, 14)); gridbag.setConstraints( label9, c); mainPanel.add( label9 ); c.gridwidth = 1; c.gridheight = 1; Label label10 = new Label("10", Label.CENTER ); label10.setFont(new Font("Helvetica", Font.BOLD, 14)); gridbag.setConstraints( label10, c); mainPanel.add( label10 ); c.gridwidth = 1; c.gridheight = 1; Label label11 = new Label("11", Label.CENTER ); label11.setFont(new Font("Helvetica", Font.BOLD, 14)); gridbag.setConstraints( label11, c); mainPanel.add( label11 ); c.gridwidth = 1; c.gridheight = 1; Label label12 = new Label("12", Label.CENTER ); label12.setFont(new Font("Helvetica", Font.BOLD, 14)); gridbag.setConstraints( label12, c); mainPanel.add( label12 ); c.gridwidth = 1; c.gridheight = 1; Label label1 = new Label(" 1", Label.CENTER ); label1.setFont(new Font("Helvetica", Font.BOLD, 14)); gridbag.setConstraints( label1, c); mainPanel.add( label1 ); c.gridwidth = 1; c.gridheight = 1; Label label2 = new Label(" 2", Label.CENTER ); label2.setFont(new Font("Helvetica", Font.BOLD, 14)); gridbag.setConstraints( label2, c); mainPanel.add( label2 ); c.gridwidth = 1; c.gridheight = 1; Label label3 = new Label(" 3", Label.CENTER ); label3.setFont(new Font("Helvetica", Font.BOLD, 14)); gridbag.setConstraints( label3, c); mainPanel.add( label3 ); c.gridwidth = GridBagConstraints.REMAINDER; c.gridheight = 1; Label label4 = new Label(" 4", Label.CENTER ); label4.setFont(new Font("Helvetica", Font.BOLD, 14)); gridbag.setConstraints( label4, c); mainPanel.add( label4 ); // show the lable with the room name for( int i = 0; i < rooms.length; i++ ) { c.gridwidth = 2; c.gridheight = 1; r_label[i] = new Label( rooms[i].getName() ); r_label[i].setFont(new Font("Helvetica", Font.BOLD, 14)); gridbag.setConstraints( r_label[i], c); mainPanel.add( r_label[i] ); // call view operation on the i-th room object and // create book or free button // meetings = rooms[i].view(); System.out.println("getting meetings for room " + i); try { meetings = jMimpl.getJiniMeeting(i); } catch(RemoteException e) { e.printStackTrace(); meetings = new JiniMeeting[0]; } System.out.println("got meetings, length " + meetings.length); c.gridheight = 1; for( int j = 0; j < meetings.length; j++ ) { if( j == meetings.length - 1 ) c.gridwidth = GridBagConstraints.REMAINDER; else c.gridwidth = 1; if( meetings[j] == null ) { // slot is free slotButton[i][j] = new Button("Book"); slotButton[i][j].setBackground( green ); slotButton[i][j].setForeground(Color.white); slotButton[i][j].setFont( new Font("Helvetica", Font.BOLD, 14)); slotButton[i][j].setActionCommand("Slot"+i+j); slotButton[i][j].addActionListener( (ActionListener) this ); booked[i][j] = false; } else { // slot is booked - view or cancel slotButton[i][j] = new Button("View"); slotButton[i][j].setBackground( red ); slotButton[i][j].setFont( new Font("Helvetica", Font.BOLD, 14)); slotButton[i][j].setActionCommand("Slot"+i+j); slotButton[i][j].addActionListener( (ActionListener) this ); booked[i][j] = true; } gridbag.setConstraints( slotButton[i][j], c); mainPanel.add( slotButton[i][j] ); } } c.gridwidth = 4; c.gridheight = 1; Label e1_label = new Label(""); gridbag.setConstraints( e1_label, c); mainPanel.add( e1_label ); c.gridheight = 1; c.gridwidth = GridBagConstraints.REMAINDER; Label e2_label = new Label(""); gridbag.setConstraints( e2_label, c); mainPanel.add( e2_label ); c.gridheight = 1; c.gridwidth = GridBagConstraints.REMAINDER; Label e3_label = new Label(""); gridbag.setConstraints( e3_label, c); mainPanel.add( e3_label ); mainPanel.validate(); } catch(SystemException system_exception) { System.err.println("View: " + system_exception); } return true; } public boolean cancel() { try { jRImpl.cancel(selected_slot); } catch(NoMeetingInThisSlot no_meeting ) { System.err.println("Cancel :" + no_meeting); } catch(RemoteException remote) { System.err.println("Cancel :" + remote); } // show bookings of all rooms return view(); } public boolean process_slot(int _selected_meeting, int _selected_slot) { selected_meeting = _selected_meeting; selected_slot = _selected_slot; if( booked[selected_meeting][selected_slot] ) { // view the meeting details, potentially cancel meeting_details(); } else { // get meeting details and book booking_form(); } return true; } public boolean meeting_details() { // clean main panel mainPanel.removeAll(); // call view operation on the selected room try { meetings = jRImpl.getMeetings(selected_meeting); } catch(SystemException system_exception ) { System.err.println("meeting_details: " + system_exception ); meetings = new JavaMeeting[0]; } catch(RemoteException e) { e.printStackTrace(); meetings = new JavaMeeting[0]; } // create new form for displaying meeting details GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); mainPanel.setLayout(gridbag); c.gridwidth = GridBagConstraints.REMAINDER; Label header_label = new Label("Meeting details"); gridbag.setConstraints( header_label, c); mainPanel.add( header_label ); c.gridwidth = 1; c.gridheight = 1; c.fill = GridBagConstraints.BOTH; Label purpose_label = new Label("Purpose: "); gridbag.setConstraints( purpose_label, c); mainPanel.add( purpose_label ); c.gridheight = 1; c.gridwidth = 2; c.gridwidth = GridBagConstraints.REMAINDER; purpose_tf = new TextField(); purpose_tf.setEditable(false); try { purpose_tf.setText( meetings[selected_slot].getPurpose() ); } catch(SystemException system_exception) { System.err.println(system_exception); } gridbag.setConstraints( purpose_tf, c); mainPanel.add( purpose_tf ); c.gridwidth = 1; c.gridheight = 1; c.fill = GridBagConstraints.BOTH; Label participants_label = new Label("Participants: "); gridbag.setConstraints( participants_label, c); mainPanel.add( participants_label ); c.gridheight = 1; c.gridwidth = 2; c.gridwidth = GridBagConstraints.REMAINDER; participants_tf = new TextField(); participants_tf = new TextField(); participants_tf.setEditable(false); try { participants_tf.setText( meetings[selected_slot].getParticipants() ); } catch(SystemException system_exception) { System.err.println(system_exception); } gridbag.setConstraints( participants_tf, c); mainPanel.add( participants_tf ); c.gridheight = 1; c.gridwidth = 3; c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints( viewButton, c); mainPanel.add( viewButton ); gridbag.setConstraints( cancelButton, c); mainPanel.add( cancelButton ); mainPanel.validate(); // mainPanel.repaint(); return true; } public void booking_form() { // clean main panel mainPanel.removeAll(); GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); mainPanel.setLayout(gridbag); c.gridwidth = GridBagConstraints.REMAINDER; Label header_label = new Label( "Please, enter details of the meeting."); gridbag.setConstraints( header_label, c); mainPanel.add( header_label ); c.gridwidth = 1; c.gridheight = 1; c.fill = GridBagConstraints.BOTH; Label purpose_label = new Label("Purpose: "); gridbag.setConstraints( purpose_label, c); mainPanel.add( purpose_label ); c.gridheight = 1; c.gridwidth = 2; c.gridwidth = GridBagConstraints.REMAINDER; purpose_tf = new TextField(); gridbag.setConstraints( purpose_tf, c); mainPanel.add( purpose_tf ); c.gridwidth = 1; c.gridheight = 1; c.fill = GridBagConstraints.BOTH; Label participants_label = new Label("Participants: "); gridbag.setConstraints( participants_label, c); mainPanel.add( participants_label ); c.gridheight = 1; c.gridwidth = 2; c.gridwidth = GridBagConstraints.REMAINDER; participants_tf = new TextField(); gridbag.setConstraints( participants_tf, c); mainPanel.add( participants_tf ); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints( bookButton, c); mainPanel.add( bookButton ); mainPanel.validate(); // mainPanel.repaint(); } public boolean book() { // modified JN try { jRImpl.book(selected_slot, selected_meeting); } catch(RemoteException e) { e.printStackTrace(); } catch(SlotAlreadyTaken already_taken ) { System.err.println( "book :" + already_taken ); } // show bookings of all rooms return view(); } // catch and process events public void actionPerformed( ActionEvent ev ) { if(ev.getActionCommand().equals("View")) view(); if(ev.getActionCommand().equals("Book")) book(); if(ev.getActionCommand().equals("Cancel")) cancel(); // look for free/book button pressed for( int i = 0; i < no_of_rooms(); i++ ) { for( int j = 0; j < MaxSlots.value; j++ ) { if( ev.getActionCommand().equals("Slot"+i+j) ) { process_slot( i, j ); } } } } class LookupThread extends Thread { ServiceRegistrar registrar; LookupThread(ServiceRegistrar registrar) { this.registrar = registrar; } public void run() { Class[] classes = new Class[] { JiniRoomServerThingProxies.class}; ServiceTemplate template = new ServiceTemplate(null, classes, null); try { jRImpl = (JiniRoom)registrar.lookup(template); } catch(java.rmi.RemoteException e) { e.printStackTrace(); System.exit(2); } if (jRImpl == null) { System.out.println("bridge null"); return; } view(); } } } The following are some ideas for further implementation; they might or might not be used later on. package ClientForSeparateServerThinProxies; import corba.RoomBooking; import JiniRoomBooking.*; import java.rmi.RMISecurityManager; import net.jini.discovery.LookupDiscovery; import net.jini.discovery.DiscoveryListener; import net.jini.discovery.DiscoveryEvent; import net.jini.core.lookup.ServiceRegistrar; import net.jini.core.lookup.ServiceTemplate; /** * TestSeparateServerThinProxiesRoom.java */ public class TestSeparateServerThinProxiesRoom implements DiscoveryListener { public static void main(String argv[]) { new TestSeparateServerThinProxiesRoom (); // stay around long enough to receive replies try { Thread.currentThread().sleep(10000L); } catch(java.lang.InterruptedException e) { // do nothing } }// End main public TestSeparateServerThinProxiesRoom () { System.setSecurityManager(new RMISecurityManager()); LookupDiscovery discover = null; try { discover = new LookupDiscovery( LookupDiscovery.ALL_GROUPS); } catch(Exception e) { System.err.println(e.toString()); System.exit(1); } discover.addDiscoveryListener(this); }// End TestSeparateServerThinProxiesRoom public void discovered(DiscoveryEvent evt) { ServiceRegistrar[] registrars = evt.getRegistrars(); for (int n = 0; n < registrars.length; n++) { System.out.println("Service found"); ServiceRegistrar registrar = registrars[n]; new LookupThread(registrar).start(); } // System.exit(0); }// End discovered public void discarded(DiscoveryEvent evt) { // empty }// End discarded class LookupThread extends Thread { ServiceRegistrar registrar; LookupThread(ServiceRegistrar registrar) { this.registrar = registrar; } public void run() { Class[] classes = new Class[]{JiniRoom.class}; JiniRoom room = null; ServiceMatchies sevMatch; ServiceTemplate template = new ServiceTemplate(null, classes, null); try { sevMatch = registrar.lookup(template, maxMatch); } catch(java.rmi.RemoteException e) { e.printStackTrace(); System.exit(2); } if (sevMatch.length() == 0) { System.out.println("room is null"); return; } String msg; try { msg = sevMatch[0].getName(); System.out.println(msg); } catch(Exception e) { System.err.println(e.toString()); } }// End run }// End LookupThread } // TestSeparateServerThinProxiesRoom 3.3.4Implementation for Single Server In this case, we should not register the Meeting server according to the language independence. Because the IDL we used here is an English example, so we understand that the word "factory" which is used in MeetingFactory means create Meeting, but to those people who do not understand English, register a Meeting server can be quite confusing. 3.3.4.1Jini Service for Single Server /****** * JiniMeetingImpl.java // single server for many thin proxies ******/ // Jini Service for single server in many // thin proxies package JiniRoomBookingSingleServerThinProxies; import org.omg.CORBA.*; import org.omg.CosNaming.*; import JiniRoomBooking.*; import corba.RoomBooking.*; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class JiniMeetingImpl implements JiniMeeting{ private Meeting corbaMeeting; private String corbaMeetingString; private String purpose; private String participants; private static HashMap map = new HashMap(); public JiniMeeting(){ } public JiniMeetingImpl(Meeting CORBAMeeting){ corbaMeeting = CORBAMeeting; map.add(corbaMeeting); } public getPurpose() throws RemoteException { return corbaMeeting.getPurpose(); }// End getPurpose public getParticipants()throws RemoteException { return corbaMeeting.getParticipants(); }// End getParticipants public Meeting getMeeting() throws RemoteException{ return corbaMeeting; }// End getMeeting }// End JiniMeetingImpl /******* * JiniMeetingFactoryImpl.java *******/ package JiniRoomBookingSingleServerThinProxies; import org.omg.CORBA.*; import org.omg.CosNaming.*; import corba.RoomBooking.*; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class JiniMeetingFactoryImpl extends UnicastRemote implements JiniMeetingFactory{ private MeetingFactory corbaMeetingFactory; private String corbaMeetingFactoryString; public JiniMeetingFactoryImpl()throws RemoteException { }// End JiniMeetingFactory constructor public JiniMeetingFactoryImpl(MeetingFactory meetingFactory) throws RemoteException { corbaMeetingFactory = meetingFactory; } public JiniMeeting createMeeting(String purpose, String participants) throws RemoteException { return new JiniMeetingImpl( corbaMeetingFactory.createMeeting( purpose, participants)); }// End createMeeting public MeetingFactory getMeetingFactory() throws RemoteException{ return cobaMeetingFactory; }// End getMeetingFactory }// End JiniMeetingFactoryImpl /******* * JiniRoomImpl.java *******/ package JiniRoomBookingSingleServerThinProxies; import org.omg.CORBA.*; import org.omg.CosNaming.*; import corba.RoomBooking.*; import JiniRoomBooking.*; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class JiniRoomImpl implements JiniRoom{ private String name; private JiniMeeting jMeeting; private JiniMeeting[] jMeetings; private JiniMeetingFactory jMeetingFactory; private Room corbaRoom; private String corbaRoomString; private Meeting[] corbaMeetings; public JiniRoomImpl()throws RemoteException { }// End JiniRoom constructor public JiniRoomImpl(Room CORBARoom) throws RemoteException { corbaRoom = CORBARoom; }// End JiniRoomImpl constructor public Room getRoom() throws RemoteException{ return corbaRoom; }// End getRoom public String getName() throws RemoteException{ return corbaRoom.getName(); }// End getName public void book(int selectedSlot, JiniMeeting selectedMeeting) throws RemoteException, SlotAlreadyTaken{ corbaRoom.book(selectedSlot, selectedMeeting); }// End book public void cancel(int selectedSlot) throws RemoteException, NoMeetingInThisSlot{ corbaRoom.cancel(selectedSlot); }// End cancel public JiniMeeting[] view()throws RemoteException{ corbaMeetings = corbaRoom.view(); }// End view }// End JiniRoomImpl 3.3.4.2Serverside Implementation for Single Server The major difference between single server and separate servers is that in single server all Jini room servers join manager after all CORBA room references are abtained; while in separate servers, each Jini room server will join the manager after it get its CORBA room reference. But in this case, the number of available room has to be assumed by us. In the following The following are implementation for single server in many thin proxies. package thinProxiesSingleServer; import net.jini.lookup.JoinManager; import net.jini.core.lookup.ServiceID; import net.jini.lookup.ServiceIDListener; import net.jini.lease.LeaseRenewalManager; import net.jini.discovery.LookupDiscovery; import net.jini.discovery.LookupDiscoveryManager; import corba.RoomBooking.*; import JiniRoomBooking.*; import org.omg.corba.*; /** * JiniRoomSingleServerThinProxies.java */ public class JiniRoomSingleServerThinProxies implements ServiceIDListener { protected static Room[] corbaRoomRef = new Vector(); protected static JiniRoom[] jRoom = new Vector(); protected static MeetingFactory corbaMeetingFactory; protected static ORB orb == null; private String argv; public static void main(String argv[]) { new JiniRoomSingleServerThinProxies (argv); // keep server running forever to // - allow time for locator discovery and // - keep re-registering the lease Object keepAlive = new Object(); synchronized(keepAlive) { try { keepAlive.wait(); } catch(java.lang.InterruptedException e) { // do nothing } }// End main private Room[] getCORBARoomRef(String argv) throws RemoteException, UserException { try { // list rooms // initialise 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 have 5 rooms via the room list // more rooms are available from the binding // iterator room_context.list( 5, 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 fiendly with system resources if( biHolder.value != null ) biHolder.value.destroy(); return rooms; } catch(SystemException system_exception) { throw new RemoteException("View", system_exception); // System.err.println("View: " + system_exception); return null; } }// End getCORBARoomRef private MeetingFactory getCORBAMeetingFactoryRef( String argv){ // Act like a CORBA client try { if(orb == null){ orb = ORB.init(argv, null); // find the CORBA name server org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(objRef); } // find the CORBA MeetingFactory proxy NameComponent nc = new NameComponent("MeetingFactory", ""); NameComponent path[] = {nc}; org.omg.CORBA.Object obj = ncRef.resolve(path); MeetingFactory corbaMeetingFactoryRef = MeetingFactoryHelper.narrow(obj); return corbaMeetingFactoryRef; } catch(Exception e) { e.printStackTrace(); return null; } }// End getCORBAMeetingFactoryRef public JiniRoomSingleServerThinProxies (String[] argv) { if(corbaRoomRef.length() == 0){ corbaRoomRef = getCORBARoomRef(argv); } if(jRoom.length() == 0){ for(int i = 0; i < corbaRoomRef.length(); i++) { jRoom[i] = new JiniRoomImpl(corbaRoomRef[i]); } } if(corbaMeetingFactory == null){ corbaMeetingFactory = getCORBAMeetingFactory(argv); } if(jMeetingFactory == null){ jMeetingFactory = new JiniMeetingFactoryImpl(corbaMeetingFactory); } JoinManager joinMgr = null; try { LookupDiscoveryManager mgr = new LookupDiscoveryManager( LookupDiscovery.ALL_GROUPS, null /* unicast locators */, null /* DiscoveryListener */); for(int i = 0; i < jRoom.length(); i ++) { joinMgr = new JoinManager( jRoom, null, this, mgr, new LeaseRenewalManager()); } joinMgr = new JoinManager(jMeetingFactory; null, this, mgr, new LeaseRenewalManager()); } catch(Exception e) { e.printStackTrace(); System.exit(1); } }// End JiniRoomSingleServerThinProxies public void serviceIDNotify(ServiceID serviceID) { System.out.println("got service ID " + serviceID.toString()); }// End serviceIDNotify } // JiniRoomSingleServerThinProxies The following are some ideas that might be (might not be) helpful for further implementation later on. package ClientForSingleServerThinProxies; import JiniRoomBooking; import java.rmi.RMISecurityManager; import net.jini.discovery.LookupDiscovery; import net.jini.discovery.DiscoveryListener; import net.jini.discovery.DiscoveryEvent; import net.jini.core.lookup.ServiceRegistrar; import net.jini.core.lookup.ServiceTemplate; /** * TestSingleServerThinProxiesRoom.java */ public class TestSingleServerThinProxiesRoom implements DiscoveryListener { public static void main(String argv[]) { new TestSingleServerThinProxiesRoom (); // stay around long enough to receive replies try { Thread.currentThread().sleep(10000L); } catch(java.lang.InterruptedException e) { // do nothing } } public TestSingleServerThinProxiesRoom () { System.setSecurityManager(new RMISecurityManager()); LookupDiscovery discover = null; try { discover = new LookupDiscovery(LookupDiscovery.ALL_GROUPS); } catch(Exception e) { System.err.println(e.toString()); System.exit(1); } discover.addDiscoveryListener(this); } public void discovered(DiscoveryEvent evt) { ServiceRegistrar[] registrars = evt.getRegistrars(); for (int n = 0; n < registrars.length; n++) { System.out.println("Service found"); ServiceRegistrar registrar = registrars[n]; new LookupThread(registrar).start(); } // System.exit(0); } public void discarded(DiscoveryEvent evt) { // empty } class LookupThread extends Thread { ServiceRegistrar registrar; LookupThread(ServiceRegistrar registrar) { this.registrar = registrar; } public void run() { Class[] classes = new Class[] {JiniRoom.class}; JiniRoom room = null; ServiceTemplate template = new ServiceTemplate(null, classes, null); try { room = (JiniRoom) registrar.lookup(template); } catch(java.rmi.RemoteException e) { e.printStackTrace(); System.exit(2); } if (room == null) { System.out.println("room is null"); return; } String msg; try { msg = room.getName(); System.out.println(msg); } catch(Exception e) { // we may get a CORBA runtime error System.err.println(e.toString()); } } } } // TestSingleServerThinProxiesRoom 4Conclusion Since this is still an undergoing project, we cannot draw a real conclusion now. But in this paper, we achieved following stages: 1. By translating a RoomBooking CORBA IDL to a serial of proper definitions for Jini service, we proved that existing CORBA application could be available to Jini service. The way for achieving this is wrapping a CORBA reference with Jini. So far, what we achieved by this example is hiding CORBA stuff from the Jini client, all the Jini servers and Jini clients are acting as CORBA client, but this is only known by Jini servers, not Jini clients. 2. By discussing possible Jini service models based on this RoomBooking example, we believe that four models will also cover all different situations for running a distributed system in real world for other problem solving. 3. By discussing the two cases for many thin proxies, one of the four models, we realise that in further implementation, we should focus on when, where and how a CORBA reference should be and could be available to the Jini server. Like what we represented in this paper, in separate servers, because each server will run in different virtu machine, then we may need to add extra server to make relevant object references are available; while in single server, we do not need worry about it since they all run in same virtu machine, servers can share references.