/* **************************************************************************** * * ContextElementResponse::ContextElementResponse - * * This constructor builds the CER object based in a BSON object taken from the * entities collection at DB. * * Note that statusCode is not touched by this constructor. */ ContextElementResponse::ContextElementResponse(const mongo::BSONObj& entityDoc, const AttributeList& attrL, bool includeEmpty) { prune = false; // Entity BSONObj id = getField(entityDoc, "_id").embeddedObject(); contextElement.entityId.fill(getStringField(id, ENT_ENTITY_ID), getStringField(id, ENT_ENTITY_TYPE), "false"); contextElement.entityId.servicePath = id.hasField(ENT_SERVICE_PATH) ? getStringField(id, ENT_SERVICE_PATH) : ""; /* Get the location attribute (if it exists) */ std::string locAttr; if (entityDoc.hasElement(ENT_LOCATION)) { locAttr = getStringField(getObjectField(entityDoc, ENT_LOCATION), ENT_LOCATION_ATTRNAME); } // // Attribute vector // FIXME P5: constructor for BSONObj could be added to ContextAttributeVector/ContextAttribute classes, to make building more modular // BSONObj attrs = getField(entityDoc, ENT_ATTRS).embeddedObject(); std::set<std::string> attrNames; attrs.getFieldNames(attrNames); for (std::set<std::string>::iterator i = attrNames.begin(); i != attrNames.end(); ++i) { std::string attrName = *i; BSONObj attr = getField(attrs, attrName).embeddedObject(); ContextAttribute* caP = NULL; ContextAttribute ca; // Name and type ca.name = dbDotDecode(basePart(attrName)); std::string mdId = idPart(attrName); ca.type = getStringField(attr, ENT_ATTRS_TYPE); // Skip attribute if the attribute is in the list (or attrL is empty) if (!includedAttribute(ca, attrL)) { continue; } /* It could happen (although very rarely) that the value field is missing in the * DB for the attribute. The following is a safety check measure to protect against that */ if (!attr.hasField(ENT_ATTRS_VALUE)) { caP = new ContextAttribute(ca.name, ca.type, ""); } else { switch(getField(attr, ENT_ATTRS_VALUE).type()) { case String: ca.stringValue = getStringField(attr, ENT_ATTRS_VALUE); if (!includeEmpty && ca.stringValue.length() == 0) { continue; } caP = new ContextAttribute(ca.name, ca.type, ca.stringValue); break; case NumberDouble: ca.numberValue = getField(attr, ENT_ATTRS_VALUE).Number(); caP = new ContextAttribute(ca.name, ca.type, ca.numberValue); break; case NumberInt: ca.numberValue = (double) getIntField(attr, ENT_ATTRS_VALUE); caP = new ContextAttribute(ca.name, ca.type, ca.numberValue); break; case Bool: ca.boolValue = getBoolField(attr, ENT_ATTRS_VALUE); caP = new ContextAttribute(ca.name, ca.type, ca.boolValue); break; case jstNULL: caP = new ContextAttribute(ca.name, ca.type, ""); caP->valueType = orion::ValueTypeNone; break; case Object: caP = new ContextAttribute(ca.name, ca.type, ""); caP->compoundValueP = new orion::CompoundValueNode(orion::ValueTypeObject); compoundObjectResponse(caP->compoundValueP, getField(attr, ENT_ATTRS_VALUE)); break; case Array: caP = new ContextAttribute(ca.name, ca.type, ""); caP->compoundValueP = new orion::CompoundValueNode(orion::ValueTypeVector); compoundVectorResponse(caP->compoundValueP, getField(attr, ENT_ATTRS_VALUE)); break; default: LM_E(("Runtime Error (unknown attribute value type in DB: %d)", getField(attr, ENT_ATTRS_VALUE).type())); } } /* Setting ID (if found) */ if (mdId != "") { Metadata* md = new Metadata(NGSI_MD_ID, "string", mdId); caP->metadataVector.push_back(md); } /* Setting location metatda (if found) */ if (locAttr == ca.name) { Metadata* md = new Metadata(NGSI_MD_LOCATION, "string", LOCATION_WGS84); caP->metadataVector.push_back(md); } /* Setting custom metadata (if any) */ if (attr.hasField(ENT_ATTRS_MD)) { std::vector<BSONElement> metadataV = getField(attr, ENT_ATTRS_MD).Array(); for (unsigned int ix = 0; ix < metadataV.size(); ++ix) { Metadata* md = new Metadata(metadataV[ix].embeddedObject()); caP->metadataVector.push_back(md); } } contextElement.contextAttributeVector.push_back(caP); } }
/* **************************************************************************** * * ContextElementResponse::ContextElementResponse - * * This constructor builds the CER object based in a BSON object taken from the * entities collection at DB. * * Note that statusCode is not touched by this constructor. */ ContextElementResponse::ContextElementResponse ( const mongo::BSONObj& entityDoc, const AttributeList& attrL, bool includeEmpty, const std::string& apiVersion ) { prune = false; // Entity BSONObj id = getFieldF(entityDoc, "_id").embeddedObject(); std::string entityId = getStringFieldF(id, ENT_ENTITY_ID); std::string entityType = id.hasField(ENT_ENTITY_TYPE) ? getStringFieldF(id, ENT_ENTITY_TYPE) : ""; contextElement.entityId.fill(entityId, entityType, "false"); contextElement.entityId.servicePath = id.hasField(ENT_SERVICE_PATH) ? getStringFieldF(id, ENT_SERVICE_PATH) : ""; /* Get the location attribute (if it exists) */ std::string locAttr; if (entityDoc.hasElement(ENT_LOCATION)) { locAttr = getStringFieldF(getObjectFieldF(entityDoc, ENT_LOCATION), ENT_LOCATION_ATTRNAME); } // // Attribute vector // FIXME P5: constructor for BSONObj could be added to ContextAttributeVector/ContextAttribute classes, to make building more modular // BSONObj attrs = getObjectFieldF(entityDoc, ENT_ATTRS); std::set<std::string> attrNames; attrs.getFieldNames(attrNames); for (std::set<std::string>::iterator i = attrNames.begin(); i != attrNames.end(); ++i) { std::string attrName = *i; BSONObj attr = getObjectFieldF(attrs, attrName); ContextAttribute* caP = NULL; ContextAttribute ca; // Name and type ca.name = dbDotDecode(basePart(attrName)); std::string mdId = idPart(attrName); ca.type = getStringFieldF(attr, ENT_ATTRS_TYPE); // Skip attribute if the attribute is in the list (or attrL is empty or includes "*") if (!includedAttribute(ca, attrL)) { continue; } /* It could happen (although very rarely) that the value field is missing in the * DB for the attribute. The following is a safety check measure to protect against that */ if (!attr.hasField(ENT_ATTRS_VALUE)) { caP = new ContextAttribute(ca.name, ca.type, ""); } else { switch(getFieldF(attr, ENT_ATTRS_VALUE).type()) { case String: ca.stringValue = getStringFieldF(attr, ENT_ATTRS_VALUE); if (!includeEmpty && ca.stringValue.length() == 0) { continue; } caP = new ContextAttribute(ca.name, ca.type, ca.stringValue); break; case NumberDouble: ca.numberValue = getNumberFieldF(attr, ENT_ATTRS_VALUE); caP = new ContextAttribute(ca.name, ca.type, ca.numberValue); break; case NumberInt: ca.numberValue = (double) getIntFieldF(attr, ENT_ATTRS_VALUE); caP = new ContextAttribute(ca.name, ca.type, ca.numberValue); break; case Bool: ca.boolValue = getBoolFieldF(attr, ENT_ATTRS_VALUE); caP = new ContextAttribute(ca.name, ca.type, ca.boolValue); break; case jstNULL: caP = new ContextAttribute(ca.name, ca.type, ""); caP->valueType = orion::ValueTypeNone; break; case Object: caP = new ContextAttribute(ca.name, ca.type, ""); caP->compoundValueP = new orion::CompoundValueNode(orion::ValueTypeObject); caP->valueType = orion::ValueTypeObject; compoundObjectResponse(caP->compoundValueP, getFieldF(attr, ENT_ATTRS_VALUE)); break; case Array: caP = new ContextAttribute(ca.name, ca.type, ""); caP->compoundValueP = new orion::CompoundValueNode(orion::ValueTypeVector); // FIXME P7: next line is counterintuitive. If the object is a vector, why // we need to use ValueTypeObject here? Because otherwise Metadata::toJson() // method doesn't work. A littely crazy... it should be fixed. caP->valueType = orion::ValueTypeObject; compoundVectorResponse(caP->compoundValueP, getFieldF(attr, ENT_ATTRS_VALUE)); break; default: LM_E(("Runtime Error (unknown attribute value type in DB: %d)", getFieldF(attr, ENT_ATTRS_VALUE).type())); } } /* Setting ID (if found) */ if (mdId != "") { Metadata* md = new Metadata(NGSI_MD_ID, "string", mdId); caP->metadataVector.push_back(md); } if (apiVersion == "v1") { /* Setting location metadata (if found) */ if ((locAttr == ca.name) && (ca.type != GEO_POINT)) { /* Note that if attribute type is geo:point then the user is using the "new way" * of locating entities in NGSIv1, thus location metadata is not rendered */ Metadata* md = new Metadata(NGSI_MD_LOCATION, "string", LOCATION_WGS84); caP->metadataVector.push_back(md); } } /* Setting custom metadata (if any) */ if (attr.hasField(ENT_ATTRS_MD)) { BSONObj mds = getObjectFieldF(attr, ENT_ATTRS_MD); std::set<std::string> mdsSet; mds.getFieldNames(mdsSet); for (std::set<std::string>::iterator i = mdsSet.begin(); i != mdsSet.end(); ++i) { std::string currentMd = *i; Metadata* md = new Metadata(dbDotDecode(currentMd), getObjectFieldF(mds, currentMd)); caP->metadataVector.push_back(md); } } /* Set creDate and modDate at attribute level */ if (attr.hasField(ENT_ATTRS_CREATION_DATE)) { caP->creDate = (double) getIntOrLongFieldAsLongF(attr, ENT_ATTRS_CREATION_DATE); } if (attr.hasField(ENT_ATTRS_MODIFICATION_DATE)) { caP->modDate = (double) getIntOrLongFieldAsLongF(attr, ENT_ATTRS_MODIFICATION_DATE); } contextElement.contextAttributeVector.push_back(caP); } /* Set creDate and modDate at entity level */ if (entityDoc.hasField(ENT_CREATION_DATE)) { contextElement.entityId.creDate = (double) getIntOrLongFieldAsLongF(entityDoc, ENT_CREATION_DATE); } if (entityDoc.hasField(ENT_MODIFICATION_DATE)) { contextElement.entityId.modDate = (double) getIntOrLongFieldAsLongF(entityDoc, ENT_MODIFICATION_DATE); } }