/* ****************************************************************************
*
* 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;
}
Пример #2
0
/* ****************************************************************************
*
* 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;
}