Skip to content

You are not logged in. Register orLog In

start:

OpenOffice Increasing UNO Ease of Use

Draft (version 1.0)


Increasing UNO Ease of Use

Why must I improve myself
Can't I just live and die?
—Bongwater

The following lists all the changes made so far (on SRC680 CWS sb10 and sb14) to increase UNO ease of use: multiple-inheritance interface types with optional base types and extended arguments, single-interface–based services with constructors, and interface-based singletons.

Overview

The main theme of all the changes made is adding type safety: Multiple inheritance has been added to UNO interface types, so that clients can now access a complete UNO object (or at least a large part of it) through a single, well-typed reference—no need to use queryInterface here any more.

That move made UNO interface types almost as expressive as UNOIDL service descriptions. What was lacking were optional base interfaces and the richness of service properties (optional, maybevoid, etc.), which was not parallelled by interface attributes. Both problems have been addressed now (see below), so that UNO interface types can now completely replace UNOIDL service descriptions.

Single-Interface–Based Services

But service descriptions are not dropped, they are rather turned into a more precise, and more useful concept: A new style of UNO services, called single-interface–based services, written in the form

    module someModule {
       service SomeService: XSomeInterface {
          ctor1( [in] long p1, [in] string p2)
                 raises (IllegalArgumentException);
          ctor2([in] any... args);
       };
    };

are used to express services that are available at the global service manager, under a given name (someModule.SomeService) and with a given interface type (XSomeInterface). Those services can be instantiated through constructors with precisely declared arguments (both number and types of arguments), which is an improvement over the sequence<any> currently passed to XMultiComponentFactory.createInstanceWithArgumentsAndContext. (For backwards compatibility, a constructor can also have a single parameter of a new rest type any..., which behaves much like a sequence<any>, and is modelled after the equivalent feature of Java 1.5). These single-interface–based services are directly supported in the various UNO language bindings, so that one can write

      XComponentContext context = …;
      XSomeInterface service = someModule.SomeService.ctor1(context, 10,
          "Whatever");

instead of

      XComponentContext context = …;
      XSomeInterface service = (XSomeInterface.class) UnoRuntime.queryInterface(
          XSomeInterface.class,
          context.getServiceManager().createInstanceWithContextAndArguments(
            "someModule.SomeService",
            new Any[] { new Integer(10), "Whatever" },
            context));

Interface-Based Singletons

The same happens to UNOIDL singleton descriptions—they are turned into new-style interface-based singletons of the form

      module someModule {
        singleton SomeSingleton: XSomeInterface;
      };

that can be used like

      XComponentContext context = …;
      XSomeInterface singleton =
         someModule.SomeSingleton.get(context);

instead of the old

    XComponentContext context = …;
    XSomeInterface singleton = (XSomeInterface)
    AnyConverter.toObject(
         XSomeInterface.class,
         context.getValueByName("/singletons/someModule.SomeSingleton"));

Optional Base Interfaces

Optional base interfaces have been added to UNO interface types as a pure design tool (that is, they do not map to any constructs within the language bindings). The intention behind optional base interfaces is that in a scenario like

    interface XSomeInterface {
       /** semantic constraints for mandatory XBase1 */
       interface XBase1;
       /** semantic constraints for mandatory XBase2 */
       interface XBase2;
       /** semantic constraints for optional XBase3 */
       [optional] interface XBase3;
    };
    interface XOtherInterface {
       interface XSomeInterface;
       interface XBase3;
    };

XOtherInterface, being a subtype of XSomeInterface, has to fulfil for its mandatory XBase3 all the semantic constraints specified at XSomeInterface for its optional XBase3. Seen the other way around, a client that has a reference of type XSomeInterface can use queryInterface to obtain a reference of type XBase3, and, if successful, can be certain that the referenced object adheres to the constraints specified for XSomeInterface's XBase3. The client need not even be aware the specific XOtherInterface exists.

Extended Attributes

