Delphi Clinic C++Builder Gate Training & Consultancy Delphi Notes Weblog Dr.Bob's Webshop
Dr.Bob's Kylix Kicks
 Borland C++Builder 4 and CORBA Exceptions
See Also: C++Builder Papers and Columns

Introduction
After having written two articles about CORBA and C++Builder, now it is the time to delve into some subjects you might be curious about. In this article, I will give you an overview of CORBA exceptions. In the next few articles I will discuss callbacks, in-process client-server and we will do some pattern mining in the generated stubs.

Discovering the model
Exceptions closely follow the C++ model. In fact, the only thing you have to do to handle CORBA exceptions is to wrap your server invocation in a try-catch block, and then catch the nested class CORBA::Exception. Then again, you also can inherit from CORBA::Exception in your IDL specification. You can add a 'raises'-clause to an IDL method specification to specify that the method can raise that kind of exception. Let's elaborate on this subject. CORBA has two types of exceptions, system exceptions and user exceptions. The first type is of class CORBA::SystemException, and is in turn derived from CORBA::Exception. The other kind of exception is a user exception. You can specify those in IDL. Let's try something.

  // IDL
  module ThrowSome
  {
    exception Xuser {};

    interface GoGetIt
    {
      void ThrowIt();
    }
  };
And of course the program to exercise it:
  // C++
  int main(int, char*[])
  {
    try
    {
      // Initialize the ORB and BOA
      CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
      CORBA::BOA_var boa = orb->BOA_init(argc, argv);

      ThrowSome::GoGetIt_var ggi = ThrowSome::GoGetIt::_bind();
      try
      {
        ggi->ThrowIt();
      }
      catch (CORBA::Exception& e)
      {
        cout << "Caught as CORBA::Exception: " << e << endl;
      }

      try
      {
        ggi->ThrowIt();
      }
      catch (CORBA::UserException& e)
      {
        cout << "Caught as CORBA::UserException: " << e << endl;
      }

      try
      {
        ggi->ThrowIt();
      }
      catch (ThrowSome::XUser& e)
      {
        cout << "Caught as ThrowSome::XUser: " << e << endl;
      }

      try
      {
        ggi->ThrowIt();
      }
      catch (CORBA::SystemException& e)
      {
        cout << "Caught as CORBA::SystemException: " << e << endl;
      }
    }
    catch (const CORBA::Exception& e)
    {
      cerr << "Caught CORBA::Exception in outer try/catch block: " << e << endl;
      return(1);
    }
  }
The result of this little program looks like this:
  Caught as CORBA::Exception: EXCEPTION ThrowSome::XUser {
  }

  Caught as CORBA::UserException: EXCEPTION ThrowSome::XUser {
  }

  Caught as ThrowSome::XUser: EXCEPTION ThrowSome::XUser {
  }

  Caught CORBA::Exception in outer try/catch block: EXCEPTION ThrowSome::XUser {
  }
What is the lesson learnt here? Apparently, the inheritance is that user defined exceptions inherit from CORBA::UserException inherit from CORBA::Exception and CORBA::SystemException inherits from CORBA::Exception.

Narrowing
In the previous paragraph you could see that I just used the normal style of exception handling to catch the exception thrown. No big deal. CORBA however has another means of discovering what kind of exception is thrown, which is called narrowing. What it bears down to is that you can determine at runtime what the real type of the occurred exception is. Correct, that's downcasting, and from the looks of it it is a dynamic_cast operation. You can do so by calling the _narrow method on an exception. Here is an example of using the narrowing method:

  // C++
  catch (CORBA::Exception& e)
  {
    CORBA::SystemException_var se = CORBA::SystemException::_narrow(&e);
    if (se != 0)
    {
      cout << "Caught a system exception!" << endl;
    }
    else
    {
      cout << "This is not a system exception!" << endl;
    }
  }

Aside: widening
Now for the bonus question: "Hey, if I can narrow to a more derived type, can I do the reverse also?" Correct again. And you're right if you conclude that that method has the name _widen. For example, every CORBA object is ultimately derived from CORBA::Object. So, if we have an object of a particular type, we can always widen it to CORBA::Object:

  // C++
  void MakeWider(ParticularObject& object)
  {
    CORBA::Object_var co = CORBA::Object::_widen(object);
    ...
  }

Basic exception functionality
The base CORBA::Exception class has two members that you can use to retrieve information about them. Those methods are _name() and _repository_id(). The first returns the name of the exception, the second in fact does the same but in another format.

System exception functionality
The CORBA::SystemException does have a number of additional methods. Those are _minor() and _completed(). Both come in a getter and a setter form, i.e. if you want to know the value for the minor error code for example you call CORBA::ULong _minor() const, and if you want to set it you must call void _minor(CORBA::ULong). The same holds for _completed(). Note the enumeration constant you can use with these two functions.

Extending user exceptions
Of course you may add functionality to a user-defined exception. Just add the methods and data you want to transport wrapped in your exception type:

  // IDL
  exception FooBar
  {
    string theFoo;
    long theBar;
  };

Conclusion
As we have seen, working with CORBA exceptions is very close to working with C++ exceptions. In fact we can just use the native model of C++. Besides that, CORBA also gives you the narrowing model to determine the proper type of an exception.

I would like to conclude with a saying I more often use, and that is 'use the source Luke'. As always, rummaging around in the headers and IDL files that come with Visibroker (or another CORBA implementation) is very educating. Enjoy!


This webpage © 2000-2017 by Bob Swart (aka Dr.Bob - www.drbob42.com). All Rights Reserved.