I have a C++ CORBA server which implements an interface throwing a user defined exception.
I am easily able to catch the specific exception when client and server are both implemented in C++ (tested using both TAO orb and omniORB).
But when I invoke the same method from Erlang (using orber), the exception appears as generic exception and not as specific user defined exception.
To test this I just used a simple IDL -
interface Messenger {
exception cirrus_error{
short error_code;
string error_desc;
};
boolean send_message(in string user_name,
in string subject,
inout string message) raises (cirrus_error);
};
If both server and client are in C++ - the exception I get is (for testing I coded it to always throw the user exception)
CORBA exception: cirrus_error (IDL:Messenger/cirrus_error:1.0)
But when invoked via Erlang - I get -
** exception throw: {'EXCEPTION',{'UNKNOWN',[],1330446337,'COMPLETED_MAYBE'}}
in function corba:raise/1
Do I need to do something special while stating Orber application to enable the correct behaviour?
Edit - This is how I call server from erlang -
On Erlang prompt, this is what I do -
1> orber:jump_start().
2> O = corba:string_to_object(IORStr).
3> 'Messenger':send_message(O, "s", "t", "f").
** exception throw: {'EXCEPTION',{'UNKNOWN',[],1330446337,'COMPLETED_MAYBE'}}
in function corba:raise/1
You need to register your IDL definitions into the orber interface repository (IFR) before invoking the method. If your IDL file is named messenger.idl
, for example, compiling it creates oe_messenger.erl
, which provides the oe_register/0
function. Calling it registers information about your user-defined exception into the IFR, which orber's CDR decoding uses to be able to properly decode any responses containing that exception:
1> orber:jump_start().
...
2> ic:gen(messenger).
Erlang IDL compiler version 4.4
ok
3> make:all().
Recompile: Messenger
Recompile: Messenger_cirrus_error
Recompile: oe_messenger
oe_messenger.erl:65: Warning: function oe_get_top_module/4 is unused
oe_messenger.erl:91: Warning: function oe_destroy_if_empty/2 is unused
up_to_date
4> oe_messenger:oe_register().
ok
5> M = corba:string_to_object(IORStr).
...
6> 'Messenger':send_message(M, "a", "b", "c").
** exception throw: {'EXCEPTION',{'Messenger_cirrus_error',"IDL:Messenger/cirrus_error:1.0",
1234,"yep, an error"}}
in function corba:raise/1 (corba.erl, line 646)
Update: The reason this extra IFR registration step is needed in orber, while rarely if ever being necessary in C++ ORBs, is due to some flexibility in the CORBA specification and also to C++ ORB development traditions. The original CORBA specification was in part a compromise between static and dynamic language camps. The dynamic camp insisted on the IFR being in the spec as they needed it for retrieving type information at runtime (and clearly they got their wish, since it's always been a part of CORBA), but the static camp assumed the IFR was unnecessary since all necessary type information could be encoded in C/C++ code generated from IDL definitions. The C++ ORB development community has traditionally followed the code generation approach and treated the IFR as an optional runtime component, and the C++ ORBs used in this question retrieve information about the user-defined cirrus_error
exception from generated stubs and skeletons. But ORBs written in other languages, such as Smalltalk and Erlang, have chosen to use the IFR as a normal component of the ORB runtime, and so they require registration of type information into the IFR in order for it to be available to the ORB runtime. It would definitely be possible in Erlang, though, to generate information about user-defined exceptions into stubs/skeletons and have the runtime retrieve it from there.