next up previous contents
Next: The IDL/Java Language Mapping Up: JacORB Programming Guidev0.9 Previous: Installing JacORB

Getting Started

Before we go about explaining this example in detail, we will 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 which also contains a Makefile so that the development steps do not have to be carried out manually every time. Still, you should know what is going on.

As this document gives only a short introduction to JacORB programming and does not cover all the details of CORBA IDL, we recommend that you also look at the other examples in the jacorb/demo/ directory. These are organised so as to show how the different aspects of CORBA IDL can be used with JacORB.

JacORB development

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 IDL, 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 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. Note that the IDL compiler will produce a directory structure corresponding to the module structure in the IDL file, so it would have produced a subdirectory jacorb with a subdirectory demo (etc.) in the current directory had we not directed it to put this directory structure to ../../.. by using the -d switch with the compiler. As a result, all generated files that would have been in the jacorb/demo/example1 subdirectory are now put into the current directory. Also note that server inherits from org.omg.CORBA.CORBject. This is an empty interface which is used for the sole purpose of telling apart interfaces that were generated by the IDL compiler from those that were not. You will never need to write this line into interfaces developed by yourself.

    // Automatically generated by idl2java from interface server
    package example1; 
    public interface server
        extends org.omg.CORBA.CORBject
    {
        java.lang.String writeMessage(java.lang.String a1);
        java.lang.String writeMessages(java.lang.String[] a1);
        void arryfy1(java.lang.String a1, int a2, 
                     jacorb.Orb.SequenceOutHolder/*out*/ s);
        void arryfy2(java.lang.String a1, 
              jacorb.demo.example1.StringArray5OutHolder/*out*/ s);
    }

Step 3: Implementing the interface

The class which implements that interface is called serverImpl:

    package 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 void arryfy1(java.lang.String a1, int a2, 
                  jacorb.Orb.SequenceOutHolder s)
        {
            String result [] = new String[a2];
            for( int j = 0; j < a2; j++ )
                result[j] = a1;
            s.set_value(result);
        }


        public void arryfy2(java.lang.String a1, 
            jacorb.demo.example1.StringArray5OutHolder s)
	  {
            int sz = s.size();
            String result [] = new String[sz];
            for( int j = 0; j < sz; j++ )
                result[j] = a1;
            s.set_value(new StringArray5(result));
	  } 
    }

Note that this class has not a single line of ORB-related code in it (save for the use of Holder classes to mimick the IDL out parameter passing mode). JacORB supports only what is known as the TIE-mechanism for binding skeleton code to an application class, so there is no need to inherit from any ORB class. As Java supports only single implementation inheritance, you will more often than not need to inherit from application defined superclasses, so the other approach (BOAImpl in Orbix parlance) will frequently be ruled out. That's why it's not supported in JacORB)

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 register it with what is known as the Object Adapter. Here is the class remoteServer.java which does all that is necessary to activate a serverImpl object (the server code itself remains unchanged):

package example1;

public class remoteServer
{
   public static void main( String[] args )
   {
      try
      {
            // initialize ORB and BOA

            org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init();
            org.omg.CORBA.BOA boa = orb.BOA_init();

            // let the BOA create the server CORBA object

            org.omg.CORBA.Object server = 
            boa.create( new serverImpl(),	
                  "IDL:example1/server:1.0");

            // tell the BOA about it
            // (this named_obj_is_ready()-call is a proprietary
            // shortcut for calling boa.obj_is_ready() and
            // telling the name server to bind a name to
            // this object. 

            boa.named_obj_is_ready( server, "server" );

            // accept incoming requests

            boa.impl_is_ready();

      } catch (Exception e ){
            e.printStackTrace();
      }
   }
}

Step 6: Writing a client

Finally, let's have a look at the client which invokes server operations. There are actually two versions of it: one uses only the standard CORBA interface, the other makes use of a few JacORB shortcuts. Let's look at both of these in turns. First, here's the compliant one:

package example1;

import org.omg.CORBA.ORB;
import org.omg.CosNaming.*;

public class CorbaClient 
{
   public static void main( String[] args )
   {
      try
      {    // initialize the ORB and find the name service

         ORB orb = ORB.init();
         NamingContext nc = NamingContextHelper.narrow( 
               orb.resolve_initial_references("NameService") );

         // find an object (standard COSS naming interface)
	
         NameComponent[] components = new NameComponent[1];
         components[0] = new NameComponent("server","service");

         server s = serverHelper.narrow(nc.resolve(components));

         // make the call

         System.out.println( s.writeMessage( "hello World" ));

      } catch (jacorb.Orb.SystemException se){
         se.printStackTrace();
      }
   }
}

Now here's the one which uses the more convenient, but proprietary interface to the naming service to locate an object.

package  example1;

import jacorb.Naming.NameServer;

public class Client
{
   public static void main( String[] args )
   {
      if( args.length != 1 )
      {
         System.out.println("Usage: client <message>");
         System.exit(1);
      }

      try
      { 
         // locate the server object using the Name Service

         server s = serverHelper.narrow( NameServer.locate("server"));

         // do something with it

         System.out.println( s.writeMessage( args[0] ));

         StringArray5OutHolder sh5 = new StringArray5OutHolder();
         s.arryfy2( args[0], sh5 );
         String a[] = sh5.value();

         System.out.println( s.writeMessages( a ));

         for( int i = 0; i < a.length; i++)
            System.out.println("From example1: " + a[i] + " " + i );

         } catch (jacorb.Orb.SystemException se){
            se.printStackTrace();
         } // catch (Exception e){}
   }
}

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/NS_Ref

where ~/public_html/NS_Ref 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


next up previous contents
Next: The IDL/Java Language Mapping Up: JacORB Programming Guidev0.9 Previous: Installing JacORB

Gerald Brose
Tue Mar 31 08:47:04 MET DST 1998