The last missing piece is how to map the rich, XPropertySet-based properties of UNOIDL service descriptions to UNO interface type attributes (which currently can only distinguish between read–write and read-only).

As a first step, attributes are extended with raises clauses, in the form of

    interface XSomeInterface {
      [attribute] long attr {
         get raises (UnknownPropertyException);
         set raises (IllegalArgumentException);
      };
    };

This allows to map optional and constrained properties: An optional property is mapped to an attribute whose getter and setter both may raise UnknownPropertyException, while a constrained property is mapped to an attribute whose setter may raise PropertyVetoException (and whose getter may only raise the general RuntimeException).

To map maybeambigious, maybedefault, and maybevoid properties, polymorphic struct types are added to UNO. For example,

    struct Option<T> {
       boolean hasValue;
       T value;
    };

(or similar) can be used to encode the maybevoid UNOIDL service description property

[property, maybevoid] string Password;

as an equivalent UNO interface type attribute

[attribute] Option<string> Password;

Polymorphic struct types have not yet been added to UNO, they are scheduled for the next increment. However, some notes on how they will probably be implemented are given here already:

  • The feature will be kept rather simple. Only struct types are extended with parametric polymorphism. The type parameters of a polymorphic struct type may only be used directly as types of members (e.g.,

    struct S1<T> { S2<T> member; };

    where S2 also is a polymorphic struct type, is not supported). Only unbounded polymorphism, accepting any UNO type (including polymorphic struct types, and ANY) for a type parameter is supported. These limitations may be relaxed in the future.

  • In the C++ language binding, polymorphic struct types will be mapped to template classes.

  • In the Java language binding, polymorphic struct types will be mapped to classes using Java's Object-polymorphism (instances of type parameters will be replaced with Object). For Java 1.5, polymorphic struct types will be mapped to generic classes (which are compatible with the corresponding Object-polymorphic classes). However, to remain compatible with older Java versions, this implies that the javamaker tool has to be changed to directly produce Java class files, instead of Java source code.
    One unfortunate consequence of using Java's Object-polymorphism in pre-1.5 Java is the potential confusion with UNO's ANY-polymorphism, which also maps to Java Object, but in a slightly different way: While

    f(new Any(Type.UNSIGNED_LONG, new Integer(10)))

    can be used to call a UNO method f taking an argument of type ANY, it would be wrong to use

    new Poly(new Any(Type.UNSIGNED_LONG, new Integer(10)))

    to create an instance of the UNO struct type Poly<UNSIGNED LONG>. (Instead, the correct code would be

    new Poly(new Integer(10));

    which makes the UNO type argument UNSIGNED LONG implicit in Java).

  • In UNO bindings for dynamically typed languages like Python, polymorphic UNO struct types will reduce to plain, monomorphic ones, in consistency with the overall type systems of those languages.

Once extended interface type attributes are fully available, there will probably be less demand for XPropertySet than there is today—properties of UNO objects can be accessed directly via getters and setters, instead of going through XPropertySet.getPropertyValue and XPropertySet.setPropertyValue. However, there will still be demand that UNO objects implement XProperySet and related interfaces in special circumstances:

  • Client code will want to add change listeners and veto listeners on properties of UNO objects.

  • Certain client code will want to access the properties of UNO objects generically (for example, an object browser may want to display all properties of arbitrary UNO objects, going through the generic XPropertySet.getPropertySetInfo and XPropertySet.getPropertyValue; for another example, a performance-critical client may want to set multiple properties simultaneously using the generic XMultiPropertySet.setPropertyValues).

  • Some UNO objects will want to support dynamic properties in addition to the static ones, offering XPropertyContainer.addProperty and XPropertyContainer.removeProperty.

