Java IDL: Java Meets CORBA - Part 4

Gopalan Suresh Raj

 

Common Object Services —The Naming Service

The COS Naming Service is an OMG-specified extension to the core CORBA standard, where COS stands for Common Object Service. This Naming Service allows an object to be published using a symbolic name and it allows client applications to obtain references to the object using a standard API. The COS Naming Service can reside on any host accessible within the network and enables applications to publish, lookup, and list CORBA object references from any network host.

A namespace is the collection of all names bound to a Naming Service. A namespace may contain naming context bindings to contexts located in another server. In such a case, the namespace is said to be a federated namespace because it is a collection of namespaces from multiple servers. An interesting point is the location of each context is transparent to the client applications; they have no knowledge that multiple servers are handling the resolution requests for an object.

Java 2 ships with a compliant implementation of the COS Naming Service, called tnameserv. The Java IDL COS Naming Service implementation supports transient bindings only, which means objects must be reregistered each time the Naming Service is restarted. The COS Naming Service implementations for Iona and Inprise are much more sophisticated and scalable because they support persistent bindings, load balancing, and customization. The JDK tnameserv Naming Service is more than adequate to get developers started on a project. When rolling out your applications, you want to purchase a commercial implementation to gain persistent naming and load-balancing capabilities.

A COS Naming Service stores object references in a hierarchical name space; much like a file system uses a directory structure to store files. Specifically, bindings maintain the association between a symbolic name and an object reference, while naming contexts are objects that organize the bindings into a naming hierarchy. Like the root directory in a file system, the initial naming context provides a known point to build binding hierarchies. To complete the file system analogy, a binding maps to a file and a naming context maps to a directory. Thus, a naming context can contain multiple bindings and other naming contexts.

Common Object Services—The Event Service

The Event Service package provides a facility that decouples the communication between objects. It provides a supplier-consumer communication model that allows multiple supplier objects to send data asynchronously to multiple consumer objects through an event channel. The supplier-consumer communication model allows an object to communicate an important change in state, such as a disk running out of free space, to any other objects that might be interested in such an event.

The flow of data into the event channel is handled by the supplier objects, while the flow of data out of the event channel is handled by the consumer objects. The event channel is both a consumer of events and a supplier of events. The data communicated between suppliers and consumers are represented by the Any class, allowing any CORBA type to be passed in a type-safe manner. Supplier and consumer objects communicate through the event channel using standard CORBA requests.

Proxy consumers and suppliers

Consumers and suppliers are completely decoupled from one another through the use of proxy objects. Instead of directly interacting with each other, they obtain a proxy object from the EventChannel and communicate with it. Supplier objects obtain a consumer proxy and consumer objects obtain a supplier proxy. The EventChannel facilitates the data transfer between consumer and supplier proxy objects.

Communication models

The Event Service provides both a pull and a push communication model for suppliers and consumers. In the push model, supplier objects control the flow of data by pushing it to consumers. In the pull model, consumer objects control the flow of data by pulling data from the supplier.

The EventChannel insulates suppliers and consumers from having to know which model is being used by other objects on the channel. This means a pull supplier can provide data to a push consumer and a push supplier can provide data to a pull consumer.

Push model

The push model is the more common of the two communication models. An example use of the push model is a supplier that monitors available free space on a disk and notifies interested consumers when the disk is filling up. The push supplier sends data to its ProxyPushConsumer in response to events it is monitoring.

The push consumer spends most of its time in an event loop, waiting for data to arrive from the ProxyPushSupplier. The EventChannel facilitates the transfer of data from the ProxyPushSupplier to the ProxyPushConsumer.

Pull model

In the pull model, the event channel regularly pulls data from a supplier object, puts the data in a queue, and makes it available to be pulled by a consumer object. An example of a pull consumer would be one or more network monitors that periodically poll a network router for statistics.

The pull supplier spends most of its time in an event loop, waiting for data requests to be received from the ProxyPullConsumer. The pull consumer requests data from the ProxyPullSupplier when it is ready for more data. The EventChannel pulls data from the supplier to a queue and makes it available to the ProxyPullSupplier.

