Skip to content

Commit

Permalink
Merge pull request #794 from FIWARE/task/get-attributes
Browse files Browse the repository at this point in the history
Task/get attributes
  • Loading branch information
kzangeli committed Apr 13, 2021
2 parents 5ca0bba + 372a17d commit d513258
Show file tree
Hide file tree
Showing 16 changed files with 859 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGES_NEXT_RELEASE
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions src/app/orionld/orionldRestServices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 },
Expand Down
1 change: 1 addition & 0 deletions src/lib/orionld/db/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ SET (SOURCES
dbCollectionPathGet.cpp
dbConfiguration.cpp
dbEntityTypesGet.cpp
dbEntityAttributesGet.cpp
dbGeoIndexAdd.cpp
dbGeoIndexLookup.cpp
)
Expand Down
2 changes: 1 addition & 1 deletion src/lib/orionld/db/dbConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
254 changes: 254 additions & 0 deletions src/lib/orionld/db/dbEntityAttributesGet.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
/*
*
* 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 <unistd.h> // 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;
}



// ----------------------------------------------------------------------------
//
// localAttrNamesExtract -
//
// 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 localAttrNamesExtract(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;
}
}
}



// ----------------------------------------------------------------------------
//
// 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)
{
//
// 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)
localAttrNamesExtract(outArray, localEntityArray);

//
// GET external attributes - i.e. from the "registrations" collection
//
KjNode* remote = dbEntityTypesFromRegistrationsGet(true);

if (remote)
remoteAttrNamesExtract(outArray, remote);

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);
}
44 changes: 44 additions & 0 deletions src/lib/orionld/db/dbEntityAttributesGet.h
Original file line number Diff line number Diff line change
@@ -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_
4 changes: 2 additions & 2 deletions src/lib/orionld/db/dbEntityTypesGet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ void entitiesAndProprertiesExtract(KjNode* regArray, KjNode* typeArray)
// ...
//
//
KjNode* mongoCppLegacyEntityTypesFromRegistrationsGet(void)
KjNode* mongoCppLegacyEntityTypesFromRegistrationsGet(bool details)
{
char collectionPath[256];

Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ extern "C"
//
// mongoCppLegacyEntityTypesFromRegistrationsGet -
//
extern KjNode* mongoCppLegacyEntityTypesFromRegistrationsGet(void);
extern KjNode* mongoCppLegacyEntityTypesFromRegistrationsGet(bool details);

#endif // SRC_LIB_ORIONLD_MONGOCPPLEGACY_MONGOCPPLEGACYENTITYTYPESFROMREGISTRATIONSGET_H_

0 comments on commit d513258

Please sign in to comment.