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

Axeda: Create and Find Extended List of Data Items - Output to XML

Level 5

Axeda: Create and Find Extended List of Data Items - Output to XML

This code creates an Extended List (supported since 6.1.6) of data item names, then finds that list and returns only the current and historical data items on the list for all the assets of a given model in XML.  In this example, Extended Lists are used instead of data item groups to store a certain subset of data items that should be returned.  In a real use case, the list of data item names would be created in a separate call, then the list would be accessed after the fact.  For purposes of demonstration, this script does both.

Parameters:

  1. model_name
  2. data_item_names
  3. from_time
  4. to_time

import com.axeda.drm.sdk.Context

import com.axeda.drm.sdk.device.ModelFinder

import com.axeda.drm.sdk.device.Model

import com.axeda.drm.sdk.device.DeviceFinder

import com.axeda.drm.sdk.data.CurrentDataFinder

import com.axeda.drm.sdk.device.Device

import com.axeda.drm.sdk.data.HistoricalDataFinder

import com.axeda.sdk.v2.bridge.ExtendedListBridge

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

import com.axeda.services.v2.ExtendedList

import com.axeda.services.v2.ExtendedListCriteria

import com.axeda.services.v2.ExtendedListReference

import groovy.xml.MarkupBuilder

/*

* DIListToXML.groovy

*

* Create a list of data items on an asset, then use that list to find selected data items for all assets in a given model.

*

* @param model_name        -   (REQ):Str name of the model.

* @param data_item_names   -    (REQ): Str list of data item names comma delimited, ie  DataName1,DataName2

* @param from_time         -   (REQ):Long millisecond timestamp to begin query from.

* @param to_time           -   (REQ):Long millisecond timestamp to end query at.

*

* @note from_time and to_time should be provided because it limits the query size.

*

* @author Sara Streeter <sstreeter@axeda.com>

*/

def response = [:]

def writer = new StringWriter()

def xml = new MarkupBuilder(writer)

// measure the script run time

def timeProfiles = [:]

def scriptStartTime = new Date()

try {

// getUserContext is supported as of release 6.1.5 and higher

    final def CONTEXT = Context.getUserContext()

// confirm that required parameters have been provided

    validateParameters(actual: parameters, expected: ["model_name", "data_item_names", "from_time", "to_time"])

// find the model

    def modelFinder = new ModelFinder(CONTEXT)

    modelFinder.setName(parameters.model_name)

    Model model = modelFinder.findOne()

// throw exception if no model found

    if (!model) {

        throw new Exception("No model found for ${parameters.model_name}.")

    }

// find or create our Extended List

    def listName = "${parameters.model_name}-data_item_list"

    ExtendedListBridge listBridge = Bridges.extendedListBridge

    def results = listBridge.find(listName)

    def data_item_list

    if (results.list != null) {

        data_item_list = results

    }

    else {

        data_item_list = new ExtendedList()

        data_item_list.name = listName

    }

// split out the data items into an Extended List

    def items = parameters.data_item_names.tokenize(",")

    items.each { entry ->

        if (!data_item_list.list.contains(entry)) {

            data_item_list.list.add(entry)

        }

    }

    listBridge.save(data_item_list)

    data_item_list.list.each {

    }

// find all assets of that model

    def assetFinder = new DeviceFinder(CONTEXT)

    assetFinder.setModel(model)

    def assets = assetFinder.findAll()

// find the current and historical data values for the data items on the list for each asset

//note: since device will be set on the datafinders going forward, a dummy device is set on instantiation which is not actually stored

    def currentDataFinder = new CurrentDataFinder(CONTEXT, new Device(CONTEXT, "placeholder", model))

    def historicalDataFinder = new HistoricalDataFinder(CONTEXT, new Device(CONTEXT, "placeholder", model))

    historicalDataFinder.startDate = new Date(parameters.from_time as Long)

    historicalDataFinder.endDate = new Date(parameters.to_time as Long)

    def currentValue

    def valueList = []

    xml.Response() {

        Assets() {

            assets.each { Device asset ->

                currentDataFinder.device = asset

                Asset() {

                    id(asset.id)

                    name(asset.name)

                    serial_number(asset.serialNumber)

                    model_id(asset.model.id)

                    model_name(asset.model.name)

                    current_data() {

                        data_item_list.list.each { data ->

                            currentValue = currentDataFinder.find(data)

                            data_item() {

                                timestamp(currentValue?.getTimestamp()?.format("yyyyMMdd HH:mm"))

                                name(currentValue?.dataItem?.name)

                                value(currentValue?.asString())

                            }

                        }

                    }

                    historical_data() {

                        data_item_list.list.each { data ->

                            historicalDataFinder.device = asset

                            valueList = historicalDataFinder.find(currentValue.dataItem)

                            valueList.each { hd ->

                                data_item() {

                                    timestamp(hd?.getTimestamp()?.format("yyyyMMdd HH:mm"))

                                    name(hd?.dataItem?.name)

                                    value(hd?.asString())

                                }

                            }

                        }

                    }

                }

            }

        }

    }

} 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())

        }

    }

}

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

