Exemple #1
0
/**
 * Expands a possible CURIE string into a full IRI. If the string is not
 * recognized as a CURIE that can be expanded into an IRI, then false is
 * returned.
 *
 * @param ctx the context to use.
 * @param str the string to expand (no <>).
 * @param iri the string to store the IRI in.
 * @param usedCtx a context to update if a value was used from "ctx".
 *
 * @return true if the string was expanded, false if not.
 */
static bool _expandCurie(
   DynamicObject& ctx, const char* str, string& iri,
   DynamicObject* usedCtx = NULL)
{
   bool rval = false;

   if(!ctx.isNull())
   {
      // try to find a colon
      const char* ptr = strchr(str, ':');
      if(ptr != NULL)
      {
         // get the potential CURIE prefix
         size_t len = ptr - str + 1;
         char prefix[len];
         snprintf(prefix, len, "%s", str);

         // see if the prefix is in the context
         if(ctx->hasMember(prefix))
         {
            // prefix found, normalize string
            DynamicObject& uri = ctx[prefix];
            len = strlen(uri->getString()) + strlen(ptr + 1) + 3;
            iri = StringTools::format("%s%s", uri->getString(), ptr + 1);
            if(usedCtx != NULL)
            {
               (*usedCtx)[prefix] = uri.clone();
            }
            rval = true;
         }
      }
   }

   return rval;
}
Exemple #2
0
/* Check if a JSON-LD object is a specific type. */
static bool _isType(DynamicObject& in, const char* type)
{
   bool rval = false;

   if(in->hasMember("a"))
   {
      DynamicObject& a = in["a"];
      switch(a->getType())
      {
         case String:
         {
            rval = (a == type);
            break;
         }
         case Array:
         {
            DynamicObjectIterator i = a.getIterator();
            while(!rval && i->hasNext())
            {
               DynamicObject& next = i->next();
               rval = (next == type);
            }
            break;
         }
         default:
            break;
      }
   }

   return rval;
}
Exemple #3
0
// FIXME: should this be using new JSON-LD frame stuff rather than this?
bool JsonLd::filter(
   DynamicObject& context, DynamicObject& filter,
   DynamicObject& in, DynamicObject& out, bool simplify)
{
   bool rval;
   DynamicObject normFilter;
   DynamicObject normIn;
   DynamicObject normOut;
   normOut->setType(Map);
   // remove contexts
   rval =
      removeContext(filter, normFilter) &&
      removeContext(in, normIn);
   // filter to the output
   if(rval)
   {
      _filter(normFilter, normIn, normOut);
      // FIXME: fixup graph
      // Search normOut for unknown references that are in normIn and add them.
      // Futher optimize by checking reference count and embedding data as
      // needed. This will result in a graph that is as complete as the input
      // with regard to references.

      // flatten in the case of one result
      if(simplify && normOut->hasMember("@") && normOut["@"]->length() == 1)
      {
         normOut = normOut["@"][0];
      }
   }
   // add context to output
   rval = rval && addContext(context, normOut, out);
   return rval;
}
Exemple #4
0
/**
 * Sets a subject's predicate to the given object value. If a value already
 * exists, it will be appended to an array. If the object value is NULL, then
 * the subject's predicate will be converted to an array.
 *
 * @param s the subject.
 * @param p the predicate.
 * @param o the object, NULL to only convert s[p] to an array.
 */
