Rhino Scripting

WorkThru? now uses the Mozilla Rhino implementation of Javascript as its scripting language. This transition has been made for the following reasons:

  • Javascript is the most widely known scripting language. Jython, while elegant, is understood by many fewer developers.
  • Rhino is now being distributed as a part of the Java6 distribution. This makes deployment much simpler in some cases.
  • Rhino has a strong development base with a great deal of ongoing development. The current Jython release is five years old with very little ongoing development. The Wikipedia entry for Jython reads like an obituary.

The Java6 Scripting Interface

Java6 incorporates a new Scripting Interface (JSR-223) that allows any scripting language to be hooked into a Java application or framework. Rhino/Javascript is the reference implementation and a Rhino subset is shipped with Java6. Other scripting interfaces have also been implemented: JAwk, JRuby, Groovy, Beanshell, Jython and others.

The new WorkThru? implementation of Rhino, while being billed as a Rhino implementation, is really a JSR-223 implementation. Very little code (one method in the ScriptExecutor? and one supplementary class) is Rhino-specific. This allows the possibility for future implementations of other scripting languages for WorkThru?.

Deployment

There are two ways to deploy Rhino scripting: 1) using the internal Java6 implementation or 2) using the full Rhino distribution with the JSR-223 reference API. WorkThru? is distributed with the latter for the following reasons:

  • The 223 API does not pre-req Java6. The WorkThru? libraries and jars will work with your current Java version.
  • More of the Rhino implementation (such as the Java debugger and the bytecode compiler) are available only through the full Rhino distribution.

If you plan to deploy using this approach you will need the following new jars: js.jar (Rhino), script-api.jar (the abstract JSR-223 API), and script-js.jar (the Javascript-specific JSR-233 implemention of the API). These jars are included with the standard WorkThru? deliverables (in the workthru.zip file, in the Subversion repository, and in the Eclipse plugins directory).

If you are deploying on Java6 you also have the option of simply removing these jars and removing these jars from your classpath. WorkThru? will then use the internal Java6 Rhino implementation.

Configuration

The wipsite.xml file has been changed to support Rhino. The former <jython> section needs to be replaced with the <scriptenvironment> section. Here as a sample:

<scriptenvironment scripttype="Javascript">
	<debug enabled="true" host="localhost" port="15555" />
	<module location="./filepool/generalscript.js" />
</scriptenvironment>

The <scriptenvironment> tag can currently on have a scripttype attribute of 'Javascript'.

<debug> is used to allow a remote scripting window as described in ScriptDebugging. Note that there is no penalty to leaving <debug> enabled during development. If no script monitor is open the script does not attempt to debug. (For the current time continue to use 'jsdebug.py' -- the Jython monitor. There is no language issue between Jython and Rhino because they're in separate virtual machines).

The OPTIONAL <module> tag is the name of a specific file (not a directory) that contains Javascript functions that will be globally available anywhere within the WorkThru? session. This is ideal for placing utility functions.

WorkThru? script contexts

The WorkThru? script documentation provides details of many types of script execution: e.g. scripts, rules, needs, etc. Each type of script execution is documented with a "Context" that defines what objects WorkThru? will provide. In general these context definitions have remained the same as the Jython implementation. But there are a few differences.

The following are the context differences:

vars()

The new 'vars()' function displays the current context. This is similar to the internal Jython 'dir()' command. As an example, assume that we create a Wip script that consists only of 'vars()' and we call the script 'tt'. If we execute 'tt' we will see the context as the script is entered:

>>>wip.action("tt")
Local scope
args,scriptname,wip,wts
Global Scope
_commands_,booleanField,booleanFields,context,copyFields,copyFieldsByPrefix,createTimestamp,debug,
deleteFieldGroup,deleteFieldGroups,doubleField,doubleFields,exists,field,fieldGroup,fieldGroups,
insertFieldGroup,load,position,print,println,remove,set,setError,setField,setGlobal,setPosition,
setReturn,setWipPathAddr,stringField,stringFields,sumDoubleFields,vars,viewpos,wip,wipPathAddr,
wippath,wpath,wtScript,wtSite,wtUser,wts

The definitions of Local and Global scope is given in the section below.

Most of these values were set up by the WorkThru? context. However copyFields, copyFieldsByPrefix, and createTimestamp are user-defined functions that were defined in the <module> tag of the <scriptenvironment>.

setReturn(<object>)

This function has been renamed. It was previously 'setreturn(<object>)'.

setError(<object>)

This function has been renamed. It was previously 'seterror(<object>)'.

load(<javascript-filename>)

This function loads the file named <javascript-filename>. The functions contained in this file are loaded into the Global context.

set(<objName>,<object>,<scope>)

This function sets an object into the engine context. If <scope> is '100' it is Local scope. If <scope> is '200' it is a Global scope.

remove(<objName>, <scope>)

This function removes an object from the engine context. The scope values are the same as above.

setGlobal(<objName>, <object>)

This is a convenience function that is equivalent to set(<objName>, <object>, 200). It is also the same as the old function that was named 'setglobal'.

Script engine details

The following technical details will not be needed for many WorkThru? developers. But it does provide an architectural background for how the scripting environment works and what capabilities it possesses.

The central object of the JSR-223 Scripting Environment is the scripting 'engine'. The engine does the work of taking a data string or stream and executing it. The engine also maintains a context'. This context is where the host application sets up the variables that the script will work upon. The default context consists of a two kinds of maps. One map is called 'engine_scope' and the other is called 'global_scope'. Engine_scope is where variables are set for the current call. WorkThru? clears engine_scope after every script invocation. Global_scope is where variables are set for the either the duration of the engine or until they are explicitly removed.

WorkThru? wraps the Rhino scripting engine with a class called ScriptExecutor?. In a WorkThru? session there may be many instances of ScriptExecutors?. In particular there is a ScriptExecutor? associated with each WorkThruSession?. This instance can be used to execute scripts unrelated to any particular Wip (for example, a script that sifts through all the objects in an ObjectStore?).

There is also a ScriptExecutor? associated with each Wip. This is used for Wip-specific operations such as processing rules or needs. The separate instances prevent script contexts (especially global variables that may be saved between script invoications) from getting intermixed.

Ordinarily a WorkThru? developer doesn't need to understand these instances because the objects are set up implicitly by the WorkThru? environment. For example, when a rule is fired within a particular Wip the environment puts the correct ScriptExecutor? into the context. In some applications that involve cross-Wip interactions understanding these distinctions may inform development.