You may have heard of Groovy, the agile and dynamic language with Java-like syntax. What you may not know is that custom objects on the Axeda Platform use Groovy to consume external web services by building on several powerful tools. Groovy on the Platform gives the developer the freedom to spend time building the meaningful parts of the app, not on the repetitive and boring problems like how to move data in and out of a particular format.
The code for this tutorial is available as an Axeda Artisan project download at the end of the article.
Terminology
A “Custom Object” is a Groovy Script running in the Platform. A custom object provides the following:
• a shortcut for customizing rules and actions for your environment
• a simple way to implement custom Java code for the Axeda Platform
• a means of executing actions as a result of evaluating expression rules or from Axeda Web services
“Scripto” is a RESTful WebService front end to the Custom Objects. As a REST-based web service, Scripto allows authentication information to be defined directly in the URL and supports HTTP basic GET and POST operations. For example, by submitting a POST to a Scripto URL such as the following, any Groovy Custom Object can be executed:
http://dev6.axeda.com/services/v1/rest/Scripto/execute/MyCustomObjectName
or more generically:
http://host:port/services/v1/rest/Scripto/execute/CustomObject
Groovy in a Sandbox
All Groovy code which runs on the Platform lives within its own ClassLoader. This ClassLoader “Sandbox” defines the boundaries of what the script can access. If the customobjects.log file or the Audit log show exceptions caused by security policy violations from within Groovy Sandbox, The Axeda Platform will not run the Groovy script.
Scripts may be blacklisted if they fit the following definitions:
• The script is defined to access restricted classes, packages or methods (from the Axeda SDK or a third-party library),
• The script is defined to loop without interruption.
• The script is defined to handle exceptions to loop interruptions, security violations, or errors.
How does Groovy access the Platform?
Groovy Scripts running on the Platform use the Platform SDK to access Objects, referred to as Assets or Devices, and Data about those Objects.

There are two ways to call Groovy Scripts on the Platform:
- Expression Rules - provide a way to evaluate events, data, and conditions and then run actions based on the results of the evaluation. Expression rules are created using programmatic If -Then-Else expressions, and must evaluate to a Boolean result (that is, true or false or 1 or 0) at runtime.
- Scripto Webservices - the bridge between the Axeda Custom Object scripting engine, and a Web Service client, that is able to output data in a particular format, such as CSV, JSON, or XML
Groovy from Expression Rules
Consider a scenario in which a supervisor is monitoring a vehicle that is transmitting stats about its speed. The supervisor only needs to know information about the speed when it becomes a problem, such as when the driver is driving over the speed limit. Expression Rules provide a means to evaluate incoming data and execute an action if it meets certain criteria, so in the case of our supervisor, she can set up a custom object to set off an alarm if the speed goes over 70mph. The Custom Object corresponds to the “Then” or “Else” blocks in a Rule.

Custom Objects triggered from Expression Rules have a variety of “Injected” Variables, based on the type of Rule. These variables are assigned values at runtime, and they include the following:
- Alarm - message that contains specific information about a problem on a particular asset
- Data Items - actual data points in the asset to which the server can read and write data
- Uploaded File – a file uploaded and associated with a particular asset
- User - individuals with login access to applications. These individuals must have user accounts and associated user group definitions within the directory service(s) configured for the system
- Event - notable information specific to the asset that is not necessarily indicative of a problem, such as asset registration, time synchronization, data overflow, failure starting a driver, and asset contacts (pings)
- Mobile Location – a point consisting of the latitude and longitude coordinates of the asset at a given point in time
- Data Values – values of data points in the asset which meet specific conditions
Passing Data to a Custom Object
To extend our driving scenario, the supervisor may want to know a driver's exact speed when the driver receives a ticket. The Expression Rule can make its Data available to a Groovy Custom Object, so the alarm set off by the Custom Object can include the desired information. The requirements to pass data from an Expression Rule are a Rule Context and a Custom Object.

A Context is similar to a user, since the Rule’s access to the data and the system is restricted to the Context defined by the method. Any Data available within this limited Context of a Rule can be passed to a Custom Object, such as Device ID, Value of a DataItem and Name of an Alarm.
Pairing a Custom Object with an Expression Rule gives a great degree of flexibility for defining Platform behaviors.
From an Expression Rule, all parameters passed to the Custom Object are retrieved by offset of the declared parameter, not the order you read it in.
The order of these parameters is defined by the Custom Object configuration


