Как проанализировать значение из полезной нагрузки HTTP JSON - PullRequest
3 голосов
/ 17 мая 2019

Я относительно новичок в Apama. Я использую v10.3.1. Я следую следующему фрагменту, чтобы выполнить REST-запрос в мониторе:

http://www.apamacommunity.com/documents/10.3.1.1/apama_10.3.1.1_webhelp/apama-webhelp/#page/apama-webhelp%2Fco-ConApaAppToExtCom_httpclient_using_predefined_generic_event_definitions.html%23wwconnect_header

Действие для обработки ответа в настоящее время выглядит следующим образом:


action handleResponse(Response response){
        if response.isSuccess(){
            print "###The response payload is :" + response.payload.toString();
        }

        else {
            print "###Request failed. Response status is: " + response.statusCode.toString() + " | " + response.statusMessage;
        }
    }

Я ищу лучший способ извлечь значение следующего свойства из полезной нагрузки ответа JSON:

assetparents.references[0].managedObject.name (here “SOME”).

Я пробовал разные способы, но всегда сталкивался с ошибкой.

Оператор print предоставляет следующие выходные данные для полезной нагрузки ответа:



###The response payload is :com.apama.util.AnyExtractor(any(string,"

{"owner":"some@one.com","additionParents":{
    "self":"https://somebaseurl/inventory/managedObjects/5706999/additionParents","references":[]
},
"childDevices":{
    "self":"https://somebaseurl/inventory/managedObjects/5706999/childDevices","references":[]
},

"childAssets":{
    "self":"https://somebaseurl/inventory/managedObjects/5706999/childAssets","references":[]
},
"creationTime":"2019-05-09T11:36:10.197Z",
"lastUpdated":"2019-05-10T05:28:07.893Z",
"childAdditions":{
    "self":"https://somebaseurl/inventory/managedObjects/5706999/childAdditions",
    "references":[{
        "managedObject":{"name":"Escalate alarmtest",
        "self":"https://somebaseurl/inventory/managedObjects/5706698",
        "id":"5706698"},
        "self":"https://somebaseurl/inventory/managedObjects/5706999/childAdditions/5706698"
    }
]},
"name":"SOME Test Device",
"deviceParents":{
    "self":"https://somebaseurl/inventory/managedObjects/5706999/deviceParents",
    "references":[]
},
"assetParents":{
    "self":"https://somebaseurl/inventory/managedObjects/5706999/assetParents",
    "references":[{
        "managedObject":{
            "additionParents":{
                "self":"https://somebaseurl/inventory/managedObjects/5706682/additionParents",
                "references":[]
            },
            "childDevices":{
                "self":"https://somebaseurl/inventory/managedObjects/5706682/childDevices",
                "references":[]
            },
            "childAssets":{
                "self":"https://somebaseurl/inventory/managedObjects/5706682/childAssets",
                "references":[]
            },
            "childAdditions":{
                "self":"https://somebaseurl/inventory/managedObjects/5706682/childAdditions",
                "references":[]
            },
            "name":"SOME",
            "deviceParents":{
                "self":"https://somebaseurl/inventory/managedObjects/5706682/deviceParents",
                "references":[]
            },
            "assetParents":{
                "self":"https://somebaseurl/inventory/managedObjects/5706682/assetParents",
                "references":[]
            },
            "self":"https://somebaseurl/inventory/managedObjects/5706682",
            "id":"5706682"
        },
        "self":"https://somebaseurl/inventory/managedObjects/5706999/assetParents/5706682"
    }]
},
"self":"https://somebaseurl/inventory/managedObjects/5706999",
"id":"5706999",
"c8y_ActiveAlarmsStatus":{
    "minor":0,
    "critical":1
},
"c8y_IsDevice":{},
"ax_Customer":"SOME CUSTOMER",
"c8y_SupportedMeasurements":["c8y_Temperature"]}"))

Помимо анализа отдельного свойства, каков рекомендуемый способ сопоставления всего объекта событию Apama?

Если бы вы могли предоставить фрагмент кода, он был бы очень признателен.

Большое спасибо Mathias

Ответы [ 2 ]

2 голосов
/ 17 мая 2019

Чтобы ответить на ваш второй вопрос, а именно: «Каков рекомендуемый способ сопоставить весь объект событию Apama?»:

Я определил несколько событий, которые будут отображаться в JSON, который вы указали:

event Reference {
    string self;
    any managedObject;
}

event Object {
    string self;
    sequence<Reference> references;
}

event ActiveAlarmsStatus {
    integer minor;
    integer critical;
}
event IsDevice {}

event ManagedObject {
    string owner;
    string self;
    string id;
    string name;
    string creationTime;
    string lastUpdated;
    Object additionParents;
    Object childDevices;
    Object childAssets;
    Object childAdditions;
    Object deviceParents;
    Object assetParents;
    ActiveAlarmsStatus c8y_ActiveAlarmsStatus;
    IsDevice c8y_IsDevice;
    string ax_Customer;
    sequence<string> c8y_SupportedMeasurements;
}

Поскольку ManagedObject содержит объект, который содержит ссылку, которая сама содержит ManagedObject, EPL не будет компилироваться из-за рекурсивных типов. Поэтому в Reference мы используем любой тип для маскировки ManagedObject. это позволяет EPL компилировать.

Однако, поскольку any скрывает тип, мы не знаем, к какому типу его преобразовать, и поэтому вместо этого у нас есть any, содержащий словарь. Это нормально, потому что мы можем использовать некоторые вспомогательные функции для извлечения необходимой нам информации:

action GetSequenceReference(sequence<any> s) returns sequence<Reference> {
    sequence<Reference> ret := new sequence<Reference>;
    any r := new any;
    for r in s {
        ret.append(<Reference>r);
    }
    return ret;
}
action GetSequenceString(sequence<any> s) returns sequence<string> {
    sequence<string> ret := new sequence<string>;
    any r := new any;
    for r in s {
        ret.append(<string>r);
    }
    return ret;
}

action GetObject(any a) returns Object {
    log "Getting object from: " + a.toString() at INFO;
    dictionary<any,any> dict := <dictionary<any,any> >a;

    Object ret := new Object;

    ret.self := <string>dict.getDefault( "self", "" );
    ret.references := GetSequenceReference( <sequence<any> >dict.getDefault( "references", new sequence<any> ) );

    return ret;
}

action GetActiveAlarmsStatus(any a) returns ActiveAlarmsStatus {
    log "Getting active alarms status from: " + a.toString() at INFO;
    dictionary<any,any> dict := <dictionary<any,any> >a;

    ActiveAlarmsStatus ret := new ActiveAlarmsStatus;

    ret.minor := <integer>dict.getDefault( "minor", 0 );
    ret.critical := <integer>dict.getDefault( "critical", 0 );

    return ret;
}
action GetIsDevice(any a) returns IsDevice {
    log "Getting is device from: " + a.toString() at INFO;
    dictionary<any,any> dict := <dictionary<any,any> >a;

    IsDevice ret := new IsDevice;

    return ret;
}
action GetManagedObject(any a) returns ManagedObject {

    log "Getting managed object from: " + a.toString() at INFO;
    dictionary<any,any> dict := <dictionary<any,any> >a;

    ManagedObject ret := new ManagedObject;
    ret.owner := <string>dict.getDefault( "owner", "" );
    ret.self := <string>dict.getDefault( "self", "" );
    ret.id := <string>dict.getDefault( "id", "" );
    ret.name := <string>dict.getDefault( "name", "" );
    ret.creationTime := <string>dict.getDefault( "creationTime", "" );
    ret.lastUpdated := <string>dict.getDefault( "lastUpdated", "" );
    ret.additionParents := GetObject( dict.getDefault( "additionParents", new dictionary<any,any> ) );
    ret.childDevices := GetObject( dict.getDefault( "childDevices", new dictionary<any,any> ) );
    ret.childAssets := GetObject( dict.getDefault( "childAssets", new dictionary<any,any> ) );
    ret.childAdditions := GetObject( dict.getDefault( "childAdditions", new dictionary<any,any> ) );
    ret.deviceParents := GetObject( dict.getDefault( "deviceParents", new dictionary<any,any> ) );
    ret.assetParents := GetObject( dict.getDefault( "assetParents", new dictionary<any,any> ) );
    ret.c8y_ActiveAlarmsStatus := GetActiveAlarmsStatus( dict.getDefault( "c8y_ActiveAlarmsStatus", new dictionary<any,any> ) );
    ret.c8y_IsDevice := GetIsDevice( dict.getDefault( "c8y_IsDevice", new dictionary<any,any> ) );
    ret.ax_Customer := <string>dict.getDefault( "ax_Customer", "" );
    ret.c8y_SupportedMeasurements := GetSequenceString( <sequence<any> >dict.getDefault( "c8y_SupportedMeasurements", new sequence<any> ) );
    return ret;
}

Используя эти вспомогательные функции, мы можем извлечь информацию из нашего исходного события:

action handleResponse(Response response){
    if response.isSuccess(){
        ManagedObject mo := GetManagedObject( response.payload.toDictionary() );
        log "###The response payload is :" + mo.toString() at INFO;
    }

    else {
        log "###Request failed. Response status is: " + response.statusCode.toString() + " | " + response.statusMessage at INFO;
    }
}

И вот оно у вас! Полностью сопоставленное событие.

2 голосов
/ 17 мая 2019

Чтобы ответить на ваш первый вопрос.

Вывод оператора print очень полезен.Это показывает, что ответом является необработанная строка JSON вместо проанализированного объекта JSON.Это означает, что кодек JOSN пропустил декодирование источника JSON.Это произойдет при использовании плагина «JSON с общими определениями запросов / ответов», если заголовок contentType не совсем application/json.Тестирование с Cumulocity показало, что значение заголовка не всегда application/json, вместо этого это может быть что-то вроде application/vnd.com.nsn.cumulocity.managedobject+json или application/vnd.com.nsn.cumulocity.measurementcollection+json, которое не может обрабатывать текущий кодек JSON.

Есть два способа справиться с этим без каких-либо изменений в кодеке JSON.

1) Отключить фильтрацию сообщений по кодеку JSON

Кодек JSON, используемыйПодключаемый модуль «JSON с общими определениями запросов / ответов» настроен на пропуск сообщений декодирования, для которых заголовок contentType не установлен в application/json.Это можно отключить, отредактировав файл HTTPClient.yaml в узле «Связь и адаптеры / HTTP-клиент / HTTPClient» в проекте Designer.Установите для свойства filterOnContentType значение false.Это приведет к тому, что все ответы будут обработаны как JSON;если полезная нагрузка не является JSON, синтаксический анализ завершится неудачно и сообщение будет удаленоПоэтому включите его, только если вы уверены, что все ответы будут в формате JSON.

2) Разбор строк JSON в EPL

Другой вариант может состоять в том, чтобы проанализировать строку в JSON в самом EPL, а затемоберните объект JSON в AnyExtractor для извлечения необходимого значения.Для этого вы можете использовать что-то вроде следующего.

using com.apama.json.JSONPlugin;
using com.apama.util.AnyExtractor;
...
action handleResponse(Response res) {
    if res.isSuccess() {
        log "Response is: " + res.toString();
        // Check if payload is string. A string payload could suggest raw JSON string
        switch (res.payload.data as payload) {
            case string: {
                // Parse the JSON string manually
                AnyExtractor extractor := AnyExtractor(JSONPlugin.fromJSON(payload));
                string name := extractor.getString("assetparents.references[0].managedObject.name");
            }
            default: { 
                // probably already parsed to JSON - use AnyExtractor to work on it
            }
        }
    } else {
        log "Failed: " + res.statusMessage at ERROR;
    }
}
...