Construct Java applications through distributed object technology

Realize a distributed object environment through Java, RMI, and HORB

Until recently, when software programs were created using object-oriented design, the designs operated mainly in the memory of single machines. Design methods other than object-oriented were necessary for adapting the software for network use and saving the software in secondary storage. Distributed object technology for networks was developed to solve this problem, and object-oriented database (ODBMS) technology, which saves the objects directly in secondary storage, was born.

These technologies are definitely not new -- development tools supporting ODBMS appeared on the market in the early 90s. However, the products either were high-priced, used an obscure language, or never gained general popularity among engineers. With the appearance of Java, distributed objects and ODBMS technology have been refined further, and prices have dropped, so they have gained acceptance by engineers. Based on recent software trends, the attention given to these technologies promises to increase even more.

It is clear that future software environments must include three important technologies:

  1. "object-orientation"
  2. "networks"
  3. "databases"

These environments can be realized through distributed object technology and ODBMS. Of these, this article focuses on Java-based distributed object technology.

What are distributed objects?

In simple terms, distributed object technology allows objects on different machines to communicate messages (Java method calls) to each other. To help you understand what distributed objects are, see Figure 1, the design of a network karaoke model. As you can see, when song selection is executed for the karaoke box in the server by remote operation, a music object is sent to the client. The client starts the music by sending the message "play."

To define some terms, an object equivalent to the karaoke box is called a "remote object," the music object that is sent to the client is called a "copy object," and the message sent from the client to the karaoke box object in the server is called a "remote message." We will use this model to try to implement a distributed object system.

An overview of RMI and HORB

This article focuses on two distributed object technologies: RMI (Remote Method Invocation), which is bundled as a standard feature of JDK 1.1; and HORB (Hirano Object Request Broker), which was developed by Satoshi Hirano of the National Institute of Electronics (Ministry of International Trade and Industry). (For more on HORB, see the Resources section.) CORBA, which is aiming to become an industry-standard distributed object system, will be introduced later in this article. The latest information on HORB is available from the following URL: http://ring.etl.go.jp/openlab/horb/.

Application of distributed objects (HORB versus RMI)

We now will try to use the two technologies, HORB and RMI, to construct a distributed object system. The fastest way to understand these technologies is by getting actual hands-on experience.

First, we will design classes based on the network karaoke model. Figure 2 shows a class diagram that illustrates the structure of the relationships among instances created based on the internal class structure and classes.

An introduction to HORB

This section provides an example of how to implement with HORB. Compared with RMI, HORB allows coding in a format that is similar to normal object-oriented programming. Listing 1 shows the class source of the HORB karaoke box (KaraokeBox.java). We will now proceed with building the system by expanding the source.

Listing 1: Karaoke box class [HORB]
class KaraokeBox{
      void hello(String s){
                System.out.println("Client Name " + s);
      }
}

Listing 2 is the client source that uses the karaoke box (Client.java). First, the hello() method of the KaraokeBox class is called. Up to this point, the program is not a distributed object. Calling the hello() method of the KaraokeBox is a local call.

Listing 2: Client source that uses karaoke box [HORB]
class Client{
   public static void main(String argv[]){ 
        String name = (argv.length == 1) ? argv[0] : "-";
        KaraokeBox  box = new KaraokeBox();
        box.hello(name);
 }
}

Now we will apply a little magic to transform KaraokeBox into a remote object. First, the client source is modified, as shown in Listing 3; this shows you how to use KaraokeBox in remote operations (Client.java). The sections that were changed from Listing 2 are identified with comments. In Listing 3, instance of KaraokeBox_Proxy, not KaraokeBox, is created. When is the all-important instance of KaraokeBox created? The answer is when the instance of KaraokeBox_Proxy is created.

