3 Orber Examples
3.1 A tutorial on how to ceate a simple service
3.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 a 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); }; }; #endif3.1.2 Generating erlang code
Run the IDL compiler on this file
1> ic:gen("stack").and it will among other files produce a stack API module called
StackModule_Stack.erl
.3.1.3 Implementation of interface
After generating the API stubs and the server skeletons it's 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
.%% ``The contents of this file are subject to the Erlang Public License, %% Version 1.0, (the "License"); you may not use this file except in %% compliance with the License. You may obtain a copy of the License at %% http://www.erlang.org/EPL1_0.txt %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% The Original Code is Erlang-4.7.3, December, 1998. %% %% The Initial Developer of the Original Code is Ericsson Telecom %% AB. Portions created by Ericsson are Copyright (C), 1998, Ericsson %% Telecom AB. All Rights Reserved. %% %% Contributor(s): ______________________________________.'' %% -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
.%% ``The contents of this file are subject to the Erlang Public License, %% Version 1.0, (the "License"); you may not use this file except in %% compliance with the License. You may obtain a copy of the License at %% http://www.erlang.org/EPL1_0.txt %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% The Original Code is Erlang-4.7.3, December, 1998. %% %% The Initial Developer of the Original Code is Ericsson Telecom %% AB. Portions created by Ericsson are Copyright (C), 1998, Ericsson %% Telecom AB. All Rights Reserved. %% %% Contributor(s): ______________________________________.'' %% -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 also is registered in the name service.%% ``The contents of this file are subject to the Erlang Public License, %% Version 1.0, (the "License"); you may not use this file except in %% compliance with the License. You may obtain a copy of the License at %% http://www.erlang.org/EPL1_0.txt %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% The Original Code is Erlang-4.7.3, December, 1998. %% %% The Initial Developer of the Original Code is Ericsson Telecom %% AB. Portions created by Ericsson are Copyright (C), 1998, Ericsson %% Telecom AB. All Rights Reserved. %% %% Contributor(s): ______________________________________.'' %% -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).3.1.4 Writing a client in erlang
At last we will write a client to access our service.
%% ``The contents of this file are subject to the Erlang Public License, %% Version 1.0, (the "License"); you may not use this file except in %% compliance with the License. You may obtain a copy of the License at %% http://www.erlang.org/EPL1_0.txt %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% The Original Code is Erlang-4.7.3, December, 1998. %% %% The Initial Developer of the Original Code is Ericsson Telecom %% AB. Portions created by Ericsson are Copyright (C), 1998, Ericsson %% Telecom AB. All Rights Reserved. %% %% Contributor(s): ______________________________________.'' %% -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.3.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 for
IDL:CosNaming/NamingContext
, we have tested with OrbixWeb. To support this a java package calledOrber
is a delivered with our product. It contains just one class,InitialReference
which can be used in to get the initial referens to Orbers 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[]) { Orber._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 = Orber.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; } } }3.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 is used.
fingolfin 127> erl Erlang (JAM) emulator version 4.6 Eshell V4.5.3 (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 ../../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/.3.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's used as default in OTP R3A, in R2 it's only available not supported and documented but orber uses it to get better performance on IIOP. An example
.inetrc
can be found in orbers example directory but is then calledinetrc
(without the starting .).fingolfin 143> erl Erlang (JAM) emulator version 4.6 Eshell V4.5.3 (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 one have to generate/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 just 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>