For implementors of such UNO objects, it would be helpful to find support in the language bindings: The implementors will only code the getters and setters of the various attributes, and helper classes will be available that add XPropertySet et al. on top of those attributes, using UNO's reflection mechanism to find out what attributes are available. The helper classes will use reflection to find out whether a property is maybevoid (the corresponding attribute would be of type Option<T>), constrained (the corresponding attribute would have a setter that may raise PropertyVetoException), etc. The only thing that cannot be detected this way is whether a property shall be bound (i.e., whether it shall support change listeners); for that reason, bound will be added as an additional flag to UNO interface type attributes, like

[attribute, bound] long Price;

That way, adding only the single wart of bound, support for properties is cleanly added to UNO objects, without spoiling core UNO with concepts like XPropertySet (which, after all, is part of the OOo UNO API, not of core UNO itself).

[TODO: The following lists only the changes made on SRC680 CWS sb10 to add multiple-inheritance interface types to UNO. It does not yet incorporate the additional changes made on SRC680 CWS sb14. Those changes will be documented here as soon as possible.]

UNO Changes for Multiple-Inheritance Interface Types

Changes to Core UNO

The definition of interface types in UNO Type System (revision 1.4) changes to the following (with actual changes in red):

Interface types
For a (user-defined) interface type, the values of that type are the null reference plus references to any UNO objects that implement that interface type. Each interface type has a name; two different interface types may not have the same name. Each interface type has a list of direct basesb1, …, bkb⟩, kb ≥ 0, where each bi is an interface type, and all the bi are mutually different. The only interface type that has an empty list of direct bases is named com.sun.star.uno.XInterface.
Each interface type has a list of direct attributesa1, …, aka⟩, ka ≥ 0, and a list of direct methods, ⟨m1, …, mkm⟩, km ≥ 0. Collectively, the direct attributes and direct methods of an interface type are called the direct members of that interface type. The interface type named com.sun.star.uno.XInterface has an empty list of direct attributes and an empty list of direct methods.
Each direct attribute of an interface type has a name, a non-void, non-exception type, and is either read–write or read-only.
Each direct method of an interface type has a name, a list of arguments ⟨r1, …, rkr⟩, kr ≥ 0, a non-exception return type, a set of exception types {e1, …, eke}, ke ≥ 0, and is either synchronous or one-way. Each argument ri has a name, a non-void, non-exception type, and is either in, out, or in–out. No two different arguments of a given method may have the same name. For a method that is one-way, none of the arguments may be out or in–out, the return type must be VOID, and the set of exception types must be empty.
The set of members of an interface type is the union of the set of direct members and the set of inherited members. The set of inherited members of an interface type is the union of the sets of members of all its direct bases. No two different members of a given interface type may have the same name.
An interface type may not be derived from itself. More formally: consider the directed graph G, with the set of interface types as nodes, and with the set of arcs defined as follows. For each pair of interface types t1, t2, where type t1 is a direct base of type t2, there is a directed arc from node t2 to node t1. The resulting graph G must not be cyclic.
An interface type may not have as direct base a type that it also has as indirect base. More formally: define the set of bases of an interface type t to be the union of the set of the direct bases of t and the sets of bases of all the direct bases of t. Then, for any interface type t, none of the direct bases of t must be a member of the set of bases of any of the direct bases of t.

Function Indices

In various places (binary UNO, URP, the C++ bridges), the concept of function indices is needed: a mapping between integers (i.e., function indices) and the members of an interface type. All those places use the same algorithm to construct these mappings, which is now described in the section “Function Indices” of UNO Type System.

Changes to UNOIDL

The syntax for interface types in UNOIDL changes from

 interface_dcl: interfaceheader { exports }
 interfaceheader: interface_decl inheritance_spec
 interface_decl: interface IDENTIFIER
 inheritance_spec: : scoped_name
     | ε
 exports: exports export
     | ε
 export: attribute ;
     | operation ;

to

 interface_dcl: interfaceheader { exports }
 interfaceheader: interface_decl inheritance_spec
 interface_decl: interface IDENTIFIER
 inheritance_spec: : scoped_name
     | ε
 exports: exports export
     | ε
 export: attribute ;
     | operation ;
     | interface_inheritance_decl ;
 interface_inheritance_decl: interface at_least_one_scoped_name

