Language

The Free and Open Productivity Suite
Released: Apache OpenOffice 4.1.15











Scripting Framework Architecture











Revision: 0.1

Date: 19/11/03





Authors:

Noel Power




Project:

Scripting Framework










Table of Contents

Revision History 2

Introduction 2

UNO Language Bridge 2

Overview of Architecture 3

MasterScriptProvider 3

Responsibilites 3

Lifecycle 4

LanguageScriptProvider 4

Responsibilites 4

Scripting Framework URI 5

Storage of Scripts 5

How To implement a LanguageScriptProvider 5

Using framework helper classes ( Java Only ) 5

Using UNO. 6

Prerequisites 6

Creating the LanguageScriptProvider component 6

InvocationCtx 6

InvocationCtx Property Set 6

InvocationCtx String 6

LanguageScriptProvider expected behaviour 7

XBrowseNode method getName() 8

XBrowseNode method getChildNodes() 8

XBrowseNode method hasChildNodes() 8

XBrowseNode method getType() 9

Building a new LangaugeScriptProvider 9

Registering a new LanguageScriptProvider 10

Using the framework with Office 10

Appendix I 13

Interfaces 13

Appendix II 13

Skeleton Code 13

Appendix III 18

parcel-descriptor.xml DTD and example 18

Appendix IV 18

Directory Structure 18



Revision History

Revision

Date

Author

Comment

0.1

19/11/03

Noel Power

Initial draft



Introduction

By creating a new LanguageScriptProvider a developer can add support for the scripting language of their choice to OpenOffice.org. The Scripting Framework provides all the required plumbing needed to facilitate the detection, assigning and invocation of scripts for a LanguageScriptProvider. The LanguageScriptProvider just has to provide the language specific execution environment for the script and execute it. The framework takes care of the rest.

UNO Language Bridge

There must be a supported UNO bridge for the scripting language to allow the framework to make calls against this new scripting runtime. The bridge will take care of all the parameter marshalling that needs to occur as the framework makes the call to the invoke method written in the new language.

The Java and BeanShell Runtimes are supported by the existing Java UNO bridge. Any scripting language with a Java implementation could use the Java UNO bridge, such as Jython [Python], Jacl [Tcl/TK] andRhino [Javascript].

Overview of Architecture

MasterScriptProvider

Figure1 MasterScriptProvider ( name space ommited )





The MasterScriptProvider is an Office side UNO component which is an integral part of the framework. It implements a number of services and interfaces. See Figure 1. It is available and deployed as part of an Office installation .

Responsibilites

Lifecycle

By default MasterScriptProvider is created by any document that is opened. Its lifecycle will be tied to the life of the document that created it.

The MasterScriptProvider can also be created standalone, in which case it will exist as long as a reference to it is held by the client that creates it.

The MasterScriptProvider is a lightweight object. It maintains some static state that will be available to all instances of the MasterScriptProvider ( such as list of currently open documents). The LanguageScriptProviders themselves are also intended to be lightweight objects. The MasterScriptProvider hides the details of the construction and access of the LanguageScriptProviders from clients and users.

LanguageScriptProvider



Figure 2. LanguageScriptProvider for language XXXX (namespace omitted)



The LanguageScriptProvider is an UNO component that provides the environment to execute a script for a specific language. For example when office encounters a scripting framework URI ( see Scripting Framework URI section ) in an event assignment it delegates to a MasterScriptProvider which in turn finds the appropriate LanguageScriptProvider to execute the script.

Responsibilites



Scripting Framework URI specification

vnd.sun.star.script://<script_name>['?'<query_element>('&'<query_element>)*]]

script_name is something meaningful that the ScriptProvider can use to determine what script to run.

Parameter

Description

language

identifies identifies the language, or LanguageScriptProvider to be used to process the URI e.g. language=StarBasic, language=Java, language=JavaScript

location

identifies the container for the script, could be document, user, share e.g. A placeholder to allow relative addressing of the document, user and share areas, the current Scripting Framework URI scheme caters for this by allowing location to be “user”, “share” or “document” indicating the location of the script is located in “install_path/User/Scripts/<language>”, “install_path/Share/Scripts/<language>” or document identified by the invocation context.

note: location could be another URI e.g. “file://” or “vnd.sun.star.pkg://”.

Currently only user/share or document are supported by the framework..



