Skip to content

Commit

Permalink
FIX partial porting of Ken's PR #3480
Browse files Browse the repository at this point in the history
  • Loading branch information
fgalan committed May 9, 2019
1 parent 4139398 commit 2b7798d
Show file tree
Hide file tree
Showing 8 changed files with 410 additions and 140 deletions.
190 changes: 138 additions & 52 deletions src/lib/mongoBackend/MongoGlobal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,16 @@ bool includedEntity(EntityId en, const EntityIdVector& entityIdV)
{
for (unsigned int ix = 0; ix < entityIdV.size(); ++ix)
{
if (matchEntity(&en, entityIdV[ix]))
if (en.isPatternIsTrue() && en.id == ".*")
{
// By the moment the only supported pattern is .*. In this case matching is
// based exclusively in type
if (en.type == entityIdV[ix]->type)
{
return true;
}
}
else if (matchEntity(&en, entityIdV[ix]))
{
return true;
}
Expand Down Expand Up @@ -2004,51 +2013,118 @@ bool registrationsQuery
long long* countP
)
{
/* Build query based on arguments */
// FIXME P2: this implementation needs to be refactored for cleanup
std::string contextRegistrationEntities = REG_CONTEXT_REGISTRATION "." REG_ENTITIES;
std::string contextRegistrationEntitiesId = REG_CONTEXT_REGISTRATION "." REG_ENTITIES "." REG_ENTITY_ID;
std::string contextRegistrationEntitiesType = REG_CONTEXT_REGISTRATION "." REG_ENTITIES "." REG_ENTITY_TYPE;
std::string contextRegistrationAttrsNames = REG_CONTEXT_REGISTRATION "." REG_ATTRS "." REG_ATTRS_NAME;
BSONArrayBuilder entityOr;
BSONArrayBuilder entitiesWithType;
BSONArrayBuilder entitiesWithoutType;
mongo::BSONObjBuilder queryBuilder;
mongo::BSONArrayBuilder entityOr;

for (unsigned int ix = 0; ix < enV.size(); ++ix)
//
// If there's only one entity in the REST request, the query to mongo can be simplified.
// NGSIv2 requests like PATCH /v2/entities/<EID>/attrs can have only ONE entity
// and will ALWAYS enter the "then part" of the if-then-else.
//
// FIXME: Note than registrations with entity id as a pattern is treated by the "then part" but not by the older "else part".
// When forwarding for batch update is implemented this needs to be fixed, somehow
// Once NGSIv1 is removed from the source code, the "else part" can be removed by just making sure that
// NGSIv2 batch operations call this function once per entity in the request (modifications needed).
// Or, we'd need to reimplement to make the else-part also support registrations with entity id as a pattern.
//
// Note by fgalan: actually in the entity update logic enV has always one element, by construction (remember that
// update logic processes entities one-by-one). In the case of entity query logic I guess that we have cases in
// which enV can have more than one element.
//
// FIXME PR: to review above text before merging
//
if (enV.size() == 1)
{
const EntityId* en = enV[ix];
if ((enV[0]->id == "") && (enV[0]->type == ""))
{
LM_E(("Bad Request (too wide query - at least one of entity::id and entity::type must be given)"));
*err = "too wide query";
return false;
}

if (isTrue(en->isPattern))
// Entity ID - if not given, no Entity ID in query - then ALL ENTITY IDs match, so not included in query
if (enV[0]->id != "")
{
BSONObjBuilder b;
mongo::BSONObjBuilder entityAnd;
mongo::BSONObjBuilder id;

b.appendRegex(contextRegistrationEntitiesId, en->id);
if (en->type != "")
{
b.append(contextRegistrationEntitiesType, en->type);
}
entityOr.append(b.obj());
// If the Registration is with idPattern, then it matches, as the only idPattern allowed for Registrations is ".*"
entityAnd.append("contextRegistration.entities.isPattern", "true");
entityAnd.append("contextRegistration.entities.id", ".*"); // FIXME TPUT: if isPattern == true, then id MUST be ".*" ! Remove?
entityOr.append(entityAnd.obj());

if (enV[0]->isPattern == "true") id.appendRegex("contextRegistration.entities.id", enV[0]->id);
else id.append("contextRegistration.entities.id", enV[0]->id);

entityOr.append(id.obj());
queryBuilder.append("$or", entityOr.arr());
}

// Entity Type
if (enV[0]->type != "")
{
queryBuilder.append("contextRegistration.entities.type", enV[0]->type);
}
else /* isPattern = false */
}
else // More than one Entity in enV
{
/* Build query based on arguments */
// FIXME P2: this implementation needs to be refactored for cleanup
std::string contextRegistrationEntities = REG_CONTEXT_REGISTRATION "." REG_ENTITIES;
std::string contextRegistrationEntitiesId = REG_CONTEXT_REGISTRATION "." REG_ENTITIES "." REG_ENTITY_ID;
std::string contextRegistrationEntitiesType = REG_CONTEXT_REGISTRATION "." REG_ENTITIES "." REG_ENTITY_TYPE;
BSONArrayBuilder entitiesWithType;
BSONArrayBuilder entitiesWithoutType;

for (unsigned int ix = 0; ix < enV.size(); ++ix)
{
if (en->type == "")
const EntityId* en = enV[ix];

if (isTrue(en->isPattern))
{
entitiesWithoutType.append(en->id);
LM_T(LmtMongo, ("Entity discovery without type: id '%s'", en->id.c_str()));
BSONObjBuilder b;

b.appendRegex(contextRegistrationEntitiesId, en->id);
if (en->type != "")
{
b.append(contextRegistrationEntitiesType, en->type);
}
entityOr.append(b.obj());
}
else
else /* isPattern = false */
{
/* We have detected that sometimes mongo stores { id: ..., type ...} and sometimes { type: ..., id: ...},
so we have to take both of them into account
*/
entitiesWithType.append(BSON(REG_ENTITY_ID << en->id << REG_ENTITY_TYPE << en->type));
entitiesWithType.append(BSON(REG_ENTITY_TYPE << en->type << REG_ENTITY_ID << en->id));
LM_T(LmtMongo, ("Entity discovery: {id: %s, type: %s}", en->id.c_str(), en->type.c_str()));
if (en->type == "")
{
entitiesWithoutType.append(BSON(REG_ENTITY_ISPATTERN << "true"));
entitiesWithoutType.append(BSON(REG_ENTITY_ID << en->id));
LM_T(LmtMongo, ("Entity discovery without type: id '%s'", en->id.c_str()));
}
else
{
/* We have detected that sometimes mongo stores { id: ..., type ...} and sometimes { type: ..., id: ...},
so we have to take both of them into account
*/
entitiesWithType.append(BSON(REG_ENTITY_ID << en->id << REG_ENTITY_TYPE << en->type));
entitiesWithType.append(BSON(REG_ENTITY_TYPE << en->type << REG_ENTITY_ID << en->id));
LM_T(LmtMongo, ("Entity discovery: {id: %s, type: %s}", en->id.c_str(), en->type.c_str()));
}
}
}

entityOr.append(BSON(contextRegistrationEntities << BSON("$in" << entitiesWithType.arr())));
entityOr.append(BSON(contextRegistrationEntitiesId << BSON("$in" << entitiesWithoutType.arr())));

/* The $or clause could be omitted if it contains only one element, but we can assume that
* it has no impact on MongoDB query optimizer
*/
queryBuilder.append("$or", entityOr.arr());
}

//
// Attributes
//
BSONArrayBuilder attrs;
std::string contextRegistrationAttrsNames = REG_CONTEXT_REGISTRATION "." REG_ATTRS "." REG_ATTRS_NAME;

for (unsigned int ix = 0; ix < attrL.size(); ++ix)
{
Expand All @@ -2058,29 +2134,21 @@ bool registrationsQuery
LM_T(LmtMongo, ("Attribute discovery: '%s'", attrName.c_str()));
}

entityOr.append(BSON(contextRegistrationEntities << BSON("$in" << entitiesWithType.arr())));
entityOr.append(BSON(contextRegistrationEntitiesId << BSON("$in" << entitiesWithoutType.arr())));

BSONObjBuilder queryBuilder;

/* The $or clause could be omitted if it contains only one element, but we can assume that
* it has no impact on MongoDB query optimizer
*/
queryBuilder.append("$or", entityOr.arr());
queryBuilder.append(REG_EXPIRATION, BSON("$gt" << (long long) getCurrentTime()));

if (attrs.arrSize() > 0)
{
/* If we don't do this check, the {$in: [] } of the attribute name part makes the query fail */
queryBuilder.append(contextRegistrationAttrsNames, BSON("$in" << attrs.arr()));
}

//
// 'And-in' the service path
// Service Path
//
const std::string servicePathString = REG_SERVICE_PATH;
queryBuilder.append(REG_SERVICE_PATH, fillQueryServicePath(servicePathV));

queryBuilder.append(servicePathString, fillQueryServicePath(servicePathV));
//
// Expiration
//
queryBuilder.append(REG_EXPIRATION, BSON("$gt" << (long long) getCurrentTime()));


//
Expand Down Expand Up @@ -2128,11 +2196,13 @@ bool registrationsQuery
std::string format = getStringFieldF(r, REG_FORMAT);
ProviderFormat providerFormat = (format == "")? PfJson : (format == "JSON")? PfJson : PfV2;

LM_T(LmtForward, ("--------------- %d registration elements to process", queryContextRegistrationV.size()));
for (unsigned int ix = 0 ; ix < queryContextRegistrationV.size(); ++ix)
{
LM_T(LmtForward, ("Processing ContextRegistrationElement. providerFormat == '%s' (%d)", format.c_str(), providerFormat));
processContextRegistrationElement(queryContextRegistrationV[ix].embeddedObject(), enV, attrL, crrV, mimeType, providerFormat);
}
LM_T(LmtForward, ("--------------- %d registration elements processed - %d elementd output in crrV", queryContextRegistrationV.size(), crrV->size()));

/* FIXME: note that given the response doesn't distinguish from which registration ID the
* response comes, it could have that we have same context registration elements, belong to different
Expand Down Expand Up @@ -2765,21 +2835,24 @@ void fillContextProviders(ContextElementResponse* cer, const ContextRegistration
}

/* Search for some CPr in crrV */
std::string perEntPa;
std::string perAttrPa;
MimeType perEntPaMimeType = NOMIMETYPE;
MimeType perAttrPaMimeType = NOMIMETYPE;
std::string perEntPa;
std::string perAttrPa;
MimeType perEntPaMimeType = NOMIMETYPE;
MimeType perAttrPaMimeType = NOMIMETYPE;
ProviderFormat providerFormat;

cprLookupByAttribute(cer->entity,
ca->name,
crrV,
&perEntPa,
&perEntPaMimeType,
&perAttrPa,
&perAttrPaMimeType);
&perAttrPaMimeType,
&providerFormat);

/* Looking results after crrV processing */
ca->providingApplication.set(perAttrPa == "" ? perEntPa : perAttrPa);
ca->providingApplication.setProviderFormat(providerFormat);
ca->found = (ca->providingApplication.get() != "");
}
}
Expand Down Expand Up @@ -2826,7 +2899,8 @@ void cprLookupByAttribute
std::string* perEntPa,
MimeType* perEntPaMimeType,
std::string* perAttrPa,
MimeType* perAttrPaMimeType
MimeType* perAttrPaMimeType,
ProviderFormat* providerFormatP
)
{
*perEntPa = "";
Expand All @@ -2841,7 +2915,17 @@ void cprLookupByAttribute
{
EntityId* regEn = crr->contextRegistration.entityIdVector[enIx];

if (regEn->id != en.id || (regEn->type != en.type && regEn->type != ""))
if (regEn->isPatternIsTrue() && regEn->id == ".*")
{
// By the moment the only supported pattern is .*. In this case matching is
// based exclusively in type
if (regEn->type != en.type && regEn->type != "")
{
/* No match (keep searching the CRR) */
continue;
}
}
else if (regEn->id != en.id || (regEn->type != en.type && regEn->type != ""))
{
/* No match (keep searching the CRR) */
continue;
Expand All @@ -2851,6 +2935,7 @@ void cprLookupByAttribute
if (crr->contextRegistration.contextRegistrationAttributeVector.size() == 0)
{
*perEntPa = crr->contextRegistration.providingApplication.get();
*providerFormatP = crr->contextRegistration.providingApplication.getProviderFormat();

break; /* enIx */
}
Expand All @@ -2863,6 +2948,7 @@ void cprLookupByAttribute
{
/* We cannot "improve" this result by keep searching the CRR vector, so we return */
*perAttrPa = crr->contextRegistration.providingApplication.get();
*providerFormatP = crr->contextRegistration.providingApplication.getProviderFormat();

return;
}
Expand Down
3 changes: 2 additions & 1 deletion src/lib/mongoBackend/MongoGlobal.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,8 @@ extern void cprLookupByAttribute
std::string* perEntPa,
MimeType* perEntPaMimeType,
std::string* perAttrPa,
MimeType* perAttrPaMimeType
MimeType* perAttrPaMimeType,
ProviderFormat* providerFormatP
);


Expand Down
13 changes: 9 additions & 4 deletions src/lib/ngsi10/UpdateContextRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "convenience/UpdateContextAttributeRequest.h"



/* ****************************************************************************
*
* UpdateContextRequest::UpdateContextRequest -
Expand All @@ -53,13 +54,15 @@ UpdateContextRequest::UpdateContextRequest()
*
* UpdateContextRequest::UpdateContextRequest -
*/
UpdateContextRequest::UpdateContextRequest(const std::string& _contextProvider, Entity* eP)
UpdateContextRequest::UpdateContextRequest(const std::string& _contextProvider, ProviderFormat _providerFormat, Entity* eP)
{
contextProvider = _contextProvider;
providerFormat = _providerFormat;
entityVector.push_back(new Entity(eP->id, eP->type, eP->isPattern));
}



/* ****************************************************************************
*
* UpdateContextRequest::toJsonV1 -
Expand All @@ -68,9 +71,10 @@ std::string UpdateContextRequest::toJsonV1(bool asJsonObject)
{
std::string out = "";

// JSON commas:
// Both fields are MANDATORY, so, comma after "contextElementVector"
//
//
// About JSON commas:
// Both fields are MANDATORY, so, always comma after "entityVector"
//
out += startTag();
out += entityVector.toJsonV1(asJsonObject, UpdateContext, true);
out += valueTag("updateAction", actionTypeString(V1, updateActionType), false);
Expand All @@ -80,6 +84,7 @@ std::string UpdateContextRequest::toJsonV1(bool asJsonObject)
}



/* ****************************************************************************
*
* UpdateContextRequest::check -
Expand Down
3 changes: 2 additions & 1 deletion src/lib/ngsi10/UpdateContextRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ typedef struct UpdateContextRequest
ActionType updateActionType; // Mandatory

std::string contextProvider; // Not part of the payload - used internally only
ProviderFormat providerFormat; // Not part of the payload - used internally only

UpdateContextRequest();
UpdateContextRequest(const std::string& _contextProvider, Entity* eP);
UpdateContextRequest(const std::string& _contextProvider, ProviderFormat _providerFormat, Entity* eP);

std::string toJsonV1(bool asJsonObject);
std::string check(ApiVersion apiVersion, bool asJsonObject, const std::string& predetectedError);
Expand Down
Loading

0 comments on commit 2b7798d

Please sign in to comment.