Content Types Returned from Axeda Scripto

    This tutorial applies to Axeda version 6.1.6+, with sections applicable to 6.5+ (indicated below)


    Custom objects (or Groovy scripts) are the backbone of Axeda custom applications.  As the developer, you decide what content type to give the data returned by the script.

     

    What this tutorial covers?

    This tutorial provides examples of outputting data in different formats from Groovy scripts and consuming that data via Javascript using the jQuery framework.  While Javascript and jQuery are preferred by the Axeda Innovation team, any front end technology that can consume web services can be used to build applications on the Axeda Machine Cloud.  On the same note, the formats discussed in this article are only a few examples of the wide variety of content types that Groovy scripts can output via Scripto.  The content types available via Scripto are limited only by their portability over the TCP protocol, a qualification which includes all text-based and downloadable binary mime types.  As of July 2013, the UDP protocol (content streaming) is not supported by the current version of the Axeda Platform.

     

    Formats discussed in this article:

    1) JSON
    2) XML
    3) CSV
    4) Binary content with an emphasis on image files (6.5+)


    For a tutorial on how to create custom objects that work with custom applications, check out Using Google Charts API with ScriptoFor a discussion of what Scripto is and how it relates to Groovy scripts and Axeda web services, take a look at Unleashing the Power of the Axeda Platform via Scripto.


    Serializing Data


    JSON

    For those building custom applications with Javascript, serializing data from scripts into JSON is a great choice, as the data is easily consumable as native Javascript objects.

     

    The net.sf.json JSON library is available to use in the SDK.  It offers an easy way to serialize objects on the Platform, particularly v2 SDK objects.

     

    import net.sf.json.JSONArray
    import static com.axeda.sdk.v2.dsl.Bridges.*
    def asset = assetBridge.findById(parameters.assetId)
    def response = JSONArray.fromObject(asset).toString(2)
    return ["Content-Type": "application/json", "Content": response]
    

     

    Outputs:

     

    [{

        "buildVersion": "",

        "condition": {

            "detail": "",

            "id": "3",

            "label": "",

            "restUrl": "",

            "systemId": "3"

        },

        "customer": {

            "detail": "",

            "id": "2",

            "label": "Default Organization",

            "restUrl": "",

            "systemId": "2"

        },

        "dateRegistered": {

            "date": 11,

            "day": 1,

            "hours": 18,

            "minutes": 7,

            "month": 2,

            "seconds": 49,

            "time": 1363025269253,

            "timezoneOffset": 0,

            "year": 113

        },

        "description": "",

        "detail": "testasset",

        "details": null,

        "gateways": [],

        "id": "12345",

        "label": "",

        "location": {

            "detail": "Default Organization",

            "id": "2",

            "label": "Default Location",

            "restUrl": "",

            "systemId": "2"

        },

        "model": {

            "detail": "testmodel",

            "id": "2345",

            "label": "standalone",

            "restUrl": "",

            "systemId": "2345"

        },

        "name": "testasset",

        "pingRate": 0,

        "properties": [

            {

                "detail": "",

                "id": "1",

                "label": "TestProperty",

                "name": "TestProperty",

                "parentId": "2345",

                "restUrl": "",

                "systemId": "1",

                "value": ""

            },

            {

                "detail": "",

                "id": "4",

                "label": "TestProperty0",

                "name": "TestProperty0",

                "parentId": "2345",

                "restUrl": "",

                "systemId": "4",

                "value": ""

            },

            {

                "detail": "",

                "id": "3",

                "label": "TestProperty1",

                "name": "TestProperty1",

                "parentId": "2345",

                "restUrl": "",

                "systemId": "3",

                "value": ""

            },

            {

                "detail": "",

                "id": "2",

                "label": "TestProperty2",

                "name": "TestProperty2",

                "parentId": "2345",

                "restUrl": "",

                "systemId": "2",

                "value": ""

            }

        ],

        "restUrl": "",

        "serialNumber": "testasset",

        "sharedKey": [],

        "systemId": "12345",

        "timeZone": "GMT"

    }]

     

    This output can be traversed as Javascript object with its nodes accessible using dot (.) notation.

     

    For example, if you set the above JSON as the content of variable "json", you can access it in the following way, without any preliminary parsing needed:

     

    assert json[0].condition.id == 3
    

     

    If you use jQuery, a Javascript library, feel free to make use of axeda.js, which contains utility functions to pass data to and from the Axeda Platform.  One function in particular is used in most example custom applications found on this site, the axeda.callScripto function.  It relies on the jQuery ajax function to make the underlying call.

     

    /**
      * makes a call to the enterprise platform services with the name of a script and passes
      * the script any parameters provided.
      *
      * default is GET if the method is unknown
      *
      * Notes: Added POST semantics - plombardi @ 2011-09-07
      *
      * original author: Zack Klink & Philip Lombardi
      * added on: 2011/7/23
      */
    // options - localstoreoff: "yes" for no local storage, contentType: "application/json; charset=utf-8",
    axeda.callScripto = function (method, scriptName, scriptParams, attempts, callback, options) {
      var reqUrl = axeda.host + SERVICES_PATH + 'Scripto/execute/' + scriptName + '?sessionid=' + SESSION_ID
      var contentType = options.contentType ? options.contentType : "application/json; charset=utf-8"
      var local
      var daystring = keygen()
      if (options.localstoreoff == null) {
      if (localStorage) {
      local = localStorage.getItem(scriptName + JSON.stringify(scriptParams))
      }
      if (local != null && local == daystring) {
      return dfdgen(reqUrl + JSON.stringify(scriptParams))
      } else {
      localStorage.setItem(scriptName + JSON.stringify(scriptParams), daystring)
      }
      }
      return $.ajax({
      type: method,
      url: reqUrl,
      data: scriptParams,
      contentType: contentType,
      dataType: "text",
      error: function () {
      if (attempts) {
      expiredSessionLogin();
      setTimeout(function () {
      axeda.callScripto('POST', scriptName, scriptParams, attempts - 1, callback, options)
      }, 1500);
      }
      },
      success: function (data) {
      if (options.localstoreoff == null) {
      localStorage.setItem(reqUrl + JSON.stringify(scriptParams), JSON.stringify([data]))
      }
      if (contentType.match("json")) {
      callback(unwrapResponse(data))
      } else {
      callback(data)
      }
      }
      })
    };
    

     

     

    Using the axeda.callScripto function:

     

    var postToPlatform = function (scriptname, callback, map) {
    
            var options = {
                localstoreoff: "yes",
                contentType: "application/json; charset=utf-8"
            }
       
         // Javascript object "map" has to be stringified to post to Axeda Platform
            axeda.callScripto("POST", scriptname, JSON.stringify(map), 2, function (json) {
                // callback gets the JSON object output by the Groovy script
                callback(json)
    
            }, options)
        }
    

    The JSON object is discussed in more detail here.

    Back to Top

     

    XML

    XML is the preferred language of integration with external applications and services. Groovy provides utilities to make XML serialization a trivial exercise.

     

    import groovy.xml.MarkupBuilder
    import static com.axeda.sdk.v2.dsl.Bridges.*
    def writer = new StringWriter()
    def xml = new MarkupBuilder(writer)
    def findAssetResult = assetBridge.find(new AssetCriteria(modelNumber: parameters.modelName))
    // find operation returns AssetReference class. Contains asset id only
    def assets = findAssetResult.assets
       
      xml.Response() {
      Assets() {
      assets.each { AssetReference assetRef ->
      def asset = assetBridge.findById(assetRef.id)
                  // asset contains a ModelReference object instead of a Model.  ModelReference has a detail property, not a name property
      Asset() {
      id(asset.id)
      name(asset.name)
      serial_number(asset.serialNumber)
      model_id(asset.model.id)
      model_name(asset.model.detail)
      }
      }
      }
      }
    
    return ['Content-Type': 'text/xml', 'Content': writer.toString()]
    

    Output:

     

    <Assets>

      <Asset>

      <id>98765</id>

      <name>testasset</name>

      <serial_number>testasset</serial_number>

      <model_id>4321</model_id>

      <model_name>testmodel</model_name>

      </Asset>

    </Assets

     

    Although XML is not a native Javascript object as is JSON, Javascript libraries and utilities are available for parsing XML into an object traversable in Javascript.

     

    For more information on parsing XML in Javascript, see W3 Schools XML Parser.  For those using jQuery, check out the jQuery.parseXML function.

     

    Back to Top

     

    Outputting Files (Binary content types)


    CSV


    CSV comes in handy for spreadsheet generation as it is compatible with Microsoft Excel.

     

    The following example is suitable for Axeda version 6.1.6+ as it makes use of the Data Accumulator feature to create a downloadable file.

     

    import com.axeda.drm.sdk.device.ModelFinder
    import com.axeda.drm.sdk.Context
    import com.axeda.drm.sdk.scripto.Request
    import com.axeda.common.sdk.id.Identifier
    import com.axeda.drm.sdk.device.Model
    import com.axeda.drm.sdk.device.DataItem
    import com.axeda.drm.sdk.device.DataItemValue
    import com.axeda.drm.sdk.data.DataValue
    import com.axeda.drm.sdk.device.DeviceFinder
    import com.axeda.drm.sdk.device.Device
    import com.axeda.drm.sdk.mobilelocation.MobileLocation
    import com.axeda.drm.sdk.data.DataValueList
    import com.axeda.drm.sdk.data.CurrentDataFinder
    import com.axeda.drm.sdk.mobilelocation.CurrentMobileLocationFinder
    import groovy.xml.MarkupBuilder
    import com.axeda.platform.sdk.v1.services.ServiceFactory
    
    /*
    * ExportObjectToCSV.groovy
    *
    * Creates a csv file from either all assets of a model of a single asset that can then be used to import them back into another system.
    *
    * @param model        -   (REQ):Str model name.
    * @param serial        -   (OPT):Str serial number.
    *
    * @author Sara Streeter <sstreeter@axeda.com>
    */
    
    def writer = new StringWriter()
    def xml = new MarkupBuilder(writer)
    InputStream is
    
    try {
       Context CONTEXT = Context.getSDKContext()
       ModelFinder modelFinder = new ModelFinder(CONTEXT)
        modelFinder.setName(Request.parameters.model)
       Model model = modelFinder.find()
       DeviceFinder deviceFinder = new DeviceFinder(CONTEXT)
       deviceFinder.setModel(model)
       List<Device> devices = []
    
    def exportkey = model.name
    
    Device founddevice
    
    if (Request.parameters.serial){
    
        deviceFinder.setSerialNumber(Request.parameters.serial)
       founddevice = deviceFinder.find()
       logger.info(founddevice?.serialNumber)
       if (founddevice != null){
       devices.add(founddevice)
       }
       else throw new Exception("Device ${Request.parameters.serial} cannot be found.")
    
       exportkey += "${founddevice.serialNumber}"
    }
    else {
        devices = deviceFinder.findAll()
        exportkey += "all"
    }
    
    // use a Data Accumulator to store the information
    def dataStoreIdentifier = "FILE-CSV-export_____" + exportkey
    
    def daSvc = new ServiceFactory().dataAccumulatorService
    
    if (daSvc.doesAccumulationExist(dataStoreIdentifier, devices[0].id.value)) {
      daSvc.deleteAccumulation(dataStoreIdentifier, devices[0].id.value)
    }
    
    List<DataItem> dataItemList = devices[0].model.dataItems
    
    def firstrow = [ "model", "serial", "devicename", "conditionname", "currentlat","currentlng" ]
                 
            def tempfirstrow = dataItemList.inject([]){list, dataItem ->
                list << dataItem.name;
                list
            }
            firstrow += tempfirstrow     
            firstrow = firstrow.join(',')
            firstrow += '\n'
            daSvc.writeChunk(dataStoreIdentifier, devices[0].id.value, firstrow);
         
    CurrentMobileLocationFinder currentMobileLocationFinder = new CurrentMobileLocationFinder(CONTEXT)
    
    devices.each{ device ->
    
                    CurrentDataFinder currentDataFinder = new CurrentDataFinder(CONTEXT, device)
                    currentMobileLocationFinder.deviceId = device.id.value
                    MobileLocation mobileLocation = currentMobileLocationFinder.find()
                    def lat = 0
                    def lng = 0
                    if (mobileLocation){
                        lat = mobileLocation?.lat
                        lng = mobileLocation?.lng
                    }
    
                    def row =
                    [
                        device.model.name,
                        device.serialNumber,
                        device.name,
                        device.condition?.name,
                        lat,
                        lng
                        ]
                     
                        def temprow = dataItemList.inject([]){ subList,dataItem ->
                            DataValue value = currentDataFinder.find(dataItem.name)
                         
                            def val = "NULL"
                            val = value?.asString() != "?" ? value?.asString() : val
                            subList <<  val
                            subList
                        }
                    row += temprow 
                    row = row.join(',')
                    row += '\n'
                    daSvc.writeChunk(dataStoreIdentifier, devices[0].id.value, row);
                }
    
        
    // stream the data accumulator to create the file
    is = daSvc.streamAccumulation(dataStoreIdentifier, devices[0].id.value)
    
    def disposition = 'attachment; filename=CSVFile' + exportkey + '.csv'
    
    return ['Content-Type': 'text/csv', 'Content-Disposition':disposition, 'Content': is.text]
    
    } catch (def ex) {
       xml.Response() {
           Fault {
               Code('Groovy Exception')
               Message(ex.getMessage())
               StringWriter sw = new StringWriter();
               PrintWriter pw = new PrintWriter(sw);
               ex.printStackTrace(pw);
               Detail(sw.toString())
           }
       }
    logger.info(writer.toString())
    
    return ['Content-Type': 'text/xml', 'Content': writer.toString()]
    }
    return ['Content-Type': 'text/xml', 'Content': writer.toString()]
    

     

    Back to Top

     

    Image Files (6.5+)


    The FileStore in Axeda version 6.5+ allows fine-grained control of uploaded and downloaded files. As Groovy scripts can return binary data via Scripto, this allows use cases such as embedding a Groovy script url as the source for an image.

     

    The following example uses the FileStore API to create an Image out of a valid image file, scales it to a smaller size and stores this smaller file.

     

    import com.axeda.drm.sdk.Context
    import com.axeda.drm.sdk.data.*
    import com.axeda.drm.sdk.device.*
    import com.axeda.drm.sdk.mobilelocation.CurrentMobileLocationFinder
    import com.axeda.drm.sdk.mobilelocation.MobileLocation
    import com.axeda.drm.sdk.mobilelocation.MobileLocationFinder
    import com.axeda.sdk.v2.bridge.FileInfoBridge
    import static com.axeda.sdk.v2.dsl.Bridges.*
    import com.axeda.services.v2.ExecutionResult
    import com.axeda.services.v2.FileInfo
    import com.axeda.services.v2.FileInfoReference
    import com.axeda.services.v2.FileUploadSession
    import net.sf.json.JSONObject
    import groovy.json.JsonBuilder
    import net.sf.json.JSONArray
    import com.axeda.drm.sdk.scripto.Request
    import org.apache.commons.io.IOUtils
    import org.apache.commons.lang.exception.ExceptionUtils
    import com.axeda.common.sdk.id.Identifier
    import groovy.json.*
    import javax.imageio.ImageIO;
    import java.awt.RenderingHints
    import java.awt.image.BufferedImage
    import java.io.ByteArrayOutputStream;
    import java.awt.*
    import java.awt.geom.*
    import javax.imageio.*
    import java.awt.image.*
    import java.awt.Graphics2D
    import javax.imageio.stream.ImageInputStream
    
    /*
       Image-specific FileStore entry point to post and store files
    */
    
    def contentType = "application/json"
    final def serviceName = "StoreScaledImage"
    
    // Create a JSON Builder
    def json = new JsonBuilder()
    
    // Global try/catch. Gotta have it, you never know when your code will be exceptional!
    
    try {
       
        Context CONTEXT = Context.getSDKContext()
        def filesList = []
        def datestring = new Date().time
        InputStream inputStream = Request.inputStream
       
        def reqbody = Request.body
    
        // all of our Request Parameters are available here
        def params = Request.parameters
        def filename = Request?.headers?.'Content-Disposition' ?
        Request?.headers?.'Content-Disposition' : "file___" + datestring + ".txt"
        def filelabel = Request.parameters.filelabel ?: filename
        def description = Request.parameters.description ?: filename
        def contType = Request.headers?."content-type" ?: "image/jpeg"
        def tag = Request.parameters.tag ?: "cappimg"
        def encoded = Request.parameters.encoded?.toBoolean()
      def dimlimit = params.dimlimit ? params.dimlimit : 280
        // host is available in the headers when the script is called with AJAX
        def domain = Request.headers?.host
    
        byte[] bytes = IOUtils.toByteArray(inputStream);
        def fileext = filename.substring(filename.indexOf(".") + 1,filename.size())
    
        def outerMap = [:]
        // check that file extension matches an image type
        if (fileext ==~ /([^\s]+(\.(?i)(jpg|jpeg|png|gif|bmp))$)/){
            if (inputStream.available() > 0) {
                    def scaledImg
                   
                    try {
                        def img = ImageIO.read(inputStream)
    
                        def width = img?.width           
                        def height = img?.height
    
                        def ratio = 1.0
                        def newBytes
                       
                        if (img){
                           
                            if (width > dimlimit || height > dimlimit){
                                // shrink by the smaller side so it can still be over the limit
                                def dimtochange = width > height ? height : width
                                ratio = dimlimit / dimtochange
                               
                                width = Math.floor(width * ratio).toInteger()
                                height = Math.floor(height * ratio).toInteger()
                            }
                           
                          newBytes = doScale(img, width, height, ratio, fileext)
                         if (newBytes?.size() > 0){
                            bytes = newBytes 
                         }
                        }
                    }
                    catch(Exception e){
                        logger.info(e.localizedMessage)  
                       
                    }
                               
                    outerMap.byteCount = bytes.size()
        
                    FileInfoBridge fib = fileInfoBridge
                    FileInfo myImageFile = new FileInfo(filelabel: filelabel,
                                                        filename: filename,
                                                        filesize: bytes?.size(),
                                                        description: description,
                                                        tags: tag
                                                        )
        
                    myImageFile.contentType = contType
        
                    FileUploadSession fus = new FileUploadSession();
                    fus.files = [myImageFile]
        
                    ExecutionResult fer = fileUploadSessionBridge.create(fus);
                    myImageFile.sessionId = fer.succeeded.getAt(0)?.id
                   
                    ExecutionResult fileInfoResult = fib.create(myImageFile)
                   
                    if (fileInfoResult.successful) {
                        outerMap.fileInfoSave = "File Info Saved"
                        outerMap.sessionId = "File Upload SessionID: "+fer.succeeded.getAt(0)?.id
                        outerMap.fileInfoId = "FileInfo ID: "+fileInfoResult?.succeeded.getAt(0)?.id
                        ExecutionResult er = fib.saveOrUpdate(fileInfoResult.succeeded.getAt(0).id,new ByteArrayInputStream(bytes))
                        def fileInfoId = fileInfoResult?.succeeded.getAt(0)?.id
                        String url = "${domain}/services/v1/rest/Scripto/execute/DownloadFile?fileId=${fileInfoId}"
                        if (er.successful) {
                            outerMap.url = url
                        } else {
                            outerMap.save = "false"
                            logger.info(logFailure(er,outerMap))
                        }
                    } else {
                        logger.info(logFailure(fileInfoResult, outerMap))
                    }
        
                } else {
                    outerMap.bytesAvail = "No bytes found to upload"
                }
            } else {
                outerMap.imagetype = "Extension $fileext is not a supported image file type."
            }
    
        filesList << outerMap
    
    
        // return the JSONBuilder contents
        // we specify the content type, and any object as the return (even an outputstream!)
        return ["Content-Type": contentType,"Content":JSONArray.fromObject(filesList).toString(2)]
    
        // alternately you may just want to serial an Object as JSON:
        // return ["Content-Type": contentType,"Content":JSONArray.fromObject(invertedMessages).toString(2)]
    
    } catch (Exception e) {
    
        // I knew you were exceptional!
        // we'll capture the output of the stack trace and return it in JSON
    
        json.Exception(
                description: "Execution Failed!!! An Exception was caught...",
                stack: ExceptionUtils.getFullStackTrace(e)
        )
    
        // return the output
        return ["Content-Type": contentType, "Content": json.toPrettyString()]
    }
    
    def doScale(image, width, height, ratio, fileext){
        if (image){
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        def bytes
         def scaledImg = new BufferedImage( width, height, BufferedImage.TYPE_INT_RGB )
           Graphics2D g = scaledImg.createGraphics();
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.scale(ratio,ratio)
            g.drawImage(image, null, null);
            g.dispose();
           
           ImageIO.write( scaledImg, fileext, baos )
          baos.flush()  
          bytes = baos.toByteArray()
          baos.close()  
        }
        else {
            logger.info("image to be scaled is null")
            return false
        }
      return bytes    
    }
    
    private void logFailure(ExecutionResult fileInfoResult, LinkedHashMap outerMap) {
        outerMap.message = fileInfoResult.failures.getAt(0)?.message
        outerMap.source = fileInfoResult.failures.getAt(0)?.sourceOfFailure
        outerMap.details = fileInfoResult.failures.getAt(0)?.details?.toString()
        outerMap.fileInfoSave = "false"
    }
    

     

    The next example makes use of the jQuery framework to upload an image to this script via an http POST.

    Note: This snippet is available as a jsFiddle at http://jsfiddle.net/LrxWF/18/


    With HTML5 button:

    <input type="file" id="fileinput" value="Upload" />

     

    var PLATFORM_HOST = document.URL.split('/apps/')[0]; // this is how you would retrieve the host on an Axeda instance
    
    var SESSION_ID = null // usually retrieved from login function included below
    
    /***
    * Depends on jQuery 1.7+ and HTML5, assumes an HTML5 element such as the following:
    * <input type="file" id="fileinput" value="Upload" />
    * **/
    
    $("#fileinput").off("click.filein").on("click.filein", function () {
        fileUpload()
    })
    
    var fileUpload = function () {
        $("#fileinput").off('change.fileinput')
        $("#fileinput").on('change.fileinput', function (event) {
            if (this.files && this.files.length > 0) {
                handleFiles("http://" + PLATFORM_HOST, this.files)
            }
        })
    }
    
    var handleFiles = function (host, files) {
        $.each(files, function (index, file) {
            var formData = new FormData();
            var filename = file.name
            formData.append(filename, file)
            var url = host + '/services/v1/rest/Scripto/execute/StoreScaledImage?filelabel=' + filename + "&tag=myimg"
    
            url = setSessionId(url)
            jQuery.ajax(url, {
                beforeSend: function (xhr) {
                    xhr.setRequestHeader('Content-Disposition', filename);
                },
                cache: false,
                cache: false,
                processData: false,
                type: 'POST',
                contentType: false,
                data: formData,
                success: function (json) {
                    refreshPage(json)
                    console.log(json)
                }
            });
        })
    }
    
    var setSessionId = function (url) {
        // you would already have this from logging in
        return url + "&sessionid=" + SESSION_ID
    }
    
    var refreshPage = function (json) {
        // here you would refresh your page with the returned JSON  
        return
    }
    
    /***
     *  The following functions are not used in this demonstration, however they are necessary for a complete app and are found in axeda.js  http://gist.github.com/axeda/4340789
    ***/
    
        function login(username, password, success, failure) {
            var reqUrl = host + SERVICES_PATH + 'Auth/login';
            localStorage.clear()
            return $.get(reqUrl, {
                'principal.username': username,
                    'password': password
            }, function (xml) {
                var sessionId = $(xml).find("ns1\\:sessionId, sessionId").text()
                // var sessionId = $(xml).find("[nodeName='ns1:sessionId']").text(); - no longer works past jquery 1.7
                if (sessionId) {
                    // set the username and password vars for future logins.          
                    storeSession(sessionId);
                    success(SESSION_ID); // return the freshly stored contents of SESSION_ID
                } else {
                    failure($(xml).find("faultstring").text());
                }
            }).error(function () {
                $('#loginerror').html('Login Failed, please try again')
            });
        };
    
    function storeSession(sessionId) {
        var date = new Date();
        date.setTime(date.getTime() + SESSION_EXPIRATION);
        SESSION_ID = sessionId
        document.cookie = APP_NAME + '_sessionId=' + SESSION_ID + '; expires=' + date.toGMTString() + '; path=/';
        return true;
    };
    

     

    The return JSON includes a URL that you can use as the source for images:

     

    [{

      "byteCount": 14863,

      "fileInfoSave": "File Info Saved",

      "sessionId": "File Upload SessionID: 01234",

      "fileInfoId": "FileInfo ID: 12345",

      "url": "http://yourdomain.axeda.com/services/v1/rest/Scripto/execute/DownloadFile?fileId=12345"

    }]

     

    The DownloadFile Custom Object looks like the following:

     

    import static com.axeda.sdk.v2.dsl.Bridges.*
    import javax.activation.MimetypesFileTypeMap
    import com.axeda.services.v2.*
    import com.axeda.sdk.v2.exception.*
    import com.axeda.drm.sdk.scripto.Request
    
    def knowntypes = [
             [png: 'image/png']
            ,[gif: 'image/gif']
            ,[jpg: 'image/jpeg']
        ]
    
    def params = Request.parameters.size() > 0 ? Request.parameters : parameters
    
    def response = fileInfoBridge.getFileData(params.fileId)
    
    def fileinfo = fileInfoBridge.findById(params.fileId)
    
    def type = fileinfo.filename.substring(fileinfo.filename.indexOf('.') + 1,fileinfo.filename.size())
    
    type = returnType(knowntypes, type)
    
    def contentType = params.type ?: (type ?: 'image/jpg')
    
    return ['Content': response, 'Content-Disposition': contentType, 'Content-Type':contentType]
    
    def returnType(knowntypes, ext){
        return knowntypes.find{ it.containsKey(ext) }?."$ext"
    }
    

     

    Make sure to append a valid session id to the end of the URL when using it as the source for an image.

     

    The techniques discussed above can be applied to any type of binary file output with consideration for the type of file being processed.

     

    A Word on Streaming

    Content streaming such as streaming of video or audio files over UDP is not currently supported by the Axeda Platform.