Scripting Existing UNO Objects

This section describes UNO bridges for type-unsafe (scripting) programming languages. These bridges are based on the com.sun.star.script.Invocation service.

The most common starting point for a new scripting language binding is that you want to control OpenOffice.org from a script running externally. To accomplish this, you need to know what your scripting language offers to extend the language, for example, Python or Perl extend the language with a module concept using locally shared libraries.

In general, your bridge must offer a static method that is called from a script. Within this method, bootstrap a UNO C++ component context as described in Bootstrapping a Service Manager.

Proxying a UNO Object

Next, this component context must be passed to the script programmer, so that you can instantiate a com.sun.star.bridge.UnoUrlResolver and connect to a running office within the script.

The component context can not be passed directly as a C++ UNO reference, because the scripting engine does not recognize it, therefore build a language dependent proxy object around the C++ object Reference.

A scripting call over a proxy instance

For example, Python offers an API to create a proxy. Typically calls invoked on the proxy from a script are narrowed into one single C function. The Python runtime passes method names and an array containing the arguments to this C function.

If a proxy is implemented for a concrete interface, the method names that you received could in theory be compared to all method names offered by the UNO interface. This is not feasible, because of all the interfaces used in OpenOffice.org. The com.sun.star.script.Invocation service exists for this purpose. It offers a simple interface com.sun.star.lang.XSingleServiceFactory that creates a proxy for an arbitrary UNO object using the createInstanceWithArguments() method and passing the object the proxy acts for. Use the com.sun.star.script.XInvocation interface that is exported by this proxy to invoke a method on the UNO object.

A scripting call using XInvocation

Argument Conversion

In addition, argument conversion must be considered by specifying how each UNO type should be mapped to your target language.

Convert the language dependent data types to UNO data types before calling com.sun.star.script.XInvocation:invoke() and convert the UNO datatypes (return value and out parameters) to language dependent types after the call has been exectuted. The conversion routines are typically recursive functions, because data values are nested in complex types, such as struct or any.

When UNO object references are returned by method calls to UNO objects, create new language dependent proxies as discussed above. When passing a previously returned UNO object as a parameter to a new method call, the language binding must recognize that it is a proxied object and pass the original UNO object reference to the com.sun.star.script.XInvocation:invoke() call instead.

A special case for conversions are UNOIDL structs. You want to call a method that takes a struct as an argument. The first problem is the struct must be created by the bridge and the script programmer must be able to set members at the struct. One solution is that the bridge implementer creates a UNO struct using core C functions from the cppu library, but this is complicated and results in a lot of difficulty.

Exception Handling

UNO method calls may throw exceptions and must be mapped to the desired target language appropriately, depending on the capabilities of your target language. Ideally, the target language supports an exception concept, but error handlers, such as in OpenOffice.org Basic can be used also. A third way and worst case scenario is to check after every API call if an exception has been thrown,. In case the UNO object throws an exception, the XInvocation proxy throws a com.sun.star.reflection.InvocationTargetException. The exception has an additional any member, that contains the exception that was really thrown.

Note that the XInvocation proxy may throw a com.sun.star.script.CannotConvertException indicating that the arguments passed by the script programmer cannot be matched to the arguments of the desired function. For example, there are missing arguments or the types are incompatible. This must be reported as an error to the script programmer.

Property Support

The com.sun.star.script.Invocation has special getProperty() and setProperty() methods. These methods are used when the UNO object supports a property set and your target language, for example, supports something similar to the following:

Implementing UNO objects

When it is possible to implement classes in your target language, consider offering support for implementation of UNO objects. This is useful for callbacks, for example, event listeners. Another typical use case is to provide a datasource through a com.sun.star.io.XInputStream.

The script programmer determines which UNOIDL types the developed class implements, such as flagged by a special member name, for example, such as __supportedUnoTypes.

When an instance of a class is passed as an argument to a call on an external UNO object, the bridge code creates a new language dependent proxy that additionally supports the XInvocation interface. the bridge code hands the XInvocation reference of the bridge's proxy to the called object. This works as long as the com.sun.star.script.XInvocation:invoke() method is used directly, for instance OpenOffice.org Basic, except if the called object expects an XInputStream.

The com.sun.star.script.InvocationAdapterFactory service helps by creating a proxy for a certain object that implements XInvocation and a set of interfaces, for example, given by the __supportedUnoTypes variable. The proxy returned by the createAdapater() method must be passed to the called object instead of the bridge's XInvocation implementation. When the Adapter is queried for one of the supported types, an appropriate proxy supporting that interface is created.

If a UNO object invokes a call on the object, the bridge proxy's com.sun.star.script.XInvocation:invoke() method is called. It converts the passed arguments from UNO types to language dependent types and conversely using the same routines you have for the other calling direction. Finally, it delegates the call to the implementation within the script.

A call sequence

It may become difficult if you do not want to start with an external scripting engine, but want to use the scripting engine inside the OpenOffice.org process instead. This must be supported by the target language. Often it is possible to load some library dynamically and access the scripting runtime engine through a C API. It should be implemented as a UNO C++ component. There are currently no generic UNO interfaces for this case, except for the com.sun.star.loader.XImplementationLoader. Define your own interfaces that best match your requirements. You might instantiate from Basic and retrieve an initial object or start a script. Future versions of OpenOffice.org may have a more comprehensive solution.