A helpful tool for debugging a Groovy Custom Object is the logger, available via a call within the script:
logger.info("Info here")
logger.debug("Where's my debug?")
logger.warn("Here's my warning!")
logger.error("ERROR. ERROR.")The output of the logger is the equivalent of printing values of variables to the console at breakpoints in an IDE.
Groovy in Scripto
To access a Groovy Custom Object via Scripto, the parameters are passed in as a map specified on the URL, or in the body. The return can be any structured (or unstructured) data, determined by specifying the Content-Type.
Scripto is called via a RESTful URL, and it supports the HTTP methods GET and POST. Scripto works in a Web Browser, from CURL, or any REST client.
The flexibility of the return mechanism derives from the guarantee that the output from a script will always be a String formatted into any Content Type specified to the client.
def hello = parameters.hello
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.Hello(hello)
return [“Content-Type”: “application:xml”, “Content”: “writer.toString()]
Now that we’ve taken a dive into the basics of Groovy on the Axeda Platform, let’s create a short script that demonstrates how easy it is to determine on the fly the return type of the data.
The Groovy Script
//import the Context which limits the access of the Script for security purposes
import com.axeda.drm.sdk.Context
//import the DeviceFinder from the Axeda SDK
import com.axeda.drm.sdk.device.DeviceFinder
// import the Groovy MarkupBuilder for xml
import groovy.xml.MarkupBuilder
// import the JSONObject construct for JSON
import net.sf.json.JSONObject
// define the content type as a parameter so it can be specified within the POST to Scripto
def contentType = parameters.contentType
// create the Context
def sdkContext = Context.create()
// looking up all devices
def dFinder = new DeviceFinder(sdkContext)
def devices = dFinder.findAll()
switch(contentType) {
case "XML":
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
// return as XML from a Groovy closure
xml.Devices {
devices.each { device ->
xml.Device(serialNumber: device.serialNumber,modelNumber: device.model.modelNumber)
}
}// return the response as a String
return ["Content-Type": "application/xml","Content":writer.toString()]
case "JSON":
try {
def writer = new StringWriter()
// create the response as a map using a Groovy closure
def map = [:]
devices.each { device ->
map."$device.serialNumber" = device.model.modelNumber
}
// convert the map to a JSONObject
def jsonMap = map as JSONObject
// return the response as a String
return ["Content-Type": "application/json","Content":jsonMap.toString()]
// output xml for error handling
} catch (Exception e) {
writer = new StringWriter()
xml = new MarkupBuilder(writer)
StringWriter logStringWriter = new StringWriter();
PrintWriter logPrintWriter = new PrintWriter(logStringWriter)
e.printStackTrace(logPrintWriter)
logger.error("Exception occurred in ScriptoExample2.groovy: ${logStringWriter.toString()}") xml.error() {
faultcode ("Groovy Exception")
faultstring(e.getMessage())
} return ['Content-Type': 'text/xml', 'Content': writer.toString()]
}
default:
// in case the return type is not specified
return ["Content-Type": "text/plain","Content":"Please choose an encoding, either 'JSON' or 'XML'"]
}The Groovy custom object allows the developer to focus on functionality and value, rather than the mechanics of moving data from one format to another.
Consuming External Services
Now let’s reach outside the Platform. Groovy scripts within the Platform have access to several powerful tools to consume external Services. As variations on the theme of consumption of web services, the GDK URL, HTTPBuilder and RESTClient provide degrees of fine-grained control and high level access to fit any use case.
- GDK URL – Groovy’s built in URL Construct, adapted to high level access to web service
- HTTPBuilder – Acts as a robust HTTP client which can handle a variety of content types
- RESTClient – Handy utility for making REST calls and parsing responses, supports all HTTP verbs
The GDK URL
Groovy has overloaded the java.net.URL class with extra functionality, resulting in the GDK (or Groovy JDK) URL. The GDK URL provides direct and simple access to a web service and can handle the most common URL use cases. For instance, say you'd like to connect to the Axeda Platform web service. You can make a single call to the GDK URL and have the contents immediately accessible, as demonstrated in the example below:
//load the whole page using a GET request
def text = new URL(“http://www.axeda.com/platform/connect”).text
println “Text: $text”
//iterate over each line of the response to a GET request
new URL(“http://www.axeda.com/platform/connect”).eachLine( { line -> println “Line: $line”
}
return false
All Connection opening, buffering, reading & closing is handled automatically, and it even works for binaries. You can access bytes directly from the response, allowing for the transfer of images and other binaries…

Yes, the GDK URL makes it that easy.
HttpBuilder
Now let's take a look at the HttpBuilder Framework. Imagine a case in which you're using the Google Search API and you need to check the response headers for success or failure. The HTTPBuilder Framework makes these headers readily available, as shown by the following example:
def http = new HTTPBuilder(‘http://ajax.googleapis.com’)
//perform a GET request, expecting JSON response data
http.request(GET, JSON) {
uri.path = ‘/ajax/services/search/web’
uri.query = [ v: ‘1.0’, q: ‘Axeda Corp.’ ]
headers.’User-Agent’ = ‘Mozilla/5.0 Ubuntu/8.10 Firefox/3.0.4’
//response handler for a success response code:
response.success = { resp, json ->
println resp.statusLine
resp.headers.each {
println “$it.name - $it.value”
}
//parse the JSON response object:
json.responseData.results.each {
println “ ${it.titleNoFormatting} : ${it.visibleUrl} “
}
}
//handler for any failure status code:
response.failure = { resp ->
println “Unexpected error: ${resp.statusLine.statusCode} : ${ resp. statusLine.reasonPhrase}
}
}
As you can see, HTTPBuilder is able to process headers and data with a Closure, in simple Groovy syntax. Not only that, but HTTPBuilder allows for full verb support - GET, POST, PUT, DELETE - along with its access to both Request and Response Headers. Its built-in response parsers for JSON and XML, along with handlers for successful and failed responses, generate output in a return format easily accessible for consumption by an external app.
RESTClient
The RESTClient is another option for accessing web services, built on top of HTTPBuilder. While HTTPBuilder has detailed access to output, the RESTClient provides similar functionality in a simple, elegant mechanism for consuming RESTful Webservices. See the difference in the example below, which accomplishes the same task as the prior example, but in much cleaner code:
def http = new RESTClient(‘http://ajax.googleapis.com’)
def resp = google.get (path: ‘ajax/services/search/web’, query : [ v: ‘1.0’, q: ‘Axeda Corp.’ ])
resp.headers.each {
println “$it.name - $it.value”
}
resp.data.each {
Println “${it.value}”
}
In this tutorial, we saw how easy it can be to consume external services and model complex business logic by using Groovy Custom Objects on the Axeda Platform. While Groovy is just one tool in your toolbox, its philosophy of less ceremony with more substance makes developing connected apps a breeze.
Download this code as an Axeda Artisan Project:

