From 316ddfb0c2fcc5cc45a0be2e7e87339574c0b659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Fri, 2 Aug 2024 11:38:51 +0200 Subject: [PATCH 1/2] ADD metadata in JEXL context --- src/lib/ngsi/Metadata.cpp | 68 +++++ src/lib/ngsi/Metadata.h | 2 + src/lib/ngsiNotify/Notifier.cpp | 16 + .../metadata_in_jexl_context_basic.test | 287 ++++++++++++++++++ .../metadata_in_jexl_context_builtin.test | 253 +++++++++++++++ .../metadata_in_jexl_context_collision.test | 222 ++++++++++++++ 6 files changed, 848 insertions(+) create mode 100644 test/functionalTest/cases/4594_metadata_in_jexl_context/metadata_in_jexl_context_basic.test create mode 100644 test/functionalTest/cases/4594_metadata_in_jexl_context/metadata_in_jexl_context_builtin.test create mode 100644 test/functionalTest/cases/4594_metadata_in_jexl_context/metadata_in_jexl_context_collision.test diff --git a/src/lib/ngsi/Metadata.cpp b/src/lib/ngsi/Metadata.cpp index c26573a0bf..549502879a 100644 --- a/src/lib/ngsi/Metadata.cpp +++ b/src/lib/ngsi/Metadata.cpp @@ -666,3 +666,71 @@ void Metadata::appendToBsoN(orion::BSONObjBuilder* mdBuilder, orion::BSONArrayBu } } } + + +/* **************************************************************************** +* +* addToContext - +* +* FIXME P5: duplicated from ContextAttrMetibute::addToContext(). Maybe they should be unified +*/ +void Metadata::addToContext(ExprContextObject* exprContextObjectP, bool legacy) +{ + if (compoundValueP != NULL) + { + // In legacy expression, objects are vector are strings to be stored in a std::map + if (valueType == orion::ValueTypeObject) + { + if (legacy) + { + exprContextObjectP->add(name, compoundValueP->toJson(), true); + } + else + { + exprContextObjectP->add(name, compoundValueP->toExprContextObject()); + } + } + else // valueType == orion::ValueTypeVector + { + if (legacy) + { + exprContextObjectP->add(name, compoundValueP->toJson(), true); + } + else + { + exprContextObjectP->add(name, compoundValueP->toExprContextList()); + } + } + } + else if (valueType == orion::ValueTypeNumber) + { + if ((type == DATE_TYPE) || (type == DATE_TYPE_ALT)) + { + exprContextObjectP->add(name, toJsonString(isodate2str(numberValue))); + } + else // regular number + { + exprContextObjectP->add(name, numberValue); + } + } + else if (valueType == orion::ValueTypeString) + { + exprContextObjectP->add(name, toJsonString(stringValue)); + } + else if (valueType == orion::ValueTypeBoolean) + { + exprContextObjectP->add(name, boolValue); + } + else if (valueType == orion::ValueTypeNull) + { + exprContextObjectP->add(name); + } + else if (valueType == orion::ValueTypeNotGiven) + { + LM_E(("Runtime Error (value not given for metadata %s)", name.c_str())); + } + else + { + LM_E(("Runtime Error (invalid value type %s for metadata %s)", valueTypeName(valueType), name.c_str())); + } +} \ No newline at end of file diff --git a/src/lib/ngsi/Metadata.h b/src/lib/ngsi/Metadata.h index e1fcdab163..6faabb18a8 100644 --- a/src/lib/ngsi/Metadata.h +++ b/src/lib/ngsi/Metadata.h @@ -98,6 +98,8 @@ typedef struct Metadata void appendToBsoN(orion::BSONObjBuilder* md, orion::BSONArrayBuilder* mdNames, bool useDefaultType); + void addToContext(ExprContextObject* exprContextObjectP, bool legacy); + std::string check(ApiVersion apiVersion); } Metadata; diff --git a/src/lib/ngsiNotify/Notifier.cpp b/src/lib/ngsiNotify/Notifier.cpp index 0ca4da8582..490eb88e20 100644 --- a/src/lib/ngsiNotify/Notifier.cpp +++ b/src/lib/ngsiNotify/Notifier.cpp @@ -367,6 +367,7 @@ static SenderThreadParams* buildSenderParamsCustom // Used by several macroSubstitute() calls along this function ExprContextObject exprContext(basic); + ExprContextObject exprMetadataContext(basic); // It seems that add() semantics are different in basic and jexl mode. In jexl mode, if the key already exists, it is // updated (in other words, the last added keys is the one that takes precedence). In basic model, if the key already @@ -376,16 +377,31 @@ static SenderThreadParams* buildSenderParamsCustom TIME_EXPR_CTXBLD_START(); exprContext.add("id", en.id); exprContext.add("type", en.type); + if (!basic) { exprContext.add("service", tenant); exprContext.add("servicePath", en.servicePath); exprContext.add("authToken", xauthToken); } + for (unsigned int ix = 0; ix < en.attributeVector.size(); ix++) { en.attributeVector[ix]->addToContext(&exprContext, basic); + + // Add attribute metadata to context + ExprContextObject exprAttrMetadataContext(basic); + for (unsigned int jx = 0; jx < en.attributeVector[ix]->metadataVector.size(); jx++) + { + en.attributeVector[ix]->metadataVector[jx]->addToContext(&exprAttrMetadataContext, basic); + } + exprMetadataContext.add(en.attributeVector[ix]->name, exprAttrMetadataContext); } + + // Add all metadata under the "metadata" context key + // (note that in JEXL if the key already exists, it is updated, so attribute with name "metadata" will never be appear in context) + exprContext.add("metadata", exprMetadataContext); + if (basic) { exprContext.add("service", tenant); diff --git a/test/functionalTest/cases/4594_metadata_in_jexl_context/metadata_in_jexl_context_basic.test b/test/functionalTest/cases/4594_metadata_in_jexl_context/metadata_in_jexl_context_basic.test new file mode 100644 index 0000000000..de86c13540 --- /dev/null +++ b/test/functionalTest/cases/4594_metadata_in_jexl_context/metadata_in_jexl_context_basic.test @@ -0,0 +1,287 @@ +# Copyright 2024 Telefonica Investigacion y Desarrollo, S.A.U +# +# This file is part of Orion Context Broker. +# +# Orion Context Broker is free software: you can redistribute it and/or +# modify it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# Orion Context Broker is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero +# General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Orion Context Broker. If not, see http://www.gnu.org/licenses/. +# +# For those usages not covered by this license please contact with +# iot_support at tid dot es + +# VALGRIND_READY - to mark the test ready for valgrindTestSuite.sh +# JEXL_EXPR_FLAVOUR - to mark the test has to execute only when contextBroker includes jexl-expr flavour + +--NAME-- +Metadata in JEXL context (basic case) + +--SHELL-INIT-- +dbInit CB +brokerStart CB +accumulatorStart --pretty-print + +--SHELL-- + +# +# 01. Create custom sub with custom expression sum: metadata.A.MD1+metadata.B.MD1 +# 02. Create entity E1 with A.MD1=1 and B.MD1=2 +# 03. Update entity E1 with A.MD1=foo and B.MD1=bar +# 04. Update entity E1 with A.MD1=2.1 and B.MD1=-3.8 +# 05. Dump accumulator and see three notifications (sum: 3, sum: foobar, sum: -1.7) +# + + +echo "01. Create custom sub with custom expression sum: metadata.A.MD1+metadata.B.MD1" +echo "===============================================================================" +payload='{ + "subject": { + "entities": [ + { + "id" : "E1", + "type": "T" + } + ] + }, + "notification": { + "httpCustom": { + "url": "http://127.0.0.1:'${LISTENER_PORT}'/notify", + "ngsi": { + "sum": { + "value": "${metadata.A.MD1+metadata.B.MD2}", + "type": "Calculated" + } + } + }, + "attrs": [ "sum" ] + } +}' +orionCurl --url /v2/subscriptions --payload "$payload" +echo +echo + + +echo "02. Create entity E1 with A.MD1=1 and B.MD1=2" +echo "=============================================" +payload='{ + "id": "E1", + "type": "T", + "A": { + "value": 10, + "type": "Number", + "metadata": { + "MD1": { + "value": 1, + "type": "Number" + } + } + }, + "B": { + "value": 20, + "type": "Number", + "metadata": { + "MD2": { + "value": 2, + "type": "Number" + } + } + } +}' +orionCurl --url /v2/entities --payload "$payload" +echo +echo + + +echo "03. Update entity E1 with A.MD1=foo and B.MD1=bar" +echo "=================================================" +payload='{ + "A": { + "value": 10, + "type": "Number", + "metadata": { + "MD1": { + "value": "foo", + "type": "Text" + } + } + }, + "B": { + "value": 20, + "type": "Number", + "metadata": { + "MD2": { + "value": "bar", + "type": "Text" + } + } + } +}' +orionCurl --url /v2/entities/E1/attrs -X PATCH --payload "$payload" +echo +echo + + +echo "04. Update entity E1 with A.MD1=2.1 and B.MD1=-3.8" +echo "==================================================" +payload='{ + "A": { + "value": 10, + "type": "Number", + "metadata": { + "MD1": { + "value": 2.1, + "type": "Number" + } + } + }, + "B": { + "value": 20, + "type": "Number", + "metadata": { + "MD2": { + "value": -3.8, + "type": "Number" + } + } + } +}' +orionCurl --url /v2/entities/E1/attrs -X PATCH --payload "$payload" +echo +echo + + +echo "05. Dump accumulator and see three notifications (sum: 3, sum: foobar, sum: -1.7)" +echo "=================================================================================" +accumulatorDump +echo +echo + + +--REGEXPECT-- +01. Create custom sub with custom expression sum: metadata.A.MD1+metadata.B.MD1 +=============================================================================== +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/subscriptions/REGEX([0-9a-f]{24}) +Content-Length: 0 + + + +02. Create entity E1 with A.MD1=1 and B.MD1=2 +============================================= +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/entities/E1?type=T +Content-Length: 0 + + + +03. Update entity E1 with A.MD1=foo and B.MD1=bar +================================================= +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +04. Update entity E1 with A.MD1=2.1 and B.MD1=-3.8 +================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +05. Dump accumulator and see three notifications (sum: 3, sum: foobar, sum: -1.7) +================================================================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 129 +User-Agent: orion/REGEX(\d+\.\d+\.\d+.*) +Ngsiv2-Attrsformat: normalized +Host: 127.0.0.1:REGEX(\d+) +Accept: application/json +Content-Type: application/json; charset=utf-8 +Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1 + +{ + "data": [ + { + "id": "E1", + "sum": { + "metadata": {}, + "type": "Calculated", + "value": 3 + }, + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 136 +User-Agent: orion/REGEX(\d+\.\d+\.\d+.*) +Ngsiv2-Attrsformat: normalized +Host: 127.0.0.1:REGEX(\d+) +Accept: application/json +Content-Type: application/json; charset=utf-8 +Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1 + +{ + "data": [ + { + "id": "E1", + "sum": { + "metadata": {}, + "type": "Calculated", + "value": "foobar" + }, + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 132 +User-Agent: orion/REGEX(\d+\.\d+\.\d+.*) +Ngsiv2-Attrsformat: normalized +Host: 127.0.0.1:REGEX(\d+) +Accept: application/json +Content-Type: application/json; charset=utf-8 +Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1 + +{ + "data": [ + { + "id": "E1", + "sum": { + "metadata": {}, + "type": "Calculated", + "value": -1.7 + }, + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= + + +--TEARDOWN-- +brokerStop CB +dbDrop CB +accumulatorStop diff --git a/test/functionalTest/cases/4594_metadata_in_jexl_context/metadata_in_jexl_context_builtin.test b/test/functionalTest/cases/4594_metadata_in_jexl_context/metadata_in_jexl_context_builtin.test new file mode 100644 index 0000000000..8b013b19e9 --- /dev/null +++ b/test/functionalTest/cases/4594_metadata_in_jexl_context/metadata_in_jexl_context_builtin.test @@ -0,0 +1,253 @@ +# Copyright 2024 Telefonica Investigacion y Desarrollo, S.A.U +# +# This file is part of Orion Context Broker. +# +# Orion Context Broker is free software: you can redistribute it and/or +# modify it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# Orion Context Broker is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero +# General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Orion Context Broker. If not, see http://www.gnu.org/licenses/. +# +# For those usages not covered by this license please contact with +# iot_support at tid dot es + +# VALGRIND_READY - to mark the test ready for valgrindTestSuite.sh +# JEXL_EXPR_FLAVOUR - to mark the test has to execute only when contextBroker includes jexl-expr flavour + +--NAME-- +Metadata in JEXL context (builtin metadata) + +--SHELL-INIT-- +dbInit CB +brokerStart CB +accumulatorStart --pretty-print + +--SHELL-- + +# +# 01. Create custom sub with custom expression diff: A-metadata.A.previousValue +# 02. Create entity E1 with A=1 +# 03. Update entity E1 with A=4 +# 04. Update entity E1 with A=2 +# 05. Dump accumulator and see three notifications (diff: null, diff: 3, diff: -2) +# + + +echo "01. Create custom sub with custom expression diff: A-metadata.A.previousValue" +echo "=============================================================================" +payload='{ + "subject": { + "entities": [ + { + "id" : "E1", + "type": "T" + } + ] + }, + "notification": { + "httpCustom": { + "url": "http://127.0.0.1:'${LISTENER_PORT}'/notify", + "ngsi": { + "diff": { + "value": "${A-metadata.A.previousValue}", + "type": "Calculated" + } + } + } + } +}' +orionCurl --url /v2/subscriptions --payload "$payload" +echo +echo + + +echo "02. Create entity E1 with A=1" +echo "=============================" +payload='{ + "id": "E1", + "type": "T", + "A": { + "value": 1, + "type": "Number" + } +}' +orionCurl --url /v2/entities --payload "$payload" +echo +echo + + +echo "03. Update entity E1 with A=4" +echo "=============================" +payload='{ + "A": { + "value": 4, + "type": "Number" + } +}' +orionCurl --url /v2/entities/E1/attrs -X PATCH --payload "$payload" +echo +echo + + +echo "04. Update entity E1 with A=2" +echo "=============================" +payload='{ + "A": { + "value": 2, + "type": "Number" + } +}' +orionCurl --url /v2/entities/E1/attrs -X PATCH --payload "$payload" +echo +echo + + +echo "05. Dump accumulator and see three notifications (diff: 1, diff: 3, diff: -2)" +echo "=============================================================================" +accumulatorDump +echo +echo + + +--REGEXPECT-- +01. Create custom sub with custom expression diff: A-metadata.A.previousValue +============================================================================= +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/subscriptions/REGEX([0-9a-f]{24}) +Content-Length: 0 + + + +02. Create entity E1 with A=1 +============================= +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/entities/E1?type=T +Content-Length: 0 + + + +03. Update entity E1 with A=4 +============================= +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +04. Update entity E1 with A=2 +============================= +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +05. Dump accumulator and see three notifications (diff: 1, diff: 3, diff: -2) +============================================================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 179 +User-Agent: orion/REGEX(\d+\.\d+\.\d+.*) +Ngsiv2-Attrsformat: normalized +Host: 127.0.0.1:REGEX(\d+) +Accept: application/json +Content-Type: application/json; charset=utf-8 +Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1 + +{ + "data": [ + { + "A": { + "metadata": {}, + "type": "Number", + "value": 1 + }, + "diff": { + "metadata": {}, + "type": "Calculated", + "value": null + }, + "id": "E1", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 176 +User-Agent: orion/REGEX(\d+\.\d+\.\d+.*) +Ngsiv2-Attrsformat: normalized +Host: 127.0.0.1:REGEX(\d+) +Accept: application/json +Content-Type: application/json; charset=utf-8 +Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1 + +{ + "data": [ + { + "A": { + "metadata": {}, + "type": "Number", + "value": 4 + }, + "diff": { + "metadata": {}, + "type": "Calculated", + "value": 3 + }, + "id": "E1", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 177 +User-Agent: orion/REGEX(\d+\.\d+\.\d+.*) +Ngsiv2-Attrsformat: normalized +Host: 127.0.0.1:REGEX(\d+) +Accept: application/json +Content-Type: application/json; charset=utf-8 +Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1 + +{ + "data": [ + { + "A": { + "metadata": {}, + "type": "Number", + "value": 2 + }, + "diff": { + "metadata": {}, + "type": "Calculated", + "value": -2 + }, + "id": "E1", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= + + +--TEARDOWN-- +brokerStop CB +dbDrop CB +accumulatorStop diff --git a/test/functionalTest/cases/4594_metadata_in_jexl_context/metadata_in_jexl_context_collision.test b/test/functionalTest/cases/4594_metadata_in_jexl_context/metadata_in_jexl_context_collision.test new file mode 100644 index 0000000000..fe3f5946ff --- /dev/null +++ b/test/functionalTest/cases/4594_metadata_in_jexl_context/metadata_in_jexl_context_collision.test @@ -0,0 +1,222 @@ +# Copyright 2024 Telefonica Investigacion y Desarrollo, S.A.U +# +# This file is part of Orion Context Broker. +# +# Orion Context Broker is free software: you can redistribute it and/or +# modify it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# Orion Context Broker is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero +# General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Orion Context Broker. If not, see http://www.gnu.org/licenses/. +# +# For those usages not covered by this license please contact with +# iot_support at tid dot es + +# VALGRIND_READY - to mark the test ready for valgrindTestSuite.sh +# JEXL_EXPR_FLAVOUR - to mark the test has to execute only when contextBroker includes jexl-expr flavour + +--NAME-- +Metadata in JEXL context (collision in metadata name) + +--SHELL-INIT-- +dbInit CB +brokerStart CB +accumulatorStart --pretty-print + +--SHELL-- + +# This test is intentionally modeling an anti-pattern that should not be used, but we include it +# to check and cover the Context Broker behabiviour in this case +# +# 01. Create custom sub with custom expression sum: metadata.A.MD1 +# 02. Create entity E1 with colliding attribute named metadata +# 03. Update entity E1 with colliding attribute named metadata +# 04. Dump accumulator and see three notifications () +# + + +echo "01. Create custom sub with custom expression sum: metadata.A.MD1" +echo "================================================================" +payload='{ + "subject": { + "entities": [ + { + "id" : "E1", + "type": "T" + } + ] + }, + "notification": { + "httpCustom": { + "url": "http://127.0.0.1:'${LISTENER_PORT}'/notify", + "ngsi": { + "sum": { + "value": "${metadata.A.MD1}", + "type": "Calculated" + } + } + }, + "attrs": [ "sum" ] + } +}' +orionCurl --url /v2/subscriptions --payload "$payload" +echo +echo + + +echo "02. Create entity E1 with colliding attribute named metadata" +echo "============================================================" +payload='{ + "id": "E1", + "type": "T", + "A": { + "value": 10, + "type": "Number", + "metadata": { + "MD1": { + "value": "from-md", + "type": "Text" + } + } + }, + "metadata": { + "value": { + "A": { + "MD1": "from-attr" + } + }, + "type": "Object" + } +}' +orionCurl --url /v2/entities --payload "$payload" +echo +echo + + +echo "03. Update entity E1 with colliding attribute named metadata" +echo "============================================================" +payload='{ + "A": { + "value": 10, + "type": "Number", + "metadata": { + "MD1": { + "value": "from-md2", + "type": "Text" + } + } + }, + "metadata": { + "value": { + "A": { + "MD1": "from-attr2" + } + }, + "type": "Object" + } +}' +orionCurl --url /v2/entities/E1/attrs -X PATCH --payload "$payload" +echo +echo + + +echo "05. Dump accumulator and see three notifications (sum: 3, sum: foobar, sum: -1.7)" +echo "=================================================================================" +accumulatorDump +echo +echo + + +--REGEXPECT-- +01. Create custom sub with custom expression sum: metadata.A.MD1 +================================================================ +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/subscriptions/REGEX([0-9a-f]{24}) +Content-Length: 0 + + + +02. Create entity E1 with colliding attribute named metadata +============================================================ +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/entities/E1?type=T +Content-Length: 0 + + + +03. Update entity E1 with colliding attribute named metadata +============================================================ +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +05. Dump accumulator and see three notifications (sum: 3, sum: foobar, sum: -1.7) +================================================================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 137 +User-Agent: orion/REGEX(\d+\.\d+\.\d+.*) +Ngsiv2-Attrsformat: normalized +Host: 127.0.0.1:REGEX(\d+) +Accept: application/json +Content-Type: application/json; charset=utf-8 +Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1 + +{ + "data": [ + { + "id": "E1", + "sum": { + "metadata": {}, + "type": "Calculated", + "value": "from-md" + }, + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 138 +User-Agent: orion/REGEX(\d+\.\d+\.\d+.*) +Ngsiv2-Attrsformat: normalized +Host: 127.0.0.1:REGEX(\d+) +Accept: application/json +Content-Type: application/json; charset=utf-8 +Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1 + +{ + "data": [ + { + "id": "E1", + "sum": { + "metadata": {}, + "type": "Calculated", + "value": "from-md2" + }, + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= + + +--TEARDOWN-- +brokerStop CB +dbDrop CB +accumulatorStop From 2256824000269ada4b55771a9295b3b7e7cce59b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Fri, 2 Aug 2024 11:58:29 +0200 Subject: [PATCH 2/2] ADD docu and CNR for #4594 --- CHANGES_NEXT_RELEASE | 1 + doc/manuals/orion-api.md | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index 8663908931..eaffe48fcd 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1,4 +1,5 @@ - Add: custom notification ngsi patching evaluation priority based in evalPriority builtin metadata (#4556) +- Add: attribute metadata to JEXL context (#4594) - Fix: $max and $min operators were not supported with DateTime attributes (#4585) - Fix: wrong date values should not allowed in subscription's expires field (#4541) - Fix: do not raise DB alarm in case of wrong GeoJSON in client request diff --git a/doc/manuals/orion-api.md b/doc/manuals/orion-api.md index 0b12ed9df8..42af692801 100644 --- a/doc/manuals/orion-api.md +++ b/doc/manuals/orion-api.md @@ -75,6 +75,7 @@ - [Additional considerations](#additional-considerations) - [JEXL Support](#jexl-support) - [JEXL usage example](#jexl-usage-example) + - [Metadata support](#metadata-support) - [Evaluation priority](#evaluation-priority) - [Available Transformations](#available-transformations) - [`uppercase`](#uppercase) @@ -2514,6 +2515,19 @@ will trigger a notification like this: ] ``` +### Metadata support + +Attribute metadata is also included in the JEXL evaluation context, along with the actual attributes. This is done using a special context key named `metadata` which value is an object with the following structure: + +* keys are the name of the attributes +* values are object with a key-map of the metadata values of the given attribute + +For instance, the expression `${metadata.A.MD1}` will result in the value of the metadata `MD1` belonging to the attribute `A`. + +Note that [builtin metadata](#builtin-metadata) are automatically added to the `metadata` context key. For instance, the `${A-metadata.A.previousValue}` expression will provide the difference between the current value of `A` (in the update request) and the previous one (before the update request). + +Finally, note that in the rare case an attribute named `metadata` is used (which is an anti-pattern strongly discouraged) it will not be added to the context, as the `metadata` with metadata values will take precedence. + ### Evaluation priority Each time an expression is evaluated, it is added to the expression context, so it can be reused by other expressions. However, by default Orion does not guarantee a given evaluation other.