Uno/Article/Working with Environments, Mappings & Objects

From Apache OpenOffice Wiki
< Uno
Revision as of 13:33, 3 August 2006 by Kr (Talk | contribs)

Jump to: navigation, search

Working with Environments, Mappings & Objects

Environments, mappings and objects are at the heart of Uno. Understanding their relationship and how to use them is fundamental for understanding how Uno integrates different programming languages or how Uno can abstract particular characteristics, e.g. as thread-unsafeness.

Theory

Environments

Environments are at the fundament of Uno. Environments allow

  • to manage a set of objects, typically sharing some characteristics as the ABI or the "purpose",
  • to control the life cycle of any particular object belonging to an environment.

Examples for environments are:

"uno"
"gcc3" 
"uno:unsafe"
"jni:affine"

The part in front of the colon being the ABI, and the part behind it being the purpose (note: purposes may be chained, e.g. "<ABI>:unsafe:debug").

While their is no difference in general, we differentiate environments to either be

ABI Environments
ABI environments do not control any state and are solely managing objects of their particular ABI.
Purpose Environments
Purpose environments typically only manage objects of the "UNO" ABI, but do control state.
Life Cycle

Every environment is process wide unique and global. Requesting a particular environment (e.g. "uno:unsafe") multiple times, always returns the same instance. Instances of environments may control some global state, e.g. mutex or contexts etc., therefor environments can be entered respectively invoked.

Entering Environments

Environments may be entered either directly e.g. by calling enter, or indirectly by calling invoke. Depending on the particular environment, semantics might differ slightly.

As only purpose environments control any state, their is actually no difference between entering two environments with different ABIs but with the same purpose:

  "gcc3:unsafe"
  "uno:unsafe"

Consequently, entering a "pure" ABI environment, such as "gcc3", has no effect at all.

Integrity

Direct manipulation (e.g. casting and calling) of an object of a particular environment must only be done, while the owning environment has been entered. In contrast, indirect manipulation through the owning environment is guaranteed to always be safe.

Objects of different environments, even having the same ABI, must never be mixed, otherwise environment integrity may break (e.g. leading to a thread-safe object providing a thread-unsafe object to multiple threads).

Mappings

Mappings connect any two particular environments in a way, that an object of one environment may be "mapped" to another environment, actually providing a representation of the source object in terms of the destination environment.

A mapping may not only be direct, but may very well be composed of multiple "smaller" mappings. See the cascaded mapping specification for details.

Objects

Basically, (Uno) objects may be implemented anywhere, in components, in libraries, in applications or in the network. Accessing and creating Uno objects solely through Uno APIs guarantees environment integrity. Unfortunately, only Uno components ensure the by-API-only access, while applications, libraries and network sockets may very well by-pass the Uno-APIs. Precautions need to be taken, to still ensure that environment integrity can not break.

Libraries as well as applications, may be implemented environment-specialized or environment-free. Even partly specialization is possible, e.g. are:

  • a library taking and returning "uno" objects only - this library is specialized on the "uno" environment,
  • a library taking and returning "gcc3:unsafe" objects only - this library is specialized on the "gcc3:unsafe" environment,
  • a library taking and returning "gcc3[:<purpose>]*" objects only - this library is specialized on the ABI only,
  • a library taking and returning "<ABI>[:<purpose>]*" objects - this library is basically able to deal with any kind of objects, it is therefor environment-free.

Actually, any specialized library (or function) can easily be wrapped into any kind of specialization, as long as the necessary mapping is available. Hence, exactly this is what the Uno runtime does dynamically, in case the APIs are formalized respectively are Uno APIs.

Depending on the capabilities of the particular programming language and language binding, correct dealing with specialization may be enforced at compilation time, e.g. by dedicated reference types.

Note: Unfortunately, no type safe purpose references are yet available for any Uno language binding. So, this is planned. Currently, the only possible way to detect the purpose of a reference is at runtime, via the getCurrentEnvironment runtime function.

Note: It is planned, to support the selection of an implementation environment, determining an implementations environment at compile time, e.g. for 'C' like languages by a macro or an include. Some experiments have been done, so no final decisions have been made yet.

Practice

So, you may ask yourself, having read the above, what exactly can you do with this stuff?! Actually, the combination of environments, mappings and objects is very powerful. You can

  • achieve remote transparency,
  • trace one or multiple particular objects,
  • transparently access objects implemented in other programming languages,
  • provide well directed backdoors for optimization purposes,
  • implicitly handle contexts,
  • protect thread-unsafe objects,
  • and more.

More examples to come.

C++ Example - Function always returning an appropriate object

The following example shows a function always returning an appropriate object of type XInterface, including ABI and purpose. For the function to work properly, the client must have entered the appropriate environment.

callee.cxx:
  void * returnMyUnsafeObject(void) {
    void * pCurrEnv_Obj = NULL;
    {
      uno::Environment unsafeEnv(rtl::OUString(RTL_CONSTASCII_PARAM("gcc3:unsafe")));

      void * pUnsafeEnv_Obj = NULL;
      {
        cppu::EnvGuard unsafeGuard(unsafeEnv);

        pUnsafeEnv_Obj = new MyUnsafeObject();
      }

      Mapping unsafe2curr(unsafeEnv, uno::getCurrentEnv());
      pCurrEnv_Obj = unsafe2curr.mapInterface(pUnsafeEnv_Obj, typeof(XInterface));
      unsafeEnv.get()->pExtEnv->releaseInterface(pUnsafeEnv_Obj);
    }

    return pCurrEnv_Obj;
  }

caller.cxx:
  ...
  {
    cppu::EnvGuard javaDebug_Guard(rtl::OUString(RTL_CONSTASCII_PARAM("java:debug")));

    jobject * jObject = returnMyUnsafeObject();
  }
  ...
Personal tools