cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - Help us improve the PTC Community by taking this short Community Survey! X

Using Axeda Scripto

No ratings

Scripto provides a RESTful endpoint for Groovy Custom Objects on the Axeda Platform.  Custom Objects exposed via Scripto can be accessed via a GET or a POST, and the script will have access to request parameters or body contents. Any Custom Object of the "Action" type will automatically be exposed via Scripto. The URL for a Scripto service is currently defined by the name of the Custom Object:

GET: http://{{YourHostName}}/services/v1/rest/Scripto/execute/<customObjectName>

Scripto enables the creation of "Domain Specific Services". This allows implementers to take the Axeda Domain Objects (Assets, Models, DataItems, Alarms) and expose them via a service that models the real-world domain directly (trucks, ATMs, MRI Machines, sensor readings). This is especially useful when creating a domain-specific UI, or when integrating with another application that will push or pull data.

Authentication

There are several ways to test your Scripto scripts, as well as several different authentication methods. The following authentication methods can be used:

Request Parameter credentials: ?username=<yourUserName>&password=<yourPassword>

Request Parameter sessionId (retrieved from the Auth service): ?sessionid=<sessionId>

Basic Authentication (challenge): From a browser or CURL, simply browse to the URL to receive an HTTP Basic challenge.

Request Parameters

You can access the parameters to the Groovy script via two Objects, Call and Request. Request is actually just a sub-class of Call, so the values will always be the same regardless of which Object you use.  Although parameters may be accessed off of either object, Call is preferable when Chaining Custom Objects (TODO LINK) together.  Call also includes a reference to the logger which can be used to log debug messages.

GET:  http://{{YourHostName}}/services/v1/rest/Scripto/execute/<Your Script Name>?sessionid=<Session Id>&serial_number=mySerialNumber

Accessing Parameters through the Request Object

import com.axeda.drm.sdk.scripto.Request

// Request.parameters is a map of strings

def serial_number = Request.parameters.serial_number

assert serial_number == "mySerialNumber"

     

Accessing Parameters through the Call Object

import com.axeda.drm.sdk.customobject.Call

// Call.parameters is a map of strings

def serial_number = Call.parameters.serial_number

assert serial_number == "mySerialNumber"

     

Accessing the POST Body through the Request Object


The content from a POST request to Scripto is accessible as a string via the body field in the Request object.  Use Slurpers for XML or JSON to parse it into an object.

POST:  http://{{YourHostName}}/services/v1/rest/Scripto/execute/<Your Script Name>?sessionid=<Session Id>

Response: { "serial_number":"mySerialNumber"}

import com.axeda.drm.sdk.scripto.Request

def body = Request.body

def slurper = new JsonSlurper()

def result = slurper.parseText(body)

assert result.serial_number == "mySerialNumber"

     

Returning Plain Text

Groovy custom objects must return some content.  The format of that content is flexible and can be returned as plain text, JSON, XML, or even binary files. The follow example simply returns plain text.

GET:  http://{{YourHostName}}/services/v1/rest/Scripto/execute/<Your Script Name>

// Outputs:  hello

return ["Content-Type":"text/plain","Content":"hello"]

     

Returning JSON

We use the JSONObject Class to format our Map-based content into a JSON structure. The eliminates the need for any concern around formatting, you just build up Maps of Maps and it will be properly formatted by the fromObject() utility method.

GET:  http://{{YourHostName}}/services/v1/rest/Scripto/execute/<Your Script Name>

import net.sf.json.JSONObject

root = [

  items:[    num_1: “one”,    num_2: “two”            ]

]

/** Outputs

{

  "items": {  "num_1": "one", "num_2": "two"  }

}

**/

return ['Content-Type': 'application/json', 'Content': JSONObject.fromObject(root).toString(2)]

     

Link to JSONObject documentation

Returning XML

To return XML, we use the MarkupBuilder to build the XML response. This allows us to create code that follows the format of the XML that is being generated.

GET:  http://{{YourHostName}}/services/v1/rest/Scripto/execute/<Your Script Name>?sessionid=<Session Id>

import groovy.xml.MarkupBuilder

def writer = new StringWriter()

def xml = new MarkupBuilder(writer)

xml.root(){

    items(){

        num_1("one")

        num_2("two")

    }

}

/** Outputs

<root>

  <items>

    <num_1>one</num_1>

    <num_2>two</num_2>

  </items>

</root>

**/

return ['Content-Type': 'text/xml', 'Content': writer.toString()]

     

Link to Groovy MarkupBuilder documentation

Returning Binary Content

To return binary content, you typically will use the fileStore API to upload a file that you can then download using Scripto.  See the fileInfo section to learn more. In this example we connect the InputStream which is associated with the getFileData() method directly to the output of the Scripto script. This will cause the bytes available in the stream to be directly forwarded to the client as the body of the response.

GET:  http://{{Your Host Name}}/services/v1/rest/Scripto/execute/{{Your Script Name}}?sessionid={{Session Id}}&fileId=123

import static com.axeda.sdk.v2.dsl.Bridges.*

import com.axeda.services.v2.*

import com.axeda.sdk.v2.exception.*

def contentType = parameters.type ?: 'image/jpg'

return ['Content':fileInfoBridge.getFileData(parameters.fileId), 'Content-Type':contentType]

 

The Auth Service - Authentication via AJAX

Groovy scripts are accessible to AJAX-powered HTML apps with Axeda instance credentials.  To obtain a session from an Axeda server, you should make a GET call to the Authentication service. The service is located at the following example URL:

