Add the power of CORBA to our distributed whiteboard

Find out how to transport serialized Java objects to and from an applet client and a Java server using CORBA

You gotta be Java -- and 1.1-patched at that.

Play with the CORBAtized whiteboard!

Note: You must use Appletviewer 1.1 or an AWT 1.1-enabled version of Netscape to view and manipulate the whiteboard (see Resources for a link to the patch required to bring Netscape up to speed).

Whiteboard history -- from sockets, RMI, and servlets to CORBA The last installment of Step by Step illustrated how to use a servlet as the server element of the collaborative whiteboard system that we've been examining of late. Because the most natural and handy use for servlets is as Web server extensions, we developed a whiteboard communications layer that used the HTTP protocol to communicate between clients and an HTTP servlet.

The client, implemented as an applet, used URLs to HTTP POST a message to the servlet, which maintained the shared whiteboard state. The servlet responded with a message of its own during the response portion of the same HTTP POST. The messages passed over HTTP were actual Java objects, serialized using the 1.1 serialization mechanism.

The interesting thing about this communications implementation is that it's hidden within ObservableList, which is the client data structure that contains the actual list of whiteboard objects to be displayed. As far as the whiteboard is concerned, it doesn't matter whether we're using RMI, Berkeley sockets, or HTTP to effect communications. In fact, the servlet-based communications layer was substituted in place of a similar one using RMI, which in turn replaced a layer that used sockets.

How do these different communication mechanisms measure up? Sockets and HTTP have the advantage of being simple, flexible, and fast. Sockets allow realtime communication. HTTP solves the problem of communicating through firewalls. On the other hand, they share the disadvantage of being low-level mechanisms, which means that you -- the developer -- have to provide a lot of application-specific code if you want to use them to enable communications. In fact, you must provide a messaging protocol as well as the message transport.

What we're really looking for is a direct object-to-object communication mechanism that would allow objects to call others' methods directly. RMI provides this, and hides the mechanics of it from the developer. But what if we want to implement the server in C++ or some other non-Java language, or we want to connect to a legacy system of some kind? We'd be out of luck because RMI is for JVM-to-JVM communications only.

That leaves us with only one alternative: CORBA.

It turns out that CORBA solves these problems for us. CORBA provides a generalized way to "glue" objects together even if they're implemented in different languages and/or are physically distributed. A word of warning: CORBA is a very powerful and complicated beast. We'll only scratch the surface here, but with the techniques you learn in this column you'll have the fundamentals for using CORBA as a distributed computing mechanism for Java.

Crash course on CORBA

Common Object Request Broker Architecture, or simply CORBA, is a high-level integration technology for distributed applications. The CORBA standard is maintained by the Object Management Group (OMG), is currently in version 2, and enjoys widespread industry support.

As an integration technology, CORBA is used to allow distributed objects to communicate with each other. CORBA is interesting because it isn't language-dependent and it's (mostly) not even vendor-dependent.

The components of CORBA

There are a number of technologies associated with CORBA. We'll cover only the core ones here.

  • The Object Request Broker (ORB) is the "software bus" between distributed objects. The ORB keeps track of the location of remote server objects and makes local objects available remotely as servers. All the developer has to do to obtain (or provide) object access to remote systems is interface with the local ORB. An ORB doesn't run in a process as a standard service does. Instead, it exists as a middleware layer that is located partially at the server (the "skeleton") and partially at the client (the "stub"). Of course, a service that listens for incoming requests from other ORBs has to run on any machine that wishes to provide server objects. ORBs are often integrated into Web browsers and OSs, and an ORB can function as both client and server, depending on the needs of the applications that make use of it. A typical client/server application would use a server application that only handles server responsibilities and a client that handles only client responsibilities. This is how we'll architect our communications layer in this installment.
  • Internet Inter-ORB Protocol (IIOP) is the protocol that ORBs use to communicate over TCP/IP networks. As applications developers, we don't have to worry too much about its internal workings -- we just need to verify that support for it is present in the ORB we choose. IIOP implementation is required for an ORB to be fully compliant with CORBA 2, the latest version.
  • Interface Description Language (IDL) is used to specify the interface between the client ORB and the server ORB. The IDL interface specification is then compiled via an IDL-to-implementation language compiler to produce stub and a skeleton code. Ideally, the IDL will enable your ORB to communicate with other vendors' ORBs. In practice, this isn't always the case, but between language-specific versions of a single vendor's ORB (for example, Visigenic's C++ ORB and Visigenic's Java ORB) the vendor's IDL can be expected to be 100 percent compatible.
  • Business Objects are what you as the applications developer produce. OMG defines business objects as high-level representations of things that exist in a business domain. Examples would be a customers, orders, and employees.

CORBA development steps

Here's the general process to follow to get your Java CORBAtized distributed app up and running. We're going to go for the gusto and use CORBA over the Web with an applet-based client instead of using a standalone client.

  1. Get and set up an ORB on your Web server. You can use ORBs from Visigenic, IONA, Expersoft, or any of a number of other vendors. This installation will be used by the CORBA server. The installation instructions should be provided with the ORB. Make its classes available under your Web tree so that clients can load them. This is not necessary if you plan to use Netscape's built-in Visigenic ORB, which is preferable if your clients will all access using Netscape.
  2. Define the server interface for your application in an IDL file.
  3. Compile the interface for the server object from IDL into (in this case) Java using the idl2java compiler. This tool will generate a set of helper classes, including the Java interface class itself.
  4. Write the server class -- for example, CorbaListServerImpl. The server will extend the class _server interface nameImplBase. It will implement the exact method signatures found in the Java server interface class that idl2java generated from the IDL definitions. In our case, this interface class is called CorbaListServer. In our case, the server will also have its own main () method so that it can export itself to the world when you start it. Generally speaking, the server object doesn't have to have its own main () method and export itself; instead, it could be exported by some other object that provides a thread for it.
  5. Write the client class. The client should register with its local ORB and create a reference to the remote server object. It can then use this reference to make calls directly on the remote server object.
  6. Compile all the code.
  7. Start the listening services for the server side. Visibroker's osagent and gatekeeper are the relevant services for our purposes. Osagent's default port is TCP 14000 and gatekeeper's is TCP 15000, so if you want to allow access behind a firewall you'll have to punch holes in the firewall at those ports.
  8. If your client is an applet, add the appropriate parameters to your HTML tag.
  9. Start the server object with java CorbaListServerImpl. Clients can now connect to your server!

Now it's time to put theory into practice and apply these steps to our whiteboard app.

Getting and setting up the ORB

The first thing to do to get up and running with CORBA is to acquire and install an ORB. We're going to use the Visigenic ORB for our project, because it is embedded in Netscape Navigator (use NS version 4.0.4 or later). Check the Resources section for the link to Visigenic's download site. We're going to use the Visigenic Java ORB, which is called VisiBroker 3.1 for Java, evaluation version.

After you've set up the VisiBroker for Java on your system, make sure you're using JDK 1.1.3 or later and that your JDK bin directory is included in your PATH. Also, your CLASSPATH must include the Visigenic classes, which are probably in c:\visigenic\vbroker\lib\ (under Windows). Create a separate entry in your CLASSPATH for each of the three JAR files in that directory. If you like, you can use the Visigenic Java compiler (vjc) instead of javac and you don't have to set your CLASSPATH to include the Visigenic classes.

Now it's time to put the classes up on the Web server. Copy the com subdirectory to the directory in your Web tree from which the applet will launch.

Now you're ready to define an IDL interface for the server.

CORBAtized whiteboard system architecture

Defining the interface with IDL

IDL is not a programming language; rather, it's an interface specification "language" for CORBA objects. A comprehensive (or even remotely complete) treatment of IDL is beyond the scope of this article, but the Resources section provides links to more information about IDL and the Visigenic mapping of IDL to Java.

The following segment is the IDL that defines the server interface.

module corbawb { typedef sequence<octet> SerializedObject; interface CorbaListServer { SerializedObject addElement (in SerializedObject element); SerializedObject replaceElement (in SerializedObject id, in serializedObject element); SerializedObject getUpdate (in long updateCount); };


The first thing this IDL file does is define the CORBA module, which maps to the Java package mechanism. The Java versions of interfaces defined in the module, as well as all helper classes generated by idl2java, will be placed into the package corbawb. We're putting them in corbawb with the other classes for the application.

Note that IDL provides a C++ -like syntax. This explains the typedef construct, which maps the CORBA type sequence<octet> to our name SerializedObject. A SerializedObject is what we will use to pass Java byte arrays that contain objects being passed by value. These objects will be passed from clients to server and vice versa.

The server The server consists of a Java server interface produced from IDL and a server implementation that implements it. The server implementation is assisted by a skeleton class and some other helpers produced by the IDL compiler. The skeleton class knows how to do the networking functions of CORBA (which you would have to write yourself with a sockets-based approach).

Class CorbaListServer

This is the code produced by idl2java, and it is the interface that we must implement in CorbaListServerImpl. It's shown here minus the comments that idl2java includes.

  package corbawb;
public interface CorbaListServer extends org.omg.CORBA.Object {
  public byte[] addElement (byte[] element);
  public byte[] replaceElement (byte[] id, byte[] element);
  public byte[] getUpdate (int updateCount);

Class CorbaListServerImpl

Here we see the imports for the ORB and BOA classes, which together manage the process of making the server available to clients and handling their requests.

package corbawb;

import org.omg.CORBA.ORB; import org.omg.CORBA.BOA; import org.merlin.step.dec.IDList;

public class CorbaListServerImpl extends _CorbaListServerImplBase {

It's highly important to note that our server implementation extends _CorbaListServerImplBase, which is produced by the IDL compiler. _CorbaListServerImplBase itself is declared to implement the CorbaListServer interface, which, of course, means that we have to provide the implementations of those methods in CorbaListServerImpl.

protected IDList list = new IDList ();

public CorbaListServerImpl (String name) { super (name); }

// CorbaListServer interface's method implementations public byte [] addElement (byte [] elementBytes) { Object element = CorbaWBUtil.deserialize (elementBytes); return CorbaWBUtil.serialize (list.addElement (element)); }

public byte [] replaceElement (byte [] idBytes, byte [] elementBytes) { Object id = CorbaWBUtil.deserialize (idBytes); Object element = CorbaWBUtil.deserialize (elementBytes); return CorbaWBUtil.serialize (list.replaceElement (id, element)); }

public byte [] getUpdate (int updateCount) { return CorbaWBUtil.serialize ((list.getUpdateCount () == updateCount) ? null : list.clone ()); }

Here we see details of the constructor and CorbaListServer interface method implementations. Notice that we're passing in and returning byte arrays. This is the interface that the IDL compiler generated for us as compatible with CORBA.

1 2 Page 1
Page 1 of 2