From 84ee8b95ae6c3a0fd824cc8b7fdad13203248cf8 Mon Sep 17 00:00:00 2001 From: Ken Zangelin Date: Tue, 13 Apr 2021 10:03:55 +0200 Subject: [PATCH 1/2] Implemented part 1 of GET /types (from local entities only - from registrations still missing) --- src/app/orionld/orionldRestServices.cpp | 2 + src/lib/orionld/db/CMakeLists.txt | 1 + src/lib/orionld/db/dbEntityAttributesGet.cpp | 193 ++++++++++++++++++ src/lib/orionld/db/dbEntityAttributesGet.h | 44 ++++ src/lib/orionld/db/dbEntityTypesGet.cpp | 2 +- src/lib/orionld/rest/orionldServiceInit.cpp | 7 + .../orionld/serviceRoutines/CMakeLists.txt | 1 + .../orionldGetEntityAttributes.cpp | 60 ++++++ .../orionldGetEntityAttributes.h | 40 ++++ .../orionld/types/OrionldProblemDetails.cpp | 7 +- .../0000_ngsild/ngsild_entity_attributes.test | 184 +++++++++++++++++ .../ngsild_get_attributes_501.test | 8 +- 12 files changed, 542 insertions(+), 7 deletions(-) create mode 100644 src/lib/orionld/db/dbEntityAttributesGet.cpp create mode 100644 src/lib/orionld/db/dbEntityAttributesGet.h create mode 100644 src/lib/orionld/serviceRoutines/orionldGetEntityAttributes.cpp create mode 100644 src/lib/orionld/serviceRoutines/orionldGetEntityAttributes.h create mode 100644 test/functionalTest/cases/0000_ngsild/ngsild_entity_attributes.test diff --git a/src/app/orionld/orionldRestServices.cpp b/src/app/orionld/orionldRestServices.cpp index 696063ff81..5a6c483723 100644 --- a/src/app/orionld/orionldRestServices.cpp +++ b/src/app/orionld/orionldRestServices.cpp @@ -51,6 +51,7 @@ #include "orionld/serviceRoutines/orionldPostBatchUpdate.h" #include "orionld/serviceRoutines/orionldGetEntityTypes.h" #include "orionld/serviceRoutines/orionldGetEntityType.h" +#include "orionld/serviceRoutines/orionldGetEntityAttributes.h" #include "orionld/serviceRoutines/orionldGetTenants.h" #include "orionld/serviceRoutines/orionldGetDbIndexes.h" #include "orionld/serviceRoutines/orionldPostQuery.h" @@ -73,6 +74,7 @@ static OrionLdRestServiceSimplified getServiceV[] = { "/ngsi-ld/v1/entities", orionldGetEntities }, { "/ngsi-ld/v1/types/*", orionldGetEntityType }, { "/ngsi-ld/v1/types", orionldGetEntityTypes }, + { "/ngsi-ld/v1/attributes", orionldGetEntityAttributes }, { "/ngsi-ld/v1/subscriptions/*", orionldGetSubscription }, { "/ngsi-ld/v1/subscriptions", orionldGetSubscriptions }, { "/ngsi-ld/v1/csourceRegistrations/*", orionldGetRegistration }, diff --git a/src/lib/orionld/db/CMakeLists.txt b/src/lib/orionld/db/CMakeLists.txt index 4af0729f08..7eddeaef99 100644 --- a/src/lib/orionld/db/CMakeLists.txt +++ b/src/lib/orionld/db/CMakeLists.txt @@ -26,6 +26,7 @@ SET (SOURCES dbCollectionPathGet.cpp dbConfiguration.cpp dbEntityTypesGet.cpp + dbEntityAttributesGet.cpp dbGeoIndexAdd.cpp dbGeoIndexLookup.cpp ) diff --git a/src/lib/orionld/db/dbEntityAttributesGet.cpp b/src/lib/orionld/db/dbEntityAttributesGet.cpp new file mode 100644 index 0000000000..9dcf233284 --- /dev/null +++ b/src/lib/orionld/db/dbEntityAttributesGet.cpp @@ -0,0 +1,193 @@ +/* +* +* Copyright 2021 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/kjBuilder.h" // kjArray, kjObject +#include "kjson/kjLookup.h" // kjLookup +#include "kjson/kjClone.h" // kjClone +#include "kjson/kjRender.h" // kjFastRender +} + +#include "logMsg/logMsg.h" // LM_* +#include "logMsg/traceLevels.h" // Lmt* + +#include "orionld/types/OrionldProblemDetails.h" // OrionldProblemDetails, orionldProblemDetailsFill +#include "orionld/common/orionldState.h" // orionldState +#include "orionld/common/uuidGenerate.h" // uuidGenerate +#include "orionld/common/orionldErrorResponse.h" // orionldErrorResponseCreate +#include "orionld/context/orionldContextItemAliasLookup.h" // orionldContextItemAliasLookup +#include "orionld/db/dbConfiguration.h" // dbEntityAttributesFromRegistrationsGet, dbEntitiesGet +#include "orionld/db/dbEntityAttributesGet.h" // Own interface + + +extern KjNode* kjArrayStringLookup(KjNode* stringArray, const char* str); // FIXME: move to kjson lib +extern void kjStringArraySortedInsert(KjNode* array, KjNode* newItemP); // FIXME: move to kjson lib + + + +// ----------------------------------------------------------------------------- +// +// getEntityAttributesResponse - All entity attributes for which entity instances are currently available in the NGSI-LD system. +// +static KjNode* getEntityAttributesResponse(KjNode* sortedArrayP) +{ + char entityAttributesId[128]; + + strncpy(entityAttributesId, "urn:ngsi-ld:EntityAttributeList:", sizeof(entityAttributesId)); + uuidGenerate(&entityAttributesId[32], sizeof(entityAttributesId) - 32, false); + + KjNode* attributeNodeResponseP = kjObject(orionldState.kjsonP, NULL); + KjNode* idNodeP = kjString(orionldState.kjsonP, "id", entityAttributesId); + KjNode* typeNodeP = kjString(orionldState.kjsonP, "type", "EntityAttributeList"); + + kjChildAdd(attributeNodeResponseP, idNodeP); + kjChildAdd(attributeNodeResponseP, typeNodeP); + kjChildAdd(attributeNodeResponseP, sortedArrayP); + + return attributeNodeResponseP; +} + + + +// ---------------------------------------------------------------------------- +// +// attrNamesExtract - +// +// PARAMETERS +// - outArray: The result of the operation +// - local: The output from dbEntitiesGet(attrNames), which is an array of the attrNames field of matching entities, e.g.: +// [ +// { "attrNames": ["https://uri.etsi.org/ngsi-ld/default-context/P1","https://uri.etsi.org/ngsi-ld/default-context/P2"] }, +// { "attrNames": ["https://uri.etsi.org/ngsi-ld/default-context/P2","https://uri.etsi.org/ngsi-ld/default-context/R1"] }, +// ] +// +// What we need to do now is to extract all "attrNames" from the objects in the array and +// - loop over the attribute names +// - lookup the alias +// - sorted insert into a new array - the output array (first lookup to we have no duplicates) +// +static void attrNamesExtract(KjNode* outArray, KjNode* local) +{ + for (KjNode* objP = local->value.firstChildP; objP != NULL; objP = objP->next) + { + KjNode* attrNamesP = kjLookup(objP, "attrNames"); + + if (attrNamesP == NULL) + { + LM_E(("Database Error (entity:attrNames not present in DB)")); + continue; + } + + if (attrNamesP->type != KjArray) + { + LM_E(("Database Error (entity:attrNames present but not an Array: '%s')", kjValueType(attrNamesP->type))); + continue; + } + + KjNode* aP = attrNamesP->value.firstChildP; + KjNode* next; + + while (aP != NULL) + { + next = aP->next; + + if (aP->type != KjString) + { + LM_E(("Database Error (entity:attrNames item is not a String (it is of type '%s')", kjValueType(aP->type))); + aP = next; + continue; + } + + aP->value.s = orionldContextItemAliasLookup(orionldState.contextP, aP->value.s, NULL, NULL); + + if (kjArrayStringLookup(outArray, aP->value.s) == NULL) + { + kjChildRemove(objP, aP); + kjStringArraySortedInsert(outArray, aP); + } + + aP = next; + } + } +} + + + +// ----------------------------------------------------------------------------- +// +// dbEntityAttributesGetWithoutDetails - +// +static KjNode* dbEntityAttributesGetWithoutDetails(OrionldProblemDetails* pdP) +{ + KjNode* localEntityArray; + char* fields[1] = { (char*) "attrNames" }; + + // + // GET local attributes - i.e. from the "entities" collection + // + localEntityArray = dbEntitiesGet(fields, 1); + + KjNode* outArray = kjArray(orionldState.kjsonP, "attributeList"); + + if (localEntityArray != NULL) + attrNamesExtract(outArray, localEntityArray); + else + { + } + + return getEntityAttributesResponse(outArray); +} + + + +// ----------------------------------------------------------------------------- +// +// dbEntityAttributesGetWithDetails - +// +static KjNode* dbEntityAttributesGetWithDetails(OrionldProblemDetails* pdP) +{ + orionldProblemDetailsFill(pdP, OrionldOperationNotSupported, "Not Implemented", "GET /ngsi-ld/v1/attributes?details=true", 501); + orionldErrorResponseCreate(OrionldOperationNotSupported, pdP->title, pdP->detail); + orionldState.noLinkHeader = true; // We don't want the Link header for non-implemented requests + + return orionldState.responseTree; +} + + + +// ---------------------------------------------------------------------------- +// +// dbEntityAttributesGet - +// +KjNode* dbEntityAttributesGet(OrionldProblemDetails* pdP) +{ + if (orionldState.uriParams.details == false) + return dbEntityAttributesGetWithoutDetails(pdP); + else + return dbEntityAttributesGetWithDetails(pdP); +} diff --git a/src/lib/orionld/db/dbEntityAttributesGet.h b/src/lib/orionld/db/dbEntityAttributesGet.h new file mode 100644 index 0000000000..0f965d8cc9 --- /dev/null +++ b/src/lib/orionld/db/dbEntityAttributesGet.h @@ -0,0 +1,44 @@ +#ifndef SRC_LIB_ORIONLD_DB_DBENTITYATTRIBUTESGET_H_ +#define SRC_LIB_ORIONLD_DB_DBENTITYATTRIBUTESGET_H_ + +/* +* +* Copyright 2019 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 +} + +#include "orionld/types/OrionldProblemDetails.h" // OrionldProblemDetails + + + +// ----------------------------------------------------------------------------- +// +// dbEntityAttributesGet - +// +extern KjNode* dbEntityAttributesGet(OrionldProblemDetails* pdP); + +#endif // SRC_LIB_ORIONLD_DB_DBENTITYATTRIBUTESGET_H_ diff --git a/src/lib/orionld/db/dbEntityTypesGet.cpp b/src/lib/orionld/db/dbEntityTypesGet.cpp index 398522236b..2195b4d8a5 100644 --- a/src/lib/orionld/db/dbEntityTypesGet.cpp +++ b/src/lib/orionld/db/dbEntityTypesGet.cpp @@ -65,7 +65,7 @@ KjNode* kjArrayStringLookup(KjNode* stringArray, const char* str) // // kjStringArraySortedInsert - // -static void kjStringArraySortedInsert(KjNode* array, KjNode* newItemP) +void kjStringArraySortedInsert(KjNode* array, KjNode* newItemP) { KjNode* prev = NULL; KjNode* itemP = array->value.firstChildP; diff --git a/src/lib/orionld/rest/orionldServiceInit.cpp b/src/lib/orionld/rest/orionldServiceInit.cpp index b8c7f10c04..cc0233a5f1 100644 --- a/src/lib/orionld/rest/orionldServiceInit.cpp +++ b/src/lib/orionld/rest/orionldServiceInit.cpp @@ -79,6 +79,7 @@ extern "C" #include "orionld/serviceRoutines/orionldPatchSubscription.h" // orionldPatchSubscription #include "orionld/serviceRoutines/orionldDeleteSubscription.h" // orionldDeleteSubscription #include "orionld/serviceRoutines/orionldGetEntityTypes.h" // orionldGetEntityTypes +#include "orionld/serviceRoutines/orionldGetEntityAttributes.h" // orionldGetEntityAttributes #include "orionld/troe/troePostEntities.h" // troePostEntities #include "orionld/troe/troePostBatchDelete.h" // troePostBatchDelete #include "orionld/troe/troeDeleteAttribute.h" // troeDeleteAttribute @@ -396,6 +397,12 @@ static void restServicePrepare(OrionLdRestService* serviceP, OrionLdRestServiceS serviceP->options |= ORIONLD_SERVICE_OPTION_NO_V2_URI_PARAMS; } + else if (serviceP->serviceRoutine == orionldGetEntityAttributes) + { + serviceP->uriParams |= ORIONLD_URIPARAM_DETAILS; + + serviceP->options |= ORIONLD_SERVICE_OPTION_NO_V2_URI_PARAMS; + } else if (serviceP->serviceRoutine == orionldGetVersion) { serviceP->options = 0; // Tenant is Ignored diff --git a/src/lib/orionld/serviceRoutines/CMakeLists.txt b/src/lib/orionld/serviceRoutines/CMakeLists.txt index 52c971e722..a0e9948034 100644 --- a/src/lib/orionld/serviceRoutines/CMakeLists.txt +++ b/src/lib/orionld/serviceRoutines/CMakeLists.txt @@ -57,6 +57,7 @@ SET (SOURCES orionldGetTemporalEntities.cpp orionldGetTemporalEntity.cpp orionldPostTemporalQuery.cpp + orionldGetEntityAttributes.cpp ) # Include directories diff --git a/src/lib/orionld/serviceRoutines/orionldGetEntityAttributes.cpp b/src/lib/orionld/serviceRoutines/orionldGetEntityAttributes.cpp new file mode 100644 index 0000000000..c727966525 --- /dev/null +++ b/src/lib/orionld/serviceRoutines/orionldGetEntityAttributes.cpp @@ -0,0 +1,60 @@ +/* +* +* Copyright 2021 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 +} + +#include "logMsg/logMsg.h" // LM_* +#include "logMsg/traceLevels.h" // Lmt* + +#include "rest/ConnectionInfo.h" // ConnectionInfo + +#include "orionld/common/orionldState.h" // orionldState +#include "orionld/common/orionldErrorResponse.h" // orionldErrorResponseCreate +#include "orionld/types/OrionldProblemDetails.h" // OrionldProblemDetails +#include "orionld/db/dbEntityAttributesGet.h" // dbEntityAttributesGet +#include "orionld/serviceRoutines/orionldGetEntityTypes.h" // Own Interface + + + +// ---------------------------------------------------------------------------- +// +// orionldGetEntityAttributes - +// +bool orionldGetEntityAttributes(ConnectionInfo* ciP) +{ + OrionldProblemDetails pd; + + orionldState.responseTree = dbEntityAttributesGet(&pd); + if (orionldState.responseTree == NULL) + { + // dbEntityAttributesGet calls orionldErrorResponseCreate + LM_E(("dbEntityAttributesGet: %s: %s", pd.title, pd.detail)); + return false; + } + + return true; +} diff --git a/src/lib/orionld/serviceRoutines/orionldGetEntityAttributes.h b/src/lib/orionld/serviceRoutines/orionldGetEntityAttributes.h new file mode 100644 index 0000000000..be6d33547a --- /dev/null +++ b/src/lib/orionld/serviceRoutines/orionldGetEntityAttributes.h @@ -0,0 +1,40 @@ +#ifndef SRC_LIB_ORIONLD_SERVICEROUTINES_ORIONLDGETENTITYATTRIBUTES_H_ +#define SRC_LIB_ORIONLD_SERVICEROUTINES_ORIONLDGETENTITYATTRIBUTES_H_ + +/* +* +* Copyright 2018 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 "logMsg/logMsg.h" + +#include "rest/ConnectionInfo.h" + + + +// ---------------------------------------------------------------------------- +// +// orionldGetEntityAttributes - +// +extern bool orionldGetEntityAttributes(ConnectionInfo* ciP); + +#endif // SRC_LIB_ORIONLD_SERVICEROUTINES_ORIONLDGETENTITYATTRIBUTES_H_ diff --git a/src/lib/orionld/types/OrionldProblemDetails.cpp b/src/lib/orionld/types/OrionldProblemDetails.cpp index 85cf2010d4..b354f2c959 100644 --- a/src/lib/orionld/types/OrionldProblemDetails.cpp +++ b/src/lib/orionld/types/OrionldProblemDetails.cpp @@ -22,8 +22,9 @@ * * Author: Ken Zangelin */ -#include "orionld/types/OrionldResponseErrorType.h" // OrionldResponseErrorType -#include "orionld/types/OrionldProblemDetails.h" // Own interface +#include "orionld/common/orionldState.h" // orionldState +#include "orionld/types/OrionldResponseErrorType.h" // OrionldResponseErrorType +#include "orionld/types/OrionldProblemDetails.h" // Own interface @@ -44,4 +45,6 @@ void orionldProblemDetailsFill pdP->title = (char*) title; pdP->detail = (char*) detail; pdP->status = status; + + orionldState.httpStatusCode = status; } diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_entity_attributes.test b/test/functionalTest/cases/0000_ngsild/ngsild_entity_attributes.test new file mode 100644 index 0000000000..148b2214ff --- /dev/null +++ b/test/functionalTest/cases/0000_ngsild/ngsild_entity_attributes.test @@ -0,0 +1,184 @@ +# Copyright 2021 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 + +# VALGRIND_READY - to mark the test ready for valgrindTestSuite.sh + +--NAME-- +Entity Attributes - simple test without collisions + +--SHELL-INIT-- +export BROKER=orionld +dbInit CB +brokerStart CB + +--SHELL-- + +# +# 01. GET Entity Attributes - see empty array +# 02. Create an Entity E0 with three attributes: P1, P2, and R1 +# 03. GET Entity Types - see three attributes +# 04. Create an Entity E1 with three attributes: P1, P3, and R1 (P1 and R1 already exist in E0) +# 05. GET Entity Types - see four attributes (P1, P2, P3, and R1) +# + +echo "01. GET Entity Attributes - see empty array" +echo "===========================================" +orionCurl --url "/ngsi-ld/v1/attributes?prettyPrint=yes" --noPayloadCheck +echo +echo + + +echo "02. Create an Entity E0 with three attributes: P1, P2, and R1" +echo "=============================================================" +payload='{ + "id": "urn:ngsi-ld:entities:E0", + "type": "T", + "P1": { + "type": "Property", + "value": 1 + }, + "P2": { + "type": "Property", + "value": 1 + }, + "R1": { + "type": "Relationship", + "object": "urn:ngsu-ld:entities:E1" + } +}' +orionCurl --url /ngsi-ld/v1/entities --payload "$payload" +echo +echo + + +echo "03. GET Entity Types - see three attributes" +echo "===========================================" +orionCurl --url /ngsi-ld/v1/attributes +echo +echo + + +echo "04. Create an Entity E1 with three attributes: P1, P3, and R1 (P1 and R1 already exist in E0)" +echo "=============================================================================================" +payload='{ + "id": "urn:ngsi-ld:entities:E1", + "type": "T", + "P1": { + "type": "Property", + "value": 1 + }, + "P3": { + "type": "Property", + "value": 1 + }, + "R1": { + "type": "Relationship", + "object": "urn:ngsu-ld:entities:E1" + } +}' +orionCurl --url /ngsi-ld/v1/entities --payload "$payload" +echo +echo + + +echo "05. GET Entity Types - see four attributes (P1, P2, P3, and R1)" +echo "===============================================================" +orionCurl --url /ngsi-ld/v1/attributes +echo +echo + + +--REGEXPECT-- +01. GET Entity Attributes - see empty array +=========================================== +HTTP/1.1 200 OK +Content-Length: 139 +Content-Type: application/json +Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Date: REGEX(.*) + +{ + "id": "urn:ngsi-ld:EntityAttributeList:REGEX(.*)", + "type": "EntityAttributeList", + "attributeList": [] +} + + + +02. Create an Entity E0 with three attributes: P1, P2, and R1 +============================================================= +HTTP/1.1 201 Created +Content-Length: 0 +Location: /ngsi-ld/v1/entities/urn:ngsi-ld:entities:E0 +Date: REGEX(.*) + + + +03. GET Entity Types - see three attributes +=========================================== +HTTP/1.1 200 OK +Content-Length: 139 +Content-Type: application/json +Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Date: REGEX(.*) + +{ + "attributeList": [ + "P1", + "P2", + "R1" + ], + "id": "urn:ngsi-ld:EntityAttributeList:REGEX(.*)", + "type": "EntityAttributeList" +} + + +04. Create an Entity E1 with three attributes: P1, P3, and R1 (P1 and R1 already exist in E0) +============================================================================================= +HTTP/1.1 201 Created +Content-Length: 0 +Location: /ngsi-ld/v1/entities/urn:ngsi-ld:entities:E1 +Date: REGEX(.*) + + + +05. GET Entity Types - see four attributes (P1, P2, P3, and R1) +=============================================================== +HTTP/1.1 200 OK +Content-Length: 144 +Content-Type: application/json +Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Date: REGEX(.*) + +{ + "attributeList": [ + "P1", + "P2", + "P3", + "R1" + ], + "id": "urn:ngsi-ld:EntityAttributeList:REGEX(.*)", + "type": "EntityAttributeList" +} + + +--TEARDOWN-- +brokerStop CB +dbDrop CB diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_get_attributes_501.test b/test/functionalTest/cases/0000_ngsild/ngsild_get_attributes_501.test index ee264fb5b9..a12446d1cd 100644 --- a/test/functionalTest/cases/0000_ngsild/ngsild_get_attributes_501.test +++ b/test/functionalTest/cases/0000_ngsild/ngsild_get_attributes_501.test @@ -31,13 +31,13 @@ brokerStart CB --SHELL-- # -# 01. Get 501 for GET /ngsi-ld/v1/attributes +# 01. Get 501 for GET /ngsi-ld/v1/attributes?details=true # 02. Get 501 for GET /ngsi-ld/v1/attributes/A1 # echo "01. Get 501 for GET /ngsi-ld/v1/attributes" echo "==========================================" -orionCurl --url /ngsi-ld/v1/attributes +orionCurl --url /ngsi-ld/v1/attributes?details=true echo echo @@ -53,12 +53,12 @@ echo 01. Get 501 for GET /ngsi-ld/v1/attributes ========================================== HTTP/1.1 501 Not Implemented -Content-Length: 128 +Content-Length: 145 Content-Type: application/json Date: REGEX(.*) { - "detail": "/ngsi-ld/v1/attributes", + "detail": "GET /ngsi-ld/v1/attributes?details=true", "title": "Not Implemented", "type": "https://uri.etsi.org/ngsi-ld/errors/OperationNotSupported" } From 372a17dc09a5fe3c2db98834e096e50f637f7741 Mon Sep 17 00:00:00 2001 From: Ken Zangelin Date: Tue, 13 Apr 2021 15:09:54 +0200 Subject: [PATCH 2/2] Implemented GET /attributes, but only without details=true --- CHANGES_NEXT_RELEASE | 1 + src/lib/orionld/db/dbConfiguration.h | 2 +- src/lib/orionld/db/dbEntityAttributesGet.cpp | 79 ++++- src/lib/orionld/db/dbEntityTypesGet.cpp | 2 +- ...pLegacyEntityTypesFromRegistrationsGet.cpp | 6 +- ...CppLegacyEntityTypesFromRegistrationsGet.h | 2 +- .../0000_ngsild/ngsild_entity_attributes.test | 269 +++++++++++++++++- 7 files changed, 336 insertions(+), 25 deletions(-) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index 4354eb7646..52965adb67 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -5,3 +5,4 @@ * Issue #280 NGSI-LD entity update requests now provoke notifications regardless on whether any actual change has been done on the entity * Issue #280 Implemented datasetId for PATCH /entities/{EID}/attrs/{attrName} * Issue #280 Implemented datasetId for DELETE /entities/{EID}/attrs/{attrName} (supporting URI params 'datasetId' and 'deleteAll') +* Issue #280 Implemented GET /attributes, but only without details=true diff --git a/src/lib/orionld/db/dbConfiguration.h b/src/lib/orionld/db/dbConfiguration.h index 2e246552d8..d6c72090c7 100644 --- a/src/lib/orionld/db/dbConfiguration.h +++ b/src/lib/orionld/db/dbConfiguration.h @@ -87,7 +87,7 @@ typedef bool (*DbSubscriptionDelete)(const char* subscriptionId); typedef KjNode* (*DbRegistrationGet)(const char* registrationId); typedef bool (*DbRegistrationReplace)(const char* registrationId, KjNode* dbRegistrationP); typedef KjNode* (*DbEntitiesGet)(char** fieldV, int fields); -typedef KjNode* (*DbEntityTypesFromRegistrationsGet)(void); +typedef KjNode* (*DbEntityTypesFromRegistrationsGet)(bool details); typedef bool (*DbGeoIndexCreate)(const char* tenant, const char* attrName); typedef bool (*DbIdIndexCreate)(const char* tenant); typedef KjNode* (*DbEntitiesQuery)(KjNode* entityInfoArrayP, KjNode* attrsP, QNode* qP, KjNode* geoqP, int limit, int offset, int* countP); diff --git a/src/lib/orionld/db/dbEntityAttributesGet.cpp b/src/lib/orionld/db/dbEntityAttributesGet.cpp index 9dcf233284..f672d842d1 100644 --- a/src/lib/orionld/db/dbEntityAttributesGet.cpp +++ b/src/lib/orionld/db/dbEntityAttributesGet.cpp @@ -76,7 +76,7 @@ static KjNode* getEntityAttributesResponse(KjNode* sortedArrayP) // ---------------------------------------------------------------------------- // -// attrNamesExtract - +// localAttrNamesExtract - // // PARAMETERS // - outArray: The result of the operation @@ -91,7 +91,7 @@ static KjNode* getEntityAttributesResponse(KjNode* sortedArrayP) // - lookup the alias // - sorted insert into a new array - the output array (first lookup to we have no duplicates) // -static void attrNamesExtract(KjNode* outArray, KjNode* local) +static void localAttrNamesExtract(KjNode* outArray, KjNode* local) { for (KjNode* objP = local->value.firstChildP; objP != NULL; objP = objP->next) { @@ -138,27 +138,88 @@ static void attrNamesExtract(KjNode* outArray, KjNode* local) +// ---------------------------------------------------------------------------- +// +// remoteAttrNamesExtract - +// +// PARAMETERS +// - outArray: The result of the operation +// - remote: The output from dbEntityTypesFromRegistrationsGet(details=true), which is an array of +// [ +// { +// "id": "urn:ngsi-ld:entity:E1", +// "type": "https://uri.etsi.org/ngsi-ld/default-context/T1", +// "attrs": ["https://uri.etsi.org/ngsi-ld/default-context/brandName", "https://uri.etsi.org/ngsi-ld/default-context/speed"] +// }, +// { +// "id": "urn:ngsi-ld:entity:E2", +// "type": "https://uri.etsi.org/ngsi-ld/default-context/T2", +// "attrs": ["https://uri.etsi.org/ngsi-ld/default-context/isParked"] +// } +// ] +// +// What we need to do now is to extract all strings in the "attrs" arrays of all the objects in the toplevel array +// - loop over the attribute names +// - lookup the alias +// - sorted insert into a new array - the output array (first lookup to we have no duplicates) +// +static void remoteAttrNamesExtract(KjNode* outArray, KjNode* remote) +{ + for (KjNode* objP = remote->value.firstChildP; objP != NULL; objP = objP->next) + { + KjNode* attrsArray = kjLookup(objP, "attrs"); + + if (attrsArray != NULL) + { + KjNode* attrNameNode = attrsArray->value.firstChildP; + KjNode* next; + + while (attrNameNode != NULL) + { + next = attrNameNode->next; + + attrNameNode->value.s = orionldContextItemAliasLookup(orionldState.contextP, attrNameNode->value.s, NULL, NULL); + + if (kjArrayStringLookup(outArray, attrNameNode->value.s) == NULL) + { + kjChildRemove(objP, attrNameNode); + kjStringArraySortedInsert(outArray, attrNameNode); + } + + attrNameNode = next; + } + } + } +} + + + // ----------------------------------------------------------------------------- // // dbEntityAttributesGetWithoutDetails - // static KjNode* dbEntityAttributesGetWithoutDetails(OrionldProblemDetails* pdP) { - KjNode* localEntityArray; - char* fields[1] = { (char*) "attrNames" }; - // // GET local attributes - i.e. from the "entities" collection // + KjNode* localEntityArray; + char* fields[1] = { (char*) "attrNames" }; + localEntityArray = dbEntitiesGet(fields, 1); KjNode* outArray = kjArray(orionldState.kjsonP, "attributeList"); if (localEntityArray != NULL) - attrNamesExtract(outArray, localEntityArray); - else - { - } + localAttrNamesExtract(outArray, localEntityArray); + + // + // GET external attributes - i.e. from the "registrations" collection + // + KjNode* remote = dbEntityTypesFromRegistrationsGet(true); + + if (remote) + remoteAttrNamesExtract(outArray, remote); return getEntityAttributesResponse(outArray); } diff --git a/src/lib/orionld/db/dbEntityTypesGet.cpp b/src/lib/orionld/db/dbEntityTypesGet.cpp index 2195b4d8a5..c6c8433da7 100644 --- a/src/lib/orionld/db/dbEntityTypesGet.cpp +++ b/src/lib/orionld/db/dbEntityTypesGet.cpp @@ -396,7 +396,7 @@ KjNode* dbEntityTypesGet(OrionldProblemDetails* pdP) // // GET remote types - i.e. from the "registrations" collection // - remote = dbEntityTypesFromRegistrationsGet(); + remote = dbEntityTypesFromRegistrationsGet(orionldState.uriParams.details); if ((remote != NULL) && (orionldState.uriParams.details == true)) remote = typesAndAttributesExtractFromRegistrations(remote); diff --git a/src/lib/orionld/mongoCppLegacy/mongoCppLegacyEntityTypesFromRegistrationsGet.cpp b/src/lib/orionld/mongoCppLegacy/mongoCppLegacyEntityTypesFromRegistrationsGet.cpp index 6f95648fec..cf4eba7232 100644 --- a/src/lib/orionld/mongoCppLegacy/mongoCppLegacyEntityTypesFromRegistrationsGet.cpp +++ b/src/lib/orionld/mongoCppLegacy/mongoCppLegacyEntityTypesFromRegistrationsGet.cpp @@ -180,7 +180,7 @@ void entitiesAndProprertiesExtract(KjNode* regArray, KjNode* typeArray) // ... // // -KjNode* mongoCppLegacyEntityTypesFromRegistrationsGet(void) +KjNode* mongoCppLegacyEntityTypesFromRegistrationsGet(bool details) { char collectionPath[256]; @@ -192,7 +192,7 @@ KjNode* mongoCppLegacyEntityTypesFromRegistrationsGet(void) fields.append("contextRegistration.entities", 1); // Entity Type is inside the 'contextRegistration.entities' field ... - if (orionldState.uriParams.details == true) + if (details == true) fields.append("contextRegistration.attrs", 1); fields.append("_id", 0); @@ -227,7 +227,7 @@ KjNode* mongoCppLegacyEntityTypesFromRegistrationsGet(void) if (regArray != NULL) { typeArray = kjArray(orionldState.kjsonP, NULL); - if (orionldState.uriParams.details == false) + if (details == false) typeExtract(regArray, typeArray); else entitiesAndProprertiesExtract(regArray, typeArray); diff --git a/src/lib/orionld/mongoCppLegacy/mongoCppLegacyEntityTypesFromRegistrationsGet.h b/src/lib/orionld/mongoCppLegacy/mongoCppLegacyEntityTypesFromRegistrationsGet.h index f1eba4463d..9ae13a05c6 100644 --- a/src/lib/orionld/mongoCppLegacy/mongoCppLegacyEntityTypesFromRegistrationsGet.h +++ b/src/lib/orionld/mongoCppLegacy/mongoCppLegacyEntityTypesFromRegistrationsGet.h @@ -39,6 +39,6 @@ extern "C" // // mongoCppLegacyEntityTypesFromRegistrationsGet - // -extern KjNode* mongoCppLegacyEntityTypesFromRegistrationsGet(void); +extern KjNode* mongoCppLegacyEntityTypesFromRegistrationsGet(bool details); #endif // SRC_LIB_ORIONLD_MONGOCPPLEGACY_MONGOCPPLEGACYENTITYTYPESFROMREGISTRATIONSGET_H_ diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_entity_attributes.test b/test/functionalTest/cases/0000_ngsild/ngsild_entity_attributes.test index 148b2214ff..f10fad0f73 100644 --- a/test/functionalTest/cases/0000_ngsild/ngsild_entity_attributes.test +++ b/test/functionalTest/cases/0000_ngsild/ngsild_entity_attributes.test @@ -33,9 +33,17 @@ brokerStart CB # # 01. GET Entity Attributes - see empty array # 02. Create an Entity E0 with three attributes: P1, P2, and R1 -# 03. GET Entity Types - see three attributes +# 03. GET Entity Attributes - see three attributes # 04. Create an Entity E1 with three attributes: P1, P3, and R1 (P1 and R1 already exist in E0) -# 05. GET Entity Types - see four attributes (P1, P2, P3, and R1) +# 05. GET Entity Attributes - see four attributes (P1, P2, P3, and R1) +# 06. Create a registration R1 without any attributes +# 07. GET Entity Attributes - see four attributes (P1, P2, P3, and R1) +# 08. Create a registration R2 with attributes P4 and R2 +# 09. GET Entity Attributes - see six attributes (P1-P4, and R1-R2) +# 10. Create a registration R3 with attributes P1-P5 and R1-R5 +# 11. GET Entity Attributes - see ten attributes (P1-P5, and R1-R5) +# 12. Remove R3, R1, E0 and E1 +# 13. GET Entity Attributes - see only P4 and R2 from R2 # echo "01. GET Entity Attributes - see empty array" @@ -68,8 +76,8 @@ echo echo -echo "03. GET Entity Types - see three attributes" -echo "===========================================" +echo "03. GET Entity Attributes - see three attributes" +echo "================================================" orionCurl --url /ngsi-ld/v1/attributes echo echo @@ -98,8 +106,120 @@ echo echo -echo "05. GET Entity Types - see four attributes (P1, P2, P3, and R1)" -echo "===============================================================" +echo "05. GET Entity Attributes - see four attributes (P1, P2, P3, and R1)" +echo "====================================================================" +orionCurl --url /ngsi-ld/v1/attributes +echo +echo + + +echo "06. Create a registration R1 without any attributes" +echo "===================================================" +payload='{ + "id": "urn:ngsi-ld:reg:1", + "type": "ContextSourceRegistration", + "information": [ + { + "entities": [ + { + "id": "urn:ngsi-ld:entity:E1", + "type": "T1" + }, + { + "id": "urn:ngsi-ld:entity:E2", + "type": "T2" + } + ] + } + ], + "endpoint": "http://my.csource.org:1026" +}' +orionCurl --url /ngsi-ld/v1/csourceRegistrations --payload "$payload" +echo +echo + + +echo "07. GET Entity Attributes - see four attributes (P1, P2, P3, and R1)" +echo "====================================================================" +orionCurl --url /ngsi-ld/v1/attributes +echo +echo + + +echo "08. Create a registration R2 with attributes P4 and R2" +echo "======================================================" +payload='{ + "id": "urn:ngsi-ld:reg:2", + "type": "ContextSourceRegistration", + "information": [ + { + "entities": [ + { + "id": "urn:ngsi-ld:entity:E1", + "type": "T1" + } + ], + "properties": [ "P4" ], + "relationships": [ "R2" ] + } + ], + "endpoint": "http://my.csource.org:1026" +}' +orionCurl --url /ngsi-ld/v1/csourceRegistrations --payload "$payload" +echo +echo + + +echo "09. GET Entity Attributes - see six attributes (P1-P4, and R1-R2)" +echo "=================================================================" +orionCurl --url /ngsi-ld/v1/attributes +echo +echo + + +echo "10. Create a registration R3 with attributes P1-P5 and R1-R5" +echo "============================================================" +payload='{ + "id": "urn:ngsi-ld:reg:3", + "type": "ContextSourceRegistration", + "information": [ + { + "entities": [ + { + "id": "urn:ngsi-ld:entity:E1", + "type": "T1" + } + ], + "properties": [ "P1", "P2", "P3", "P4", "P5" ], + "relationships": [ "R1", "R2", "R3", "R4", "R5" ] + } + ], + "endpoint": "http://my.csource.org:1026" +}' +orionCurl --url /ngsi-ld/v1/csourceRegistrations --payload "$payload" +echo +echo + + +echo "11. GET Entity Attributes - see ten attributes (P1-P5, and R1-R5)" +echo "=================================================================" +orionCurl --url /ngsi-ld/v1/attributes +echo +echo + + +echo "12. Remove R3, R1, E0 and E1" +echo "============================" +orionCurl --url /ngsi-ld/v1/entities/urn:ngsi-ld:entities:E0 -X DELETE +orionCurl --url /ngsi-ld/v1/entities/urn:ngsi-ld:entities:E1 -X DELETE +orionCurl --url /ngsi-ld/v1/csourceRegistrations/urn:ngsi-ld:reg:1 -X DELETE +orionCurl --url /ngsi-ld/v1/csourceRegistrations/urn:ngsi-ld:reg:3 -X DELETE +echo +echo + + +echo "13. GET Entity Attributes - see only P4 and R2 from R2" +echo "======================================================" orionCurl --url /ngsi-ld/v1/attributes echo echo @@ -131,8 +251,8 @@ Date: REGEX(.*) -03. GET Entity Types - see three attributes -=========================================== +03. GET Entity Attributes - see three attributes +================================================ HTTP/1.1 200 OK Content-Length: 139 Content-Type: application/json @@ -159,8 +279,37 @@ Date: REGEX(.*) -05. GET Entity Types - see four attributes (P1, P2, P3, and R1) -=============================================================== +05. GET Entity Attributes - see four attributes (P1, P2, P3, and R1) +==================================================================== +HTTP/1.1 200 OK +Content-Length: 144 +Content-Type: application/json +Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Date: REGEX(.*) + +{ + "attributeList": [ + "P1", + "P2", + "P3", + "R1" + ], + "id": "urn:ngsi-ld:EntityAttributeList:REGEX(.*)", + "type": "EntityAttributeList" +} + + +06. Create a registration R1 without any attributes +=================================================== +HTTP/1.1 201 Created +Content-Length: 0 +Location: /ngsi-ld/v1/csourceRegistrations/urn:ngsi-ld:reg:1 +Date: REGEX(.*) + + + +07. GET Entity Attributes - see four attributes (P1, P2, P3, and R1) +==================================================================== HTTP/1.1 200 OK Content-Length: 144 Content-Type: application/json @@ -179,6 +328,106 @@ Date: REGEX(.*) } +08. Create a registration R2 with attributes P4 and R2 +====================================================== +HTTP/1.1 201 Created +Content-Length: 0 +Location: /ngsi-ld/v1/csourceRegistrations/urn:ngsi-ld:reg:2 +Date: REGEX(.*) + + + +09. GET Entity Attributes - see six attributes (P1-P4, and R1-R2) +================================================================= +HTTP/1.1 200 OK +Content-Length: 154 +Content-Type: application/json +Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Date: REGEX(.*) + +{ + "attributeList": [ + "P1", + "P2", + "P3", + "P4", + "R1", + "R2" + ], + "id": "urn:ngsi-ld:EntityAttributeList:REGEX(.*)", + "type": "EntityAttributeList" +} + + +10. Create a registration R3 with attributes P1-P5 and R1-R5 +============================================================ +HTTP/1.1 201 Created +Content-Length: 0 +Location: /ngsi-ld/v1/csourceRegistrations/urn:ngsi-ld:reg:3 +Date: REGEX(.*) + + + +11. GET Entity Attributes - see ten attributes (P1-P5, and R1-R5) +================================================================= +HTTP/1.1 200 OK +Content-Length: 174 +Content-Type: application/json +Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Date: REGEX(.*) + +{ + "attributeList": [ + "P1", + "P2", + "P3", + "P4", + "P5", + "R1", + "R2", + "R3", + "R4", + "R5" + ], + "id": "urn:ngsi-ld:EntityAttributeList:REGEX(.*)", + "type": "EntityAttributeList" +} + + +12. Remove R3, R1, E0 and E1 +============================ +HTTP/1.1 204 No Content +Date: REGEX(.*) + +HTTP/1.1 204 No Content +Date: REGEX(.*) + +HTTP/1.1 204 No Content +Date: REGEX(.*) + +HTTP/1.1 204 No Content +Date: REGEX(.*) + + + +13. GET Entity Attributes - see only P4 and R2 from R2 +====================================================== +HTTP/1.1 200 OK +Content-Length: 134 +Content-Type: application/json +Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" +Date: REGEX(.*) + +{ + "attributeList": [ + "P4", + "R2" + ], + "id": "urn:ngsi-ld:EntityAttributeList:REGEX(.*)", + "type": "EntityAttributeList" +} + + --TEARDOWN-- brokerStop CB dbDrop CB