From 442e9e56fa62684f520d26684bafa3f3ae309452 Mon Sep 17 00:00:00 2001 From: Ken Zangelin Date: Thu, 3 Oct 2024 14:48:34 +0200 Subject: [PATCH] The rest of the tasks for read-only legacy mode --- src/lib/orionld/common/orionldState.h | 4 +- src/lib/orionld/common/traceLevels.h | 10 +- src/lib/orionld/dbModel/CMakeLists.txt | 1 + .../dbModelAttributePublishedAtLookup.cpp | 53 ++++ .../dbModelAttributePublishedAtLookup.h | 41 +++ src/lib/orionld/dds/CMakeLists.txt | 2 + .../dds/{archived => }/ddsAttributeCreate.cpp | 0 .../dds/{archived => }/ddsAttributeCreate.h | 0 .../ddsConfigTopicToAttribute.cpp | 2 + .../ddsConfigTopicToAttribute.h | 0 .../dds/ddsEntityCreateFromAttribute.cpp | 25 +- src/lib/orionld/dds/ddsInit.cpp | 6 +- src/lib/orionld/dds/ddsNotification.cpp | 131 +++------ .../serviceRoutines/orionldPostEntities.cpp | 29 +- .../serviceRoutines/orionldPutAttribute.cpp | 19 +- .../cases/0000_dds/dds_notifications.test | 251 ++++++++++++++++-- 16 files changed, 435 insertions(+), 139 deletions(-) create mode 100644 src/lib/orionld/dbModel/dbModelAttributePublishedAtLookup.cpp create mode 100644 src/lib/orionld/dbModel/dbModelAttributePublishedAtLookup.h rename src/lib/orionld/dds/{archived => }/ddsAttributeCreate.cpp (100%) rename src/lib/orionld/dds/{archived => }/ddsAttributeCreate.h (100%) rename src/lib/orionld/dds/{archived => }/ddsConfigTopicToAttribute.cpp (94%) rename src/lib/orionld/dds/{archived => }/ddsConfigTopicToAttribute.h (100%) diff --git a/src/lib/orionld/common/orionldState.h b/src/lib/orionld/common/orionldState.h index 2293b7f424..da9afe7081 100644 --- a/src/lib/orionld/common/orionldState.h +++ b/src/lib/orionld/common/orionldState.h @@ -447,11 +447,13 @@ typedef struct OrionldConnectionState DistOp* distOpList; uint32_t acceptMask; // "1 << MimeType" mask for all accepted Mime Types, regardless of which is chosen and of weight bool ddsSample; // Are we treating a sample from DDS? + char* ddsType; // type of DDS Sample + double ddsPublishTime; // time of DDS publication // // TRoE // - bool noDbUpdate; // If nothing changed in DB - troe is not invoked + bool noDbUpdate; // If nothing changed in DB - troe is not invoked bool troeError; KjNode* duplicateArray; KjNode* troeIgnoreV[20]; diff --git a/src/lib/orionld/common/traceLevels.h b/src/lib/orionld/common/traceLevels.h index 51dbd4a141..b81540f42c 100644 --- a/src/lib/orionld/common/traceLevels.h +++ b/src/lib/orionld/common/traceLevels.h @@ -35,16 +35,18 @@ typedef enum OrionldTraceLevels { StMhdInit = 100, + StSR = 101, + StRequest = 200, StDds = 201, StDdsPublish = 202, StDdsNotification = 203, StDdsLibInfo = 204, StDdsLibDebug = 205, - StDump = 206, - StDdsDump = 207, - StDdsConfig = 208, - StSR = 209 + StDdsConfig = 206, + + StDump = 300, + StDdsDump = 301 } OrionldTraceLevels; #endif // SRC_LIB_ORIONLD_COMMON_TRACELEVELS_H_ diff --git a/src/lib/orionld/dbModel/CMakeLists.txt b/src/lib/orionld/dbModel/CMakeLists.txt index f48ccbf962..11a9fc7f13 100644 --- a/src/lib/orionld/dbModel/CMakeLists.txt +++ b/src/lib/orionld/dbModel/CMakeLists.txt @@ -49,6 +49,7 @@ SET (SOURCES dbModelAttributeCreatedAtSet.cpp dbModelAttributeLookup.cpp dbModelToEntityIdAndTypeObject.cpp + dbModelAttributePublishedAtLookup.cpp ) # Include directories diff --git a/src/lib/orionld/dbModel/dbModelAttributePublishedAtLookup.cpp b/src/lib/orionld/dbModel/dbModelAttributePublishedAtLookup.cpp new file mode 100644 index 0000000000..24f5eec9de --- /dev/null +++ b/src/lib/orionld/dbModel/dbModelAttributePublishedAtLookup.cpp @@ -0,0 +1,53 @@ +/* +* +* Copyright 2024 FIWARE Foundation e.V. +* +* This file is part of Orion-LD Context Broker. +* +* Orion-LD 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-LD 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-LD Context Broker. If not, see http://www.gnu.org/licenses/. +* +* For those usages not covered by this license please contact with +* orionld at fiware dot org +* +* Author: Ken Zangelin +*/ +#include // NULL + +extern "C" +{ +#include "kjson/KjNode.h" // KjNode +#include "kjson/kjLookup.h" // kjLookup +#include "ktrace/kTrace.h" // trace messages - ktrace library +} + +#include "orionld/common/traceLevels.h" // KT_T trace levels +#include "orionld/dds/kjTreeLog.h" // kjTreeLog2 + + + +// ----------------------------------------------------------------------------- +// +// dbModelAttributePublishedAtLookup - +// +double dbModelAttributePublishedAtLookup(KjNode* dbAttrP) +{ + kjTreeLog2(dbAttrP, "dbAttr", StDds); + + KjNode* publishedAtP = kjLookup(dbAttrP, "publishedAt"); + + if (publishedAtP != NULL) + return publishedAtP->value.f; + + return 0; +} diff --git a/src/lib/orionld/dbModel/dbModelAttributePublishedAtLookup.h b/src/lib/orionld/dbModel/dbModelAttributePublishedAtLookup.h new file mode 100644 index 0000000000..0fdad895a1 --- /dev/null +++ b/src/lib/orionld/dbModel/dbModelAttributePublishedAtLookup.h @@ -0,0 +1,41 @@ +#ifndef SRC_LIB_ORIONLD_DBMODEL_DBMODELATTRIBUTEPUBLISHEDATLOOKUP_H_ +#define SRC_LIB_ORIONLD_DBMODEL_DBMODELATTRIBUTEPUBLISHEDATLOOKUP_H_ + +/* +* +* Copyright 2024 FIWARE Foundation e.V. +* +* This file is part of Orion-LD Context Broker. +* +* Orion-LD 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-LD 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-LD Context Broker. If not, see http://www.gnu.org/licenses/. +* +* For those usages not covered by this license please contact with +* orionld at fiware dot org +* +* Author: Ken Zangelin +*/ +extern "C" +{ +#include "kjson/KjNode.h" // KjNode +} + + + +// ----------------------------------------------------------------------------- +// +// dbModelAttributePublishedAtLookup - +// +extern double dbModelAttributePublishedAtLookup(KjNode* dbAttrP); + +#endif // SRC_LIB_ORIONLD_DBMODEL_DBMODELATTRIBUTEPUBLISHEDATLOOKUP_H_ diff --git a/src/lib/orionld/dds/CMakeLists.txt b/src/lib/orionld/dds/CMakeLists.txt index 8847eec0f7..db3c819ef4 100644 --- a/src/lib/orionld/dds/CMakeLists.txt +++ b/src/lib/orionld/dds/CMakeLists.txt @@ -27,6 +27,8 @@ SET (SOURCES ddsCategoryToKlogSeverity.cpp ddsNotification.cpp ddsEntityCreateFromAttribute.cpp + ddsConfigTopicToAttribute.cpp + ddsAttributeCreate.cpp ) # Include directories diff --git a/src/lib/orionld/dds/archived/ddsAttributeCreate.cpp b/src/lib/orionld/dds/ddsAttributeCreate.cpp similarity index 100% rename from src/lib/orionld/dds/archived/ddsAttributeCreate.cpp rename to src/lib/orionld/dds/ddsAttributeCreate.cpp diff --git a/src/lib/orionld/dds/archived/ddsAttributeCreate.h b/src/lib/orionld/dds/ddsAttributeCreate.h similarity index 100% rename from src/lib/orionld/dds/archived/ddsAttributeCreate.h rename to src/lib/orionld/dds/ddsAttributeCreate.h diff --git a/src/lib/orionld/dds/archived/ddsConfigTopicToAttribute.cpp b/src/lib/orionld/dds/ddsConfigTopicToAttribute.cpp similarity index 94% rename from src/lib/orionld/dds/archived/ddsConfigTopicToAttribute.cpp rename to src/lib/orionld/dds/ddsConfigTopicToAttribute.cpp index 378dedeee5..ba23ab344b 100644 --- a/src/lib/orionld/dds/archived/ddsConfigTopicToAttribute.cpp +++ b/src/lib/orionld/dds/ddsConfigTopicToAttribute.cpp @@ -30,7 +30,9 @@ extern "C" } #include "orionld/common/orionldState.h" // ddsConfigTree +#include "orionld/common/traceLevels.h" // KT_T trace levels #include "orionld/kjTree/kjNavigate.h" // kjNavigate +#include "orionld/dds/kjTreeLog.h" // kjTreeLog2 #include "orionld/dds/ddsConfigTopicToAttribute.h" // Own interface diff --git a/src/lib/orionld/dds/archived/ddsConfigTopicToAttribute.h b/src/lib/orionld/dds/ddsConfigTopicToAttribute.h similarity index 100% rename from src/lib/orionld/dds/archived/ddsConfigTopicToAttribute.h rename to src/lib/orionld/dds/ddsConfigTopicToAttribute.h diff --git a/src/lib/orionld/dds/ddsEntityCreateFromAttribute.cpp b/src/lib/orionld/dds/ddsEntityCreateFromAttribute.cpp index 5cb7906353..3ffea6e5fc 100644 --- a/src/lib/orionld/dds/ddsEntityCreateFromAttribute.cpp +++ b/src/lib/orionld/dds/ddsEntityCreateFromAttribute.cpp @@ -46,30 +46,9 @@ extern "C" // int ddsEntityCreateFromAttribute(KjNode* attrNodeP, const char* entityId, const char* attrName) { - char* entityType = NULL; - - kjTreeLog2(orionldState.requestTree, "Attribute", StDds); - - // Create entity and continue - // What do I do if there is no entity type? - // - KjNode* entityTypeNodeP = (orionldState.requestTree->type == KjObject)? kjLookup(orionldState.requestTree, "entityType") : NULL; - if (entityTypeNodeP != NULL) - { - kjChildRemove(orionldState.requestTree, entityTypeNodeP); - entityType = entityTypeNodeP->value.s; - } - else - entityType = (char*) "T"; // FIXME: find the antity type in the config file, if not present as node "entityType" in orionldState.requestTree - - orionldState.payloadIdNode = kjString(orionldState.kjsonP, "id", entityId); - orionldState.payloadTypeNode = kjString(orionldState.kjsonP, "type", entityType); - - KT_T(StDds, "Entity doesn't exist - calling orionldPostEntities"); - KT_T(StDds, "But first, need to transform the incoming request tree into a JSON object"); - KjNode* attributeP = orionldState.requestTree; - attributeP->name = (char*) attrName; + + attributeP->name = (char*) attrName; orionldState.requestTree = kjObject(orionldState.kjsonP, NULL); kjChildAdd(orionldState.requestTree, attributeP); diff --git a/src/lib/orionld/dds/ddsInit.cpp b/src/lib/orionld/dds/ddsInit.cpp index db9a233c82..7ff9fb9e5f 100644 --- a/src/lib/orionld/dds/ddsInit.cpp +++ b/src/lib/orionld/dds/ddsInit.cpp @@ -37,6 +37,7 @@ extern "C" #include "orionld/common/traceLevels.h" // kjTreeLog2 #include "orionld/common/orionldState.h" // ddsEnablerConfigFile, ddsConfigFile #include "orionld/kjTree/kjNavigate.h" // kjNavigate +#include "orionld/dds/ddsConfigTopicToAttribute.h" // ddsConfigTopicToAttribute - for debugging only #include "orionld/dds/ddsCategoryToKlogSeverity.h" // ddsCategoryToKlogSeverity #include "orionld/dds/ddsConfigLoad.h" // ddsConfigLoad #include "orionld/dds/kjTreeLog.h" // kjTreeLog2 @@ -92,8 +93,6 @@ int ddsInit(Kjson* kjP, DdsOperationMode _ddsOpMode) { ddsOpMode = _ddsOpMode; // Not yet in use ... invent usage or remove ! - eprosima::ddsenabler::init_dds_enabler(ddsEnablerConfigFile, ddsNotification, ddsTypeNotification, ddsLog); - // // DDS Configuration File // @@ -127,5 +126,8 @@ int ddsInit(Kjson* kjP, DdsOperationMode _ddsOpMode) #endif } + KT_T(StDds, "Calling init_dds_enabler"); + eprosima::ddsenabler::init_dds_enabler(ddsEnablerConfigFile, ddsNotification, ddsTypeNotification, ddsLog); + return 0; } diff --git a/src/lib/orionld/dds/ddsNotification.cpp b/src/lib/orionld/dds/ddsNotification.cpp index 49395bf793..3c3b4060ea 100644 --- a/src/lib/orionld/dds/ddsNotification.cpp +++ b/src/lib/orionld/dds/ddsNotification.cpp @@ -34,8 +34,10 @@ extern "C" #include "orionld/common/orionldState.h" // orionldState, kjTreeLog #include "orionld/common/traceLevels.h" // KT_T trace levels #include "orionld/common/tenantList.h" // tenant0 +#include "orionld/context/orionldContextItemExpand.h" // orionldContextItemExpand #include "orionld/serviceRoutines/orionldPutAttribute.h" // orionldPutAttribute #include "orionld/dds/kjTreeLog.h" // kjTreeLog2 +#include "orionld/dds/ddsConfigTopicToAttribute.h" // ddsConfigTopicToAttribute #include "orionld/dds/ddsNotification.h" // Own interface @@ -46,7 +48,7 @@ extern "C" // void ddsNotification(const char* typeName, const char* topicName, const char* json, double publishTime) { - KT_T(StDds, "Got a notification on %s:%s (json: %s)", typeName, topicName, json); + KT_T(StDdsNotification, "Got a notification on %s:%s (json: %s)", typeName, topicName, json); orionldStateInit(NULL); @@ -54,28 +56,42 @@ void ddsNotification(const char* typeName, const char* topicName, const char* js if (kTree == NULL) KT_RVE("Error parsing json payload from DDS: '%s'", json); - KjNode* idNodeP = kjLookup(kTree, "id"); - KjNode* typeNodeP = kjLookup(kTree, "type"); - KjNode* attrValueNodeP = kjLookup(kTree, topicName); + char* entityId = NULL; + char* entityType = NULL; + char* attrShortName = ddsConfigTopicToAttribute(topicName, &entityId, &entityType); - if (idNodeP == NULL) KT_RVE("No 'id' field in DDS payload "); - if (typeNodeP == NULL) KT_RVE("No 'type' field in DDS payload "); - if (attrValueNodeP == NULL) KT_RVE("No attribute field ('%s') in DDS payload", topicName); + if (attrShortName == NULL) + { + KT_W("Topic '%s' not found in the config file - redirect to default DDS entity", topicName); + entityId = (char*) "urn:ngsi-ld:dds:default"; + entityType = (char*) "DDS"; + attrShortName = (char*) topicName; + } - orionldState.payloadIdNode = idNodeP; - orionldState.payloadTypeNode = typeNodeP; - KT_T(StDds, "orionldState.payloadIdNode: %p", orionldState.payloadIdNode); - KT_T(StDds, "orionldState.payloadTypeNode: %p", orionldState.payloadTypeNode); + KjNode* participantIdNodeP = kjLookup(kTree, "id"); + if (participantIdNodeP != NULL) + { + char* pipe = strchr(participantIdNodeP->value.s, '|'); + if (pipe != NULL) + *pipe = 0; + participantIdNodeP->name = (char*) "participantId"; + } + + KjNode* idNodeP = kjString(orionldState.kjsonP, "id", entityId); + KjNode* typeNodeP = kjLookup(kTree, "type"); - // char* attributeLongName = orionldAttributeExpand(coreContextP, topicName, true, NULL); + if (typeNodeP != NULL) + orionldState.ddsType = typeNodeP->value.s; - char* pipe = strchr(idNodeP->value.s, '|'); - if (pipe != NULL) - *pipe = 0; + char* expandedType = orionldContextItemExpand(orionldState.contextP, entityType, true, NULL); + typeNodeP = kjString(orionldState.kjsonP, "type", expandedType); + + KjNode* attrValueNodeP = kjLookup(kTree, topicName); + if (attrValueNodeP == NULL) + KT_RVE("No attribute field ('%s') in DDS payload", topicName); - char id[256]; - snprintf(id, sizeof(id) - 1, "urn:%s", idNodeP->value.s); - KT_T(StDds, "New entity id: %s", id); + orionldState.payloadIdNode = idNodeP; + orionldState.payloadTypeNode = typeNodeP; KjNode* attrNodeP = kjObject(orionldState.kjsonP, NULL); kjChildAdd(attrNodeP, attrValueNodeP); @@ -84,84 +100,18 @@ void ddsNotification(const char* typeName, const char* topicName, const char* js orionldState.requestTree = attrNodeP; orionldState.uriParams.format = (char*) "simplified"; orionldState.uriParams.type = typeNodeP->value.s; - orionldState.wildcard[0] = id; - orionldState.wildcard[1] = (char*) topicName; + orionldState.wildcard[0] = entityId; + orionldState.wildcard[1] = (char*) attrShortName; orionldState.tenantP = &tenant0; // FIXME ... Use tenants? orionldState.in.pathAttrExpanded = (char*) topicName; orionldState.ddsSample = true; + orionldState.ddsPublishTime = publishTime; - // - // If the entity does not exist, it needs to be created - // Except of course, if it is registered and exists elsewhere - // - KT_T(StDds, "Calling orionldPutAttribute"); - orionldPutAttribute(); -} - -#if 0 -#include "orionld/dds/ddsConfigTopicToAttribute.h" // ddsConfigTopicToAttribute -void ddsNotification(const char* entityType, const char* entityId, const char* topicName, KjNode* notificationP) -{ - KT_V("Got a notification from DDS"); - kjTreeLog2(notificationP, "notification", StDds); - - // - // We receive entire NGSI-LD Attributes - // - KjNode* aValueNodeP = kjLookup(notificationP, "attributeValue"); - - if (entityId == NULL) - { - KT_W("Entity without id from DDS"); - return; - } - - // - // Criteria for obtaining the necessary attribute info (Entity ID+Type + Attribute long name): - // - // 1. Set the attribute long name to the topic name - // 2. Take all three from the DDS config file (depending on the topic name) - // 3. Override entity id+type with entityType+entityId from the parameters of this function - // - - // - // GET the attribute long name (and entity id+type) from the DDS config file - // - char* eId = NULL; - char* eType = NULL; - char* attributeLongName = ddsConfigTopicToAttribute(topicName, &eId, &eType); - - if (attributeLongName == NULL) // Topic name NOT found in DDS config file - attributeLongName = (char*) topicName; - - // Take entity id+type from config file unless given as parameters to this function (which would override) - if (entityType == NULL) - entityType = eType; - if (entityId == NULL) - entityId = eId; - - // What to do if we have no entity id+type ? - // - The entity id is MANDATORY - cannot continue if we don't know the entity ID - // - The entity type is onbly needed when creating the entity - and we don't know right now whether the entity already exists. - // So, we let it pass and get an error later (404 Not Found) - if (entityId == NULL) - { - KT_E(("Got a DDS sample for an entity whose ID cannot be obtained")); - return; - } - - orionldState.uriParams.type = (char*) entityType; - - orionldState.wildcard[0] = (char*) entityId; - orionldState.wildcard[1] = (char*) attributeLongName; // The topic is the attribute long name - - orionldState.requestTree = aValueNodeP; - orionldState.tenantP = &tenant0; // FIXME ... Use tenants? - orionldState.in.pathAttrExpanded = (char*) topicName; - orionldState.ddsSample = true; + kjChildAdd(attrNodeP, participantIdNodeP); - KT_T(StDds, "Calling orionldPutAttribute"); + KjNode* publishedAt = kjFloat(orionldState.kjsonP, "publishedAt", publishTime); + kjChildAdd(attrNodeP, publishedAt); // // If the entity does not exist, it needs to be created @@ -169,4 +119,3 @@ void ddsNotification(const char* entityType, const char* entityId, const char* t // orionldPutAttribute(); } -#endif diff --git a/src/lib/orionld/serviceRoutines/orionldPostEntities.cpp b/src/lib/orionld/serviceRoutines/orionldPostEntities.cpp index cb2fbfa91d..ac533e0d9b 100644 --- a/src/lib/orionld/serviceRoutines/orionldPostEntities.cpp +++ b/src/lib/orionld/serviceRoutines/orionldPostEntities.cpp @@ -44,6 +44,7 @@ extern "C" #include "orionld/common/orionldError.h" // orionldError #include "orionld/common/performance.h" // PERFORMANCE #include "orionld/common/responseFix.h" // responseFix +#include "orionld/common/traceLevels.h" // KT_T trace levels #include "orionld/http/httpHeaderLocationAdd.h" // httpHeaderLocationAdd #include "orionld/legacyDriver/legacyPostEntities.h" // legacyPostEntities #include "orionld/payloadCheck/PCHECK.h" // PCHECK_* @@ -61,6 +62,7 @@ extern "C" #include "orionld/distOp/distOpResponses.h" // distOpResponses #include "orionld/kjTree/kjChildCount.h" // kjChildCount #include "orionld/kjTree/kjSort.h" // kjStringArraySort +#include "orionld/serviceRoutines/orionldPostEntity.h" // orionldPostEntity #include "orionld/serviceRoutines/orionldPostEntities.h" // Own interface @@ -132,6 +134,21 @@ bool orionldPostEntities(void) KjNode* apiEntityP = NULL; KjNode* dbEntityP = NULL; + if ((orionldState.ddsSample == true) && (orionldState.ddsType != NULL)) + { + // + // Adding special atrtribute 'ddsType' - must be normalized (it's after payload check) + // + KjNode* ddsTypeObjectNodeP = kjObject(orionldState.kjsonP, "ddsType"); + KjNode* valueNodeP = kjString(orionldState.kjsonP, "value", orionldState.ddsType); + KjNode* typeNodeP = kjString(orionldState.kjsonP, "type", "Property"); + + kjChildAdd(ddsTypeObjectNodeP, typeNodeP); + kjChildAdd(ddsTypeObjectNodeP, valueNodeP); + + kjChildAdd(orionldState.requestTree, ddsTypeObjectNodeP); + } + // // If the entity already exists, a "409 Conflict" is returned, either complete or as part of a 207 // @@ -140,6 +157,16 @@ bool orionldPostEntities(void) { if (distOpList == NULL) // Purely local request { + if (orionldState.ddsSample == true) + { + // We got here from a DDS notification, via PUT Attribute. + // Adding an attribute to an entity - transform the request to a POST Entity + // orionldPutAttribute already transformed everything, + // + KT_T(StDds, "Entity '%s' already exists - calling orionldPostEntity to add/modify an attribute", entityId); + return orionldPostEntity(); + } + orionldError(OrionldAlreadyExists, "Entity already exists", entityId, 409); return false; } @@ -169,7 +196,6 @@ bool orionldPostEntities(void) orionldState.payloadIdNode->next = orionldState.payloadTypeNode; orionldState.payloadTypeNode->next = (apiEntityP != NULL)? apiEntityP->value.firstChildP : NULL; - // // An entity can be created without attributes. // Also, all attributes may be chopped off to exclusively registered endpoints. @@ -192,6 +218,7 @@ bool orionldPostEntities(void) if (orionldState.requestTree == NULL) orionldState.requestTree = kjObject(orionldState.kjsonP, NULL); + if (dbModelFromApiEntity(orionldState.requestTree, NULL, true, orionldState.payloadIdNode->value.s, orionldState.payloadTypeNode->value.s) == false) { // diff --git a/src/lib/orionld/serviceRoutines/orionldPutAttribute.cpp b/src/lib/orionld/serviceRoutines/orionldPutAttribute.cpp index 99c774cf5a..6331223200 100644 --- a/src/lib/orionld/serviceRoutines/orionldPutAttribute.cpp +++ b/src/lib/orionld/serviceRoutines/orionldPutAttribute.cpp @@ -47,6 +47,7 @@ extern "C" #include "orionld/dbModel/dbModelToApiEntity.h" // dbModelToApiEntity2 #include "orionld/dbModel/dbModelFromApiAttribute.h" // dbModelFromApiAttribute #include "orionld/dbModel/dbModelAttributeCreatedAtLookup.h" // dbModelAttributeCreatedAtLookup +#include "orionld/dbModel/dbModelAttributePublishedAtLookup.h" // dbModelAttributePublishedAtLookup #include "orionld/dbModel/dbModelAttributeCreatedAtSet.h" // dbModelAttributeCreatedAtSet #include "orionld/dbModel/dbModelAttributeLookup.h" // dbModelAttributeLookup #include "orionld/dbModel/dbModelEntityTypeLookup.h" // dbModelEntityTypeLookup @@ -57,6 +58,7 @@ extern "C" #include "orionld/distOp/distOpSuccess.h" // distOpSuccess #include "orionld/dds/kjTreeLog.h" // kjTreeLog2 #include "orionld/dds/ddsEntityCreateFromAttribute.h" // ddsEntityCreateFromAttribute +#include "orionld/dds/ddsAttributeCreate.h" // ddsAttributeCreate #include "orionld/notifications/alteration.h" // alteration #include "orionld/notifications/previousValuePopulate.h" // previousValuePopulate #include "orionld/notifications/sysAttrsStrip.h" // sysAttrsStrip @@ -136,8 +138,8 @@ bool orionldPutAttribute(void) dbAttrP = dbModelAttributeLookup(dbEntityP, attrLongNameEq); if (dbAttrP == NULL) { -// if (orionldState.ddsSample == true) -// return ddsAttributeCreate(orionldState.requestTree, entityType, attrName); + if (orionldState.ddsSample == true) + return ddsAttributeCreate(orionldState.requestTree, entityType, attrName); if (orionldState.distributed == false) { @@ -149,6 +151,19 @@ bool orionldPutAttribute(void) } else { + if (orionldState.ddsSample == true) + { + // + // If iniated by a DDS sample and the attribute has a newer publishedAt than the DDS publication time, + // then ignore the entire thing + // + // This can happen during startup, during the discovery phase of DDS. + // + double publishedAt = dbModelAttributePublishedAtLookup(dbAttrP); + if (publishedAt > orionldState.ddsPublishTime) + return true; + } + // GET Attribute creation date from database createdAt = dbModelAttributeCreatedAtLookup(dbAttrP); if (createdAt == -1) diff --git a/test/functionalTest/cases/0000_dds/dds_notifications.test b/test/functionalTest/cases/0000_dds/dds_notifications.test index 8a26fdb52f..8b4a935d0a 100644 --- a/test/functionalTest/cases/0000_dds/dds_notifications.test +++ b/test/functionalTest/cases/0000_dds/dds_notifications.test @@ -21,11 +21,28 @@ # VALGRIND_READY - to mark the test ready for valgrindTestSuite.sh --NAME-- -Two DDS test clients, one publishes, the other receives notifications +the test client publishes on DDS, the broker receives DDS notifications and creates/updates the corresponding NGSI-LD entities --SHELL-INIT-- +echo '{ + "dds": { + "topics": { + "P1": { + "entityId": "urn:ngsi-ld:camera:cam1", + "entityType": "Camera", + "attribute": "shutterSpeed" + }, + "P2": { + "entityId": "urn:ngsi-ld:arm:arm1", + "entityType": "Arm", + "attribute": "armReach" + } + } + } +}' > /tmp/ddsConfig + dbInit CB -orionldStart CB -mongocOnly -dds -ddsSubsTopics https://uri.etsi.org/ngsi-ld/default-context/P1,https://uri.etsi.org/ngsi-ld/default-context/P2 -ddsTopicType xyz +orionldStart CB -mongocOnly -dds -ddsConfigFile /tmp/ddsConfig ftClientStart -t 0-5000 --SHELL-- @@ -35,7 +52,9 @@ ftClientStart -t 0-5000 # 02. Ask FT to publish an entity urn:E2 on topic 'P2' # 03. Ask FT to publish an entity urn:E3 on topic 'P3' # 04. Ask FT to publish an entity urn:E4 on topic 'P4' -# 05. Query the broker for all its entities, see all four +# 05. Query the broker for all its entities, see all three (urn:ngsi-ld:camera:cam1, urn:ngsi-ld:arm:arm1, and the default entity)) +# 06. Kill the broker and empty its databae, then restart the broker again +# 07. Query the broker for all its entities, see all three - should be present due to the DDS discovery # echo "01. Ask FT to publish an entity urn:E1 on topic 'P1'" @@ -87,6 +106,23 @@ echo echo +echo "06. Kill the broker and empty its database, then restart the broker again" +echo "=========================================================================" +brokerStop +dbInit CB > /dev/null +orionldStart CB -mongocOnly -dds -ddsConfigFile /tmp/ddsConfig > /dev/null +echo Orion-LD is running again +echo +echo + + +echo "07. Query the broker for all its entities, see all three - should be present due to the DDS discovery " +echo "======================================================================================================" +orionCurl --url /ngsi-ld/v1/entities?local=true +echo +echo + + --REGEXPECT-- 01. Ask FT to publish an entity urn:E1 on topic 'P1' ==================================================== @@ -119,14 +155,27 @@ Date: REGEX(.*) 05. Query the broker for all its entities, see all four ======================================================= HTTP/1.1 200 OK -Content-Length: 820 +Content-Length: 1438 Content-Type: application/json Date: REGEX(.*) Link: