OpenOfficeComparison of the UNO - CORBA object models


Overview

This paper provides a comparison between the UNO and the CORBA object model. It describes advantages and disadvantages of both models; clarifying, why we developed UNO and didn't use CORBA directly.

Differences between UNO and CORBA

The following table shows the differences between UNO and CORBA.

 
UNO
CORBA
mapping possible
multiple inheritance of interfaces
no
yes
yes
inheritance of structures
yes
no
yes
inheritance of exceptions
yes
no
yes
mandatory base interface for all interfaces
yes
no
yes
mandatory base exception for all exceptions
yes
no
yes
context for methods
no
yes
no
char
no
yes
yes
8 bit string
no
yes
yes
union
no
yes
yes
array
no
yes
yes
assigned values for enum
yes
no
yes
metatype 'type'
yes
no
yes
object identity
yes
no
no
life time mechanism
yes
no
no
succession of one-way calls
yes
no
no
in process communication
yes
no
no
thread identity
yes
no
no
customized calls
no
yes
yes
less code generation
yes
no
no

 


  • multiple inheritance of interfaces
    CORBA supports multiple inheritance of interfaces while UNO supports only single inheritance of interfaces.
    Mapping: We could generate an additional interface with all methods and attributes of the inherited interfaces which must be implemented, in addition to the other interfaces.
  • inheritance of structures
    CORBA doesn't support inheritance for structures. UNO supports inheritance for structures, and it makes sense. You could specify general types and more detailed subtypes.
    Mapping: We generate a struct with all members, plus all members of the inherited structs.
  • inheritance of exceptions
    CORBA doesn't support inheritance for exceptions, but UNO does. Inheritance of exceptions allows the specification of a complex exception concept. It is possible to make finely-grained concepts using the detailed exception in the layers where they are useful, and the base exception in higher levels. The UNO error handling, based on exceptions and inheritance of exceptions, makes it possible to specify 'error classes' with a base exception and more detailed errors of the same 'error class', which inherit from this base exception. On higher level api's, it is enough to declare the base exception to specify the 'error class' and it will be possible to support all errors of this 'error class'.
    Mapping: We generate an exception with all members plus all members of the inherited exceptions. the same solution as for structs.
  • mandatory base interface for all interfaces
    UNO specifies a mandatory base interface for all interfaces. This interface provides acquire and release functions for ref counting. The minimum life time of an object is managed with ref counting.
    mandatory base exception for all exceptions
    UNO specifies a mandatory base exception for all exceptions. This base exception contains a string member 'Message', which should describe in a human readable format, the reason for the exception. The base exception also makes it possible to filter out all UNO exceptions.
  • context for methods
    CORBA supports a request context. This context consists of a name value pair which is specified in IDL for methods. The context could be used for describing the current state of the caller object. A request context provides additional, operation-specific information that may affect the performance of a request.
  • char
    UNO doesn't support 8 bit characters. In UNO 'char' represents a 16 bit unicode character.
    Mapping: To support 8 bit characters, it seems possible that we could expand the TypeClass enum to support 8 bit characters and strings. The internal representation doesn't change anything; only for mapping the TypeClass will it be relevant.
  • 8 bit string
    UNO doesn't support 8 bit strings. In UNO, 'string' represents a 16 bit unicode string.
    Mapping: The same possibilities as for 'char'
  • union
    UNO doesn't support unions at the moment, but it is planned for the future.
  • array
    UNO doesn't support arrays at the moment, but it is, also, planned for the future.
  • assigned values for enum
    UNO supports the assignment of values for enum values in IDL. This means that it is possible, in target languages which support this feature (e.g., C/C++), to use these values directly to specify or operate with the desired enum value.
    Mapping: Using the names of the values, and if the values are needed on UNO side, we start with 0 and count by 1. On the CORBA side we convert the value to the valuename.
  • metatype 'type'
    UNO supports an IDL type 'type' which is used to transport type information. 'type' consists of a typename and a typeclass which specify the transported type. It is similar to the CORBA TypeCode interface, but it is a basetype of the UNO runtime and not an interface, as in CORBA. TypeCode is specified in CORBA IDL, but it isn't a real interface. In fact, it is a pseudo-object and would be marshaled especially.
    Mapping: It seems that it would be possible to map the UNO 'type' with the CORBA 'TypeCode'.
  • object identity
    UNO supports object identity. This means, if you got an interface, referenced twice over two different ways, and the equals operator returns true, then the interfaces refer to the same object -- The objects are equal. If the CORBA method 'is_equivalent' returns true then the object references refer to the same object. But if the method returns false, it means that the object references are different; they could refer to the same object and so they should be equal, but 'is_equivalent' returned false. This is very helpful for managing object references in containers or something else.
  • life time mechanism
    UNO supports a life time mechanism with the acquire and release functions of the mandatory base interface 'XInterface'. Acquire increases the reference count of an object and release decreases the reference count. If the reference count drops to zero the object may be destroyed. It is not assured, but the object could no longer be used, e.g., in C++ the object will normally be destroyed, while in Java the garbage collector will destroy the object, maybe later. In CORBA, it is normally impossible to say something about the lifetime of an object.
  • succession of one-way calls
    UNO guarantees that one-way calls, on the server side, are worked out in the same order, as they have been called, on the client side.
  • in process communication
    UNO supports fast in-process communication. If there are objects in the same process and implemented with the same language (e.g., C++), calls between these objects are the same as pure virtual function calls. There is no overhead caused by UNO.
  • thread identity
    UNO supports thread identity. Example: object A in thread 1 in process 1, calls object B in thread 1 in process 2. If now object B from thread 1 in process 2, calls object A in process 1, the call will be executed in the same thread 1 in process 1. In CORBA, it is possible that the second call could be executed in a new thread 2 in process 1. This could be a problem if there is a mutex used, or something similar, to be thread safe. If the call were executed in a second thread, it could result in a deadlock.
  • customized calls
    Customized call means that it should be possible to send a call but not wait on the reply; furthermore, the reply could be requested at an arbitrary, later time. In CORBA, this kind of call could be done by the dynamic invocation interface. This feature is very nice because it is possible to make many synchronous calls, one after another, and call later for the reply, so the latency of the calls could significantly reduced.
  • less code generation
    UNO generates only declaration code for IDL types, that means, for example, in C++ abstract classes for interfaces, C++ struct definitions for IDL structs, and so on. But UNO doesn't generate any marshaling code, it generates only a 'getCppuType' function which provides complete type information for the IDL type. CORBA generates much more code. It generates pure type definitions as in UNO, and furthermore, it generates marshaling code: special code for the use in anys and skeleton code for the server side.

    Example:

    UNO

    account.hdl:
    #ifndef _XACCOUNT_HDL_
    #define _XACCOUNT_HDL_
    
    #ifndef _CPPU_MACROS_HXX_
    #include <cppu/macros.hxx>
    #endif
    #ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
    #include <com/sun/star/uno/Reference.h>
    #endif
    
    #ifndef _COM_SUN_STAR_UNO_RUNTIMEEXCEPTION_HDL_
    #include <com/sun/star/uno/RuntimeException.hdl>
    #endif
    #ifndef _COM_SUN_STAR_UNO_TYPECLASS_HDL_
    #include <com/sun/star/uno/TypeClass.hdl>
    #endif
    #ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
    #include <com/sun/star/uno/Reference.h>
    #endif
    #ifndef _COM_SUN_STAR_UNO_XINTERFACE_HDL_
    #include <com/sun/star/uno/XInterface.hdl>
    #endif
    
    
    class XAccount : public ::com::sun::star::uno::XInterface
    {
    public:
    
        // Methods
        virtual void SAL_CALL deposit( sal_uInt32 amount )
        	throw(::com::sun::star::uno::RuntimeException) = 0;
        virtual void SAL_CALL withdraw( sal_uInt32 amount )
        	throw(::com::sun::star::uno::RuntimeException) = 0;
        virtual sal_Int32 SAL_CALL balance(  )
        	throw(::com::sun::star::uno::RuntimeException) = 0;
    };
    
    
    namespace com { namespace sun { namespace star { namespace uno {
    class Type;
    } } } }
    
    inline const ::com::sun::star::uno::Type& SAL_CALL
    	getCppuType( const ::com::sun::star::uno::Reference< XAccount >* );
    
    #endif // _XACCOUNT_HDL_
    		  

    account.hpp:
    #ifndef _XACCOUNT_HPP_
    #define _XACCOUNT_HPP_
    
    #ifndef _XACCOUNT_HDL_
    #include <XAccount.hdl>
    #endif
    
    #ifndef _OSL_MUTEX_HXX_
    #include <osl/mutex.hxx>
    #endif
    
    #ifndef _COM_SUN_STAR_UNO_TYPE_HXX_
    #include <com/sun/star/uno/Type.hxx>
    #endif
    #ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
    #include <com/sun/star/uno/Reference.hxx>
    #endif
    
    #ifndef _COM_SUN_STAR_UNO_RUNTIMEEXCEPTION_HPP_
    #include <com/sun/star/uno/RuntimeException.hpp>
    #endif
    #ifndef _COM_SUN_STAR_UNO_TYPECLASS_HPP_
    #include <com/sun/star/uno/TypeClass.hpp>
    #endif
    #ifndef _COM_SUN_STAR_UNO_XINTERFACE_HPP_
    #include <com/sun/star/uno/XInterface.hpp>
    #endif
    
    #if ((defined(__SUNPRO_CC) && (__SUNPRO_CC == 0x500)) || (defined(__GNUC__) && defined(__APPLE__)))
    static typelib_TypeDescriptionReference * s_pType_XAccount = 0;
    #endif
    
    inline const ::com::sun::star::uno::Type& SAL_CALL
    getCppuType( const ::com::sun::star::uno::Reference< XAccount >* )
    {
    #if ! ((defined(__SUNPRO_CC) && (__SUNPRO_CC == 0x500)) || (defined(__GNUC__) && defined(__APPLE__)))
        static typelib_TypeDescriptionReference * s_pType_XAccount = 0;
    #endif
    
        if ( !s_pType_XAccount )
        {
            typelib_static_interface_type_init( &s_pType_XAccount, "XAccount", 0 );
        }
        return * reinterpret_cast< ::com::sun::star::uno::Type * >( &s_pType_XAccount );
    }
    
    #endif // _XACCOUNT_HPP_
    		  

    CORBA (example of MICO orb)

    account.h:
    #if !defined(__ACCOUNT_H__) || defined(MICO_NO_TOPLEVEL_MODULES)
    #define __ACCOUNT_H__
    
    #ifndef MICO_NO_TOPLEVEL_MODULES
    #include <CORBA.h>
    #include <mico/throw.h>
    #endif
    
    class Account;
    typedef Account *Account_ptr;
    typedef Account_ptr AccountRef;
    typedef ObjVar Account_var;
    typedef Account_var Account_out;
    
    
    // Common definitions for interface Account
    class Account :
      virtual public CORBA::Object
    {
      public:
        virtual ~Account();
    
        #ifdef HAVE_TYPEDEF_OVERLOAD
        typedef Account_ptr _ptr_type;
        typedef Account_var _var_type;
        #endif
    
        static Account_ptr _narrow( CORBA::Object_ptr obj );
        static Account_ptr _narrow( CORBA::AbstractBase_ptr obj );
        static Account_ptr _duplicate( Account_ptr _obj )
        {
          CORBA::Object::_duplicate (_obj);
          return _obj;
        }
    
        static Account_ptr _nil()
        {
          return 0;
        }
    
        virtual void *_narrow_helper( const char *repoid );
        static vector *_narrow_helpers;
        static bool _narrow_helper2( CORBA::Object_ptr obj );
    
        virtual void deposit( CORBA::ULong amount ) = 0;
        virtual void withdraw( CORBA::ULong amount ) = 0;
        virtual CORBA::Long balance() = 0;
    
      protected:
        Account() {};
      private:
        Account( const Account& );
        void operator=( const Account& );
    };
    
    extern CORBA::TypeCodeConst _tc_Account;
    
    // Stub for interface Account
    class Account_stub:
      virtual public Account
    {
      public:
        virtual ~Account_stub();
        void deposit( CORBA::ULong amount );
        void withdraw( CORBA::ULong amount );
        CORBA::Long balance();
    
      private:
        void operator=( const Account_stub& );
    };
    
    class Account_skel :
      virtual public StaticMethodDispatcher,
      virtual public Account
    {
      public:
        Account_skel( const CORBA::BOA::ReferenceData & = CORBA::BOA::ReferenceData() );
        virtual ~Account_skel();
        Account_skel( CORBA::Object_ptr obj );
        virtual bool dispatch( CORBA::StaticServerRequest_ptr _req, CORBA::Environment &_env );
        Account_ptr _this();
    
    };
    
    #ifndef MICO_CONF_NO_POA
    
    #endif // MICO_CONF_NO_POA
    
    #if !defined(MICO_NO_TOPLEVEL_MODULES) || defined(MICO_MODULE__GLOBAL)
    
    extern CORBA::StaticTypeInfo *_marshaller_Account;
    
    #endif // !defined(MICO_NO_TOPLEVEL_MODULES) || defined(MICO_MODULE__GLOBAL)
    
    
    #if !defined(MICO_NO_TOPLEVEL_MODULES) && !defined(MICO_IN_GENERATED_CODE)
    #include <mico/template_impl.h>
    #endif
    
    #endif
    		  

    account.cpp:
    #include "account.h"
    
    //--------------------------------------------------------
    //  Implementation of stubs
    //--------------------------------------------------------
    
    // Stub interface Account
    Account::~Account()
    {
    }
    
    void *Account::_narrow_helper( const char *_repoid )
    {
      if( strcmp( _repoid, "IDL:Account:1.0" ) == 0 )
        return (void *)this;
      return NULL;
    }
    
    bool Account::_narrow_helper2( CORBA::Object_ptr _obj )
    {
      if( strcmp( _obj->_repoid(), "IDL:Account:1.0" ) == 0) {
        return true;
      }
      for( vector<CORBA::Narrow_proto>::size_type _i = 0;
           _narrow_helpers && _i < _narrow_helpers->size(); _i++ ) {
        bool _res = (*(*_narrow_helpers)[ _i ])( _obj );
        if( _res )
          return true;
      }
      return false;
    }
    
    Account_ptr Account::_narrow( CORBA::Object_ptr _obj )
    {
      Account_ptr _o;
      if( !CORBA::is_nil( _obj ) ) {
        void *_p;
        if( (_p = _obj->_narrow_helper( "IDL:Account:1.0" )))
          return _duplicate( (Account_ptr) _p );
        if( _narrow_helper2( _obj ) ||
           ( _obj->_is_a_remote( "IDL:Account:1.0" ) ) ) {
          _o = new Account_stub;
          _o->MICO_SCOPE(CORBA,Object::operator=)( *_obj );
          return _o;
        }
      }
      return _nil();
    }
    
    Account_ptr
    Account::_narrow( CORBA::AbstractBase_ptr _obj )
    {
      return _narrow (_obj->_to_object());
    }
    
    Account_stub::~Account_stub()
    {
    }
    
    void Account_stub::deposit( CORBA::ULong amount )
    {
      CORBA::StaticAny _amount( CORBA::_stc_ulong, &amount );
      CORBA::StaticRequest __req( this, "deposit" );
      __req.add_in_arg( &_amount );
    
      __req.invoke();
    
      mico_sii_throw( &__req,
        0);
    }
    
    
    void Account_stub::withdraw( CORBA::ULong amount )
    {
      CORBA::StaticAny _amount( CORBA::_stc_ulong, &amount );
      CORBA::StaticRequest __req( this, "withdraw" );
      __req.add_in_arg( &_amount );
    
      __req.invoke();
    
      mico_sii_throw( &__req,
        0);
    }
    
    
    CORBA::Long Account_stub::balance()
    {
      CORBA::Long _res;
      CORBA::StaticAny __res( CORBA::_stc_long, &_res );
    
      CORBA::StaticRequest __req( this, "balance" );
      __req.set_result( &__res );
    
      __req.invoke();
    
      mico_sii_throw( &__req,
        0);
      return _res;
    }
    
    
    vector * Account::_narrow_helpers;
    CORBA::TypeCodeConst _tc_Account;
    
    class _Marshaller_Account : public CORBA::StaticTypeInfo {
        typedef Account_ptr _MICO_T;
      public:
        StaticValueType create () const;
        void assign (StaticValueType dst, const StaticValueType src) const;
        void free (StaticValueType) const;
        CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
        void marshal (CORBA::DataEncoder &, StaticValueType) const;
    };
    
    
    CORBA::StaticValueType _Marshaller_Account::create() const
    {
      return (StaticValueType) new _MICO_T( 0 );
    }
    
    void _Marshaller_Account::assign( StaticValueType d, const StaticValueType s ) const
    {
      *(_MICO_T*) d = ::Account::_duplicate( *(_MICO_T*) s );
    }
    
    void _Marshaller_Account::free( StaticValueType v ) const
    {
      CORBA::release( *(_MICO_T *) v );
      delete (_MICO_T*) v;
    }
    
    CORBA::Boolean _Marshaller_Account::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
    {
      CORBA::Object_ptr obj;
      if (!CORBA::_stc_Object->demarshal(dc, &obj))
        return FALSE;
      *(_MICO_T *) v = ::Account::_narrow( obj );
      CORBA::Boolean ret = CORBA::is_nil (obj) || !CORBA::is_nil (*(_MICO_T *)v);
      CORBA::release (obj);
      return ret;
    }
    
    void _Marshaller_Account::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
    {
      CORBA::Object_ptr obj = *(_MICO_T *) v;
      CORBA::_stc_Object->marshal( ec, &obj );
    }
    
    CORBA::StaticTypeInfo *_marshaller_Account;
    
    struct __tc_init_ACCOUNT {
      __tc_init_ACCOUNT()
      {
        _tc_Account =
        "010000000e00000024000000010000001000000049444c3a4163636f756e"
        "743a312e3000080000004163636f756e7400";
        _marshaller_Account = new _Marshaller_Account;
      }
    };
    
    static __tc_init_ACCOUNT __init_ACCOUNT;
    		  

    account_skel.cpp:
    #include "account.h"
    
    //--------------------------------------------------------
    //  Implementation of skeletons
    //--------------------------------------------------------
    
    Account_skel::Account_skel( const CORBA::BOA::ReferenceData &_id )
    {
      CORBA::ImplementationDef_var _impl =
        _find_impl( "IDL:Account:1.0", "Account" );
      assert( !CORBA::is_nil( _impl ) );
      _create_ref( _id,
        0,
        _impl,
        "IDL:Account:1.0" );
      register_dispatcher( new StaticInterfaceDispatcherWrapper<Account_skel>( this ) );
    }
    
    Account_skel::Account_skel( CORBA::Object_ptr _obj )
    {
      CORBA::ImplementationDef_var _impl =
        _find_impl( "IDL:Account:1.0", "Account" );
      assert( !CORBA::is_nil( _impl ) );
      _restore_ref( _obj,
        CORBA::BOA::ReferenceData(),
        0,
        _impl );
      register_dispatcher( new StaticInterfaceDispatcherWrapper<Account_skel>( this ) );
    }
    
    Account_skel::~Account_skel()
    {
    }
    
    bool Account_skel::dispatch( CORBA::StaticServerRequest_ptr _req, CORBA::Environment & /*_env*/ )
    {
      #ifdef HAVE_EXCEPTIONS
      try {
      #endif
        if( strcmp( _req->op_name(), "deposit" ) == 0 ) {
          CORBA::ULong amount;
          CORBA::StaticAny _amount( CORBA::_stc_ulong, &amount );
    
          _req->add_in_arg( &_amount );
    
          if( !_req->read_args() )
            return true;
    
          deposit( amount );
          _req->write_results();
          return true;
        }
        if( strcmp( _req->op_name(), "withdraw" ) == 0 ) {
          CORBA::ULong amount;
          CORBA::StaticAny _amount( CORBA::_stc_ulong, &amount );
    
          _req->add_in_arg( &_amount );
    
          if( !_req->read_args() )
            return true;
    
          withdraw( amount );
          _req->write_results();
          return true;
        }
        if( strcmp( _req->op_name(), "balance" ) == 0 ) {
          CORBA::Long _res;
          CORBA::StaticAny __res( CORBA::_stc_long, &_res );
          _req->set_result( &__res );
    
          if( !_req->read_args() )
            return true;
    
          _res = balance();
          _req->write_results();
          return true;
        }
      #ifdef HAVE_EXCEPTIONS
      } catch( CORBA::SystemException_catch &_ex ) {
        _req->set_exception( _ex->_clone() );
        _req->write_results();
        return true;
      } catch( ... ) {
        assert( 0 );
        return true;
      }
      #endif
      return false;
    }
    Account_ptr Account_skel::_this()
    {
      return Account::_duplicate( this );
    }
    		  

Author: Juergen Schmidt ($Date: 2002/02/04 11:51:20 $)
Copyright 2001 Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto, CA 94303 USA.