Count example in Java IDL

JDK 1.2 includes JavaIDL, which is a lightweight implementation of CORBA. The distribution of JDK 1.2 includes all required elements, including the idltojava compiler. A version of JavaIDL, which is distributed for JDK 1.1.x does not include the compiler, so it has to be downloaded separately.

Note:

idltojava compiler uses a CPP preprocessor. If you do need a preprocessor, you can use the following command:

prompt> idltojava -fno-cpp Count.idl

If you need a preprocessor (to process directives like #include, #pragma, etc.), then you need to note the following.

idltojava is hard-coded to use a default preprocessor. On Solaris machines, it uses the path /usr/ccs/lib/cpp when looking for the preprocessor. On Wintel machines, it is hard-coded to use the MS Visual C++ preprocessor.

You can change the preprocessor that idltojava uses by setting two environment variables:

Examples for Wintel users:

Windows 95 --in your autoexec.bat file, type something like the following:

prompt> set CPP=\usr\share\lib\cpp
prompt> set CPPARGS=/nologo
For Borland C++ compiler, the following will do:
prompt> set CPP=\BC5\bin\cpp32.exe
prompt> set CPPARGS=-P- -oCON
NT --go to Control Panel-->System and click on the Environment tab; then set the environment variables

Examples for Solaris users:

C shell --in your .cshrc file, type something like

prompt> setenv CPP /usr/ccs/lib/cpp
prompt> setenv CPPARGS -BCY
Bourne or Korn shells --in your .profile file, type something like
prompt> CPP=/usr/ccs/lib/cpp
prompt> export CPP
prompt> CPPARGS=-BCY
prompt> export CPPARGS
In the example above, B tells the preprocessor to support C++ style comments (// to indicate that the rest of the line is a comment), C tells the preprocessor to leave comments in the preprocessed file, and Y tells the preprocessor not to bother looking at standard input files (such as /usr/include) since they are mostly C header files.

When you run idltojava with these two environment variables set, and the flag -fcpp is ON, idltojava will automatically use the preprocessor you specified in CPP and pass it the arguments you put in CPPARGS.
 

Building the Count example

prompt> cd myCountDirectory
prompt> dir /w *.java *.idl
[...]
CountClient.java         CountClientApplet.java   CountClientDII.java
CountClientDIIDSI.java   CountDSIServer.java      CountImpl.java
CountServer.java         count.idl
[...]
prompt> idltojava  Count.idl
prompt> dir Counter
[...]
Count.java            CountHelper.java      CountHolder.java
_CountImplBase.java   _CountStub.java
[...]
prompt> type Counter\Count.java
/*
 * File: ./COUNTER/COUNT.JAVA
 * From: COUNT.IDL
 * Date: Wed Mar 04 16:48:51 1998
 *   By: idltojava Java IDL 1.2 Nov 10 1997 13:52:11
 */

package Counter;
public interface Count
    extends org.omg.CORBA.Object {
    int sum();
    void sum(int arg);
    void increment(int val)
;
}
prompt> javac *.java Counter/*.java
 

Modules generated by idltojava

As you can see, idltojava generates a number of files in a subdirectory with the name determined by the name of the module in the IDL file. Because these provide standard functionality, you can ignore them until it is time to deploy and run your program. The five files generated by the idltojava are:
  • _CountImplBase.java
  • This abstract class is the server skeleton, providing basic CORBA functionality for the server. It implements the Count.java  interface. The server class CountImpl extends _CountImplBase.
  • _CountStub.java
  • This class is the client stub, providing CORBA functionality for the client. It implements the Count.java interface.
  • Count.java
  • This interface contains the Java version of our IDL interface. It contains the single method sayHello(). The Count.java interface extends org.omg.CORBA.Object, providing standard CORBA object functionality as well.
  • CountHelper.java
  • This final class provides auxiliary functionality, notably the narrow() method required to cast CORBA object references to their  proper types.
  • CountHolder.java
  • This final class holds a public instance member of type Count. It provides operations for out and inout arguments, which CORBA has but which do not map easily to Java's semantics.
    When you write the IDL interface, you do all the programming required to generate all these files for your distributed application. The only  additional work required is the actual implementation of client and server classes.

    Java IDL Transient Nameservice

    The Java IDL Transient Nameservice is an object server provided with Java IDL. Use tnameserv at the command line prompt to start the
    Nameservice. This object server conforms to the standard object implementation and invocation techniques described in the previous sections
    of this page.

    The Nameservice stores object references by name in a tree structure similar to a file directory. A client may lookup or resolve object
    references by name.

    The Nameservice implements two CORBA objects: NamingContext (nc), which is analagous to a directory, and BindingIterator(bi), which is
    analagous to a file. Each BindingIterator instance represents a name/object reference pair.

    Note that NamingContexts and BindingIterators are transient objects themselves and that the entire directory structure is lost each time
    tnameserv stops running.

    COS Naming Service

    A name-to-object association is called a name binding. A name binding is always defined relative to a naming context. A naming context is an object that contains a set of name bindings in which each name is unique. Different names can be bound to an object in the same or different contexts at the same time. There is no requirement, however, that all objects must be named.

    To resolve a name is to determine the object associated with the name in a given context. To bind a name is to create a name binding in a given context. A name is always resolved relative to a context -- there are no absolute names.

    Because a context is like any other object, it can also be bound to a name in a naming context. Binding contexts in other contexts creates a naming graph (as in a file system, inserting directories in directories creates a naming graph). A naming graph allows more complex names to reference an object. Given a context in a naming graph, a sequence of names can reference an object. This sequence of names (called a compound name) defines a path in the naming graph to navigate the resolution process.

    Names

    Many of the operations defined on a naming context take names as parameters. Names have structure. A name is an ordered sequence of components.

    A name with a single component is called a simple name; a name with multiple components is called a compound name. Each component except the last is used to name a context; the last component denotes the bound object. The notation:

            < component1 ; component2 ; component3 >
    indicates the sequences of components.

    Note: The semicolon (;) characters are simply the notation used in this document and are not intended to imply that names are sequences of characters separated by semicolons.

    A name component consists of two attributes: the identifier attribute and the kind attribute. Both the identifier attribute and the kind attribute are represented as IDL strings.

    Note: When the Java IDL name server evaluates a name, it examines both the identifier and kind attributes. Both must match for a name match to result.

    The kind attribute adds descriptive power to names in a syntax-independent way. Examples of the value of the kind attribute include c_source, object_code, executable, postscript, or " ". The naming system does not interpret, assign, or manage these values in any way. Higher levels of software may make policies about the use and management of these values. This feature addresses the needs of applications that use syntactic naming conventions to distinguish related objects. For example, UNIX uses suffixes such as .c and .o. Applications (such as the C compiler) depend on these syntactic conventions to make name transformations (for example, to transform foo.c to foo.o).

    The lack of name syntax is especially important when considering internationalization issues. Software that does not depend on the syntactic conventions for names does not have to be changed when it is localized for a natural language that has different syntactic conventions -- unlike software that does depend on the syntactic conventions (which must be changed to adopt to new conventions).

    To avoid issues of differing name syntax, the Naming Service always deals with names in their structural form (that is, there are no canonical syntaxes or distinguished meta characters). It is assumed that various programs and system services will map names from the representation into the structural form in a manner that is convenient to them.

    Design principles of the Naming Service:

    1. The design imparts no semantics or interpretation of the names themselves; this is up to higher-level software. The naming service provides only a structural convention for names, for example, compound names.

    2.  
    3. The design supports distributed, heterogeneous implementation and administration of names and name contexts.

    4.  
    5. Names are structures, not just character strings. A struct is necessary to avoid encoding information syntactically in the name string (for example, separating the human-meaningful name and its type with a ".", and the type and version with a "!"), which is a bad idea with respect to the generality, extensibility, and internationalization of the Name Service. The structure define includes a human-chosen string plus a kind field.

    6.  
    7. Naming Service clients need not be aware of the physical site of name servers in a distributed environment, or which server interprets what portion of a compound name, or of the way that servers are implemented.

    8.  
    9. The Naming Service is a fundamental object service, with no dependencies on other interfaces.

    10.  
    11. Name contexts of arbitrary and unknown implementation may be utilized together as nested graphs of nodes that cooperate in resolving names for a client. No "universal" root is needed for a name hierarchy.

    12.  
    13. Existing name and directory services employed in different network computing environments can be transparently encapsulated using name contexts. All of the above features contribute to making this possible.

    14.  
    15. The design does not address namespace administration. It is the responsibility of higher-level software to administer the namespace.

    Running the application

    prompt> start tnameserv
    prompt> start java CountServer
    prompt> java CountClient

    If the version for JDK 1.1.x is used, then nameserv.bat should be used instead of tnameserv to start the name server.

    If another port is needed, then the following sequence of commands can be used:

    prompt> start tnameserv -ORBInitialPort 1050
    prompt> start java HelloServer -ORBInitialPort 1050
    prompt> java HelloClient -ORBInitialPort 1050

    The programs use org.omg.CORBA.InitialPort property to indicate the port to the ORB.

    A dynamic client can be used as well:

    prompt> start tnameserv
    prompt> start java CountServer
    prompt> java CountClientDII

    There is also a server that uses Dynamic Skeleton Interface (DSI), which can be used with both static and dynamic clients. An additional client CountClientDIIDSI obtains object reference from a file written by the server:

    prompt> start tnameserv
    prompt> start java CountDSIServer
    prompt> java CountClient
    [...]
    prompt> java CountClientDII
    [...]
    prompt> java CountClientDIIDSI
    [...]

    Implementation

    The following is the implementation of the Count example using JavaIDL. There are a number of ways to implement both the client and the server. They are shown in seperate sections.

    Count defininition

    The following is a slightly modified IDL file, which defines a step parameter to the increment method. The increment method is now void, and the value can be obtained by automatic get and set functions, which are generated for attributes. The names of the operations depend on the way they are implemented. We will discuss it further in one of the subsequent sections.

    module Counter
    {
      interface Count
      {
        attribute long sum;
        void increment(in long val);
      };
    };

    Count static implementation

    sum() and sum(int val)are generated automatically in the  Java interface (Counter\Count.java) corresponding to the IDL definition. They have to be implemented by the server object.

    // CountImpl.java: The Count Implementation

    import Counter.*;

    public class CountImpl extends _CountImplBase
    {
      private int sum;

      // Constructor
      CountImpl()
      {
        System.out.println("Count Object Created");
        sum = 0;
      }

      // get sum
      public  int sum()
      {
        return sum;
      }

      // set sum
      public  void sum(int val)
      {
        sum = val;
      }

      // increment method
      public void increment(int step)
      {
        sum = sum + step;
      }
    }

    Static server’s code

    // CountServer.java: The Count Server main program

    import Counter.*;           // The package containing our stubs.
    import org.omg.CosNaming.*;  // CountClient will use the naming service.
    import org.omg.CORBA.*;      // All CORBA applications need these classes.

    public class CountServer {

        public static void main(String args[])
        {
            try
            {
              // create and initialize the ORB
              ORB orb = ORB.init(args, null);

              // create servant and register it with the ORB
              CountImpl countRef = new CountImpl();
              orb.connect(countRef);

              // get the root naming context
              org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
              NamingContext ncRef = NamingContextHelper.narrow(objRef);

              // bind the Object Reference in Naming
              NameComponent nc = new NameComponent("Count", "");
              NameComponent path[] = {nc};
              ncRef.rebind(path, countRef);

              // wait for invocations from clients
              java.lang.Object sync = new java.lang.Object();
              synchronized (sync)
              {
                  sync.wait();
              }

            }
            catch (Exception e)
            {
                System.err.println("ERROR: " + e);
                e.printStackTrace(System.out);
            }
        }
    }

    Static client’s code

    // CountClient.java: The Count Client main program

    import Counter.*;           // The package containing our stubs.
    import org.omg.CosNaming.*;  // CountClient will use the naming service.
    import org.omg.CORBA.*;      // All CORBA applications need these classes.

    public class CountClient
    {
      public static void main(String args[])
      {
        try
        {
          // Initialize the ORB
          System.out.println("Initializing the ORB");
          ORB orb = ORB.init(args, null);

          // Bind to the Count Object
          System.out.println("Initializing naming services");
          org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
          System.out.println("Obtaining naming context");
          NamingContext ncRef = NamingContextHelper.narrow(objRef);
          System.out.println("Binding the Count object");
          NameComponent nc = new NameComponent("Count", "");
          NameComponent path[] = {nc};
          Count counter = CountHelper.narrow(ncRef.resolve(path));

          // Set sum to initial value of 0
          System.out.println("Setting sum to 0");
          counter.sum((int)0);

          // Calculate Start time
          long startTime = System.currentTimeMillis();

          // Increment 1000 times
          System.out.println("Incrementing");
          for (int i = 0 ; i < 1000 ; i++ )
          {
            counter.increment((int)5);
          }

          // Calculate stop time; print out statistics
          long stopTime = System.currentTimeMillis();
          System.out.println("Avg Ping = "
                           + ((stopTime - startTime)/1000f) + " msecs");

          System.out.println("Sum = " + counter.sum());
        }
        catch(Exception e)
        {
           System.out.println("ERROR : " + e);
           e.printStackTrace(System.out);
        }
      }
    }

    Dynamic client

    This is an implementation of a client that uses Dynamic Invocation Interface (DII). Note that the operation names that JavaIDL expects for attributes are _set_<attribute name> and _get_<attribute_name> (_set_sum and _get_sum in our case).

    // CountClientDII.java: The DII Count Client main program

    import Counter.*;
    import org.omg.CosNaming.*;
    import org.omg.CORBA.*;
    import java.io.*;

    public class CountClientDII
    {
      public static void main(String args[])
      {
        try
        {
          // create and initialize the ORB
          System.out.println("Initializing the ORB");
          ORB orb = ORB.init(args, null);

          System.out.println("Listing initial services");
          String[] listOfServices = orb.list_initial_services();
          for (int i = 0; i < listOfServices.length; i++)
            System.out.println(listOfServices[i++]);

          // get the root naming context
          System.out.println("Resolving initial references");
          org.omg.CORBA.Object objRef = orb.resolve_initial_references(listOfServices[0]);
          NamingContext ncRef = NamingContextHelper.narrow(objRef);

          // resolve the Object Reference in Naming
          System.out.println("Resolving object reference");
          NameComponent nc = new NameComponent("Count", "");
          NameComponent path[] = {nc};
          Count counterRef = CountHelper.narrow(ncRef.resolve(path));

    /* Here we could use CORBA interface introspection to discover
       the interface of the object:

       org.omg.CORBA.InterfaceDef interface = counterRef._get_interface();
       org.omg.CORBA.InterfaceDefPackage.FullInterfaceDescription descr = interface.describe_interface()

       FullInterfaceDescription includes the following fields:
          attributes
          base_interfaces
          defined_in
          id
          name
          operations
          type
          version

       The fields could be used to construct subsequent requests.
    */
          // Create a DII set request and set the arguments
          org.omg.CORBA.Request r = counterRef._request("_set_sum");

          r.set_return_type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_void));
          Any setVal = r.add_in_arg();
          setVal.insert_long(999); // set to 999

          // call the Count server object
          r.invoke();

          // Create a DII increment request and set the return value
          r = counterRef._request("increment");
          r.set_return_type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_void));

          //set the parameter
          setVal = r.add_in_arg();
          setVal.insert_long(4); // increment by 4
     

          // Calculate Start time
          long startTime = System.currentTimeMillis();

          // Increment 1000 times
          System.out.println("Incrementing");
          for (int i = 0 ; i < 1000 ; i++ )
          {
            // call the Count server object
            r.invoke();
          }

          // Calculate stop time; print out statistics
          long stopTime = System.currentTimeMillis();
          System.out.println("Avg Ping = "
                           + ((stopTime - startTime)/1000f) + " msecs");

          // get the value of the sum
          r = counterRef._request("_get_sum");
          r.set_return_type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_long));
          r.invoke();

          // extract the result
          int result = r.return_value().extract_long();
          System.out.println("Sum: " + result);

        }
        catch (Exception e)
        {
          System.out.println("CountClient : Exception: " + e) ;
          e.printStackTrace(System.out);
        }
      }
    }

    Dynamic client with direct object reference

    In this implementation, we do not use the Name Service to obtain a reference to object. The server writes it in a file as a string using orb.object_to_string() to tranlate the reference to a string. The client reads its stringified version and transforms it into an object with orb.string_to_object().

    // CountClientDII.java: The DII Count Client main program

    import Counter.*;
    import org.omg.CosNaming.*;
    import org.omg.CORBA.*;
    import java.io.*;

    public class CountClientDIIDSI
    {
      public static void main(String args[])
      {
        try
        {
          // create and initialize the ORB
          System.out.println("Initializing the ORB");
          ORB orb = ORB.init(args, null);

          System.out.println("Listing initial services");
          String[] listOfServices = orb.list_initial_services();
          for (int i = 0; i < listOfServices.length; i++)
            System.out.println(listOfServices[i++]);

          // get the root naming context
          System.out.println("Resolving initial references");
          org.omg.CORBA.Object objRef = orb.resolve_initial_references(listOfServices[0]);
          NamingContext ncRef = NamingContextHelper.narrow(objRef);

          // Read IOR from file
          byte[] iorBytes = new byte[1024];
          InputStream f = new FileInputStream(
                System.getProperty("user.home") +
                System.getProperty("file.separator") + "DSI.ior") ;
          DataInputStream in = new DataInputStream(f) ;
          int bytesRead = in.read(iorBytes) ;
          in.close();

          String ior = new String(iorBytes, 0, bytesRead);
          System.out.println("Object Ref: " + ior);

          Count counterRef = CountHelper.narrow(orb.string_to_object(ior));

          org.omg.CORBA.Request r;
          Any setVal;

          // Create a DII set request and set the arguments
          r = counterRef._request("_set_sum");

          r.set_return_type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_void));
          setVal = r.add_in_arg();
          setVal.insert_long(999); // set to 999

          // call the Count server object
          r.invoke();

          // Create a DII increment request and set the return value
          r = counterRef._request("increment");
          r.set_return_type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_void));

          //set the parameter
          setVal = r.add_in_arg();
          setVal.insert_long(4); // increment by 4
     

          // Calculate Start time
          long startTime = System.currentTimeMillis();

          // Increment 1000 times
          System.out.println("Incrementing");
          for (int i = 0 ; i < 1000 ; i++ )
          {
            // call the Count server object
            r.invoke();
          }

          // Calculate stop time; print out statistics
          long stopTime = System.currentTimeMillis();
          System.out.println("Avg Ping = "
                           + ((stopTime - startTime)/1000f) + " msecs");

          // get the value of the sum
          r = counterRef._request("_get_sum");
          r.set_return_type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_long));
          r.invoke();

          // extract the result
          int result = r.return_value().extract_long();
          System.out.println("Sum: " + result);
        }
        catch (Exception e)
        {
          System.out.println("CountClient : Exception: " + e) ;
          e.printStackTrace(System.out);
        }
      }
    }

    Dynamic Skeleton Interface

    DSI allows servers to serve a servant object without prior (compile time) knowledge of the object's interface. Instead of using skeleton code compiled from the IDL interface definition, the server constructs an operation invocation dynamically.

    Why Use DSI?

    Use DSI for servers that cannot have compile-time knowledge of the implementation interface. For example, you might need a bridging application to allow CORBA clients to invoke services residing in a COM environment while allowing COM clients the same access to services residing in the CORBA realm. Each environment has its own, very different way of building requests and responses.

    This bridging application would use DSI to convert a CORBA client request to a format understood by a COM server. And it would use DII to convert a COM client request to a format understood by a CORBA server. The application programmer writes all the code to perform this work.

    Contrast this with a typical static object invocation. The server has access to the compiled skeletons for the interfaces being invoked upon. These skeletons are generated by compiling the IDL interface definitions with the idltojava compiler. When the ORB receives a request, it uses the skeleton code to build the operation arguments on the server side and to send back any result.

    Steps to Using DSI

    To use DSI, implement and register a dynamic servant by doing the following:
    1. Declare your class to extend org.omg.CORBA.DynamicImplementation.

    2.  
    3. Implement the invoke() method.

    4. Write the invoke() method code to work with a ServerRequest object to:
      1. Extract the operation name via a call on op_name().
      2. Build an NVList of the operation parameters (this requires type information on the parameters, possibly from an interface repository).
      3. Extract the parameter values via a call on params(), passing the NVList.
      4. Perform the operation, assigning new values to out and inout parameters in the NVList as appropriate.
      5. Call either result() or except(), as appropriate.
      Note: The calls to params() and then to result() or except() must be made in the proper order. You must call params() before calling either of the other two methods, and you must call only one of result() or except() once only. Failure to observe any of these limitations results in a BAD_INV_ORDER exception.
       
    5. Implement the _ids() method.

    6. This method is inherited from org.omg.CORBA.portable.ObjectImpl, the superclass of DynamicImplementation. It returns the repository IDs of the interfaces implemented by this dynamic server.
       
    7. Create an instance of the DSI object and register it with the ORB via a call to org.omg.CORBA.ORB.connect().

    Server with Dynamic Skeleton Interface (DSI)

    // DSIServer implementation
    import java.io.*;
    import org.omg.CORBA.*;
    import java.util.*;
    import org.omg.CosNaming.*;

    // Dynamic servant class implementation
    class CountDSIServantImpl extends DynamicImplementation {

      private int sum;

      // Store the repository ID for the interface implemented
      static String[] myIds = {"IDL:Counter/Count:1.0"};

      // Create a reference to the ORB
      ORB orb;

      CountDSIServantImpl(ORB orb)
      {
        System.out.println("Count Object Created");
        sum = 0;
        this.orb = orb;
      }

      // Implementation of invoke() for handling dynamic requests
      public void invoke(ServerRequest request) {
        try
        {
          // System.out.println("DSI: invoke called, op = "+ request.op_name());

          // Create an NVList to hold the parameters
          NVList nvlist = orb.create_list(0);

          // An auxiliary object for obtaining parameters
          Any any;

          // Check the type of the operation
          if (request.op_name().equals("increment") == true)
          {
            // Add first argument to NVList
            any = orb.create_any();
            any.insert_long((int)0);
            nvlist.add_value("val", any, ARG_IN.value);
            request.params(nvlist);

            int step = nvlist.item(0).value().extract_long();
            // System.err.println("Argument: In value: step = " + step);

            sum = sum + step;

            // Set the return value
            TypeCode result_tc = orb.get_primitive_tc(TCKind.tk_void);
            Any result_any = orb.create_any();
            result_any.type(result_tc);

            request.result(result_any);
          }
          else if (request.op_name().equals("_set_sum") == true)
          {
            // Add first argument to NVList
            any = orb.create_any();
            any.insert_long((int)0);
            nvlist.add_value("val", any, ARG_IN.value);
            request.params(nvlist);

            sum = nvlist.item(0).value().extract_long();
            // System.err.println("Argument: In value: " + sum);

            // Set the return value
            TypeCode result_tc = orb.get_primitive_tc(TCKind.tk_void);
            Any result_any = orb.create_any();
            result_any.type(result_tc);

            request.result(result_any);
          }
          else if (request.op_name().equals("_get_sum") == true)
          {
           // this is always required - if no parameters, then use empty nvlist
            request.params(nvlist);

            System.err.println("Sum: " + sum);

            // Set the return value
            Any result_any = orb.create_any();
            TypeCode result_tc = orb.get_primitive_tc(TCKind.tk_long);
            result_any.type(result_tc);
            result_any.insert_long((int)sum);

            request.result(result_any);
          }
        }
        catch ( Exception ex ) {
          ex.printStackTrace();
          System.out.println("CountDSIServer: Exception thrown: " + ex);
        }
      }

      // Implement the _ids() method to return repository ID of interface
      public String[] _ids() {
        return myIds;
      }
    }

    public class CountDSIServer {

      public static void main(String[] args)
      {
        try
        {
          // Access and initialize the ORB
          org.omg.CORBA.ORB orb = ORB.init(args, null);

          // Create an instance of the dynamic implementation
          CountDSIServantImpl countRef = new CountDSIServantImpl(orb);

          // Register the dynamic servant with the ORB
          orb.connect(countRef);
          String ior = orb.object_to_string(countRef) ;
          System.out.println("IOR is " + ior) ;

          // Write IOR into file
          // It can be read by a client and used to re-create object reference
          OutputStream f = new FileOutputStream(
                System.getProperty("user.home") +
                System.getProperty("file.separator") + "DSI.ior") ;
          DataOutputStream out = new DataOutputStream(f) ;
          out.writeBytes(ior) ;
          out.close();

          // Alternate code using name services to pass the object reference
          // This lets connect the clients that use the naming service

          // get the root naming context
          org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
          NamingContext ncRef = NamingContextHelper.narrow(objRef);

          // bind the Object Reference in Naming
          NameComponent nc = new NameComponent("Count", "");
          NameComponent path[] = {nc};
          ncRef.rebind(path, countRef);

          // Wait for requests from client
          java.lang.Object sync = new java.lang.Object();
          synchronized(sync){
            sync.wait();
          }

        }
        catch (Exception ex) {
          ex.printStackTrace();
          System.err.println("DSIServer: Exception thrown: " + ex);
        }
      }
    }