It is an error for an interface_dcl to have both a non-empty inheritance_spec and one or more interface_inheritance_decls. Then, there are four cases how the list of direct bases can be specified for an interface type in UNOIDL:

  • If the interface type is named com.sun.star.uno.XInterface, then the interface_dcl must have an empty inheritance_spec and no interface_inheritance_decls.

  • Otherwise, if the interface_dcl has an empty inheritance_spec and no interface_inheritance_decls, then the list of direct bases is implicitly taken to only contain the interface type named com.sun.star.uno.XInterface.

  • Otherwise, if the interface_dcl has a non-empty inheritance_spec (and thus no interface_inheritance_decls), then the list of direct bases contains just the interface type given in the inheritance_spec.

  • Otherwise (the interface_dcl has an empty inheritance_spec and one or more interface_inheritance_decls), the list of direct bases contains all the interface types given in all the interface_inheritance_decls, in the given order.

Module idlc has been changed accordingly. [TODO: idlc does not yet check that an interface type does not have as direct base a type that it also has as an indirect base.]

Changes to Binary UNO

The format of the binary type library (Binary specification of the type representation in the UNO typelibrary) already allowed to represent interface types with more than one base type (nSuperTypes in the header section).

The low-level RegistryTypeReader and RegistryTypeWriter APIs in module registry have been enhanced backwards-compatibly, adding functions getMISuperTypeCount/getMISuperTypeName and createMIEntry/setMISuperTypeData, respectively. [TODO: Find out whether/how to mark the functions initRegistryTypeReader_Api and initRegistryTypeWriter_Api as having changed backwards-compatibly in registry/util/reg.map.]

The interface-type–related UNO type description types in cppu/inc/typelib/typedescription.h have been enhanced backwards-compatibly. [TODO: Any chance to reflect these backwards-compatible changes in the shared library symbol versioning?] There are two important changes:

  • The member pBaseTypeDescription of typelib_InterfaceTypeDescription has been deprecated and superseded by the two new members nBaseTypes and ppBaseTypes (pBaseTypeDescription continues to point to the the first base type, ppBaseTypes[0], if any). All code that used pBaseTypeDescription has to be adapted to use ppBaseTypes instead. [TODO: With a grep over SRC680m20, the files that are affected by this change (and not yet fixed on CWS sb10), are bridges/source/jni_uno/jni_info.cxx, bridges/source/jni_uno/jni_java2uno.cxx, cppu/source/uno/assign.hxx, cppu/source/uno/lbenv.cxx, pyuno/source/module/pyuno_except.cxx, stoc/source/invocation_adapterfactory/iafactory.cxx, and stoc/source/proxy_factory/proxyfac.cxx.]

  • Interface member type descriptions are no longer shared across base/derived interface types. Instead, each interface type t has its own instance of an interface member type description, for each (direct or inherited) member. For a direct member named N, the name of the member type description is still t::N. But for an inherited member named N, the name has changed to β:@i,j:t, where β, i, and j are defined as follows. Let b0 be the interface type that directly defines N, and let b be the first direct base of t that is either b0 itself or inherits b0. Then β is the name of the interface member type description of N at b, i is the index of direct base b within t (in the range [0 … kb − 1]), and j is the overall member index of N within t. [TODO: It might be possible to avoid those additional member type descriptions for members inherited on the “primary chain.”] One consequence of this change of how interface member type descriptions are named is that the functions IdlAttributeFieldImpl/IdlInterfaceMethodImpl::getDeclaringClass (in stoc/source/corereflection/criface.cxx) had to be adapted, so that BASIC continued to work. [TODO: Any other places that depend on the names of interface member type descriptions?]

The UNO interface type com.sun.star.reflection.XInterfaceTypeDescription has been superseded by the new, derived interface type com.sun.star.reflection.XInterfaceTypeDescription2, which adds a method getBaseTypes (obsoleting the existing method getBaseType). The documentation of com.sun.star.uno.XTypeDescriptionEnumerationAccess has been changed to reflect that information about interface types is returned as instances of com.sun.star.reflection.XInterfaceTypeDescription2. The corresponding service implementation in stoc/source/registry_tdprovider has been changed accordingly.

Changes to The C++ Language Binding

Multiple UNO interface inheritance maps naturally to multiple inheritance of C++ classes.

The cppumaker in module codemaker has been adapted accordingly.

The implementation helper classes (cppuhelper/implbase_ex.hxx, cppuhelper/implbase1.hxx, etc.) have been adapted to multiple inheritance. (The obsolete cppuhelper/implbase.hxx cannot be removed, see issue 25058.)

The framework for the various platform-specific C++–binary-UNO bridges (bridges/source/cpp_uno) has been changed as follows:

  • The inline code in bridges/inc/bridges/cpp_uno has been replaced with code in bridges/inc/bridges/cpp_uno/shared and bridges/source/cpp_uno/shared. Individual bridges now need to link in the cpp_uno_shared library. Once all bridges have been adapted, the old inline code at bridges/inc/bridges/cpp_uno can be removed.

  • The component-related code (component_canUnload, uno_initEnvironment, and uno_ext_getMapping) has been moved out of the individual bridges to bridges/source/cpp_uno/shared/component.cxx.

  • The bridging-related functions individual bridges have to implement have been reduced to bridges::cpp_uno::shared::UnoInterfaceProxy::dispatch (in bridges/inc/bridges/cpp_uno/shared/unointerfaceproxy.hxx) and bridges::cpp_uno::shared::VtableFactory::createBlock/addLocalFunctions/flushCode (in bridges/inc/bridges/cpp_uno/shared/vtablefactory.hxx), factoring out common functionality into shared.

  • On top of that, the classes cppu_cppInterfaceProxy and cppu_unoInterfaceProxy have undergone slight changes: they have been renamed to CppInterfaceProxy and UnoInterfaceProxy, respectively, and many of their members are now private, so that code within the individual bridges has to be adapted to use the new getter methods.

The bridges in bridges/source/cpp_uno/cc50_solaris_sparc, bridges/source/cpp_uno/gcc3_linux_intel, bridges/source/cpp_uno/gcc3_linux_powerpc, bridges/source/cpp_uno/gcc3_macosx_powerpc, and bridges/source/cpp_uno/msvc_win32_intel have already been adapted to multiple-inheritance interface types and the new framework. [TODO: Change those other bridges as well that have not been removed because they are obsolete.]

Changes to The Java Language Binding

Multiple UNO interface inheritance maps naturally to multiple Java interface inheritance.

The javamaker in module codemaker has been adapted accordingly. No further visible changes were necessary.

Changes to The Python Language Binding

[TODO: To be determined.]

Changes to The CLI Language Binding

[TODO: To be determined.]

Changes to URP

The notion of method IDs in UNO Remote Protocol Version 1.0 Specification (revision 1.9) has been revised (in revision 1.10). First, “method ID” has been changed to “request ID,” to avoid confusion with the methods of interface types. Second, the request ID that corresponds to a given interface type member function is defined to be the function index the member function maps to. It is an error for the function index to be outside the range [0 … 216 − 1].

The binary-UNO– and Java–URP bridges in modules bridges and jurt have been changed accordingly.

Tests

There are new tests in bridges/test/java_uno/multinherit. Any combination of testmultinherit-native-server/testmultinherit-native-client, testmultinherit-native-server/testmultinherit-java-client, testmultinherit-java-server/testmultinherit-native-client, and testmultinherit-java-server/testmultinherit-java-client must work.

Documentation

[TODO: The Developer's Guide has to be updated.]

Author: Stephan Bergmann ($Date: 2006/03/17 12:24:24 $)
Copyright 2002 Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto, CA 94303 USA.