Putting It All Together—The Bank Example

In this section, we build a sample client application that can query and perform operations on the balance in a bank checking account.

Define the IDL

The Bank.idl file defines the Bank module that contains two interfaces: The Account interface provides methods for setting and obtaining the current balance; the CheckingsAccount interface provides a method that opens, credits to, debits from, and creates accounts with a specified name, and returns an Account object reference. The Account object reference can then be used to obtain the balance in the account.

User-defined exceptions

The Bank.idl defines a user exception called InvalidTransaction. This exception is raised by many of the methods defined in this file in various interfaces. User-defined exceptions map to final Java classes that extend org.omg.CORBA.UserException. The idltojava compiler automatically generates a Java class for each exception you define in the IDL. The class generated by the idltojava compiler provides instance variables for the fields of exception, as well as constructors. The IDL is shown in Listing

module Bank {

 exception InvalidTransaction {
  string explanation;
 };

 interface Account {
  float getBalance ();
  void setBalance (in float balance) 
         raises (InvalidTransaction);
 };

 interface CheckingsAccount {
  Account open(in string name);
  Account create(in string name, in float balance);
  Account credit(in string name, in float amount)
                      raises (InvalidTransaction);
  Account debit(in string name, in float amount)
                     raises (InvalidTransaction);
 };
};

Listing 8: The Bank Account CORBA IDL

Because the Bank.idl file requires no special handling, you can compile it by typing the following command:

F:\>idltojava Bank.idl

The generated code

Because Java allows only one public interface or class per file, compiling the Bank.idl file generates several java files. These files are stored in a generated subdirectory named Bank, which is the module name specified in the IDL file. IDL modules are mapped to Java packages, so all the files listed in the following will be part of the Bank package:

Develop the client

The Client class implements the client application that obtains the current balance of a bank account. The program performs the following steps:

  1. Initializes the Object Request Broker.
  2. Binds to a CheckingsAccount.
  3. Requests the CheckingsAccount to open the Account with the specified name. If no account name is supplied, a default name is used.
  4. Gets the balance of the Account using the object reference returned by the methods of the server.
  5. Prints the balance.

Listing 9 below, shows the Bank Account CORBA client implementation.

// Client.java
package ex3;

public class Client {
 
 public static void main (String[] args) {
  try {
   // Initialize the ORB.
   org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init (args,null);
   // Get a reference to the Naming Service
   org.omg.CORBA.Object nameServiceObj = orb.resolve_initial_references 
    ("NameService");
   
   if ( nameServiceObj == null ) {
    System.out.println ("nameServiceObj = null");
    return;
   }
   // Narrow the object
   org.omg.CosNaming.NamingContext nameService = org.omg.CosNaming.NamingContextHelper.narrow 
    (nameServiceObj);
   
   if( nameService == null ) {
    System.out.println ("nameService = null");
    return;
   }
   // Locate an object called CheckingsAccount
   // relative to the initial namecontext
   org.omg.CosNaming.NameComponent[] accountName = { 
    new org.omg.CosNaming.NameComponent ("CheckingsAccount", "")
   };
   Bank.CheckingsAccount checkingsAccount = Bank.CheckingsAccountHelper.narrow 
    (nameService.resolve (accountName));
   
   nameService.rebind (accountName, checkingsAccount);
   // use args[1] as the account name, or a default.
   String op = args.length > 0 ? args[0] : "-c";
   String name = args.length > 1 ? args[1] : "Gopalan";
   float amount = args.length > 2 ? 
                  (new Float (args[2])).floatValue () : 1000;
   // Request the CheckingsAccount to open a named account.
   Bank.Account account = null;
   try {
    if (op.equals("-c")) 
     account = checkingsAccount.create (name, amount);
    if (op.equals("-o")) 
     account = checkingsAccount.open (name);
    if (op.equals("-cr")) 
     account = checkingsAccount.credit (name, amount);
    if (op.equals("-db")) 
     account = checkingsAccount.debit (name, amount);
   } catch (Exception e) { e.printStackTrace (); }
   // Get the balance of the account.
   float balance = account.getBalance ();
   // Print out the balance.
   System.out.println ("The balance in " + name + "'s account is $" 
                       + balance);
  } catch (Exception e) { e.printStackTrace (); }
 }
}

Listing 9: The Bank Account CORBA client

Code the AccountImpl servant

The AccountImpl class in this file extends Bank._AccountImplBase class generated in the Bank package. This class contains methods to set or get an account Balance. If the Balance goes below zero, it throws an InvalidTransaction Exception. Listing 10 below, shows the AccountImpl servant class definition.

// AccountImpl.java
package ex3;
import java.util.*;

public class AccountImpl extends Bank._AccountImplBase {
 private float _balance;

 public AccountImpl (float balance) {
  super ();
  _balance = balance;
  System.out.println ("Created Account Server");
 }

 public float getBalance () { return _balance; }

 public void setBalance (float amount) 
  throws Bank.InvalidTransaction { 
  if (amount < 0)
   throw new Bank.InvalidTransaction ();
  else
   _balance = amount; 
 }
}

Listing 10: The AccountImpl class definiton

Code the CheckingAccountImpl servant

The CheckingsAccountImpl class in this file extends Bank._CheckingsAccountImplBase class generated in the Bank package. This class provides the actual implementation of the open, create, credit, and debit method used to obtain, create, credit, or debit an Account. The CheckingsAccountImpl uses a Dictionary to contain all the accounts.

When a request to create an account is received, the create method does the following:

All the other code is straightforward and needs no explanation.

Listing 11 below shows the CheckingsAccountImpl class definition

// CheckingsAccountImpl.java
package ex3;
import java.util.*;

public class CheckingsAccountImpl 
 extends Bank._CheckingsAccountImplBase {
 
 private Dictionary _accountsTable = new Hashtable ();
 private Random _random = new Random ();

 public CheckingsAccountImpl () {
  super ();
  System.out.println ("Created CheckingsAccount Server");
 }

 public synchronized Bank.Account open(String name) {
  // Lookup the account in the account dictionary.
  Bank.Account account = (Bank.Account) _accountsTable.get (name);
  // Return the account. 
  return account; 
 }

 public synchronized Bank.Account credit(String name, float amount) 
  throws Bank.InvalidTransaction {
  // Lookup the account in the account dictionary.
  Bank.Account account = (Bank.Account) _accountsTable.get (name);
  if (amount > 0)
   account.setBalance (account.getBalance ()+amount);
  // Return the account. 
  return account; 
 }

 public synchronized Bank.Account debit(String name, float amount)
  throws Bank.InvalidTransaction {
  // Lookup the account in the account dictionary.
  Bank.Account account = (Bank.Account) _accountsTable.get (name);
  if (amount > 0)
   account.setBalance (account.getBalance ()-amount);
  // Return the account. 
  return account; 
 }

 public synchronized Bank.Account create(String name, float balance) {
  // Lookup the account in the account dictionary.
  Bank.Account account = (Bank.Account) _accountsTable.get (name);
  // If the account is not in the dictionary, create an account.
  if (account == null) {
   // Create the account implementation, given the balance.
   account = new AccountImpl (balance);
   // Make the object available to the ORB. 
   // Export the newly created object 
   _orb ().connect (account);
   System.out.println ("Created " + name + "'s account: " +
                       account);
   // Save the account in the account dictionary.
   _accountsTable.put (name, account); 
  } 
  // Return the account. 
  return account; 
 }
}

Listing 11: The CheckingAccountsImpl CORBA servant class definition

Develop the server class

Just as with the client, many of the files used in implementing the bank server are contained in the Bank package generated by the idl2java compiler. The program performs the following steps:

  1. Initializes the Object Request Broker.
  2. Initializes the Portable Object Adaptor.
  3. Creates an CheckingsAccount object.
  4. Activates the newly created object.
  5. Prints a status message.
  6. Waits for incoming client requests.

Listing 12 below, shows the Bank Account CORBA server:

// Server.java
package ex3;
import org.omg.CosNaming.*;

public class Server { 
 
 public static void main (String[] args) {
  try {
   // Initialize the ORB.
   org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init (args,null);
   System.out.println ("Orb Initialized.");
   // Create the account CheckingsAccount object. 
   Bank.CheckingsAccount checkingsAccount = new CheckingsAccountImpl();
   if (checkingsAccount == null) {
    System.out.println ("CheckingsAccount = null");
    return;
   }
   // Export the newly created object 
   orb.connect (checkingsAccount);
   System.out.println ("CheckingsAccountServer is connected.");
   // Get a reference to the Naming Service
   org.omg.CORBA.Object nameServiceObj = orb.resolve_initial_references 
    ("NameService");
   
   if (nameServiceObj == null) {
    System.out.println ("nameServiceObj = null");
    return;
   }
   // Narrow the object
   org.omg.CosNaming.NamingContext nameService = org.omg.CosNaming.NamingContextHelper.narrow 
    (nameServiceObj);
   
   if (nameService == null) {
    System.out.println ("nameService = null");
    return;
   }
   // bind the CheckingsAccount object in the Naming Service
   org.omg.CosNaming.NameComponent[] accountName = { 
    new org.omg.CosNaming.NameComponent ("CheckingsAccount", "")};
   nameService.rebind (accountName, checkingsAccount);
   // Wait forever for current thread to die
   Thread.currentThread ().join (); 
  } catch (Exception e) { e.printStackTrace (); }
 }
}

Listing 12: The Bank Account CORBA server application

Run the Naming Service

F:\>
F:\>tnameserv
Initial Naming Context:
IOR:000000000000002849444c3a6f6d672e6f72672f436f734e61
6d696e672f4e616d696e67436f6e746578743a312e30000000000
100000000000000300001000000000008686f6d655f706300108c
000000000018afabcafe000000025ddcc3cd000000080000000000000000
TransientNameServer: setting port for initial object references to: 900

Run the CheckingAccount server

When the Checkings Account server is up and running, a typical session shows up like this on the window:

F:\>
F:\>java ex3.Server
Orb Initialized.
Created CheckingsAccount Server
CheckingsAccountServer is connected.
Created Account Server
Created Gopalan's account: ex3.AccountImpl:com.sun.CORBA.idl.GenericCORBAClientSC@dc47ae34
Created Account Server
Created Athul's account: ex3.AccountImpl:com.sun.CORBA.idl.GenericCORBAClientSC@d08fae34

Run the client

When the client is executed, typical sessions show up like this on the window:

F:\>
F:\>java ex3.Client
The balance in Gopalan's account is $1000.0
F:\>java ex3.Client -c Athul 2000
The balance in Athul's account is $2000.0
F:\>e:\java\jdk1.2\bin\java ex3.Client -o Athul
The balance in Athul's account is $2000.0
F:\>e:\java\jdk1.2\bin\java ex3.Client -cr Athul 100
The balance in Athul's account is $2100.0
F:\>e:\java\jdk1.2\bin\java ex3.Client -db Athul 100
The balance in Athul's account is $2000.0

F:\>

This concludes this 4 part article on Java and CORBA. I hope you enjoyed reading this as much as I did writing it.

You can always refer to my Homepage at http://www.execpc.com/~gopalan for more CORBA source code. Another good resource is the comp-object-corba@omg.org mailing list from OMG. You can get the CORBA specs from http://www.omg.org.

 

click here to go to
My CORBA HomePage...

 

About the Author...
Gopalan Suresh Raj is a Software Architect, Developer and an active Author. He is contributing author to a couple of books "Enterprise Java Computing-Applications and Architecture" and "The Awesome Power of JavaBeans". His expertise spans enterprise component architectures and distributed object computing. Visit him at his Web Cornucopia© site (http://www.execpc.com/~gopalan) or mail him at gopalan@execpc.com.

Go to the Component Engineering Cornucopia page

This site was developed and is maintained by Gopalan Suresh Raj

This page has been visited times since September 21,1998.

Last Updated : Dec 19, '98

If you have any questions, comments, or problems regarding this site, please write to me I would love to hear from you.


Copyright (c) 1997-99, Gopalan Suresh Raj - All rights reserved. Terms of use.

All products and companies mentioned at this site,are trademarks of their respective owners.