[Erlang Systems]

9 Orber Examples

9.1 A tutorial on how to create a simple service

9.1.1 Interface design

This example uses a very simple stack server. The specification contains two interfaces: the first is the Stack itself and the other is the StackFactory which is used to create new stacks. The specification is in the file stack.idl.

#ifndef _STACK_IDL
#define _STACK_IDL

module StackModule {
  
  exception EmptyStack {};

  interface Stack {

    long pop() raises(StackModule::EmptyStack);

    void push(in long value);

    void empty();

  };

  interface StackFactory {

    StackModule::Stack create_stack();
    void destroy_stack(in StackModule::Stack s);

  };

};

#endif

9.1.2 Generating Erlang code

Run the IDL compiler on this file by calling the ic:gen/1 function

   1> ic:gen("stack").
      

This will produce the client stub and server skeleton. Among other files a stack API module named StackModule_Stack.erl will be produced. This will produce among other files a stack API module called StackModule_Stack.erl which contains the client stub and the server skeleton.

9.1.3 Implementation of interface

After generating the API stubs and the server skeletons it is time to implement the servers and if no special options are sent to the IDl compiler the file name should be <global interface name>_impl.erl, in our case StackModule_Stack_impl.erl.

-module('StackModule_Stack_impl').
-include_lib("orber/include/corba.hrl").
-include_lib("orber/examples/Stack/StackModule.hrl").
-export([pop/1, push/2, empty/1, init/1, terminate/2]).


init(Env) ->
    {ok, []}.

terminate(From, Reason) ->
    ok.

push(Stack, Val)  ->
    {reply, ok, [Val | Stack]}.

pop([Val | Stack]) ->
    {reply, Val, Stack};
