[ Previous document | Content Table | Next document ]

5  Extensions

 

An extension is a file intended for the distribution of code and / or data which is to be used by OOo. The file has the file extension “oxt”(formerly .uno.pkg and .zip), and it acts as a container for various items, such as libraries, JARs, configuration data, type libraries, Basic libraries, Basic dialogs, etc.  Before OOo can use any content of the extension, it needs to be installed by the Extension Manager.

5.1  Extension Manager

The Extension Manager is a tool for managing extensions and other deployable items, such as separate libraries, JARs, configuration data files. This includes adding, removing, enabling and disabling of these items. 

The Extension Manager can be started from within the office  by pressing the menu item Tools | Extension Manager or by running the unopkg executable, which is contained in the program directory of the office installation.

When an extension is installed, then a copy is created which is kept either in the user installation or the shared installation (<office-directory>/share).  The original extension can therefore be (re) moved after installation.

5.1.1  Deployment Items

The Extension Manager can be used to deploy various types of files. It is primarily used for extensions. The latest incarnation of an extensions is the .oxt file, which has superseded “.uno.pkg” and “.zip”. 

Apart from extensions the Extension Manager can also manage these types: 

5.1.2  Installing Extensions for All or a Single User

When installing an extension one has to decide if all possible users can use it or only oneself. In the first case,  users cannot enable, disable or remove the extension. This can only be done by the administrator. That also means, that in case the extension changes the appearance (toolbars, menu bar, etc.), all users are affected. They may, however, configure their office so that particular menu or toolbar items are not shown. There is currently no way to centrally install an extension for particular user groups.

If an extension is to be installed for all users or only for the single user is determined during installation. The person, who is going to install the extension, must select in the Extension Manager dialog either “My Extensions” or “OpenOffice.org Extensions” before pressing the “Add...” button.  In the first case, the extension will only be installed for the current user, whereas in the latter case it  will be installed for all users.

When running unopkg in a windowless mode then the option “--shared” determines if an extension can be used by all users. For example: 

[<OfficePath>/program] $ unopkg add --shared my_extension.oxt 

would install my_extensions, so that it can be used by all users. 

Extensions which are installed for all users are also called shared extensions, and those installed only for the user (who installed it) are called user extensions.  

5.1.3  Extension Manager in OpenOffice.org

Within a running office the Extension Manager is started through the menu item “Tools | Extension Manager ...”.  When started in this way,  extensions can only be installed as user extensions.  All items deployed under “OpenOffice.org Extensions cannot be modified. But it is possible to export them.

5.1.4  unopkg

The unopkg executable offers another way to start the Extension Manager.  It supersedes the pkgchk executable which was used in OpenOffice.org 1.1.0 and older versions and which no longer works.

In contrast to the Extension Manager in OpenOffice.org unopkg can also  manage  shared extensions. For example:

[<OfficePath>/program] $ unopkg add --shared my_extension.oxt 

installs my_extension.oxt for all users. 

unopkg offers a windowless mode in which all interactions occurs through the console. This is the default. If unopkg is started with the subcommand “gui” then the Extension Manager dialog appears which is exactly the same as the one in OpenOffice.org. 

[<OfficePath>/program] $ unopkg gui 

The difference is that in the dialog all items deployed under “OpenOffice.org Extensions” can be modified and new items can be added there as well. All actions, that is, adding, removing, etc. can be done in the dialog. Therefore “unopkg gui” does not require any more parameters. 

It follows a short overview what can be done with unopkg. Since there are many more commands, have a look at the help text that can be obtained by calling “unopkg -h”.

First of all open a console and change into the program directory of the office installation. 

Adding an extension for a single user: 

[<OfficePath>/program] $ unopkg add my_extension.oxt 

Adding an extension for all users: 

[<OfficePath>/program] $ unopkg add --shared my_extension.oxt 

Removing a user extension is done via the identifier of the extension (see 5.3 Extensions - Extension Identifiers): 

[<OfficePath>/program] $ unopkg remove my.domain.my_extension-id 

Remove a shared extension: 

[<OfficePath>/program] $ unopkg remove --shared my.domain.my_extension-id 

Before you install an extension or other item for all users, make absolutely sure there are no running instances of OpenOffice.org. unopkg cannot recognize if there are running instances of  OpenOffice.org from different users. Installing into a running office installation might cause inconsistencies and destroy your installation!

When a user starts OpenOffice.org and then starts unopkg, then the Extension Manager from the office is used and unopkg terminates. Then, however, no shared extensions and other shared items can be modified. 

Pay attention to the following important text section

Although it is now possible to deploy “live” into a running OpenOffice.org process, there are some limitations you should be aware of: Removing a type library from a running process is not possible, because this may lead to crashes when the type is needed. Thus if you, for example,  uninstall a package that comes with a UNO type library, these types will vanish upon next process startup, but not before.

There may also be problems with cached configuration data, because parts of the running process do not listen for configuration updates (for example, menu bars). Most often, those parts read the configuration just once upon startup.

5.1.5  Location of installed Extensions

Sometimes an extension developer needs to know the path to the root of his installed extension e.g. to load some additional data. You can use the singleton PackageInformationProvider to get an URL for an installed extension with a given Extension Identifier. For more information about Extension Identifiers see 5.3 Extensions - Extension Identifiers. For more information see com.sun.star.deployement.PackageInformationProvider and have a look at com.sun.star.deployment.XPackageInformationProvider.

... 

namespace css = com::sun::star; 

css::uno::Reference< css::uno::XComponentContext > mxContext; 

... 

css::uno::Reference< css::deployment::XPackageInformationProvider > 

    xInfoProvider( css::deployment::PackageInformationProvider::get( mxContext ) );

 

// "MY_PACKAGE_ID" is the identifier of the package where we want to get location from 

rtl::OUString sLocation = xInfoProvider->getPackageLocation(  

        rtl::OUString::createFromAscii( "MY_PACKAGE_ID" ) );

... 

5.2  File Format

An extension is a zip file having a name that ends on “.oxt“ (formerly ”.uno.pkg” or “.zip”).  The file extension .oxt is associated with the MIME / media type vnd.openofficeorg.extension.  An extension can contain UNO components, type libraries, configuration files, dialog or basic libraries, etc.

An extension should also contain a description.xml (see 5.5 Extensions - description.xml) and must contain a directory META-INF (all uppercase). The META-INF directory contains a manifest.xml which lists all items and their media-type. 

Note graphics marks a special text section

For backward compatibility, legacy bundles (extension uno.pkg, .zip) that have been formerly deployed using pkgchk are deployable, too. Migrate legacy bundles to the current .oxt format. This can easily be done using the GUI, exporting a legacy bundle as .an .oxt file. When a legacy bundle is exported, a manifest.xml file is generated, enumerating the detected items of the bundle.

Depending on the media-type the respective file needs to be treated particularly. For example a UNO component needs to be registered before it can be used. All media types which does not require a particular handling of the file are ignored currently (and actually need not be contained in the manifest.xml). 

It follows a description of possible extension items and their media-types: 

Shared Library UNO Components

The media-type for a shared library UNO component is “application/vnd.sun.star.uno-component;type=native”, for example,

<manifest:file-entry manifest:media-type="application/vnd.sun.star.uno-component;type=native"
                    manifest:full-path="myComponent.uno.so"/>


Shared Library UNO Components for particular Platforms 

When you implement a UNO native component, for example, a .dll or .so file, then this file is only deployable on that specific platform. It is often convenient to package a bundle for different platforms. For instance, you compile your component for x86 Linux, Solaris SPARC and Windows. You have to tell the Extension Manager which version of your component file corresponds to which platform via a platform attribute supplied with the media-type, for example,

<manifest:file-entry manifest:media-type=
                      "application/vnd.sun.star.uno-component;type=native;platform=Windows"

                     manifest:full-path="windows/mycomp.uno.dll"/>

<manifest:file-entry manifest:media-type=
                      "application/vnd.sun.star.uno-component;type=native;platform=Linux_x86"

                     manifest:full-path="linux/myComp.uno.so"/>

<manifest:file-entry manifest:media-type=
                      "application/vnd.sun.star.uno-component;type=native;platform=Solaris_SPARC"

                     manifest:full-path="solsparc/myComp.uno.so"/>

RDB Type Library 

The media-type for a UNO RDB type library is “application/vnd.sun.star.uno-typelibrary;type=RDB”, for example,

<manifest:file-entry manifest:media-type="application/vnd.sun.star.uno-typelibrary;type=RDB"
                    manifest:full-path="myTypes.uno.rdb"/>

Jar Type Library 

The media-type for a UNO Jar typelibrary is “application/vnd.sun.star.uno-typelibrary;type=Java”, for example,

<manifest:file-entry manifest:media-type="application/vnd.sun.star.uno-typelibrary;type=Java"
                    manifest:full-path="myTypes.uno.jar"/>

 

Keep in mind that the RDB variant of that type library must be deployed also. This is currently necessary, because your Java UNO types may be referenced from native UNO code. 

Uno Jar Components

The media-type for a UNO Jar component is “application/vnd.sun.star.uno-component;type=Java”, for example,

<manifest:file-entry manifest:media-type="application/vnd.sun.star.uno-component;type=Java"
                    manifest:full-path="myComponent.uno.jar"/>

 

UNO Python Components

unopkg now supports registration of Python components (.py files). Those files are registered using the com.sun.star.loader.Python loader. For details concerning Python-UNO, please refer to http://udk.openoffice.org/python/python-bridge.html.
The media-type for a UNO Python component is “application/vnd.sun.star.uno-component;type=Python”, for example,

<manifest:file-entry manifest:media-type="application/vnd.sun.star.uno-component;type=Python"
                    manifest:full-path="myComponent.uno.py"/>

OpenOffice.org Basic Libraries

OpenOffice.org Basic libraries are linked to the basic library container files. Refer to 12 OpenOffice.org Basic and Dialogs for additional information.
The media-type for a OpenOffice.org Basic Library is “application/vnd.sun.star.basic-library”, for example,

<manifest:file-entry manifest:media-type="application/vnd.sun.star.basic-library"
                    manifest:full-path="myBasicLib/"/>

Dialog Libraries

Dialog libraries are linked to the basic dialog library container files. Refer to 12 OpenOffice.org Basic and Dialogs for additional information.
The media-type for a dialog library is “application/vnd.sun.star.dialog-library”, for example,

<manifest:file-entry manifest:media-type="application/vnd.sun.star.dialog-library"
                    manifest:full-path="myDialog/"/>

Configuration Data Files

The media-type for a configuration data file is “application/vnd.sun.star.configuration-data”, for example,

<manifest:file-entry manifest:media-type="application/vnd.sun.star.configuration-data"
                    manifest:full-path="myData.xcu"/>

Configuration Schema Files

The media-type for a configuration schema file is “application/vnd.sun.star.configuration-schema”, for example,

<manifest:file-entry manifest:media-type="application/vnd.sun.star.configuration-schema"
                    manifest:full-path="mySchema.xcs"/>

Be careful not to install schemata (.xcs files) which contain the same elements  (oor:package, oor:name) but have different definitions.

Extension Tooltip Description 

If you want to add a  tooltip description (which shows up in the balloon help of a bundle node in the Extension Manager dialog), then you can do so by specifying localized UTF-8 files, for example,

<manifest:file-entry manifest:media-type="application/vnd.sun.star.package-bundle-description;locale=en"
                    manifest:full-path="readme.en" />
<manifest:file-entry manifest:media-type="application/vnd.sun.star.package-bundle-description;locale=de"
                    manifest:full-path="readme.de" />
manifest:media-type="application/vnd.sun.star.package-bundle-description"
                    manifest:full-path="readme.txt" />


