コード例 #1
0
/* ****************************************************************************
*
* getSubscription -
*
* GET /v2/subscription/<id>
*
*/
std::string getSubscription
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  ngsiv2::Subscription sub;
  std::string          idSub = compV[2];
  OrionError           oe;
  std::string          out;
  std::string          err;

  if ((err = idCheck(idSub)) != "OK")
  {
    OrionError oe(SccBadRequest, err);
    return oe.render(ciP, "Invalid subscription ID");
  }

  TIMED_MONGO(mongoGetSubscription(&sub, &oe, idSub, ciP->uriParam, ciP->tenant));

  if (oe.code != SccOk)
  {
    TIMED_RENDER(out = oe.render(ciP, "Invalid subscription ID"));
    return out;
  }

  TIMED_RENDER(out = sub.toJson());
  return out;
}
コード例 #2
0
/* ****************************************************************************
*
* deleteSubscription -
*
* DELETE /v2/subscriptions/{entityId}
*
* Payload In:  None
* Payload Out: None
*
* URI parameters:
*   -
*/
std::string deleteSubscription
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  std::string                 subscriptionId =  compV[2];
  UnsubscribeContextResponse  uncr;

  // 'Fill In' UnsubscribeContextRequest
  parseDataP->uncr.res.subscriptionId.set(subscriptionId);

  TIMED_MONGO(mongoUnsubscribeContext(&parseDataP->uncr.res, &uncr, ciP->tenant));

  // Check for potential error
  std::string  answer = "";
  if (uncr.oe.code != SccNone )
  {
    TIMED_RENDER(answer = uncr.oe.toJson());
    ciP->httpStatusCode = uncr.oe.code;
  }
  else
  {
    ciP->httpStatusCode = SccNoContent;
  }

  return answer;
}
コード例 #3
0
/* ****************************************************************************
*
* patchSubscription -
*
* PATCH /v2/subscriptions/{entityId}
*
* Payload In:  None
* Payload Out: None
*
* URI parameters:
*   -
*/
std::string patchSubscription
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  std::string                        answer;
  std::string                        subscriptionId =  compV[2];
  UpdateContextSubscriptionResponse  ucsr;


  // 'Fill In' UpdateContextSubscriptionRequest
  parseDataP->ucsr.res.subscriptionId.set(subscriptionId);

  TIMED_MONGO(ciP->httpStatusCode = mongoUpdateContextSubscription(&parseDataP->ucsr.res,
                                                                   &ucsr,
                                                                   ciP->outFormat,
                                                                   ciP->tenant,
                                                                   ciP->httpHeaders.xauthToken,
                                                                   ciP->servicePathV,
                                                                   ciP->apiVersion));

  if (ciP->httpStatusCode != SccOk)
  {
    OrionError oe(ciP->httpStatusCode);

    TIMED_RENDER(answer = oe.render(ciP, ""));

    return answer;
  }
  else if (ucsr.subscribeError.errorCode.code != SccNone)
  {
    OrionError oe(ucsr.subscribeError.errorCode.code);

    ciP->httpStatusCode = ucsr.subscribeError.errorCode.code;

    oe.reasonPhrase = ucsr.subscribeError.errorCode.reasonPhrase;

    if (ucsr.subscribeError.errorCode.code == SccContextElementNotFound)
    {
      oe.details = "The requested subscription has not been found. Check id";
    }

    TIMED_RENDER(answer = oe.render(ciP, ""));

    return answer;
  }

  ciP->httpStatusCode = SccNoContent;

  return "";
}
コード例 #4
0
/* ****************************************************************************
*
* postNotifyContext -
*/
std::string postNotifyContext
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  NotifyContextResponse  ncr;
  std::string            answer;

  TIMED_MONGO(ciP->httpStatusCode = mongoNotifyContext(&parseDataP->ncr.res, &ncr, ciP->tenant, ciP->httpHeaders.xauthToken, ciP->servicePathV));
  TIMED_RENDER(answer = ncr.render(NotifyContext, ciP->outFormat, ""));

  return answer;
}
コード例 #5
0
/* ****************************************************************************
*
* postUnsubscribeContextAvailability - 
*/
std::string postUnsubscribeContextAvailability
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  UnsubscribeContextAvailabilityResponse  ucar;
  std::string                             answer;

  TIMED_MONGO(ciP->httpStatusCode = mongoUnsubscribeContextAvailability(&parseDataP->ucar.res, &ucar, ciP->tenant));
  TIMED_RENDER(answer = ucar.toJsonV1());

  return answer;
}
/* ****************************************************************************
*
* postUpdateContextAvailabilitySubscription -
*/
std::string postUpdateContextAvailabilitySubscription
(
    ConnectionInfo*            ciP,
    int                        components,
    std::vector<std::string>&  compV,
    ParseData*                 parseDataP
)
{
    UpdateContextAvailabilitySubscriptionResponse  ucas;
    std::string                                    answer;

    ucas.subscriptionId = parseDataP->ucas.res.subscriptionId;

    TIMED_MONGO(ciP->httpStatusCode = mongoUpdateContextAvailabilitySubscription(&parseDataP->ucas.res,
                                      &ucas,
                                      ciP->httpHeaders.correlator,
                                      ciP->tenant));

    TIMED_RENDER(answer = ucas.render(UpdateContextAvailabilitySubscription, "", 0));

    return answer;
}
コード例 #7
0
/* ****************************************************************************
*
* postUpdateContextSubscription - 
*/
std::string postUpdateContextSubscription
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  UpdateContextSubscriptionResponse  ucsr;
  std::string                        answer;

  ucsr.subscribeError.subscriptionId = parseDataP->ucsr.res.subscriptionId;  

  TIMED_MONGO(ciP->httpStatusCode = mongoUpdateContextSubscription(&parseDataP->ucsr.res,
                                                                   &ucsr,                                                                   
                                                                   ciP->tenant,
                                                                   ciP->httpHeaders.xauthToken,
                                                                   ciP->servicePathV));

  TIMED_RENDER(answer = ucsr.render(UpdateContextSubscription, ""));

  return answer;
}
コード例 #8
0
/* ****************************************************************************
*
* getEntityType -
*
* GET /v2/types/<entityType>
*
* Payload In:  None
* Payload Out: EntityTypeResponse
*
* URI parameters:
*   - options=noAttrDetail
*
*/
std::string getEntityType
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  EntityTypeResponse  response;
  std::string         entityTypeName = compV[2];
  std::string         answer;
  bool                noAttrDetail   = ciP->uriParamOptions[OPT_NO_ATTR_DETAIL];

  if (entityTypeName == "")
  {
    OrionError oe(SccBadRequest, EMPTY_ENTITY_TYPE, "BadRequest");
    ciP->httpStatusCode = oe.code;
    return oe.toJson();
  }

  TIMED_MONGO(mongoAttributesForEntityType(entityTypeName, &response, ciP->tenant, ciP->servicePathV, ciP->uriParam, noAttrDetail, ciP->apiVersion));

  if (response.entityType.count == 0)
  {
    OrionError oe(SccContextElementNotFound, "Entity type not found", "NotFound");
    TIMED_RENDER(answer = oe.toJson());
    ciP->httpStatusCode = oe.code;
  }
  else
  {
    TIMED_RENDER(answer = response.toJson(ciP));
  }

  response.release();

  return answer;
}
コード例 #9
0
/* ****************************************************************************
*
* postSubscribeContext - 
*
* POST /v1/subscribeContext
* POST /ngsi10/subscribeContext
*
* Payload In:  SubscribeContextRequest
* Payload Out: SubscribeContextResponse
*
* URI parameters
*   - notifyFormat=XXX    (used by mongoBackend)
*/
std::string postSubscribeContext
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  SubscribeContextResponse  scr;
  std::string               answer;

  //
  // FIXME P0: Only *one* service path is allowed for subscriptions.
  //           Personally (kz) I kind of like that. If you want additional service-paths, just add another subscription!
  //           However, we need to at least state that HERE is where we limit the number of service paths to *one*.
  //
  if (ciP->servicePathV.size() > 1)
  {
    char  noOfV[STRING_SIZE_FOR_INT];
    snprintf(noOfV, sizeof(noOfV), "%lu", ciP->servicePathV.size());
    std::string details = std::string("max *one* service-path allowed for subscriptions (") + noOfV + " given";

    alarmMgr.badInput(clientIp, details);

    scr.subscribeError.errorCode.fill(SccBadRequest, "max one service-path allowed for subscriptions");

    TIMED_RENDER(answer = scr.render(SubscribeContext, ""));
    return answer;
  }

  TIMED_MONGO(ciP->httpStatusCode = mongoSubscribeContext(&parseDataP->scr.res, &scr, ciP->tenant, ciP->uriParam, ciP->httpHeaders.xauthToken, ciP->servicePathV));
  TIMED_RENDER(answer = scr.render(SubscribeContext, ""));

  parseDataP->scr.res.release();

  return answer;
}
コード例 #10
0
/* ****************************************************************************
*
* postUpdateContext -
*
* POST /v1/updateContext
* POST /ngsi10/updateContext
*
* Payload In:  UpdateContextRequest
* Payload Out: UpdateContextResponse
*/
std::string postUpdateContext
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP,
  Ngsiv2Flavour              ngsiV2Flavour
)
{
  UpdateContextResponse*  upcrsP = &parseDataP->upcrs.res;
  UpdateContextRequest*   upcrP  = &parseDataP->upcr.res;
  std::string             answer;

  bool asJsonObject = (ciP->uriParam[URI_PARAM_ATTRIBUTE_FORMAT] == "object" && ciP->outMimeType == JSON);
  bool forcedUpdate = ciP->uriParamOptions[OPT_FORCEDUPDATE];
  //
  // 01. Check service-path consistency
  //
  // If more than ONE service-path is input, an error is returned as response.
  // If ONE service-path is issued and that service path is "", then the default service-path is used.
  // Note that by construction servicePath cannot have 0 elements
  // After these checks, the service-path is checked to be 'correct'.
  //
  if (ciP->servicePathV.size() > 1)
  {
    upcrsP->errorCode.fill(SccBadRequest, "more than one service path in context update request");
    alarmMgr.badInput(clientIp, "more than one service path for an update request");

    TIMED_RENDER(answer = upcrsP->toJsonV1(asJsonObject));
    upcrP->release();

    return answer;
  }
  else if (ciP->servicePathV[0] == "")
  {
    ciP->servicePathV[0] = SERVICE_PATH_ROOT;
  }

  std::string res = servicePathCheck(ciP->servicePathV[0].c_str());
  if (res != "OK")
  {
    upcrsP->errorCode.fill(SccBadRequest, res);

    TIMED_RENDER(answer = upcrsP->toJsonV1(asJsonObject));

    upcrP->release();
    return answer;
  }


  //
  // 02. Send the request to mongoBackend/mongoUpdateContext
  //
  upcrsP->errorCode.fill(SccOk);
  attributesToNotFound(upcrP);

  HttpStatusCode httpStatusCode;
  TIMED_MONGO(httpStatusCode = mongoUpdateContext(upcrP,
                                                  upcrsP,
                                                  ciP->tenant,
                                                  ciP->servicePathV,
                                                  ciP->uriParam,
                                                  ciP->httpHeaders.xauthToken,
                                                  ciP->httpHeaders.correlator,
                                                  ciP->httpHeaders.ngsiv2AttrsFormat,
                                                  forcedUpdate,
                                                  ciP->apiVersion,
                                                  ngsiV2Flavour));

  if (ciP->httpStatusCode != SccCreated)
  {
    ciP->httpStatusCode = httpStatusCode;
  }

  foundAndNotFoundAttributeSeparation(upcrsP, upcrP, ciP);



  //
  // 03. Normal case - no forwards
  //
  // If there is nothing to forward, just return the result
  //
  bool forwarding = forwardsPending(upcrsP);
  LM_T(LmtForward, ("forwardsPending returned %s", FT(forwarding)));
  if (forwarding == false)
  {
    TIMED_RENDER(answer = upcrsP->toJsonV1(asJsonObject));

    upcrP->release();
    return answer;
  }



  //
  // 04. mongoBackend doesn't give us the values of the attributes.
  //     So, here we have to do a search inside the initial UpdateContextRequest to fill in all the
  //     attribute-values in the output from mongoUpdateContext
  //
  for (unsigned int cerIx = 0; cerIx < upcrsP->contextElementResponseVector.size(); ++cerIx)
  {
    Entity* eP = &upcrsP->contextElementResponseVector[cerIx]->entity;

    for (unsigned int aIx = 0; aIx < eP->attributeVector.size(); ++aIx)
    {
      ContextAttribute* aP = upcrP->attributeLookup(eP, eP->attributeVector[aIx]->name);

      if (aP == NULL)
      {
        LM_E(("Internal Error (attribute '%s' not found)", eP->attributeVector[aIx]->name.c_str()));
      }
      else
      {
        eP->attributeVector[aIx]->stringValue    = aP->stringValue;
        eP->attributeVector[aIx]->numberValue    = aP->numberValue;
        eP->attributeVector[aIx]->boolValue      = aP->boolValue;
        eP->attributeVector[aIx]->valueType      = aP->valueType;
        eP->attributeVector[aIx]->compoundValueP = aP->compoundValueP == NULL ? NULL : aP->compoundValueP->clone();
      }
    }
  }


  //
  // 05. Forwards necessary - sort parts in outgoing requestV
  //     requestV is a vector of UpdateContextRequests and each Context Provider
  //     will have a slot in the vector.
  //     When a ContextElementResponse is found in the output from mongoUpdateContext, a
  //     UpdateContextRequest is to be found/created and inside that UpdateContextRequest
  //     a ContextElement for the Entity of the ContextElementResponse.
  //
  //     Non-found parts go directly to 'response'.
  //
  UpdateContextRequestVector  requestV;
  UpdateContextResponse       response;

  response.errorCode.fill(SccOk);
  for (unsigned int cerIx = 0; cerIx < upcrsP->contextElementResponseVector.size(); ++cerIx)
  {
    ContextElementResponse* cerP  = upcrsP->contextElementResponseVector[cerIx];

    if (cerP->entity.attributeVector.size() == 0)
    {
      //
      // If we find a contextElement without attributes here, then something is wrong
      //
      LM_E(("Orion Bug (empty contextAttributeVector for ContextElementResponse %d)", cerIx));
    }
    else
    {
      for (unsigned int aIx = 0; aIx < cerP->entity.attributeVector.size(); ++aIx)
      {
        ContextAttribute* aP = cerP->entity.attributeVector[aIx];

        //
        // 0. If the attribute is 'not-found' - just add the attribute to the outgoing response
        //
        if (aP->found == false)
        {
          ContextAttribute ca(aP);
          response.notFoundPush(&cerP->entity, &ca, NULL);
          continue;
        }


        //
        // 1. If the attribute is found locally - just add the attribute to the outgoing response
        //
        if (aP->providingApplication.get() == "")
        {
          ContextAttribute ca(aP);
          response.foundPush(&cerP->entity, &ca);
          continue;
        }


        //
        // 2. Lookup UpdateContextRequest in requestV according to providingApplication.
        //    If not found, add one.
        UpdateContextRequest*  reqP = requestV.lookup(aP->providingApplication.get());
        if (reqP == NULL)
        {
          reqP = new UpdateContextRequest(aP->providingApplication.get(), aP->providingApplication.providerFormat, &cerP->entity);
          reqP->updateActionType = ActionTypeUpdate;
          requestV.push_back(reqP);
        }

        //
        // 3. Lookup ContextElement in UpdateContextRequest according to EntityId.
        //    If not found, add one (to the EntityVector of the UpdateContextRequest).
        //
        Entity* eP = reqP->entityVector.lookup(cerP->entity.id, cerP->entity.type);
        if (eP == NULL)
        {
          eP = new Entity();
          eP->fill(cerP->entity.id, cerP->entity.type, cerP->entity.isPattern);
          reqP->entityVector.push_back(eP);
        }


        //
        // 4. Add ContextAttribute to the correct ContextElement in the correct UpdateContextRequest
        //
        eP->attributeVector.push_back(new ContextAttribute(aP));
      }
    }
  }


  //
  // Now we are ready to forward the Updates
  //


  //
  // Calling each of the Context Providers, merging their results into the
  // total response 'response'
  //
  bool forwardOk = true;

  for (unsigned int ix = 0; ix < requestV.size() && ix < cprForwardLimit; ++ix)
  {
    if (requestV[ix]->contextProvider == "")
    {
      LM_E(("Internal Error (empty context provider string)"));
      continue;
    }

    UpdateContextResponse upcrs;
    bool                  b;

    b = updateForward(ciP, requestV[ix], &upcrs);

    if (b == false)
    {
      forwardOk = false;
    }

    //
    // Add the result from the forwarded update to the total response in 'response'
    //
    response.merge(&upcrs);
  }

  //
  // Note this is a slight break in the separation of concerns among the different layers (i.e.
  // serviceRoutine/ logic should work in a "NGSIv1 isolated context"). However, it seems to be
  // a smart way of dealing with partial update situations
  //
  if (ciP->apiVersion == V2)
  {
    LM_T(LmtForward, ("ciP->apiVersion == V2"));
    //
    // Adjust OrionError response in the case of partial updates. This may happen in CPr forwarding
    // scenarios. Note that mongoBackend logic "splits" successfull updates and failing updates in
    // two different CER (maybe using the same entity)
    //
    std::string failing = "";
    unsigned int failures  = 0;

    LM_T(LmtForward, ("Going over a contextElementResponseVector of %d items", response.contextElementResponseVector.size()));
    for (unsigned int ix = 0; ix < response.contextElementResponseVector.size(); ++ix)
    {
      ContextElementResponse* cerP = response.contextElementResponseVector[ix];

      if (cerP->statusCode.code != SccOk)
      {
        failures++;

        std::string failingPerCer = "";
        for (unsigned int jx = 0; jx < cerP->entity.attributeVector.size(); ++jx)
        {
          failingPerCer += cerP->entity.attributeVector[jx]->name;
          if (jx != cerP->entity.attributeVector.size() - 1)
          {
            failingPerCer +=", ";
          }
        }

        failing += cerP->entity.id + "-" + cerP->entity.type + " : [" + failingPerCer + "], ";
      }
    }

    //
    // Note that we modify parseDataP->upcrs.res.oe and not response.oe, as the former is the
    // one used by the calling postBatchUpdate() function at serviceRoutineV2 library
    //
    if ((forwardOk == true) && (failures == 0))
    {
      parseDataP->upcrs.res.oe.fill(SccNone, "");
    }
    else if (failures == response.contextElementResponseVector.size())
    {
      parseDataP->upcrs.res.oe.fill(SccContextElementNotFound, ERROR_DESC_NOT_FOUND_ENTITY, ERROR_NOT_FOUND);
    }
    else if (failures > 0)
    {
      // Removing trailing ", "
      failing = failing.substr(0, failing.size() - 2);

      // If some CER (but not all) fail, then it is a partial update
      parseDataP->upcrs.res.oe.fill(SccContextElementNotFound, "Attributes that were not updated: { " + failing + " }", "PartialUpdate");
    }
    else  // failures == 0
    {
      // No failure, so invalidate any possible OrionError filled by mongoBackend on the mongoUpdateContext step
      parseDataP->upcrs.res.oe.fill(SccNone, "");
    }
  }
  else  // v1
  {
    LM_T(LmtForward, ("ciP->apiVersion != V2"));
    // Note that v2 case doesn't use an actual response (so no need to waste time rendering it).
    // We render in the v1 case only
    TIMED_RENDER(answer = response.toJsonV1(asJsonObject));
  }

  //
  // Cleanup
  //
  upcrP->release();
  requestV.release();
  upcrsP->release();
  upcrsP->fill(&response);
  response.release();

  return answer;
}