pop([]) ->
    corba:raise(#'StackModule_EmptyStack'{}).

empty(_) ->
    {reply, ok, []}.

We also have the factory interface which is used to create new stacks and that implementation is in the file StackModule_StackFactory_impl.erl.

-module('StackModule_StackFactory_impl').
-include_lib("orber/include/corba.hrl").
-export([create_stack/1, destroy_stack/2, init/1, terminate/2]).


init(Env) ->
    {ok, []}.

terminate(From, Reason) ->
    ok.

create_stack(State)  ->
    %% Just a create we don't want a link.
    {reply, 'StackModule_Stack':oe_create(), State}.

destroy_stack(State, Stack)  ->
    {reply, corba:dispose(Stack), State}.

To start the factory server one executes the function StackModule_StackFactory:oe_create/0 which in this example is done in the module stack_factory.erl where the started service is also registered in the name service.

-module('stack_factory').
-include_lib("orber/include/corba.hrl").
-include_lib("orber/COSS/CosNaming/CosNaming.hrl").
-include_lib("orber/COSS/CosNaming/lname.hrl").

-export([start/0]).

start() ->
    SFok = 'StackModule_StackFactory':oe_create(),
    NS = corba:resolve_initial_references("NameService"),
    NC = lname_component:set_id(lname_component:create(), "StackFactory"),
    N = lname:insert_component(lname:create(), 1, NC),
    'CosNaming_NamingContext':bind(NS, N, SFok).

9.1.4 Writing a client in Erlang

At last we will write a client to access our service.

-module('stack_client').
-include_lib("orber/include/corba.hrl").
-include_lib("orber/COSS/CosNaming/CosNaming.hrl").
-include_lib("orber/COSS/CosNaming/lname.hrl").
 
-export([run/0, run/1]).


run() ->
    NS = corba:resolve_initial_references("NameService"),
    run_1(NS).

run(HostRef) ->
    NS = corba:resolve_initial_references_remote("NameService", HostRef),
    run_1(NS).


run_1(NS) ->
    NC = lname_component:set_id(lname_component:create(), "StackFactory"),
    N = lname:insert_component(lname:create(), 1, NC),
    case catch 'CosNaming_NamingContext':resolve(NS, N) of
        {'EXCEPTION', E} ->
            io:format("The stack factory server is not registered~n",[]);
        SF ->
            %% Create the stack
            SS = 'StackModule_StackFactory':create_stack(SF),

            %% io:format("SS pid ~w~n",[iop_ior:get_key(SS)]),
            'StackModule_Stack':push(SS, 4),
            'StackModule_Stack':push(SS, 7),
            'StackModule_Stack':push(SS, 1),
            'StackModule_Stack':push(SS, 1),
            Res = 'StackModule_Stack':pop(SS),
            io:format("~w~n", [Res]),
            Res1 = 'StackModule_Stack':pop(SS),
            io:format("~w~n", [Res1]),
            Res2 = 'StackModule_Stack':pop(SS),
            io:format("~w~n", [Res2]),
            Res3 = 'StackModule_Stack':pop(SS),
            io:format("~w~n", [Res3]),

            %% Remove the stack
            'StackModule_StackFactory':destroy_stack(SF, SS)
            
    end.


9.1.5 Writing a client in Java

To write a Java client for Orber you must have another ORB that uses IIOP for client-server communication and supports a Java language mapping. It must also have support for IDL:CosNaming/NamingContext, we have tested with OrbixWeb. To support this, a Java package named Orber is included with our product. It contains just one class, InitialReference which can be used to get the initial reference to Orber's naming service. The Java client will then look like this:

package StackModule;

import CosNaming._NamingContextRef;
import CosNaming.Name;
import IE.Iona.Orbix2._CORBA;
import IE.Iona.Orbix2.CORBA.SystemException;
import IE.Iona.Orbix2.CORBA._ObjectRef;

public class StackClient 
{
  public static void main(String args[])
    {
      CORBA._InitialReferencesRef init;
      _NamingContextRef nsContext;
      Name name;
      _ObjectRef initRef, nsRef, objRef;
      _StackFactoryRef sfRef = null;
      _StackRef sRef = null;
      Orber.InitialReference ir = new Orber.InitialReference();

      int i;
      String srvHost = new String(args[0]);
      Integer srvPort = new Integer(args[1]);

      try
        {
          // For an explanation about initial reference handling see 
          // the "Interoperable Naming Service" specification.

          // Create Initial reference (objectkey "INIT").
          String s = ir.stringified_ior(srvHost, srvPort.intValue());

          initRef = _CORBA.Orbix.string_to_object(s);

          init = CORBA.InitialReferences._narrow(initRef);
          // Fetch name service reference.
          nsRef = init.get("NameService");

          nsContext = CosNaming.NamingContext._narrow(nsRef);

          // Create a name
          name = new Name(1);
          name.buffer[0] = new CosNaming.NameComponent("StackFactory", "");

          try
            {
              objRef = nsContext.resolve(name);
            }
          catch(IE.Iona.Orbix2.CORBA.UserException n)
            {
              System.out.println("Unexpected exception: " + n.toString());
              return;
            }       
          sfRef = StackFactory._narrow(objRef);
          
          sRef = sfRef.create_stack();

          sRef.push(4);
          sRef.push(7);
          sRef.push(1);
          sRef.push(1);
              
          try
            {
              System.out.println(sRef.pop());
              System.out.println(sRef.pop());
              System.out.println(sRef.pop());
              System.out.println(sRef.pop());
              // The following operation shall return an EmptyStack exception
              System.out.println(sRef.pop());
            }
          catch(EmptyStack es)
            {
              System.out.println("Empty stack");
            };

        sfRef.destroy_stack(sRef);

        }
      catch(SystemException se)
        {
          System.out.println("Unexpected exception: " + se.toString());
          return;
        }
      
    }
}

Note!

If an ORB supply CosNaming it is possible to use this package instead. We have tested with Sun Microsystems Java IDL (import org.omg.CosNaming.*;)

9.1.6 Building the example

To build the example for access from a Java client you need a Java enabled ORB. In the build log below OrbixWeb's IDL compiler was used.

fingolfin 127> erl 
Erlang (BEAM) emulator version 4.9
 
Eshell V4.9  (abort with ^G)
1> ic:gen(stack).
Erlang IDL compiler version 20
ok
2> make:all().
Recompile: oe_stack
Recompile: StackModule_StackFactory
Recompile: StackModule_Stack
Recompile: StackModule
Recompile: stack_client
Recompile: stack_factory
Recompile: StackModule_StackFactory_impl
Recompile: StackModule_Stack_impl
up_to_date
3> 
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
       (v)ersion (k)ill (D)b-tables (d)istribution
a

fingolfin 128> idl stack.idl
fingolfin 129> idl InitialReferences.idl 
fingolfin 130> idl <OTP_INSTALLATIONPATH>/lib/orber-<Orber Version>/COSS/
                   CosNaming/cos_naming.idl 
fingolfin 131> 
fingolfin 132> cd java_output/
fingolfin 133> javac *.java
fingolfin 134> cd CosNaming/
fingolfin 135> javac *.java
fingolfin 136> cd ../_NamingContext/
fingolfin 137> cd javac *.java../_NamingContext/
fingolfin 138> cd ../../CORBA/
fingolfin 139> javac *.java
fingolfin 140> cd ../StackModule/
fingolfin 141> javac *.java
fingolfin 142> cd ../..
fingolfin 143> javac *.java
fingolfin 144> cp StackClient.class java_output/StackModule/.

      

9.1.7 How to run everything

Below is a short transcript on how to run Orber. The commands for starting the new socket communication package will not be necessary when it is used as default in OTP R3A. In R2 it is only available unsupported, and without documentation but Orber uses this for better IIOP performance. An example .inetrc can also be found in Orber's example directory and is named inetrc (without the starting .).

fingolfin 143> erl 
Erlang (BEAM) emulator version 4.9
 
Eshell V4.9    (abort with ^G)
1> mnesia:create_schema([]).
ok
2> orber:install([]). 
ok
3> orber:start().             
ok
4> oe_stack:oe_register().     
ok
5> stack_factory:start().
ok
6> stack_client:run().
1
1
7
4
ok
7> 
      

Before testing the Java part of this example generate and compile Java classes for orber/examples/stack.idl, orber/examples/InitialReferences.idl and orber/COSS/CosNaming/cos_naming.idl as seen in the build example. We have tested with OrbixWeb.

To run the Java client use the following command (the second parameter is the port number for the bootstrap port):

fingolfin 38> java StackModule.StackClient fingolfin 4001
[New Connection (fingolfin,4001, null,null,pid=0) ]
[New Connection (fingolfin.du.etx.ericsson.se,4001, null,null,pid=0) ]
1
1
7
4
Empty stack
fingolfin 39> 
      

Copyright © 1991-1999 Ericsson Utvecklings AB