static void _setPredicate(DynamicObject& s, const char* p, const char* o)
{
   // FIXME: must sort objects or keep array order?
   if(s->hasMember(p))
   {
      if(s[p]->getType() != Array)
      {
         DynamicObject tmp = s[p];
         s[p] = DynamicObject();
         s[p]->append(tmp);
      }
      if(o != NULL)
      {
         s[p]->append(o);
      }
   }
   else if(o == NULL)
   {
      s[p]->setType(Array);
   }
   else
   {
      s[p] = o;
   }
}
bool SampleService::getFileInfos(
   BtpAction* action, DynamicObject& in, DynamicObject& out,
   DynamicObject& fileInfos)
{
   bool rval;

   // do not send dyno as response
   out.setNull();

   // get catalog interface
   CatalogInterface* ci = dynamic_cast<CatalogInterface*>(
      mNode->getModuleApiByType("bitmunk.catalog"));

   // get targeted node user
   DynamicObject vars;
   action->getResourceQuery(vars);
   if(!vars->hasMember("nodeuser"))
   {
      BM_ID_SET(vars["nodeuser"], mNode->getDefaultUserId());
   }

   // get resource parameters
   DynamicObject params;
   action->getResourceParams(params);

   // populate ware bundle
   Ware ware;
   BM_ID_SET(ware["mediaId"], BM_MEDIA_ID(params[0]));
   MediaPreferenceList mpl;
   mpl[0]["preferences"][0]["contentType"] = vars["contentType"];
   mpl[0]["preferences"][0]["minBitrate"] = 1;
   // FIXME: Make sure the node user is checked against logged in user?
   if((rval = ci->populateWareBundle(
      BM_USER_ID(vars["nodeuser"]), ware, mpl)))
   {
      FileInfoIterator i = ware["fileInfos"].getIterator();
      while(i->hasNext())
      {
         FileInfo& fi = i->next();

         // FIXME: get content type for file info instead of "extension"
         const char* extension = fi["extension"]->getString();
         // FIXME: only support for mp3 audio at this time
         if(strcmp(extension, "mp3") == 0)
         {
            // get sample range for file info
            Media media;
            BM_ID_SET(media["id"], BM_MEDIA_ID(fi["mediaId"]));
            if(getSampleRange(media))
            {
               fi["media"] = media;
               fileInfos->append() = fi;
            }
         }
      }
   }

   return rval;
}
Exemple #6
0
inline static bool _isBlankNode(DynamicObject& v)
{
   // look for no subject or "<_:" or "_:" at the beginning of the subject
   return (
      !v->hasMember("@") ||
      strstr(v["@"], "<_:") == v["@"]->getString() ||
      strstr(v["@"], "_:") == v["@"]->getString());
}
Exemple #7
0
ExceptionRef Exception::convertToException(DynamicObject& dyno)
{
   ExceptionRef rval = new Exception(
      dyno["message"]->getString(),
      dyno["type"]->getString());

   if(dyno->hasMember("cause"))
   {
      ExceptionRef cause = convertToException(dyno["cause"]);
      rval->setCause(cause);
   }

   if(dyno->hasMember("details"))
   {
      *(*rval).mDetails = dyno["details"].clone();
   }

   return rval;
}
Exemple #8
0
static void _setPredicate(
   DynamicObject& s, const char* predicate, DynamicObject& object)
{
   if(s->hasMember(predicate))
   {
      s[predicate].push(object);
   }
   else
   {
      s[predicate] = object;
   }
}
Exemple #9
0
bool Map::isValid(
   DynamicObject& obj,
   ValidatorContext* context)
{
   bool rval = true;

   if(!obj.isNull() && obj->getType() == monarch::rt::Map)
   {
      Validators::iterator i;
      for(i = mValidators.begin(); i != mValidators.end(); ++i)
      {
         // only add a "." if this is not a root map
         if(context->getDepth() != 0)
         {
            context->pushPath(".");
         }
         context->pushPath(i->first);
         if(obj->hasMember(i->first))
         {
            // do not short-circuit to ensure all keys tested
            if(!i->second.validator->isValid(obj[i->first], context))
            {
               rval = false;
            }
         }
         else if(!i->second.validator->isOptional(context))
         {
            rval = false;
            DynamicObject detail =
               context->addError("monarch.validation.MissingField", &obj);
            detail["validator"] = "monarch.validator.Map";
            detail["message"] = "A required field has not been specified.";
            detail["key"] = i->first;
         }
         context->popPath();
         if(context->getDepth() > 0)
         {
            context->popPath();
         }
      }
   }
   else
   {
      rval = false;
      DynamicObject detail =
         context->addError("monarch.validation.TypeError", &obj);
      detail["validator"] = "monarch.validator.Map";
      detail["message"] = "The given object type must a mapping (Map) type";
   }

   return rval;
}
Exemple #10
0
bool Messenger::exchange(
   UserId peerId,
   Url* url, BtpMessage* out, BtpMessage* in, UserId userId, UserId agentId,
   uint32_t timeout)
{
   bool rval = true;

   if(userId != 0)
   {
      // get user profile
      ProfileRef p;
      if(!mNode->getLoginData(agentId == 0 ? userId : agentId, NULL, &p))
      {
         ExceptionRef e = new Exception(
            "Could not do BTP exchange. Not logged in.",
            "bitmunk.node.Messenger.NotLoggedIn");
         BM_ID_SET(e->getDetails()["userId"], userId);
         BM_ID_SET(e->getDetails()["agentId"], agentId);
         Exception::set(e);
         rval = false;
      }
      else if(!p.isNull())
      {
         // set user ID and profile for outgoing secure message
         out->setUserId(userId);
         out->setAgentProfile(p);

         // set public key source for incoming secure message
         in->setPublicKeySource(mNode->getPublicKeyCache());
      }
   }

   // do btp exchange
   if(rval)
   {
      // if nodeuser is set, override peer ID with it
      DynamicObject vars;
      url->getQueryVariables(vars);
      if(vars->hasMember("nodeuser"))
      {
         peerId = BM_USER_ID(vars["nodeuser"]);
      }

      rval = mClient.exchange(peerId, url, out, in, timeout);
   }

   return rval;
}
Exemple #11
0
static bool _setDecodedParam(
   Statement* s, unsigned int index,
   DynamicObject& param, DynamicObject& value)
{
   bool rval = true;

   if(param->hasMember("encode"))
   {
      // FIXME: could use streams here and handle types other than string,
      // but the DatabaseClient API might be abandoned before this actually
      // ever really gets used to that extent

      // fill byte buffer with initial data
      ByteBuffer b;
      b.put(value->getString(), value->length(), true);

      // apply each decoding
      // FIXME: optimize this by doing it once and storing it when
      // defining the schema
      DynamicObject decode = param["encode"].clone();
      decode->reverse();
      DynamicObjectIterator i = decode.getIterator();
      while(rval && i->hasNext())
      {
         const char* type = i->next()->getString();

         // convert hex to binary
         if(strcmp(type, "hex") == 0)
         {
            const char* hex = b.bytes();
            unsigned int len = b.length();
            unsigned int binLen = (len >> 1) + 1;
            char bin[binLen];
            rval = Convert::hexToBytes(hex, len, bin, binLen);
            if(rval)
            {
               b.clear();
               b.put(bin, binLen, true);
            }
         }
      }

      // only blobs are supported at the moment
      rval = rval && s->setBlob(index, b.bytes(), b.length());
   }
Exemple #12
0
static void _setEmbed(DynamicObject& s, const char* p, DynamicObject& o)
{
   // FIXME: must sort objects or keep array order?
   if(s->hasMember(p))
   {
      if(s[p]->getType() != Array)
      {
         DynamicObject tmp = s[p];
         s[p] = DynamicObject();
         s[p]->append(tmp);
      }
      s[p]->append(o);
   }
   else
   {
      s[p] = o;
   }
}
void DirectiveService::insertDirective(
   DynamicObject& cache, DynamicObject& directive)
{
   // Note: Assume cache lock is engaged.

   // get random number for ID
   char tmp[22];
   do
   {
      // get a random number between 1 and 1000000000
      uint64_t n = Random::next(1, 1000000000);
      snprintf(tmp, 22, "%" PRIu64, n);
   }
   while(cache->hasMember(tmp));

   // set directive ID and insert into cache
   directive["id"] = tmp;
   cache[tmp] = directive;
}
Exemple #14
0
// Currently just handles top level and @:[...] constructs.
static bool _findId(DynamicObject& in, const char* id, DynamicObject& out)
{
   out.setNull();

   if(in->hasMember("@"))
   {
      DynamicObject& _id = in["@"];
      switch(_id->getType())
      {
         // top level object
         case String:
         {
            if(_id == id)
            {
               out = in;
            }
            break;
         }
         // top level is blank node
         case Array:
         {
            bool found = false;
            DynamicObjectIterator i = _id.getIterator();
            while(!found && i->hasNext())
            {
               DynamicObject& next = i->next();
               if(next["@"] == id)
               {
                  out = next;
                  found = true;
               }
            }
            break;
         }
         default:
            break;
      }
   }

   return true;
}
Exemple #15
0
/**
 * Recursively removes context from the given input object.
 *
 * @param ctx the context to use (changes during recursion as necessary).
 * @param in the input object.
 * @param out the normalized output object.
 * @param bnodeId the last blank node ID used.
 *
 * @return true on success, false on failure with exception set.
 */
static bool _removeContext(
   DynamicObject& ctx, DynamicObject& in, DynamicObject& out, int& bnodeId)
{
   bool rval = true;

   if(in.isNull())
   {
      out.setNull();
   }
   else
   {
      // initialize output
      DynamicObjectType inType = in->getType();
      out->setType(inType);

      // update context
      if(inType == Map && in->hasMember("#"))
      {
         ctx = in["#"];
      }

      if(inType == Map)
      {
         rval = _normalize(ctx, in, NULL, &out, bnodeId);
      }
      else if(inType == Array)
      {
         // strip context from each object in the array
         DynamicObjectIterator i = in.getIterator();
         while(i->hasNext())
         {
            DynamicObject& next = i->next();
            rval = _removeContext(ctx, next, out->append(), bnodeId);
         }
      }
   }

   return rval;
}
Exemple #16
0
// Currently just handles top level and @:[...] constructs.
static bool _findType(DynamicObject& in, const char* type, DynamicObject& out)
{
   out->clear();

   if(in->hasMember("@"))
   {
      DynamicObject& id = in["@"];
      switch(id->getType())
      {
         // top level object
         case String:
         {
            if(_isType(in, type))
            {
               out->append(in);
            }
            break;
         }
         // top level is blank node
         case Array:
         {
            DynamicObjectIterator i = id.getIterator();
            while(i->hasNext())
            {
               DynamicObject& next = i->next();
               if(_isType(next, type))
               {
                  out->append(next);
               }
            }
            break;
         }
         default:
            break;
      }
   }

   return true;
}
Exemple #17
0
static bool _filterOne(DynamicObject& filter, DynamicObject& object)
{
   bool rval = true;

   // loop over all filter properties
   DynamicObjectIterator i;
   i = filter.getIterator();
   while(rval && i->hasNext())
   {
      DynamicObject& next = i->next();
      const char* name = i->getName();
      // check if object has property
      rval = object->hasMember(name);
      if(rval)
      {
         // loop over all filter values
         DynamicObjectIterator fpi;
         fpi = next.getIterator();
         while(rval && fpi->hasNext())
         {
            DynamicObject& fpnext = fpi->next();
            // make sure value appears in object property
            DynamicObjectIterator opi;
            opi = object[name].getIterator();
            rval = false;
            while(!rval && opi->hasNext())
            {
               DynamicObject& opnext = opi->next();
               rval = (fpnext == opnext);
            }
         }
      }
   }

   return rval;
}
void DownloadStateInitializer::runSellerPoolUpdater()
{
    // create list of all seller pools
    SellerPoolList pools;
    pools->setType(Array);
    FileInfoIterator fii = mDownloadState["ware"]["fileInfos"].getIterator();
    while(fii->hasNext())
    {
        FileInfo& fi = fii->next();

        // create a seller pool to populate, try to retrieve up
        // to 100 sellers
        SellerPool sp;
        BM_ID_SET(sp["fileInfo"]["id"], BM_FILE_ID(fi["id"]));
        BM_ID_SET(sp["fileInfo"]["mediaId"], BM_MEDIA_ID(fi["mediaId"]));
        sp["sellerDataSet"]["start"] = 0;
        sp["sellerDataSet"]["num"] = 100;

        // add seller pool to list
        pools->append(sp);

        yield();
    }

    // start up SellerPoolUpdater fiber
    SellerPoolUpdater* spu = new SellerPoolUpdater(getNode(), getId());
    spu->setUserId(getUserId());
    spu->setDownloadState(mDownloadState);
    spu->setSellerPools(pools);
    spu->initializeFileProgress(true);
    mNode->getFiberScheduler()->addFiber(spu);

    // sleep until spu is done
    bool keepSleeping = true;
    while(keepSleeping)
    {
        sleep();

        // get messages
        FiberMessageQueue* msgs = getMessages();
        while(!msgs->empty())
        {
            DynamicObject msg = msgs->front();
            msgs->pop_front();

            if(msg->hasMember("interrupt"))
            {
                logDownloadStateMessage("interrupted");

                // send interrupted event
                Event e;
                e["type"] = EVENT_DOWNLOAD_STATE ".initializationInterrupted";
                sendDownloadStateEvent(e);
                keepSleeping = false;
            }
            // FIXME: is this intentionally not an elseif?
            if(msg->hasMember("sellerPoolUpdateComplete"))
            {
                // stop processing download state
                mPurchaseDatabase->stopProcessingDownloadState(
                    mDownloadState, getId());

                // send success event
                Event e;
                e["type"] = EVENT_DOWNLOAD_STATE ".initialized";
                sendDownloadStateEvent(e);
                keepSleeping = false;
            }
            else if(msg->hasMember("sellerPoolUpdateError"))
            {
                // send error event
                Event e;
                e["type"] = EVENT_DOWNLOAD_STATE ".exception";
                e["details"]["exception"] = msg["exception"];
                sendDownloadStateEvent(e);
                keepSleeping = false;
            }
        }
    }
}
Exemple #19
0
/**
 * Recursively normalizes the given input object.
 *
 * Input: A subject with predicates and possibly embedded other subjects.
 * Output: Either a map of normalized subjects OR a tree of normalized subjects.
 *
 * Normalization Algorithm:
 *
 * Replace the existing context if the input has '#'.
 *
 * For each key-value:
 * 1. Split the key on a colon and look for prefix in the context. If found,
 *    expand the key to an IRI, else it is already an IRI, add <>, save the
 *    new predicate to add to the output.
 * 2. If value is a Map, then it is a subject, set the predicate to the
 *    subject's '@' IRI value and recurse into it. Else goto #3.
 * 3. Look up the key in the context to find type coercion info. If not found,
 *    goto #4, else goto #5.
 * 4. Check the value for an integer, double, or boolean. If matched, set
 *    type according to xsd types. If not matched, look for <>, if found,
 *    do CURIE vs. IRI check like #1 and create appropriate value.
 * 5. If type coercion entry is a string, encode the value using the specific
 *    type. If it is an array, check the type in order of preference. If an
 *    unrecognized type (non-xsd, non-IRI) is provided, throw an exception.
 *
 * @param ctx the context to use (changes during recursion as necessary).
 * @param in the input object.
 * @param subjects a map of normalized subjects.
 * @param out a tree normalized objects.
 * @param bnodeId the last blank node ID used.
 *
 * @return true on success, false on failure with exception set.
 */
static bool _normalize(
   DynamicObject ctx, DynamicObject& in,
   DynamicObject* subjects, DynamicObject* out, int& bnodeId)
{
   bool rval = true;

   // FIXME: validate context (check for non-xsd types in type coercion arrays)

   if(!in.isNull())
   {
      // update context
      if(in->hasMember("#"))
      {
         ctx = in["#"];
      }

      // vars for normalization state
      DynamicObject subject(NULL);
      if(subjects != NULL)
      {
         subject = DynamicObject();
         subject->setType(Map);

         // assign blank node ID as needed
         if(!in->hasMember("@"))
         {
            string bnodeKey = _createBlankNodeId(++bnodeId);
            subject["@"] = bnodeKey.c_str();
         }
      }
      string nKey;

      // iterate over key-values
      DynamicObjectIterator i = in.getIterator();
      while(rval && i->hasNext())
      {
         DynamicObject& value = i->next();
         const char* key = i->getName();

         // skip context keys
         if(key[0] == '#')
         {
            continue;
         }

         // get normalized key
         nKey = _normalizeValue(ctx, key, RDF_TYPE_IRI, NULL, NULL);

         // put values in an array for single code path
         DynamicObject values;
         values->setType(Array);
         if(value->getType() == Array)
         {
            values.merge(value, true);

            // preserve array structure when not using subjects map
            if(out != NULL)
            {
               (*out)[nKey.c_str()]->setType(Array);
            }
         }
         else
         {
            values->append(value);
         }

         // normalize all values
         DynamicObjectIterator vi = values.getIterator();
         while(rval && vi->hasNext())
         {
            DynamicObject v = vi->next();
            if(v->getType() == Map)
            {
               if(subjects != NULL)
               {
                  // get a normalized subject for the value
                  string vSubject;
                  if(v->hasMember("@"))
                  {
                     // normalize existing subject
                     vSubject = _normalizeValue(
                        ctx, v["@"], RDF_TYPE_IRI, NULL, NULL);
                  }
                  else
                  {
                     // generate the next blank node ID in order to preserve
                     // the blank node embed in the code below
                     vSubject = _createBlankNodeId(bnodeId + 1);
                  }

                  // determine if value is a blank node
                  bool isBNode = _isBlankNode(v);

                  // update non-blank node subject (use value's subject IRI)
                  if(!isBNode)
                  {
                     _setPredicate(subject, nKey.c_str(), vSubject.c_str());
                  }

                  // recurse
                  rval = _normalize(ctx, v, subjects, out, bnodeId);

                  // preserve embedded blank node
                  if(rval && isBNode)
                  {
                     // remove embed from top-level subjects
                     DynamicObject embed = (*subjects)[vSubject.c_str()];
                     (*subjects)->removeMember(vSubject.c_str());
                     embed->removeMember("@");
                     _setEmbed(subject, nKey.c_str(), embed);
                  }
               }
               else
               {
                  // update out and recurse
                  DynamicObject next = (*out)[nKey.c_str()];
                  if(value->getType() == Array)
                  {
                     next = next->append();
                  }
                  else
                  {
                     next->setType(Map);
                  }
                  rval = _normalize(ctx, v, subjects, &next, bnodeId);
               }
            }
            else
            {
               _setPredicate(
                  (subjects != NULL) ? subject : *out, nKey.c_str(),
                  _normalizeValue(ctx, v, RDF_TYPE_UNKNOWN, key, NULL).c_str());
            }
         }
      }

      // add subject to map
      if(subjects != NULL)
      {
         (*subjects)[subject["@"]->getString()] = subject;
      }
   }

   return rval;
}
Exemple #20
0
/* Check if a JSON-LD object has an id. */
static bool _hasId(DynamicObject& in)
{
   return in->hasMember("@");
}
bool SampleService::sendm3u(BtpAction* action, DynamicObject& fileInfos)
{
   bool rval = true;

   // build m3u file
   string content;
   content.append("#EXTM3U\n");

   // create play list
   char temp[22];
   FileInfoIterator i = fileInfos.getIterator();
   while(i->hasNext())
   {
      FileInfo& fi = i->next();
      Media& media = fi["media"];
      int sampleLength =
         media["sampleRange"][1]->getUInt32() -
         media["sampleRange"][0]->getUInt32();
      snprintf(temp, 22, "%u", (sampleLength < 0 ? 0 : sampleLength));

      string artist;
      if(media["contributors"]->hasMember("Performer"))
      {
         artist = media["contributors"]["Performer"][0]["name"]->getString();
      }
      else if(media["contributors"]->hasMember("Artist"))
      {
         artist = media["contributors"]["Artist"][0]["name"]->getString();
      }

      content.append("#EXTINF:");
      content.append(temp);
      content.push_back(',');
      content.append(artist);
      content.append(" - ");
      content.append(media["title"]->getString());
      content.push_back('\n');

      // FIXME: get host from configuration or something
      // needs to be public IP that remote side can access
      DynamicObject vars;
      action->getResourceQuery(vars);
      if(!vars->hasMember("nodeuser"))
      {
         BM_ID_SET(vars["nodeuser"], mNode->getDefaultUserId());
      }

      HttpRequestHeader* header = action->getRequest()->getHeader();
      string host = header->getFieldValue("X-Forwarded-Host");
      if(host.length() == 0)
      {
         host = header->getFieldValue("Host");
      }
      content.append("http://");
      content.append(host);
      content.append("/api/3.0/sales/samples/file/");
      content.append(fi["mediaId"]->getString());
      content.push_back('/');
      content.append(fi["id"]->getString());
      content.push_back('\n');
   }

   // set up response header
   HttpResponseHeader* header = action->getResponse()->getHeader();
   header->setField("Content-Type", "audio/x-mpegurl");
   header->setField(
      "Content-Disposition", "attachment; filename=bitmunk-sample.m3u");

   // create content input stream
   ByteBuffer b(content.length());
   b.put(content.c_str(), content.length(), false);
   ByteArrayInputStream bais(&b);

   // send sample
   action->getResponse()->getHeader()->setStatus(200, "OK");
   action->sendResult(&bais);

   return rval;
}
Exemple #22
0
bool DomWriter::writeWithNamespaceSupport(
   Element& e, OutputStream* os, int level, DynamicObject& nsPrefixMap)
{
   bool rval = true;

   if(level < 0)
   {
      level = mIndentLevel;
   }

   // add any entries to the current namespace prefix map
   if(e->hasMember("attributes") && e["attributes"]->getType() == Map)
   {
      AttributeIterator attrs = e["attributes"].getIterator();
      while(attrs->hasNext())
      {
         Attribute& attr = attrs->next();

         // check for an xml namespace prefix definition
         const char* attrName = attrs->getName();
         if(strncmp(attrName, "xmlns:", 6) == 0)
         {
            const char* uri = attr["value"]->getString();
            nsPrefixMap[uri] = attrName + 6;
         }
      }
   }

   // create element name, which may require using the namespace prefix map
   string elementName;
   if(e->hasMember("namespace"))
   {
      const char* ns = e["namespace"]->getString();
      if(nsPrefixMap->hasMember(ns))
      {
         // prepend prefix for given namespace
         elementName.append(nsPrefixMap[ns]->getString());
         elementName.push_back(':');
      }
   }
   elementName.append(e["name"]->getString());

   // open start element
   rval =
      ((mCompact || level == 0) ? true : os->write("\n", 1)) &&
      writeIndentation(os, level) &&
      os->write("<", 1) &&
      os->write(elementName.c_str(), elementName.length());

   // write attributes
   e["attributes"]->setType(Map);
   AttributeIterator attrs = e["attributes"].getIterator();
   while(rval && attrs->hasNext())
   {
      Attribute& attr = attrs->next();

      // create attribute name, which may require using the namespace prefix map
      string attrName;
      if(attr->hasMember("namespace"))
      {
         const char* ns = attr["namespace"]->getString();
         if(nsPrefixMap->hasMember(ns))
         {
            // prepend prefix for given namespace
            attrName.append(nsPrefixMap[ns]->getString());
            attrName.push_back(':');
         }
      }
      attrName.append(attr["name"]->getString());

      rval =
         os->write(" ", 1) &&
         os->write(attrName.c_str(), attrName.length()) &&
         os->write("=\"", 2) &&
         os->write(attr["value"]->getString(), attr["value"]->length()) &&
         os->write("\"", 1);
   }

   // close start element, if element is empty, use compact element
   e["data"]->setType(String);
   e["children"]->setType(Map);
   int dataLength = e["data"]->length();
   bool empty = (dataLength == 0 && e["children"]->length() == 0);
   rval = rval && (empty ? os->write("/>", 2) : os->write(">", 1));

   // write element data and children
   if(rval && !empty)
   {
      // write element children
      if(rval && e["children"]->length() > 0)
      {
         // serialize each child
         DynamicObjectIterator lists = e["children"].getIterator();
         while(rval && lists->hasNext())
         {
            DynamicObject& list = lists->next();
            list->setType(Array);
            ElementIterator children = list.getIterator();
            while(rval && children->hasNext())
            {
               // serialize child
               Element& child = children->next();
               rval = writeWithNamespaceSupport(
                  child, os, level + 1, nsPrefixMap);
            }
         }
      }

      // write element data
      if(dataLength > 0)
      {
         // xml-encode data
         string encoded = encode(e["data"]->getString());
         rval = os->write(encoded.c_str(), encoded.length());
      }

      // write end element
      // (only write indentation when data is blank and children are present)
      if(dataLength == 0 && !empty)
      {
         rval = rval &&
            (mCompact ? true : os->write("\n", 1)) &&
            writeIndentation(os, level);
      }

      rval = rval &&
         os->write("</", 2) &&
         os->write(elementName.c_str(), elementName.length()) &&
         os->write(">", 1);
   }

   return rval;
}
bool SampleService::getSampleFileByIds(
   BtpAction* action, DynamicObject& in, DynamicObject& out,
   MediaId mediaId, FileId fileId)
{
   bool rval;

   // do not send dyno as response
   out.setNull();

   // determine if too busy or not
   bool permit = false;
   mSampleSemaphoreLock.lock();
   {
      int current = mSampleSemaphore["current"]->getInt32();
      if(current < mSampleSemaphore["max"]->getInt32())
      {
         mSampleSemaphore["current"] = current + 1;
         permit = true;
      }
   }
   mSampleSemaphoreLock.unlock();

   // ensure permit was granted to stream sample
   if(!permit)
   {
      // too many samples streaming
      action->getResponse()->getHeader()->setStatus(503, "Service Unavailable");
      action->sendResult();
      rval = true;
   }
   else
   {
      // get catalog interface
      CatalogInterface* ci = dynamic_cast<CatalogInterface*>(
         mNode->getModuleApiByType("bitmunk.catalog"));

      // get targeted node user
      DynamicObject vars;
      action->getResourceQuery(vars);
      if(!vars->hasMember("nodeuser"))
      {
         BM_ID_SET(vars["nodeuser"], mNode->getDefaultUserId());
      }

      // get resource parameters
      DynamicObject params;
      action->getResourceParams(params);

      FileInfo fi;
      BM_ID_SET(fi["mediaId"], mediaId);
      BM_ID_SET(fi["id"], fileId);
      if((rval = ci->populateFileInfo(BM_USER_ID(vars["nodeuser"]), fi)))
      {
         // send the sample
         rval = sendFile(action, fi);
      }

      // release permit
      mSampleSemaphoreLock.lock();
      {
         int current = mSampleSemaphore["current"]->getInt32();
         mSampleSemaphore["current"] = current - 1;
      }
      mSampleSemaphoreLock.unlock();

      if(!rval)
      {
         // sample not found
         action->getResponse()->getHeader()->setStatus(404, "Not Found");
         action->sendResult();
         rval = true;
      }
   }

   return rval;
}
Exemple #24
0
static DynamicObject _compactIri(
   DynamicObject& ctx, DynamicObject& usedCtx,
   const char* predicate, const char* encoded,
   const char* value, char** curie)
{
   DynamicObject rval(NULL);

   // used to store if brackets should be added
   bool addBrackets = true;

   // predicates themselves have no brackets
   if(predicate == NULL)
   {
      addBrackets = false;
   }
   // no brackets for "@" or "a"
   else if(strcmp(predicate, "@") == 0 || strcmp(predicate, "a") == 0)
   {
      addBrackets = false;
   }
   // check type coercion for IRI
   else if(ctx->hasMember("#types") && ctx["#types"]->hasMember(predicate))
   {
      DynamicObject& type = ctx["#types"][predicate];
      usedCtx["#types"][predicate] = type.clone();

      // single type
      if(type->getType() == String)
      {
         string t = _normalizeValue(ctx, type, RDF_TYPE_IRI, NULL, &usedCtx);
         if(strcmp(t.c_str(), XSD_ANY_URI_NORM) == 0)
         {
            addBrackets = false;
         }
      }
      // type coercion info is an ordered list of possible types
      else
      {
         // do not add brackets if URI is a valid type
         DynamicObjectIterator ti = type.getIterator();
         while(ti->hasNext())
         {
            DynamicObject& next = ti->next();
            string t = _normalizeValue(ctx, next, RDF_TYPE_IRI, NULL, &usedCtx);
            if(strcmp(t.c_str(), XSD_ANY_URI_NORM) == 0)
            {
               addBrackets = false;
            }
         }
      }
   }

   // check the context for a prefix that could shorten the IRI to a CURIE
   DynamicObjectIterator i = ctx.getIterator();
   while(rval.isNull() && i->hasNext())
   {
      DynamicObject& next = i->next();

      // skip special context keys (start with '#')
      const char* name = i->getName();
      if(name[0] != '#')
      {
         const char* uri = next;
         const char* ptr = strstr(value, uri);
         if(ptr != NULL && ptr == value)
         {
            size_t ulen = strlen(uri);
            size_t vlen = strlen(value);
            if(vlen > ulen)
            {
               // add 2 to make room for null-terminator and colon
               size_t total = strlen(name) + (vlen - ulen) + 2;
               if(addBrackets)
               {
                  total += 2;
               }
               _realloc(curie, total);
               const char* format = addBrackets ? "<%s:%s>" : "%s:%s";
               snprintf(*curie, total, format, name, ptr + ulen);
               rval = DynamicObject();
               rval = *curie;
               usedCtx[name] = uri;
            }
            else if(vlen == ulen && strcmp(name, "a") == 0)
            {
               rval = DynamicObject();
               rval = "a";
            }
         }
      }
   }

   // if rval still not set, use encoded or value based on addBrackets
   if(rval.isNull())
   {
      rval = DynamicObject();
      rval = addBrackets ? encoded : value;
   }

   return rval;
}
Exemple #25
0
static DynamicObject _compactTypedLiteral(
   DynamicObject& ctx, DynamicObject& usedCtx,
   const char* predicate, const char* encoded,
   const char* value, const char* datatype, char** tmp)
{
   DynamicObject rval(NULL);

   // check type coercion
   if(predicate != NULL)
   {
      // prefer type coercion map first, then use default basic types
      bool inTypesMap = false;
      string t;
      if(ctx->hasMember("#types") && ctx["#types"]->hasMember(predicate))
      {
         DynamicObject& type = ctx["#types"][predicate];
         usedCtx["#types"][predicate] = type.clone();
         inTypesMap = true;

         // single type
         if(type->getType() == String)
         {
            // get fully-qualified datatype
            t = _normalizeValue(ctx, type, RDF_TYPE_IRI, NULL, &usedCtx);
         }
         // type coercion info is an ordered list of possible types
         else
         {
            // FIXME: need to check if datatype matches type coercion type
            // FIXME: determine whether to make int,bool,double,or IRI
         }
      }
      else
      {
         // use given datatype (try to coerce basic built in types)
         DynamicObject nullCtx(NULL);
         DynamicObject type;
         type = datatype;
         t = _normalizeValue(nullCtx, type, RDF_TYPE_IRI, NULL, NULL);
      }

      rval = DynamicObject();
      if(strcmp(t.c_str(), XSD_ANY_URI_NORM) == 0)
      {
         rval = value;
      }
      else if(strcmp(t.c_str(), XSD_BOOLEAN_NORM) == 0)
      {
         rval = value;
         rval->setType(Boolean);
      }
      else if(strcmp(t.c_str(), XSD_INTEGER_NORM) == 0)
      {
         rval = value;
         rval->setType(Int64);
      }
      else if(strcmp(t.c_str(), XSD_DOUBLE_NORM) == 0)
      {
         rval = value;
         rval->setType(Double);
      }
      // unrecognized type
      else
      {
         // if the type was explicitly specified in the type coercion map,
         // then use the decoded value, otherwise use the encoded one
         rval = inTypesMap ? value : encoded;
      }
   }

   // use full encoded value, nothing in context to compact IRI
   if(rval.isNull())
   {
      rval = DynamicObject();
      rval = encoded;
   }

   return rval;
}
Exemple #26
0
void DatabaseClient::buildParams(
   SchemaObject& schema, DynamicObject& members, DynamicObject& params,
   const char* tableAlias)
{
   // ensure params is an array
   params->setType(Array);

   // create shared table alias object
   DynamicObject taObj(NULL);
   if(tableAlias != NULL)
   {
      taObj = DynamicObject();
      taObj = tableAlias;
   }

   // map the given members object into a list of parameters that can
   // be used to generate sql and set parameter values
   DynamicObjectIterator i = schema["columns"].getIterator();
   while(i->hasNext())
   {
      DynamicObject& column = i->next();
      const char* memberName = column["memberName"]->getString();

      // if the members map contains the given member name, create a param
      // for it and append it to the params array
      if(members->hasMember(memberName))
      {
         /* Note: The member value is either a value, map, or an array. If it's
          * an array, then each entry in the array is either a value or a map.
          *
          * Create a single parameter for all values. Create an individual
          * parameter for every map entry. This algorithm will store all maps
          * in "p" and all values in "values". Then "values" will be added to
          * "p". Then a new parameter will be created for each entry in "p".
          */
         DynamicObject& mv = members[memberName];
         DynamicObject p(Array);
         DynamicObject values(Array);

         // group maps and values
         if(mv->getType() == Map)
         {
            p->append(mv);
         }
         else if(mv->getType() == Array)
         {
            DynamicObjectIterator mvi = mv.getIterator();
            while(mvi->hasNext())
            {
               DynamicObject& next = mvi->next();
               if(next->getType() == Map)
               {
                  p->append(next);
               }
               else
               {
                  values->append(next);
               }
            }
         }
         else
         {
            values->append(mv);
         }

         // treat values as a single param
         if(values->length() > 0)
         {
            p->append(values);
         }

         // create params
         DynamicObjectIterator pi = p.getIterator();
         while(pi->hasNext())
         {
            DynamicObject& next = pi->next();

            // add param
            DynamicObject& param = params->append();
            param["name"] = column["name"];
            param["type"] = column["columnType"];
            param["op"] = "=";
            param["boolOp"] = "AND";
            if(column->hasMember("encode"))
            {
               param["encode"] = column["encode"];
            }
            if(tableAlias != NULL)
            {
               param["tableAlias"] = taObj;
            }

            // if next param is a map, get operator and value
            if(next->getType() == Map)
            {
               if(next->hasMember("op"))
               {
                  param["op"] = next["op"].clone();
               }
               if(next->hasMember("boolOp"))
               {
                  param["boolOp"] = next["boolOp"].clone();
               }
               param["value"] = next["value"].clone();
            }
            else
            {
               param["value"] = next.clone();
            }
         }
      }
   }
}
Exemple #27
0
bool JsonLd::normalize(DynamicObject& in, DynamicObject& out)
{
   bool rval = true;

   // initialize output
   out->setType(Map);
   out->clear();

   // create map to store subjects
   DynamicObject subjects;
   subjects->setType(Map);

   // initialize context
   DynamicObject ctx(NULL);
   if(in->hasMember("#"))
   {
      ctx = in["#"];
   }

   // put all subjects in an array for single code path
   DynamicObject input;
   input->setType(Array);
   if(in->hasMember("@") && in["@"]->getType() == Array)
   {
      input.merge(in["@"], true);
   }
   else
   {
      input->append(in);
   }

   // do normalization
   int bnodeId = 0;
   DynamicObjectIterator i = input.getIterator();
   while(rval && i->hasNext())
   {
      rval = _normalize(ctx, i->next(), &subjects, NULL, bnodeId);
   }

   // build output
   if(rval)
   {
      // single subject
      if(subjects->length() == 1)
      {
         DynamicObject subject = subjects.first();
         out.merge(subject, false);

         // FIXME: will need to check predicates for blank nodes as well...
         // and fail if they aren't embeds?

         // strip blank node '@'
         if(_isBlankNode(out))
         {
            out->removeMember("@");
         }
      }
      // multiple subjects
      else
      {
         DynamicObject& array = out["@"];
         array->setType(Array);
         i = subjects.getIterator();
         while(i->hasNext())
         {
            DynamicObject& next = i->next();

            // FIXME: will need to check predicates for blank nodes as well...
            // and fail if they aren't embeds?

            // strip blank node '@'
            if(_isBlankNode(next))
            {
               next->removeMember("@");
            }
            array->append(next);
         }
      }
   }

   return rval;
}
static void customCatalogTests(Node& node, TestRunner& tr)
{
   resetTestEnvironment(node);

   Messenger* messenger = node.getMessenger();

   // generate the ware URLs that will be used throughout the test.
   Url waresUrl;
   waresUrl.format(
      "%s/api/3.0/catalog/wares?nodeuser=%" PRIu64,
      messenger->getSelfUrl(true).c_str(), TEST_USER_ID);
   Url waresNonDefaultListUrl;
   waresNonDefaultListUrl.format(
      "%s/api/3.0/catalog/wares?nodeuser=%" PRIu64 "&id=%s&default=false",
      messenger->getSelfUrl(true).c_str(), TEST_USER_ID, TEST_WARE_ID_2);
   Url wareUrl;
   wareUrl.format(
      "%s/api/3.0/catalog/wares/%s?nodeuser=%" PRIu64,
      messenger->getSelfUrl(true).c_str(), TEST_WARE_ID_2, TEST_USER_ID);

   // generate the files URL that will be used to prime the medialibrary
   Url filesUrl;
   filesUrl.format("%s/api/3.2/medialibrary/files?nodeuser=%" PRIu64,
      messenger->getSelfUrl(true).c_str(), TEST_USER_ID);
   Url removeUrl;
   removeUrl.format(
      "%s/api/3.2/medialibrary/files/%s?nodeuser=%" PRIu64,
      messenger->getSelfUrl(true).c_str(), TEST_FILE_ID_2, TEST_USER_ID);

   // Create basic and detailed test ware with id=2
   Ware basicWare2;
   Ware detailedWare2;
   {
      basicWare2["id"] = TEST_WARE_ID_2;
      basicWare2["description"] =
         "This ware was added by test-services-customcatalog";

      detailedWare2 = basicWare2.clone();
      detailedWare2["mediaId"] = 2;
      detailedWare2["fileInfos"]->setType(Array);
      FileInfo fi = detailedWare2["fileInfos"]->append();
      fi["id"] = TEST_FILE_ID_2;
      fi["mediaId"] = 2;
      File file((sTestDataDir + TEST_FILENAME_2).c_str());
      fi["extension"] = file->getExtension() + 1;
      fi["contentType"] = "audio/mpeg";
      fi["contentSize"] = TEST_CONTENT_SIZE_2;
      fi["size"] = (uint64_t)file->getLength();
      fi["path"] = file->getAbsolutePath();

      detailedWare2["payees"]->setType(Array);
      Payee p1 = detailedWare2["payees"]->append();
      Payee p2 = detailedWare2["payees"]->append();

      p1["id"] = 900;
      p1["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE;
      p1["amount"] = "0.10";
      p1["description"] = "This payee is for media ID 2";

      p2["id"] = 900;
      p2["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL;
      p2["percentage"] = "0.10";
      p2["description"] = "This payee is for media ID 2";
   }

   // remove any previous files from the media library
   messenger->deleteResource(&removeUrl, NULL, node.getDefaultUserId());
   // pass even if there is an exception - this is meant to just clear any
   // previous entries in the medialibrary database if they existed.
   Exception::clear();

   tr.group("customcatalog");

   tr.test("add file to medialibrary (valid)");
   {
      DynamicObject in;
      DynamicObject out;

      // create a FileInfo object
      string normalizedPath;
      File::normalizePath(
         (sTestDataDir + TEST_FILENAME_2).c_str(), normalizedPath);
      out["path"] = normalizedPath.c_str();
      out["mediaId"] = 2;

      // prepare event waiter
      EventWaiter ew(node.getEventController());
      ew.start("bitmunk.medialibrary.File.updated");
      ew.start("bitmunk.medialibrary.File.exception");

      // add the file to the media library
      assertNoException(
         messenger->post(&filesUrl, &out, &in, node.getDefaultUserId()));

      // wait for file ID set event
      assert(ew.waitForEvent(5*1000));

      // ensure it has an exception
      Event e = ew.popEvent();
      //dumpDynamicObject(e);
      if(e["details"]->hasMember("exception"))
      {
         ExceptionRef ex = Exception::convertToException(
            e["details"]["exception"]);
         Exception::set(ex);
      }
      else if(strcmp(
         e["type"]->getString(), "bitmunk.medialibrary.File.updated") == 0)
      {
         // add new mediaLibraryId to the basic and detailed wares
         basicWare2["mediaLibraryId"] = e["details"]["mediaLibraryId"];
         detailedWare2["mediaLibraryId"] = e["details"]["mediaLibraryId"];
      }
   }
   tr.passIfNoException();

   tr.test("add ware without payee-scheme (valid)");
   {
      DynamicObject in;
      DynamicObject out;

      // create the outgoing ware object
      FileInfo fi;
      fi["id"] = TEST_FILE_ID_2;

      out["id"] = TEST_WARE_ID_2;
      out["mediaId"] = 2;
      out["description"] = "This ware was added by test-services-customcatalog";
      out["fileInfo"] = fi;
      out["payees"]->setType(Array);
      Payee p1 = out["payees"]->append();
      Payee p2 = out["payees"]->append();

      p1["id"] = 900;
      p1["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE;
      p1["amount"] = "0.10";
      p1["description"] = "This payee is for media ID 2";

      p2["id"] = 900;
      p2["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL;
      p2["percentage"] = "0.10";
      p2["description"] = "This payee is for media ID 2";

      // add the ware to the custom catalog
      messenger->post(&waresUrl, &out, &in, node.getDefaultUserId());

      // set ware payeeSchemeIds
      basicWare2["payeeSchemeId"] = in["payeeSchemeId"];
      detailedWare2["payeeSchemeId"] = in["payeeSchemeId"];
   }
   tr.passIfNoException();

   tr.test("get ware (valid)");
   {
      // get a specific ware from the custom catalog
      Ware receivedWare;
      assertNoException(
         messenger->get(&wareUrl, receivedWare, node.getDefaultUserId()));

      // remove format details for comparison
      if(receivedWare->hasMember("fileInfos") &&
         receivedWare["fileInfos"]->getType() == Array &&
         receivedWare["fileInfos"]->length() == 1)
      {
         receivedWare["fileInfos"][0]->removeMember("formatDetails");
      }

      // check to make sure that the wares match
      assertNamedDynoCmp(
         "Expected ware ResourceSet", detailedWare2,
         "Received ware ResourceSet", receivedWare);
   }
   tr.passIfNoException();

   tr.test("get wares");
   {
      // get a specific ware from the custom catalog
      Ware receivedWareSet;
      Url url;
      url.format(
         "%s/api/3.0/catalog/wares?nodeuser=%" PRIu64 "&id=%s",
         messenger->getSelfUrl(true).c_str(), TEST_USER_ID, TEST_WARE_ID_2);
      assertNoException(
         messenger->get(&url, receivedWareSet, node.getDefaultUserId()));

      // check ware set
      Ware expectedWareSet;
      expectedWareSet["resources"][0] = basicWare2.clone();
      expectedWareSet["total"] = 1;
      expectedWareSet["num"] = 1;
      expectedWareSet["start"] = 0;

      assertNamedDynoCmp(
         "Expected ware ResourceSet", expectedWareSet,
         "Received ware ResourceSet", receivedWareSet);
   }
   tr.passIfNoException();

   tr.test("get wares by fileId");
   {
      // get a specific ware from the custom catalog
      Ware receivedWareSet;
      Url url;
      url.format(
         "%s/api/3.0/catalog/wares?nodeuser=%" PRIu64 "&fileId=%s",
         messenger->getSelfUrl(true).c_str(), TEST_USER_ID, TEST_FILE_ID_2);
      assertNoException(
         messenger->get(&url, receivedWareSet, node.getDefaultUserId()));

      // check ware set
      Ware expectedWareSet;
      expectedWareSet["resources"][0] = basicWare2.clone();
      expectedWareSet["total"] = 1;
      expectedWareSet["num"] = 1;
      expectedWareSet["start"] = 0;

      assertNamedDynoCmp(
         "Expected ware ResourceSet", expectedWareSet,
         "Received ware ResourceSet", receivedWareSet);
   }
   tr.passIfNoException();

   tr.test("get specific unknown wares");
   {
      // get a specific ware from the custom catalog
      Ware receivedWareSet;
      Url url;
      url.format(
         "%s/api/3.0/catalog/wares?nodeuser=%" PRIu64 "&id=%s&id=INVALID",
         messenger->getSelfUrl(true).c_str(), TEST_USER_ID, TEST_WARE_ID_2);
      messenger->get(&url, receivedWareSet, node.getDefaultUserId());

      // check ware set
      Ware expectedWareSet;
      expectedWareSet["resources"][0] = basicWare2.clone();
      expectedWareSet["total"] = 1;
      expectedWareSet["num"] = 2;
      expectedWareSet["start"] = 0;

      assertNamedDynoCmp(
         "Expected ware ResourceSet", expectedWareSet,
         "Received ware ResourceSet", receivedWareSet);
   }
   tr.passIfNoException();

   tr.test("get wares by dup ware+file ids");
   {
      // This test gets the same ware by both ware id and file id and returns
      // duplicate results.

      // get a specific ware from the custom catalog
      Ware receivedWareSet;
      Url url;
      url.format(
         "%s/api/3.0/catalog/wares?nodeuser=%" PRIu64 "&id=%s&fileId=%s",
         messenger->getSelfUrl(true).c_str(), TEST_USER_ID,
         TEST_WARE_ID_2, TEST_FILE_ID_2);
      messenger->get(&url, receivedWareSet, node.getDefaultUserId());

      // check ware set
      Ware expectedWareSet;
      expectedWareSet["resources"][0] = basicWare2.clone();
      expectedWareSet["total"] = 1;
      expectedWareSet["num"] = 2;
      expectedWareSet["start"] = 0;

      assertNamedDynoCmp(
         "Expected ware ResourceSet", expectedWareSet,
         "Received ware ResourceSet", receivedWareSet);
   }
   tr.passIfNoException();

   tr.test("remove ware (valid)");
   {
      // remove the ware
      messenger->deleteResource(&wareUrl, NULL, node.getDefaultUserId());
   }
   tr.passIfNoException();

   /*************************** Payee Scheme tests **************************/
   // generate the payee schemes URL
   Url payeeSchemesUrl;
   payeeSchemesUrl.format("%s/api/3.0/catalog/payees/schemes?nodeuser=%" PRIu64,
      messenger->getSelfUrl(true).c_str(), TEST_USER_ID);
   PayeeSchemeId psId = 0;

   tr.test("add payee scheme (valid)");
   {
      DynamicObject in;
      DynamicObject out;

      // create the outgoing list of payees to organize into a payee scheme
      out["description"] = "Payee scheme description 1";
      out["payees"]->setType(Array);
      PayeeList payees = out["payees"];
      Payee p1 = payees->append();
      Payee p2 = payees->append();

      p1["id"] = 900;
      p1["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE;
      p1["amount"] = "0.10";
      p1["description"] = "test-services-customcatalog test payee 1";

      p2["id"] = 900;
      p2["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL;
      p2["percentage"] = "0.10";
      p2["description"] = "test-services-customcatalog test payee 2";

      // add the ware to the custom catalog
      messenger->post(&payeeSchemesUrl, &out, &in, node.getDefaultUserId());

      if(in->hasMember("payeeSchemeId"))
      {
         psId = in["payeeSchemeId"]->getUInt32();
      }
   }
   tr.passIfNoException();

   // generate the payee scheme URL
   Url payeeSchemeIdUrl;
   payeeSchemeIdUrl.format("%s/api/3.0/catalog/payees/schemes/%u?nodeuser=%"
      PRIu64,
      messenger->getSelfUrl(true).c_str(), psId, TEST_USER_ID);
   tr.test("get payee scheme (valid)");
   {
      // Create the expected payee scheme
      PayeeScheme expectedPayeeScheme;
      expectedPayeeScheme["id"] = psId;
      expectedPayeeScheme["userId"] = node.getDefaultUserId();
      expectedPayeeScheme["description"] = "Payee scheme description 1";
      expectedPayeeScheme["payees"]->setType(Array);
      Payee p1 = expectedPayeeScheme["payees"]->append();
      Payee p2 = expectedPayeeScheme["payees"]->append();

      p1["id"] = 900;
      p1["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE;
      p1["amount"] = "0.10";
      p1["description"] = "test-services-customcatalog test payee 1";

      p2["id"] = 900;
      p2["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL;
      p2["percentage"] = "0.10";
      p2["description"] = "test-services-customcatalog test payee 2";

      // get a specific payee scheme from the custom catalog
      PayeeScheme receivedPayeeScheme;
      messenger->get(
         &payeeSchemeIdUrl, receivedPayeeScheme, node.getDefaultUserId());

      // check payee schemes
      assertNamedDynoCmp(
         "Expected payee scheme", expectedPayeeScheme,
         "Received payee scheme", receivedPayeeScheme);
   }
   tr.passIfNoException();

   tr.test("get all payee schemes (valid)");
   {
      // Create the result set
      ResourceSet expectedResults;
      expectedResults["total"] = 2;
      expectedResults["start"] = 0;
      expectedResults["num"] = 2;

      PayeeScheme ps = expectedResults["resources"]->append();
      ps["id"] = 1;
      ps["userId"] = node.getDefaultUserId();
      ps["description"] = "This ware was added by test-services-customcatalog";
      ps["payees"]->setType(Array);
      Payee p1 = ps["payees"]->append();
      Payee p2 = ps["payees"]->append();

      p1["id"] = 900;
      p1["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE;
      p1["amount"] = "0.10";
      p1["description"] = "This payee is for media ID 2";

      p2["id"] = 900;
      p2["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL;
      p2["percentage"] = "0.10";
      p2["description"] = "This payee is for media ID 2";

      ps = expectedResults["resources"]->append();
      ps["id"] = 2;
      ps["userId"] = node.getDefaultUserId();
      ps["description"] = "Payee scheme description 1";
      ps["payees"]->setType(Array);
      Payee p3 = ps["payees"]->append();
      Payee p4 = ps["payees"]->append();

      p3["id"] = 900;
      p3["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE;
      p3["amount"] = "0.10";
      p3["description"] = "test-services-customcatalog test payee 1";

      p4["id"] = 900;
      p4["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL;
      p4["percentage"] = "0.10";
      p4["description"] = "test-services-customcatalog test payee 2";

      // get all payee schemes from the custom catalog
      ResourceSet receivedResults;
      messenger->get(
         &payeeSchemesUrl, receivedResults, node.getDefaultUserId());

      // check payee schemes
      assertNamedDynoCmp(
         "Expected payee scheme ResourceSet", expectedResults,
         "Received payee scheme ResourceSet", receivedResults);
   }
   tr.passIfNoException();

   tr.test("update payee scheme (valid)");
   {
      DynamicObject in;
      DynamicObject out;

      // create the outgoing list of payees to organize into a payee scheme
      out["description"] = "Payee scheme description 2";
      Payee p1 = out["payees"]->append();
      Payee p2 = out["payees"]->append();

      p1["id"] = 900;
      p1["amountType"] = PAYEE_AMOUNT_TYPE_FLATFEE;
      p1["amount"] = "0.15";
      p1["description"] = "test-services-customcatalog test payee 1 (updated)";

      p2["id"] = 900;
      p2["amountType"] = PAYEE_AMOUNT_TYPE_PTOTAL;
      p2["percentage"] = "0.14";
      p2["description"] = "test-services-customcatalog test payee 2 (updated)";

      // update a pre-existing payee scheme
      assertNoException(
         messenger->post(
            &payeeSchemeIdUrl, &out, &in, node.getDefaultUserId()));

      // ensure that the payee scheme was updated
      assert(in["payeeSchemeId"]->getUInt32() == 2);

      if(in->hasMember("payeeSchemeId"))
      {
         psId = in["payeeSchemeId"]->getUInt32();
      }
   }
   tr.passIfNoException();

   tr.test("add ware with payee scheme (valid)");
   {
      DynamicObject in;
      DynamicObject out;

      // create the outgoing ware object
      FileInfo fi;
      fi["id"] = TEST_FILE_ID_2;
      out["id"] = TEST_WARE_ID_2;
      out["mediaId"] = 2;
      out["description"] = "This ware was added by test-services-customcatalog";
      out["fileInfo"] = fi;
      out["payeeSchemeId"] = psId;

      // add the ware to the custom catalog
      messenger->post(&waresUrl, &out, &in, node.getDefaultUserId());
   }
   tr.passIfNoException();

   tr.test("remove associated payee scheme (invalid)");
   {
      messenger->deleteResource(
         &payeeSchemeIdUrl, NULL, node.getDefaultUserId());
   }
   tr.passIfException();

   tr.test("remove ware associated w/ payee scheme (valid)");
   {
      messenger->deleteResource(
         &wareUrl, NULL, node.getDefaultUserId());
   }
   tr.passIfNoException();

   tr.test("remove payee scheme (valid)");
   {
      messenger->deleteResource(
         &payeeSchemeIdUrl, NULL, node.getDefaultUserId());
   }
   tr.passIfNoException();

   tr.test("create ware w/ invalid payee scheme (invalid)");
   {
      DynamicObject in;
      DynamicObject out;

      // create the outgoing ware object
      FileInfo fi;
      fi["id"] = TEST_FILE_ID_2;
      PayeeScheme ps;
      ps["id"] = psId;

      out["id"] = TEST_WARE_ID_2;
      out["mediaId"] = 2;
      out["description"] = "This ware was added by test-services-customcatalog";
      out["fileInfo"] = fi;
      out["payeeScheme"] = ps;

      // add the ware to the custom catalog
      messenger->post(&waresUrl, &out, &in, node.getDefaultUserId());
   }
   tr.passIfException();

   tr.test("remove ware (invalid)");
   {
      // remove a ware that doesn't exist
      messenger->deleteResource(&wareUrl, NULL, node.getDefaultUserId());
   }
   tr.passIfException();

   tr.ungroup();
}
Exemple #29
0
bool DatabaseClient::mapInstance(
   const char* objType,
   DynamicObject& obj, DynamicObject& mapping,
   DynamicObject* userData)
{
   bool rval = false;

   /* Algorithm to create a column mapping to the values in the given object:

      1. Get the OR mapping for the object type.
      2. Iterate over the members in the mapping, assigning each one's
         associated information to a matching member in the instance object.
      3. Include any values from the instance object in the instance mapping
         validating and coercing types as needed.
   */

   /* The instance mapping format:
    *
    * mapping: {
    *    "tables": {} of table name to table entry
    *    "entries": [
    *       "table": the database table name
    *       "columns": [
    *          (cloned info from the OR mapping) +
    *          "member": the object member name
    *          "value": the value for the column (to apply via an operator,
    *             coerced to columnType)
    *          "userData": as given to this call
    *       ],
    *       "fkeys": [
    *          (cloned info from the OR mapping) +
    *          "member": the object member name
    *          "value": the value for "fcolumn" (coerced to columnType)
    *          "userData": as given to this call
    *       ]
    *    ]
    * }
    */

   // initialize mapping
   mapping["tables"]->setType(Map);
   mapping["entries"]->setType(Array);

   // get OR map for the given object type
   ObjRelMap orMap = getObjRelMap(objType);
   if(!orMap.isNull())
   {
      rval = true;
      DynamicObjectIterator i = orMap["members"].getIterator();
      while(rval && i->hasNext())
      {
         // get OR member info
         DynamicObject& info = i->next();

         // if object is NULL, then we want to get ALL members
         if(obj.isNull() || obj->hasMember(i->getName()))
         {
            // start building an instance mapping entry
            DynamicObject entry(NULL);

            // add/update entry based on table
            const char* table = info["table"]->getString();
            if(mapping["tables"]->hasMember(table))
            {
               // update existing entry
               entry = mapping["tables"][table];
            }
            else
            {
               // add a new entry
               entry = mapping["entries"]->append();
               entry["table"] = info["table"];
               entry["columns"]->setType(Array);
               entry["fkeys"]->setType(Array);
               if(orMap->hasMember("autoIncrement") &&
                  orMap["autoIncrement"]->hasMember(table))
               {
                  const char* id = orMap["autoIncrement"][table]->getString();
                  entry["autoIncrement"]["id"] = id;
                  entry["autoIncrement"]["type"]->setType(
                     orMap["members"][id]["columnType"]->getType());
               }
               mapping["tables"][table] = entry;
            }

            // clone info, add member name and user-data
            DynamicObject d = info.clone();
            d["member"] = i->getName();
            if(userData != NULL)
            {
               d["userData"] = *userData;
            }

            // set value
            if(obj.isNull())
            {
               d["value"];
            }
            else
            {
               // FIXME: validate data type
               d["value"] = obj[i->getName()].clone();
            }

            // coerce data type to match column type
            d["value"]->setType(d["columnType"]->getType());

            // add to entry based on group
            entry[info["group"]->getString()]->append(d);
         }
      }
   }

   return rval;
}
Exemple #30
0
/**
 * Normalizes a value using the given context.
 *
 * @param ctx the context.
 * @param value the value to normalize.
 * @param type the expected RDF type, use RDF_TYPE_UNKNOWN if not known.
 * @param predicate an optional predicate for the value (used to look up
 *           type coercion info).
 * @param usedCtx a context to update if a value was used from "ctx".
 *
 * @return the normalized string.
 */
static string _normalizeValue(
   DynamicObject& ctx, DynamicObject value,
   RdfType type, const char* predicate, DynamicObject* usedCtx)
{
   string rval;

   // "@" or "a"/RDF_TYPE predicates have values that are IRIs or CURIEs
   if(predicate != NULL &&
      (strcmp(predicate, "@") == 0 || strcmp(predicate, "a") == 0 ||
       strcmp(predicate, RDF_TYPE_NORM) == 0))
   {
      type = RDF_TYPE_IRI;
   }

   // IRI "@" is already normalized
   if(type == RDF_TYPE_IRI && strcmp(value, "@") == 0)
   {
      rval.assign(value);
   }
   // IRI "a" is special rdf type
   else if(type == RDF_TYPE_IRI && strcmp(value, "a") == 0)
   {
      rval.assign(RDF_TYPE_NORM);
   }
   else
   {
      string datatype;

      // look for type coercion info
      if(type == RDF_TYPE_UNKNOWN && predicate != NULL &&
         !ctx.isNull() && ctx->hasMember("#types") &&
         ctx["#types"]->hasMember(predicate))
      {
         DynamicObject& tci = ctx["#types"][predicate];
         if(usedCtx != NULL)
         {
            (*usedCtx)["#types"][predicate] = tci.clone();
         }

         // handle specific type
         if(tci->getType() == String)
         {
            rval = value->getString();
            datatype = _normalizeValue(ctx, tci, RDF_TYPE_IRI, NULL, usedCtx);
            type = (strcmp(datatype.c_str(), XSD_ANY_URI_NORM) == 0) ?
               RDF_TYPE_IRI : RDF_TYPE_TYPED_LITERAL;
         }
         // handle type preferences in order
         else
         {
            DynamicObjectIterator ti = tci.getIterator();
            while(type == RDF_TYPE_UNKNOWN && ti->hasNext())
            {
               // FIXME: if value works w/type, set value, datatype, type
               //type = RDF_TYPE_TYPED_LITERAL;
            }
         }
      }
      // determine type from DynamicObjectType
      else if(type == RDF_TYPE_UNKNOWN && value->getType() != String)
      {
         type = RDF_TYPE_TYPED_LITERAL;
         rval = value->getString();

         // handle native xsd types
         if(value->isNumber())
         {
            datatype = value->isInteger() ? XSD_INTEGER : XSD_DOUBLE;
         }
         else if(value->getType() == Boolean)
         {
            datatype = XSD_BOOLEAN;
         }
         else
         {
            // FIXME: this should never happen?
            datatype = XSD_ANY_TYPE;
         }
      }
      else
      {
         // JSON-LD decode
         RdfType t = type;
         _decode(value, type, rval, datatype);
         if(type == RDF_TYPE_TYPED_LITERAL)
         {
            _expandCurie(ctx, datatype.c_str(), datatype, usedCtx);
         }

         // preserve expected type
         if(t != RDF_TYPE_UNKNOWN)
         {
            type = t;
         }
      }

      // expand CURIE
      if(type == RDF_TYPE_IRI)
      {
         _expandCurie(ctx, rval.c_str(), rval, usedCtx);
      }

      // JSON-LD encode
      rval = _encode(type, rval.c_str(), datatype.c_str());
   }

   return rval;
}