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.