/* **************************************************************************** * * processRegisterContext - * * This function has a slightly different behaviour depending on whether the id * parameter is null (new registration case) or not null (update case), in * particular: * * - In the new registration case, the _id is generated and insert() is used to * put the document in the DB. * - In the update case, the _id is set according to the argument 'id' and update() is * used to put the document in the DB. * */ HttpStatusCode processRegisterContext ( RegisterContextRequest* requestP, RegisterContextResponse* responseP, OID* id, const std::string& tenant, const std::string& servicePath, const std::string& format ) { std::string err; /* If expiration is not present, then use a default one */ if (requestP->duration.isEmpty()) { requestP->duration.set(DEFAULT_DURATION); } /* Calculate expiration (using the current time and the duration field in the request) */ long long expiration = getCurrentTime() + requestP->duration.parse(); LM_T(LmtMongo, ("Registration expiration: %lu", expiration)); /* Create the mongoDB registration document */ BSONObjBuilder reg; OID oid; if (id == NULL) { oid.init(); } else { oid = *id; } reg.append("_id", oid); reg.append(REG_EXPIRATION, expiration); reg.append(REG_SERVICE_PATH, servicePath); reg.append(REG_FORMAT, format); // // We accumulate the subscriptions in a map. The key of the map is the string representing // subscription id // std::map<string, TriggeredSubscription*> subsToNotify; // This vector is used to define which entities to include in notifications EntityIdVector triggerEntitiesV; BSONArrayBuilder contextRegistration; for (unsigned int ix = 0; ix < requestP->contextRegistrationVector.size(); ++ix) { ContextRegistration* cr = requestP->contextRegistrationVector.get(ix); BSONArrayBuilder entities; for (unsigned int jx = 0; jx < cr->entityIdVector.size(); ++jx) { EntityId* en = cr->entityIdVector.get(jx); triggerEntitiesV.push_back(en); if (en->type == "") { entities.append(BSON(REG_ENTITY_ID << en->id)); LM_T(LmtMongo, ("Entity registration: {id: %s}", en->id.c_str())); } else { entities.append(BSON(REG_ENTITY_ID << en->id << REG_ENTITY_TYPE << en->type)); LM_T(LmtMongo, ("Entity registration: {id: %s, type: %s}", en->id.c_str(), en->type.c_str())); } } BSONArrayBuilder attrs; for (unsigned int jx = 0; jx < cr->contextRegistrationAttributeVector.size(); ++jx) { ContextRegistrationAttribute* cra = cr->contextRegistrationAttributeVector.get(jx); attrs.append(BSON(REG_ATTRS_NAME << cra->name << REG_ATTRS_TYPE << cra->type << "isDomain" << cra->isDomain)); LM_T(LmtMongo, ("Attribute registration: {name: %s, type: %s, isDomain: %s}", cra->name.c_str(), cra->type.c_str(), cra->isDomain.c_str())); for (unsigned int kx = 0; kx < requestP->contextRegistrationVector[ix]->contextRegistrationAttributeVector[jx]->metadataVector.size(); ++kx) { // FIXME: metadata not supported at the moment } } contextRegistration.append( BSON( REG_ENTITIES << entities.arr() << REG_ATTRS << attrs.arr() << REG_PROVIDING_APPLICATION << requestP->contextRegistrationVector.get(ix)->providingApplication.get())); LM_T(LmtMongo, ("providingApplication registration: %s", requestP->contextRegistrationVector.get(ix)->providingApplication.c_str())); std::string err; if (!addTriggeredSubscriptions(*cr, subsToNotify, err, tenant)) { responseP->errorCode.fill(SccReceiverInternalError, err); return SccOk; } } reg.append(REG_CONTEXT_REGISTRATION, contextRegistration.arr()); /* Note we are using upsert = "true". This means that if the document doesn't previously * exist in the collection, it is created. Thus, this way both uses of registerContext are OK * (either new registration or updating an existing one) */ if (!collectionUpdate(getRegistrationsCollectionName(tenant), BSON("_id" << oid), reg.obj(), true, &err)) { responseP->errorCode.fill(SccReceiverInternalError, err); releaseTriggeredSubscriptions(subsToNotify); return SccOk; } // // Send notifications for each one of the subscriptions accumulated by // previous addTriggeredSubscriptions() invocations // processSubscriptions(triggerEntitiesV, subsToNotify, err, tenant); // Fill the response element responseP->duration = requestP->duration; responseP->registrationId.set(oid.toString()); responseP->errorCode.fill(SccOk); return SccOk; }
/* **************************************************************************** * * processRegisterContext - * * This function has a slightly different behaviour depending on whether the id * parameter is null (new registration case) or not null (update case), in * particular: * * - In the new registration case, the _id is generated and insert() is used to * put the document in the DB. * - In the update case, the _id is set according to the argument 'id' and update() is * used to put the document in the DB. * */ HttpStatusCode processRegisterContext ( RegisterContextRequest* requestP, RegisterContextResponse* responseP, OID* id, const std::string& tenant, const std::string& servicePath, const std::string& format ) { DBClientBase* connection = NULL; /* If expiration is not present, then use a default one */ if (requestP->duration.isEmpty()) { requestP->duration.set(DEFAULT_DURATION); } /* Calculate expiration (using the current time and the duration field in the request) */ long long expiration = getCurrentTime() + requestP->duration.parse(); LM_T(LmtMongo, ("Registration expiration: %lu", expiration)); /* Create the mongoDB registration document */ BSONObjBuilder reg; OID oid; if (id == NULL) { oid.init(); } else { oid = *id; } reg.append("_id", oid); reg.append(REG_EXPIRATION, expiration); reg.append(REG_SERVICE_PATH, servicePath); reg.append(REG_FORMAT, format); /* We accumulate the subscriptions in a map. The key of the map is the string representing * subscription id */ std::map<string, TriggeredSubscription*> subsToNotify; /* This vector is used to define which entities to include in notifications */ EntityIdVector triggerEntitiesV; BSONArrayBuilder contextRegistration; for (unsigned int ix = 0; ix < requestP->contextRegistrationVector.size(); ++ix) { ContextRegistration* cr = requestP->contextRegistrationVector.get(ix); BSONArrayBuilder entities; for (unsigned int jx = 0; jx < cr->entityIdVector.size(); ++jx) { EntityId* en = cr->entityIdVector.get(jx); triggerEntitiesV.push_back(en); if (en->type == "") { entities.append(BSON(REG_ENTITY_ID << en->id)); LM_T(LmtMongo, ("Entity registration: {id: %s}", en->id.c_str())); } else { entities.append(BSON(REG_ENTITY_ID << en->id << REG_ENTITY_TYPE << en->type)); LM_T(LmtMongo, ("Entity registration: {id: %s, type: %s}", en->id.c_str(), en->type.c_str())); } } BSONArrayBuilder attrs; for (unsigned int jx = 0; jx < cr->contextRegistrationAttributeVector.size(); ++jx) { ContextRegistrationAttribute* cra = cr->contextRegistrationAttributeVector.get(jx); attrs.append(BSON(REG_ATTRS_NAME << cra->name << REG_ATTRS_TYPE << cra->type << "isDomain" << cra->isDomain)); LM_T(LmtMongo, ("Attribute registration: {name: %s, type: %s, isDomain: %s}", cra->name.c_str(), cra->type.c_str(), cra->isDomain.c_str())); for (unsigned int kx = 0; kx < requestP->contextRegistrationVector.get(ix)->contextRegistrationAttributeVector.get(jx)->metadataVector.size(); ++kx) { // FIXME: metadata not supported at the moment } } contextRegistration.append(BSON( REG_ENTITIES << entities.arr() << REG_ATTRS << attrs.arr() << REG_PROVIDING_APPLICATION << requestP->contextRegistrationVector.get(ix)->providingApplication.get()) ); LM_T(LmtMongo, ("providingApplication registration: %s", requestP->contextRegistrationVector.get(ix)->providingApplication.c_str())); std::string err; if (!processAssociations(cr->registrationMetadataVector, &err, tenant)) { responseP->errorCode.fill(SccReceiverInternalError); return SccOk; } if (!addTriggeredSubscriptions(*cr, subsToNotify, err, tenant)) { responseP->errorCode.fill(SccReceiverInternalError, err); return SccOk; } } reg.append(REG_CONTEXT_REGISTRATION, contextRegistration.arr()); BSONObj regDoc = reg.obj(); LM_T(LmtMongo, ("upsert update() in '%s' collection: '%s'", getRegistrationsCollectionName(tenant).c_str(), regDoc.toString().c_str())); try { connection = getMongoConnection(); /* Note the fourth parameter is set to "true". This means "upsert", so if the document doesn't previously * exist in the collection, it is created. Thus, this way is ok with both uses of * registerContext (either new registration or updating an existing one) */ connection->update(getRegistrationsCollectionName(tenant).c_str(), BSON("_id" << oid), regDoc, true); releaseMongoConnection(connection); LM_I(("Database Operation Successful (_id: %s)", oid.toString().c_str())); } catch (const DBException& e) { releaseMongoConnection(connection); responseP->errorCode.fill(SccReceiverInternalError, std::string("collection: ") + getRegistrationsCollectionName(tenant).c_str() + " - upsert update(): " + regDoc.toString() + " - exception: " + e.what()); LM_E(("Database Error (%s)", responseP->errorCode.reasonPhrase.c_str())); releaseTriggeredSubscriptions(subsToNotify); return SccOk; } catch (...) { releaseMongoConnection(connection); responseP->errorCode.fill(SccReceiverInternalError, std::string("collection: ") + getRegistrationsCollectionName(tenant).c_str() + " - upsert update(): " + regDoc.toString() + " - exception: " + "generic"); LM_E(("Database Error (%s)", responseP->errorCode.reasonPhrase.c_str())); releaseTriggeredSubscriptions(subsToNotify); return SccOk; } /* Send notifications for each one of the subscriptions accumulated by * previous addTriggeredSubscriptions() invocations */ std::string err; processSubscriptions(triggerEntitiesV, subsToNotify, err, tenant); /* Fill the response element */ responseP->duration = requestP->duration; responseP->registrationId.set(oid.toString()); responseP->errorCode.fill(SccOk); return SccOk; }