Listing 3: Using KaraokeBox in remote operation (Client.java) [HORB]
import horb.orb.*;          // Add
class Client{
   public static void main(String argv[]){
       String name = (argv.length == 1) ? argv[0] : "-";
       KaraokeBox_Proxy box = new KaraokeBox_Proxy("horb://kinta"); // Change (change host name)
       box.hello(name);
  }
}

In the next code example, you see how to use KaraokeBox in an RMI operation (Client.java):

Listing 4: Using KaraokeBox in an RMI operation (Client.java) [RMI]
class Client{
   public static void main(String argv[]){
       String name = (argv.length == 1) ? argv[0] : "-";
       try{                                                                              // Change
         KaraokeBox box = (KaraokeBox)java.rmi.Naming.lookup("rmi://kinta/karaokebox1"); // Change
         box.hello(name);
       }                                                                                 // Change
       catch(Exception e){e.printStackTrace();}                                          // Change
  }
}

Figure 3 shows the mechanism for the karaoke box.

KaraokeBox_Proxy is called the "proxy object" of KaraokeBox. The actual instance for KaraokeBox is located in the server (host name "kinta" in this example). The client creates the instance for KaraokeBox_Proxy as the proxy object. Messages to KaraokeBox are sent to the KaraokeBox_Proxy instance. The message is relayed to the KaraokeBox instance through the KaraokeBox_Proxy and the mechanism called KaraokeBox_Skeleton, which is located in the server. The result is then returned to the client. So you can see that remote object operations are possible.

Here are the necessary source changes. One of the nice features of HORB is that the KaraokeBox source, which becomes the remote object, does not have to be changed at all.

Creating the execution environment

KaraokeBox_Proxy and KaraokeBox_Skeleton are created automatically by the HORB compiler. Client.java is compiled by the Java compiler, as usual.

  1. >horbc KaraokeBox.java

    • KaraokeBox.class
    • KaraokeBox_Proxy.class
    • KaraokeBox_Skeleton.class are created
  2. >javac Client.java

    • Client.class is created.
  3. Copy Client.class and KaraokeBox_Proxy.class to the client, and KaraokeBox.class and KaraokeBox_Skeleton.class to the server. (HORB must be installed in both the client and the server.)

Execution procedure

  1. Start the HORB daemon on the server.
  2. From the client, start Client with the character string "Junzo" as an argument.
  3. The results "Client Name Junzo" is displayed at the server.

The execution result is shown in Figure 4.

An introduction to RMI

This section introduces implementing with RMI. First, you change the client source as shown in Listing 4 above. The locations to be changed are almost the same as those changed for HORB. Comments identify the changes from Listing 2 above.

In Listing 4, the RMI method called lookup() is used instead of creating a KaraokeBox instance by calling new. So does lookup() then create the KaraokeBox instance? Actually, no. The reason for this is explained later.

When RMI is used, the KaraokeBox source also must be changed. First, you must create the Java interface. Listing 5 shows the source for the KaraokeBox interface (KaraokeBox.java). The object type that the client receives from lookup() is this interface.

Listing 5: Karaoke box interface (KaraokeBox.java) [RMI]
interface KaraokeBox extends java.rmi.Remote{
   public void hello(String s) throws java.rmi.RemoteException;
}

Listing 6 shows the class source of the implementation of the interface (KaraokeBoxImpl.java). Compared with the initial source (Listing 1 above), in which the objects are not distributed, these sources have more code.

Listing 6: Karaoke box implementation (KaraokeBoxImpl.java) [RMI]
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
public class KaraokeBoxImpl extends UnicastRemoteObject implements KaraokeBox{
    public KaraokeBoxImpl() throws RemoteException{
        super();
    }
    public void hello(String s) throws RemoteException{
        System.out.println("Client Name " + s);
    }
    public static void main(String argv[]){
        System.setSecurityManager(new RMISecurityManager());
         try{
           KaraokeBox box = new KaraokeBoxImpl();
            java.rmi.Naming.rebind("karaokebox1", box);
         }
         catch(Exception e){e.printStackTrace();}
     }
}

Here are the necessary source changes. In RMI, the remote objects are registered with assigned names (rebind.bind). Although, these names do not need to be specified in the source, RMI, like HORB, uses objects to enable remote object operation. These objects are called Stub (equivalent to "proxy" in HORB) and Skeleton.

Creating the execution environment

RMI has functions that are equivalent to those of the HORB compiler, and these functions automatically create Stub and Skeleton.

  1. >javac Client.java KaraokeBox.java KaraokeBoxImpl.java

    • Client.class
    • KaraokeBox.class
    • KaraokeBoxImpl.class are created
  2. >rmic KaraokeBoxImpl KaraokeBoxImpl_Stub.class KaraokeBoxImpl_Skel.class are created

  3. Copy Client.class, KaraokeBox.class, and KaraokeBoxImpl_Stub.class to the client and KaraokeBox.class, KaraokeBoxImpl.class, KaraokeBoxImpl_Stub.class, and KaraokeBoxImpl_Skel.class to the server. (RMI must be installed in both the client and the server.)

Execution procedure

  1. Start the RMI Registry on the server.
  2. Start the KaraokeBoxImpl remote object on the server.
  3. From the client, start Client with the character string "Junzo" as an argument.
  4. The results "Client Name Junzo" is displayed at the server.

The execution result is shown in Figure 5.

An introduction to the basic object model

This section explains the basic object models for HORB and RMI based on the source presented earlier. The basic object model refers to the "view shown to the remote object user" when a remote object is generated and used. HORB and RMI differ significantly in their basic object models.

Generation model [HORB, DCOM]

The generational model provides the same method as instance creation as object-oriented programming. Refer to the section added to Listing 3 above (HORB client source).

The following listing contains the source that generates KaraokeBox_Proxy:

Code 1: Proxy object creation
KaraokeBox_Proxy box = new KaraokeBox_Proxy("horb://YourHostName");

Recall that the KaraokeBox instance also is created as a consequence of this execution. In other words, if you use KaraokeBox_Proxy thinking that it is KaraokeBox, a remote object can be created via a method that does not vary from the normal instance generation process in object-oriented programming (see Figure 6).

Connection model [CORBA (Java IDL), RMII, HORB, PDO (NEXTSTEP)]

The connection model is used to connect to remote objects that were generated earlier by the server. As in the generation model, with the connection model the client does not simply create the KaraokeBox instance. Instead, the object that was created earlier by the server is used.

When the RMI execution procedure is compared with the HORB execution procedure, it is evident that the server starts KaraokeBoxImpl so that the client can start Client (see Figure 7).

The following listing contains the source code that allows the client to connect to the remote object:

Code 2: Connection to remote object
KaraokeBox box = (KaraokeBox)Naming.lookup("rmi://YourHostName/karaokebox1");

The reason for the additional code in the server source (see Listings 5 and 6 above) with RMI is that a main() method must be created so that the code for generating the remote object can be incorporated.

The connection model is a type that is provided by nearly all distributed object technologies. HORB supports both the generation and connection models.

One problem with the connection model is that the client can only connect to objects generated by the server. To resolve this problem, use a technique in which the server creates the remote object requested by the client before returning it to the client. Here is an example of this technique:

Code 3: Remote object creation by a client request
  public KaraokeBox getObject() throws RemoteException{
      KaraokeBox box = null;
      try{
         box = new KaraokeBoxImpl("karaokebox" + instanceNo );
      }
      catch(Exception e){e.printStackTrace();}
      return box;
}

Remote messages

The method for sending a remote message after a remote object becomes usable is almost the same for both RMI and HORB. Figure 8 shows hello() method calling and the copying of a String instance (as a parameter in the hello() method) to the server.

In this process, the distributed object system turns the String interface into simple stream data and uses the low-level Socket class to send the data to the server. The server returns the String class to its original form. These mechanisms are called "marshalling" and "unmarshalling."

1 2 3 Page 1
Page 1 of 3