private Map createTimeProfile(String label, Date startTime, Date endTime) {

    [

            (label): [

                    startTime: [timestamp: startTime.time, readable: startTime.toString()],

                    endTime: [timestamp: endTime.time, readable: endTime.toString()],

                    profile: [

                            elapsed_millis: endTime.time - startTime.time,

                            elapsed_secs: (endTime.time - startTime.time) / 1000

                    ]

            ]

    ]

}

private validateParameters(Map args) {

    if (!args.containsKey("actual")) {

        throw new Exception("validateParameters(args) requires 'actual' key.")

    }

    if (!args.containsKey("expected")) {

        throw new Exception("validateParameters(args) requires 'expected' key.")

    }

    def config = [

            require_username: false

    ]

    Map actualParameters = args.actual.clone() as Map

    List expectedParameters = args.expected

    config.each { key, value ->

        if (args.options?.containsKey(key)) {

            config[key] = args.options[key]

        }

    }

    if (!config.require_username) { actualParameters.remove("username") }

    expectedParameters.each { paramName ->

        if (!actualParameters.containsKey(paramName) || !actualParameters[paramName]) {

            throw new IllegalArgumentException(

                    "Parameter '${paramName}' was not found in the query; '${paramName}' is a reqd. parameter.")

        }

    }

}

Sample Output:

<Response>
  <Assets>
    <Asset>
      <id>5052</id>
      <name>VendingMachine_1</name>
      <serial_number>VendingMachine_1</serial_number>
      <model_id>1616</model_id>
      <model_name>VendingMachineModel</model_name>
      <current_data>
        <data_item>
          <timestamp>20120419 02:55</timestamp>
          <name>CurrentBalance</name>
          <value>0.0</value>
        </data_item>
        <data_item>
          <timestamp>20120419 02:55</timestamp>
          <name>CurrentStock</name>
          <value>180.0</value>
        </data_item>
      </current_data>
      <historical_data />
    </Asset>
    <Asset>
      <id>5056</id>
      <name>VendingMachine_5</name>
      <serial_number>VendingMachine_5</serial_number>
      <model_id>1616</model_id>
      <model_name>VendingMachineModel</model_name>
      <current_data>
        <data_item>
          <timestamp>20120419 02:55</timestamp>
          <name>CurrentBalance</name>
          <value>0.0</value>
        </data_item>
        <data_item>
          <timestamp>20120419 02:55</timestamp>
          <name>CurrentStock</name>
          <value>180.0</value>
        </data_item>
      </current_data>
      <historical_data />
    </Asset>
    <Asset>
      <id>5054</id>
      <name>VendingMachine_3</name>
      <serial_number>VendingMachine_3</serial_number>
      <model_id>1616</model_id>
      <model_name>VendingMachineModel</model_name>
      <current_data>
        <data_item>
          <timestamp>20120419 02:55</timestamp>
          <name>CurrentBalance</name>
          <value>0.0</value>
        </data_item>
        <data_item>
          <timestamp>20120419 02:55</timestamp>
          <name>CurrentStock</name>
          <value>180.0</value>
        </data_item>
      </current_data>
      <historical_data />
    </Asset>
    <Asset>
      <id>5053</id>
      <name>VendingMachine_2</name>
      <serial_number>VendingMachine_2</serial_number>
      <model_id>1616</model_id>
      <model_name>VendingMachineModel</model_name>
      <current_data>
        <data_item>
          <timestamp>20120419 02:55</timestamp>
          <name>CurrentBalance</name>
          <value>0.0</value>
        </data_item>
        <data_item>
          <timestamp>20120419 02:55</timestamp>
          <name>CurrentStock</name>
          <value>180.0</value>
        </data_item>
      </current_data>
      <historical_data />
    </Asset>
    <Asset>
      <id>5055</id>
      <name>VendingMachine_4</name>
      <serial_number>VendingMachine_4</serial_number>
      <model_id>1616</model_id>
      <model_name>VendingMachineModel</model_name>
      <current_data>
        <data_item>
          <timestamp>20120419 02:55</timestamp>
          <name>CurrentBalance</name>
          <value>0.0</value>
        </data_item>
        <data_item>
          <timestamp>20120419 02:55</timestamp>
          <name>CurrentStock</name>
          <value>180.0</value>
        </data_item>
      </current_data>
      <historical_data />
    </Asset>
  </Assets>
</Response>