Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Exploring the range of CORBA technology

A simple CORBA/Java example

Dave Bartlett (dbartlett@pobox.com), Consultant, author, and lecturer
Residing in Berwyn, Pennsylvania, Dave Bartlett is an independent consultant and freelance author and instructor. He is the author of Hands-On CORBA with Java, a 5-day course presented via public sessions or in-house to organizations. Presently, Dave is working to turn the course material into a book entitled Thinking in CORBA with Java. Dave has Masters degrees in Engineering and Business from Penn State. He can be reached at dbartlett@pobox.com.

Summary:  In June, we talked about why you would want to use CORBA and Java technology. This month, I'll get you started with a simple example that we can use to explore the many areas of CORBA technology. However, let's not lose sight of our goal: to create a distributed application with a client residing on one computer and making a request to a service running on another computer. We don't want to worry about details such as hardware or operating system software. We just want the service to answer the client's request.

Date:  06 Jul 2000
Level:  Introductory
Also available in:   Japanese

Activity:  4818 views
Comments:  

The IDL interface

The CORBA mechanics all start with an interface. The best way to think of an interface is to envision my car. That's right -- my car. You're not familiar with it, but if I said to you, "Take my car and pick up some sandwiches for lunch," you probably wouldn't question whether you're capable of driving my car. You may wonder where it's parked or whether it's safe to drive, but you should be confident that driving my car will be similar to driving your car. That's because the person-to-car interface is highly standardized among cars. There may be some implementation differences between my sedan and your sports car, but with the standard placement of the gas pedal, brakes, and steering, you should be down the road quickly and effortlessly.

Because CORBA is language independent, it relies on an interface definition language (IDL) to express how clients will make a request to the service that implements the interface. Our interface is one method: add(). This method takes two numbers (IDL longs) and returns the sum of those numbers. Here is our interface calculator:


Listing 1. calcsimpl.idl

module corbasem {
	module gen {
		module calcsimpl {
			interface calculator {
				long add(in long x, in long y);
			};
		};
	};
};

The IDL keywords in this interface are: module, interface, long, and in. IDL uses the module keyword to create namespaces and it maps very cleanly to the Java keyword package. When we run the IDL-to-Java compiler, the generated Java files will be placed into a subdirectory with the name calcsimpl. IDL keyword interface maps perfectly to Java interface and represents an abstract type in that both define only how you communicate with an object; it says nothing about the object's implementation. The IDL keyword long is a fundamental integer type that is mapped to at least a 4-byte type, which, in Java code, is an int.

If you think about the mechanics of making a remote method call, it makes perfect sense to define the direction that the parameters will be moving in -- client-to-server, server-to-client, or both. In IDL operations these are declared with the in, out, and inout keywords. Every parameter must have its direction declared so that the object request broker (ORB) knows in which direction the parameter is going. This impacts packaging up the parameters for sending, unpacking parameters, and memory management. The more the ORB understands about parameters, the more efficient it can be. The keyword in signifies that the long x and long y are passed from client to server.


Figure 1. Participants in a CORBA request
Figure 1. Participants in a CORBA request

The IDL compiler

After the interface is defined, it has to run through an IDL-to-Java compiler provided by your ORB vendor. The IDL compiler is a neat utility that produces the IDL stubs and skeletons, as well as other support files. Most of these generated source files will faciliate some portion of the marshalling of the specified IDL types as defined in the CORBA standard. The compiler produces most of the network plumbing, which in a distributed system is not trivial. On the most fundamental level, the IDL-to-Java compiler is simply a program that implements the IDL-to-Java language mapping as defined by the CORBA 2.3 specification. If we had to produce this code by hand it would be tedious, time-consuming, and prone to errors; the IDL-to-Java compiler takes care of all this so you don't have to. At the same time, it binds you to certain laws and forces encapsulation upon you. The IDL-to-Java compiler will force upon your system the laws of CORBA-land.

I entered the following command to execute the IDL-to-Java compiler from Orbacus. I target all the generated files to an output directory that is in my CLASSPATH.


Listing 2. Calling the IDL-to-Java compiler

What has been produced? All the Java source files on which the implementation will be built are generated by this command. The IDL-to-Java compiler ensures that the defined interface will abide by the laws set forth by the CORBA specification.


Figure 2. IDL-to-Java compiler file generation
Figure 2. IDL-to-Java compiler file generation

Need an IDL compiler? You may already have an ORB vendor and an IDL-to-Java compiler. But if you don't, where do you get them? There are quite a few out there, and some are even free to download. I recommend the Orbacus ORB from Object Oriented Concepts, Inc. If you are not using it for commercial purposes, it is free, downloadable, and fully compliant to the CORBA 2.3 specification. Also available for a 60-day evaluation is Inprise's Visibroker, which is also fully CORBA 2.3-compliant and available for download. See Resources for both of these products.