MAY CHANGE, for the next milestone we are going to be using a new UNO URL service, format may slightly change as a result of conformance to general office URL formating conventions.



Storage of Scripts

A LanguageScriptProvider is responsible for knowing about how its own scripts are stored, where, what format and what kind of directory structure is used.

The scripting framework however attempts to standardise how to store and discover scripts by defining

In addition the scripting framework provides a mechanism for packaging and deploying scripts that wish to use these framework defined structures ( see using commandline-tools)

Note: it is up to the developer to decide whether they use these features or not.

How To implement a LanguageScriptProvider

To implement a LanguageScriptProvider you need to create an UNO component. The component needs to satisfy certain criteria



Using framework helper classes ( Java Only )

To bypass the complexity of UNO and to reduce the cost of developing an UNO component the Scripting Framework provides a helper class in the form of an abstract base class com.sun.star.script.framework.provider.ScriptProvider. This class can be found in the ScriptFramework.jar. This jar file will be available at runtime located in the “OFFICE_INSTALL_PATH/program/classes” directory.

To create an UNO service to support the scripting language you wish to create a LanguageScriptProvider for, you just

See section on building a new LanguageScriptProvider for details on the tools available for building you new implementation.

Using UNO.

Prerequisites

Have read and understood the following chapters in the Office Developer Guide.

Familiarity with building office components either manually or using OpenOffice SDK

Creating the LanguageScriptProvider component

Create UNO component drafts.com.sun.star.script.provider.ScriptProviderForXXXX according to the guidelines outlined in the prerequisites mentioned above.

In addition to the interfaces mentioned in the service description it is also necessary for the component to implement the com.sun.star.lang.XInitialization interface.

LanguageScriptProviders are created and initialised by the MasterScriptProvider with an Invocation context.

Invocation Context

The invocationCtx either an implementation of com.sun.star.beans.XPropertySet or an OUString setup by the MasterScriptProvider to pass context information to the LanguageScriptProvider. The context a LanguageScriptProvider is created with determines its behaviour in terms of both execution and what scripts it returns via the XBrowseNode API.

Invocation Context Property Set

Property Key

Type

Description

DOC_REF

XModel

The XModel of the current document

DOC_URI

OUString

The document URI of the current document


Invocation Context String

Contains a url to a location on the file system that contains scripts e.g. OFFICE_INSTALL_PATH/user or OFFICE_INSTALL_PATH/share



LanguageScriptProvider expected behaviour

As mentioned above the new LanguageScriptProvider service will be instantiated by the MasterScriptProvider. It will be passed an invocation context ( invocationCtx described above ) as a parameter of the initialise() method .

Xinitialization Method initialize()

Parameter Types

Parameters

Description

[in] sequence< any >

aParams

An invocation context. Contains either reference to the XModel ( representing a document context ) or location of user or share directory (representing and application context ).



A LanguageScriptProvider should

XScriptProvider Method getScript()

Parameter Types

Parameters

Description

[in] string

URL

URL to script.


ReturnType

Description

XScript

Instance of an object implementing the XScript interface that represents a script that will execute against the context of the LanguageScriptProvider that created it. This means that when the invoke() method of this object is called that script will act on the document from which the script was invoked.

Note: It is up to the LanguageScriptProvider to decide what information to pass to a running script. It makes sense to pass information to the script which makes the script writer's job easier, such as a reference to the current document ( context ), reference to the service manager (available from the component context passed into the LanguageScriptProvider component's constructor by UNO) and a reference to the desktop (available from UNO using this service manager).

All of the Java based reference LanguagesScriptProviders provided with Office make this information available to the running script in the form of an object implementing the interface drafts.com.sun.script.provider.XScriptContext. This provides accessor methods to get the current document, the desktop and the component context. Depending on the contraints of the language this information is passed to the scripts in different ways, for example in Beanshell and JavaScript this is available as an environment variable and in the case of Java it is passed as a parameter to the script.

Xscript invoke() method.

Parameter Types

Parameters

Description

[in] string

scriptURI

Original URI passed to the framework

[in] sequence< any >

aParams

Input parameters

[out] sequence< short >

aOutParamIndex

Output parameter index

[out] sequence< any >

aOutParam

Output parameters




ReturnType

Description

Any

Return value of script.


XScriptContext methods


XscriptContext Method

Returns

