Using JavaScript to extend operations

JavaScript can be used to add integration code in a number of places, such as job tasks, transcode presets, naming scripts, etc. This article describes functions and utilities that are common to all JavaScript invocations.

If a script is not working as expected, then it is also possible to debug the script using Eclipse.

Common JavaScript functions

A number of global variables are defined for the script to use. It is also possible to add custom global JavaScript objects and functions, as described in Add generic JavaScript code.

The api object

The api object can be used to perform a synchronous HTTP request to the Vidispine API. By default the request will be performed as the user that created the job that is running, unless overridden by the script using the api.user() function.

These functions all return a new api object with the parameters of the function added to it, and should thus be chained as shown in the example below.

api.path(path)

Adds the given path to the API URI.

api.queryParam(key, value)

Adds a query parameter to the API URI.

api.dataType(type)

The type of data that should be returned from the server.

Arguments:
  • type (string) – Supported types are text, json and xml, or a media type such as application/json. The default is json, xml.
api.input(input[, type])

The data to be sent. The content type is optional if the input is a JavaScript or XML object, but mandatory if input is a string (such as a JSON or a XML string).

Arguments:
  • type (string) – Supported types are text, json and xml, or a media type such as application/json.
api.user(username[, password])

The user to authenticate as. If no password is specified then the request will be authenticated using token authentication.

api.timeout(timeout)

Sets the timeout of the request.

Arguments:
  • timeout (int) – The timeout in milliseconds.

New in version 4.0.3.

Once the request parameters have been specified the request can be performed using one of these four functions:

api.get()

Performs a GET request.

api.put()

Performs a PUT request.

api.post()

Performs a POST request.

api.delete()

Performs a DELETE request.

For example, to retrieve the metadata and shapes for a specific item:

item = api.path("item").path(itemId)
   .queryParam("content", "metadata,shape")
   .get();

Rich output

By adding rich() on the api chain, more information about the HTTP response is given. Without rich, the operation functions (api.get() et al.) only return the value returned by the API, and throws an exception if the API returns an error.

api.rich()

With rich, the functions returns a JavaScript object, with the following properties:

  • output - The response, parsed as an object.
  • response - The response as a string.
  • status - The HTTP status code.
  • httpheader-* - The various HTTP headers, with the HTTP header name in lower case, e.g. httpheader-content-length.

New in version 4.0.3.

API call information

To aid in troubleshooting API calls, this function can be used to get information about the call that is about to be made.

api.getInfo()

New in version 4.0.3.

Returns:A JavaScript object with properties:
  • uri - The URI of the request.
  • queryParams - A javax.ws.rs.core.MultivaluedMap containing all of the query parameters.
  • inputIsXML - True if the input is an XML object.
  • inputIsJSON - True if the input is a JSON object.
  • returnTypes - The media types that have been set using api.dataType().
  • user - The name of the user performing the request.
  • passwordIsSet - True if the password has been set.

The http object

New in version 4.0.3.

The http object is similar to the api object, but can be used to invoke other HTTP resources. The http object needs to be used with the http.uri() function, which takes one parameter, the URI to be used.

http.uri(uri):()
Arguments:
  • uri (string) – The URI of the resource.

Example:

var uri = api.path('version').getInfo().uri;
http.uri(uri).user('admin','admin').dataType('JSON').get().licenseInfo.licenceType

The shell object

The shell object is used to invoke shell commands.

shell.exec(command[, arg, ...][, options])

Executes the command with the given arguments.

Arguments:
  • command (string) – The name of the command to execute.
  • arg (string) – Any arguments to pass to the command.
  • options

    A JavaScript object with fields:

    • timeout - An optional timeout in milliseconds.
    • input - Optional input to send to standard input.
    • output - Optional java.io.OutputStream to contain the output from the command. If this field is specified then output will not be included in the response.
    • err - Optional java.io.OutputStream to contain the error output from the command. If this field is specified then output will not be included in the response.
Returns:

An object with fields:

  • exitcode - The return code (an integer) from the command.
  • output - Standard output as a string.
  • err - Standard error as a string.

A step that checks a file for viruses might for example look something like:

var file = ...
var result = shell.exec("clamscan", file);
if (result.exitcode == 1) {
  job.failFatal("Virus(es) found");
}

The logger object

New in version 4.0.3.

The logger object outputs information to the log file of the application server. If the JavaScript object is concatenated to a string, the full representation may not be shown.

logger.log('information is '+info);

This can be fixed by using the logger.json() function:

logger.log('information is '+logger.json(info));
logger.log(message)

Logs the given message to the application server log file.

Arguments:
  • message – The message to log. If this is a JavaScript object then it will automatically be transformed into JSON format.
logger.json(object)

Converts the given JavaScript object into JSON.

Debugging JavaScript

New in version 4.0.3.

The JavaScript code can be debugged using Eclipse. The configuration property debugJavaScript controls if debugging is enabled or not. With this setting set to true, all JavaScript code will wait for a remote debugger to attach before continuing.

  1. Enable JavaScript debugging. Set the configuration property debugJavaScript to true.
  1. Set up Eclipse. To set up Eclipse for debugging, select Run ‣ Debug Configurations... and create a new Remote JavaScript configuration. Use Mozilla Rhino as Connection, and port 59000. The port can be changed using the configuration property debugJavaScriptPort.

    For Source Lookup Path, select a File System Directory, and point it to any existing directory. The directory does not have to contain the source files; it will be sent via the Mozilla Rhino connector.

  1. Execute a script. Now, Eclipse is ready to connect. To test, POST some JavaScript code to API/javascript/test, e.g. using curl:

    $ curl –uadmin:admin –Hcontent-type:application/javascript \
    localhost:8080/API/javascript/test –X POST --data-binary \
    'var a=3;
    var b=4;
    a+b;’
    

    If debugJavaScript is true, then the call will not return immediately.

  2. Connect the debugger. In Eclipse, choose Run ‣ Debug Configurations..., select the created configuration and choose Debug.

    Eclipse should show a file named testscript-xxxx.js or similar in the source window. The first line includes the text debugger;. This is intentional and can be ignored; it is only added so that the debugger will actually start in suspended mode.

    Also, when the script starts, a random line – typically the second or third – is selected. Single-step once and the first line should be selected and the actual debugging can start. After the script has completed, the API call returns.

Interfacing with the JavaScript engine manually

New in version 4.0.3.

In order to test functionality, the JavaScript engine can be called manually. For more information, see JavaScript.

Add generic JavaScript code

In order to avoid redundant code, it is possible to register JavaScript code in a “global library”. This is done using configuration properties of the form javascript-{extension}, where extension is any suffix.

When doing this, all code that is in the javascript- properties will be executed before the specific code. Multiple properties can be added, and will be parsed in lexical order. It is advised that only definitions (function) are made, and not direct statements, in order to avoid confusion.

Example

$ curl –uadmin:admin –Hcontent-type:text/plain \
localhost:8080/API/configuration/properties/javascript-1234 –X PUT --data-binary \
'function add(a,b) {
  return a+b;
}’
$ curl –uadmin:admin –Hcontent-type:application/javascript \
localhost:8080/API/javascript/test –X POST --data-binary \
'var a=3;
var b=4;
add(a,b);’