https://{{YourHostName}}/services/v1/rest/Auth/login

This service accepts a valid username/password combination in the incoming Request parameters and returns a SessionID. The parameter names it expects to see are as follows:

Property NameDescription
principal.usernameThe username for the valid Axeda credential.
password The password for the supplied credential.

A sample request to the Auth Service:

GET: https://{{YourHostName}}/services/v1/rest/Auth/login?principal.username=YOURUSER&password=YOURPASS

Would yield this response (at this time the response is always in XML):

<ns1:WSSessionInfo xsi:type="ns1:WSSessionInfo" xmlns:ns1="http://type.v1.webservices.sl.axeda.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <ns1:created>2013-08-12T13:19:37 +0000</ns1:created>

  <ns1:expired>false</ns1:expired>

  <ns1:sessionId>19c33190-dded-4655-b2c0-921528f7b873</ns1:sessionId>

<ns1:sessionTimeout>

1800

</ns1:sessionTimeout>

</ns1:WSSessionInfo>

     

The response fields are as follows:

Field NameDescription
created The timestamp for the date the session was created
expired A boolean indicating whether or not this session is expired (should be false)
sessionId The ID of the session which you will use in subsequent requests
sessionTimeout The time (in seconds) that this session will remain active for

The Auth Service is frequently invoked from JavaScript as part of Custom Applications. The following code demonstrates this style of invocation.

function authenticate(host, username, password) {

            try {

                netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");

            } catch (e) {

                // must be IE

            }

            var xmlHttpReq = false;

            var self = this;

            // Mozilla/Safari

            if (window.XMLHttpRequest) {

                self.xmlHttpReq = new XMLHttpRequest();

            }

            // IE

            else if (window.ActiveXObject) {

                self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");

            }

            var SERVICES_PATH = "/services/v1/rest/"

            var url = host + SERVICES_PATH + "Auth/login?principal.username=" + username + "&password=" + password;

            self.xmlHttpReq.open('GET', url, true);

            self.xmlHttpReq.onreadystatechange = function() {

                if (self.xmlHttpReq.readyState == 4) {

                    getSessionId(self.xmlHttpReq.responseXML);

                }

            }

            self.xmlHttpReq.send()

}

function getSessionId(xml) {

            var value

            if (window.ActiveXObject) {

                // xml traversing with IE

                var objXML = new ActiveXObject("MSXML2.DOMDocument.6.0");

                objXML.async = false;

                var xmldoc = objXML.loadXML(xml);

                objXML.setProperty("SelectionNamespaces", "xmlns:ns1='http://type.v1.webservices.sl.axeda.com'");

                objXML.setProperty("SelectionLanguage","XPath");

                value =  objXML.selectSingleNode("//ns1:sessionId").childNodes[0].nodeValue;

            } else {

                // xml traversing in non-IE browsers

                var node = xml.getElementsByTagNameNS("*", "sessionId")

                value = node[0].textContent

            }

            return value

}

authenticate ("http://mydomain.axeda.com", "myUsername", "myPassword")

     

Calling Scripto via AJAX

Once you have obtained a session id through authentication via AJAX, you can use that session id in Scripto calls. The following is a utility function which is frequently used to wrap Scripto invocations from a UI.

function callScripto(host, scriptName, sessionId, parameter) {

            try {

                netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");

            } catch (e) {

                // must be IE

            }

            var xmlHttpReq = false;

            var self = this;

            // Mozilla/Safari

            if (window.XMLHttpRequest) {

                self.xmlHttpReq = new XMLHttpRequest();

            }

            // IE

            else if (window.ActiveXObject) {

                self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");

            }

            var url = host + SERVICES_PATH + "Scripto/execute/" + scriptName + "?sessionid=" + sessionId;

            self.xmlHttpReq.open('GET', url, true);

            self.xmlHttpReq.onreadystatechange = function() {

                if (self.xmlHttpReq.readyState == 4) {

                    updatepage(div, self.xmlHttpReq.responseText);

                }

            }

            self.xmlHttpReq.send(parameter);

}

function updatepage(div, str) {

            document.getElementById(div).innerHTML = str;

}

callScripto("http://mydomain.axeda.com", "myGroovyScriptName", "mySessionId", "myparameter=foo")

     

A more modern jQuery-based example might look like the following:

function callScripto(host, scriptName, sessionId, parameter) {

    var url = host + '/services/v1/rest/Scripto/execute/' + scriptName + '?sessionid=' + sessionId

    if ( parameter != null ) url += '&' + parameter

    $.ajax({url: url,

              success:  function(response) {  updatepage(div, response); }

          });

}

function updatepage(div, str) {

    $("#" + div).innerHTML = str

}

callScripto("http://mydomain.axeda.com", "myGroovyScriptName", "mySessionId", "myparameter=foo")

In Conclusion

As shown above, Scripto offers a number of ways to interact with the platform.  On each version of the Axeda Platform, all supported v1 and v2 APIs are available for Scripto to interact with the Axeda domain objects and implement business logic to solve real-world customer problems.

Bibliography (PTC.net account required)

    Axeda v2 API/Services Developer's Reference Version 6.8.3 August 2015

    Axeda® v1 API Developer’s Reference Guide Version 6.8 August 2014

    Documentation Map for Axeda® 6.8.2 January 2015

Version history
Last update:
‎Jan 22, 2016 11:39 AM
Updated by:
Labels (1)