The best matching locale (against the current installation's locale) is taken. The locale is of the form "locale=language-country-variant".

All other contents of the extension are simply copied into the Extension Manager cache. You can, for instance, deploy an image for add-on menus within a package, or any other file needed by your component. The OpenOffice.org configuration is used to find out in which path this file is located in a particular installation.
When you define a package containing additional files, include an .xcu configuration data file, which points to your files. Use a variable %origin% as a placeholder for the exact path where the file will be copied by the Extension Manager. When unopkg installs the data, it replaces the path with anURL containg a macro an writes into the configuration. This URL has to be expanded before it is a valid file URL. This can be done using the com.sun.star.util.MacroExpander service. The %origin% variable is, for instance, used by the ImageIdentifier property of add-on menus and toolbar items, which is described in the 4.7.3 Writing UNO Components - Integrating Components into OpenOffice.org - User Interface Add-Ons - Configuration section.

5.3  Extension Identifiers

Extensions now have unique identifiers. This removes the previous restriction that no two extensions with identical file names can be deployed. 

Technically, an extension identifier is a finite sequence of Unicode scalar values. Identifier identity is element-by-element identity of the sequences (no case folding, no normalization, etc.). It is assumed that extension writers cooperate to keep extension identifiers unique. By convention, use lowercase reversed-domain-name syntax (e.g., “org.openoffice.”) prefixes to generate unique (but still humanly comprehensible) identifiers. When you write an extension, use the reversed domain name of a site you controll (and notorg.openoffice.”) as prefix. Identifiers starting with the prefix “org.openoffice.legacy.” are reserved for legacy extensions (see next).

The extension identifier is obtained from the description.xml contained in the extension. If the extension does not specify such an explicit identifier, then an implict identifier is generated by prepending “org.openoffice.legacy.” to the (obvious sequence of Unicode scalar values representing the) file name of the extension. (Uniqueness of identifiers is then guaranteed by the assumption underlying legacy extension management that no two legacy extensions have the same file name.)

5.4  Extension Versions

Extensions are often improved over time. That is, publishers want to ship new versions of the same extension with added functionality and/or bug fixes. Adding extension versions allows publishers to ship new versions, and allows [PRODCUTNAME] to detect and handle the case that an extension installed by the user is an update of an existing extension. 

Technically, an extension version v is defined as an infinite sequence of non-negative integers v = ‹v0, v1, ...› where all but a finite number of elements have the value zero. A total order is defined on versions via lexicographical comparison. A textual representation of a version v = ‹v0, v1, ...› is a finite string built from the BNF

version ::= [element (“.” element)*]

element ::= (“0” | “1” | “2” | “3” | “4” | “5” | “6” | “7” | “8” | “9”)+

of n ≥ 0 elements where each element is a decimal representation of vi for 0 ≤ in, and each vi = 0 for i ≥ n.

The extension version is obtained from the description.xml contained in the extension. If the extension does not specify such an explicit version, then an implict textual version representation of the empty string (representing a version of all zeroes) is assumed. 

No general semantics are prescribed to versions, other than the total order which determines whether one version is less than, equal to, or greater than another version, respectively. However, extension publishers are encouraged to use the widely accepted three-level scheme of major (incompatible changes), minor (compatible changes), micro (bug fixes) where applicable. 

5.5  description.xml

The description.xml is a means to provide additional useful information, such as dependencies, license and update information. It will be extended to support new features in the future. The file must be located in the root of the extension and the name is case sensitive. 

Pay attention to the following important text section

The description.xml is searched case sensitive in an oxt package. This is important to know when you package your extensions content into a new oxt package.

5.5.1  Description of XML Elements

Element <description>

XPath: /description 

Parent element:  document root

Child elements: 

<registration> (page 8)

<dependencies> (page 9)

<update-information> (page 9)

<description> is the root element of the description.xml. 

 

Table 1 Attributes of <description>

Attribute 

Description 

xmlns 

The default namespace of element description and all children must be defined as 

"http://openoffice.org/extensions/description/2006"

xmlns:dep 

The namespace for dependency information must also be defined as 

"http://openoffice.org/extensions/description/2006"

xmlns:xlink

 

The xlink namespace must be defined as

"http://www.w3.org/1999/xlink" 

other namespace definitions 

Other namespaces can be added as necessary 

Element <identifier> 

XPath: /description/identifer 

Parent: <description> (page 7)

Child elements: none 

 

Table 2 Attributes of <identifier>

Attribute 

Description 

value 

Required. The extension identifier. 

Element <version> 

XPath: /description/version 

Parent: <description> (page 7)

Child elements: none 

 

Table 3 Attributes of <version>

Attribute 

Description 

value 

Required. A textual representation of the extension version. 

Element <registration>

XPath: /description/registration  

Parent: <description> (page 7)

Child elements: 

<simple-license> (page 9)

 

The registration element currently only contains the  <simple-license> element. If the <registration> element exists, then it must have a child element. For more information about using licenses see chapter  5.6.

Element <dependencies>

XPath: /description/dependencies 

Parent: <description> (page 7)

Child elements: 

<OpenOffice.org-minimal-version> (page 10)

others 

Element <update-information>

XPath: /description/update-information 

Parent: <description> (page 7)

Child elements: 

<src> (page 10)

 

<update-information> must have one or more <src>  children. The second, third, etc. element are regarded as fallback, that is, the elements provide URLs to mirrors.  The Extension Manager will try to get update information by using a URL and only use a different URL if an error occurred. That is, if for example the first URL references an atom feed that does not contain any references at all, but is a valid feed, then the Extension Manager assumes that there are no update information available. Then URLs from other <src> elements are not examined. Therefore the update information referenced by every URL must be identical.  For more information about online updates of extensions see chapter 5.9.

 

Element <simple-license>

XPath: /description/registration/simple-license 

Parent: <registration> (page 8)

Child elements: 

<license-text> (page 11)

 

The element contains the <license-text> elements, determines if all user must agree to the license, or just the person who installs it, and determines a default <license-text> element . 

If the <simple-license> element exists, then it must have at least one child element.

 

Table 4 Attributes of <simple-license>

Attribute 

Description 

accept-by 

Required.Value is either “user” or “admin”. “user” means that every user has to agree to the license. That is, the extension can only be installed as user extension but not as shared extension. If it has the value “admin” then it can be deployed as shared extension as well. In that case only the person who installs it has to agree to the license. Individual users will not be asked to accept the license. They can use the extension right away. In case the value is “user” and the extension is being installed as user extension then the user must always agree to the license.

default-license-id 

Required. Determines what <license-text> is used if no <license-text> element has a lang attribute whoose value matches the locals of OOo. There must always be exactly one <license-text> element whith a license-id attribute whoose value matches that of the default-license-id. The type is xsd:IDREF

suppress-on-update 

Optional.  When the attribute is not provided then the value “false” is assumed. The value true indicates that the license for this extension will not be displayed during installation when the same extension (same id but probably different version) is already installed. This applies for the automatic update as well as for manually installing an extension. The version of the already installed extension does not matter.  Suppressing the license can be useful during the online update, because otherwise the update operation could be interrupted by many license dialogs.

Element <OpenOffice.org-minimal-version>

XPath: /description/dependencies/OpenOffice.org-minimal-version 

Parent: <dependencies> (page 9)

Child elements: none 

 

Table 5 Attributes of <OpenOffice.org-minimal-version>

Attribute 

Description 

xmlns:dep 

The namespace for dependency information (inherited from <description>, see page 7) must be defined as

"http://openoffice.org/extensions/description/2006"

dep:name 

Required. The string “OpenOffice.org value” (where value is the value of the attribute value).

dep:OpenOffice.org-minimal-version 

Optional. This attribute should never be used with this element. 

value 

Required. The required underlying OpenOffice.org version (“2.1”, “2.2”, etc.), starting with OpenOffice.org 2.1.

Element <src>

XPath: /description/update-information/src 

Parent: <update-information> (page 9)

Child elements: none 

Table 6 Attributes of <src>

Attribute 

Description 

xlink:href 

Required. The value is a URL which provides the update information directly or an atom feed which in turn references the update information.  The URL can point directly to a file or it may invoke code, such as a servlet, cgi, etc, that returns the atom feed or the update information.

 

Element <license-text>

XPath: /description/registration/simple-license/license-text 

Parent: <simple-license> (page 9)

Child elements: none 

 

The element contains information about where to find the file containing the license text, which language it uses, and if this element is the “default” <license-text>

 

Table 7 Attributes of <license-text>

Attribute 

Description 

xlink:href 

Required. The value is a relative URL to the file which contains the license text. The base URL is the URL of the root directory of the extension. That is, if the extension has been unzipped, then the resulting directory is the root directory. 

lang 

Required. A language identifier according to RFC 3066. Values can be for example: en, en-US, en-US-variant, etc. Currently OOo does not make use of variants.

license-id 

Optional. However one license-text element must have this attribute and the value must match the value of the default-license-id attribute of the <simple-license> element. The type is xsd:ID.

5.5.2  Example

<?xml version="1.0" encoding="UTF-8"?>

<description xmlns="http://openoffice.org/extensions/description/2006" xmlns:d="http://openoffice.org/extensions/description/2006" 

    xmlns:xlink="http://www.w3.org/1999/xlink">

    <version value="1.0" />    

 

    <dependencies>

         <OpenOffice.org-minimal-version value="2.2" d:name="OpenOffice.org 2.2"/>

    </dependencies>

 

    <update-information>

      <src xlink:href="http://extensions.openoffice.org/testarea/desktop/license/update/lic3.update.xml" />

    </update-information>

       

    <registration>

        <simple-license  accept-by="admin" default-license-id="en-NZ" suppress-on-update="true" >

            <license-text xlink:href="registration/license_de-DE.txt" lang="de-DE" />

            <license-text xlink:href="registration/license_en-GB.txt" lang="en-GB" />

            <license-text xlink:href="registration/license_en-NZ.txt" lang="en-NZ" license-id="en-NZ" />

            <license-text xlink:href="registration/license_en-US.txt" lang="en-US" />

        </simple-license>

    </registration>

</description> 

 

 

This description.xml contains these information: 

5.6  Simple License

This feature is about displaying a license text to the user during installation. The user can agree or decline the license, where in the latter case the installation will be aborted.  It is called “Simple License” because there is no tamper resistant mechanism that prevents the installation in case the user does not agree to the license. It also does not do anything more than just displaying a license text. However it provides a way to use localized licenses. More on that later.

The license text is displayed either in a dialog or in the console dependent on the way the package manager was started. When it was started by the tools->Package Manager menu item or by invoking unopkg gui in the console then a dialog is used. By using unopkg add the license text will be displayed in the console and user input has to be done through the same.

The license dialog or the license text in the console is displayed when the extension is being installed. Currently there are two modes to install extensions, user mode and shared mode. An extension that was installed in user mode (let's call it a user extension) can only be used by just that person who installed it. If the extension was installed in shared mode (let's call it a shared extension), then it can be used by all users.  Since the license text is only displayed during installation, all users who are using a shared extension will not see any license text (except the user who installed this shared extension). However, the publisher of the extension may think it necessary that everyone who wants to use it has to agree to the license first. For this purpose, he can mark the extension accordingly. This extension can then only be installed in user mode and not in shared mode. Likewise the extension can be marked indicating that only the person who installs it needs to agree to the license. Such an extension can be installed in both modes.  But when installing in user mode then every user has to agree to the license nonetheless.

Here is an example of the description.xml: 

<?xml version="1.0" encoding="UTF-8"?>

<description xmlns="http://openoffice.org/extensions/description/2006"

    xmlns:xlink="http://www.w3.org/1999/xlink">

    <registration>

        <simple-license  accept-by="user" default-license-id="de">

            <license-text xlink:href="registration/license_de.txt" lang="de" license-id="de" />

            <license-text xlink:href="registration/license_en_US.txt" lang="en-US" />

        </simple-license>

    </registration>

</description>

 

 

In this example, the license would have to be agreed to by all users (that means no shared mode installation). This is indicated by the value “user” of the attribute accept-by in the <simple-license> element. The attribute could also have the value “admin”, which would indicate that the license needs only be agreed to by the person who installs it.

The <license-text> elements contain information about the files which contain the text that is displayed. The content of these files must be UTF-8 encoded. It is displayed exactly as it is in the file. That is, no formatting occurs. There can be one to many <license-text> elements, where each element provides information about a different language of the license text. The attribute xlink:href contains a relative URL (relative to the root directory of the extension) which points to a file which countains the license text in exacty one language. Which language is indicated by lang attribute.

If the package manager does not find a <license-text> element which matches the locale of OOo then it will pick the <license-text> that is marked as the default language. This mark is expressed by the license-id attribute of <license-text> and the default-license-id attribute of the <simple-license> element. There must always be exactly one <license-text> whose attribute value is the same as that from <simple-license>. This <license-text> element is then used as the default.

5.6.1  Determining the Locale of the License

The locale used by OOo and the license text files is expressed by a language string according to RFC 3066. This string contains the language and can optionally contain a country and further information.  Let's assume that the office uses britisch english (en-GB) end the extension has two license text files, one in german (de), which is also the default, and the other in english from New Zealand (en-NZ). Obviously there is no perfekt match, since en-GB is not en-NZ. But we would not want to use the default yet, because en-NZ is most probably closer to en-GB as german. Therefore we use an algorithm that tries to find a “close match” of the local before it resorts to the default. Here is the algorithm:

In order to find the appropriate <license-text> element, the values of lang attribute are compared with the office's Locale. Both are represented as strings according to RFC3066. The comparison is done case sensitive.

Input to the algorithm: 

Output of the algoritm: 

Algorithm: 

  1. The language, country and variant part of the office's locale are used to find a matching license-text.  If there is an exact match then the respective license-text is selected as output and we are done. Only the first match is used.

  2. The language and country part of the office's locale are used to find a matching license-text. If there is an exact match then the respective license-text is selected as output and we are done.

  3. The language and country part of the office's locale are used to find a matching license-text. This time, we try to match only the language and country parts. For example, the office locale strings “en-US”, “en-US-east” match the lang attribute with the values “en-US-north”, “en-US-south”,etc. The first license-text with a matching lang attribute is selected as output. If there is a match then we are done.

  4. Only the language part of the office's locale is used to find a matching license-text. If there is an exact match then the respective license-text is selected as output and we are done. Only the first match is used.

  5. Only the language part of the office's locale is used to find a matching license-text. This time, we try to match only the language part. For example, the office locale strings “en”, “en-US”, “en-US-east” match the lang attribute with the values “en-GB”,“en-GB-north”, etc. The first license-text with a matching lang attributed is selected as output. If there is a match then we are done.

  6. The license-text element which is marked as “default” will be selected. That is, the value of the attribute license-id must match the default-license-id of the simple-license element.

The following example show what values would match. 

Example 1: Locale of OOo is en-US and the relevant part of the description.xml is:

<simple-license accept-by="user" default-license-id="en-US" > 

  <license-text xlink:href="lic_en-GB" lang="en-GB"  />

  <license-text xlink:href="lic_en-US" lang="en-US" license-id="en-US" />

</simple-license> 

The <license-text> with lang=”en-US” will be selected. 

Example 2: Locale of OOo is en-US and the relevant part of the description.xml is:

<simple-license accept-by="user" default-license-id="en-NZ" > 

  <license-text xlink:href="lic_en-GB" lang="en-GB"  />

  <license-text xlink:href="lic_en-NZ" lang="en-NZ" license-id="en-NZ" />

</simple-license> 

The <license-text> with lang=”en-GB” will be selected. 

Example 3: Locale of OOo is en-US and the relevant part of the description.xml is:

<simple-license accept-by="user" default-license-id="en-NZ" > 

  <license-text xlink:href="lic_en" lang="en" />

  <license-text xlink:href="lic_en-GB" lang="en-GB"  />

  <license-text xlink:href="lic_en-NZ" lang="en-NZ" license-id="en-NZ" />

</simple-license> 

The <license-text> with lang=”en” will be selected. 

Example 4: Locale of OOo is de-DE and the relevant part of the description.xml is:

<simple-license accept-by="user" default-license-id="en-NZ" >

  <license-text xlink:href="lic_en" lang="en" />

  <license-text xlink:href="lic_en-GB" lang="en-GB"  />

  <license-text xlink:href="lic_en-NZ" lang="en-NZ" license-id="en-NZ" />

</simple-license> 

The <license-text> with lang=”en-NZ” will be selected. 

5.7  Dependencies

One can imagine a large variety of dependencies an extension can have on its environment: availability of certain UNO types and services, availability of features only present since some specific version of OOo, availability of other installed extensions, availability of third-party libraries, etc. 

To support this, a mechanism is introduced so that extensions can bring along a specification of their dependencies. When a user wants to install an extension, the application first checks whether all dependencies are met.  If not, an error dialog is displayed informing the user that the extension could not be installed.

The only actual dependency currently defined is <OpenOffice.org-minimal-version value=“X”>, where X is the required underlying OpenOffice.org version (“2.1”, “2.2”, etc.), starting with OpenOffice.org 2.1. (Even if an extension is installed in a derived product like StarOffice, this dependency is on the underlying OpenOffice.org version.)

OOo 2.0.3 and earlier are not prepared to correctly handle extensions with dependencies. In OOo 2.0.3 and earlier, if a .uno.pkg (or .zip) extension specifies any dependencies, they are effectively ignored and the extension is installed nonetheless. An .oxt extension cannot be installed at all in OOo 2.0.3 and earlier. So, if an extension shall run in any OOo version, it should be named .uno.pkg and should not specify any dependencies; if an extension shall only run in OOo 2.0.4 and later, it should be named .oxt and should not specify any dependencies; and if an extension shall only run in a future OOo version, it should be named .oxt and should specify the appropriate dependencies (which will be defined by the time the given OOo version is available).

There is a certain dilemma: On the one hand, nothing is yet known about the kinds of dependencies that will be defined in the future. On the other hand, at least some information about the unsatisfied dependencies of a future extension must be displayed in OOo 2.0.4. Therefore, each dependency specified by an extension must contain a human-readable (non-localized, English) name that can be displayed to the user, conveying at least rudimentary information about the nature of the unsatisfied dependency. Future versions of OOo that already know a certain kind of dependency are expected to display more detailed information.

Likewise, when new dependencies are defined over time, old versions of OOo will not know about them. Those old OOo will thus reject extensions making use of those dependencies, even if the old OOo version would actually satisfy the dependencies. Therefore, each dependency specified by an extension may optionally contain an OpenOffice.org-minimal-version attribute that specifies the minimal version of OOo that would satisfy the dependency. Old versions of OOo that do not know the given dependency will then check for the optional attribute and, if present, nevertheless accept the dependency if the given version is large enough. This feature is only supported since OOo 2.3.

Within the description.xml, dependencies are recorded as follows: An XML element whose name consists of the namespace name http://openoffice.org/extensions/description/2006 and the local part dependencies may appear at most once as a child of the root element. This element has as its element content an arbitrary number of child elements that are not further constrained expect for the following: Each such child element should have an attribute whose name consists of the namespace  name http://openoffice.org/extensions/description/2006 and the local part name, and it may optionally have an attribute whose name consists of the namespace http://openoffice.org/extensions/description/2006 and the local part OpenOffice.org-minimal-version. Each such child element represents one dependency, and the value of its name attribute shall contain the human-readable dependency name (and the value, after normalization, should not be empty).

If an extensions is either not of type .oxt, .uno.pkg, or .zip, or does not contain a description.xml, or the description.xml does not contain a dependencies element, or the dependencies element does not contain any child elements, then the extension does not specify any dependencies.

5.8  System Integration

When installing OpenOffice.org, the installation routine  is adding information to the system which can be used by other software products to install extensions.  For example, double-clicking on an extension in a file browser should start the Extension Manager and install the extension. Also mail clients and web browser should offer a way of installing the extension, when it comes as an attachment of an e-mail or is the target of a link.

Extension which are installed by way of using the system integration are always installed as user extensions.

The system integration is available since OOo 2.2.  

5.9  Online Update of Extensions

Extensions are often improved over a period of time. That is, publishers ship new versions of the same extension with added functionality and/or bug fixes. Currently users must update their extensions manually, that is, find out where to get updates, obtain the updates, remove the old extensions, install the new extension. This feature will make updating easier. Users can run the update mechanism from the Extension Manager. A dialog will show available updates and the user will be able to choose which to install.  

More particular information for this feature can be found in the specification at: 

http://specs.openoffice.org/appwide/packagemanager/online_update_for_extensions.odt

Currently the update mechanism completely replaces an installed extension. That is, the update is actually a complete new extension which could also be installed separately without replacing an earlier version of this extension. 

5.9.1  Running Online - Update

The update procedure needs to be started by the user in the Extension Manager. One can update all installed extensions by pressing the “Updates” button or select particular extensions, press the right mouse button and select “Update” in the context menu. The extension manager will then try to obtain update information for the affected extension. If it finds that a new version of an extension is available then it will be displayed in the update window.

In some cases an update cannot be installed, for example because the  installed extension is shared by all users and the current user does not have permission to manage shared extensions. In this case a message to this regard is displayed in the window.  To update shared extensions one needs to close OpenOffice.org and run unopkg gui. Then the user has access to all extensions.

An extension may also not be installable, because it has unfulfilled dependencies. For example,  the extensions requires a particular version of OpenOffice.org.

The user can determine which of the updates he wants to install by checking them. When the “Download and Installation” button is pressed then, as the name suggests, the extensions are being downloaded and installed. 

5.9.2  Concept

The actual download location of an update is contained in the update information which is typically a xml file which is hosted on a server.  Every update information contains only information for exactly one extension.  The most important information are the location of the update and the version of this extension.

The Extension Manager needs to get hold of the update information in order to decide if the respective extension is a valid update. For example, it only makes sense to take a version into account that is greater than the version of the already installed extension.  The information where the update information is located is contained in the description.xml of each extension. In particular the children of the <update-information>  element (see page 9), contain URLs which reference the update information. The Extension Manager uses these URL to download the update information and later uses the information in the update information to download the respective extension.

In case that an extension does not contain a description.xml or the description.xml does not contain the <update-information> element, the Extension Manager uses a default location to get update information. This location is build-in, and is therefore determined by the  publisher  of OpenOffice.org. Currently this information is contained in the version.(ini|rc) of the the office installation.

Now the attentive reader may be wondering, because it was mentioned before that the update information only contain information for just one extension. How come that just one build-in URL can be used to get information for multiple extensions? The answer is that there is a way to bundle several update information in one piece of data. This is done by using an XML atom feed which can reference  multiple update information. For example a feed could reference multiple update information, which refer all to an extension with the same Id but have different versions. It could also contain references to update information of distinct extensions (different Id). Then the Extensions Manager will pick out the information it needs.

Not only the build-in URL can reference an atom feed but also every extension. 

5.9.3  Example Scenario for Providing Updates

Using an Atom Feed

By using  an atom feed one has greater flexibility in terms of where the actual updates are hosted. For example, a company which has published many extensions, may utilize just one atom feed which are referenced by all extensions. The location of this atom feed must be well chosen, because changing it may break the automatic update. Then the Extension Manager cannot obtain update information for these extensions anymore.  For this reason, the company could set up a dedicated server which is guaranteed to be available  in the foreseeable future. The actual extensions can then be hosted on different servers. The atom feed file needs only be edited if an update information file is moved to a different  place, or when update information for new extensions become available.

If no actual update is available,  for example, there is just version 1.0, then the update information could still refer to this extension.  This does not do any harm because the Extension Manager compares the version number of the installed extension and the version which is contained in the update information, in order to display only real updates.

The location of the extension used as update could be the same as the location where customers download the extension for the first time. For example, there could be a web site which contains links to extensions.  Let's assume one link is:

http://mycomp/extension.oxt 

The extension references a feed at: 

http://openoffice.org/extensions/updatefeed.xml 

The feed contains the reference to the update information:

http://mycomp/updates/extension.update.xml 

and this file refers to the update which is again: 

http://mycomp/extension.oxt 

If now version 2.0 of the extension becomes available, then the publisher could simply replace the extension at http://mycomp/extension.oxt and change the update information so that it reflects the new version. This way, users download always the latest version from the website and the Extension Manager can use this extension as update for an older version which is already installed.

5.9.4  Migration of Update Information

I could become necessary to change the server which hosts the update feed or update information.  If this results in a different URL for these files, then the automatic update will not work.  Therefore the following procedure is recommended.

  1. Plan for a transition period, that is long enough for most users to get a new update. 

  2. Set up the new server, or the locations for hosting the update information, and run both servers in parallel. That is, the same update information and updates should be available from both servers.

  3.  Prepare new versions for extensions that contain  an URL to the new server.

  4. Switch of the old server after the transition period. Users, which have obtained the update, will be able to use the update mechanism as before. All other users will not be able to get an update anymore. 

5.9.5  Description of  the Update Information

If the update information can be contained in a file which can be directly accessed through a URL or are generated on demand (HTTP get request). If it is a file then it could be named according to this pattern: 

<extension_file_name>.update.xml 

For example, the update information file for the extension myextension.oxt is myextension.update.xml. The .oxt file extension is not used. 

It follows the description of the XML structure of the update information data:

Element <description>

XPath: /description 

Parent element:  document root

Child elements: 

<identifier> (page 19)

<version> (page 20)

<update-download> (page 20)

<dependencies> (page 20)

<description> is the root element of the  update information XML document.

 

Table 8Attribute <description>

Attribute 

Description 

xmlns 

The default namespace of element description and all children must be defined as 

"http://openoffice.org/extensions/update/2006"

xmlns:dep 

The namespace for dependency information must be defined as 

"http://openoffice.org/extensions/description/2006"

xmlns:xlink 

The xlink namespace must be defined as  

"http://www.w3.org/1999/xlink" 

other namespace definitions 

Other namespaces can be added as necessary. 

Element <identifier>

XPath: /description/identifier 

Parent element:  <description> (page 19)

Child elements: none 

 

Table 9 Attributes of <identifier>

Attribute 

Description 

value 

Required. The extension identifier. 

Element <version>

XPath: /description/version 

Parent element:  <description> (page 19)

Child elements: none 

 

Table 10 Attributes of <version>

Attribute 

Description 

value 

Required. A textual representation of the extension version. 

Element <update-download>

XPath: /description/update-download 

Parent element:  <description> (page 19)

Child elements:  

<src> (page 20)

<update-download> must have one or more <src>  children. The second, third, etc. <src> element are regarded as fallback, that is, the elements provide URLs to mirrors.  The Extension Manager will try to download the extension by using the first URL and only uses the next URL if an error occurred, for example because the the connection was interrupted.

Element <dependencies>

XPath: /description/dependencies 

Parent element:  <description> (page 19)

Child elements:  

<dep:OpenOffice.org-minimal-version> (page 21)

others 

Element <src>

XPath: /description/update-download/src 

Parent element:  <update-download> (page 20)

Child elements: none 

Table 11 Attributes of <src>

Attribute 

Description 

xlink:href 

Required. The value is a URL which refers to the extension 

Element <dep:OpenOffice.org-minimal-version>

XPath: /description/dependencies/dep:OpenOffice.org-minimal-version 

Parent element:  <dependencies> (page 20)

Child elements: none 

 

Table 12 Attributes of <dep:OpenOffice.org-minimal-version>

Attribute 

Description 

xmlns:dep 

The namespace for dependency information (inherited from <description>, see page 19) must be defined as

"http://openoffice.org/extensions/description/2006"

dep:name 

Required. The string “OpenOffice.org value” (where value is the value of the attribute value).

value 

Required. The required underlying OpenOffice.org version (“2.1”, “2.2”, etc.), starting with OpenOffice.org 2.1.

5.9.6  Description of Atom Feed

The description of the atom feed is available at: 

http://wiki.services.openoffice.org/wiki/Update_Notification_Protocol

5.9.7  Examples

description.xml Containing Direct Reference to the Update Information

The following content of a description.xml directly references update information: 

<?xml version="1.0" encoding="UTF-8"?>

<description xmlns="http://openoffice.org/extensions/description/2006" 

    xmlns:xlink="http://www.w3.org/1999/xlink">

    <version value="1.0" />    

 

    <update-information>

      <src xlink:href="http://extensions.openoffice.org/testarea/desktop/simple/update/plain1.update.xml" />

      <src xlink:href="http://extensions.mirror.openoffice.org./testarea/desktop/simple/update/plain1.update.xml" />

    </update-information>

</description> 

The second src element contains a URL to a mirror which will be used by the Extension Manager if the location referenced by the URL in the first src element cannot be reached. 

This is the  content of plain1.update.xml:

<?xml version="1.0" encoding="UTF-8"?>

<description xmlns="http://openoffice.org/extensions/update/2006" 

             xmlns:xlink="http://www.w3.org/1999/xlink">

    <identifier value="org.openoffice.legacy.plain1.oxt"/>

    <version value="2.0" />    

    <update-download>

        <src xlink:href="http://extensions.openoffice.org/testarea/desktop/simple/update/plain1.oxt" />

    </update-download>

</description> 

The src element contains a URL to version 2.0 of plain1.oxt. Plain1.oxt has the identifier org.openoffice.legacy.plain1.oxt because it does not define an identifier in its description.xml. Otherwise the identifier would be the same as the one in the description.xml. 

Using the Atom Feed

This is the content of the description.xml of feed1.oxt which references an atom feed: 

<?xml version="1.0" encoding="UTF-8"?>

<description xmlns="http://openoffice.org/extensions/description/2006" 

    xmlns:xlink="http://www.w3.org/1999/xlink">

    <version value="1.0" />    

    <update-information>

      <src xlink:href="http://extensions.openoffice.org/testarea/desktop/updatefeed/update/feed1.xml" />

    </update-information>

</description> 

The feed: 

<?xml version="1.0" encoding="utf-8"?>

<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"> 

 

  <title>Extensions Update Feed</title>

  <link rel="alternate" type="text/html" href="http://update.services.openoffice.org/ooo/snapshot.html"/>

  <updated>2006-11-06T18:30:02Z</updated>

  <author>

    <name>The OpenOffice.org Project</name>

    <uri>http://openoffice.org</uri>

    <email>updatefeed@openoffice.org</email>

  </author>

  <id>urn:uuid:a4ccd383-1dd1-11b2-a95c-0003ba566e9d</id>

  <entry>

    <title>feed1.oxt version 2.0 available</title>

    <link rel="alternate" type="text/html"

        href="http://extensions.openoffice.org"/>

    <id>urn:uuid:a4ccd383-1dd1-11b2-a95c-0003ba566e9f</id>

    <category term="org.openoffice.legacy.feed1.oxt" label="feed1.oxt" />

    <updated>2006-11-06T18:30:02Z</updated>

    <summary>Click here to go to the download page.</summary>

    <content type="application/xml" src="http://extensions.openoffice.org/testarea/desktop/updatefeed/update/feed1.update.xml" />

  </entry>

  <entry>

    <title>feed2.oxt version 2.0 available</title>

    <link rel="alternate" type="text/html"

        href="http://extensions.openoffice.org"/>

    <id>urn:uuid:a4ccd383-1dd1-11b2-a95c-0003ba566eaf</id>

    <category term="org.openoffice.legacy.feed2.oxt" label="feed2.oxt" />

    <updated>2006-11-06T18:30:02Z</updated>

    <summary>Click here to go to the download page.</summary>

    <content type="application/xml" src="http://extensions.openoffice.org/testarea/desktop/updatefeed/update/feed2.update.xml" />

  </entry>

</feed>

 

The feed contains two entry elements and each references the update information for a different extensions. It could, however, also reference the update information for two different versions of the same extension.

The update information for the version of feed1.oxt:

<?xml version="1.0" encoding="UTF-8"?>

<description xmlns="http://openoffice.org/extensions/update/2006" 

             xmlns:xlink="http://www.w3.org/1999/xlink">

    <identifier value="org.openoffice.legacy.feed1.oxt"/>

    <version value="2.0" />    

    <update-download>

        <src xlink:href="http://extensions.openoffice.org/testarea/desktop/updatefeed/update/feed1.oxt" />

    </update-download>

</description> 

5.10  Options Dialog

Extensions can add options pages to OOo's options dialog. It is also possible to start an options dialog from within the Extension Manager on behalf of a particular extensions.  An options page represents a child window that is displayed within the options dialog. An extension can provide multiple options pages. It can determine that they can be added to already existing nodes, such as “OpenOffice.org Writer” or  “Internet Settings”.  It is also possible to create completely new nodes.

The specification for this feature can be found at: 

http://specs.openoffice.org/appwide/packagemanager/options_dialog_for_extensions.odt

In the following paragraphs we will show what has to be done in order to add options pages to an extension. Along the way we will go into some details where necessary.  It is assumed that the reader has already knowledge about extension programming and that he or she knows how the OOo's registry (including xcs and xcu files) works.

A note about writing some terms. When we refer to elements from the configuration schema of OOo then we use the respective uppercase names, for example Node, Module. The plural will expressed by adding a pipe symbol an the respective postfix, for example Node|s, Module|s. 

5.11  Creating the GUI of the Options Page

The GUI of an options page needs to be created by the dialog editor of OOo.   Exporting the dialog will result in saving a .xdl file and perhaps  multiple .properties files. The xdl file contains the description of the dialog in XML whereas the properties files contain localized strings. For example, if the dialog is named Dialog1 and it contains strings which are localized for German and US – English, then you will obtain these files:

Dialog1.xdl 

Dialog1_de_DE.properties 

Dialog1_en-US.properties 

Please make sure that you have set the property “With title bar” to “no” for the whole dialog. 

The exported files can be anywhere in the extensions, except in META-INF. They must also be in the same directory. 

The options dialog will use the service com.sun.star.awt.ContainerWindowProvider to create the options pages. The service constructors takes an URL to the xdl file and an an event handler component. The latter will be used to process events which have been defined in the dialog editor for particular controls. It is also used for saving and loading the data of the controls which are on the options pages. 

5.12  Saving and Reading Data for the Options Page

An options page typically allows the user to enter some data, which of course must be saved when the user presses the OK button. When the options page is displayed it should show the data which the user entered previously. In case nothing has ever been entered, the options page could show some “default” data or nothing at all. 

How the data is saved and where it is stored is not covered by the specification. It only defines the events “ok”, “initialize”, and “back” which the extension needs to process in order to save the entered data, initialize the controls with data, or restore the state of the controls with the previously saved data.  The “ok” and “back” events are triggered by the “OK” and “Back” button of the options dialog. “initialize” is called before the options page is being displayed. In most cases “initialize” and “back” have the same meaning.

In order to receive these events one has to provide a service that implements the interface com.sun.star.awt.XContainerWindowEventHandler. The component is then installed like any other component. That is, one provides for example a jar file or a dll and adds the proper entries to the manifest.xml. 

The action events are processed in the com.sun.star.awt.XContainerWindowEventHandler.callHandlerMethod. This method takes three parameter. The first is a  com.sun.star.awt.XWindow which represents the dialog for which the event is called. The second is an com.sun.star.uno.Any, which describes the actual event. Therefore the IDL calls it the “EventObject”. The last parameter is a string which contains a “method name”. This method may not exists, but the name identifies an action which should be invoked.

In case of our previously mentioned events the method is called with the respective XWindow interface, a method name of “external_event”, and an any containing either  “ok”, “back”, or “initialize”. For example, the java code could look like this:

        public boolean callHandlerMethod(com.sun.star.awt.XWindow aWindow,

                                        Object aEventObject, String sMethod)

            throws WrappedTargetException {

            if (sMethod.equals("external_event") ){

                try {

                    return handleExternalEvent(aWindow, aEventObject);

                } catch (com.sun.star.uno.RuntimeException re) {

                    throw re;

                } catch (com.sun.star.uno.Exception e) {

                    throw new WrappedTargetException(sMethod, this, e);

                }

            } else if (sMethod.equals("another_method_name") ){

                ...

           }

               

            return true;

        }

       

         private boolean handleExternalEvent(com.sun.star.awt.XWindow aWindow, Object aEventObject)

            throws com.sun.star.uno.Exception {

            try {

                String sMethod = AnyConverter.toString(aEventObject);

                if (sMethod.equals("ok")) {

                    saveData(aWindow);

                } else if (sMethod.equals("back") || sMethod.equals("initialize")) {

                    loadData(aWindow);

                }

            } catch (com.sun.star.lang.IllegalArgumentException e) {

                throw new com.sun.star.lang.IllegalArgumentException(

                    "Method external_event requires a string in the event object argument.", this,

                   (short) -1);

            }

The method saveData and loadData need to be implemented according to where the data actually is stored. In most cases the OOo's registry is a suitable place. Then, of course, one needs to provide a configuration schema (requires an appropriate entry in the manifest.xml as well).  

For example: 

<?xml version="1.0" encoding="UTF-8"?> 

<oor:component-schema xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" oor:name="ExtensionData" oor:package="org.openoffice.desktop.deployment.options" xml:lang="en-US"> 

  <info>

    <author></author>

    <desc>Contains the options data used for the test extensions.</desc>

  </info>

  <templates>

    <group oor:name="Leaf">

      <info>

        <desc>The data for one leaf.</desc>

      </info>

      <prop oor:name="String0" oor:type="xs:string">

        <value></value>

      </prop>

      <prop oor:name="String1" oor:type="xs:string">

        <value></value>

      </prop>

      <prop oor:name="String2" oor:type="xs:string">

        <value></value>

      </prop>

      <prop oor:name="String3" oor:type="xs:string">

        <value></value>

      </prop>

      <prop oor:name="String4" oor:type="xs:string">

        <value></value>

      </prop>

    </group>

  </templates>

  <component>

    <group oor:name="Leaves">

      <node-ref oor:name="Writer1" oor:node-type="Leaf" />

      <node-ref oor:name="Writer2" oor:node-type="Leaf" />

        <!-- .... -->

    </group>

  </component>

</oor:component-schema> 

Please make sure that the package (oor:package) together with the name (oor:name) for this schema are unique.  For example, it should  start with YOUR reversed domain name (do not use org.openoffice in your code), followed by the product name and other values which together uniquely identify this registry node.

 In the example I have defined a group “Leaves”, which contains several entries and which are all of the same type. Each entry holds the data for one options page. In this case, each options page may provide five different strings.

If a new version of the extension uses the same schema, then data, which have been entered by a user for the previous version, will be automatically applied for the new version. If this is not wanted then one need to provide a new schema. In our case we could just change the attribute  oor:component-schema@ oor:name to a value, for example, ExtensionData2.

Now the question is, how one can access the controls on the options page in order to set the data or read from them. The following code example shows the whole service as Java implementation. Please have look at the loadData and saveData method. Please be aware that is is only an example and may need to be adapted to personal needs.

 

package com.sun.star.comp.extensionoptions; 

 

import com.sun.star.lib.uno.helper.Factory; 

import com.sun.star.lib.uno.helper.WeakBase; 

import com.sun.star.lang.XMultiComponentFactory; 

import com.sun.star.lang.XSingleComponentFactory; 

import com.sun.star.lang.XMultiServiceFactory; 

import com.sun.star.lang.WrappedTargetException; 

import com.sun.star.lang.IllegalArgumentException; 

import com.sun.star.lang.XInitialization; 

import com.sun.star.lang.XTypeProvider; 

import com.sun.star.lang.XServiceInfo; 

import com.sun.star.lang.WrappedTargetException; 

import com.sun.star.uno.UnoRuntime; 

import com.sun.star.uno.Any; 

import com.sun.star.uno.AnyConverter; 

import com.sun.star.uno.XComponentContext; 

import com.sun.star.uno.Exception; 

import com.sun.star.registry.XRegistryKey; 

import com.sun.star.awt.XContainerWindowEventHandler; 

import com.sun.star.awt.XControl; 

import com.sun.star.awt.XControlModel; 

import com.sun.star.awt.XControlContainer; 

import com.sun.star.container.XNameAccess; 

import com.sun.star.container.NoSuchElementException; 

import com.sun.star.beans.PropertyValue; 

import com.sun.star.beans.PropertyState; 

import com.sun.star.beans.XPropertySet; 

import com.sun.star.beans.UnknownPropertyException; 

import com.sun.star.beans.PropertyVetoException; 

import com.sun.star.util.XChangesBatch; 

 

/** A handler which supports multiple options pages which all 

 *  have the same controls.

 */

public class OptionsEventHandler { 

 

    public static class _OptionsEventHandler extends WeakBase

        implements XServiceInfo, XContainerWindowEventHandler {

 

        static private final String __serviceName =

        "com.sun.star.comp.extensionoptions.OptionsEventHandler";

   

        private XComponentContext m_cmpCtx;

 

        private XMultiComponentFactory m_xMCF;

 

        private XNameAccess m_xAccessLeaves;

 

        /**Names of supported options pages.

         */

        private String[] m_arWindowNames = {

            "Writer1", "Writer2", "Writer3", "Calc1", "Calc2", "Calc3",

            "Draw1", "Draw2", "Draw3", "Node1_1", "Node1_2", "Node1_3",

            "Node2_1", "Node2_2", "Node2_3", "Node3_1", "Node3_2", "Node3_3"};

 

        /**Names of the controls which are supported by this handler. All these

         *controls must have a "Text" property.

         */

        private String[] m_arStringControls = {

            "String0", "String1", "String2", "String3", "String4"};

       

        public _OptionsEventHandler(XComponentContext xCompContext) {

                m_cmpCtx = xCompContext;

                m_xMCF = m_cmpCtx.getServiceManager();                

 

            //Create the com.sun.star.configuration.ConfigurationUpdateAccess

            //for the registry node which contains the data for our option

            //pages.

            XMultiServiceFactory xConfig;

            try {

                xConfig = (XMultiServiceFactory) UnoRuntime.queryInterface(

                    XMultiServiceFactory.class,

                    m_cmpCtx.getServiceManager().createInstanceWithContext(

                        "com.sun.star.configuration.ConfigurationProvider", m_cmpCtx));

            } catch (com.sun.star.uno.Exception e) {

                e.printStackTrace();

                return;

            }

 

            //One argument for creating the ConfigurationUpdateAccess is the "nodepath".

            //Our nodepath point to the node of which the direct subnodes represent the

            //different options pages.

            Object[] args = new Object[1];

            args[0] = new PropertyValue(

                "nodepath", 0, "/org.openoffice.desktop.deployment.options.ExtensionData/Leaves",

                PropertyState.DIRECT_VALUE);

 

            //We get the com.sun.star.container.XNameAccess from the instance of

            //ConfigurationUpdateAccess and save it for later use.

            try {

                m_xAccessLeaves = (XNameAccess) UnoRuntime.queryInterface(

                    XNameAccess.class, xConfig.createInstanceWithArguments(

                        "com.sun.star.configuration.ConfigurationUpdateAccess", args));

 

            } catch (com.sun.star.uno.Exception e) {

                e.printStackTrace();

                return;

            }

        }

       

        /** This method returns an array of all supported service names.

         * @return Array of supported service names.

         */

        public String[] getSupportedServiceNames() {

            return getServiceNames();

        }

 

        /** This method is a simple helper function to used in the

         * static component initialisation functions as well as in

         * getSupportedServiceNames.

         */

        public static String[] getServiceNames() {

            String[] sSupportedServiceNames = { __serviceName };

            return sSupportedServiceNames;

        }

     

        /** This method returns true, if the given service will be

         * supported by the component.

         * @param sServiceName Service name.

         * @return True, if the given service name will be supported.

         */

        public boolean supportsService( String sServiceName ) {

            return sServiceName.equals( __serviceName );

        }

   

        /** Return the class name of the component.

         * @return Class name of the component.

         */

        public String getImplementationName() {

            return  _OptionsEventHandler.class.getName();

        }

 

        //XContainerWindowEventHandler

        public boolean callHandlerMethod(com.sun.star.awt.XWindow aWindow,

                                        Object aEventObject, String sMethod)

            throws WrappedTargetException {

            if (sMethod.equals("external_event") ){

                try {

                    return handleExternalEvent(aWindow, aEventObject);

                } catch (com.sun.star.uno.RuntimeException re) {

                    throw re;

                } catch (com.sun.star.uno.Exception e) {

                    throw new WrappedTargetException(sMethod, this, e);

                }

            }

               

            return true;

        }

       

        //XContainerWindowEventHandler

        public String[] getSupportedMethodNames() {

            return new String[] {"external_event"};

        }

 

        private boolean handleExternalEvent(com.sun.star.awt.XWindow aWindow, Object aEventObject)

            throws com.sun.star.uno.Exception {

            try {

                String sMethod = AnyConverter.toString(aEventObject);

                if (sMethod.equals("ok")) {

                    saveData(aWindow);

                } else if (sMethod.equals("back") || sMethod.equals("initialize")) {

                    loadData(aWindow);

                }

            } catch (com.sun.star.lang.IllegalArgumentException e) {

                throw new com.sun.star.lang.IllegalArgumentException(

                    "Method external_event requires a string in the event object argument.",

                    this, (short) -1);

            }

           

            return true;

        }

 

        private void saveData(com.sun.star.awt.XWindow aWindow)

            throws com.sun.star.lang.IllegalArgumentException,

            com.sun.star.uno.Exception {

 

            //Determine the name of the options page. This serves two purposes. First, if this

            //options page is supported by this handler and second we use the name two locate

            //the corresponding data in the registry.

            String sWindowName = getWindowName(aWindow);

            if (sWindowName == null)

                throw new com.sun.star.lang.IllegalArgumentException(

                    "This window is not supported by this handler", this, (short) -1);

 

            //To access the separate controls of the window we need to obtain the

            //XControlContainer from the window implementation

            XControlContainer xContainer = (XControlContainer) UnoRuntime.queryInterface(

                XControlContainer.class, aWindow);

            if (xContainer == null)

                throw new com.sun.star.uno.Exception(

                    "Could not get XControlContainer from window.", this);

 

            //This is an implementation which will be used for several options pages

            //which all have the same controls. m_arStringControls is an array which

            //contains the names.

            for (int i = 0; i < m_arStringControls.length; i++) {

 

                //To obtain the data from the controls we need to get their model.

                //First get the respective control from the XControlContainer.

                XControl xControl = xContainer.getControl(m_arStringControls[i]);

 

                //This generic handler and the corresponding registry schema support

                //up to five text controls. However, if a options page does not use all

                //five controls then we will not complain here.

                if (xControl == null)

                    continue;

 

                //From the control we get the model, which in turn supports the

                //XPropertySet interface, which we finally use to get the data from

                //the control.                

                XPropertySet xProp = (XPropertySet) UnoRuntime.queryInterface(

                    XPropertySet.class, xControl.getModel());

 

                if (xProp == null)

                    throw new com.sun.star.uno.Exception(

                        "Could not get XPropertySet from control.", this);

                //Get the "Text" property.

                Object aText = xProp.getPropertyValue("Text");

                String sValue = null;

 

                //The value is still contained in a com.sun.star.uno.Any - so convert it.

                try {

                    sValue = AnyConverter.toString(aText);

                } catch (com.sun.star.lang.IllegalArgumentException e) {

                    throw new com.sun.star.lang.IllegalArgumentException(

                        "Wrong property type.", this, (short) -1);

                }

 

                //Now we have the actual string value of the control. What we need now is

                //the XPropertySet of the respective property in the registry, so that we

                //can store the value.

                //To access the registry we have previously created a service instance

                //of com.sun.star.configuration.ConfigurationUpdateAccess which supports

                //com.sun.star.container.XNameAccess. The XNameAccess is used to get the

                //particular registry node which represents this options page.

                //Fortunately the name of the window is the same as the registry node.

                XPropertySet xLeaf = (XPropertySet) UnoRuntime.queryInterface(

                    XPropertySet.class, m_xAccessLeaves.getByName(sWindowName));

                if (xLeaf == null)

                    throw new  com.sun.star.uno.Exception(

                        "XPropertySet not supported.", this);

 

                //Finally we can set the value

                xLeaf.setPropertyValue(m_arStringControls[i], sValue);

            }

 

            //Committing the changes will cause or changes to be written to the registry.

            XChangesBatch xUpdateCommit =

                (XChangesBatch) UnoRuntime.queryInterface(XChangesBatch.class, m_xAccessLeaves);

            xUpdateCommit.commitChanges();

        }

 

        private void loadData(com.sun.star.awt.XWindow aWindow)

            throws com.sun.star.uno.Exception {

 

            //Determine the name of the window. This serves two purposes. First, if this

            //window is supported by this handler and second we use the name two locate

            //the corresponding data in the registry.

            String sWindowName = getWindowName(aWindow);

            if (sWindowName == null)

                throw new com.sun.star.lang.IllegalArgumentException(

                    "The window is not supported by this handler", this, (short) -1);

 

            //To acces the separate controls of the window we need to obtain the

            //XControlContainer from window implementation

            XControlContainer xContainer = (XControlContainer) UnoRuntime.queryInterface(

                XControlContainer.class, aWindow);

            if (xContainer == null)

                throw new com.sun.star.uno.Exception(

                    "Could not get XControlContainer from window.", this);

 

            //This is an implementation which will be used for several options pages

            //which all have the same controls. m_arStringControls is an array which

            //contains the names.

            for (int i = 0; i < m_arStringControls.length; i++) {

 

                //load the values from the registry

                //To access the registry we have previously created a service instance

                //of com.sun.star.configuration.ConfigurationUpdateAccess which supports

                //com.sun.star.container.XNameAccess. We obtain now the section

                //of the registry which is assigned to this options page.

                XPropertySet xLeaf = (XPropertySet) UnoRuntime