Until now, in all the code fragments I showed, there were some CORBA_Environment variables lying around with some CORBA_exception_init calls... Let's see what these variables are about.
This is no news: there is no support in C for exception handling. One has to create complete systems to support signals and the like (look at GTK+ signal system). CORBA has such a system. Its use is really simple. Each method has a CORBA_Environment * parameter which is used to store the exceptions' data. If, during a method execution an exception is raised, the fact that the exception occurred and the exception data is stored in this structure. Here it is:
typedef struct CORBA_Environment {
CORBA_exception_type _major;
/* .... */
} CORBA_Environment; |
The _major field indicates whether an exception was raised or not during method invocation. It may have 3 values: CORBA_NO_EXCEPTION, CORBA_USER_EXCEPTION or CORBA_SYSTEM_EXCEPTION. Their signification is rather clear. Typically, good code should test after each method invocation if an exception occurred with:
CORBA_Environment ev;
if (ev->_major == CORBA_NO_EXCEPTION)
/* goooood :) */
else
/* baaaaad :( */
|
We have also a nice set of functions to operate on these exceptions. We can throw exceptions with CORBA_exception_set. CORBA_exception_id returns a string to clearly identify the exception. CORBA_exception_value returns a pointer to the exception structure and CORBA_exception_free is used to reinitialize the ev structure after an exception. Here are their signatures:
extern CORBA_char *CORBA_exception_id (CORBA_Environment *ev);
extern void *CORBA_exception_value (CORBA_Environment *ev);
extern void CORBA_exception_free (CORBA_Environment *ev);
extern void CORBA_exception_set (CORBA_Environment *ev,
CORBA_exception_type major,
CORBA_char *exception_id,
void *parameters);
|
And here is some sample code which uses the 3 first functions:
// here is the interface we wish to access
module FruitsBasket {
interface Apple {
exception eaten {
string<40> why;
};
void EatMe () raises (eaten);
};
}; |
#include <orb/orbit.h>
/* here, code to access the interface */
int main (int argc, char *argv)
{
CORBA_Object obj;
CORBA_Environment ev;
CORBA_ORB orb;
CORBA_exception_init (&ev);
orb = CORBA_ORB_init (&ev);
if (ev->_major != CORBA_NO_EXCEPTION) {
fprintf (stderr,
"Error: unable to initialize the ORB: %s\n",
CORBA_exception_id (&ev));
CORBA_exception_free (&ev);
exit (1);
}
/* code to link to an Apple object */
/* note that a switch /case statement would
* have been cleaner but i am sick of all this code ...
*/
FruitsBasket_Apple_EatMe (orb, &ev);
if (ev->_major != CORBA_NO_EXCEPTION) {
if (ev->_major == CORBA_USER_EXCEPTION) {
CORBA_char *buffer;
buffer = CORBA_exception_id (&ev);
if (strcmp (buffer, "FruitsBasket_Apple_eaten")) {
fprintf (stderr,
"user exception: Apple already eaten: %s\n",
(CORBA_exception_value (&ev))->why);
exit (1);
} else {
fprintf (stderr,
"unknown exception raised!! Error!!\n");
exit (2);
}
} else {
fprintf (stderr,
"System exception: %s\n",
CORBA_exception_id (&ev));
exit (1);
}
}
return 0;
} |
Finally, to throw exceptions from your code, you must pass to CORBA_exception_set the correct parameters: the CORBA_exception_type must be either CORBA_USER_EXCEPTION or CORBA_SYSTEM_EXCEPTION. The CORBA_char must be the exception name #defined in the headers and the void * a pointer to an exception structure where fields are filled and where memory is allocated with __alloc(). Here is a small example using the same Apple object:
/* here, we are in the server and we wish to throw
* the "eaten" exception with the correct "why"
* reason.
* note that our Apple Object exception will map
* to the following C structure:
typedef struct FruitsBasket_Apple_eaten {
CORBA_char why[40];
/* ... plus miscellaneous implementation specific members */
} FruitsBasket_Apple_eaten;
#define ex_FruitsBasket_Apple_eaten <identifier>
FruitsBasket_Apple_eaten *FruitsBasket_Apple_eatme__alloc ()
*/
FruitsBasket_Apple_eaten *exception;
exception = FruitsBasket_Apple_eaten__alloc ();
strcpy (exception->why, "mmmm...");
CORBA_exception_set (&ev, CORBA_USER_EXCEPTION,
ex_FruitsBasket_Apple_eaten,
(void *) exception);
|
Now that exception handling has no secret for you anymore, you may look at this hello world code easily. We will use the following interface definition:
interface Echo {
void echo (in string<40> str);
};
|
And here is the code:
main ()
{
CORBA_ORB orb;
CORBA_Environment ev;
CORBA_Object obj;
FILE *file;
/* rather long string: should be enough for all our needs :) */
char buffer[10000];
char *ior;
CORBA_exception_init(&ev);
orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev);
if (ev->_major != CORBA_NO_EXCEPTION) {
fprintf (stderr,
"Error: exception during ORB init: %s\n",
CORBA_exception_id(&ev));
exit (1);
}
if (!file = fopen ("object.ior", "r")) {
fprintf (stderr,
"error: could not open serializing file\n");
exit (2);
}
fgets (buffer, 10000, file);
ior = g_strdup (buffer); /* gets the raw string */
/* now, we have it finally !! */
obj = CORBA_ORB_string_to_object (orb, ior, &ev);
if (ev->_major != CORBA_NO_EXCEPTION) {
fprintf (stderr,
"Error: could not get object reference: %s\n",
CORBA_exception_id(&ev));
exit (3);
}
fclose (file);
Echo_echo (obj, ,&ev);
if (ev->_major != CORBA_NO_EXCEPTION)
fprintf (stderr,
"Error: could not get method: %s\n",
CORBA_exception_id(&ev));
CORBA_exception_free(&ev);
/* now, we could call many other objects... */
} |
In fact, this code is nothing but code we already seen, with exception handling code added.