9 Orber Examples
9.1 A Tutorial on How to Create a SimpleSservice
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); }; }; #endif9.1.2 Generating Erlang Code
Run the IDL compiler on this file by calling the
ic:gen/1
function1> 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 calledStackModule_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 caseStackModule_Stack_impl.erl
.%% StackModule_Stack_impl example file. -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
.%% StackModule_StackFactory_impl example file. -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 modulestack_factory.erl
where the started service is also registered in the name service.%% stack_factory example file. -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.
%% stack_client example file. -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
orIDL:CosNaming/NamingContextExt
. If the client ORB support Interoperable Naming Service the Java Client can look like:/* * Stack example using Interoperable Naming Service. */ package StackModule; import org.omg.CORBA.*; import org.omg.CORBA.SystemException; import org.omg.CORBA.ORB.*; public class StackClient { public static void main(String args[]) { org.omg.CORBA.Object objRef; StackFactory sfRef = null; Stack sRef = null; // The argument can look like // "corbaname::host:4001/#StackFactory" String corbaName = new String(args[0]); try{ ORB orb = ORB.init(args, null); objRef = orb.string_to_object(corbaName); sfRef = StackFactoryHelper.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; } } }If the Client ORB does not support Interoperable Naming Service, 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:/* * Stack example. */ package StackModule; import org.omg.CosNaming.*; import org.omg.CORBA.*; import org.omg.CORBA.SystemException; import org.omg.CORBA.ORB.*; public class StackClient { public static void main(String args[]) { NamingContext nsContext; org.omg.CORBA.Object objRef; StackFactory sfRef = null; Stack sRef = null; org.omg.CORBA.Object nsRef, initRef; NameComponent[] name = new NameComponent[1]; Orber.InitialReference ir = new Orber.InitialReference(); Orber.InitialReferences init; String srvHost = new String(args[0]); Integer srvPort = new Integer(args[1]); try { ORB orb = ORB.init(args, null); // Create Initial reference (objectkey "INIT"). String s = ir.stringified_ior(srvHost, srvPort.intValue()); initRef = orb.string_to_object(s); init = Orber.InitialReferencesHelper.narrow(initRef); // Fetch name service reference. nsRef = init.get("NameService"); nsContext = NamingContextHelper.narrow(nsRef); // Create a name name[0] = new NameComponent("StackFactory", ""); try { objRef = nsContext.resolve(name); } catch(Exception n) { System.out.println("Unexpected exception: " + n.toString()); return; } sfRef = StackFactoryHelper.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; } } }
If an ORB does not support CosNaming at all the
cos_naming.idl
file must be compiled and imported.9.1.6 Building the Example
To build the example for access from a Java client you need a Java enabled ORB. The build log below, using OrbixWeb's IDL compiler, describes the scenario where the Client ORB does not support Naming Service.
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 fingolfin 138> cd ../../Orber/ 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 namedinetrc
(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
andorber/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>9.2 A Tutorial on How to Start Orber as Lightweight
9.2.1 Preparation
When starting Erlang the configuration parameter
lightweight
must be used. The value is set to a list of remote modifiers, equal to theorber:resolve_initial_references_remote/2
argument, i.e., "iiop://host:port". On these given nodes, all necessaryoe_X:oe_register()
calls must be done before running a Orber lightweight.Lightweight Orber do not allow us to:
- Create objects locally
- Accept incoming requests
- Access local NameService
- Register data in the IFR
With lightweight Orber we do not:
- Start Mnesia
- Run
orber:install/1
To be able to start objects we must supply a factory on a non-lightweight node(s) which can start necessary objects. One way to accomplish this is:
smaug 125> erl -orber domain "ORBER_MAIN" Erlang (BEAM) emulator version 4.9 Eshell V4.9 (abort with ^G) 1> mnesia:create_schema([]). 2> orber:install([]). 3> orber:start(). 4> oe_MyFactory:oe_register(). 5> oe_MyObjects:oe_register(). %% Do this for all objects necessary. 6> Factory=MyFactory_Creater:oe_create(). 7> NS=orber:resolve_initial_references("NameService"). 8> NC=lname_component:set_id(lname_component:create(), "myFactory"). 9> N =lname:insert_component(lname:create(), 1, NC). 10> 'CosNaming_NamingContext':bind(NS, N, Factory)).Now we have a factory we can access from, hence, we can now start a lightweight Orber:
fingolfin 14> erl -orber lightweight [\"iiop://host1:port\", \"iiop://host2:port\"] -orber domain "ORBER_LIGHT" Erlang (BEAM) emulator version 4.9 Eshell V4.9 (abort with ^G) 1> orber:start_lightweight(). 2> NS=orber:resolve_initial_references_remote("NameService", ["iiop://hostX:port"]). 3> NC=lname_component:set_id(lname_component:create(), "myFactory"). 4> N =lname:insert_component(lname:create(), 1, NC). 5> Factory='CosNaming_NamingContext':resolve(NS, N)). 6> Obj=MyFactory_Creater:MyObject(Factory, Args). 7> MyObject:myFunction(Obj,Args2).It is not necessary to start both Orber types using the configuration parameter
domain
, but at least one of them.