[ Previous document | Content Table | Next document ]
This chapter provides in-depth information about UNO and the use of UNO in various programming languages. There are four sections:
The 3.1 Professional UNO - Introduction gives an outline of the UNO architecture.
The section 3.2 Professional UNO - API Concepts supplies background information on the API reference.
The section 3.3 Professional UNO - UNO Concepts describes the mechanics of UNO, i.e. it shows how UNO objects connect and communicate with each other.
The section 3.4 Professional UNO - UNO Language Bindings elaborates on the use of UNO from Java, C++, OpenOffice.org Basic, COM automation, and CLI.
The goal of UNO (Universal Network Objects) is to provide an environment for network objects across programming language and platform boundaries. UNO objects run and communicate everywhere. UNO reaches this goal by providing the following fundamental framework:
UNO objects are specified in an abstract meta language, called UNOIDL (UNO Interface Definition Language), which is similar to CORBA IDL or MIDL. From UNOIDL specifications, language dependent header files and libraries can be generated to implement UNO objects in the target language. UNO objects in the form of compiled and bound libraries are called components. Components must support certain base interfaces to be able to run in the UNO environment.
To instantiate components in a target environment UNO uses a factory concept. This factory is called the service manager. It maintains a database of registered components which are known by their name and can be created by name. The service manager might ask Linux to load and instantiate a shared object written in C++ or it might call upon the local Java VM to instantiate a Java class. This is transparent for the developer, there is no need to care about a component's implementation language. Communication takes place exclusively over interface calls as specified in UNOIDL.
UNO provides bridges to send method calls and receive return values between processes and between objects written in different implementation languages. The remote bridges use a special UNO remote protocol (URP) for this purpose which is supported for sockets and pipes. Both ends of the bridge must be UNO environments, therefore a language-specific UNO runtime environment to connect to another UNO process in any of the supported languages is required. These runtime environments are provided as language bindings.
Most objects of OpenOffice.org are able to communicate in a UNO environment. The specification for the programmable features of OpenOffice.org is called the OpenOffice.org API.
The OpenOffice.org API is a language independent approach to specify the functionality of OpenOffice.org. Its main goals are to provide an API to access the functionality of OpenOffice.org, to enable users to extend the functionality by their own solutions and new features, and to make the internal implementation of OpenOffice.org exchangeable.
A long term target on the OpenOffice.org roadmap is to split the existing OpenOffice.org into small components which are combined to provide the complete OpenOffice.org functionality. Such components are manageable, they interact with each other to provide high level features and they are exchangeable with other implementations providing the same functionality, even if these new implementations are implemented in a different programming language. When this target will be reached, the API, the components and the fundamental concepts will provide a construction kit, which makes OpenOffice.org adaptable to a wide range of specialized solutions and not only an office suite with a predefined and static functionality.
This section provides you with a thorough understanding of the concepts behind the OpenOffice.org API. In the API reference there are UNOIDL data types which are unknown outside of the API. The reference provides abstract specifications which sometimes can make you wonder how they map to implementations you can actually use.
The data types of the API reference are explained in 3.2.1 Professional UNO - API Concepts - Data Types. The relationship between API specifications and OpenOffice.org implementations is treated in 3.2.2 Professional UNO - API Concepts - Understanding the API Reference.
The data types in the API reference are UNO types which have to be mapped to the types of any programming language that can be used with the OpenOffice.org API. In the chapter 2 First Steps the most important UNO types were introduced. However, there is much more to be said about simple types, interfaces, properties and services in UNO. There are special flags, conditions and relationships between these entities which you will want to know if you are working with UNO on a professional level.
This section explains the types of the API reference from the perspective of a developer who wants to use the OpenOffice.org API. If you are interested in writing your own components, and you must define new interfaces and types, please refer to the chapter 4 Writing UNO Components, which describes how to write your own UNOIDL specifications and how to create UNO components.
UNO provides a set of predefined, simple types which are listed in the following table:
|
UNO Type |
Description |
|
void |
Empty type, used only as method return type and in any. |
|
boolean |
Can be true or false. |
|
byte |
Signed 8-bit integer type (ranging from -128 to 127, inclusive). |
|
short |
Signed 16-bit integer type (ranging from −32768 to 32767, inclusive). |
|
unsigned short |
Unsigned 16-bit integer type (deprecated). |
|
long |
Signed 32-bit integer type (ranging from −2147483648 to 2147483647, inclusive). |
|
unsigned long |
Unsigned 32-bit integer type (deprecated). |
|
hyper |
Signed 64-bit integer type (ranging from −9223372036854775808 to 9223372036854775807, inclusive). |
|
unsigned hyper |
Unsigned 64-bit integer type (deprecated). |
|
float |
IEC 60559 single precision floating point type. |
|
double |
IEC 60559 double precision floating point type. |
|
char |
Represents individual Unicode characters (more precisely: individual UTF-16 code units). |
|
string |
Represents Unicode strings (more precisely: strings of Unicode scalar values). |
|
type |
Meta type that describes all UNO types. |
|
any |
Special type that can represent values of all other types. |
The chapters about language bindings 3.4.1 Professional UNO - UNO Language Bindings - Java Language Binding, 3.4.2 Professional UNO - UNO Language Bindings - C++ Language Binding, 3.4.3 Professional UNO - UNO Language Bindings - OpenOffice.org Basic and 3.4.4 Professional UNO - UNO Language Bindings - Automation Bridge describe how these types are mapped to the types of your target language.
The special type any can represent values of all other UNO types. In the target languages, the any type requires special treatment. There is an AnyConverter in Java and special operators in C++. For details, see the section 3.4 Professional UNO - UNO Language Bindings about language bindings.
Communication between UNO objects is based on object interfaces. Interfaces can be seen from the outside or the inside of an object.
From the outside of an object, an interface provides a functionality or special aspect of the object. Interfaces provide access to objects by publishing a set of operations that cover a certain aspect of an object without telling anything about its internals.
The concept of interfaces is quite natural and frequently used in everyday life. Interfaces allow the creation of things that fit in with each other without knowing internal details about them. A power plug that fits into a standard socket or a one-size-fits-all working glove are simple examples. They all work by standardizing the minimal conditions that must be met to make things work together.
A more advanced example would be the “remote control aspect” of a simple TV system. One possible feature of a TV system is a remote control. The remote control functions can be described by an XPower and an XChannel interface. The illustration below shows a RemoteControl object with these interfaces:
Illustration 3.1: RemoteControl service |
The XPower interface has the functions turnOn() and turnOff() to control the power and the XChannel interface has the functions select(), next(), previous() to control the current channel. The user of these interfaces does not care if he uses an original remote control that came with a TV set or a universal remote control as long as it carries out these functions. The user is only dissatisfied if some of the functions promised by the interface do not work with a remote control.
From the inside of an object, or from the perspective of someone who implements a UNO object, interfaces are abstract specifications. The abstract specification of all the interfaces in the OpenOffice.org API has the advantage that user and implementer can enter into a contract, agreeing to adhere to the interface specification. A program that strictly uses the OpenOffice.org API according to the specification will always work, while an implementer can do whatever he wants with his objects, as long as he serves the contract.
UNO uses the interface type to describe such aspects of UNO objects. By convention, all interface names start with the letter X to distinguish them from other types. All interface types must inherit the com.sun.star.uno.XInterface root interface, either directly or in the inheritance hierarchy. XInterface is explained in 3.3.3 Professional UNO - UNO Concepts - Using UNO Interfaces. The interface types define methods (sometimes also called operations) to provide access to the specified UNO objects.
Interfaces allow access to the data inside an object through dedicated methods (member functions) which encapsulate the data of the object. The methods always have a parameter list and a return value, and they may define exceptions for smart error handling.
The exception concept in the OpenOffice.org API is comparable with the exception concepts known from Java or C++. All operations can raise com.sun.star.uno.RuntimeExceptions without explicit specification, but all other exceptions must be specified. UNO exceptions are explained in the section 3.3.7 Professional UNO - UNO Concepts - Exception Handling below.
Consider the following two examples for interface definitions in UNOIDL notation. UNOIDL interfaces resemble Java interfaces, and methods look similar to Java method signatures. However, note the flags in square brackets in the following example:
// base interface for all UNO interfaces
interface XInterface
{
any queryInterface( [in] type aType );
[oneway] void acquire();
[oneway] void release();
};
// fragment of the Interface com.sun.star.io.XInputStream
interface XInputStream: com::sun::star::uno::XInterface
{
long readBytes( [out] sequence<byte> aData,
[in] long nBytesToRead )
raises( com::sun::star::io::NotConnectedException,
com::sun::star::io::BufferSizeExceededException,
com::sun::star::io::IOException);
...
};
The [oneway] flag indicates that an operation can be executed asynchronously if the underlying method invocation system does support this feature. For example, a UNO Remote Protocol (URP) bridge is a system that supports oneway calls.
|
|
Although there are no general problems with the specification and the implementation of the UNO oneway feature, there are several API remote usage scenarios where oneway calls cause deadlocks in OpenOffice.org. Therefore, do not introduce new oneway methods with new OpenOffice.org UNO APIs. |
There are also parameter flags. Each parameter definition begins with one of the direction flags in, out, or inout to specify the use of the parameter:
in specifies that the parameter will be used as an input parameter only
out specifies that the parameter will be used as an output parameter only
inout specifies that the parameter will be used as an input and output parameter
These parameter flags do not appear in the API reference. The fact that a parameter is an [out] or [inout] parameter is explained in the method details.
Interfaces consisting of methods form the basis for service specifications.
We have seen that a single-inheritance interface describes only one aspect of an object. However, it is quite common that objects have more than one aspect. UNO uses multiple-inheritance interfaces and services to specify complete objects which can have many aspects.
In a first step, all the various aspects of an object (which are typically represented by single-inheritance interfaces) are grouped together in one multiple-inheritance interface type. If such an object is obtainable by calling specific factory methods, this step is all that is needed. The factory methods are specified to return values of the given, multiple-inheritance interface type. If, however, such an object is available as a general service at the global component context, a service description must be provided in a second step. This service description will be of the new style, mapping the service name (under which the service is available at the component context) to the given, multiple-inheritance interface type.
For backward compatibility, there are also old-style services, which comprise a set of single-inheritance interfaces and properties that are needed to support a certain functionality. Such a service can include other old-style services as well. The main drawback of an old-style service is that it is unclear whether it describes objects that can be obtained through specific factory methods (and for which there would therefore be no new-style service description), or whether it describes a general service that is available at the global component context, and for which there would thus be a new-style service description.
From the perspective of a user of a UNO object, the object offers one or sometimes even several independent, multiple-inheritance interfaces or old-style services described in the API reference. The services are utilized through method calls grouped in interfaces, and through properties, which are handled through special interfaces as well. Because the access to the functionality is provided by interfaces only, the implementation is irrelevant to a user who wants to use an object.
From the perspective of an implementer of a UNO object, multiple-inheritance interfaces and old-style services are used to define a functionality independently of a programming language and without giving instructions about the internal implementation of the object. Implementing an object means that it must support all specified interfaces and properties. It is possible that a UNO object implements more than one independent, multiple-inheritance interface or old-style service. Sometimes it is useful to implement two or more independent, multiple-inheritance interfaces or services because they have related functionality, or because they support different views to the object.
Illustration 3.2 shows the relationship between interfaces and services. The language independent specification of an old-style service with several interfaces is used to implement a UNO object that fulfills the specification. Such a UNO object is sometimes called a “component,” although that term is more correctly used to describe deployment entities within a UNO environment. The illustration uses an old-style service description that directly supports multiple interfaces; for a new-style service description, the only difference would be that it would only support one multiple-inheritance interface, which in turn would inherit the other interfaces.
Illustration 3.2: Interfaces, services and implementation |
The functionality of a TV system with a TV set and a remote control can be described in terms of service specifications. The interfaces XPower and XChannel described above would be part of a service specification RemoteControl. The new service TVSet consists of the three interfaces XPower, XChannel and XStandby to control the power, the channel selection, the additional power function standby() and a timer() function.
Illustration 3.3: TV System Specification |
References to interfaces in a service definition mean that an implementation of this service must offer the specified interfaces. However, optional interfaces are possible. If a multiple-inheritance interface inherits an optional interface, or an old-style service contains an optional interface, any given UNO object may or may not support this interface. If you utilize an optional interface of a UNO object, always check if the result of queryInterface() is equal to null and react accordingly—otherwise your code will not be compatible with implementations without the optional interface and you might end up with null pointer exceptions. The following UNOIDL snippet shows a fragment of the specification for the old-style com.sun.star.text.TextDocument service in the OpenOffice.org API. Note the flag optional in square brackets, which makes the interfaces XFootnotesSupplier and XEndnotesSupplier non-mandatory.
// com.sun.star.text.TextDocument
service TextDocument
{
...
interface com::sun::star::text::XTextDocument;
interface com::sun::star::util::XSearchable;
interface com::sun::star::util::XRefreshable;
[optional] interface com::sun::star::text::XFootnotesSupplier;
[optional] interface com::sun::star::text::XEndnotesSupplier;
...
};
New-style services can have constructors, similar to interface methods:
service SomeService: XSomeInterface {
create1();
create2([in] long arg1, [in] string arg2);
create3([in] any... rest);
};
In the above example, there are three explicit constructors, named create1, create2, and create3. The first has no parameters, the second has two normal parameters, and the third has a special rest parameter, which accepts an arbitrary number of any values. Constructor parameters may only be [in], and a rest parameter must be the only parameter of a constructor, and must be of type any; also, unlike an interface method, a service constructor does not specify a return type.
The various language bindings map the UNO constructors into language-specific constructs, which can be used in client code to obtain instances of those services, given a component context. The general convention (followed,for example, by the Java and C++ language bindings) is to map each constructor to a static method (resp. function) with the same name, that takes as a first parameter an XComponentContext, followed by all the parameters specified in the constructor, and returns an (appropriately typed) service instance. If an instance cannot be obtained, a com.sun.star.uno.DeploymentException is thrown. The above SomeService would map to the following Java 1.5 class, for example:
public class SomeService {
public static XSomeInterface create1(
com.sun.star.uno.XComponentContext context) { ... }
public static XSomeInterface create2(
com.sun.star.uno.XComponentContext context, int arg1, String arg2) { ... }
public static XSomeInterface create3(
com.sun.star.uno.XComponentContext context, Object... rest) { ... }
}
Service constructors can also have exception specifications (“raises (Exception1, ...)”), which are treated in the same way as exception specifications of interface methods. (If a constructor has no exception specification, it may only throw runtime exceptions, com.sun.star.uno.DeploymentException in particular.)
If a new-style service is written using the short form,
service SomeService: XSomeInterface;
then it has an implicit constructor. The exact behavior of the implicit constructor is language-binding–specific, but it is typically named create, takes no arguments besides the XComponentContext, and may only throw runtime exceptions.
When the structure of the OpenOffice.org API was founded, the designers discovered that the objects in an office environment would have huge numbers of qualities that did not appear to be part of the structure of the objects, rather they seemed to be superficial changes to the underlying objects. It was also clear that not all qualities would be present in each object of a certain kind. Therefore, instead of defining a complicated pedigree of optional and non-optional interfaces for each and every quality, the concept of properties was introduced. Properties are data in an object that are provided by name over a generic interface for property access, that contains getPropertyValue() and setPropertyValue() access methods. The concept of properties has other advantages, and there is more to know about properties. Please refer to 3.3.4 Professional UNO - UNO Concepts - Properties for further information about properties.
Old-style services can list supported properties directly in the UNOIDL specification. A property defines a member variable with a specific type that is accessible at the implementing component by a specific name. It is possible to add further restrictions to a property through additional flags. The following old-style service references one interface and three optional properties. All known API types can be valid property types:
// com.sun.star.text.TextContent
service TextContent
{
interface com::sun::star::text::XTextContent;
[optional, property] com::sun::star::text::TextContentAnchorType AnchorType;
[optional, readonly, property] sequence<com::sun::star::text::TextContentAnchorType> AnchorTypes;
[optional, property] com::sun::star::text::WrapTextMode TextWrap;
};
Possible property flags are:
optional
The property does not have to be supported by the implementing component.
readonly
The value of the property cannot be changed using com.sun.star.beans.XPropertySet.
bound
Changes of property values are broadcast to com.sun.star.beans.XPropertyChangeListeners, if any were registered through com.sun.star.beans.XPropertySet.
constrained
The property broadcasts an event before its value changes. Listeners have the right to veto the change.
maybeambiguous
Possibly the property value cannot be determined in some cases, for example, in multiple selections with different values.
maybedefault
The value might be stored in a style sheet or in the environment instead of the object itself.
maybevoid
In addition to the range of the property type, the value can be void. It is similar to a null value in databases.
removable
The property is removable, this is used for dynamic properties.
transient
The property will not be stored if the object is serialized
Old-style services can include other old-style services. Such references may be optional. That a service is included by another service has nothing to do with implementation inheritance, only the specifications are combined. It is up to the implementer if he inherits or delegates the necessary functionality, or if he implements it from scratch.
The old-style service com.sun.star.text.Paragraph in the following UNOIDL example includes one mandatory service com.sun.star.text.TextContent and five optional services. Every Paragraph must be a TextContent. It can be a TextTable and it is used to support formatting properties for paragraphs and characters:
// com.sun.star.text.Paragraph
service Paragraph
{
service com::sun::star::text::TextContent;
[optional] service com::sun::star::text::TextTable;
[optional] service com::sun::star::style::ParagraphProperties;
[optional] service com::sun::star::style::CharacterProperties;
[optional] service com::sun::star::style::CharacterPropertiesAsian;
[optional] service com::sun::star::style::CharacterPropertiesComplex;
...
};
If all the old-style services in the example above were multiple-inheritance interface types instead, the structure would be similar: the multiple-inheritance interface type Paragraph would inherit the mandatory interface TextContent and the optional interfaces TextTable, ParagraphProperties, etc.
A component is a shared library or Java archive containing implementations of one or more services in one of the target programming languages supported by UNO. Such a component must meet basic requirements, mostly different for the different target language, and it must support the specification of the implemented services. That means all specified interfaces and properties must be implemented. Components must be registered in the UNO runtime system. After the registration all implemented services can be used by ordering an instance of the service at the appropriate service factory and accessing the functionality over interfaces.
Based on our example specifications for a TVSet and a RemoteControl service, a component RemoteTVImpl could simulate a remote TV system:
Illustration 3.4: RemoteTVImpl Component |
Such a RemoteTV component could be a jar file or a shared library. It would contain two service implementations, TVSet and RemoteControl. Once the RemoteTV component is registered with the global service manager, users can call the factory method of the service manager and ask for a TVSet or a RemoteControl service. Then they could use their functionality over the interfaces XPower, XChannel and XStandby. When a new implementation of these services with better performance or new features is available later on, the old component can be replaced without breaking existing code, provided that the new features are introduced by adding interfaces.
A struct type defines several elements in a record. The elements of a struct are UNO types with a unique name within the struct. Structs have the disadvantage not to encapsulate data, but the absence of get() and set() methods can help to avoid the overhead of method calls over a UNO bridge. UNO supports single inheritance for struct types. A derived struct recursively inherits all elements of the parent and its parents.
// com.sun.star.lang.EventObject
/** specifies the base for all event objects and identifies the
source of the event.
*/
struct EventObject
{
/** refers to the object that fired the event.
*/
com::sun::star::uno::XInterface Source;
};
// com.sun.star.beans.PropertyChangeEvent
struct PropertyChangeEvent : com::sun::star::lang::EventObject {
string PropertyName;
boolean Further;
long PropertyHandle;
any OldValue;
any NewValue;
};
A new feature of OpenOffice.org 2.0 is the polymorphic struct type. A polymorphic struct type template is similar to a plain struct type, but it has one or more type parameters, and its members can have these parameters as types. A polymorphic struct type template is not itself a UNO type—it has to be instantiated with actual type arguments to be used as a type.
// A polymorphic struct type template with two type parameters:
struct Poly<T,U> {
T member1;
T member2;
U member3;
long member4;
};
// Using an instantiation of Poly as a UNO type:
interface XIfc { Poly<boolean, any> fn(); };
In the example, Poly<boolean, any> will be an instantiated polymorphic struct type with the same form as the plain struct type
struct PolyBooleanAny {
boolean member1;
boolean member2;
any member3;
long member4;
};
Polymorphic struct types were added primarily to support rich interface type attributes that are as expressive as maybeambiguous, maybedefault, or maybevoid properties (see com.sun.star.beans.Ambiguous, com.sun.star.beans.Defaulted, com.sun.star.beans.Optional), but they are probably useful in other contexts, too.
The API offers many predefined values, that are used as method parameters, or returned by methods. In UNO IDL there are two different data types for predefined values: constants and enumerations.
A const defines a named value of a valid UNO IDL type. The value depends on the specified type and can be a literal (integer number, floating point number or a character), an identifier of another const type or an arithmetic term using the operators: +, -, *, /, ~, &, |, %, ^, <<, >>.
Since a wide selection of types and values is possible in a const, const is occasionally used to build bit vectors which encode combined values.
const short ID = 23;
const boolean ERROR = true;
const double PI = 3.1415;
Usually const definitions are part of a constants group.
The constants type defines a named group of const values. A const in a constants group is denoted by the group name and the const name. In the UNO IDL example below, ImageAlign.RIGHT refers to the value 2:
constants ImageAlign {
const short LEFT = 0;
const short TOP = 1;
const short RIGHT = 2;
const short BOTTOM = 3;
};
An enum type is equivalent to an enumeration type in C++. It contains an ordered list of one or more identifiers representing long values of the enum type. By default, the values are numbered sequentially, beginning with 0 and adding 1 for each new value. If an enum value has been assigned a value, all following enum values without a predefined value get a value starting from this assigned value.
// com.sun.star.uno.TypeClass
enum TypeClass {
VOID,
CHAR,
BOOLEAN,
BYTE,
SHORT,
...
};
enum Error {
SYSTEM = 10, // value 10
RUNTIME, // value 11
FATAL, // value 12
USER = 30, // value 30
SOFT // value 31
};
If enums are used during debugging, you should be able to derive the numeric value of an enum by counting its position in the API reference. However, never use literal numeric values instead of enums in your programs.
|
|
Once an enum type has been specified and published, you can trust that it is not extended later on, for that would break existing code. However, new const vaues may be added to a constant group. |
A sequence type is a set of elements of the same type, that has a variable number of elements. In UNO IDL, the used element always references an existing and known type or another sequence type. A sequence can occur as a normal type in all other type definitions.
sequence< com::sun::star::uno::XInterface >
sequence< string > getNamesOfIndex( sequence< long > indexes );
Modules are namespaces, similar to namespaces in C++ or packages in Java. They group services, interfaces, structs, exceptions, enums, typedefs, constant groups and submodules with related functional content or behavior. They are utilized to specify coherent blocks in the API, this allows for a well-structured API. For example, the module com.sun.star.text contains interfaces and other types for text handling. Some other typical modules are com.sun.star.uno, com.sun.star.drawing, com.sun.star.sheet and com.sun.star.table. Identifiers inside a module do not clash with identifiers in other modules, therefore it is possible for the same name to occur more than once. The global index of the API reference shows that this does happen.
Although it may seem that the modules correspond with the various parts of OpenOffice.org, there is no direct relationship between the API modules and the OpenOffice.org applications Writer, Calc and Draw. Interfaces from the module com.sun.star.text are used in Calc and Draw. Modules like com.sun.star.style or com.sun.star.document provide generic services and interfaces that are not specific to any one part of OpenOffice.org.
The modules you see in the API reference were defined by nesting UNO IDL types in module instructions. For example, the module com.sun.star.uno contains the interface XInterface:
module com {
module sun {
module star {
module uno {
interface XInterface {
...
};
};
};
};
};
An exception type indicates an error to the caller of a function. The type of an exception gives a basic description of the kind of error that occurred. In addition, the UNO IDL exception types contain elements which allow for an exact specification and a detailed description of the error. The exception type supports inheritance, this is freqzuently used to define a hierarchy of errors. Exceptions are only used to raise errors, not as method parameters or return types.
UNO IDL requires that all exceptions must inherit from com.sun.star.uno.Exception. This is a precondition for the UNO runtime.
// com.sun.star.uno.Exception is the base exception for all exceptions
exception Exception {
string Message;
Xinterface Context;
};
// com.sun.star.uno.RuntimeException is the base exception for serious problems
// occuring at runtime, usually programming errors or problems in the runtime environment
exception RuntimeException : com::sun::star::uno::Exception {
};
// com.sun.star.uno.SecurityException is a more specific RuntimeException
exception SecurityException : com::sun::star::uno::RuntimeException {
};
Exceptions may only be thrown by operations which were specified to do so. In contrast, com.sun.star.uno.RuntimeExceptions can always occur.
|
|
The methods acquire() and release of the UNO base interface com.sun.star.uno.XInterface are an exception to the above rule. They are the only operations that may not even throw runtime exceptions. But in Java and C++ programs, you do not use these methods directly, they are handled by the respective language binding. |
Singletons are used to specify named objects where exactly one instance can exist in the life of a UNO component context. A singleton references one interface type and specifies that the only existing instance of this singleton can be reached over the component context using the name of the singleton. If no instance of the singleton exists, the component context will instantiate a new one. An example of such a new-style singleton is
module com { module sun { module star { module deployment {
singleton thePackageManagerFactory: XPackageManagerFactory;
}; }; }; };
The various language bindings offer language-specific ways to obtain the instance of a new-style singleton, given a component context. For example, in Java and C++ there is a static method (resp. function) named get, that takes as its only argument an XComponentContext and returns the (appropriately typed) singleton instance. If the instance cannot be obtained, a com.sun.star.uno.DeploymentException is thrown.
There are also old-style singletons, which reference (old-style) services instead of interfaces. However, for old-style services, the language bindings offer no get functionality.
The API specifications you find in the API reference are abstract. The service descriptions of the API reference are not about classes that previously exist somewhere. The specifications are first, then the UNO implementation is created according to the specification. That holds true even for legacy implementations that had to be adapted to UNO.
Moreover, since a component developer is free to implement services and interfaces as required, there is not necessarily a one-to-one relationship between a certain service specification and a real object. The real object can be capable of more things than specified in a service definition. For example, if you order a service at the factory or receive an object from a getter or getPropertyValue() method, the specified features will be present, but there may be additional features. For instance, the text document model has a few interfaces which are not included in the specification for the com.sun.star.text.TextDocument.
Because of the optional interfaces and properties, it is impossible to comprehend fully from the API reference what a given instance of an object in OpenOffice.org is capable of. The optional interfaces and properties are correct for an abstract specification, but it means that when you leave the scope of mandatory interfaces and properties, the reference only defines how things are allowed to work, not how they actually work.
Another important point is the fact that there are several entry points where object implementations are actually available. You cannot instantiate every old-style service that can be found in the API reference by means of the global service manager. The reasons are:
Some old-style services need a certain context. For instance, it does not make sense to instantiate a com.sun.star.text.TextFrame independently from an existing text document or any other surrounding where it could be of any use. Such services are usually not created by the global service manager, but by document factories which have the necessary knowledge to create objects that work in a certain surrounding. That does not mean you will never be able to get a text frame from the global service manager to insert. So, if you wish to use a service in the API reference, ask yourself where you can get an instance that supports this service, and consider the context in which you want to use it. If the context is a document, it is quite possible that the document factory will be able to create the object.
Old-style services are not only used to specify possible class implementations. Sometimes they are used to specify nothing but groups of properties that can be referenced by other old-style services. That is, there are services with no interfaces at all. You cannot create such a service at the service manager.
A few old-style services need special treatment. For example, you cannot ask the service manager to create an instance of a com.sun.star.text.TextDocument. You must load it using the method loadComponentFromUrl() at the desktop's com.sun.star.frame.XComponentLoader interface.
In the first and the last case above, using multiple-inheritance interface types instead of old-style services would have been the right design choice, but the mentioned services predate the availability of multiple-inheritance interface types in UNO.
Consequently, it is sometimes confusing to look up a needed functionality in the API reference, for you need a basic understanding how a functionality works, which services are involved, where they are available etc., before you can really utilize the reference. This manual aims at giving you this understanding about the OpenOffice.org document models, the database integration and the application itself.
Interfaces support single and multiple inheritance, and they are all based on com.sun.star.uno.XInterface. In the API reference, this is mirrored in the Base Hierarchy section of any interface specification. If you look up an interface, always check the base hierarchy section to understand the full range of supported methods. For instance, if you look up com.sun.star.text.XText, you see two methods, insertTextContent() and removeTextContent(), but there are nine more methods provided by the inherited interfaces. The same applies to exceptions and sometimes also to structs, which support single inheritance as well.
The service specifications in the API reference can contain a section Included Services , which is similar to the above in that a single included old-style service might encompass a whole world of services. However, the fact that a service is included has nothing to do with class inheritance. In which manner a service implementation technically includes other services, by inheriting from base implementations, by aggregation, some other kind of delegation or simply by re-implementing everything is by no means defined (which it is not, either, for UNO interface inheritance). And it is uninteresting for an API user – he can absolutely rely on the availability of the described functionality, but he must never rely on inner details of the implementation, which classes provide the functionality, where they inherit from and what they delegate to other classes.
Now that you have an advanced understanding of OpenOffice.org API concepts and you understand the specification of UNO objects, we are ready to explore UNO, i.e. to see how UNO objects connect and communicate with each other.
UNO objects in different environments connect via the interprocess bridge. You can execute calls on UNO object instances, that are located in a different process. This is done by converting the method name and the arguments into a byte stream representation, and sending this package to the remote process, for example, through a socket connection. Most of the examples in this manual use the interprocess bridge to communicate with the OpenOffice.org.
This section deals with the creation of UNO interprocess connections using the UNO API.
Most examples in this developers guide connect to a running OpenOffice.org and perform API calls, which are then executed in OpenOffice.org. By default, the office does not listen on a resource for security reasons. This makes it necessary to make OpenOffice.org listen on an interprocess connection resource, for example, a socket. Currently this can be done in two ways:
Start the office with an additional parameter:
soffice -accept=socket,host=0,port=2002;urp;
This string has to be quoted on unix shells, because the semicolon ';' is interpreted by the shells
Place the same string without '-accept=' into a configuration file. You can edit the file
<OfficePath>/share/registry/data/org/openoffice/Setup.xcu
and replace the tag
<prop oor:name="ooSetupConnectionURL"/>
with
<prop oor:name="ooSetupConnectionURL">
<value>socket,host=localhost,port=2002;urp;StarOffice.ServiceManager
</value>
</prop>
If the tag is not present, add it within the tag
<node oor:name="Office"/>
This change affects the whole installation. If you want to configure it for a certain user in a network installation, add the same tag within the node <node oor:name="Office/> to the file Setup.xcu in the user dependent configuration directory <OfficePath>/user/registry/data/org/openoffice/
Choose the procedure that suits your requirements and launch OpenOffice.org in listening mode now. Check if it is listening by calling netstat -a or -na on the command-line. An output similar to the following shows that the office is listening:
TCP <Hostname>:8100 <Fully qualified hostname>: 0 Listening
If you use the -n option, netstat displays addresses and port numbers in numerical form. This is sometimes useful on UNIX systems where it is possible to assign logical names to ports.
If the office is not listening, it probably was not started with the proper connection URL parameter. Check the Setup.xcu file or your command-line for typing errors and try again.
|
|
Note: In versions before OpenOffice.org 1.1.0, there are several differences. The configuration setting that makes the office listen everytime is located elsewhere. Open the file <OfficePath>/share/config/registry/instance/org/openoffice/Setup.xml in an editor, and look for the element: <ooSetupConnectionURL cfg:type="string"/> Extend it with the following code: <ooSetupConnectionURL cfg:type="string"> The commandline option -accept is ignored when there is a running instance of the office, including the quick starter and the online help. If you use it, make sure that no soffice process runs on your system. |
The various parts of the connection URL will be discussed in the next section.
The most common use case of interprocess connections is to import a reference to a UNO object from an exporting server. For instance, most of the Java examples described in this manual retrieve a reference to the OpenOffice.org ComponentContext. The correct way to do this is using the com.sun.star.bridge.UnoUrlResolver service. Its main interface com.sun.star.bridge.XUnoUrlResolver is defined in the following way:
interface XUnoUrlResolver: com::sun::star::uno::XInterface
{
/** resolves an object on the UNO URL */
com::sun::star::uno::XInterface resolve( [in] string sUnoUrl )
raises (com::sun::star::connection::NoConnectException,
com::sun::star::connection::ConnectionSetupException,
com::sun::star::lang::IllegalArgumentException);
};
The string passed to the resolve() method is called a UNO URL. It must have the following format:
An example URL could be uno:socket,host=localhost,port=2002;urp;StarOffice.ServiceManager. The parts of this URL are:
The URL schema uno:. This identifies the URL as UNO URL and distinguishes it from others, such as http: or ftp: URLs.
A string which characterizes the type of connection to be used to access the other process. Optionally, directly after this string, a comma separated list of name-value pairs can follow, where name and value are separated by a '='. The currently supported connection types are described in 3.3.1 Professional UNO - UNO Concepts - UNO Interprocess Connections - Opening a Connection. The connection type specifies the transport mechanism used to transfer a byte stream, for example, TCP/IP sockets or named pipes.
A string which characterizes the type of protocol used to communicate over the established byte stream connection. The string can be followed by a comma separated list of name-value pairs, which can be used to customize the protocol to specific needs. The suggested protocol is urp (UNO Remote Protocol). Some useful parameters are explained below. Refer to the document named UNO-URL at udk.openoffice.org. for the complete specification.
A process must explicitly export a certain object by a distinct name. It is not possible to access an arbitrary UNO object (which would be possible with IOR in CORBA, for instance).
The following example demonstrates how to import an object using the UnoUrlResolver: (ProfUNO/InterprocessConn/UrlResolver.java):
XComponentContext xLocalContext =
com.sun.star.comp.helper.Bootstrap.createInitialComponentContext(null);
// initial serviceManager
XMultiComponentFactory xLocalServiceManager = xLocalContext.getServiceManager();
// create a URL resolver
Object urlResolver = xLocalServiceManager.createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", xLocalContext);
// query for the XUnoUrlResolver interface
XUnoUrlResolver xUrlResolver =
(XUnoUrlResolver) UnoRuntime.queryInterface(XUnoUrlResolver.class, urlResolver);
// Import the object
Object rInitialObject = xUrlResolver.resolve(
“uno:socket,host=localhost,port=2002;urp;StarOffice.ServiceManager”);
// XComponentContext
if (null != rInitialObject) {
System.out.println("initial object successfully retrieved");
} else {
System.out.println("given initial-object name unknown at server side");
}
The usage of the UnoUrlResolver has certain disadvantages. You cannot:
be notified when the bridge terminates for whatever reasons
close the underlying interprocess connection
offer a local object as an initial object to the remote process
These issues are addressed by the underlying API, which is explained below. in 3.3.1 Professional UNO - UNO Concepts - UNO Interprocess Connections - Opening a Connection.
The whole bridge is threadsafe and allows multiple threads to execute remote calls. The dispatcher thread inside the bridge cannot block because it never executes calls. It instead passes the requests to worker threads.
A synchronous call sends the request through the connection and lets the requesting thread wait for the reply. All calls that have a return value, an out parameter, or throw an exceptions other than a RuntimeException must be synchronous.
An asynchronous (or oneway) call sends the request through the connection and immediately returns without waiting for a reply. It is currently specified at the IDL interface if a request is synchronous or asynchronous by using the [oneway] modifier.
|
|
Although there are no general problems with the specification and the implementation of the UNO oneway feature, there are several API remote usage scenarios where oneway calls cause deadlocks in OpenOffice.org. Therefore do not introduce new oneway methods with new OpenOffice.org UNO APIs. |
For synchronous requests, thread identity is guaranteed. When process A calls process B, and process B calls process A, the same thread waiting in process A will take over the new request. This avoids deadlocks when the same mutex is locked again. For asynchronous requests, this is not possible because there is no thread waiting in process A. Such requests are executed in a new thread. The series of calls between two processes is guaranteed. If two asynchronous requests from process A are sent to process B, the second request waits until the first request is finished.
Although the remote bridge supports asynchronous calls, this feature is disabled by default. Every call is executed synchronously. The oneway flag of UNO interface methods is ignored. However, the bridge can be started in a mode that enables the oneway feature and thus executes calls flagged with the [oneway] modifier as asynchronous calls. To do this, the protocol part of the connection string on both sides of the remote bridge must be extended by ',Negotiate=0,ForceSynchronous=0' . For example:
soffice “-accept=socket,host=0,port=2002;urp,Negotiate=0,ForceSynchronous=0;”
for starting the office and
"uno:socket,host=localhost,port=2002;urp,Negotiate=0,ForceSynchronous=0;StarOffice.ServiceManager"
as UNO URL for connecting to it.
|
|
The asynchronous mode can cause deadlocks in OpenOffice.org. It is recommended not to activate it if one side of the remote bridge is OpenOffice.org. |
The method to import a UNO object using the UnoUrlResolver has drawbacks as described in the previous chapter. The layer below the UnoUrlResolver offers full flexibility in interprocess connection handling.
UNO interprocess bridges are established on the com.sun.star.connection.XConnection interface, which encapsulates a reliable bidirectional byte stream connection (such as a TCP/IP connection).
interface XConnection: com::sun::star::uno::XInterface
{
long read( [out] sequence < byte > aReadBytes , [in] long nBytesToRead )
raises( com::sun::star::io::IOException );
void write( [in] sequence < byte > aData )
raises( com::sun::star::io::IOException );
void flush( ) raises( com::sun::star::io::IOException );
void close( ) raises( com::sun::star::io::IOException );
string getDescription();
};
There are different mechanisms to establish an interprocess connection. Most of these mechanisms follow a similar pattern. One process listens on a resource and waits for one or more processes to connect to this resource.
This pattern has been abstracted by the services com.sun.star.connection.Acceptor that exports the com.sun.star.connection.XAcceptor interface and com.sun.star.connection.Connector that exports the com.sun.star.connection.XConnector interface.
interface XAcceptor: com::sun::star::uno::XInterface
{
XConnection accept( [in] string sConnectionDescription )
raises( AlreadyAcceptingException,
ConnectionSetupException,
com::sun::star::lang::IllegalArgumentException);
void stopAccepting();
};
interface XConnector: com::sun::star::uno::XInterface
{
XConnection connect( [in] string sConnectionDescription )
raises( NoConnectException,ConnectionSetupException );
};
The acceptor service is used in the listening process while the connector service is used in the actively connecting service. The methods accept() and connect() get the connection string as a parameter. This is the connection part of the UNO URL (between uno: and ;urp).
The connection string consists of a connection type followed by a comma separated list of name-value pairs. The following table shows the connection types that are supported by default.
|
Connection type |
| ||||||||||
|
socket |
| ||||||||||
|
pipe |
| ||||||||||
|
|
You can add more kinds of interprocess connections by implementing connector and acceptor services, and choosing the service name by the scheme com.sun.star.connection.Connector.<connection-type>, where <connection-type> is the name of the new connection type. If you implemented the service com.sun.star.connection.Connector.mytype, use the UnoUrlResolver with the URL 'uno:mytype,param1=foo;urp;StarOffice.ServiceManager' to establish the interprocess connection to the office. |
Illustration 3.5: The interaction of services that are needed to initiate a UNO interprocess bridge. The interfaces have been simplified. |
The XConnection instance can now be used to establish a UNO interprocess bridge on top of the connection, regardless if the connection was established with a Connector or Acceptor service (or another method). To do this, you must instantiate the service com.sun.star.bridge.BridgeFactory. It supports the com.sun.star.bridge.XBridgeFactory interface.
interface XBridgeFactory: com::sun::star::uno::XInterface
{
XBridge createBridge(
[in] string sName,
[in] string sProtocol ,
[in] com::sun::star::connection::XConnection aConnection ,
[in] XInstanceProvider anInstanceProvider )
raises ( BridgeExistsException , com::sun::star::lang::IllegalArgumentException );
XBridge getBridge( [in] string sName );
sequence < XBridge > getExistingBridges( );
};
The BridgeFactory service administrates all UNO interprocess connections. The createBridge() method creates a new bridge:
You can give the bridge a distinct name with the sName argument. Later the bridge can be retrieved by using the getBridge() method with this name. This allows two independent code pieces to share the same interprocess bridge. If you call createBridge() with the name of an already working interprocess bridge, a BridgeExistsException is thrown. When you pass an empty string, you always create a new anonymous bridge, which can never be retrieved by getBridge() and which never throws a BridgeExistsException.
The second parameter specifies the protocol to be used on the connection. Currently, only the 'urp' protocol is supported. In the UNO URL, this string is separated by two ';'. The urp string may be followed by a comma separated list of name-value pairs describing properties for the bridge protocol. The urp specification can be found on udk.openoffice.org.
The third parameter is the XConnection interface as it was retrieved by Connector/Acceptor service.
The fourth parameter is a UNO object, which supports the com.sun.star.bridge.XInstanceProvider interface. This parameter may be a null reference if you do not want to export a local object to the remote process.
interface XInstanceProvider: com::sun::star::uno::XInterface
{
com::sun::star::uno::XInterface getInstance( [in] string sInstanceName )
raises ( com::sun::star::container::NoSuchElementException );
};
The BridgeFactory returns a com.sun.star.bridge.XBridge interface.
interface XBridge: com::sun::star::uno::XInterface
{
XInterface getInstance( [in] string sInstanceName );
string getName();
string getDescription();
};
The XBridge.getInstance() method retrieves an initial object from the remote counterpart. The local XBridge.getInstance() call arrives in the remote process as an XInstanceProvider.getInstance() call. The object returned can be controlled by the string sInstanceName. It completely depends on the implementation of XInstanceProvider, which object it returns.
The XBridge interface can be queried for a com.sun.star.lang.XComponent interface, that adds a com.sun.star.lang.XEventListener to the bridge. This listener will be terminated when the underlying connection closes (see above). You can also call dispose() on the XComponent interface explicitly, which closes the underlying connection and initiates the bridge shutdown procedure.
The closure of an interprocess connection can occur for the following reasons:
The bridge is not used anymore. The interprocess bridge will close the connection when all the proxies to remote objects and all stubs to local objects have been released. This is the normal way for a remote bridge to destroy itself. The user of the interprocess bridge does not need to close the interprocess connection directly—it is done automatically. When one of the communicating processes is implemented in Java, the closure of a bridge is delayed to that point in time when the VM finalizes the last proxies/stubs. Therefore it is unspecified when the interprocess bridge will be closed.
The interprocess bridge is directly disposed by calling its dispose() method.
The remote counterpart process crashes.
The connection fails. For example, failure may be due to a dialup internet connection going down.
An error in marshalling/unmarshalling occurs due to a bug in the interprocess bridge implementation, or an IDL type is not available in one of the processes.
Except for the first reason, all other connection closures initiate an interprocess bridge shutdown procedure. All pending synchronous requests abort with a com.sun.star.lang.DisposedException, which is derived from the com.sun.star.uno.RuntimeException. Every call that is initiated on a disposed proxy throws a DisposedException. After all threads have left the bridge (there may be a synchronous call from the former remote counterpart in the process), the bridge explicitly releases all stubs to the original objects in the local process, which were previously held by the former remote counterpart. The bridge then notifies all registered listeners about the disposed state using com.sun.star.lang.XEventListener. The example code for a connection-aware client below shows how to use this mechanism. The bridge itself is destroyed, after the last proxy has been released.
Unfortunately, the various listed error conditions are not distinguishable.
The following example shows an advanced client which can be informed about the status of the remote bridge. A complete example for a simple client is given in the chapter 2 First Steps.
The following Java example opens a small awt window containing the buttons new writer and new calc that opens a new document and a status label. It connects to a running office when a button is clicked for the first time. Therefore it uses the connector/bridge factory combination, and registers itself as an event listener at the interprocess bridge.
When the office is terminated, the disposing event is terminated, and the Java program sets the text in the status label to 'disconnected' and clears the office desktop reference. The next time a button is pressed, the program knows that it has to re-establish the connection.
The method getComponentLoader() retrieves the XComponentLoader reference on demand:
(ProfUNO/InterprocessConn/ConnectionAwareClient.java)
XComponentLoader _officeComponentLoader = null;
// local component context
XComponentContext _ctx;
protected com.sun.star.frame.XComponentLoader getComponentLoader()
throws com.sun.star.uno.Exception {
XComponentLoader officeComponentLoader = _officeComponentLoader;
if (officeComponentLoader == null) {
// instantiate connector service
Object x = _ctx.getServiceManager().createInstanceWithContext(
"com.sun.star.connection.Connector", _ctx);
XConnector xConnector = (XConnector) UnoRuntime.queryInterface(XConnector.class, x);
// helper function to parse the UNO URL into a string array
String a[] = parseUnoUrl(_url);
if (null == a) {
throw new com.sun.star.uno.Exception("Couldn't parse UNO URL "+ _url);
}
// connect using the connection string part of the UNO URL only.
XConnection connection = xConnector.connect(a[0]);
x = _ctx.getServiceManager().createInstanceWithContext(
"com.sun.star.bridge.BridgeFactory", _ctx);
XBridgeFactory xBridgeFactory = (XBridgeFactory) UnoRuntime.queryInterface(
XBridgeFactory.class , x);
// create a nameless bridge with no instance provider
// using the middle part of the UNO URL
XBridge bridge = xBridgeFactory.createBridge("" , a[1] , connection , null);
// query for the XComponent interface and add this as event listener
XComponent xComponent = (XComponent) UnoRuntime.queryInterface(
XComponent.class, bridge);
xComponent.addEventListener(this);
// get the remote instance
x = bridge.getInstance(a[2]);
// Did the remote server export this object ?
if (null == x) {
throw new com.sun.star.uno.Exception(
"Server didn't provide an instance for" + a[2], null);
}
// Query the initial object for its main factory interface
XMultiComponentFactory xOfficeMultiComponentFactory = (XMultiComponentFactory)
UnoRuntime.queryInterface(XMultiComponentFactory.class, x);
// retrieve the component context (it's not yet exported from the office)
// Query for the XPropertySet interface.
XPropertySet xProperySet = (XPropertySet)
UnoRuntime.queryInterface(XPropertySet.class, xOfficeMultiComponentFactory);
// Get the default context from the office server.
Object oDefaultContext =
xProperySet.getPropertyValue("DefaultContext");
// Query for the interface XComponentContext.
XComponentContext xOfficeComponentContext =
(XComponentContext) UnoRuntime.queryInterface(
XComponentContext.class, oDefaultContext);
// now create the desktop service
// NOTE: use the office component context here !
Object oDesktop = xOfficeMultiComponentFactory.createInstanceWithContext(
"com.sun.star.frame.Desktop", xOfficeComponentContext);
officeComponentLoader = (XComponentLoader)
UnoRuntime.queryInterface( XComponentLoader.class, oDesktop);
if (officeComponentLoader == null) {
throw new com.sun.star.uno.Exception(
"Couldn't instantiate com.sun.star.frame.Desktop" , null);
}
_officeComponentLoader = officeComponentLoader;
}
return officeComponentLoader;
}
This is the button event handler:
public void actionPerformed(ActionEvent event) {
try {
String sUrl;
if (event.getSource() == _btnWriter) {
sUrl = "private:factory/swriter";
} else {
sUrl = "private:factory/scalc";
}
getComponentLoader().loadComponentFromURL(
sUrl, "_blank", 0,new com.sun.star.beans.PropertyValue[0]);
_txtLabel.setText("connected");
} catch (com.sun.star.connection.NoConnectException exc) {
_txtLabel.setText(exc.getMessage());
} catch (com.sun.star.uno.Exception exc) {
_txtLabel.setText(exc.getMessage());
exc.printStackTrace();
throw new java.lang.RuntimeException(exc.getMessage());
}
}
And the disposing handler clears the _officeComponentLoader reference:
public void disposing(com.sun.star.lang.EventObject event) {
// remote bridge has gone down, because the office crashed or was terminated.
_officeComponentLoader = null;
_txtLabel.setText("disconnected");
}
This chapter discusses the root object for connections to OpenOffice.org (and to any UNO application) – the service manager. The root object serves as the entry point for every UNO application and is passed to every UNO component during instantiation.
Two different concepts to get the root object currently exist. StarOffice6.0 and OpenOffice.org1.0 use the previous concept. Newer versions or product patches use the newer concept and provide the previous concept for compatibility issues only. First we will look at the previous concept, the service manager as it is used in the main parts of the underlying OpenOffice.org implementation of this guide. Second, we will introduce the component context—which is the newer concept and explain the migration path.
The com.sun.star.lang.ServiceManager is the main factory in every UNO application. It instantiates services by their service name, to enumerate all implementations of a certain service, and to add or remove factories for a certain service at runtime. The service manager is passed to every UNO component during instantiation.
The main interface of the service manager is the com.sun.star.lang.XMultiServiceFactory interface. It offers three methods: createInstance(), createInstanceWithArguments() and getAvailableServiceNames().
interface XMultiServiceFactory: com::sun::star::uno::XInterface
{
com::sun::star::uno::XInterface createInstance( [in] string aServiceSpecifier )
raises( com::sun::star::uno::Exception );
com::sun::star::uno::XInterface createInstanceWithArguments(
[in] string ServiceSpecifier,
[in] sequence<any> Arguments )
raises( com::sun::star::uno::Exception );
sequence<string> getAvailableServiceNames();
};
createInstance() returns a default constructed service instance. The returned service is guaranteed to support at least all interfaces, which were specified for the requested servicename. The returned XInterface reference can now be queried for the interfaces specified at the service description.
When using the service name, the caller does not have any influence on which concrete implementation is instantiated. If multiple implementations for a service exist, the service manager is free to decide which one to employ. This in general does not make a difference to the caller because every implementation does fulfill the service contract. Performance or other details may make a difference. So it is also possible to pass the implementation name instead of the service name, but it is not advised to do so as the implementation name may change.
In case the service manager does not provide an implementation for a request, a null reference is returned, so it is mandatory to check. Every UNO exception may be thrown during instantiation. Some may be described in the specification of the service that is to be instantiated, for instance, because of a misconfiguration of the concrete implementation. Another reason may be the lack of a certain bridge, for instance the Java-C++ bridge, in case a Java component shall be instantiated from C++ code.
createInstanceWithArguments() instantiates the service with additional parameters. A service signals that it expects parameters during instantiation by supporting the com.sun.star.lang.XInitialization interface. The service definition should describe the meaning of each element of the sequence. There maybe services which can only be instantiated with parameters.
getAvailableServiceNames() returns every servicename the service manager does support.
The com.sun.star.container.XContentEnumerationAccess interface allows the creation of an enumeration of all implementations of a concrete servicename.
interface XContentEnumerationAccess: com::sun::star::uno::XInterface
{
com::sun::star::container::XEnumeration createContentEnumeration( [in] string aServiceName );
sequence<string> getAvailableServiceNames();
};
The createContentEnumeration() method returns a com.sun.star.container.XEnumeration interface. Note that it may return an empty reference in case the enumeration is empty.
interface XEnumeration: com::sun::star::uno::XInterface
{
boolean hasMoreElements();
any nextElement()
raises( com::sun::star::container::NoSuchElementException,
com::sun::star::lang::WrappedTargetException );
};
In the above case, the returned any of the method Xenumeration.nextElement() contains a com.sun.star.lang.XSingleServiceFactory interface for each implementation of this specific service. You can, for instance, iterate over all implementations of a certain service and check each one for additional implemented services. The XSingleServiceFactory interface provides such a method. With this method, you can instantiate a feature rich implementation of a service.
The com.sun.star.container.XSet interface allows the insertion or removal of com.sun.star.lang.XSingleServiceFactory or com.sun.star.lang.XSingleComponentFactory implementations to the service manager at runtime without making the changes permanent. When the office application terminates, all the changes are lost. The object must also support the com.sun.star.lang.XServiceInfo interface that provides information about the implementation name and supported services of the component implementation.