Description

getDocument

XModel

Access to the current document.

getDesktop

XDesktop

Access to the current desktop.

getComponentContext

XComponentContext

Can be used by the script to get the default multi component factory to create other UNO services.





The Browse interfaces ( XBrowseNode ) exported by the new LanguageScriptProvider service are the initial point of contact for the office application. In order for the Office process to display all scripts it first needs to create all available LanguageScriptProviders, each LanguageScriptProvider is created with a context (see above). Depending on how the new LanguageScriptProvider is initialised it will enumerate the scripts stored in that context. It is expected that the LanguageScriptProvider implementation will return the language name as the name of the top-level CONTAINER node. It is up to the LanguageScriptProvider how to arrange the hierarchy of the scripts and how they are presented to the user.

XBrowseNode method getName()

ReturnType

Description

string

Name of Node.

XBrowseNode method getChildNodes()

ReturnType

Description

Sequence <XBrowseNode>

Children of this node.

XBrowseNode method hasChildNodes()

ReturnType

Description

boolean

True if children exist, false otherwise

XBrowseNode method getType()

ReturnType

Description

short

Constant defined in BrowseNodeTypes.idl indicating that node is

  • the root node ( Reserved for use by the MasterScriptProvider service )

  • a container of other nodes

  • a script



XBrowseNode implementations of type BrowseNodeTypes.SCRIPT is treated by OpenOffice.org as a special node see Figure 3. below.

Figure 3.



PropertySet 1. available from node of type SCRIPT ( BroswseNodeTypes.idl in Appendix I )

Key

Value type

URI

string

EDITABLE

boolean

In order for Office to be able to assign a script it needs to be able to retrieve the scripting framework URI that describes the script. When a XBrowseNode implementation of type SCRIPT is selected it needs to export the URI as a property named URI. Similarly it is possible to integrate an IDE that is capable of editing the script by exporting a property named Editable. The script XBrowseNode implementation object needs to also implement the com.sun.star.script.XInvocation interface. This allows the implementation object to receive a request to edit the script. It is up the implementation to call the IDE and pass it the information required for the IDE to be able to edit and invoke the script.

The prototype ScriptSelector GUI demonstrates this capability for the reference LanguageScriptProviders which are shipped with Office . See Figure 6.

Building a new LanguageScriptProvider

It is possible to build a new LanguageScriptProvider component using either the SDK or by integrating changes directly in to the scripting framework project and using OpenOffice build environment.

This section will only cover how to manually build a Java LanguageScriptProvider.

Registering a new LanguageScriptProvider

Assuming the new LanguageScriptProvider is bundled in an uno package file called newProvider.zip

  1. Exit Office ( on windows make sure that the QuickStarter is also shut down )

  2. copy newProvider.zip into INSTALL_DIR/Program directory

  3. From INSTALL_DIR/Program run the pkgchk command

    1. ./pkgchk newProvider.zip ( unix systems )

    2. pkgchk.exe newProvider.zip ( windows systems )

Using the framework with Office

Scripts in Office are executed in two ways

One of the main entry points to associate such actions with scripts is the Tools/Configure dialog ( shown in Figure 4.) To assign a script to a menu item

To invoke script select “File” in the drop down list, you should find the new menu item. Clicking on the new menu item should start the script.



Figure 4.



For detailed help please use the help provided by the clicking the“Help” button. The help text provided only considers Basic but should be sufficient to explain the functionality. There is a User Guide available for the Scripting Framework here. It is also possible to assign scripts to Dialogs, embedded Objects charts etc. These won't be covered in this document.

Additionally a number of scripts written in Beanshell, JavaScript and Java are provided as examples. These are all located under the share node contained by the “OpenOffice,org Scripts” root node. One of these scripts allows the user select a script and then edit that script in an appropriate IDE. To enable this dialog follow the instructions given above to create a menu assignment for the ScriptSelector.showOrganiser script see Figure 5.



Figure 5



Selecting File->ScriptSelector.showOrganiser should display the script selector ( Figure 6. )

To open the script in the IDE simply navigate to the script, if the script is editable and an IDE is available then the “Edit” button should be enabled.





Figure 6. Showing new language XXXX integrated with the scripting framework.


Appendix I

Interfaces

[ *** Links to the IDL or IDL doc for all of the scripting interfaces ]

Appendix II

Skeleton Code

package com.sun.star.script.framework.provider.xxxx;

import com.sun.star.script.framework.provider.*;
import java.util.*;
import java.io.*;
import com.sun.star.uno.XComponentContext;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.lang.XInitialization;
import com.sun.star.lang.XTypeProvider;
import com.sun.star.lang.XServiceInfo;
import com.sun.star.lang.*;
import com.sun.star.registry.*;
import com.sun.star.frame.XModel;
import com.sun.star.util.XMacroExpander;

import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.AnyConverter;
import com.sun.star.uno.Type;
import com.sun.star.uno.Any;
import com.sun.star.lib.uno.helper.*;
import com.sun.star.comp.loader.*;

import com.sun.star.beans.XPropertySet;

import com.sun.star.lang.IllegalArgumentException;
import com.sun.star.lang.WrappedTargetException;
import com.sun.star.reflection.InvocationTargetException;
import com.sun.star.script.CannotConvertException;

import drafts.com.sun.star.script.provider.XScriptContext;
import drafts.com.sun.star.script.framework.storage.XScriptInfo;
import drafts.com.sun.star.script.provider.XScriptProvider;
import drafts.com.sun.star.script.provider.XScript;
import drafts.com.sun.star.script.browse.XBrowseNode;
import drafts.com.sun.star.script.browse.BrowseNodeTypes;

import com.sun.star.script.framework.log.LogUtils;
import com.sun.star.script.framework.browse.DirBrowseNode;
import com.sun.star.script.framework.browse.DocBrowseNode;
import com.sun.star.script.framework.browse.XMLParserFactory;
import java.net.*;

public class ScriptProviderForXXXX
{
    static private final String[] __serviceNames = {
        "drafts.com.sun.star.script.provider.ScriptProviderForXXXX",
        "drafts.com.sun.star.script.provider.LanguageScriptProvider" };

    public static class _ScriptProviderForXXXX extends ScriptProvider
    {
        public _ScriptProviderForXXXX(XComponentContext ctx)
        {
            super(ctx, "XXXX");
        }

        /**
         * The invoke method of the ScriptProviderForXXXX runs the
         * XXXX script specified in the URI
         *
         *
         * @param scriptName The scriptName is the language specific
         * name of the script
         *
         * @param invocationCtx The invocation context contains the
         * documentStorageID and document reference
         * for use in script name resolving
         *
         * @param aParams All parameters; pure, out params are
         * undefined in sequence, i.e., the value
         * has to be ignored by the callee
         *
         * @param aOutParamIndex Out indices
         *
         * @param aOutParam Out parameters
         *
         * @returns The value returned from the function
         * being invoked
         *
         * @throws IllegalArgumentException If there is no matching script name
         *
         * @throws CannotConvertException If args do not match or cannot
         * be converted the those of the
         * invokee
         *
         * @throws InvocationTargetException If the running script throws
         * an exception this information
         * is captured and rethrown as
         * this exception type.
         */
         
        private Object invoke( /*IN*/String scriptURI,
                               /*IN*/Object invocationCtx,
                               /*IN*/Object[] params,
                               /*OUT*/short[][] aOutParamIndex,
                               /*OUT*/Object[][] aOutParam )
        
            throws IllegalArgumentException, InvocationTargetException,
                   CannotConvertException
        {
            // Initialise the out paramters - not used at the moment
            aOutParamIndex[0] = new short[0];
            aOutParam[0] = new Object[0];
        
            XPropertySet languageProps = m_xScriptInfo.getLanguageProperties();
            String cp = null;
        
            // Set up ClassLoader based on property defined with script
            try {
                cp = (String)languageProps.getPropertyValue(CLASSPATH);
            }
            catch (Exception e) {
            }
        
            if (cp == null) {
                cp = "";
            }
        
            String parcelURI = m_xScriptInfo.getParcelURI();
            if (!parcelURI.endsWith("/")) {
                parcelURI += "/";
            }
        
            Vector classpath;
            try {
                classpath = PathUtils.buildClasspath(parcelURI, cp);
            }
            catch (MalformedURLException mue) {
                throw new InvocationTargetException(mue.getMessage());
            }
        
            ClassLoader cl = null;
            try {
                cl = ClassLoaderFactory.getClassLoader(m_xContext,
                this.getClass().getClassLoader(), classpath);
            }
            catch (Exception e)
            {
                throw new InvocationTargetException(e.getMessage());
            }
        
            try {
                String script = parcelURI + m_xScriptInfo.getFunctionName();
                InputStream is;
                Object result = null;
        
                try {
                    is = PathUtils.getScriptFileStream( script, m_xContext );
                }
                catch (IOException ioe) {
                    throw new InvocationTargetException(ioe.getMessage());
                }
        
                if (is == null) {
                    throw new InvocationTargetException("Could not load script");
                }
        
                try {
                //****
                //* INSERT CODE TO CALL MyScriptingLanguage here
                //* variables you can use
                //* is = stream to script
                //* cl = a classLoader that is setup with the classpath requirements
                //* specified in the parcel-descriptor.xml
                //* parcelURI path to location of parcel directory that contains the
                //* script(s)
                //*
                //****
                }
                catch (Exception e) {
                    e.printStackTrace();
                    throw new InvocationTargetException(e.getMessage());
                }
                finally {
                    try {is.close();} catch (IOException ignored) {}
                }
        
                return result;
            }
            catch (Exception ex) {
                ex.printStackTrace();
                throw new InvocationTargetException(ex.getMessage());
            }
        }
        
        public Object invoke( /*IN*/Object[] aParams,
                              /*OUT*/short[][] aOutParamIndex,
                              /*OUT*/Object[][] aOutParam )
            throws IllegalArgumentException, CannotConvertException,
                   InvocationTargetException
        {
             return invoke(m_scriptURI, m_xInvocationContext, aParams,
             aOutParamIndex, aOutParam);
        }
    }
        
    /**
    * Returns a factory for creating the service.
    * This method is called by the JavaLoader
    * 

* * @param implName the name of the implementation for which a service is desired * @param multiFactory the service manager to be used if needed * @param regKey the registryKey * @return returns a XSingleServiceFactory for creating * the component * @see com.sun.star.comp.loader.JavaLoader */ public static XSingleServiceFactory __getServiceFactory( String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey ) { XSingleServiceFactory xSingleServiceFactory = null; if ( implName.equals( ScriptProviderForXXXX._ScriptProviderForXXXX.class.getName() ) ) { xSingleServiceFactory = FactoryHelper.getServiceFactory( ScriptProviderForXXXX._ScriptProviderForXXXX.class, "drafts.com.sun.star.script.provider.ScriptProviderForXXXX", multiFactory, regKey ); } return xSingleServiceFactory; } /** * Writes the service information into the given registry key. * This method is called by the JavaLoader *

* * @param regKey the registryKey * @return returns true if the operation succeeded * @see com.sun.star.comp.loader.JavaLoader */ public static boolean __writeRegistryServiceInfo( XRegistryKey regKey ) { String impl = "com.sun.star.script.framework.provider.xxxx." + "ScriptProviderForXXXX$_ScriptProviderForXXXX"; String service = "drafts.com.sun.star.script.provider." + "ScriptProviderForXXXX"; if (Factory.writeRegistryServiceInfo(impl, __serviceNames, regKey) ) { return true; } return false; } }

Appendix III

parcel-descriptor.xml DTD and example

Appendix IV

Directory Structure

At the top level in the uncompressed format of a document, OFFICE_INSTALL_PATH/user or OFFICE_INSTALL_PATH/share there exists a “Scripts” directory with the following structure below it.

Scripts/

|

+- java/

|

+- otherLanguage/



under the language specific directory



+- a_language_name/

|

+- "user named deployment directory"/

|

+- bin/

|

+- src/

|

+- data/

|

+- resource/

directly underneath the "user named deployment directory" is where the parcel-descriptor.xml file is located.



Note: WILL CHANGE Similar to above, the file structure above is expected for storage of scripts that use the framework helper classes. At the moment we are discussing ways to consolidate UNO packages so that scripts will also be supported. It will then be possible to deploy scripts as within such packages. This of course means that the storage

Scripting Framework Architecture Page 19 of 19

Apache Software Foundation

Copyright & License | Privacy | Contact Us | Donate | Thanks

Apache, OpenOffice, OpenOffice.org and the seagull logo are registered trademarks of The Apache Software Foundation. The Apache feather logo is a trademark of The Apache Software Foundation. Other names appearing on the site may be trademarks of their respective owners.