Script Application

All scripts are initialised with an object of type com.metrici.xerula.ScriptApplication, in variable "application". This provides access to the service request and allows the script to call other services.

ScriptApplication also provides a complete set of error fields. See Scripting errors for details.

put(name,value) Store an attribute against the application object. This allows you to pass values between scripts, and to return values from the script.
remove(name) Remove an attribute from the application object.
Object = get(name)

String = getString(name)

double = getNumber(name)

int = getInt(name)

Retrieve an attribute stored against the application object. The getString, getNumber and getInt retrieve as String, double or Int respectively.
ServiceMessageWriter = newServiceRequest(serviceName) Create and return a Service Message Writer object which you can use to call another service.
ServiceMessageWriter = newServiceResponse(responseName) Create a Service Message Writer to hold the XML response of the service. The result of the script, in the return attribute, is automatically set to the response.
ServiceMessageWriter = newMessageWriter(elementName) Create a Service Message Writer object which you can use to create any XML.

This is different from newServiceRequest() because it does not surround the XML with the "Run" element, and so can not be used to run services. It is different from newServiceResponse() because it does not set the return attribute.

XPathEvaluator = parse(ServiceMessageWriter) Parse a message from a Service Message Writer. Any user credentials in the message are automatically removed (so that this can not be used to intercept credentials on service message requests).

XPathEvaluator = service(serviceRequest
[,addCredentials=true|false
[,mergeErrors=true|false]])

XPathEvaluator = service(serviceRequest,ServiceCredentials
[,mergeErrors=true|false])

Runs a service request. serviceRequest can be a service message writer or a string. Returns an XPath Evaluator object containing the result.

By default, this will automatically inherit the credentials (user logon reference and password, etc) from the calling service. Use service(message,false) to run a service request without adding credentials. Use service(message,credentials) to run a service with different credentials.

If there are any errors, these are by default merged into the application's error state. This means that if the error state is not already set, then errors from the service will set the error state. (Also, system errors, other than error 105, will overwrite user error 105.)

If mergeErrors is false, then errors from the service are not merged into the application's error state.

Each service is run under a fresh database connection. If the service needs to access nodes created by this script, then the script must commit those changes using application.commit(), or the service will not be able to see the changes.

boolean = include(node[,memberType[,allowNull]]) Run the script contained in another node, as if it were included in the current script.

memberType identifies the member on the node which contains the script. It is optional, and defaults to Script (system.NODE_SCRIPT).

The node and memberType can be specified by integer, String or Script Node (but the second can only be a script node if the first is one).

The included script has the same context node as the including script.

The included script has full read and write access to the attributes, global variables and credentials of the including script.

Returns true if there are no errors in the included script, false if there are errors.

If the node does not exist, the user is not authorised to read it, or the script raises an exception, an exception will be raised. allowNull specifies what to do when the node exists but the script is null. If allowNull is true, no error is raised and the method returns true. If false (the default) an exception is raised. 

boolean = execute(node,method[,allowNull]) Run a script against another node. Return false if the node can not be found.

method identifies the memberType on the type which contains the script.

Return value and allowNull is as for include()

The node and memberType can be specified by integer, String or Script Node (but the second can only be a script node if the first is one).

The executed script runs in the context of the specified node.

The executed script has full read and write access to the attributes of the executing script. It has a copy of the credentials of the executing script, but if it changes credentials then these changes are not passed back to the executing script. The executed script has no access to the executing script's global variables, and vice versa.

Deprecated versions of this method have an additional call type parameter before the allowNull which specifies whether to read the method from the node type or instance. If callType is 'type', these should be converted to execute() without the third parameter, or if callType is 'instance', to a call() method.

boolean = call(node[,memberType[,allowNull]]) Run a script contained in another node using the current context.

This is the same as execute, except that the node and method are specified the same as the node and memberType on include, and the script runs using the context of the calling node.

call() allows scripts defined for use on one node to be applied to another, for example to call scripts defined on inherited-from nodes but overridden.

call() is analogous to call() in JavaScript, which allows a method to be called with a different context.

object = require(node[,memberType[,allowNull]])

Run a script contained in another node using the current context, and return the value of the "exports" attribute.

If the script has been required before by this application object, do not run it again, just return the value of the "exports" attribute.

Within the called script, the "exports" attribute is set to an empty object. The script can add to this or overwrite this. The previous values of the "exports" attribute is preserved when making a require(), so using require() within a required script works.

This is similar to require() within Node.js, and can be used instead of import() for loading classes. It has the advantages of not polluting global variables and of allowing classes to be referenced in multiple places without re-reading the definition.

If the node does not exist, the user is not authorised to read it, or the script raises an exception, an exception will be raised. allowNull specifies what to do when the node exists but the script is null. If allowNull is true, no error is raised and the method returns null. If false (the default) an exception is raised. 

setCredentials(serviceCredentials)

setCredentials(userLogonReference,password)

resetCredentials()

Change the default credentials used by newServiceRequest. This is useful if the script creates a new user and then calls scripts as that new user.

resetCredentials() resets the credentials to those of the script user.

credentials = getCredentials() Get the current credentials. This can be useful before using runAsOwner(), to allow calls to be made as the original caller.
extendTimeout() Gives the script a bit more time to complete.
sleep(milliseconds) Suspend the script for the given number of milliseconds. This can be useful between service calls to give other threads a chance to access resources.
runAsOwner() Run as the owner of the context node. This is always permitted (since the owner has control over the script anyway). Raise an error if the context node is not set, or the context node does not have an owner (for example, because it is a system node).
userIdentifier = getUserIdentifier() Retrieve the identifier of the current user.
String = getUserLogonReference() Get the logon reference of the current user.
ScriptUser = getUser([user])

Return a Script User object for a given user, or the current user if omitted.

If the user is 0 or null, or the method is called when there is no user, it returns an empty Script User object.

If the method is called with an invalid user, or if you are not authorised to see the user details, the method returns null.

This means that getUser() will always return a user object, even if there is no user. getUser(user) may return null, if the user does not exist.

ScriptNode = getNode(node[,freshness]) Get a node, as a read-only Script Node. This allows the derived data of the node to be accessed. Node can be specified by reference as a string, by node version identifier as a number, or as another node object.

The optional freshness parameter specifies whether the data on the node should be fully up-to-date. It is a numeric parameter, with the following values:

  • 0 – Stale data (not up to date calculations) may be returned.
  • 1 – Data must be fresh, i.e. all calculations must be up-to-date.
  • 2 – Data should be refreshed, i.e. this node should be recalculated.
  • 3 – Data should be force-refreshed, i.e. this node and all its dependents should be recalculated.

The value defaults to 1, and should usually be left to default. Only use the other values if you have a specific need to do so.

If you are accessing nodes and do not care about their freshness (for example, getting the name and reference of a package or target), use a freshness of 0 to prevent unnecessary recalculations. Any nodes retrieved from this node may also be stale. This can significantly speed up some types of solution.

Freshness of 2 can be useful to force local recalculation, for example in a package that is not automatically updated when its content changes.

Freshness of 3 can also be useful to force local recalculation, and recalculation of anything that depends on the node. Use this option with caution as it can cause a large number of recalculations

If you want to navigate from a node to other nodes, but want to access stale data, you may need to re-retrieve the node, for example:

node = application.getNode(node,0);

ScriptNode = toNode(object) If object is a node, return the object. If it is a number or a string, look up the node with that node version id or reference, respectively. Return null if the node can not be found.
ScriptNodeWritableDerived = getNodeWritableDerived(node[,freshness]) Get a node, as a writable Script Node Writable Derived object. This allows the dervied data of the node to be read and updated.

The user must be the owner of the node or authorised to administer the node.

Node can be passed as a number, string or node. If passed as a node, a writable copy is returned, independent of the node that is passed in.

Freshness is as for getNode().

Return null if node not found or if the user is not authorised.

ScriptNodeWritableOriginal = getNodeWritable(node[,freshness]) Get a node, as a writable Script Node Writable Original object. This allows the original data of the node to be read and updated. Use the apply() method on the ScriptNodeWritableObject to write the updates to the database.

Node can be passed as a number, string or node. If passed as a node, a writable copy is returned, independent of the node that is passed in.

Return null if node not found.

ScriptNodeWritableOriginal = newNode(nodeType) Create a new node of the given type, as a writable Script Node Writable Original object. Use the apply() method on the Script Node Writable Object to write the new node to the database.

Return null if node type not found.

Return null and an error if unable to create a new object.

boolean = nodeExists(reference) Indicates whether a node exists. This detects whether a node exists even if the user has no authority to access it. It is useful to check uniqueness of references before creating nodes.
setUserData(object)
setUserData(node,data)
setUserData(node,user,data)

Set user-specific data associated with a node. object is a JavaScript object which will be merged with any existing user data for the node. Set values to undefined to delete user data properties.

node is optional and can be passed as a string, node identifier or script node object. It defaults to the value of the "contextNode" attribute or the value returned from application.getContext();

user is optional and can be passed as a string, user identifier or script user object. It defaults to the value of the "userCurrent" attribute or the user for the script.

object = getUserData()
object = getUserData(node)
object = getUserData(node,user)
Get user-specific data associated with a node, as a JavaScript object. Node and user as for setUserData()
string = escape(string) Escape a string to valid XML.
string = escapeUnicode(string[,others]) Escape a string to valid unicode.

Also escape any characters in the "others" string. e.g.

var myVar = '"' + application.escapeUnicode(rawData,'"') + '"';

string = filterHTML(string) Filter a string of HTML according to the Text formatting rules:
  • Fix any broken markup
  • Remove scripting and other potentially malicious content
  • In the top-level text elements only, add HTML markup to recreate line breaks and indentation
String = nodeURL(string) Turns a node reference or a node version reference into a URL.
boolean = checkPermissionToken(permissionToken [,user])

Indicate whether a user is permitted to perform an action on a resource, the action and resource being represented by a permission token.

User can be passed as a user logon reference or a user identifier. It is optional and defaults to the current user.

ScriptNodeWritable = getContext() Get the context node, i.e. the node that the script can update.

This will be a ScriptNodeWritableDerived object in all cases, except for validation scripts where this returns a ScriptNodeWritableOriginal object.

getSourceName() Returns name of source of script. Typically, but not always, this is of the form nnn/mmm, where nnn is the node version reference of the node that holds the script, and mmm is the node version reference of the member type on that node that holds the script.
XPathEvaluator = parse(String)

XPathEvaluator = parse(ServiceMessageWriter)

Parse data in a service message writer or string, for example returned from another script. Return null if the data can not be parsed.
commit() Commit database processing.
rollback() Rollback database processing. Note that this does not roll back database processing that takes place in called services, which are always committed at the end of the service.
application = getSafeApplication([allowServices])

Return an application object that does not provide data access. If the optional allowServices argument is true, the application object does allow service calls. Attempt to use the data access methods of a safe application object will result in an exception.

This is for specialist use for the safe evaluation of user-provided scripts.

sleep(millis) Suspend execution for the given number of milliseconds.
ScriptNode = getSourceNode() Return the node on which the current source is defined (not the originally called script). Returns null if source node has not been set, for example because the script is called directly from the RunScript service.
ScriptNode = getBinding(String) Returns the node bound on the source node with the given string. If the bounding can not be found, it returns null and sets the application error. See Scripting basics.

This is roughly equivalent to getSourceNode().getTargetByValue(), but raises errors.

String = stringify(object) Return the JavaScript object notation (JSON) string of the object. The object can be any JavaScript type, array, or object.

ScriptNodes are returned as their node version reference in a string.

ScriptMembers are returned as an object with value, scale and target members.

The function correctly processes the lists returned from other calls, so for example application.strinfigy(node.listTargets(foo)) works correctly.

The function will also work on all primitive types.

The script correctly returns the keywords null or undefined for null or undefined values within arrays or objects. It correctly returns a null when passed null. However, when passed avalue of undefined, it returns the string "undefined" rather than the undefined value. This is a restriction of the underlying scripting platform, and programs must not rely on this behaviour.

StringBuilder = newStringBuilder() Return a String Builder object for efficient string handling. This creates a default string builder object; if you want to set constructor parameters, use new java.lang.StringBuilder().
String = formatDateReadable(object [,short]) Format a date to be read, e.g. "1 November 2013". Input can be a date object or a string in format yyyy-mm-dd, or a string in format yyyy-mm-ddThh:mm:ss.sss. Will return null if the object is null, and may return a junked date if an invalid date format is passed.

If short is passed and set to true, short month names will be used, e.g. "1 Nov 2013".

String = formatTimestampReadable(object [,short]) Format a timestamp to be read, e.g. "1 November 2013 9:14". Input can be a date object or a timestamp in format yyyy-mm-ddThh:mm:ss.sss. Will return null if the object is null, and may return a junked date if an invalid date format is passed.

If short is passed and set to true, short month names will be used.

String = formatDate(date) Format a date object to yyyy-mm-dd. Will return null if the date is null.
String = formatTimestamp(date) Format a date object to yyyy-mm-ddThh:mm:ss.sss. Will return null if the date is null.
date = parseDate(string)

Parse the date (yyyy-mm-dd) or timestamp (yyyy-mm-ddThh:mm:ss.sss) string and return a date object. Returns null if date can not be parsed.

New solutions should consider using localDateTime which returns a string rather than a date object, and which supports relative time periods.

String = localDateTime()
String = localDateTime(ts)
String = localDateTime(base,ts)

Retrieves, converts, formats or performs calculations on timestamps.

When called with no parameters, returns the current timestamp as a string.

When passed a single parameter which is a date object or an ISO 8601 date or timestamp string, formats that as a timestamp.

When passed a single parameter which is an ISO 8601 time period, adds the period to the current timestamp and returns the result. The period is of the form PnYnMnDTnHnMnS, where: P is required; Y, M before the T and D are year, month, day; H, M after the T and S are hour minutes and seconds; T is mandatory if there are sub-day periods; n is a number that may be negative; n may exceed the number of units to make the next higher unit (e.g. P24M or PT180H); n must be integer except when specifying seconds; date/time parts need not be passed if they are zero. Examples are "P7D" for "seven days time", "PT-4H" for "four hours ago", or "P1Y1M7D".

When passed two parameters, the first will be evaluated as a timestamp (as if a single parameter were passed) and assuming the second is a period, this used to calculate a time relative to the first. If the second parameter is a timestamp rather than a period, the first parameter is ignored and the value of the second is returned.

If a timestamp or duration cannot be parsed, the method returns null, as it does if the only or second parameter is null. When two parameters are passed, a null first parameter is considered the same as the current timestamp, i.e. localDateTime(null,X) is the same as localDateTime(X).

base64String = btoa(String) Convert a string to its base64 representation.
String = atob(base64String) Decode a sequence of base64 to a string.
String = getRandomUUID() Get a random univerally unique identifier (UUID).
String = getNameUUID(namespace,name) Get a type 5 name UUID, which is built from a namespace UUID and a name. The namespace must be a string representation of a UUID, null, one of the standard pre-defined values ("ns:DNS", "ns:URL", "ns:OID" or "ns:X500"), or the custom value "ns:FSK" for creating a UUID from a file storage key.
ScriptResultSet = newResultSet() Return an empty Script Result Set object.
ScriptResultSet = getResultSet(options) Retrieve a Script Result Set object.

The rows in the result set are specified by:

  • The rows option, which specifies an array of rows, or
  • The row option, which specifies a single row, or
  • both the rowSource and the rowMemberType options, which specify a list of target nodes.

The columns in the result set are specified by:

  • The columns option, which specifies an array of columns, or
  • The column option, which specifies a single column, or
  • both the columnSource and columnMemberType options, which specify a list of target nodes.

When using the SciptNode methods listTargets(), listPackageContent() and listInboundLinks() to build a list of rows, specify the readMembers option on the method to pre-check the authority to read data from the rows, for significantly improved performance.

rows take precedence over row, row takes precedence over rowSource and rowMemberType, columns takes precedence over column, column takes precedence over columnSource and columnMemberType.

An additional cacheColumn can be specified. If one or more members for the cache column member type exists for a row, only it or they are returned for the row, and members for other member types are not. The cache column should not be in the list specified by column source and column member type, and is always returned as column 0. This can be used to efficiently retrieve cached or calculated members, and only retrieve base data where the cache is not available.

If the cacheColumn is used, a cacheExpiryTimestamp can be set (as a string in format yyyy-mm-ddThh:mm:ss.sss). Any cache values that were derived before this timestamp are ignored, and other members returned in their place. The cacheExpiryTimestamp defaults to the derivation timestamp of the cache column member type.

Other options, all of which default to false:

  • stale – set to true to allow stale reads. It is good practice to set this when retrieving original data, provided that you are not interested in the row objects. Has no effect if the rows option is used.
  • extend – set to true, then if any combinations of row/member type return no members, run the member type extension script and then re-retrieve the members. This can make sense where extension scripts are used for delayed derivation. Rember that member types with extension scripts must be defined in the row's node types.
  • original – return original data, not derived data. Can not be used with the extend option.

Example:

{
  rowSource: context,
  rowMemberType: mtIndexAll,
  column: 'system.NODE_NAME'
}

Returns a one-column result set containg the names of all the mtIndexAll targets of context.

original and extend are mutually exclusive.

Columns are always made up to date before retrieval.

If there are any errors, the method returns null and sets the application error fields.

boolean = index(options) Create an index, a derived data structure to speed up subsequent data access. Returns true if index created, returns false is there is an error in the options. See Indexing.