From d9a522b756e2609de0aff72e18397eb96b9be81f Mon Sep 17 00:00:00 2001 From: Ken Zangelin Date: Fri, 19 Jan 2024 18:13:18 +0100 Subject: [PATCH] Support for the format url param, got GET /entities and /entities/{entityId} --- CHANGES_NEXT_RELEASE | 4 +- src/lib/apiTypesV2/Entity.cpp | 2 +- src/lib/jsonParseV2/parseContextAttribute.cpp | 2 +- src/lib/orionld/common/langStringExtract.cpp | 8 +- src/lib/orionld/common/orionldState.h | 1 + .../dbModel/dbModelFromApiAttribute.cpp | 2 +- .../legacyDriver/legacyGetEntities.cpp | 6 +- .../orionld/legacyDriver/legacyGetEntity.cpp | 10 +- src/lib/orionld/mhd/mhdConnectionInit.cpp | 36 +++++- .../orionld/payloadCheck/pCheckAttribute.cpp | 6 +- .../orionld/service/orionldServiceInit.cpp | 2 + .../orionldGetEntitiesLocal.cpp | 5 +- .../serviceRoutines/orionldGetEntity.cpp | 2 +- .../serviceRoutines/orionldPatchEntity2.cpp | 2 +- .../serviceRoutines/orionldPostQuery.cpp | 5 +- src/lib/orionld/subCache/subCacheCreate.cpp | 109 ++++++++++++++++ src/lib/orionld/types/OrionLdRestService.h | 1 + src/lib/rest/rest.cpp | 12 +- .../serviceRoutinesV2/getEntityAttribute.cpp | 2 +- .../getEntityAttributeValue.cpp | 2 +- .../ngsild_new_entity_query-with-concise.test | 120 +++++++++++++++++- 21 files changed, 295 insertions(+), 44 deletions(-) create mode 100644 src/lib/orionld/subCache/subCacheCreate.cpp diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index 6e1bb69777..0fbb83c741 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -2,5 +2,5 @@ Fixed Issue: * #1535 No matching with 'q' when matching subscriptions for deletion of an entity New Features: - * Support for VocabularyProperty (highlu untested and 'q' expansions for vocab-properties is not yet implemented) - + * Support for VocabularyProperty (highly untested and 'q' expansions for vocab-properties is not yet implemented) + * Support for the new URL parameter "format" for output formats (normalized, concise, simplified) diff --git a/src/lib/apiTypesV2/Entity.cpp b/src/lib/apiTypesV2/Entity.cpp index 40b629c705..e7d5fd2df1 100644 --- a/src/lib/apiTypesV2/Entity.cpp +++ b/src/lib/apiTypesV2/Entity.cpp @@ -83,7 +83,7 @@ std::string Entity::render(bool comma) OrionldRenderFormat renderFormat = RF_NORMALIZED; - if (orionldState.uriParamOptions.keyValues == true) { renderFormat = RF_KEYVALUES; } + if (orionldState.out.format == RF_KEYVALUES) { renderFormat = RF_KEYVALUES; } else if (orionldState.uriParamOptions.values == true) { renderFormat = RF_VALUES; } else if (orionldState.uriParamOptions.uniqueValues == true) { renderFormat = RF_UNIQUE_VALUES; } diff --git a/src/lib/jsonParseV2/parseContextAttribute.cpp b/src/lib/jsonParseV2/parseContextAttribute.cpp index 7d3b0fb7ea..726153a049 100644 --- a/src/lib/jsonParseV2/parseContextAttribute.cpp +++ b/src/lib/jsonParseV2/parseContextAttribute.cpp @@ -198,7 +198,7 @@ std::string parseContextAttribute caP->name = name; - if (orionldState.uriParamOptions.keyValues) + if (orionldState.out.format == RF_SIMPLIFIED) { if (type == "String") { diff --git a/src/lib/orionld/common/langStringExtract.cpp b/src/lib/orionld/common/langStringExtract.cpp index acbfa87669..728891a005 100644 --- a/src/lib/orionld/common/langStringExtract.cpp +++ b/src/lib/orionld/common/langStringExtract.cpp @@ -109,7 +109,7 @@ void langValueFix(KjNode* attrP, KjNode* valueP, KjNode* typeP, const char* lang if (langValueNodeP == NULL) { - if (orionldState.uriParamOptions.keyValues == false) + if (orionldState.out.format != RF_SIMPLIFIED) { valueP->type = KjString; valueP->value.s = (char*) "empty languageMap ..."; @@ -122,7 +122,7 @@ void langValueFix(KjNode* attrP, KjNode* valueP, KjNode* typeP, const char* lang } else if (langValueNodeP->type == KjString) { - if (orionldState.uriParamOptions.keyValues == false) + if (orionldState.out.format != RF_SIMPLIFIED) { valueP->type = KjString; valueP->value.s = langValueNodeP->value.s; @@ -135,7 +135,7 @@ void langValueFix(KjNode* attrP, KjNode* valueP, KjNode* typeP, const char* lang } else // It's an array { - if (orionldState.uriParamOptions.keyValues == false) + if (orionldState.out.format != RF_SIMPLIFIED) { valueP->type = KjArray; valueP->value.firstChildP = langValueNodeP->value.firstChildP; @@ -152,7 +152,7 @@ void langValueFix(KjNode* attrP, KjNode* valueP, KjNode* typeP, const char* lang langValueNodeP->lastChild = NULL; } - if (orionldState.uriParamOptions.keyValues == false) + if (orionldState.out.format != RF_SIMPLIFIED) { if (langValueNodeP != NULL) { diff --git a/src/lib/orionld/common/orionldState.h b/src/lib/orionld/common/orionldState.h index 37e288bf3f..2c0577d0fb 100644 --- a/src/lib/orionld/common/orionldState.h +++ b/src/lib/orionld/common/orionldState.h @@ -166,6 +166,7 @@ typedef struct OrionldUriParams bool local; bool onlyIds; bool entityMap; + char* format; double observedAtAsDouble; uint64_t mask; diff --git a/src/lib/orionld/dbModel/dbModelFromApiAttribute.cpp b/src/lib/orionld/dbModel/dbModelFromApiAttribute.cpp index 3a85705082..b583cf29ce 100644 --- a/src/lib/orionld/dbModel/dbModelFromApiAttribute.cpp +++ b/src/lib/orionld/dbModel/dbModelFromApiAttribute.cpp @@ -248,7 +248,7 @@ bool dbModelFromApiAttribute(KjNode* attrP, KjNode* dbAttrsP, KjNode* attrAddedV // Very Special case: If key-values is set, and an uri param 'observedAt' is present, and we're doing a patchEntity2, then: // modify the observedAt sub-attr accordingly // - if ((orionldState.uriParamOptions.keyValues == true) && (orionldState.uriParams.observedAt != NULL) && (dbMdP != NULL)) + if ((orionldState.out.format == RF_SIMPLIFIED) && (orionldState.uriParams.observedAt != NULL) && (dbMdP != NULL)) { KjNode* observedAtP = kjLookup(dbMdP, "observedAt"); if (observedAtP != NULL) diff --git a/src/lib/orionld/legacyDriver/legacyGetEntities.cpp b/src/lib/orionld/legacyDriver/legacyGetEntities.cpp index ba8f6015dc..d652c1fc04 100644 --- a/src/lib/orionld/legacyDriver/legacyGetEntities.cpp +++ b/src/lib/orionld/legacyDriver/legacyGetEntities.cpp @@ -145,8 +145,8 @@ bool legacyGetEntities(void) char* coordinates = orionldState.uriParams.coordinates; bool local = orionldState.uriParams.local; char* lang = orionldState.uriParams.lang; - bool keyValues = orionldState.uriParamOptions.keyValues; - bool concise = orionldState.uriParamOptions.concise; + bool keyValues = orionldState.out.format == RF_SIMPLIFIED; + bool concise = orionldState.out.format == RF_CONCISE; char* idString = (id != NULL)? id : idPattern; const char* isIdPattern = (id != NULL)? "false" : "true"; bool isTypePattern = (type != NULL)? false : true; @@ -483,7 +483,7 @@ bool legacyGetEntities(void) if (countP != NULL) orionldHeaderAdd(&orionldState.out.headers, HttpResultsCount, NULL, *countP); - if (orionldState.uriParamOptions.concise == true) + if (orionldState.out.format == RF_CONCISE) kjEntityNormalizedToConcise(orionldState.responseTree, NULL); // lang already taken care of by apiEntityLanguageProps mongoRequest.release(); diff --git a/src/lib/orionld/legacyDriver/legacyGetEntity.cpp b/src/lib/orionld/legacyDriver/legacyGetEntity.cpp index 0615d4a92b..8a33c99ba5 100644 --- a/src/lib/orionld/legacyDriver/legacyGetEntity.cpp +++ b/src/lib/orionld/legacyDriver/legacyGetEntity.cpp @@ -223,14 +223,14 @@ static KjNode* orionldForwardGetEntityPart(KjNode* registrationP, char* entityId if (*newUriParamAttrsString != 0) { - if (orionldState.uriParamOptions.keyValues) + if (orionldState.out.format == RF_SIMPLIFIED) snprintf(urlPath, size, "%s/ngsi-ld/v1/entities/%s?options=keyValues&attrs=%s", uriDirP, entityId, newUriParamAttrsString); else snprintf(urlPath, size, "%s/ngsi-ld/v1/entities/%s?attrs=%s", uriDirP, entityId, newUriParamAttrsString); } else { - if (orionldState.uriParamOptions.keyValues) + if (orionldState.out.format == RF_SIMPLIFIED) snprintf(urlPath, size, "%s/ngsi-ld/v1/entities/%s?options=keyValues", uriDirP, entityId); else snprintf(urlPath, size, "%s/ngsi-ld/v1/entities/%s", uriDirP, entityId); @@ -429,8 +429,8 @@ bool legacyGetEntity(void) eqAttrV, attrsMandatory, orionldState.uriParamOptions.sysAttrs, - orionldState.uriParamOptions.keyValues, - orionldState.uriParamOptions.concise, + orionldState.out.format == RF_SIMPLIFIED, + orionldState.out.format == RF_CONCISE, orionldState.uriParams.datasetId, geometryProperty, &orionldState.geoPropertyNode, @@ -483,7 +483,7 @@ bool legacyGetEntity(void) orionldState.uriParams.geometryProperty, orionldState.geoPropertyMissing, orionldState.linkHeaderAdded, - orionldState.uriParamOptions.concise, + orionldState.out.format == RF_CONCISE, orionldState.contextP->url); return true; diff --git a/src/lib/orionld/mhd/mhdConnectionInit.cpp b/src/lib/orionld/mhd/mhdConnectionInit.cpp index 772fa4abfc..4011881512 100644 --- a/src/lib/orionld/mhd/mhdConnectionInit.cpp +++ b/src/lib/orionld/mhd/mhdConnectionInit.cpp @@ -163,7 +163,7 @@ static void ipAddressAndPort(void) // // optionsParse - // -static void optionsParse(const char* options) +void optionsParse(const char* options) { char* optionStart = (char*) options; char* cP = (char*) options; @@ -182,10 +182,10 @@ static void optionsParse(const char* options) if (strcmp(optionStart, "update") == 0) orionldState.uriParamOptions.update = true; else if (strcmp(optionStart, "replace") == 0) orionldState.uriParamOptions.replace = true; else if (strcmp(optionStart, "noOverwrite") == 0) orionldState.uriParamOptions.noOverwrite = true; - else if (strcmp(optionStart, "keyValues") == 0) orionldState.uriParamOptions.keyValues = true; - else if (strcmp(optionStart, "simplified") == 0) orionldState.uriParamOptions.keyValues = true; - else if (strcmp(optionStart, "concise") == 0) orionldState.uriParamOptions.concise = true; - else if (strcmp(optionStart, "normalized") == 0) orionldState.uriParamOptions.normalized = true; + else if (strcmp(optionStart, "keyValues") == 0) { if (orionldState.uriParams.format == NULL) orionldState.uriParamOptions.keyValues = true; } + else if (strcmp(optionStart, "simplified") == 0) { if (orionldState.uriParams.format == NULL) orionldState.uriParamOptions.keyValues = true; } + else if (strcmp(optionStart, "concise") == 0) { if (orionldState.uriParams.format == NULL) orionldState.uriParamOptions.concise = true; } + else if (strcmp(optionStart, "normalized") == 0) { if (orionldState.uriParams.format == NULL) orionldState.uriParamOptions.normalized = true; } else if (strcmp(optionStart, "sysAttrs") == 0) orionldState.uriParamOptions.sysAttrs = true; else if (strcmp(optionStart, "fromDb") == 0) orionldState.uriParamOptions.fromDb = true; else if (strcmp(optionStart, "append") == 0) orionldState.uriParamOptions.append = true; // NGSIv2 compatibility @@ -676,9 +676,24 @@ MHD_Result orionldUriArgumentGet(void* cbDataP, MHD_ValueKind kind, const char* else if (strcmp(key, "options") == 0) { orionldState.uriParams.options = (char*) value; - optionsParse(value); orionldState.uriParams.mask |= ORIONLD_URIPARAM_OPTIONS; } + else if (strcmp(key, "format") == 0) + { + orionldState.uriParams.format = (char*) value; + + if (strcmp(value, "normalized") == 0) orionldState.out.format = RF_NORMALIZED; + else if (strcmp(value, "concise") == 0) orionldState.out.format = RF_CONCISE; + else if (strcmp(value, "simplified") == 0) orionldState.out.format = RF_SIMPLIFIED; + else if (strcmp(value, "keyValues") == 0) orionldState.out.format = RF_SIMPLIFIED; + else + { + orionldError(OrionldBadRequestData, "Bad value for URI parameter /format/", value, 400); + return MHD_YES; + } + + orionldState.uriParams.mask |= ORIONLD_URIPARAM_FORMAT; + } else if (strcmp(key, "geometry") == 0) { orionldState.uriParams.geometry = (char*) value; @@ -1152,7 +1167,14 @@ MHD_Result mhdConnectionInit // 5. GET URI params // MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, orionldUriArgumentGet, NULL); - LM_T(LmtCount, ("orionldState.uriParams.count: %s", K_FT(orionldState.uriParams.count))); + + // + // As "format" has precedence over options=concise/simplified/etc, the call to optionsParse must wait until after + // all calls to orionldUriArgumentGet are done. + // Because, optionsParse n eeds to know whether "format" has been used. + // + if (orionldState.uriParams.options != NULL) + optionsParse(orionldState.uriParams.options); // // Format of response payload diff --git a/src/lib/orionld/payloadCheck/pCheckAttribute.cpp b/src/lib/orionld/payloadCheck/pCheckAttribute.cpp index dcdc3a1296..997bc0e2b4 100644 --- a/src/lib/orionld/payloadCheck/pCheckAttribute.cpp +++ b/src/lib/orionld/payloadCheck/pCheckAttribute.cpp @@ -221,7 +221,7 @@ inline bool pCheckAttributeString // // If all those are fulfilled, then the value (object) of the Relationship will be modified // - if ((orionldState.uriParamOptions.keyValues == true) && + if ((orionldState.out.format == RF_SIMPLIFIED) && (orionldState.serviceP->serviceRoutine == orionldPatchEntity2) && (attrTypeFromDb == Relationship)) { @@ -985,7 +985,7 @@ static bool pCheckAttributeObject if ((attrTypeFromDb != NoAttributeType) && (attributeType != attrTypeFromDb)) { // This might be OK, if keyValues is ON => attributeType is a guess - if (orionldState.uriParamOptions.keyValues == false) + if (orionldState.out.format != RF_SIMPLIFIED) { const char* title = attrTypeChangeTitle(attrTypeFromDb, attributeType); orionldError(OrionldBadRequestData, title, attrP->name, 400); @@ -1046,7 +1046,7 @@ static bool pCheckAttributeObject if ((attrTypeFromDb != NoAttributeType) && (attributeType != NoAttributeType) && (attributeType != attrTypeFromDb)) { // This might be OK, if keyValues is ON => attributeType is a guess - if (orionldState.uriParamOptions.keyValues == false) + if (orionldState.out.format != RF_SIMPLIFIED) { const char* title = attrTypeChangeTitle(attrTypeFromDb, attributeType); orionldError(OrionldBadRequestData, title, attrP->name, 400); diff --git a/src/lib/orionld/service/orionldServiceInit.cpp b/src/lib/orionld/service/orionldServiceInit.cpp index 4d352aaae5..a2040314d3 100644 --- a/src/lib/orionld/service/orionldServiceInit.cpp +++ b/src/lib/orionld/service/orionldServiceInit.cpp @@ -216,6 +216,7 @@ static void restServicePrepare(OrionLdRestService* serviceP, OrionLdRestServiceS else if (serviceP->serviceRoutine == orionldGetEntities) { serviceP->uriParams |= ORIONLD_URIPARAM_OPTIONS; + serviceP->uriParams |= ORIONLD_URIPARAM_FORMAT; serviceP->uriParams |= ORIONLD_URIPARAM_LIMIT; serviceP->uriParams |= ORIONLD_URIPARAM_OFFSET; serviceP->uriParams |= ORIONLD_URIPARAM_COUNT; @@ -238,6 +239,7 @@ static void restServicePrepare(OrionLdRestService* serviceP, OrionLdRestServiceS else if (serviceP->serviceRoutine == orionldGetEntity) { serviceP->uriParams |= ORIONLD_URIPARAM_OPTIONS; + serviceP->uriParams |= ORIONLD_URIPARAM_FORMAT; serviceP->uriParams |= ORIONLD_URIPARAM_ATTRS; serviceP->uriParams |= ORIONLD_URIPARAM_GEOMETRYPROPERTY; serviceP->uriParams |= ORIONLD_URIPARAM_LANG; diff --git a/src/lib/orionld/serviceRoutines/orionldGetEntitiesLocal.cpp b/src/lib/orionld/serviceRoutines/orionldGetEntitiesLocal.cpp index 155ae8ff8a..18bc7423ed 100644 --- a/src/lib/orionld/serviceRoutines/orionldGetEntitiesLocal.cpp +++ b/src/lib/orionld/serviceRoutines/orionldGetEntitiesLocal.cpp @@ -203,10 +203,7 @@ bool orionldGetEntitiesLocal else { KjNode* apiEntityArray = kjArray(orionldState.kjsonP, NULL); - OrionldRenderFormat rf = RF_NORMALIZED; - - if (orionldState.uriParamOptions.concise == true) rf = RF_CONCISE; - else if (orionldState.uriParamOptions.keyValues == true) rf = RF_SIMPLIFIED; + OrionldRenderFormat rf = orionldState.out.format; if (orionldState.out.contentType == MT_GEOJSON) { diff --git a/src/lib/orionld/serviceRoutines/orionldGetEntity.cpp b/src/lib/orionld/serviceRoutines/orionldGetEntity.cpp index 352ef73934..ff5f67e04f 100644 --- a/src/lib/orionld/serviceRoutines/orionldGetEntity.cpp +++ b/src/lib/orionld/serviceRoutines/orionldGetEntity.cpp @@ -370,7 +370,7 @@ bool orionldGetEntity(void) orionldState.uriParams.geometryProperty, orionldState.geoPropertyMissing, orionldState.linkHeaderAdded, - orionldState.uriParamOptions.concise, + orionldState.out.format == RF_CONCISE, orionldState.contextP->url); // diff --git a/src/lib/orionld/serviceRoutines/orionldPatchEntity2.cpp b/src/lib/orionld/serviceRoutines/orionldPatchEntity2.cpp index ef952ed0c5..a5ea4f2584 100644 --- a/src/lib/orionld/serviceRoutines/orionldPatchEntity2.cpp +++ b/src/lib/orionld/serviceRoutines/orionldPatchEntity2.cpp @@ -575,7 +575,7 @@ bool orionldPatchEntity2(void) // If options=simplified/keyValues is present, the behaviour is very different // BUT, if I add the "value" to each attribute in the payload body, I have "Normalized" it // - if (orionldState.uriParamOptions.keyValues == true) + if (orionldState.out.format == RF_SIMPLIFIED) { if (apiEntitySimplifiedToNormalized(orionldState.requestTree, dbAttrsP) == false) return false; diff --git a/src/lib/orionld/serviceRoutines/orionldPostQuery.cpp b/src/lib/orionld/serviceRoutines/orionldPostQuery.cpp index e78671f2ed..ff29c3e719 100644 --- a/src/lib/orionld/serviceRoutines/orionldPostQuery.cpp +++ b/src/lib/orionld/serviceRoutines/orionldPostQuery.cpp @@ -95,10 +95,7 @@ bool orionldPostQuery(void) return false; KjNode* apiEntityArray = kjArray(orionldState.kjsonP, NULL); - OrionldRenderFormat rf = RF_NORMALIZED; - - if (orionldState.uriParamOptions.concise == true) rf = RF_CONCISE; - else if (orionldState.uriParamOptions.keyValues == true) rf = RF_SIMPLIFIED; + OrionldRenderFormat rf = orionldState.out.format; if (orionldState.out.contentType == MT_GEOJSON) { diff --git a/src/lib/orionld/subCache/subCacheCreate.cpp b/src/lib/orionld/subCache/subCacheCreate.cpp new file mode 100644 index 0000000000..89a68f2a37 --- /dev/null +++ b/src/lib/orionld/subCache/subCacheCreate.cpp @@ -0,0 +1,109 @@ +/* +* +* Copyright 2024 FIWARE Foundation e.V. +* +* This file is part of Orion-LD Context Broker. +* +* Orion-LD Context Broker is free software: you can redistribute it and/or +* modify it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* Orion-LD Context Broker is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero +* General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with Orion-LD Context Broker. If not, see http://www.gnu.org/licenses/. +* +* For those usages not covered by this license please contact with +* orionld at fiware dot org +* +* Author: Ken Zangelin +*/ +extern "C" +{ +#include "kjson/KjNode.h" // KjNode +#include "kjson/kjLookup.h" // kjLookup +} + +#include "logMsg/logMsg.h" // LM_* + +#include "orionld/types/OrionldTenant.h" // OrionldTenant +#include "orionld/types/SubCache.h" // SubCache +#include "orionld/common/orionldState.h" // orionldState +#include "orionld/context/orionldContextFromUrl.h" // orionldContextFromUrl +#include "orionld/mongoc/mongocSubscriptionsIter.h" // mongocSubscriptionsIter +#include "orionld/dbModel/dbModelToApiSubscription.h" // dbModelToApiSubscription +#include "orionld/subCache/subCacheItemAdd.h" // subCacheItemAdd +#include "orionld/subCache/subCacheCreate.h" // Own interface + + + +extern void apiModelToCacheSubscription(KjNode* apiSubscriptionP); +// ----------------------------------------------------------------------------- +// +// subIterFunc - +// +int subIterFunc(SubCache* scP, KjNode* dbSubP) +{ + // Convert DB Sub to API Sub + if (dbModelToApiSubscription(dbSubP, true, true) == false) + LM_RE(-1, ("dbModelToApiSubscription failed")); + + // The DB Subscription 'dbSubP' is now in API Subscription format (after calling dbModelToApiSubscription) + KjNode* apiSubP = dbSubP; + + // If a jsonldContext is given for the subscription, make sure it's valid + OrionldContext* jsonldContextP = NULL; + KjNode* jsonldContextNodeP = kjLookup(apiSubscriptionP, "jsonldContext"); + if (jsonldContextNodeP != NULL) + { + jsonldContextP = orionldContextFromUrl(jsonldContextNodeP->value.s, NULL); + + if (jsonldContextP == NULL) + { + LM_W(("Unable to resolve a Subscription @context for a sub-cache item")); + return 0; + } + } + + // Subscription Id + KjNode* subIdNodeP = kjLookup(apiSubP, "id"); + char* subId = (subIdNodeP != NULL)? subIdNodeP->value.s : (char*) "no:sub:id"; + + // Convert API Sub to Cache Sub + apiModelToCacheSubscription(apiSubP); + + // Insert cacheSubP in tenantP->subCache + subCacheItemAdd(scP, subId, apiSubP, true, jsonldContextP); + + return 0; +} + + + +// ----------------------------------------------------------------------------- +// +// subCacheCreate - +// +SubCache* subCacheCreate(OrionldTenant* tenantP, bool scanSubs) +{ + SubCache* scP = (SubCache*) malloc(sizeof(SubCache)); + + if (scP == NULL) + LM_RE(NULL, ("Out of memory (attempt to create a subscription cache)")); + + scP->tenantP = tenantP; + scP->subList = NULL; + scP->last = NULL; + + if (scanSubs) + { + if (mongocSubscriptionsIter(scP, subIterFunc) != 0) + LM_E(("mongocSubscriptionsIter failed")); + } + + return scP; +} diff --git a/src/lib/orionld/types/OrionLdRestService.h b/src/lib/orionld/types/OrionLdRestService.h index 0ef2b00b3b..3e1656961a 100644 --- a/src/lib/orionld/types/OrionLdRestService.h +++ b/src/lib/orionld/types/OrionLdRestService.h @@ -154,6 +154,7 @@ typedef struct OrionLdRestServiceSimplifiedVector #define ORIONLD_URIPARAM_LEVEL (UINT64_C(1) << 37) #define ORIONLD_URIPARAM_ONLYIDS (UINT64_C(1) << 38) #define ORIONLD_URIPARAM_ENTITYMAP (UINT64_C(1) << 39) +#define ORIONLD_URIPARAM_FORMAT (UINT64_C(1) << 40) diff --git a/src/lib/rest/rest.cpp b/src/lib/rest/rest.cpp index bc1301f573..f8a3428345 100644 --- a/src/lib/rest/rest.cpp +++ b/src/lib/rest/rest.cpp @@ -1098,6 +1098,11 @@ ConnectionInfo* connectionTreatInit // URI parameters // MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, orionldUriArgumentGet, ciP); + + extern void optionsParse(const char* options); + if (orionldState.uriParams.options != NULL) + optionsParse(orionldState.uriParams.options); + if (orionldState.httpStatusCode >= 400) { LM_W(("Bad Request (error in URI parameters - %s: %s)", orionldState.pd.title, orionldState.pd.detail)); @@ -1380,9 +1385,10 @@ static MHD_Result connectionTreat // bool keyValuesEtAl = true; - if ((orionldState.uriParamOptions.keyValues) && (orionldState.uriParamOptions.values)) keyValuesEtAl = false; - else if ((orionldState.uriParamOptions.keyValues) && (orionldState.uriParamOptions.uniqueValues)) keyValuesEtAl = false; - else if ((orionldState.uriParamOptions.values) && (orionldState.uriParamOptions.uniqueValues)) keyValuesEtAl = false; + if ((orionldState.out.format == RF_SIMPLIFIED) && (orionldState.uriParamOptions.values)) keyValuesEtAl = false; + else if ((orionldState.out.format == RF_SIMPLIFIED) && (orionldState.uriParamOptions.uniqueValues)) keyValuesEtAl = false; + else if ((orionldState.uriParamOptions.values) && (orionldState.uriParamOptions.uniqueValues)) keyValuesEtAl = false; + if (keyValuesEtAl == false) { OrionError error(SccBadRequest, "Invalid value for URI param /options/"); diff --git a/src/lib/serviceRoutinesV2/getEntityAttribute.cpp b/src/lib/serviceRoutinesV2/getEntityAttribute.cpp index 21f9e50850..b5eafb6454 100644 --- a/src/lib/serviceRoutinesV2/getEntityAttribute.cpp +++ b/src/lib/serviceRoutinesV2/getEntityAttribute.cpp @@ -94,7 +94,7 @@ std::string getEntityAttribute TIMED_RENDER(answer = attribute.render(orionldState.out.contentType, &orionldState.out.contentType, &orionldState.httpStatusCode, - orionldState.uriParamOptions.keyValues, + orionldState.out.format == RF_SIMPLIFIED, orionldState.uriParams.metadata? orionldState.uriParams.metadata : "", EntityAttributeResponse)); diff --git a/src/lib/serviceRoutinesV2/getEntityAttributeValue.cpp b/src/lib/serviceRoutinesV2/getEntityAttributeValue.cpp index 69cd605c97..8d9cd15663 100644 --- a/src/lib/serviceRoutinesV2/getEntityAttributeValue.cpp +++ b/src/lib/serviceRoutinesV2/getEntityAttributeValue.cpp @@ -110,7 +110,7 @@ std::string getEntityAttributeValue TIMED_RENDER(answer = attribute.render(orionldState.out.contentType, &orionldState.out.contentType, &orionldState.httpStatusCode, - orionldState.uriParamOptions.keyValues, + orionldState.out.format == RF_SIMPLIFIED, orionldState.uriParams.metadata? orionldState.uriParams.metadata : "", EntityAttributeValueRequest, false)); diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_new_entity_query-with-concise.test b/test/functionalTest/cases/0000_ngsild/ngsild_new_entity_query-with-concise.test index ee9e40c186..b091e61e80 100644 --- a/test/functionalTest/cases/0000_ngsild/ngsild_new_entity_query-with-concise.test +++ b/test/functionalTest/cases/0000_ngsild/ngsild_new_entity_query-with-concise.test @@ -77,14 +77,14 @@ echo echo "02. GET using Concise output format" echo "===================================" -orionCurl --url '/ngsi-ld/v1/entities?type=T&options=concise' +orionCurl --url '/ngsi-ld/v1/entities?type=T&format=concise' echo echo echo "03. GET using Normalized output format" echo "======================================" -orionCurl --url '/ngsi-ld/v1/entities?type=T&options=normalized' +orionCurl --url '/ngsi-ld/v1/entities?type=T&format=normalized' echo echo @@ -131,6 +131,13 @@ echo echo +echo "10. GET single entity using Concise output format w/ sysAttrs" +echo "=============================================================" +orionCurl --url '/ngsi-ld/v1/entities/urn:ngsi-ld:entities:E1?type=T&options=sysAttrs&format=concise' +echo +echo + + --REGEXPECT-- 01. Create an entity E1 attributes of all types, and sub-attrs of all types =========================================================================== @@ -471,6 +478,115 @@ Link: