An Introduction to Programming with JacORB

Gerald Brose
Institut für Informatik
Freie Universität Berlin, Germany
[email protected]

This document gives an introduction to programming distributed applications with JacORB, a free Java object request broker. It is structured as follows. First, we briefly describe how to obtain and install JacORB. Section 2 gives a few examples on how to use JacORB to write distributed Java programs while section 3 contains a description of the utilities that come with JacORB.

1 Obtaining and installing JacORB

JacORB can be obtained as a gzipped tar-archive from the JacORB home page at http://www.inf.fu-berlin.de/~brose/jacorb/.

You need to have a Java JDK (version 1.0 or above) and the CUP parser generator packagegif installed properly on your system. (The IDL compiler uses a number of classes from the CUP package.)

To install JacORB, just gunzip and untar the archive in a directory, say JacORB. Make sure your CLASSPATH environment variable contains the path to the installation directory. Extend your search path with JacORB/jacorb/bin, so that the utilities in this directory are found. Also make sure the C-Preprocessor cpp is in your search path. You can then test your installation by typing "make" in one of the subdirectories of the jacorb/demo/ directory which contains a number of examples for using JacORB.

JacORB documentation consists of an overview paper, this document and a set of html-Files produced by javadoc which describe the Java API of the JacORB class library. All these files reside in the jacorb/doc/ subdirectory. (Warning: the API isn't documented particularly well. The most useful bit of documentation are the examples).

1.1 Contents of the Package

Utilities in jacorb/bin/

JacORB comes with three utilty programs. idl2j is the Idl-to-Java compiler which creates Java source code from IDL specifications. jgen is the JacORB generator and produces stubs and skeleton files from Java .class-Files, and ns is the name server. The use of these utilities is described in section 3.

CORBA specifications

The file Corba.idl contains the complete CORBA specification in IDL. The corresponding Java classes -- which were produced by running idl2j on Corba.idl, reside in the jacorb/CORBA/ directory

Common Object Services specifications

The complete set of IDL specifications from COSS is in Coss.idl. The IDL compiler generated the corresponding Java classes, which reside in the jacorb/COSS/ subdirectory.

ORB

The Java classes needed by the JacORB ORB are part of the package jacorb.Orb and can therefore be found in jacorb/Orb/.

Generator

The package jacorb.Generator and the corresponding directory contain the files needed by the JacORB stub generator. The main classes are Main.java and StubGen.java.

IDL compiler

The classes making up the IDL compiler are in package jacorb.Idl The main classes are:

Name Service

The Java classes implementing the name service can be found in jacorb/Naming/

Documentation in jacorb/doc

Programming examples in jacorb/demo/

2 A JacORB example

Before we go about explaining this example in detail, let's have a look at the general process of developing CORBA or distributed Java applications with JacORB. We'll follow this roadmap when working through the example (this example can be found in jacorb/demo/example1. We recommend that you look at the other examples as well).

The Steps we will generally have to take are:

1)
write an IDL interface specification for objects that are to be accessed as CORBA objects. (If you want to do only Java programming and have no need for CORBA, this step can be skipped).
2)
generate a corresponding Java interface with the IDL compiler and compile it with javac. If step 1) was omitted, you have to come up with the Java interface yourself.
3)
write a Java class which implements the interface of 2) and compile it
4)
generate a stub and a skeleton class from the server interface with the stub generator jgen and compile them
5)
write a "Main" class that instantiates the server implementation and its skeleton (and compile it)
6)
write a client class which instantiates a server stub and binds to it (and compile it).

Step 1: Interface Design

This example uses a very simple server. Its interface is given in server.idl.

	// File: server.idl
	module jacorb {	
	  module demo {
	     module example1 {
                typedef sequence < string > strings;
                interface server {
                   string writeMessage(in string a1);
                   string writeMessages(in strings a1);
                   strings arryfy(in string a1, in long a2);
                };
	     };
	  };
	};

Step 2: Generating the Java interface

Feeding this file into the idl compiler

$ idl2j -d ../../.. server.idl

produces a corresponding java interface in server.java which can then be compiled with javac.

    // Automatically generated by idl2java from interface server
    package jacorb.demo.example1; 
        public interface server extends CORBA.CORBject{
            java.lang.String writeMessage(java.lang.String a1);
            java.lang.String writeMessages(java.lang.String[] a1);
            java.lang.String[] arryfy(java.lang.String a1, int a2);
    }

Step 3: Implementing the interface

The class which implements that interface is called serverImpl:

    // File: jacorb/demo/example1/server.java
    package jacorb.demo.example1;

    public class serverImpl implements server {

        public String writeMessage( String s ){
            System.out.println("Message: " + s );
            return s + " written";
        }
        public String writeMessages( String[] s ){
            for( int i = 0; i < s.length; i++)
                System.out.println("Message: " + s[i] );
            return "string array written";
        }
	
        public String[] arryfy( String s, int i ){
            String result [] = new String[i];
            for( int j = 0; j < i; j++ )
                result[j] = s;
            return result;
        }
    }

Step 4: Generating stubs and skeletons

A client of this server relies only on the operation signatures in server.idl or server.java. What the client actually uses is not an instance of serverImpl, but a stub that is automatically generated from the Java interface (which in turn was generated from the IDL interface). It is type-correct to use the stub in place of the server since the stub also implements the interface server.

In order to generate the stub (and the server side skeleton), all you have to do now is type:

$ jgen server.class

This produces the two files serverStub.java and serverSkeleton.java. Alternatively, you can do a make all to compile and generate everything. To build everything anew cou can do a make clean; make all.

Step 5: Writing the server mainline

To actually start a serverImpl object which can be accessed remotely you have to instantiate it in a main method of some other class and initialize a skeleton for it. This skeleton was generated at the same time we generated the stub, so we can use it without further ado. Here is the class remoteServer.java which does all that is necessary to activate a serverImpl object (the server code itself remains unchanged):

    // File: jacorb/demo/example1/remoteServer.java	
    package jacorb.demo.example1;
    import jacorb.*;
	
    public class remoteServer{
       public static serverImpl s = new serverImpl();
       public static serverSkeleton st = new serverSkeleton( s );
	
       public static void main( String[] args ){
          try{
             st.skeleton_init("server", 
                 new URL ("http://www.inf.fu-berlin.de/~brose/ServiceLog"));
          } catch (IOException e ){
             e.printStackTrace();
          }
       }
    }

Step 6: Writing a client

Finally, let's have a look at the client which uses the stub:

    // File: jacorb/demo/example1/Client.java
    package jacorb.demo.example1;
	
    public class Client{
        //  use the stub instead of the real thing
        public static server s = new serverStub();
	
        public static void main( String[] args ){
           try{
              ((serverStub)s).bind("server", 
                  new URL("http://www.inf.fu-berlin.de/~brose/ServiceLog"));
	
              System.out.println( s.writeMessage( args[0] ));
              String a[] = s.arryfy( args[0],5 );
              System.out.println( s.writeMessages( a ));
	
              for( int i = 0; i < a.length; i++)
                 System.out.println("From example1: " + a[i] + " " + i );
           } catch (IOException e){
              e.printStackTrace();
           }
        }
    }

After compiling everything we're now ready to actually run the server and the client on different (virtual) machines. Make sure the name server is running before starting either the server or the client. If it isn't, type something like:

$ ns ~/public_html/ServiceLog

where ~/public_html/ServiceLog is the name of a locally writable file which can be read by using the URL given in both the remote client and server code. (This is to avoid using a well-known address for the name server, so both client and server look up the location of the nameserver via the URL and later communicate with it directly.)

You can now launch the server:

$ java jacorb.demo.example1.remoteServer

The client can be invoked on any machine you like:

$ java jacorb.demo.example1.Client hello

Running the client using the server stub after starting the server remotely produces the following output, which is exactly the same as if the server object was local:

   Message: hello
   hello written
   From example1: hello 0
   From example1: hello 1
   From example1: hello 2
   From example1: hello 3
   From example1: hello 4

3 JacORB utilities

3.1 The IDL-to-Java compiler

The IDL compiler parses IDL specifications and maps these to a set of Java classes. IDL interfaces are translated into Java interfaces, and typedefs, structs, const declarations etc. are mapped onto "equivalent" Java classes. For a description of the Java language mapping please see [1]

Usage

idl2j [-syntax] [-d <Output Directory>] file.idl

Invoking idl2j with the -syntax option allows you to check your IDL specification for syntactic errors without producing code. Without -syntax, the compiler creates directories according to the Java package structure.

Compiling a file with a module ModuleX and an interface InterfaceY in it will result in a subdirectory ModuleX with InterfaceY.java in it (and possibly more .java-files). By default, the root directory for all of the files created during the process is the current directory. You can, however, provide a different directory in which these files are to be placed by using the -d option. Using the -d option when you are only checking the syntax of an IDL file has no effect.

To generate stub and skeleton code after the IDL-to-Java translation step, you will have to run the JacORB generator on the relevant Java interface files that were produced in this step.

The parser was generated with Scott Hudson's CUP parser generator. The LALR grammar for the CORBA IDL is in the file jacorb/Idl/parser.cup.

3.2 The Stub Generator

The generator will take a .class-file (which can be compiled from a regular class or from an interface) and automatically construct Java source code for a client and a server stub class from it.

It can also be used to derive a class's interface from its implementation or produce informative interface output about the class on stdout. It does more than the javap disassembler in that it traverses the whole inheritance graph of a class in order to list every method of your class -- the inherited ones as well as the ones defined in the class itself. There is one exception to this: methods inherited from class Object are not listed.

Usage

jgen [ options ] <file.class>

The JacORB generator, when used without command line options, produces two files containing the Java source code for a client stub and a server skeleton.

Example:

$ jgen Game.class

generates GameStub.java and GameSkeleton.java which you can then compile and use.

Options

-i
derive an interface file instead of stub and proxy class files from a class. This interface file can then be compiled with javac.

Example:

$ jgen -i Game.class

generates a file GameInterface.java. You can check that it is ok by adding implements GameInterface to your class definition Game in Game.java and recompile.

In the produced interface file, every inherited method has a comment to it which indicates where it was inherited from, e.g.:

public void repaint(int, int, int, int);
// from java.awt.Component

Any method which is not accessible to the class the interface is derived from is commented out, so that the interface will compile correctly.

-f
print interface information on stdout.

Example:

$ jgen -f jacorb/demo/cardgame/PlayerApp.class

(The -f means "flatten the inheritance structure").

3.3 The Name Server

JacORB provides a service for mapping names to network references. The name server itself is written in Java like the rest of the package and is a straightforward implementation of the CORBA "Naming Service" from Common Object Services Spec., Vol.1 [2]. The IDL interfaces are mapped to Java according to our Java mapping.

Usage

ns <filename>

Example:

ns ~/public_html/ServiceLog

The name server does not use a well known port for its service and there is no way to direct it to a specific port. Since clients cannot (and need not) know in advance where the name service will be provided, we use a bootstrap file in which the name server records an opaque object reference to itself (its Interoperable Object Reference or IOR). The name of this bootstrap file has to be given as an argument to the ns command. This bootstrap file has to be available to clients networkwide, so we demand that it be reachable via a URL -- that is, there must be an appropriately configured HTTP server in your network domain which allows read access to the bootstrap file over a HTTP connection. After locating the name service through this mechanism, clients will connect to the name server directly, so the only HTTP overhead is in the first lookup of the server.

The name bindings in the server's database are mirrored in the bootstrap file, so you have a network wide readable log of which names are already in use.

4 Limitations

5 Bug reports

Please mail bug reports as well as suggestions to:

[email protected]

References

1
Gerald Brose, JacORB -- A Java Object Request Broker,
http://www.inf.fu-berlin.de/~brose/jacorb/jacorb.ps.

2
OMG, Common Object Services Specification, Volume I, Revision 1.0, March 1994, OMG Document 94-1-1.

3
OMG, The Common Object Request Broker: Architecture and Specification, Revision 2.0, July 1995.

About this document ...

An Introduction to Programming with JacORB

This document was generated using the LaTeX2HTML translator Version 96.1 (Feb 5, 1996) Copyright © 1993, 1994, 1995, 1996, Nikos Drakos, Computer Based Learning Unit, University of Leeds.

The command line arguments were:
latex2html -no_navigation -no_subdir -split 0 -show_section_numbers tutorial.tex.

The translation was initiated by Gerald Brose on Mon Apr 7 13:02:34 MET DST 1997

...package
Scott Hudson's CUP can be obtained from:
http://www.cc.gatech.edu/gvu/people/Faculty/hudson/java_cup/home.html.
 


Gerald Brose
Mon Apr 7 13:02:34 MET DST 1997