Difference between revisions of "Documentation/DevGuide/FirstSteps/Using Services"

From Apache OpenOffice Wiki
Jump to: navigation, search
(correct idlm tag for queryInterface method)
(21 intermediate revisions by 7 users not shown)
Line 1: Line 1:
{{Documentation/APIGuide/FirstStepsTOC|FirstSteps=block|FirstSteps2b=block|PrevNext=block|Prev=Documentation/APIGuide/FirstSteps/Objects, Interfaces, and Services|Next=Documentation/APIGuide/FirstSteps/Example: Working with a Spreadsheet Document}}
+
{{Documentation/DevGuide/FirstStepsTOC
 +
|FirstSteps2b=block
 +
|ShowPrevNext=block
 +
|PrevPage=Documentation/DevGuide/FirstSteps/Objects, Interfaces, and Services
 +
|NextPage=Documentation/DevGuide/FirstSteps/Example: Working with a Spreadsheet Document
 +
}}
 +
{{Documentation/DevGuideLanguages|Documentation/DevGuide/FirstSteps/{{SUBPAGENAME}}}}
 
{{DISPLAYTITLE:Using Services}}
 
{{DISPLAYTITLE:Using Services}}
 
The concepts of interfaces and services were introduced for the following reasons:
 
The concepts of interfaces and services were introduced for the following reasons:
  
 
'''Interfaces and services separate specification from implementation'''
 
'''Interfaces and services separate specification from implementation'''
: The specification of an interface or service is ''abstract'', that is, it does not define how objects supporting a certain functionality do this ''internally''. Through the abstract specification of the {{PRODUCTNAME}} API, it is possible to pull the implementation out from under the API and install a different implementation if required.
+
: The specification of an interface or service is ''abstract'', that is, it does not define how objects supporting a certain functionality do this ''internally''. Through the abstract specification of the {{OOo}} API, it is possible to pull the implementation out from under the API and install a different implementation if required.
  
 
'''Service names allow to create instances by specification name, not by class names'''
 
'''Service names allow to create instances by specification name, not by class names'''
: In Java or C++ you use the new operator to create a class instance. This approach is restricted: the class you get is hard-coded. You cannot later on exchange it by another class without editing the code. The concept of services solves this. The central object factory in {{PRODUCTNAME}} the global service manager, is asked to create an object that can be used for a certain purpose without defining its internal implementation. This is possible, because a service can be ordered from the factory by its ''service name'' and the factory decides which service implementation it returns. Which implementation you get makes no difference, you only use the well-defined interface of the service.
+
: In Java or C++ you use the new operator to create a class instance. This approach is restricted: the class you get is hard-coded. You cannot later on exchange it by another class without editing the code. The concept of services solves this. The central object factory in {{OOo}}, the global service manager, is asked to create an object that can be used for a certain purpose without defining its internal implementation. This is possible because a service can be ordered from the factory by its ''service name'' and the factory decides which service implementation it returns. Which implementation you get makes no difference, you only use the well-defined interface of the service.
  
'''Multiple-inheritance interfaces make fine-grained interfaces manageable'''
+
===Interfaces===
: Abstract interfaces are more reusable if they are fine-grained, i.e., if they are small and describe only one aspect of an object, not several aspects. But then you need many of them to describe a useful object. Multiple-inheritance interfaces allow to have fine-grained interfaces on the one hand and to manage them easily by forging them into a collection. Since it is quite probable that objects in an office environment will share many aspects, this fine granularity allows the interfaces to be reused and thus to get objects that behave consistently. For instance, it was possible to realize a unified way to handle text, no matter if you are dealing with body text, text frames, header or footer text, footnotes, table cells or text in drawing shapes. It was not necessary to define separate interfaces for all of these purposes.
+
Abstract interfaces are more reusable if they are fine-grained, i.e., if they are small and describe only a single aspect of an object. To describe the many aspects of an object, objects can implement more than one of these fine-grained interfaces.  Being able to implement multiple interfaces allows similar aspects of similar objects to be accessed with the same code. For example, many objects support text:  text may be found in the body of a document, in text frames, in headers and footers, footnotes, table cells, and in drawing shapes. These objects all support the same interface, so a procedure can use, for example, getText() to retrieve text from ''any'' of these objects.
  
Let us consider the old-style service [http://api.openoffice.org/docs/common/ref/com/sun/star/text/TextDocument.html com.sun.star.text.TextDocument] in UML notation. The UML chart shown below depicts the mandatory interfaces of a <code>TextDocument</code> service. These interfaces express the basic aspects of a text document in {{PRODUCTNAME}} It contains text, it is searchable and refreshable. It is a model with URL and controller, and it is modifiable, printable and storable. The UML chart shows how this is specified in the API.
+
Services, interfaces, and methods are illustrated in the figure below for the old-style service <idl>com.sun.star.text.TextDocument</idl>, shown using [http://en.wikipedia.org/wiki/Unified_Modeling_Language UML] notation. In this figure, services are shown on the left side.  The arrow between services indicates that one service provided by the upper (arrowhead) service are inherited by the lower service. Interfaces exported by these services are shown on the right.  All interface names in the {{OOo}} API start with an X, so as to be distinguishable from the names of other entities.   Each interface contains methods, which are listed beneath the interface.
  
[[Image:TextDocumentWithMethods.png|none|thumb|400px|Text Document]]
+
[[Image:TextDocumentWithMethods.png|none|thumb|450px|Figure.  TextDocument inherits the methods of OfficeDocument.]]
  
On the left side of the illustration, the services [http://api.openoffice.org/docs/common/ref/com/sun/star/text/TextDocument.html com.sun.star.text.TextDocument] and [http://api.openoffice.org/docs/common/ref/com/sun/star/document/OfficeDocument.html com.sun.star.document.OfficeDocument] are shown. Every <code>TextDocument</code> must include these services by definition.
+
A <code>TextDocument</code> object provides the <idl>com.sun.star.text.TextDocument</idl> service, which implements the interfaces, <code>XTextDocument</code>, <code>XSearchable</code>, and <code>XRefreshable</code>.  These interfaces provide, for example, the methods <code>getText()</code>, for adding text to a document, and <code>findAll()</code>, for searching the document.
  
On the right side of the illustration, you find the interfaces, that the services must export. Their method compartments list the methods contained in the various interfaces. In the {{PRODUCTNAME}} API, all interface names have to start with an X to be distinguishable from the names of other entities.
+
As indicated by the arrow, the <idl>com.sun.star.text.TextDocument</idl> service also inherits all the interfaces provided by the <idl>com.sun.star.document.OfficeDocument</idl> service, so these interfaces are also provided to a <code>TextDocument</code> object. These interfaces handle tasks common to the {{OOo}} applications:  printing, <code>XPrintable</code>; storing, <code>XStorable</code>; modifying, <code>XModifiable</code>; and model handling, <code>XModel</code>.
  
Every <code>TextDocument</code> object must support three interfaces: <code>XTextDocument</code>, <code>XSearchable</code>, and <code>XRefreshable</code>. In addition, because a <code>TextDocument</code> is always an <code>OfficeDocument</code>, it must also support the interfaces <code>XPrintable</code>, <code>XStorable</code>, <code>XModifiable</code> and <code>XModel</code>. The methods contained in these interfaces cover these aspects: printing, storing, modification and model handling.
+
The interfaces shown in the figure are only the mandatory interfaces of a <code>TextDocument</code> object. A <code>TextDocument</code> has optional properties and interfaces, among them the properties <code>CharacterCount</code>, <code>ParagraphCount</code> and <code>WordCount</code>, and the interface  <code>XPropertySet</code>, which must be supported if properties are present at all. The implementation of the <code>TextDocument</code> service in {{OOo}} supports both required and all optional interfaces as well. The usage of a <code>TextDocument</code> is described thoroughly in [[Documentation/DevGuide/Text/Text Documents|Text Documents]].
  
Note that the interfaces shown in the illustration are only the mandatory interfaces of a <code>TextDocument</code>. A <code>TextDocument</code> has optional properties and interfaces, among them the properties <code>CharacterCount</code>, <code>ParagraphCount</code> and <code>WordCount</code> and the <code>XPropertySet</code> interface which must be supported if properties are present at all. The current implementation of the <code>TextDocument</code> service in {{PRODUCTNAME}} does not only support these interfaces, but all optional interfaces as well. The usage of a <code>TextDocument</code> is described thoroughly in [[Documentation/APIGuide/Text/Text Documents|Text Documents]].
+
C++ and Java require that the interface name be provided when accessing a method.  An old-style service may provide several interfaces to keep track of. New-style services are easier to use because, since they have just one interface, the multiple-inheritance interface, all the methods are accessed through the same interface.
  
 
===Using Interfaces===
 
===Using Interfaces===
  
<!--[TOPIC:com.sun.star.uno.XInterface]-->
+
<!--<idltopic>com.sun.star.uno.XInterface</idltopic>-->
 
The fact that every UNO object must be accessed through its interfaces has an effect in languages like Java and C++, where the compiler needs the correct type of an object reference before you can call a method from it. In Java or C++, you normally just cast an object before you access an interface it implements. When working with UNO objects this is different: You must ask the UNO environment to get the appropriate reference for you whenever you want to access methods of an interface which your object supports, but your compiler does not yet know about. Only then you can cast it safely.
 
The fact that every UNO object must be accessed through its interfaces has an effect in languages like Java and C++, where the compiler needs the correct type of an object reference before you can call a method from it. In Java or C++, you normally just cast an object before you access an interface it implements. When working with UNO objects this is different: You must ask the UNO environment to get the appropriate reference for you whenever you want to access methods of an interface which your object supports, but your compiler does not yet know about. Only then you can cast it safely.
  
The Java UNO environment has a method <code>queryInterface()</code> for this purpose. It looks complicated at first sight, but once you understand that <code>queryInterface()</code> is about safe casting of UNO types across process boundaries, you will soon get used to it. Take a look to the second example FirstLoadComponent <!--[SOURCE:FirstSteps/FirstLoadComponent.java]--> where a new Desktop object is created and afterwards the [http://api.openoffice.org/docs/common/ref/com/sun/star/uno/XInterface.html#queryInterface queryInterface()] method is used to get the [http://api.openoffice.org/docs/common/ref/com/sun/star/frame/XComponentLoader.html XComponentLoader] interface.
+
The Java UNO environment has a method <code>queryInterface()</code> for this purpose. It looks complicated at first sight, but once you understand that <code>queryInterface()</code> is about safe casting of UNO types across process boundaries, you will soon get used to it. Take a look at the second example FirstLoadComponent.java (in the sample directory, if you have installed the SDK on your computer), where a new Desktop object is created and, afterwards, the <idlm>com.sun.star.uno.XInterface:queryInterface</idlm>() method is used to get the <idls>com.sun.star.frame.XComponentLoader</idls> interface.
  
 +
  <source lang="java">
 
   Object desktop = xRemoteServiceManager.createInstanceWithContext(
 
   Object desktop = xRemoteServiceManager.createInstanceWithContext(
 
                 "com.sun.star.frame.Desktop", xRemoteContext);
 
                 "com.sun.star.frame.Desktop", xRemoteContext);
Line 36: Line 43:
 
   XComponentLoader xComponentLoader = (XComponentLoader)
 
   XComponentLoader xComponentLoader = (XComponentLoader)
 
                 UnoRuntime.queryInterface(XComponentLoader.class, desktop);
 
                 UnoRuntime.queryInterface(XComponentLoader.class, desktop);
 +
  </source>
  
We asked the service manager to create a [http://api.openoffice.org/docs/common/ref/com/sun/star/frame/Desktop.html com.sun.star.frame.Desktop] using its factory method createInstanceWithContext(). This method is defined to return a Java Object type, which should not surprise you—after all the factory must be able to return any type:
+
We asked the service manager to create a <idl>com.sun.star.frame.Desktop</idl> using its factory method createInstanceWithContext(). This method is defined to return a Java Object type, which should not surprise you—after all the factory must be able to return any type:
  
 +
  <source lang="java">
 
   java.lang.Object createInstanceWithContext(String serviceName, XComponentContext context)
 
   java.lang.Object createInstanceWithContext(String serviceName, XComponentContext context)
 +
  </source>
  
The object we receive is a [http://api.openoffice.org/docs/common/ref/com/sun/star/frame/Desktop.html com.sun.star.frame.Desktop] service.
+
The object we receive is a <idl>com.sun.star.frame.Desktop</idl> service.  The point is, while we know that the object we ordered at the factory is a DesktopUnoUrlResolver and exports among other interfaces the interface <code>XComponentLoader</code>, the compiler does ''not''. Therefore, we have to use the UNO runtime environment to ask or ''query'' for the interface <code>XComponentLoader</code>, since we want to use the <code>loadComponentFromURL()</code> method on this interface. The method <code>queryInterface()</code> makes sure we get a reference that can be cast to the needed interface type, no matter if the target object is a local or a remote object. There are two <code>queryInterface</code> definitions in the Java UNO language binding:
 
+
The following figure is a simplified specification in UML notation showing the relation to the [http://api.openoffice.org/docs/common/ref/com/sun/star/frame/Frame.html com.sun.star.frame.Frame] service and the supported interfaces.The point is, while we know that the object we ordered at the factory is a DesktopUnoUrlResolver and exports among other interfaces the interface <code>XComponentLoader</code>, the compiler does ''not''. Therefore, we have to use the UNO runtime environment to ask or ''query'' for the interface <code>XComponentLoader</code>, since we want to use the <code>loadComponentFromURL()</code> method on this interface. The method <code>queryInterface()</code> makes sure we get a reference that can be cast to the needed interface type, no matter if the target object is a local or a remote object. There are two <code>queryInterface</code> definitions in the Java UNO language binding:
+
  
 +
  <source lang="java">
 
   java.lang.Object UnoRuntime.queryInterface(java.lang.Class targetInterface, Object sourceObject)
 
   java.lang.Object UnoRuntime.queryInterface(java.lang.Class targetInterface, Object sourceObject)
 
   java.lang.Object UnoRuntime.queryInterface(com.sun.star.uno.Type targetInterface, Object sourceObject)
 
   java.lang.Object UnoRuntime.queryInterface(com.sun.star.uno.Type targetInterface, Object sourceObject)
 +
  </source>
  
 
Since <code>UnoRuntime.queryInterface()</code> is specified to return a java.lang.Object just like the factory method <code>createInstanceWithContext()</code>, we still must explicitly cast our interface reference to the needed type. The difference is that after <code>queryInterface()</code> we can safely cast the object to our interface type and, most important, that the reference will now work even with an object in another process. Here is the <code>queryInterface()</code> call, explained step by step:
 
Since <code>UnoRuntime.queryInterface()</code> is specified to return a java.lang.Object just like the factory method <code>createInstanceWithContext()</code>, we still must explicitly cast our interface reference to the needed type. The difference is that after <code>queryInterface()</code> we can safely cast the object to our interface type and, most important, that the reference will now work even with an object in another process. Here is the <code>queryInterface()</code> call, explained step by step:
  
 +
  <source lang="java">
 
   XComponentLoader xComponentLoader = (XComponentLoader)
 
   XComponentLoader xComponentLoader = (XComponentLoader)
 
                   UnoRuntime.queryInterface(XComponentLoader.class, desktop);
 
                   UnoRuntime.queryInterface(XComponentLoader.class, desktop);
    
+
   </source>
 +
 
 
<code>XComponentLoader</code> is the interface we want to use, so we define a <code>XComponentLoader</code> variable named <code>xComponentLoader</code> (lower x) to store the interface we expect from <code>queryInterface</code>.  
 
<code>XComponentLoader</code> is the interface we want to use, so we define a <code>XComponentLoader</code> variable named <code>xComponentLoader</code> (lower x) to store the interface we expect from <code>queryInterface</code>.  
 
Then we query our desktop object for the <code>XComponentLoader</code> interface, passing in <code>XComponentLoader.class</code> as target interface and desktop as source object. Finally we cast the outcome to <code>XComponentLoader</code> and assign the resulting reference to our variable <code>xComponentLoader</code>.
 
Then we query our desktop object for the <code>XComponentLoader</code> interface, passing in <code>XComponentLoader.class</code> as target interface and desktop as source object. Finally we cast the outcome to <code>XComponentLoader</code> and assign the resulting reference to our variable <code>xComponentLoader</code>.
Line 59: Line 71:
 
In Java, this call to <code>queryInterface()</code> is necessary whenever you have a reference to an object which is known to support an interface that you need, but you do not have the proper reference type yet. Fortunately, you are not only allowed to <code>queryInterface()</code> from <code>java.lang.Object</code> source types, but you may also query an interface from another interface reference, like this:
 
In Java, this call to <code>queryInterface()</code> is necessary whenever you have a reference to an object which is known to support an interface that you need, but you do not have the proper reference type yet. Fortunately, you are not only allowed to <code>queryInterface()</code> from <code>java.lang.Object</code> source types, but you may also query an interface from another interface reference, like this:
  
 +
  <source lang="java">
 
   // loading a blank spreadsheet document gives us its XComponent interface:
 
   // loading a blank spreadsheet document gives us its XComponent interface:
 
   XComponent xComponent = xComponentLoader.loadComponentFromURL(
 
   XComponent xComponent = xComponentLoader.loadComponentFromURL(
Line 66: Line 79:
 
   XSpreadsheetDocument xSpreadsheetDocument = (XSpreadsheetDocument)UnoRuntime.queryInterface(
 
   XSpreadsheetDocument xSpreadsheetDocument = (XSpreadsheetDocument)UnoRuntime.queryInterface(
 
                   XSpreadsheetDocument.class, xComponent);   
 
                   XSpreadsheetDocument.class, xComponent);   
 +
  </source>
  
Furthermore, if a method is defined in such a way that it already returns an interface type, you do not need to query the interface, but you can use its methods right away. In the snippet above, the method <code>loadComponentFromURL</code> is specified to return an [http://api.openoffice.org/docs/common/ref/com/sun/star/lang/XComponent.html com.sun.star.lang.XComponent] interface, so you may call the <code>XComponent</code> methods <code>addEventListener()</code> and <code>removeEventListener()</code> directly at the <code>xComponent</code> variable, if you want to be notified that the document is being closed.
+
Furthermore, if a method is defined in such a way that it already returns an interface type, you do not need to query the interface, but you can use its methods right away. In the snippet above, the method <code>loadComponentFromURL</code> is specified to return an <idl>com.sun.star.lang.XComponent</idl> interface, so you may call the <code>XComponent</code> methods <code>addEventListener()</code> and <code>removeEventListener()</code> directly at the <code>xComponent</code> variable, if you want to be notified that the document is being closed.
 
The corresponding step in C++ is done by a <code>Reference<></code> template that takes the source instance as parameter:
 
The corresponding step in C++ is done by a <code>Reference<></code> template that takes the source instance as parameter:
  
 +
  <source lang="java">
 
   // instantiate a sample service with the servicemanager.
 
   // instantiate a sample service with the servicemanager.
 
   Reference< XInterface > rInstance =
 
   Reference< XInterface > rInstance =
Line 78: Line 93:
 
   // Query for the XComponentLoader interface
 
   // Query for the XComponentLoader interface
 
   Reference< XComponentLoader > rComponentLoader( rInstance, UNO_QUERY );
 
   Reference< XComponentLoader > rComponentLoader( rInstance, UNO_QUERY );
 +
  </source>
  
In {{PRODUCTNAME}} Basic, querying for interfaces is not necessary, the Basic runtime engine takes care about that internally.
+
In {{OOo}} Basic, querying for interfaces is not necessary; the Basic runtime engine takes care of that internally.
With the proliferation of multiple-inheritance interfaces in the {{PRODUCTNAME}} API, there will be less of a demand to explicitly query for specific interfaces in Java or C++. For example, with the hypothetical interfaces
+
With the proliferation of multiple-inheritance interfaces in the {{OOo}} API, there will be less of a demand to explicitly query for specific interfaces in Java or C++. For example, with the hypothetical interfaces
  
 +
  <source lang="idl">
 
   interface XBase1 {  void fun1();
 
   interface XBase1 {  void fun1();
 
   };
 
   };
Line 93: Line 110:
 
   interface XFactory {
 
   interface XFactory {
 
       XBoth getBoth();};
 
       XBoth getBoth();};
 +
  </source>
  
 
you can directly call both <code>fun1()</code> and <code>fun2()</code> on a reference obtained through <code>XFactory.getBoth()</code>, without querying for either <code>XBase1</code> or <code>XBase2</code>.
 
you can directly call both <code>fun1()</code> and <code>fun2()</code> on a reference obtained through <code>XFactory.getBoth()</code>, without querying for either <code>XBase1</code> or <code>XBase2</code>.
  
 
===Using Properties===
 
===Using Properties===
<!--[TOPIC:com.sun.star.beans.XPropertySet]-->
+
<!--<idltopic>com.sun.star.beans.XPropertySet</idltopic>-->
An object must offer its properties through interfaces that allow you to work with properties. The most basic form of these interfaces is the interface [http://api.openoffice.org/docs/common/ref/com/sun/star/beans/XPropertySet.html com.sun.star.beans.XPropertySet]. There are other interfaces for properties, such as [http://api.openoffice.org/docs/common/ref/com/sun/star/beans/XMultiPropertySet.html com.sun.star.beans.XMultiPropertySet], that gets and sets a multitude of properties with a single method call. The <code>XPropertySet</code> is always supported when properties are present in a service.
+
An object must offer its properties through interfaces that allow you to work with properties. The most basic form of these interfaces is the interface <idl>com.sun.star.beans.XPropertySet</idl>. There are other interfaces for properties, such as <idl>com.sun.star.beans.XMultiPropertySet</idl>, that gets and sets a multitude of properties with a single method call. The <code>XPropertySet</code> is always supported when properties are present in a service.
  
 
In <code>XPropertySet</code>, two methods carry out the property access, which are defined in Java as follows:  
 
In <code>XPropertySet</code>, two methods carry out the property access, which are defined in Java as follows:  
  
 +
  <source lang="java">
 
   void setPropertyValue(String propertyName, Object propertyValue)
 
   void setPropertyValue(String propertyName, Object propertyValue)
 
   Object getPropertyValue(String propertyName)
 
   Object getPropertyValue(String propertyName)
 +
  </source>
  
 
In the FirstLoadComponent example, the <code>XPropertySet</code> interface was used to set the CellStyle property at a cell object. The cell object was a <code>com.sun.star.sheet.SheetCell</code> and therefore supports also the <code>com.sun.star.table.CellProperties</code> service which had a property <code>CellStyle</code>. The following code explains how this property was set:
 
In the FirstLoadComponent example, the <code>XPropertySet</code> interface was used to set the CellStyle property at a cell object. The cell object was a <code>com.sun.star.sheet.SheetCell</code> and therefore supports also the <code>com.sun.star.table.CellProperties</code> service which had a property <code>CellStyle</code>. The following code explains how this property was set:
  
 +
  <source lang="java">
 
   // query the XPropertySet interface from cell object
 
   // query the XPropertySet interface from cell object
 
   XPropertySet xCellProps = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, xCell);
 
   XPropertySet xCellProps = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, xCell);
Line 112: Line 133:
 
   // set the CellStyle property
 
   // set the CellStyle property
 
   xCellProps.setPropertyValue("CellStyle", "Result");
 
   xCellProps.setPropertyValue("CellStyle", "Result");
 +
  </source>
 
    
 
    
 
You are now ready to start working with a {{PRODUCTNAME}} document.
 
You are now ready to start working with a {{PRODUCTNAME}} document.
  
 
{{PDL1}}
 
{{PDL1}}
[[Category: First Steps]]
+
 
 +
[[Category:Documentation/Developer's Guide/First Steps]]

Revision as of 11:13, 27 May 2009



The concepts of interfaces and services were introduced for the following reasons:

Interfaces and services separate specification from implementation

The specification of an interface or service is abstract, that is, it does not define how objects supporting a certain functionality do this internally. Through the abstract specification of the Apache OpenOffice API, it is possible to pull the implementation out from under the API and install a different implementation if required.

Service names allow to create instances by specification name, not by class names

In Java or C++ you use the new operator to create a class instance. This approach is restricted: the class you get is hard-coded. You cannot later on exchange it by another class without editing the code. The concept of services solves this. The central object factory in Apache OpenOffice, the global service manager, is asked to create an object that can be used for a certain purpose without defining its internal implementation. This is possible because a service can be ordered from the factory by its service name and the factory decides which service implementation it returns. Which implementation you get makes no difference, you only use the well-defined interface of the service.

Interfaces

Abstract interfaces are more reusable if they are fine-grained, i.e., if they are small and describe only a single aspect of an object. To describe the many aspects of an object, objects can implement more than one of these fine-grained interfaces. Being able to implement multiple interfaces allows similar aspects of similar objects to be accessed with the same code. For example, many objects support text: text may be found in the body of a document, in text frames, in headers and footers, footnotes, table cells, and in drawing shapes. These objects all support the same interface, so a procedure can use, for example, getText() to retrieve text from any of these objects.

Services, interfaces, and methods are illustrated in the figure below for the old-style service com.sun.star.text.TextDocument, shown using UML notation. In this figure, services are shown on the left side. The arrow between services indicates that one service provided by the upper (arrowhead) service are inherited by the lower service. Interfaces exported by these services are shown on the right. All interface names in the Apache OpenOffice API start with an X, so as to be distinguishable from the names of other entities. Each interface contains methods, which are listed beneath the interface.

Figure. TextDocument inherits the methods of OfficeDocument.

A TextDocument object provides the com.sun.star.text.TextDocument service, which implements the interfaces, XTextDocument, XSearchable, and XRefreshable. These interfaces provide, for example, the methods getText(), for adding text to a document, and findAll(), for searching the document.

As indicated by the arrow, the com.sun.star.text.TextDocument service also inherits all the interfaces provided by the com.sun.star.document.OfficeDocument service, so these interfaces are also provided to a TextDocument object. These interfaces handle tasks common to the Apache OpenOffice applications: printing, XPrintable; storing, XStorable; modifying, XModifiable; and model handling, XModel.

The interfaces shown in the figure are only the mandatory interfaces of a TextDocument object. A TextDocument has optional properties and interfaces, among them the properties CharacterCount, ParagraphCount and WordCount, and the interface XPropertySet, which must be supported if properties are present at all. The implementation of the TextDocument service in Apache OpenOffice supports both required and all optional interfaces as well. The usage of a TextDocument is described thoroughly in Text Documents.

C++ and Java require that the interface name be provided when accessing a method. An old-style service may provide several interfaces to keep track of. New-style services are easier to use because, since they have just one interface, the multiple-inheritance interface, all the methods are accessed through the same interface.

Using Interfaces

The fact that every UNO object must be accessed through its interfaces has an effect in languages like Java and C++, where the compiler needs the correct type of an object reference before you can call a method from it. In Java or C++, you normally just cast an object before you access an interface it implements. When working with UNO objects this is different: You must ask the UNO environment to get the appropriate reference for you whenever you want to access methods of an interface which your object supports, but your compiler does not yet know about. Only then you can cast it safely.

The Java UNO environment has a method queryInterface() for this purpose. It looks complicated at first sight, but once you understand that queryInterface() is about safe casting of UNO types across process boundaries, you will soon get used to it. Take a look at the second example FirstLoadComponent.java (in the sample directory, if you have installed the SDK on your computer), where a new Desktop object is created and, afterwards, the queryInterface() method is used to get the XComponentLoader interface.

  Object desktop = xRemoteServiceManager.createInstanceWithContext(
                "com.sun.star.frame.Desktop", xRemoteContext);
 
  XComponentLoader xComponentLoader = (XComponentLoader)
                UnoRuntime.queryInterface(XComponentLoader.class, desktop);

We asked the service manager to create a com.sun.star.frame.Desktop using its factory method createInstanceWithContext(). This method is defined to return a Java Object type, which should not surprise you—after all the factory must be able to return any type:

  java.lang.Object createInstanceWithContext(String serviceName, XComponentContext context)

The object we receive is a com.sun.star.frame.Desktop service. The point is, while we know that the object we ordered at the factory is a DesktopUnoUrlResolver and exports among other interfaces the interface XComponentLoader, the compiler does not. Therefore, we have to use the UNO runtime environment to ask or query for the interface XComponentLoader, since we want to use the loadComponentFromURL() method on this interface. The method queryInterface() makes sure we get a reference that can be cast to the needed interface type, no matter if the target object is a local or a remote object. There are two queryInterface definitions in the Java UNO language binding:

  java.lang.Object UnoRuntime.queryInterface(java.lang.Class targetInterface, Object sourceObject)
  java.lang.Object UnoRuntime.queryInterface(com.sun.star.uno.Type targetInterface, Object sourceObject)

Since UnoRuntime.queryInterface() is specified to return a java.lang.Object just like the factory method createInstanceWithContext(), we still must explicitly cast our interface reference to the needed type. The difference is that after queryInterface() we can safely cast the object to our interface type and, most important, that the reference will now work even with an object in another process. Here is the queryInterface() call, explained step by step:

  XComponentLoader xComponentLoader = (XComponentLoader)
                  UnoRuntime.queryInterface(XComponentLoader.class, desktop);

XComponentLoader is the interface we want to use, so we define a XComponentLoader variable named xComponentLoader (lower x) to store the interface we expect from queryInterface. Then we query our desktop object for the XComponentLoader interface, passing in XComponentLoader.class as target interface and desktop as source object. Finally we cast the outcome to XComponentLoader and assign the resulting reference to our variable xComponentLoader. If the source object does not support the interface we are querying for, queryInterface() will return null.

In Java, this call to queryInterface() is necessary whenever you have a reference to an object which is known to support an interface that you need, but you do not have the proper reference type yet. Fortunately, you are not only allowed to queryInterface() from java.lang.Object source types, but you may also query an interface from another interface reference, like this:

  // loading a blank spreadsheet document gives us its XComponent interface:
  XComponent xComponent = xComponentLoader.loadComponentFromURL(
  "private:factory/scalc", "_blank", 0, loadProps);
 
  // now we query the interface XSpreadsheetDocument from xComponent
  XSpreadsheetDocument xSpreadsheetDocument = (XSpreadsheetDocument)UnoRuntime.queryInterface(
                  XSpreadsheetDocument.class, xComponent);

Furthermore, if a method is defined in such a way that it already returns an interface type, you do not need to query the interface, but you can use its methods right away. In the snippet above, the method loadComponentFromURL is specified to return an com.sun.star.lang.XComponent interface, so you may call the XComponent methods addEventListener() and removeEventListener() directly at the xComponent variable, if you want to be notified that the document is being closed. The corresponding step in C++ is done by a Reference<> template that takes the source instance as parameter:

  // instantiate a sample service with the servicemanager.
  Reference< XInterface > rInstance =
  rServiceManager->createInstanceWithContext( 
  OUString::createFromAscii("com.sun.star.frame.Desktop" ),
  rComponentContext );
 
  // Query for the XComponentLoader interface
  Reference< XComponentLoader > rComponentLoader( rInstance, UNO_QUERY );

In Apache OpenOffice Basic, querying for interfaces is not necessary; the Basic runtime engine takes care of that internally. With the proliferation of multiple-inheritance interfaces in the Apache OpenOffice API, there will be less of a demand to explicitly query for specific interfaces in Java or C++. For example, with the hypothetical interfaces

  interface XBase1 {   void fun1();
  };
  interface XBase2 {
      void fun2();
  };
  interface XBoth { // inherits from both XBase1 and XBase2
      interface XBase1;
      interface XBase2;
  };
  interface XFactory {
      XBoth getBoth();};

you can directly call both fun1() and fun2() on a reference obtained through XFactory.getBoth(), without querying for either XBase1 or XBase2.

Using Properties

An object must offer its properties through interfaces that allow you to work with properties. The most basic form of these interfaces is the interface com.sun.star.beans.XPropertySet. There are other interfaces for properties, such as com.sun.star.beans.XMultiPropertySet, that gets and sets a multitude of properties with a single method call. The XPropertySet is always supported when properties are present in a service.

In XPropertySet, two methods carry out the property access, which are defined in Java as follows:

  void setPropertyValue(String propertyName, Object propertyValue)
  Object getPropertyValue(String propertyName)

In the FirstLoadComponent example, the XPropertySet interface was used to set the CellStyle property at a cell object. The cell object was a com.sun.star.sheet.SheetCell and therefore supports also the com.sun.star.table.CellProperties service which had a property CellStyle. The following code explains how this property was set:

  // query the XPropertySet interface from cell object
  XPropertySet xCellProps = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, xCell);
 
  // set the CellStyle property
  xCellProps.setPropertyValue("CellStyle", "Result");

You are now ready to start working with a OpenOffice.org document.

Content on this page is licensed under the Public Documentation License (PDL).
Personal tools
In other languages