/* **************************************************************************** * * mongoQueryContext - * * NOTE * If the in/out-parameter countP is non-NULL then the number of matching entities * must be returned in *countP. * * This replaces the 'uriParams[URI_PARAM_PAGINATION_DETAILS]' way of passing this information. * The old method was one-way, using the new method */ HttpStatusCode mongoQueryContext ( QueryContextRequest* requestP, QueryContextResponse* responseP, const std::string& tenant, const std::vector<std::string>& servicePathV, std::map<std::string, std::string>& uriParams, long long* countP ) { int offset = atoi(uriParams[URI_PARAM_PAGINATION_OFFSET].c_str()); int limit = atoi(uriParams[URI_PARAM_PAGINATION_LIMIT].c_str()); std::string detailsString = uriParams[URI_PARAM_PAGINATION_DETAILS]; bool details = (strcasecmp("on", detailsString.c_str()) == 0)? true : false; LM_T(LmtMongo, ("QueryContext Request")); LM_T(LmtPagination, ("Offset: %d, Limit: %d, Details: %s", offset, limit, (details == true)? "true" : "false")); /* FIXME: restriction not supported for the moment */ if (!requestP->restriction.attributeExpression.isEmpty()) { LM_W(("Bad Input (restriction found, but restrictions are not supported by mongo backend)")); } std::string err; bool ok; bool limitReached = false; bool reqSemTaken; ContextElementResponseVector rawCerV; reqSemTake(__FUNCTION__, "ngsi10 query request", SemReadOp, &reqSemTaken); ok = entitiesQuery(requestP->entityIdVector, requestP->attributeList, requestP->restriction, &rawCerV, &err, true, tenant, servicePathV, offset, limit, &limitReached, countP); if (!ok) { responseP->errorCode.fill(SccReceiverInternalError, err); rawCerV.release(); reqSemGive(__FUNCTION__, "ngsi10 query request", reqSemTaken); return SccOk; } ContextRegistrationResponseVector crrV; /* In the case of empty response, if only generic processing is needed */ if (rawCerV.size() == 0) { if (registrationsQuery(requestP->entityIdVector, requestP->attributeList, &crrV, &err, tenant, servicePathV, 0, 0, false)) { if (crrV.size() > 0) { processGenericEntities(requestP->entityIdVector, rawCerV, crrV, limitReached); } } else { /* Different from errors in DB at entitiesQuery(), DB fails at registrationsQuery() are not considered "critical" */ LM_E(("Database Error (%s)", err.c_str())); } crrV.release(); } /* First CPr lookup (in the case some CER is not found): looking in E-A registrations */ if (someContextElementNotFound(rawCerV)) { if (registrationsQuery(requestP->entityIdVector, requestP->attributeList, &crrV, &err, tenant, servicePathV, 0, 0, false)) { if (crrV.size() > 0) { fillContextProviders(rawCerV, crrV); processGenericEntities(requestP->entityIdVector, rawCerV, crrV, limitReached); } } else { /* Different from errors in DB at entitiesQuery(), DB fails at registrationsQuery() are not considered "critical" */ LM_E(("Database Error (%s)", err.c_str())); } crrV.release(); } /* Second CPr lookup (in the case some element stills not being found): looking in E-<null> registrations */ AttributeList attrNullList; if (someContextElementNotFound(rawCerV)) { if (registrationsQuery(requestP->entityIdVector, attrNullList, &crrV, &err, tenant, servicePathV, 0, 0, false)) { if (crrV.size() > 0) { fillContextProviders(rawCerV, crrV); } } else { /* Different from errors in DB at entitiesQuery(), DB fails at registrationsQuery() are not considered "critical" */ LM_E(("Database Error (%s)", err.c_str())); } crrV.release(); } /* Special case: request with <null> attributes. In that case, entitiesQuery() may have captured some local attribute, but * the list need to be completed. Note that in the case of having this request someContextElementNotFound() is always false * so we efficient not invoking registrationQuery() too much times */ if (requestP->attributeList.size() == 0) { if (registrationsQuery(requestP->entityIdVector, requestP->attributeList, &crrV, &err, tenant, servicePathV, 0, 0, false)) { if (crrV.size() > 0) { addContextProviders(rawCerV, crrV, limitReached); } } else { /* Different from fails in DB at entitiesQuery(), DB fails at registrationsQuery() are not considered "critical" */ LM_E(("Database Error (%s)", err.c_str())); } crrV.release(); } /* Prune "not found" CERs */ pruneContextElements(rawCerV, &responseP->contextElementResponseVector); /* Pagination stuff */ if (responseP->contextElementResponseVector.size() == 0) { // If the query has an empty response, we have to fill in the status code part in the response. // // However, if the response was empty due to a too high pagination offset, // and if the user has asked for 'details' (as URI parameter, then the response should include information about // the number of hits without pagination. // if ((countP != NULL) && (*countP > 0) && (offset >= *countP)) { char details[256]; snprintf(details, sizeof(details), "Number of matching entities: %lld. Offset is %d", *countP, offset); responseP->errorCode.fill(SccContextElementNotFound, details); } else { responseP->errorCode.fill(SccContextElementNotFound); } } else if (countP != NULL) { // // If all was OK, but the details URI param was set to 'on', then the responses error code details // 'must' contain the total count of hits. // char details[64]; snprintf(details, sizeof(details), "Count: %lld", *countP); responseP->errorCode.fill(SccOk, details); } rawCerV.release(); reqSemGive(__FUNCTION__, "ngsi10 query request", reqSemTaken); return SccOk; }