Here are the files:

  • calculator.java - This file is called the signature interface file. The CORBA specification states that this file must extend IDLEntity and have the same name as the IDL interface name. This file provides the type signature so that this interface can be used in method declarations for other interfaces.
  • calculatorOperations.java - This file contains the Java public interface -- calculatorOperations. The specification states that this file should have the same name as the IDL interface name with the Operations suffix added and contains the mapped operations signatures for the interface. The signature interface defined above (calculator.java) extends this interface.
  • calculatorHelper.java - The helper class is designed to keep many of the needed housekeeping functions out of our interfaces but readily available to our implementations. The helper file contains the important static narrow method that allows an org.omg.CORBA.Object to be narrowed to an object reference of a more specific type, which in this case will be a calculator type.
  • calculatorHolder.java - The holder class is a specialized class that is generated for any type that may need to be passed by reference. The holder class will not be used in this example but we will see it often in future columns.
  • calculatorPOA.java - The skeleton class provides much of the request-response plumbing for CORBA functionality. calculatorPOA.java is generated because our default implementation is inheritance based. Our output would be different if we chose to have a delegation-based implementation. Future columns will present these topics in detail.
  • _calculatorStub.java - As the name implies, this is the stub class. Your client will need this class to make it all work.

The server

The generated files must now be put to work in a server that implements our interface. Thankfully, much of the plumbing is in place for us, but don't celebrate too soon -- there is still a lot of work to do; namely, all these files have be used in the correct places.

Let's start with an implementation of our method add(). (You can download the complete SimpleCalcSvr.java file.)


SimpleCalcServant extends calculatorPOA {
    public int add(intx, inty) {
      return x + y;
   }
}

Notice that our implementation class extends the generated class calculatorPOA. When a request comes in from a client it comes up through the ORB into the skeleton. The skeleton will eventually call into SimpleCalcServant to complete the request and start the response. Our interface was simple, therefore our implementation is simple as well.

Implementing the rest of the server involves setting up the CORBA architecture around this interface implementation. For reasons of portability and flexibility, many of these calls are mandated by the CORBA specification.

The first task we need to complete is detailing which ORB we would like to use, and then initializing it. The following code (lines 18 thru 29 in file SimpleCalcSvr.java) handle this task:


   java.util.Propertiesprops = System.getProperties();
   props.put("org.omg.CORBA.ORBClass",
             "com.ooc.CORBA.ORG");
   props.put("org.omg.CORBA.ORBSingletonClass",
             "com.ooc.CORBA.ORBSingleton");

   org.omg.CORBA.ORBorb =null;
   // initialize the ORB
   orb = org.omg.CORBA.ORB.init(args, props);

When we initialize the ORB we need to tell it exactly which class will be acting as the ORBClass and which will be acting as the ORBSingleton class. Our implementation should not care, but all of our associated plumbing will. As I said before, in this case I am using Object Oriented Concepts, Inc. Orbacus ORB and the OOC classes are given in those two props.put() calls. Once the properties are filled in, props is simply passed as a parameter to the ORB.init() method. The fact is, things change and if we wanted to move this server to another ORB we would not want to have to recode our server. Therefore, we would ideally like to alter a configuration file to point to another ORB class and simply restart.

The ORB is now in place and initialized, and the implementation is in place but not yet created. At this point we need to create the perfect place for our implementation to live in, and this is not as easy as it sounds. In a distributed environment, each of our implementations may require slight environmental differences. There are a lot of characteristics that we can give our implementations. Implementations can be single-threaded or multi-threaded, they can be highly scalable pools of objects, or they can be singletons. These many different server characteristics have given rise to the Portable Object Adapter (POA). The POA allows us to create the perfect environment for our implementation to reside in. All 2.3-compliant ORBs will have a root POA from which all other POAs are created. In this simple example I have split off the implementation-specific code into its own method: runcalc().

Creating an environment for our implementation will be our first task, so we'll have to set up a POA. Originally, CORBA servers worked with Basic Object Adapters (BOA), but every vendor's BOA was different. With the latest version of the CORBA specification, the BOA is completely replaced by the POA.


   // setup the Portable Object Adapter
   // from the always present rootPOA
   org.omg.PortableServer.POArootPOA =
      org.omg.PortableServer.POAHelper.narrow(
         orb.resolve_initial_references("RootPOA"));

   org.omg.PortableServer.POAManagermanager =
      rootPOA.the_POAManager();

By title and definition, this is a simple example. We will keep things simple by using the root POA rather than creating a new one. The POA manager is an object that encapsulates the processing state of the POA. So, we will use the POA manager to start the queuing of requests to our servants.

We still need to instantiate our implementation:


   // create servant for calculator interface
   SimpleCalcServantcalcSvt =new SimpleCalcServant();
      calculatorcalc = calcSvt._this(orb);

Per the CORBA 2.3 specification, all skeletons provide a _this() method, which allows the servant to obtain the object reference for the target CORBA object it is associating for those requests.

After we have instantiated the implementation, the mechanics must be put into place for our clients to be able to locate it. There are many different methods and services available to locate objects that will satisfy the request to an interface. The CORBA Services define the Naming Service and the Trader Service specifically to help clients find objects to handle requests. An object could also be passed in on a method call.

In this example, we will use the most straightforward method of all -- writing our object reference to a file that will be picked up by our client. The creation of a string representation of an object reference and the reverse, string-to-object reference, is required functionality for all ORBs.


   // write the object reference to a file
   PrintWriterrefstr =new PrintWriter(
      new FileWriter("calcref.ior"));
   refstr.println(orb.object_to_string(calc));
   refstr.close();

The last thing we need to do is activate our POA to start queuing client requests and force the server to enter its event loop to receive those incoming requests.


Listing 8. SimpleCalcSvr.java -- Activate POA

// make the implementation available
 manager.activate();
 System.out.println("SimpleCalcSvr is running!");
 orb.run();


The client

If you think about the mechanics of what is happening, you should realize that the client and server are really just mirror images of each other. The client creates the request by packaging up all the parameters and sending the request on its way. The server simply unpacks the parameters of the request, performs the operation, packages up the return value and out parameters, and sends the response back to the client. The client unpacks the return value and out parameters, then continues processing. Therefore, what the client packages, the server unpacks and vice versa.

This means that you should expect to see similar structures between the client and the server. The client must also create and initialize an ORB. It could be the same ORB we were using, or it could be an ORB from a different vendor. However, it cannot be just any ORB. It should be an ORB that supports IIOP, the TCP/IP-based interoperability protocol defined by the Object Management Group (OMG). If you have an older ORB, beware -- it may not speak with other ORBs.

First, we create our ORB in the same manner as the server. (You can download the complete SimpleCalcClient.java file.)


Listing 9. SimpleCalcClient.java -- Initialize ORB

   java.util.Propertiesprops = System.getProperties();
   props.put("org.omg.CORBA.ORBClass",
      "com.ooc.CORBA.ORG");
   props.put("org.omg.CORBA.ORBSingletonClass",
      "com.ooc.CORBA.ORBSingleton");

   org.omg.CORBA.ORBorb =null;
   // initialize the ORB
   orb = ORB.init(args, props);

Look familiar? It should, it is exactly like the server. Our client is now connected to an ORB, but our goal is to call to a service that is provided elsewhere in our system. We need to locate the object that will respond to our request. In this example, that means obtaining an object reference from the file we created in the server. To locate the calculator server we need to take the string version of the object reference stored in the file and turn it into an object reference we can use to call through.


Listing 10. SimpleCalcClient.java -- Get object reference

   System.out.println("Getting reference from string...");
   BufferedReaderin = new BufferedReader(
      new FileReader("calcref.ior"));
   Stringior = in.readLine();
   in.close();

   calculatorcalc = calculatorHelper.narrow(
      orb.string_to_object(ior));

Notice the use of the calculatorHelper class generated by our IDL-to-Java compiler. The calcref.ior file contains an object reference rather than a calculator reference. The calculatorHelper class's narrow method is used to focus the abstract type to the specific calculator type.

Look closely at calculator calc. That represents the server somewhere out there in cyberspace. The last thing we have to do is invoke the method add() on calc.


Listing 11. SimpleCalcClient.java -- Invoke add()

 System.out.println( calc.add(2,3) );


In conclusion

I know we've covered a lot, but think of what we've gained. Our client is completely isolated from our server. It does not know what hardware it is running on, what operating system it is using, what language it is written in, if it is multi-threaded, or where it is located -- be it in the next room or halfway around the world. All it knows is that if it calls add() on calc it will get a response it can count on.

This is all about providing a service like the telephone or the electric company. When you pick up your phone you expect to get a dial tone and a clear connection for your call. You don't care if the call is being routed through fiber optic cables or bounced off a satellite. The same is now coming true in the information industry, thanks to the OMG and the infrastructure we put into our simple, yet extraordinarily powerful, example.

Next month we will dig a little deeper and look at the magic of IIOP that is happening just below the surface.


Resources

About the author

Dave Bartlett

Residing in Berwyn, Pennsylvania, Dave Bartlett is an independent consultant and freelance author and instructor. He is the author of Hands-On CORBA with Java, a 5-day course presented via public sessions or in-house to organizations. Presently, Dave is working to turn the course material into a book entitled Thinking in CORBA with Java. Dave has Masters degrees in Engineering and Business from Penn State. He can be reached at dbartlett@pobox.com.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services, Java technology
ArticleID=10458
ArticleTitle=Exploring the range of CORBA technology
publish-date=07062000
author1-email=dbartlett@pobox.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers