Using ACE try Macros to Enhance CORBA Portability

CORBA Environment arguments provide a way to handle exceptions when native c++ exception handling is unavailable or undesirable. However, writing portable code using both native C++ exception handling and CORBA::Environment objects is very hard. If you plan to write portable code that must run on platforms that do not have native C++ exceptions, therefore, we recommend you use the ACE exception macros. This document explains how these macros can help alleviate much of the accidental complexity. However, keep in mind macros cannot solve all problems perfectly.

Before reading the rest of this document, we recommend you check out pages 307 through to 322 in the book, Advanced Corba Programming with C++ by Michi Henning & Steve Vinoski. Likewise, we recommend that you read the Error Handling chapter from the TAO Developer's Guide.


Table of Contents


ACE Try Macros in a Nutshell

This section explains some simple rules of writing programs for platforms with and without native exception support using ACE's try macros.

  1. ACE try macros are modelled like C++ language exceptions and can be used like them, but with a small difference. These macros rely on the CORBA::Environment variable to handle exceptions on platforms that do not support exception handling. (Please note that native exceptions can be turned on or off at COMPILE time as an option to your make) The exception macros have been modelled with some extra rules to ensure it works even on platforms without native exception support. See some quick examples on how to use ACE try macros.

  2. Name of CORBA::Environment variable
    A function that may throw a CORBA::Exception needs a CORBA::Environment variable to pass up exceptions (to throw in the C++ sense) and to gather (catch () in the C++ sense) exceptions from functions it called. By default, ACE try macros assumes that the variable is named ACE_TRY_ENV. ACE_TRY_ENV itself is also a macro which can be redefined.

    You can redefine the name of the variable to something else to avoid name clashing. Alternatively, there's another macro (ACE_ADOPT_CORBA_ENV) that allow you to use another variable name as the default CORBA::Environment within a function.

  3. Definition of the CORBA::Environment variable
    If you are using TAO for writing application programs and you are interested in using exceptions (which is a pretty neat way to go about), the environmnet variable can be brought in to your scope by the adding a statement ACE_DECLARE_NEW_CORBA_ENV; You can then invoke the methods on the servant from the client side as

          object_reference->func_name (x, y, ACE_TRY_ENV);
          
    Even if you are interested in making calls within the client side, you can define your method like this
          int AN_OBJ::foobar (int a, int b, CORBA_Environment &ACE_TRY_ENV);
          
  4. Throwing exceptions:
    Use ACE_THROW and ACE_THROW_RETURN to throw exceptions. They should never be used within a try block; please use ACE_TRY_THROW instead.

  5. Propagating exceptions:
    To simulate native exceptions on platforms without native exception handling, every function call that may throw exceptions must be followed by ACE_CHECK or ACE_CHECK_RETURN.

    Exception-throwing functions include the following categories:

    1. Any function that takes a CORBA_Environment argument.

    2. ACE_NEW_THROW_EX. Notice that you should not use ACE_NEW_THROW, ACE_NEW_THROW_RETURN, ACE_NEW_TRY_THROW anymore because they don't work right with ACE try macros. Instead, use ACE_NEW_THROW with appropriate ACE_CHECK* macros.

    3. ACE_GUARD_THROW_EX, ACE_READ_GURAD_THROW_EX, and ACE_WRITE_THROW_EX.

    4. ACE_TRY blocks. Follow every ACE_ENDTRY with appropriate ACE_CHECK* macros.

    You should pass ACE_TRY_ENV to these functions.

    Be very careful not to combine exception throwing functions in one statement like this:

              x = obj1->callme (ACE_TRY_ENV) + obj2->dare_me (ACE_TRY_ENV);
              ACE_CHECK;
          

    This example may work differently when native exception handling is enabled/disabled.

  6. Catching exceptions:
    Use ACE_TRY to catch exceptions if there's an ACE_TRY_ENV available. Otherwise, you should use ACE_DECLARE_NEW_CORBA_ENV to create one at proper scope. The use of ACE_TRY_NEW_ENV is considered depricated because it can't deal with the case when you have multiple TRY blocks in the scope of ACE_TRY_NEW_ENV. If there are more than one try blocks in a function, use ACE_TRY_EX for all subsequence try blocks to avoid name clashing of labels.

  7. Printing out exceptions. Use ACE_PRINT_EXCEPTION (EX,INFO) to print out an exception. The macro takes two arguments, a reference to an exception (EX) and a char * string (INFO) which provides more information on the exception. Since there's no portable way to print out exceptions, you can redefine ACE_PRINT_EXCEPTION to fit your need (or define it to null.) You should always print out the exception itself, not the CORBA_Environment that carries the exception.


Examples

Refer to $ACE_ROOT/ace/CORBA_macros.h for complete definitions of macros discussed here.

General Guidelines for Exception Handling


Transition from TAO try macros to ACE try macros

This list tries to give a comprehensive list of mapping between TAO try macros and ACE try macros. It's sole purpose is to provide hints in the converting the use of TAO try macros to ACE try macros and is by no mean complete.
  1. Rename all CORBA_Environment variables to ACE_TRY_ENV.

  2. Replace TAO_TRY TAO_TRY_VAR with ACE_TRY. Added ACE_DECLARE_NEW_CORBA_ENV if necessary.

  3. Replace TAO_TRY_EX TAO_TRY_VAR_EX with ACE_TRY_EX.

  4. Replace TAO_CHECK_RETURN and TAO_CHECK_RETURN_VOID with ACE_CHECK_RETURN and ACE_CHECK. These macros are used outside of TRY/CATCH blocks.

  5. Replace TAO_THROW, TAO_THROW_ENV, TAO_THROW_RETURN, TAO_THROW_ENV_RETURN with ACE_THROW and ACE_THROW_RETURN.

  6. Replace ACE_NEW_THROW, ACE_NEW_THROW_RETURN, ACE_TRY_NEW_THROW with ACE_NEW_THROW_EX and appropriate ACE_CHECK* macros. aformention

  7. Replace TAO_CHECK_ENV and TAO_CHECK_ENV_EX with ACE_TRY_CHECK and ACE_TRY_CHECK_EX.

  8. Replace TAO_TRY_THOW and TAO_TRY_THROW_EX with ACE_TRY_THROW and ACE_TRY_THROW_EX. Notice that you can also use ACE_TRY_THROW* within CATCH blocks.

  9. Replace TAO_RETHROW, TAO_RETHROW_RETURN, TAO_RETHROW_RETURN_VOID with ACE_RETHROW.

  10. Replace TAO_CATCH, TAO_CATCHANY, and TAO_CATCHALL with ACE_CATCH, ACE_CATCHANY and ACE_CATCHALL respectively.

  11. Replace TAO_ENDTRY with ACE_ENDTRY followed by an appropriate CHECK macro (ACE_CHECK, ACE_CHECK_RETURN, ACE_TRY_CHECK, or ACE_TRY_CHECK_EX.)


Caveats

As we already mentioned no set of macros can cover all cases and preserve the semantics between native C++ exceptions and the CORBA::Environment based mapping. Some of the problems that our macros are described below:


Back to the ACE documentation page.
Back to ACE Documentation Home.