/* **************************************************************************** * * getEntityAttribute - * * GET /v2/entities/:id:/attrs/:attrName: * * Payload In: None * Payload Out: Entity Attribute * * * 01. Fill in QueryContextRequest * 02. Call standard op postQueryContext * 03. Render Entity Attribute response * 04. Cleanup and return result */ std::string getEntityAttribute ( ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP ) { std::string type = ciP->uriParam["type"]; std::string answer; Attribute attribute; if (forbiddenIdChars(ciP->apiVersion, compV[2].c_str() , NULL) || (forbiddenIdChars(ciP->apiVersion, compV[4].c_str() , NULL))) { OrionError oe(SccBadRequest, INVAL_CHAR_URI, "BadRequest"); ciP->httpStatusCode = oe.code; return oe.toJson(); } // 01. Fill in QueryContextRequest parseDataP->qcr.res.fill(compV[2], type, "false", EntityTypeEmptyOrNotEmpty, ""); parseDataP->qcr.res.metadataList.fill(ciP->uriParam[URI_PARAM_METADATA]); // 02. Call standard op postQueryContext postQueryContext(ciP, components, compV, parseDataP); // 03. Render entity attribute response attribute.fill(&parseDataP->qcrs.res, compV[4]); TIMED_RENDER(answer = attribute.render(ciP, EntityAttributeResponse)); if (attribute.oe.reasonPhrase == "TooManyResults") { ciP->httpStatusCode = SccConflict; } else if (attribute.oe.reasonPhrase == "NotFound") { ciP->httpStatusCode = SccContextElementNotFound; // Attribute to be precise! } else { // the same of the wrapped operation ciP->httpStatusCode = parseDataP->qcrs.res.errorCode.code; } // 04. Cleanup and return result parseDataP->qcr.res.release(); return answer; }
/* **************************************************************************** * * getNgsi10ContextEntityTypes - * * GET /ngsi10/contextEntityTypes/{typeName} */ std::string getNgsi10ContextEntityTypes ( ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP ) { std::string typeName = compV[2]; LM_T(LmtConvenience, ("CONVENIENCE: got a 'GET' request for entity type '%s'", typeName.c_str())); parseDataP->qcr.res.fill(".*", typeName, ""); std::string answer = postQueryContext(ciP, components, compV, parseDataP); parseDataP->qcr.res.release(); return answer; }
/* **************************************************************************** * * postBatchQuery - * * POST /v2/op/query * * Payload In: BatchQueryRequest * Payload Out: Entities * * URI parameters: * - limit=NUMBER * - offset=NUMBER * - options=count,keyValues */ std::string postBatchQuery ( ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP ) { BatchQuery* bqP = &parseDataP->bq.res; QueryContextRequest* qcrP = &parseDataP->qcr.res; Entities entities; std::string answer; qcrP->fill(bqP); bqP->release(); // qcrP just 'took over' the data from bqP, bqP no longer needed answer = postQueryContext(ciP, components, compV, parseDataP); if (ciP->httpStatusCode != SccOk) { parseDataP->qcr.res.release(); return answer; } // 03. Render Entities response if (parseDataP->qcrs.res.contextElementResponseVector.size() == 0) { ciP->httpStatusCode = SccOk; answer = "[]"; } else { entities.fill(&parseDataP->qcrs.res); TIMED_RENDER(answer = entities.render(ciP, EntitiesResponse)); } // 04. Cleanup and return result entities.release(); parseDataP->qcr.res.release(); return answer; }
/* **************************************************************************** * * getEntityAttribute - * * GET /v2/entities/:id:/attrs/:attrName: * * Payload In: None * Payload Out: Entity Attribute * * * 01. Fill in QueryContextRequest * 02. Call standard op postQueryContext * 03. Render Entity Attribute response * 04. Cleanup and return result */ std::string getEntityAttribute ( ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP ) { std::string answer; Attribute attribute; // 01. Fill in QueryContextRequest parseDataP->qcr.res.fill(compV[2], "", "false", EntityTypeEmptyOrNotEmpty, ""); // 02. Call standard op postQueryContext postQueryContext(ciP, components, compV, parseDataP); // 03. Render entity attribute response attribute.fill(&parseDataP->qcrs.res, compV[4]); answer = attribute.render(ciP, EntityAttributeResponse); if (attribute.errorCode.error == "TooManyResults") { ciP->httpStatusCode = SccConflict; } else if (attribute.errorCode.error == "NotFound") { ciP->httpStatusCode = SccContextElementNotFound; // Attribute to be precise! } else { // the same of the wrapped operation ciP->httpStatusCode = parseDataP->qcrs.res.errorCode.code; } // 04. Cleanup and return result parseDataP->qcr.res.release(); return answer; }
/* **************************************************************************** * * getEntities - * * GET /v2/entities * * Payload In: None * Payload Out: Entities * * URI parameters: * - limit=NUMBER * - offset=NUMBER * - count=true/false * * 01. Fill in QueryContextRequest * 02. Call standard op postQueryContext * 03. Render Entities response * 04. Cleanup and return result */ std::string getEntities ( ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP ) { std::string answer; Entities entities; // 01. Fill in QueryContextRequest parseDataP->qcr.res.fill(".*", "", "true", EntityTypeEmptyOrNotEmpty, ""); // 02. Call standard op postQueryContext answer = postQueryContext(ciP, components, compV, parseDataP); // 03. Render Entities response if (parseDataP->qcrs.res.contextElementResponseVector.size() == 0) { ciP->httpStatusCode = SccOk; answer = "[]"; } else { entities.fill(&parseDataP->qcrs.res); answer = entities.render(ciP, EntitiesResponse); } // 04. Cleanup and return result entities.release(); parseDataP->qcr.res.release(); return answer; }
/* **************************************************************************** * * getIndividualContextEntityAttributeWithTypeAndId - * * GET /v1/contextEntities/type/{entity::type}/id/{entity::id}/attributes/{attribute::name} * * Payload In: None * Payload Out: ContextAttributeResponse * * URI parameters: * - attributesFormat=object * - entity::type=XXX (must coincide with entity::type in URL) * - !exist=entity::type (if set - error -- entity::type cannot be empty) * - exist=entity::type (not supported - ok if present, ok if not present ...) * * 01. Get values from URL (entityId::type, esist, !exist) * 02. Check validity of URI params * 03. Fill in QueryContextRequest * 04. Call standard operation postQueryContext * 05. If 404 Not Found - enter request info into response context element * 06. Translate QueryContextResponse to ContextElementResponse * 07. Cleanup and return result */ std::string getIndividualContextEntityAttributeWithTypeAndId ( ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP ) { std::string answer; std::string entityType = compV[3]; std::string entityId = compV[5]; std::string attributeName = compV[7]; std::string entityTypeFromUriParam = ciP->uriParam[URI_PARAM_ENTITY_TYPE]; EntityTypeInfo typeInfo = EntityTypeEmptyOrNotEmpty; ContextAttributeResponse response; // 01. Get values from URL (entityId::type, esist, !exist) if (ciP->uriParam[URI_PARAM_NOT_EXIST] == URI_PARAM_ENTITY_TYPE) { typeInfo = EntityTypeEmpty; } else if (ciP->uriParam[URI_PARAM_EXIST] == URI_PARAM_ENTITY_TYPE) { typeInfo = EntityTypeNotEmpty; } // // 02. Check validity of URI params ... // and if OK; // 03. Fill in QueryContextRequest // 04. Call standard operation postQueryContext // 05. If 404 Not Found - enter request info into response context element // if (typeInfo == EntityTypeEmpty) { parseDataP->qcrs.res.errorCode.fill(SccBadRequest, "entity::type cannot be empty for this request"); LM_W(("Bad Input (entity::type cannot be empty for this request)")); } else if ((entityTypeFromUriParam != entityType) && (entityTypeFromUriParam != "")) { parseDataP->qcrs.res.errorCode.fill(SccBadRequest, "non-matching entity::types in URL"); LM_W(("Bad Input non-matching entity::types in URL")); } else { // 03. Fill in QueryContextRequest parseDataP->qcr.res.fill(entityId, entityType, attributeName); // 04. Call standard operation postQueryContext parseDataP->qcrs.res.errorCode.fill(SccOk); postQueryContext(ciP, components, compV, parseDataP); // 05. If 404 Not Found - enter request info into response context element if (parseDataP->qcrs.res.errorCode.code == SccContextElementNotFound) { response.statusCode.details = "entityId::type/attribute::name pair not found"; } } // 06. Translate QueryContextResponse to ContextAttributeResponse response.fill(&parseDataP->qcrs.res, entityId, entityType, attributeName, ""); // 07. Cleanup and return result TIMED_RENDER(answer = response.render(ciP, RtContextAttributeResponse, "")); parseDataP->qcr.res.release(); parseDataP->qcrs.res.release(); response.release(); return answer; }
/* **************************************************************************** * * getEntityAttributeValue - * * GET /v2/entities/:id:/attrs/:attrName: * * Payload In: None * Payload Out: Entity Attribute * */ std::string getEntityAttributeValue ( ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP ) { std::string answer; Attribute attribute; bool text = (ciP->uriParam["options"] == "text" || ciP->outFormat == TEXT); // Fill in QueryContextRequest parseDataP->qcr.res.fill(compV[2], "", "false", EntityTypeEmptyOrNotEmpty, ""); // Call standard op postQueryContext postQueryContext(ciP, components, compV, parseDataP); attribute.fill(&parseDataP->qcrs.res, compV[4]); // Render entity attribute response if (attribute.errorCode.error == "TooManyResults") { ciP->httpStatusCode = SccConflict; TIMED_RENDER(answer = attribute.render(ciP, EntityAttributeResponse)); } else if (attribute.errorCode.error == "NotFound") { ciP->httpStatusCode = SccContextElementNotFound; TIMED_RENDER(answer = attribute.render(ciP, EntityAttributeResponse)); } else { // the same of the wrapped operation ciP->httpStatusCode = parseDataP->qcrs.res.errorCode.code; // Remove unwanted fields from attribute before rendering attribute.pcontextAttribute->type = ""; attribute.pcontextAttribute->metadataVector.release(); if (!text) { // Do not use attribute name, change to 'value' attribute.pcontextAttribute->name = "value"; TIMED_RENDER(answer = attribute.render(ciP, EntityAttributeResponse)); } else { if (attribute.pcontextAttribute->compoundValueP != NULL) { TIMED_RENDER(answer = attribute.pcontextAttribute->compoundValueP->render(ciP, JSON, "")); if (attribute.pcontextAttribute->compoundValueP->isObject()) { answer = "{" + answer + "}"; } else if (attribute.pcontextAttribute->compoundValueP->isVector()) { answer = "[" + answer + "]"; } } else { TIMED_RENDER(answer = attribute.pcontextAttribute->toStringValue()); } ciP->outFormat = TEXT; } } // Cleanup and return result parseDataP->qcr.res.release(); return answer; }
/* **************************************************************************** * * getEntity - * * GET /v2/entities/:id:[?attrs=:list:] * * Payload In: None * Payload Out: Entity * * * Fill in QueryContextRequest * Call standard op postQueryContext * Render Entity response * Cleanup and return result */ std::string getEntity ( ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP ) { std::string attrs = ciP->uriParam["attrs"]; std::string type = ciP->uriParam["type"]; if (forbiddenIdChars(ciP->apiVersion, compV[2].c_str() , NULL)) { OrionError oe(SccBadRequest, INVAL_CHAR_URI); return oe.render(ciP, ""); } // Fill in QueryContextRequest parseDataP->qcr.res.fill(compV[2], type, "false", EntityTypeEmptyOrNotEmpty, ""); if (attrs != "") { std::vector<std::string> attrsV; stringSplit(attrs, ',', attrsV); for (std::vector<std::string>::const_iterator it = attrsV.begin(); it != attrsV.end(); ++it) { parseDataP->qcr.res.attributeList.push_back_if_absent(*it); } } // Call standard op postQueryContext postQueryContext(ciP, components, compV, parseDataP); // Render entity response Entity entity; // If request was for /entities/<<id>>/attrs, type and id should not be shown if (compV.size() == 4 && compV[3] == "attrs") { entity.hideIdAndType(); } entity.fill(&parseDataP->qcrs.res); std::string answer; TIMED_RENDER(answer = entity.render(ciP, EntityResponse)); if (parseDataP->qcrs.res.errorCode.code == SccOk && parseDataP->qcrs.res.contextElementResponseVector.size() > 1) { // No problem found, but we expect only one entity ciP->httpStatusCode = SccConflict; } else { // the same of the wrapped operation ciP->httpStatusCode = parseDataP->qcrs.res.errorCode.code; } // 04. Cleanup and return result entity.release(); parseDataP->qcr.res.release(); return answer; }
/* **************************************************************************** * * getEntities - * * GET /v2/entities * * Payload In: None * Payload Out: Entities * * URI parameters: * - limit=NUMBER * - offset=NUMBER * - count=true/false * - id * - idPattern * - q * - geometry * - coords * * 01. Fill in QueryContextRequest * 02. Call standard op postQueryContext * 03. Render Entities response * 04. Cleanup and return result */ std::string getEntities ( ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP ) { Entities entities; std::string answer; std::string pattern = ".*"; // all entities, default value std::string id = ciP->uriParam["id"]; std::string idPattern = ciP->uriParam["idPattern"]; std::string q = ciP->uriParam["q"]; std::string geometry = ciP->uriParam["geometry"]; std::string coords = ciP->uriParam["coords"]; std::string out; if ((idPattern != "") && (id != "")) { OrionError oe(SccBadRequest, "Incompatible parameters: id, IdPattern"); TIMED_RENDER(answer = oe.render(ciP, "")); return answer; } else if (id != "") { // FIXME: a more efficient query could be possible ... std::vector<std::string> idsV; stringSplit(id, ',', idsV); for (unsigned int ix = 0; ix != idsV.size(); ++ix) { if (ix != 0) { pattern += "|"; } pattern += idsV[ix]; } } else if (idPattern != "") { pattern = idPattern; } // Making sure geometry and coords are not used individually if ((coords != "") && (geometry == "")) { OrionError oe(SccBadRequest, "URI param /coords/ used without /geometry/"); TIMED_RENDER(out = oe.render(ciP, "")); return out; } else if ((geometry != "") && (coords == "")) { OrionError oe(SccBadRequest, "URI param /geometry/ used without /coords/"); TIMED_RENDER(out = oe.render(ciP, "")); return out; } // Making sure geometry is valid (if present) orion::Geometry geo; std::vector<std::string> coordsV; if (geometry != "") { std::string errorString; if (geo.parse(geometry.c_str(), &errorString) != 0) { OrionError oe(SccBadRequest, std::string("error parsing geometry: ") + errorString); TIMED_RENDER(out = oe.render(ciP, "")); return out; } if ((geo.areaType != "polygon") && (geo.areaType != "circle")) { OrionError oe(SccBadRequest, "URI param /geometry/ must be either /polygon/ or /circle/"); TIMED_RENDER(out = oe.render(ciP, "")); return out; } // // As 'geometry' is present, so is 'coords' - checking coords // int noOfCoords = stringSplit(coords, ';', coordsV); if (noOfCoords == 0) { OrionError oe(SccBadRequest, "URI param /coords/ has no coordinates"); TIMED_RENDER(out = oe.render(ciP, "")); return out; } if ((geo.areaType == "circle") && (noOfCoords != 1)) { OrionError oe(SccBadRequest, "Too many coordinates for circle"); TIMED_RENDER(out = oe.render(ciP, "")); return out; } if ((geo.areaType == "polygon") && (noOfCoords < 3)) { OrionError oe(SccBadRequest, "Too few coordinates for polygon"); TIMED_RENDER(out = oe.render(ciP, "")); return out; } } // // 01. Fill in QueryContextRequest - type "" is valid for all types // parseDataP->qcr.res.fill(pattern, ciP->uriParam["type"], "true", EntityTypeEmptyOrNotEmpty, ""); // If URI param 'q' is given, its value must be put in a scope if (q != "") { Scope* scopeP = new Scope(SCOPE_TYPE_SIMPLE_QUERY, q); parseDataP->qcr.res.restriction.scopeVector.push_back(scopeP); } // If URI params 'geometry' and 'coords' are given, another scope is to be created for this if ((coords != "") && (geometry != "")) { Scope* scopeP = new Scope(SCOPE_TYPE_LOCATION, ""); std::string errorString; if (scopeP->fill(&geo, coordsV, &errorString) != 0) { OrionError oe(SccBadRequest, errorString); TIMED_RENDER(out = oe.render(ciP, "")); return out; } parseDataP->qcr.res.restriction.scopeVector.push_back(scopeP); } // 02. Call standard op postQueryContext answer = postQueryContext(ciP, components, compV, parseDataP); if (ciP->httpStatusCode != SccOk) { // Something went wrong in the query, an invalid pattern for example parseDataP->qcr.res.release(); return answer; } // 03. Render Entities response if (parseDataP->qcrs.res.contextElementResponseVector.size() == 0) { ciP->httpStatusCode = SccOk; answer = "[]"; } else { entities.fill(&parseDataP->qcrs.res); TIMED_RENDER(answer = entities.render(ciP, EntitiesResponse)); } // 04. Cleanup and return result entities.release(); parseDataP->qcr.res.release(); return answer; }
/* **************************************************************************** * * getNgsi10ContextEntityTypes - * * GET /v1/contextEntityTypes/{entity::type} * GET /ngsi10/contextEntityTypes/{entity::type} * * Payload In: None * Payload Out: QueryContextResponse * * URI parameters: * - attributesFormat=object * - entity::type=XXX (must coincide with entity::type in URL) * - !exist=entity::type (if set - error -- entity::type cannot be empty) * - exist=entity::type (not supported - ok if present, ok if not present ...) * * 01. Get values from URL (entityId::type, esist, !exist) * 02. Check validity of URI params * 03. Fill in QueryContextRequest * 04. Call standard operation postQueryContext (that renders the QueryContextResponse) * 05. If 404 Not Found - enter request entityId::type into response context element * 06. Cleanup and return result */ std::string getNgsi10ContextEntityTypes ( ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP ) { std::string answer; std::string typeName = compV[2]; EntityTypeInfo typeInfo = EntityTypeEmptyOrNotEmpty; std::string typeNameFromUriParam = ciP->uriParam[URI_PARAM_ENTITY_TYPE]; // 01. Get values from URL (entityId::type, esist, !exist) if (ciP->uriParam[URI_PARAM_NOT_EXIST] == URI_PARAM_ENTITY_TYPE) { typeInfo = EntityTypeEmpty; } else if (ciP->uriParam[URI_PARAM_EXIST] == URI_PARAM_ENTITY_TYPE) { typeInfo = EntityTypeNotEmpty; } // 02. Check validity of URI params if (typeInfo == EntityTypeEmpty) { parseDataP->qcrs.res.errorCode.fill(SccBadRequest, "entity::type cannot be empty for this request"); LM_W(("Bad Input (entity::type cannot be empty for this request)")); TIMED_RENDER(answer = parseDataP->qcrs.res.render(ciP, Ngsi10ContextEntityTypes, "")); parseDataP->qcr.res.release(); return answer; } else if ((typeNameFromUriParam != typeName) && (typeNameFromUriParam != "")) { parseDataP->qcrs.res.errorCode.fill(SccBadRequest, "non-matching entity::types in URL"); LM_W(("Bad Input non-matching entity::types in URL")); TIMED_RENDER(answer = parseDataP->qcrs.res.render(ciP, Ngsi10ContextEntityTypes, "")); parseDataP->qcr.res.release(); return answer; } // 03. Fill in QueryContextRequest parseDataP->qcr.res.fill(".*", typeName, ""); // 04. Call standard operation postQueryContext (that renders the QueryContextResponse) answer = postQueryContext(ciP, components, compV, parseDataP); // 05. If 404 Not Found - enter request entityId::type into response context element if (parseDataP->qcrs.res.errorCode.code == SccContextElementNotFound) { parseDataP->qcrs.res.errorCode.details = std::string("entityId::type /") + typeName + "/ non-existent"; TIMED_RENDER(answer = parseDataP->qcrs.res.render(ciP, Ngsi10ContextEntityTypes, "")); } // 06. Cleanup and return result parseDataP->qcr.res.release(); return answer; }