diff --git a/src/app/orionld/orionldRestServices.cpp b/src/app/orionld/orionldRestServices.cpp index 31c22b6d7d..f153138ffe 100644 --- a/src/app/orionld/orionldRestServices.cpp +++ b/src/app/orionld/orionldRestServices.cpp @@ -92,7 +92,7 @@ static OrionLdRestServiceSimplified getServiceV[] = { "/ngsi-ld/ex/v1/ping", orionldGetPing }, { "/ngsi-ld/v1/entities/*", orionldGetEntity }, { "/ngsi-ld/v1/entities", orionldGetEntities }, - { "/ngsi-ld/v1/entityMap/*", orionldGetEntityMap }, + { "/ngsi-ld/v1/entityMaps/*", orionldGetEntityMap }, { "/ngsi-ld/v1/types/*", orionldGetEntityType }, { "/ngsi-ld/v1/types", orionldGetEntityTypes }, { "/ngsi-ld/v1/attributes/*", orionldGetEntityAttribute }, @@ -176,7 +176,7 @@ static OrionLdRestServiceSimplified deleteServiceV[] = { { "/ngsi-ld/v1/entities/*/attrs/*", orionldDeleteAttribute }, { "/ngsi-ld/v1/entities/*", orionldDeleteEntity }, - { "/ngsi-ld/v1/entityMap/*", orionldDeleteEntityMap }, + { "/ngsi-ld/v1/entityMaps/*", orionldDeleteEntityMap }, { "/ngsi-ld/v1/subscriptions/*", orionldDeleteSubscription }, { "/ngsi-ld/v1/csourceRegistrations/*", orionldDeleteRegistration }, { "/ngsi-ld/v1/jsonldContexts/*", orionldDeleteContext }, diff --git a/src/lib/logMsg/traceLevels.h b/src/lib/logMsg/traceLevels.h index c7e18cb32d..1344508d43 100644 --- a/src/lib/logMsg/traceLevels.h +++ b/src/lib/logMsg/traceLevels.h @@ -83,11 +83,13 @@ typedef enum TraceLevels LmtDistOpResponseHeaders, // HTTP headers of responses to distributed requests LmtDistOpRequestHeaders, // HTTP headers of request of distributed requests LmtDistOpList, // Linked list of DistOps + LmtDistOpAttributes, // The union of attributes URL-Param / Registered Attributes + LmtDistOpMerge, // Merge of responses from forwsrded requests (GET /entities) // // Context // - LmtContexts = 80, // Contexts + LmtContexts = 82, // Contexts LmtContextTree, // Context Tree LmtContextCache, // Context Cache LmtContextDownload, // Context Download diff --git a/src/lib/orionld/forwarding/distOpCreate.cpp b/src/lib/orionld/forwarding/distOpCreate.cpp index c6703e4d90..687e89bffb 100644 --- a/src/lib/orionld/forwarding/distOpCreate.cpp +++ b/src/lib/orionld/forwarding/distOpCreate.cpp @@ -27,66 +27,12 @@ #include "logMsg/logMsg.h" // LM_* #include "orionld/common/orionldState.h" // orionldState -#include "orionld/types/StringArray.h" // StringArray -#include "orionld/context/orionldContextItemAliasLookup.h" // orionldContextItemAliasLookup +#include "orionld/types/StringArray.h" // StringArray, stringArrayClone #include "orionld/forwarding/DistOp.h" // DistOp #include "orionld/forwarding/DistOpType.h" // DistOpType - -// ----------------------------------------------------------------------------- -// -// attrsParam - -// -static void attrsParam(DistOp* distOpP, StringArray* attrList, bool permanent) -{ - // - // The attributes are in longnames but ... should probably compact them. - // A registration can have its own @context, in cSourceInfo - for now, we use the @context of the original request. - // The attrList is always cloned, so, no problem modifying it. - // - int attrsLen = 0; - for (int ix = 0; ix < attrList->items; ix++) - { - attrList->array[ix] = orionldContextItemAliasLookup(orionldState.contextP, attrList->array[ix], NULL, NULL); - attrsLen += strlen(attrList->array[ix]) + 1; - } - - // Make room for "attrs=" and the string-end zero - attrsLen += 7; - - char* attrs = (char*) ((permanent == true)? malloc(attrsLen) : kaAlloc(&orionldState.kalloc, attrsLen)); - - if (attrs == NULL) - LM_X(1, ("Out of memory")); - - bzero(attrs, attrsLen); - - strcpy(attrs, "attrs="); - - int pos = 6; - for (int ix = 0; ix < attrList->items; ix++) - { - int len = strlen(attrList->array[ix]); - strcpy(&attrs[pos], attrList->array[ix]); - - // Add comma unless it's the last attr (in which case we add a zero, just in case) - pos += len; - - if (ix != attrList->items - 1) // Not the last attr - { - attrs[pos] = ','; - pos += 1; - } - else - attrs[pos] = 0; - } - - distOpP->attrsParam = attrs; - distOpP->attrsParamLen = pos; -} - - +extern void attrsParam(DistOp* distOpP, StringArray* attrList, bool permanent); // ----------------------------------------------------------------------------- // @@ -98,7 +44,7 @@ DistOp* distOpCreate RegCacheItem* regP, StringArray* idList, StringArray* typeList, - StringArray* attrList, + StringArray* attrList, // As it arrives in the GET request (URL param 'attrs') bool permanent ) { @@ -111,13 +57,14 @@ DistOp* distOpCreate distOpP->regP = regP; distOpP->operation = operation; - distOpP->attrList = attrList; distOpP->idList = idList; distOpP->typeList = typeList; - // Fix the comma-separated attribute list + attrList = (attrList != NULL)? stringArrayClone(attrList) : NULL; if ((attrList != NULL) && (attrList->items > 0)) - attrsParam(distOpP, attrList, permanent); + attrsParam(distOpP, attrList, true); + else + distOpP->attrsParam = NULL; // Assign an ID to this DistOp if (regP != NULL) @@ -126,7 +73,7 @@ DistOp* distOpCreate ++orionldState.distOpNo; } else - strncpy(distOpP->id, "local", sizeof(distOpP->id)); + strncpy(distOpP->id, "@none", sizeof(distOpP->id)); if (distOpP->regP != NULL) LM_T(LmtDistOpList, ("Created distOp '%s', for reg '%s'", distOpP->id, distOpP->regP->regId)); diff --git a/src/lib/orionld/forwarding/distOpEntityMerge.cpp b/src/lib/orionld/forwarding/distOpEntityMerge.cpp index 904b016a22..dca0f11ad6 100644 --- a/src/lib/orionld/forwarding/distOpEntityMerge.cpp +++ b/src/lib/orionld/forwarding/distOpEntityMerge.cpp @@ -111,6 +111,8 @@ static KjNode* newerAttribute(KjNode* currentP, KjNode* pretenderP) // // distOpEntityMerge - // +// FIXME: createdAt and modifiedAt should be converted to floats before comparing! +// void distOpEntityMerge(KjNode* apiEntityP, KjNode* additionP, bool sysAttrs, bool auxiliary) { KjNode* idP = kjLookup(additionP, "id"); @@ -141,46 +143,62 @@ void distOpEntityMerge(KjNode* apiEntityP, KjNode* additionP, bool sysAttrs, boo { next = attrP->next; - KjNode* currentP = kjLookup(apiEntityP, attrP->name); + KjNode* currentP = kjLookup(apiEntityP, attrP->name); + bool createdAt = strcmp(attrP->name, "createdAt") == 0; + bool modifiedAt = strcmp(attrP->name, "modifiedAt") == 0; if (currentP == NULL) { + LM_T(LmtDistOpMerge, ("New Attribute '%s' - adding it to the entity", attrP->name)); kjChildRemove(additionP, attrP); kjChildAdd(apiEntityP, attrP); } + else if (createdAt == true) // Special attribute - need to keep the oldest, not the newest + { + LM_T(LmtDistOpMerge, ("'createdAt' in any type of registration")); + LM_T(LmtDistOpMerge, ("Current createdAt: %s", currentP->value.s)); + LM_T(LmtDistOpMerge, ("Candidate createdAt: %s", attrP->value.s)); + if (strcmp(attrP->value.s, currentP->value.s) > 0) + { + LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - keeping it as it is OLDER than the old one", attrP->name)); + kjChildRemove(apiEntityP, currentP); + kjChildRemove(additionP, attrP); + kjChildAdd(apiEntityP, attrP); + } + else + LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - ignoring it as it is NEWER than the old one", attrP->name)); + } + else if (modifiedAt == true) // Special attribute - non-reified + { + LM_T(LmtDistOpMerge, ("'modifiedAt' in any type of registration")); + LM_T(LmtDistOpMerge, ("Current modifiedAt: %s", currentP->value.s)); + LM_T(LmtDistOpMerge, ("Candidate modifiedAt: %s", attrP->value.s)); + if (strcmp(attrP->value.s, currentP->value.s) < 0) + { + LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - keeping it as it is newer than the old one", attrP->name)); + kjChildRemove(apiEntityP, currentP); + kjChildRemove(additionP, attrP); + kjChildAdd(apiEntityP, attrP); + } + else + LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - ignoring it as it is older than the old one", attrP->name)); + } else if (auxiliary == false) // two copies of the same attr ... and NOT from an auxiliary registration { + LM_T(LmtDistOpMerge, ("Existing Attribute '%s' in non-Auxiliary registration", attrP->name)); if (newerAttribute(currentP, attrP) == attrP) { + LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - keeping it as it is newer than the old one", attrP->name)); kjChildRemove(apiEntityP, currentP); kjChildRemove(additionP, attrP); kjChildAdd(apiEntityP, attrP); } + else + LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - ignoring it as it is older than the old one", attrP->name)); } + else + LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - ignoring it as the registration is Auxiliary", attrP->name)); attrP = next; } } - - - -// ----------------------------------------------------------------------------- -// -// distOpEntityMerge - -// -void distOpEntityMerge(KjNode* entityArray, KjNode* entityP) -{ - KjNode* entityIdNode = kjLookup(entityP, "id"); - - if (entityIdNode == NULL) - LM_RVE(("Invalid entity in response from forwarded request")); - - char* entityId = entityIdNode->value.s; - - KjNode* arrayEntityP = kjEntityIdLookupInEntityArray(entityArray, entityId); - - if (arrayEntityP == NULL) // Not there yet - let's add it - kjChildAdd(entityArray, entityP); - else // Need to merge the two entities - distOpEntityMerge(arrayEntityP, entityP, orionldState.uriParamOptions.sysAttrs, false); -} diff --git a/src/lib/orionld/forwarding/distOpEntityMerge.h b/src/lib/orionld/forwarding/distOpEntityMerge.h index 79a6139559..cb279410db 100644 --- a/src/lib/orionld/forwarding/distOpEntityMerge.h +++ b/src/lib/orionld/forwarding/distOpEntityMerge.h @@ -38,12 +38,4 @@ extern "C" // extern void distOpEntityMerge(KjNode* apiEntityP, KjNode* additionP, bool sysAttrs, bool auxiliary); - - -// ----------------------------------------------------------------------------- -// -// distOpEntityMerge - -// -extern void distOpEntityMerge(KjNode* entityArray, KjNode* entityP); - #endif // SRC_LIB_ORIONLD_FORWARDING_DISTOPENTITYMERGE_H_ diff --git a/src/lib/orionld/forwarding/distOpListDebug.cpp b/src/lib/orionld/forwarding/distOpListDebug.cpp index af5a40e207..9926412513 100644 --- a/src/lib/orionld/forwarding/distOpListDebug.cpp +++ b/src/lib/orionld/forwarding/distOpListDebug.cpp @@ -119,7 +119,7 @@ void distOpListDebug2(DistOp* distOpP, const char* what) if (distOpP->attrsParam != NULL) { - LM_T(LmtDistOpList, (" URL Attributes: %s (len: %d)", distOpP->attrsParam, distOpP->attrsParamLen)); + LM_T(LmtDistOpList, (" URL Attributes: '%s' (len: %d)", distOpP->attrsParam, distOpP->attrsParamLen)); } if (distOpP->typeList != NULL) diff --git a/src/lib/orionld/forwarding/regMatchAttributesForGet.cpp b/src/lib/orionld/forwarding/regMatchAttributesForGet.cpp index ef490f9927..908753e5bd 100644 --- a/src/lib/orionld/forwarding/regMatchAttributesForGet.cpp +++ b/src/lib/orionld/forwarding/regMatchAttributesForGet.cpp @@ -24,14 +24,13 @@ */ extern "C" { -#include "kalloc/kaStrdup.h" // kaStrdup #include "kjson/kjLookup.h" // kjLookup } #include "logMsg/logMsg.h" // LM_* #include "orionld/common/orionldState.h" // orionldState -#include "orionld/types/StringArray.h" // StringArray +#include "orionld/types/StringArray.h" // StringArray, stringArrayClone #include "orionld/kjTree/kjStringValueLookupInArray.h" // kjStringValueLookupInArray #include "orionld/regCache/RegCache.h" // RegCacheItem #include "orionld/forwarding/regMatchAttributesForGet.h" // Own interface @@ -76,27 +75,6 @@ static bool stringArrayRemoveItem(StringArray* saP, int ix) -// ----------------------------------------------------------------------------- -// -// stringArrayClone - FIXME: Move to common/stringArrayClone.h/cpp -// -StringArray* stringArrayClone(StringArray* attrV) -{ - StringArray* clone = (StringArray*) kaAlloc(&orionldState.kalloc, sizeof(StringArray)); - - clone->items = attrV->items; - clone->array = (char**) kaAlloc(&orionldState.kalloc, attrV->items * sizeof(char*)); - - for (int ix = 0; ix < clone->items; ix++) - { - clone->array[ix] = kaStrdup(&orionldState.kalloc, attrV->array[ix]); - } - - return clone; -} - - - // ----------------------------------------------------------------------------- // // regMatchAttributesForGet - @@ -117,6 +95,8 @@ StringArray* regMatchAttributesForGet { bool allAttributes = (propertyNamesP == NULL) && (relationshipNamesP == NULL); + LM_T(LmtDistOpAttributes, ("Creating the union of attributes GET URL-Param vs Registered Attributes")); + if (allAttributes == true) { // @@ -129,7 +109,10 @@ StringArray* regMatchAttributesForGet // Now, if the query is with an "attrs" parameter, we'll create a copy of it for this DistOp // if (attrListP != NULL) + { + LM_T(LmtDistOpAttributes, ("Keeping the URL-Param Attributes as the registration has no attributes specified")); return stringArrayClone(attrListP); + } } StringArray* sList = (StringArray*) kaAlloc(&orionldState.kalloc, sizeof(StringArray)); @@ -140,6 +123,7 @@ StringArray* regMatchAttributesForGet // Everything matches - return an empty array sList->items = 0; sList->array = NULL; + LM_T(LmtDistOpAttributes, ("Using ALL Attributes as the registration has no attributes specified and the Query also not")); return sList; } else if ((attrListP != NULL) && (attrListP->items > 0)) @@ -165,6 +149,7 @@ StringArray* regMatchAttributesForGet { for (KjNode* pName = propertyNamesP->value.firstChildP; pName != NULL; pName = pName->next) { + LM_T(LmtDistOpAttributes, ("Adding '%s' to the attrList of the DistOp", pName->value.s)); sList->array[ix++] = pName->value.s; } } @@ -173,6 +158,7 @@ StringArray* regMatchAttributesForGet { for (KjNode* rName = relationshipNamesP->value.firstChildP; rName != NULL; rName = rName->next) { + LM_T(LmtDistOpAttributes, ("Adding '%s' to the attrList of the DistOp", rName->value.s)); sList->array[ix++] = rName->value.s; } } @@ -195,6 +181,7 @@ StringArray* regMatchAttributesForGet if (match == false) continue; + LM_T(LmtDistOpAttributes, ("Adding '%s' to the attrList of the DistOp", attrListP->array[ix])); sList->array[matches++] = attrListP->array[ix]; if (regP->mode == RegModeExclusive) @@ -207,5 +194,6 @@ StringArray* regMatchAttributesForGet sList->items = matches; } + LM_T(LmtDistOpAttributes, ("Returning an attrList of %d items", sList->items)); return sList; } diff --git a/src/lib/orionld/forwarding/regMatchInformationArrayForGet.cpp b/src/lib/orionld/forwarding/regMatchInformationArrayForGet.cpp index af9b0b4d58..69acbd9fed 100644 --- a/src/lib/orionld/forwarding/regMatchInformationArrayForGet.cpp +++ b/src/lib/orionld/forwarding/regMatchInformationArrayForGet.cpp @@ -38,7 +38,7 @@ extern "C" #include "orionld/forwarding/regMatchInformationItemForGet.h" // Own interface - +extern void attrsParam(DistOp* distOpP, StringArray* attrList, bool permanent); // ----------------------------------------------------------------------------- // // regMatchInformationArrayForGet - @@ -57,6 +57,9 @@ DistOp* regMatchInformationArrayForGet(RegCacheItem* regP, const char* entityId, // If we get this far, then it's a match and we can create the DistOp item and return DistOp* distOpP = distOpCreate(DoQueryEntity, regP, NULL, NULL, attrList, false); + if ((distOpP->attrList != NULL) && (distOpP->attrList->items > 0)) + attrsParam(distOpP, distOpP->attrList, true); + distOpP->geometryProperty = (char*) geoProp; return distOpP; diff --git a/src/lib/orionld/forwarding/regMatchInformationItemForQuery.cpp b/src/lib/orionld/forwarding/regMatchInformationItemForQuery.cpp index 9524fb7bb6..3f506ed336 100644 --- a/src/lib/orionld/forwarding/regMatchInformationItemForQuery.cpp +++ b/src/lib/orionld/forwarding/regMatchInformationItemForQuery.cpp @@ -31,6 +31,7 @@ extern "C" #include "orionld/common/orionldState.h" // orionldState, kjTreeLog #include "orionld/regCache/RegCache.h" // RegCacheItem #include "orionld/types/StringArray.h" // StringArray +#include "orionld/context/orionldContextItemAliasLookup.h" // orionldContextItemAliasLookup #include "orionld/forwarding/DistOp.h" // DistOp #include "orionld/forwarding/distOpCreate.h" // distOpCreate #include "orionld/forwarding/distOpListsMerge.h" // distOpListsMerge @@ -40,6 +41,60 @@ extern "C" +// ----------------------------------------------------------------------------- +// +// attrsParam - +// +void attrsParam(DistOp* distOpP, StringArray* attrList, bool permanent) +{ + // + // The attributes are in longnames but ... should probably compact them. + // A registration can have its own @context, in cSourceInfo - for now, we use the @context of the original request. + // The attrList is always cloned, so, no problem modifying it. + // + int attrsLen = 0; + for (int ix = 0; ix < attrList->items; ix++) + { + attrList->array[ix] = orionldContextItemAliasLookup(orionldState.contextP, attrList->array[ix], NULL, NULL); + attrsLen += strlen(attrList->array[ix]) + 1; + } + + // Make room for "attrs=" and the string-end zero + attrsLen += 7; + + char* attrs = (char*) ((permanent == true)? malloc(attrsLen) : kaAlloc(&orionldState.kalloc, attrsLen)); + + if (attrs == NULL) + LM_X(1, ("Out of memory")); + + bzero(attrs, attrsLen); + + strcpy(attrs, "attrs="); + + int pos = 6; + for (int ix = 0; ix < attrList->items; ix++) + { + int len = strlen(attrList->array[ix]); + strcpy(&attrs[pos], attrList->array[ix]); + + // Add comma unless it's the last attr (in which case we add a zero, just in case) + pos += len; + + if (ix != attrList->items - 1) // Not the last attr + { + attrs[pos] = ','; + pos += 1; + } + else + attrs[pos] = 0; + } + + distOpP->attrsParam = attrs; + distOpP->attrsParamLen = pos; +} + + + // ----------------------------------------------------------------------------- // // regMatchInformationItemForQuery - @@ -114,6 +169,10 @@ DistOp* regMatchInformationItemForQuery for (DistOp* distOpP = distOpList; distOpP != NULL; distOpP = distOpP->next) { distOpP->attrList = attrUnionP; + if ((distOpP->attrList != NULL) && (distOpP->attrList->items > 0)) + attrsParam(distOpP, distOpP->attrList, true); + else + distOpP->attrsParam = NULL; } return distOpList; diff --git a/src/lib/orionld/mongoc/mongocKjTreeToBson.cpp b/src/lib/orionld/mongoc/mongocKjTreeToBson.cpp index bfe1f7f71f..ca1a5938ed 100644 --- a/src/lib/orionld/mongoc/mongocKjTreeToBson.cpp +++ b/src/lib/orionld/mongoc/mongocKjTreeToBson.cpp @@ -54,13 +54,13 @@ static void kjTreeToBson(KjNode* nodeP, bson_t* parentP, bool inArray, int array { slen = snprintf(nameBuf, sizeof(nameBuf), "%d", arrayIndex); name = nameBuf; - LM_T(LmtMongoc, ("Array Index: '%s'", name)); + // LM_T(LmtMongoc, ("Array Index: '%s'", name)); } else { name = nodeP->name; slen = strlen(name); - LM_T(LmtMongoc, ("Name: '%s'", name)); + // LM_T(LmtMongoc, ("Name: '%s'", name)); } if (nodeP->type == KjString) bson_append_utf8(parentP, name, slen, nodeP->value.s, -1); @@ -77,7 +77,7 @@ static void kjTreeToBson(KjNode* nodeP, bson_t* parentP, bool inArray, int array for (KjNode* itemP = nodeP->value.firstChildP; itemP != NULL; itemP = itemP->next) { - LM_T(LmtMongoc, ("Calling kjTreeToBson for item '%s' of container '%s'", itemP->name, nodeP->name)); + // LM_T(LmtMongoc, ("Calling kjTreeToBson for item '%s' of container '%s'", itemP->name, nodeP->name)); kjTreeToBson(itemP, &bObject, false); } bson_append_document_end(parentP, &bObject); @@ -91,7 +91,7 @@ static void kjTreeToBson(KjNode* nodeP, bson_t* parentP, bool inArray, int array bson_append_array_begin(parentP, name, slen, &bArray); for (KjNode* itemP = nodeP->value.firstChildP; itemP != NULL; itemP = itemP->next) { - LM_T(LmtMongoc, ("Calling kjTreeToBson for array item %d of '%s'", arrayIndex, nodeP->name)); + // LM_T(LmtMongoc, ("Calling kjTreeToBson for array item %d of '%s'", arrayIndex, nodeP->name)); kjTreeToBson(itemP, &bArray, true, arrayIndex); arrayIndex += 1; } @@ -115,7 +115,7 @@ void mongocKjTreeToBson(KjNode* treeP, bson_t* bsonP) int arrayIx = 0; for (KjNode* itemP = treeP->value.firstChildP; itemP != NULL; itemP = itemP->next) { - LM_T(LmtMongoc, ("Calling kjTreeToBson for '%s' of '%s'", itemP->name, treeP->name)); + // LM_T(LmtMongoc, ("Calling kjTreeToBson for '%s' of '%s'", itemP->name, treeP->name)); kjTreeToBson(itemP, bsonP, inArray, arrayIx); if (inArray == true) diff --git a/src/lib/orionld/serviceRoutines/orionldGetEntities.cpp b/src/lib/orionld/serviceRoutines/orionldGetEntities.cpp index 396dc8e57a..2512b75cf9 100644 --- a/src/lib/orionld/serviceRoutines/orionldGetEntities.cpp +++ b/src/lib/orionld/serviceRoutines/orionldGetEntities.cpp @@ -197,6 +197,7 @@ DistOp* distOpRequestsForEntitiesQuery(char* idPattern, QNode* qNode) DistOp* exclusiveList = regMatchForEntitiesQuery(RegModeExclusive, &orionldState.in.idList, &orionldState.in.typeList, &orionldState.in.attrList); DistOp* redirectList = regMatchForEntitiesQuery(RegModeRedirect, &orionldState.in.idList, &orionldState.in.typeList, &orionldState.in.attrList); // FIXME: Strip off attrs, entityId, entityType, etc from URI params (regMatchForEntitiesQuery(RegModeExclusive) already does it for each match + DistOp* inclusiveList = regMatchForEntitiesQuery(RegModeInclusive, &orionldState.in.idList, &orionldState.in.typeList, &orionldState.in.attrList); DistOp* distOpList; @@ -310,21 +311,21 @@ bool orionldGetEntities(void) orionldState.uriParams.onlyIds, true); - // Create the "local" DistOp + // Create the "@none" DistOp DistOp* local = distOpCreate(DoQueryEntity, NULL, &orionldState.in.idList, &orionldState.in.typeList, &orionldState.in.attrList, true); - // Add lang, geometryProperty, qNode, ... to the "local" DistOp - local->lang = (orionldState.uriParams.lang != NULL)? strdup(orionldState.uriParams.lang) : NULL; + // Add lang, geometryProperty, qNode, ... to the "@none" DistOp + local->lang = (orionldState.uriParams.lang != NULL)? strdup(orionldState.uriParams.lang) : NULL; local->geoInfo.geometry = geoInfo.geometry; local->geoInfo.georel = geoInfo.georel; local->geoInfo.coordinates = (geoInfo.coordinates != NULL)? kjClone(NULL, geoInfo.coordinates) : NULL; local->geoInfo.minDistance = geoInfo.minDistance; local->geoInfo.maxDistance = geoInfo.maxDistance; - local->geoInfo.geoProperty = (geoInfo.geoProperty != NULL)? strdup(geoInfo.geoProperty) : NULL; + local->geoInfo.geoProperty = (geoInfo.geoProperty != NULL)? strdup(geoInfo.geoProperty) : NULL; local->geometryProperty = (orionldState.uriParams.geometryProperty != NULL)? strdup(orionldState.uriParams.geometryProperty) : NULL; local->qNode = (qNode != NULL)? qClone(qNode) : NULL; - // Add the "local" DistOp to the linked list of DistOps + // Add the "@none" DistOp to the linked list of DistOps local->next = orionldDistOps; orionldDistOps = local; diff --git a/src/lib/orionld/serviceRoutines/orionldGetEntitiesDistributed.cpp b/src/lib/orionld/serviceRoutines/orionldGetEntitiesDistributed.cpp index 8614fcc71e..0b79a48e59 100644 --- a/src/lib/orionld/serviceRoutines/orionldGetEntitiesDistributed.cpp +++ b/src/lib/orionld/serviceRoutines/orionldGetEntitiesDistributed.cpp @@ -147,7 +147,7 @@ void distOpsReceive(DistOp* distOpList, DistOpResponseTreatFunction treatFunctio // // Right now it looks like this: // { -// "urn:entities:E1": [ "urn:registrations:R1", "urn:registrations:R2", ... "local" ], +// "urn:entities:E1": [ "urn:registrations:R1", "urn:registrations:R2", ... "@none" ], // "urn:entities:E1": [ "urn:registrations:R1", "urn:registrations:R2", ... ], // } // @@ -155,7 +155,7 @@ void distOpsReceive(DistOp* distOpList, DistOpResponseTreatFunction treatFunctio // { // "urn:registrations:R1": ["urn:entities:E1", "urn:entities:E2" ], // "urn:registrations:R2": ["urn:entities:E1", "urn:entities:E2" ], -// "local": ["urn:entities:E1"] +// "@none": ["urn:entities:E1"] // } // // BUT, I need also entity type and attrs ... @@ -163,7 +163,7 @@ void distOpsReceive(DistOp* distOpList, DistOpResponseTreatFunction treatFunctio // New Entity Map: // { // "urn:entities:E1": { -// "regs": [ "urn:registrations:R1", "urn:registrations:R2", ... "local" ] +// "regs": [ "urn:registrations:R1", "urn:registrations:R2", ... "@none" ] // "type": "T", // "attrs": [ "urn:attribute:P1", "urn:attribute:P2", ... ] // } @@ -188,14 +188,14 @@ void distOpsReceive(DistOp* distOpList, DistOpResponseTreatFunction treatFunctio // // New Entity Map II: // { -// "urn:entities:E1": [ "DistOp0001", "DistOp0002", "DistOp0003", ... "local" ], +// "urn:entities:E1": [ "DistOp0001", "DistOp0002", "DistOp0003", ... "@none" ], // } // // And turn that into: // { // "DistOp0001": [ "urn:entities:E1", "urn:entities:E2" ], // "DistOp0002": [ "urn:entities:E1", "urn:entities:E2" ], -// "local": [ "urn:entities:E1", "urn:entities:E2" ], +// "@none": [ "urn:entities:E1", "urn:entities:E2" ], // } // // Does local have a DistOp? @@ -223,7 +223,7 @@ static void entityMapItemAdd(const char* entityId, DistOp* distOpP) // // Add DistOp ID to matchP's array - remember it's a global variable, can't use kaAlloc // - const char* distOpId = (distOpP != NULL)? distOpP->id : "local"; + const char* distOpId = (distOpP != NULL)? distOpP->id : "@none"; KjNode* distOpIdNodeP = kjString(NULL, NULL, distOpId); LM_T(LmtEntityMap, ("Adding DistOp '%s' to entity '%s'", distOpId, matchP->name)); @@ -281,6 +281,7 @@ static void distOpMatchIdsRequest(DistOp* distOpList) // static void entityMapCreate(DistOp* distOpList, char* idPattern, QNode* qNode, OrionldGeoInfo* geoInfoP) { + LM_T(LmtMongoc, ("orionldState.in.attrList.items: %d", orionldState.in.attrList.items)); orionldEntityMap = kjObject(NULL, "orionldEntityMap"); // @@ -300,6 +301,19 @@ static void entityMapCreate(DistOp* distOpList, char* idPattern, QNode* qNode, O // Get the local matches KjNode* localEntityV = NULL; + LM_T(LmtMongoc, ("orionldState.in.attrList.items: %d", orionldState.in.attrList.items)); + LM_T(LmtMongoc, ("Calling mongocEntitiesQuery")); + + // + // Can't do any pagination in this step, and we only really need the Entity ID + // Need to teporarily modify the users input for that + // + int offset = orionldState.uriParams.offset; + int limit = orionldState.uriParams.limit; + + orionldState.uriParams.offset = 0; + orionldState.uriParams.limit = 1000; + KjNode* localDbMatches = mongocEntitiesQuery(&orionldState.in.typeList, &orionldState.in.idList, idPattern, @@ -310,6 +324,9 @@ static void entityMapCreate(DistOp* distOpList, char* idPattern, QNode* qNode, O geojsonGeometryLongName, true); + orionldState.uriParams.offset = offset; + orionldState.uriParams.limit = limit; + kjTreeLog(localDbMatches, "localDbMatches", LmtSR); if (localDbMatches != NULL) { @@ -356,10 +373,16 @@ static void entityMapCreate(DistOp* distOpList, char* idPattern, QNode* qNode, O // bool orionldGetEntitiesDistributed(DistOp* distOpList, char* idPattern, QNode* qNode, OrionldGeoInfo* geoInfoP) { + LM_T(LmtMongoc, ("orionldState.in.attrList.items: %d", orionldState.in.attrList.items)); if (orionldEntityMap != NULL) + { + LM_T(LmtMongoc, ("Calling orionldGetEntitiesPage")); return orionldGetEntitiesPage(); + } + LM_T(LmtMongoc, ("orionldState.in.attrList.items: %d", orionldState.in.attrList.items)); entityMapCreate(distOpList, idPattern, qNode, geoInfoP); + LM_T(LmtMongoc, ("orionldState.in.attrList.items: %d", orionldState.in.attrList.items)); // // if there are no entity hits to the matching registrations, the request is treated as a local request diff --git a/src/lib/orionld/serviceRoutines/orionldGetEntitiesPage.cpp b/src/lib/orionld/serviceRoutines/orionldGetEntitiesPage.cpp index f908b4263f..a9926d6092 100644 --- a/src/lib/orionld/serviceRoutines/orionldGetEntitiesPage.cpp +++ b/src/lib/orionld/serviceRoutines/orionldGetEntitiesPage.cpp @@ -37,8 +37,10 @@ extern "C" #include "orionld/common/orionldState.h" // orionldState, orionldEntityMapCount #include "orionld/common/orionldError.h" // orionldError #include "orionld/kjTree/kjChildCount.h" // kjChildCount +#include "orionld/kjTree/kjEntityIdLookupInEntityArray.h" // kjEntityIdLookupInEntityArray #include "orionld/regCache/regCacheItemLookup.h" // regCacheItemLookup #include "orionld/forwarding/DistOp.h" // DistOp +#include "orionld/forwarding/distOpLookupById.h" // distOpLookupById #include "orionld/forwarding/distOpCreate.h" // distOpCreate #include "orionld/forwarding/distOpListDebug.h" // distOpListDebug #include "orionld/forwarding/distOpEntityMerge.h" // distOpEntityMerge @@ -117,16 +119,16 @@ DistOp* distOpLookup(const char* distOpId) // DistOpListItem* distOpListItemCreate(const char* distOpId, char* idString) { - DistOpListItem* itemP = (DistOpListItem*) kaAlloc(&orionldState.kalloc, sizeof(DistOpListItem)); + DistOp* distOpP = distOpLookupById(orionldDistOps, distOpId); + + if (distOpP == NULL) + LM_RE(NULL, ("Internal Error (unable to find the DistOp '%s'", distOpId)); + DistOpListItem* itemP = (DistOpListItem*) kaAlloc(&orionldState.kalloc, sizeof(DistOpListItem)); if (itemP == NULL) LM_X(1, ("Out of memory")); - itemP->distOpP = distOpLookup(distOpId); - - if (itemP->distOpP == NULL) - LM_RE(NULL, ("Internal Error (unable to find the DistOp '%s'", distOpId)); - + itemP->distOpP = distOpP; itemP->next = NULL; itemP->entityIds = idString; @@ -160,6 +162,12 @@ DistOpListItem* distOpListItemAdd(DistOpListItem* distOpList, const char* distOp // // queryResponse - // +// FIXME: +// I have a problem here with responses for requests forwarded due to Auxiliary Registrations. +// They can't be taken into account until AFTER all other responses have been dealt with, +// So, unless all other responses have been treated (merging entities), responses from Aux Regs must be delayed. +// They must be kept in a list and treated once no other responses are left. +// static int queryResponse(DistOp* distOpP, void* callbackParam) { LM_T(LmtSR, ("Got a response. status code: %d. body: '%s'", distOpP->httpResponseCode, distOpP->rawResponse)); @@ -169,7 +177,7 @@ static int queryResponse(DistOp* distOpP, void* callbackParam) if ((distOpP->httpResponseCode == 200) && (distOpP->responseBody != NULL)) { LM_T(LmtSR, ("Got a body from endpoint registered in reg '%s'", distOpP->regP->regId)); - LM_T(LmtSR, ("Must merge these new entities with the once already received")); + LM_T(LmtSR, ("Must merge these new entities with the ones already received")); KjNode* entityP = distOpP->responseBody->value.firstChildP; KjNode* next; @@ -177,7 +185,33 @@ static int queryResponse(DistOp* distOpP, void* callbackParam) { next = entityP->next; kjChildRemove(distOpP->responseBody, entityP); - distOpEntityMerge(entityArray, entityP); + + // Lookup the entity in entityArray and: + // - Add entityP if not found in entityArray + // - Merge the two if found in entityArray + // + KjNode* entityIdNodeP = kjLookup(entityP, "id"); + + if (entityIdNodeP != NULL) + { + char* entityId = entityIdNodeP->value.s; + KjNode* baseEntityP = kjEntityIdLookupInEntityArray(entityArray, entityId); + + if (baseEntityP == NULL) + { + LM_T(LmtDistOpMerge, ("New Entity '%s' - adding it to the entity array", entityId)); + kjChildAdd(entityArray, entityP); + } + else + { + bool auxiliary = distOpP->regP->mode == RegModeAuxiliary; + LM_T(LmtDistOpMerge, ("Existing Entity '%s' - merging it in the entity array (reg-mode: %s)", entityId, registrationModeToString(distOpP->regP->mode))); + distOpEntityMerge(baseEntityP, entityP, orionldState.uriParamOptions.sysAttrs, auxiliary); + } + } + else + LM_W(("No Entity ID in response from forwarded GET /entities request (reg %s)", distOpP->regP->regId)); + entityP = next; } } @@ -261,15 +295,19 @@ static void distOpQueryRequest(DistOpListItem* distOpList, KjNode* entityArray) // static void cleanupSysAttrs(void) { + LM_T(LmtSR, ("In cleanupSysAttrs: orionldState.responseTree: %p", orionldState.responseTree)); + for (KjNode* entityP = orionldState.responseTree->value.firstChildP; entityP != NULL; entityP = entityP->next) { KjNode* attrP = entityP->value.firstChildP; KjNode* nextAttrP; + kjTreeLog(entityP, "Entity", LmtSR); while (attrP != NULL) { nextAttrP = attrP->next; + LM_T(LmtSR, ("attrP->name: '%s'", attrP->name)); if (strcmp(attrP->name, "createdAt") == 0) kjChildRemove(entityP, attrP); else if (strcmp(attrP->name, "modifiedAt") == 0) kjChildRemove(entityP, attrP); else if (attrP->type == KjObject) @@ -307,6 +345,7 @@ bool orionldGetEntitiesPage(void) int limit = orionldState.uriParams.limit; KjNode* entityArray = kjArray(orionldState.kjsonP, NULL); + LM_T(LmtDistOpResponseDetail, ("entityArray at %p", entityArray)); LM_T(LmtEntityMap, ("entity map: '%s'", orionldEntityMapId)); LM_T(LmtEntityMap, ("items in entity map: %d", orionldEntityMapCount)); @@ -315,6 +354,7 @@ bool orionldGetEntitiesPage(void) // HTTP Status code and payload body orionldState.responseTree = entityArray; + LM_T(LmtSR, ("orionldState.responseTree: %p", orionldState.responseTree)); orionldState.httpStatusCode = 200; if (orionldState.uriParams.count == true) @@ -356,7 +396,7 @@ bool orionldGetEntitiesPage(void) // { // "urn:reg1": [ "urn:E1", ... "urn:En" ], // "urn:reg2": [ "urn:E1", ... "urn:En" ], - // "local": [ "urn:E1", ... "urn:En" ] + // "@none": [ "urn:E1", ... "urn:En" ] // } // ] // @@ -373,7 +413,7 @@ bool orionldGetEntitiesPage(void) for (KjNode* regP = entityMap->value.firstChildP; regP != NULL; regP = regP->next) { - const char* regId = (regP->type == KjString)? regP->value.s : "local"; + const char* regId = (regP->type == KjString)? regP->value.s : "@none"; KjNode* regArray = kjLookup(sources, regId); if (regArray == NULL) @@ -394,9 +434,9 @@ bool orionldGetEntitiesPage(void) DistOpListItem* distOpList = NULL; for (KjNode* sourceP = sources->value.firstChildP; sourceP != NULL; sourceP = sourceP->next) { - if (strcmp(sourceP->name, "local") == 0) + if (strcmp(sourceP->name, "@none") == 0) { - DistOp* distOpP = distOpLookup("local"); + DistOp* distOpP = distOpLookupById(orionldDistOps, "@none"); // Local query - set input params for orionldGetEntitiesLocal @@ -406,8 +446,26 @@ bool orionldGetEntitiesPage(void) // The type doesn't matter, we have a list of entity ids orionldState.in.typeList.items = 0; - // Set orionldState.in.attrList according to the entityMap creation request (that's filtering away attributes) - orionldState.uriParams.attrs = distOpP->attrsParam; +#if 0 + LM_T(LmtDistOpAttributes, ("------------ Local DB Query -------------")); + LM_T(LmtDistOpAttributes, ("orionldState.uriParams.attrs: %s", orionldState.uriParams.attrs)); + LM_T(LmtDistOpAttributes, ("orionldState.in.attrList.items: %d", orionldState.in.attrList.items)); + for (int ix = 0; ix < orionldState.in.attrList.items; ix++) + { + LM_T(LmtDistOpAttributes, ("orionldState.in.attrList.array[%d]: '%s'", ix, orionldState.in.attrList.array[ix])); + } + LM_T(LmtDistOpAttributes, ("distOpP->attrsParam: %s", distOpP->attrsParam)); + LM_T(LmtDistOpAttributes, ("distOpP->attrList: %p", distOpP->attrList)); + + if (distOpP->attrList != NULL) + { + LM_T(LmtDistOpAttributes, ("distOpP->attrList->items: %d", distOpP->attrList->items)); + for (int ix = 0; ix < distOpP->attrList->items; ix++) + { + LM_T(LmtDistOpAttributes, ("distOpP->attrList->array[%d]: '%s'", ix, distOpP->attrList->array[ix])); + } + } +#endif // Set orionldState.in.geometryPropertyExpanded according to the entityMap creation request (that's modifying the response) orionldState.in.geometryPropertyExpanded = NULL; // FIXME: fix @@ -415,6 +473,8 @@ bool orionldGetEntitiesPage(void) // Set orionldState.in.idList according to the entities in the entityMap idListFix(sourceP); + // Use orionldState.in.attrList and not distOpP->attrList for local requests + // No paging here orionldState.uriParams.offset = 0; orionldState.uriParams.limit = orionldState.in.idList.items; @@ -422,7 +482,7 @@ bool orionldGetEntitiesPage(void) LM_T(LmtEntityMap, ("Query local database for %d entities", orionldState.in.idList.items)); orionldGetEntitiesLocal(distOpP->typeList, distOpP->idList, - distOpP->attrList, + &orionldState.in.attrList, NULL, distOpP->qNode, &distOpP->geoInfo, @@ -433,9 +493,10 @@ bool orionldGetEntitiesPage(void) true); // Response comes in orionldState.responseTree - move those to entityArray - kjTreeLog(orionldState.responseTree, "orionldState.responseTree", LmtEntityMapDetail); + kjTreeLog(orionldState.responseTree, "orionldState.responseTree", LmtDistOpResponseDetail); if ((orionldState.responseTree != NULL) && (orionldState.responseTree->value.firstChildP != NULL)) { + LM_T(LmtDistOpResponseDetail, ("Adding a 'distop-response-entity' to the entityArray")); orionldState.responseTree->lastChild->next = entityArray->value.firstChildP; entityArray->value.firstChildP = orionldState.responseTree->value.firstChildP; } @@ -478,6 +539,7 @@ bool orionldGetEntitiesPage(void) distOpQueryRequest(distOpList, entityArray); } + orionldState.responseTree = entityArray; // // Time to cleanup ... diff --git a/src/lib/orionld/serviceRoutines/orionldGetEntity.cpp b/src/lib/orionld/serviceRoutines/orionldGetEntity.cpp index 018fb1e4ec..50f06938f0 100644 --- a/src/lib/orionld/serviceRoutines/orionldGetEntity.cpp +++ b/src/lib/orionld/serviceRoutines/orionldGetEntity.cpp @@ -189,6 +189,7 @@ bool orionldGetEntity(void) // Send the forwarded request and await all responses if (distOpP->regP != NULL) { + LM_T(LmtDistOpAttributes, ("distOp::attrsParam: '%s'", distOpP->attrsParam)); if (distOpSend(distOpP, dateHeader, xff) == 0) { ++forwards; diff --git a/src/lib/orionld/serviceRoutines/orionldGetEntityMap.cpp b/src/lib/orionld/serviceRoutines/orionldGetEntityMap.cpp index cbacf6b4b9..b38144028e 100644 --- a/src/lib/orionld/serviceRoutines/orionldGetEntityMap.cpp +++ b/src/lib/orionld/serviceRoutines/orionldGetEntityMap.cpp @@ -64,10 +64,14 @@ bool orionldGetEntityMap(void) DistOp* distOpP = distOpLookupById(orionldDistOps, distOpId->value.s); if (distOpP == NULL) continue; - KjNode* urlP = (distOpP->regP->regTree != NULL)? kjLookup(distOpP->regP->regTree, "endpoint") : NULL; + + KjNode* urlP = ((distOpP->regP != NULL) && (distOpP->regP->regTree != NULL))? kjLookup(distOpP->regP->regTree, "endpoint") : NULL; if (urlP != NULL) distOpId->value.s = urlP->value.s; + else + distOpId->value.s = (char*) "@none"; } + kjStringArraySort(eArray); } diff --git a/src/lib/orionld/types/CMakeLists.txt b/src/lib/orionld/types/CMakeLists.txt index d30a01bd6a..622d6e5760 100644 --- a/src/lib/orionld/types/CMakeLists.txt +++ b/src/lib/orionld/types/CMakeLists.txt @@ -31,6 +31,7 @@ SET (SOURCES OrionldResponseErrorType.cpp RegistrationMode.cpp Protocol.cpp + StringArray.cpp ) # Include directories diff --git a/src/lib/orionld/types/StringArray.cpp b/src/lib/orionld/types/StringArray.cpp new file mode 100644 index 0000000000..53f70599de --- /dev/null +++ b/src/lib/orionld/types/StringArray.cpp @@ -0,0 +1,53 @@ +/* +* +* Copyright 2023 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 "kalloc/kaAlloc.h" // kaAlloc +#include "kalloc/kaStrdup.h" // kaStrdup +} + +#include "orionld/common/orionldState.h" // orionldState +#include "orionld/types/StringArray.h" // Own interface + + + +// ----------------------------------------------------------------------------- +// +// stringArrayClone - +// +StringArray* stringArrayClone(StringArray* saP) +{ + StringArray* clone = (StringArray*) kaAlloc(&orionldState.kalloc, sizeof(StringArray)); + + clone->items = saP->items; + clone->array = (char**) kaAlloc(&orionldState.kalloc, saP->items * sizeof(char*)); + + for (int ix = 0; ix < clone->items; ix++) + { + clone->array[ix] = kaStrdup(&orionldState.kalloc, saP->array[ix]); + } + + return clone; +} diff --git a/src/lib/orionld/types/StringArray.h b/src/lib/orionld/types/StringArray.h index 932ac0a106..aaa87a3979 100644 --- a/src/lib/orionld/types/StringArray.h +++ b/src/lib/orionld/types/StringArray.h @@ -38,4 +38,13 @@ typedef struct StringArray char** array; } StringArray; + + + +// ----------------------------------------------------------------------------- +// +// stringArrayClone - +// +extern StringArray* stringArrayClone(StringArray* saP); + #endif // SRC_LIB_ORIONLD_TYPES_STRINGARRAY_H_ diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_entityMap-errors.test b/test/functionalTest/cases/0000_ngsild/ngsild_entityMap-errors.test index 757fc38364..1bef4d091c 100644 --- a/test/functionalTest/cases/0000_ngsild/ngsild_entityMap-errors.test +++ b/test/functionalTest/cases/0000_ngsild/ngsild_entityMap-errors.test @@ -26,7 +26,7 @@ Error handling for entity maps --SHELL-INIT-- dbInit CB dbInit CP1 -export CB_TRACELEVELS=${CB_TRACELEVELS:-70-79,80} +export CB_TRACELEVELS=${CB_TRACELEVELS:-70-79,110,200} orionldStart CB -experimental -forwarding orionldStart CP1 -experimental @@ -38,6 +38,8 @@ orionldStart CP1 -experimental # 04. Create an exclusive registration R1 on urn:E1/P1 for CP1 # 05. Query the CB with type=T, to get urn:E1 and the entity map (FIXME: shouldn't get one as all entities are returned in the very first query) # 06. Query the CB using the correct entity map but with offset=10 (we don't have that many entities in the map) +# +# Later: # 07. Query the CB with an entity map that doesn't exist (yes, again, but this time the broker has a valid entity map) # 08. Query the CB using the correct entity map AND with URL parameter 'id' - see error as the entities are already selected # 09. Query the CB using the correct entity map AND with URL parameter 'type' - see error as the entities are already selected @@ -167,11 +169,11 @@ Location: /ngsi-ld/v1/csourceRegistrations/urn:Reg1 05. Query the CB with type=T, to get urn:E1 and the entity map ============================================================== HTTP/1.1 200 OK -Content-Length: +Content-Length: 114 Content-Type: application/json Date: REGEX(.*) Entity-Map: urn:ngsi-ld:entity-map:REGEX(.*) -Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Link: ; rel="http:/ "P1": { "type": "Property", "value": "P1 in CP1" - } + }, "id": "urn:E1", "type": "T" } @@ -195,7 +197,7 @@ HTTP/1.1 200 OK Content-Length: 2 Content-Type: application/json Date: REGEX(.*) -Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" + +{ + "P1": { + "type": "Property", + "value": 1 + }, + "id": "urn:E1", + "type": "T" +} + + +04. Dump accumulator and see attrs=P1,P2 +======================================== +GET http://REGEX(.*)/ngsi-ld/v1/entities/urn:E1?attrs=P1,P2&options=sysAttrs&type=T +User-Agent: orionld/REGEX(.*) +Host: localhost:9997 +Accept: application/json +Date: REGEX(.*) +X-Forwarded-For: REGEX(.*) +======================================= + + +--TEARDOWN-- +brokerStop CB +accumulatorStop +dbDrop CB diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_entityMap_get.test b/test/functionalTest/cases/0000_ngsild/ngsild_entityMap_get.test index 523ecf1cb9..f12e2c6150 100644 --- a/test/functionalTest/cases/0000_ngsild/ngsild_entityMap_get.test +++ b/test/functionalTest/cases/0000_ngsild/ngsild_entityMap_get.test @@ -42,20 +42,20 @@ orionldStart CP4 -experimental # 03. In CP2, Create an entity urn:E1 with attributes P1-P3+R1 # 04. In CP3, Create an entity urn:E1 with attributes P1-P3+R1 # 05. In CP4, Create an entity urn:E1 with attributes P1-P4+R1+R4 (only P4 and R4 will be used) -# 06. Create an exclusive registration R1 on urn:E1/P1 for CP1 -# 07. Create a redirect registration R2 on urn:E1/P2 for CP2 -# 08. Create an inclusive registration R3 on T/P3 for CP3 -# 09. Create an auxiliar registration R4 on T for CP4 +# 06. Create an exclusive registration R1 on urn:E1/P1 for CP1 (on urn:E1 only) +# 07. Create a redirect registration R2 on urn:E1/P2 for CP2 (on urn:E1 only) +# 08. Create an inclusive registration R3 on T/P3 for CP3 (on type:T) +# 09. Create an auxiliar registration R4 on T for CP4 (on type:T) # 10. GET /entities, only to create the entityMap -# 11. GET /entityMap/* - see the entityMap with urn:E1 and its 4 registrations + URLs +# 11. GET /entityMaps/* - see the entityMap with urn:E1 and its 4 registrations + URLs # 12. In CB, create an entity urn:E2 # 13. In CP1, create an entity urn:E3 # 14. In CP2, Create an entity urn:E4 # 15. In CP3, Create an entity urn:E5 # 16. In CP4, Create an entity urn:E6 # 17. Delete the old entity map -# 18. GET /entities, only to create a new entityMap -# 19. GET /entityMap/* - see the entityMap with urn:E1 - urn:E5 +# 18. GET /entities, only to create a new entityMap (finding urn:E1, urn:E5) +# 19. GET /entityMaps/* - see the entityMap with urn:E1 - urn:E5 # echo "01. In CB, create an entity urn:E1 with attribute P0" @@ -237,9 +237,9 @@ echo echo -echo "11. GET /entityMap/* - see the entityMap with urn:E1 and its 4 registrations + URLs" -echo "===================================================================================" -orionCurl --url /ngsi-ld/v1/entityMap/$entityMap +echo "11. GET /entityMaps/* - see the entityMap with urn:E1 and its 4 registrations + URLs" +echo "====================================================================================" +orionCurl --url /ngsi-ld/v1/entityMaps/$entityMap echo echo @@ -306,7 +306,7 @@ echo echo "17. Delete the old entity map" echo "=============================" -orionCurl --url /ngsi-ld/v1/entityMap/$entityMap -X DELETE +orionCurl --url /ngsi-ld/v1/entityMaps/$entityMap -X DELETE echo echo @@ -319,9 +319,9 @@ echo echo -echo "19. GET /entityMap/* - see the entityMap with urn:E1 - urn:E5" -echo "=============================================================" -orionCurl --url /ngsi-ld/v1/entityMap/$entityMap +echo "19. GET /entityMaps/* - see the entityMap with urn:E1 - urn:E5" +echo "==============================================================" +orionCurl --url /ngsi-ld/v1/entityMaps/$entityMap echo echo @@ -421,15 +421,16 @@ NGSILD-Results-Count: 1 [] -11. GET /entityMap/* - see the entityMap with urn:E1 and its 4 registrations + URLs -=================================================================================== +11. GET /entityMaps/* - see the entityMap with urn:E1 and its 4 registrations + URLs +==================================================================================== HTTP/1.1 200 OK -Content-Length: 108 +Content-Length: 116 Content-Type: application/json Date: REGEX(.*) { "urn:E1": [ + "@none", "http://localhost:9801", "http://localhost:9802", "http://localhost:9803", @@ -504,22 +505,23 @@ NGSILD-Results-Count: 3 [] -19. GET /entityMap/* - see the entityMap with urn:E1 - urn:E5 -============================================================= +19. GET /entityMaps/* - see the entityMap with urn:E1 - urn:E5 +============================================================== HTTP/1.1 200 OK -Content-Length: 178 +Content-Length: 170 Content-Type: application/json Date: REGEX(.*) { "urn:E1": [ + "@none", "http://localhost:9801", "http://localhost:9802", "http://localhost:9803", "http://localhost:9804" ], - "urn:E5": [ - "http://localhost:9803" + "urn:E2": [ + "@none" ], "urn:E6": [ "http://localhost:9804" diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_forward_get_entities-entity-split-over-many-brokers.test b/test/functionalTest/cases/0000_ngsild/ngsild_forward_get_entities-entity-split-over-many-brokers.test index 9749ccf2dd..cde70220a2 100644 --- a/test/functionalTest/cases/0000_ngsild/ngsild_forward_get_entities-entity-split-over-many-brokers.test +++ b/test/functionalTest/cases/0000_ngsild/ngsild_forward_get_entities-entity-split-over-many-brokers.test @@ -60,7 +60,6 @@ orionCurl --url /ngsi-ld/v1/entities --payload "$payload" echo echo - echo "02. In CP1, create an entity urn:E1 with attributes P1-P3+R1" echo "============================================================" payload='{ @@ -213,7 +212,7 @@ payload='{ ], "mode": "auxiliary", "operations": [ "queryEntity" ], - "endpoint": "http://localhost:'$CP1_PORT'" + "endpoint": "http://localhost:'$CP4_PORT'" }' orionCurl --url /ngsi-ld/v1/csourceRegistrations --payload "$payload" echo @@ -312,17 +311,46 @@ Location: /ngsi-ld/v1/csourceRegistrations/urn:Reg4 10. GET /entities - see all properties P1-P4, each from a different broker, and relationships R1+R4 from CP4 ============================================================================================================ HTTP/1.1 200 OK -Content-Length: +Content-Length: 351 Content-Type: application/json Date: REGEX(.*) Entity-Map: urn:ngsi-ld:entity-map:REGEX(.*) -Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Link: ; rel="http:/ "id": "urn:cp3:entities:E39", "type": "T" } +#SORT_END ] diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_entityMap.test b/test/functionalTest/cases/0000_ngsild/ngsild_new_GET_entities-with-entityMap.test similarity index 89% rename from test/functionalTest/cases/0000_ngsild/ngsild_entityMap.test rename to test/functionalTest/cases/0000_ngsild/ngsild_new_GET_entities-with-entityMap.test index b1939b62c6..3ba1fe2d01 100644 --- a/test/functionalTest/cases/0000_ngsild/ngsild_entityMap.test +++ b/test/functionalTest/cases/0000_ngsild/ngsild_new_GET_entities-with-entityMap.test @@ -38,7 +38,7 @@ orionldStart CP1 -experimental # 03. In CP1, create an entity urn:E1 with attributes P1+P2+R1 # 04. In CP1, create an entity urn:E2 with attributes P1+P2+R1 # 05. Create an inclusive registration R1 on urn:E1/P1+R1 for CP1 -# 06. Create an inclusive registration R1 on urn:E2/P1+R1 for CP1 +# 06. Create an inclusive registration R2 on urn:E2/P1+R1 for CP1 # 07. Query the CB with type=T, to get urn:E1+urn:E2 and the entity map # 08. Query the CB with attrs=P1,P2 - see only P1, as P2 isn't registered # @@ -101,7 +101,7 @@ echo echo "05. Create an inclusive registration R1 on urn:E1/P1+R1 for CP1" echo "===============================================================" payload='{ - "id": "urn:Reg1", + "id": "urn:R1", "type": "ContextSourceRegistration", "information": [ { @@ -124,10 +124,10 @@ echo echo -echo "06. Create an inclusive registration R1 on urn:E1/P1+R1 for CP1" +echo "06. Create an inclusive registration R2 on urn:E1/P1+R1 for CP1" echo "===============================================================" payload='{ - "id": "urn:Reg2", + "id": "urn:R2", "type": "ContextSourceRegistration", "information": [ { @@ -207,27 +207,27 @@ Location: /ngsi-ld/v1/entities/urn:E2 HTTP/1.1 201 Created Content-Length: 0 Date: REGEX(.*) -Location: /ngsi-ld/v1/csourceRegistrations/urn:Reg1 +Location: /ngsi-ld/v1/csourceRegistrations/urn:R1 -06. Create an inclusive registration R1 on urn:E1/P1+R1 for CP1 +06. Create an inclusive registration R2 on urn:E1/P1+R1 for CP1 =============================================================== HTTP/1.1 201 Created Content-Length: 0 Date: REGEX(.*) -Location: /ngsi-ld/v1/csourceRegistrations/urn:Reg2 +Location: /ngsi-ld/v1/csourceRegistrations/urn:R2 07. Query the CB with type=T, to get urn:E1+urn:E2 and the entity map ===================================================================== HTTP/1.1 200 OK -Content-Length: +Content-Length: 376 Content-Type: application/json Date: REGEX(.*) Entity-Map: urn:ngsi-ld:entity-map:REGEX(.*) -Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Link: ; rel="http:/ "type": "Property", "value": "P1 in CP1" }, - "P2": { - "type": "Property", - "value": "P2 in CP1" - }, "P3": { "type": "Property", "value": "In CB" @@ -257,7 +253,7 @@ Link: ; rel="http:/ }, "P2": { "type": "Property", - "value": "P2 in CP1" + "value": "In CB" }, "R1": { "object": "urn:in:cp1", @@ -276,11 +272,32 @@ Link: ; rel="http:/ 08. Query the CB with attrs=P1,P2 - see only P1, as P2 isn't registered ======================================================================= HTTP/1.1 200 OK -Content-Length: +Content-Length: 186 Content-Type: application/json Date: REGEX(.*) +Link: