<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/vfs/virtual_file_system.h"

#include "xenia/base/filesystem.h"
#include "xenia/base/logging.h"
#include "xenia/base/string.h"
#include "xenia/kernel/xfile.h"

namespace xe {
namespace vfs {

VirtualFileSystem::VirtualFileSystem() {}

VirtualFileSystem::~VirtualFileSystem() {
  // Delete all devices.
  // This will explode if anyone is still using data from them.
  devices_.clear();
  symlinks_.clear();
}

bool VirtualFileSystem::RegisterDevice(std::unique_ptr<Device> device) {
  auto global_lock = global_critical_region_.Acquire();
  devices_.emplace_back(std::move(device));
  return true;
}

bool VirtualFileSystem::UnregisterDevice(const std::string& path) {
  auto global_lock = global_critical_region_.Acquire();
  for (auto it = devices_.begin(); it != devices_.end(); ++it) {
    if ((*it)->mount_path() == path) {
      XELOGD("Unregistered device: %s", (*it)->mount_path().c_str());
      devices_.erase(it);
      return true;
    }
  }
  return false;
}

bool VirtualFileSystem::RegisterSymbolicLink(const std::string& path,
                                             const std::string& target) {
  auto global_lock = global_critical_region_.Acquire();
  symlinks_.insert({path, target});
  XELOGD("Registered symbolic link: %s => %s", path.c_str(), target.c_str());

  return true;
}

bool VirtualFileSystem::UnregisterSymbolicLink(const std::string& path) {
  auto global_lock = global_critical_region_.Acquire();
  auto it = symlinks_.find(path);
  if (it == symlinks_.end()) {
    return false;
  }
  XELOGD("Unregistered symbolic link: %s => %s", it->first.c_str(),
         it->second.c_str());

  symlinks_.erase(it);
  return true;
}

bool VirtualFileSystem::IsSymbolicLink(const std::string& path) {
  auto global_lock = global_critical_region_.Acquire();
  auto it = symlinks_.find(path);
  if (it == symlinks_.end()) {
    return false;
  }
  return true;
}

Entry* VirtualFileSystem::ResolvePath(const std::string& path) {
  auto global_lock = global_critical_region_.Acquire();

  // Resolve relative paths
  std::string normalized_path(xe::filesystem::CanonicalizePath(path));

  // Resolve symlinks.
  std::string device_path;
  std::string relative_path;
  for (int i = 0; i < 2; i++) {
    for (const auto& it : symlinks_) {
      if (xe::find_first_of_case(normalized_path, it.first) == 0) {
        // Found symlink!
        device_path = it.second;
        if (relative_path.empty()) {
          relative_path = normalized_path.substr(it.first.size());
        }

        // Bit of a cheaty move here, but allows double symlinks to be resolved.
        normalized_path = device_path;
        break;
      }
    }

    // Break as soon as we've completely resolved the symlinks to a device.
    if (!IsSymbolicLink(device_path)) {
      break;
    }
  }

  if (device_path.empty()) {
    // Symlink wasn't passed in - Check if we've received a raw device name.
    for (auto& device : devices_) {
      if (xe::find_first_of_case(normalized_path, device->mount_path()) == 0) {
        device_path = device->mount_path();
        relative_path = normalized_path.substr(device_path.size());
      }
    }
  }

  if (device_path.empty()) {
    XELOGE("ResolvePath(%s) failed - no root found", path.c_str());
    return nullptr;
  }

  // Scan all devices.
  for (auto& device : devices_) {
    if (strcasecmp(device_path.c_str(), device->mount_path().c_str()) == 0) {
      return device->ResolvePath(relative_path);
    }
  }

  XELOGE("ResolvePath(%s) failed - device not found (%s)", path.c_str(),
         device_path.c_str());
  return nullptr;
}

Entry* VirtualFileSystem::ResolveBasePath(const std::string& path) {
  auto base_path = xe::find_base_path(path);
  return ResolvePath(base_path);
}

Entry* VirtualFileSystem::CreatePath(const std::string& path,
                                     uint32_t attributes) {
  // Create all required directories recursively.
  auto path_parts = xe::split_path(path);
  if (path_parts.empty()) {
    return nullptr;
  }
  auto partial_path = path_parts[0];
  auto partial_entry = ResolvePath(partial_path);
  if (!partial_entry) {
    return nullptr;
  }
  auto parent_entry = partial_entry;
  for (size_t i = 1; i < path_parts.size() - 1; ++i) {
    partial_path = xe::join_paths(partial_path, path_parts[i]);
    auto child_entry = ResolvePath(partial_path);
    if (!child_entry) {
      child_entry =
          parent_entry->CreateEntry(path_parts[i], kFileAttributeDirectory);
    }
    if (!child_entry) {
      return nullptr;
    }
    parent_entry = child_entry;
  }
  return parent_entry->CreateEntry(path_parts[path_parts.size() - 1],
                                   attributes);
}

bool VirtualFileSystem::DeletePath(const std::string& path) {
  auto entry = ResolvePath(path);
  if (!entry) {
    return false;
  }
  auto parent = entry->parent();
  if (!parent) {
    // Can't delete root.
    return false;
  }
  return parent->Delete(entry);
}

X_STATUS VirtualFileSystem::OpenFile(const std::string& path,
                                     FileDisposition creation_disposition,
                                     uint32_t desired_access, bool is_directory,
                                     File** out_file, FileAction* out_action) {
  // TODO(gibbed): should 'is_directory' remain as a bool or should it be
  // flipped to a generic FileAttributeFlags?

  // Cleanup access.
  if (desired_access & FileAccess::kGenericRead) {
    desired_access |= FileAccess::kFileReadData;
  }
  if (desired_access & FileAccess::kGenericWrite) {
    desired_access |= FileAccess::kFileWriteData;
  }
  if (desired_access & FileAccess::kGenericAll) {
    desired_access |= FileAccess::kFileReadData | FileAccess::kFileWriteData;
  }

  // Lookup host device/parent path.
  // If no device or parent, fail.
  Entry* parent_entry = nullptr;
  Entry* entry = nullptr;
  if (!xe::find_base_path(path).empty()) {
    parent_entry = ResolveBasePath(path);
    if (!parent_entry) {
      *out_action = FileAction::kDoesNotExist;
      return X_STATUS_NO_SUCH_FILE;
    }

    auto file_name = xe::find_name_from_path(path);
    entry = parent_entry->GetChild(file_name);
  } else {
    entry = ResolvePath(path);
  }

  // Check if exists (if we need it to), or that it doesn't (if it shouldn't).
  switch (creation_disposition) {
    case FileDisposition::kOpen:
    case FileDisposition::kOverwrite:
      // Must exist.
      if (!entry) {
        *out_action = FileAction::kDoesNotExist;
        return X_STATUS_NO_SUCH_FILE;
      }
      break;
    case FileDisposition::kCreate:
      // Must not exist.
      if (entry) {
        *out_action = FileAction::kExists;
        return X_STATUS_OBJECT_NAME_COLLISION;
      }
      break;
    default:
      // Either way, ok.
      break;
  }

  // Verify permissions.
  bool wants_write = desired_access & FileAccess::kFileWriteData ||
                     desired_access & FileAccess::kFileAppendData;
  if (wants_write && ((parent_entry && parent_entry->is_read_only()) ||
                      (entry && entry->is_read_only()))) {
    // Fail if read only device and wants write.
    // return X_STATUS_ACCESS_DENIED;
    // TODO(benvanik): figure out why games are opening read-only files with
    // write modes.
    assert_always();
    XELOGW("Attempted to open the file/dir for create/write");
    desired_access = FileAccess::kGenericRead | FileAccess::kFileReadData;
  }

  bool created = false;
  if (!entry) {
    // Remember that we are creating this new, instead of replacing.
    created = true;
    *out_action = FileAction::kCreated;
  } else {
    // May need to delete, if it exists.
    switch (creation_disposition) {
      case FileDisposition::kCreate:
        // Shouldn't be possible to hit this.
        assert_always();
        return X_STATUS_ACCESS_DENIED;
      case FileDisposition::kSuperscede:
        // Replace (by delete + recreate).
        if (!entry->Delete()) {
          return X_STATUS_ACCESS_DENIED;
        }
        entry = nullptr;
        *out_action = FileAction::kSuperseded;
        break;
      case FileDisposition::kOpen:
      case FileDisposition::kOpenIf:
        // Normal open.
        *out_action = FileAction::kOpened;
        break;
      case FileDisposition::kOverwrite:
      case FileDisposition::kOverwriteIf:
        // Overwrite (we do by delete + recreate).
        if (!entry->Delete()) {
          return X_STATUS_ACCESS_DENIED;
        }
        entry = nullptr;
        *out_action = FileAction::kOverwritten;
        break;
    }
  }
  if (!entry) {
    // Create if needed (either new or as a replacement).
    entry = CreatePath(
        path, !directory ? kFileAttributeNormal : kFileAttributeDirectory);
    if (!entry) {
      return X_STATUS_ACCESS_DENIED;
    }
  }

  // Open.
  auto result = entry->Open(desired_access, out_file);
  if (XFAILED(result)) {
    *out_action = FileAction::kDoesNotExist;
  }
  return result;
}

}  // namespace vfs
}  // namespace xe
<commit_msg>[VFS] Fix an outdated commit of OpenFile that somehow slipped through.<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/vfs/virtual_file_system.h"

#include "xenia/base/filesystem.h"
#include "xenia/base/logging.h"
#include "xenia/base/string.h"
#include "xenia/kernel/xfile.h"

namespace xe {
namespace vfs {

VirtualFileSystem::VirtualFileSystem() {}

VirtualFileSystem::~VirtualFileSystem() {
  // Delete all devices.
  // This will explode if anyone is still using data from them.
  devices_.clear();
  symlinks_.clear();
}

bool VirtualFileSystem::RegisterDevice(std::unique_ptr<Device> device) {
  auto global_lock = global_critical_region_.Acquire();
  devices_.emplace_back(std::move(device));
  return true;
}

bool VirtualFileSystem::UnregisterDevice(const std::string& path) {
  auto global_lock = global_critical_region_.Acquire();
  for (auto it = devices_.begin(); it != devices_.end(); ++it) {
    if ((*it)->mount_path() == path) {
      XELOGD("Unregistered device: %s", (*it)->mount_path().c_str());
      devices_.erase(it);
      return true;
    }
  }
  return false;
}

bool VirtualFileSystem::RegisterSymbolicLink(const std::string& path,
                                             const std::string& target) {
  auto global_lock = global_critical_region_.Acquire();
  symlinks_.insert({path, target});
  XELOGD("Registered symbolic link: %s => %s", path.c_str(), target.c_str());

  return true;
}

bool VirtualFileSystem::UnregisterSymbolicLink(const std::string& path) {
  auto global_lock = global_critical_region_.Acquire();
  auto it = symlinks_.find(path);
  if (it == symlinks_.end()) {
    return false;
  }
  XELOGD("Unregistered symbolic link: %s => %s", it->first.c_str(),
         it->second.c_str());

  symlinks_.erase(it);
  return true;
}

bool VirtualFileSystem::IsSymbolicLink(const std::string& path) {
  auto global_lock = global_critical_region_.Acquire();
  auto it = symlinks_.find(path);
  if (it == symlinks_.end()) {
    return false;
  }
  return true;
}

Entry* VirtualFileSystem::ResolvePath(const std::string& path) {
  auto global_lock = global_critical_region_.Acquire();

  // Resolve relative paths
  std::string normalized_path(xe::filesystem::CanonicalizePath(path));

  // Resolve symlinks.
  std::string device_path;
  std::string relative_path;
  for (int i = 0; i < 2; i++) {
    for (const auto& it : symlinks_) {
      if (xe::find_first_of_case(normalized_path, it.first) == 0) {
        // Found symlink!
        device_path = it.second;
        if (relative_path.empty()) {
          relative_path = normalized_path.substr(it.first.size());
        }

        // Bit of a cheaty move here, but allows double symlinks to be resolved.
        normalized_path = device_path;
        break;
      }
    }

    // Break as soon as we've completely resolved the symlinks to a device.
    if (!IsSymbolicLink(device_path)) {
      break;
    }
  }

  if (device_path.empty()) {
    // Symlink wasn't passed in - Check if we've received a raw device name.
    for (auto& device : devices_) {
      if (xe::find_first_of_case(normalized_path, device->mount_path()) == 0) {
        device_path = device->mount_path();
        relative_path = normalized_path.substr(device_path.size());
      }
    }
  }

  if (device_path.empty()) {
    XELOGE("ResolvePath(%s) failed - no root found", path.c_str());
    return nullptr;
  }

  // Scan all devices.
  for (auto& device : devices_) {
    if (strcasecmp(device_path.c_str(), device->mount_path().c_str()) == 0) {
      return device->ResolvePath(relative_path);
    }
  }

  XELOGE("ResolvePath(%s) failed - device not found (%s)", path.c_str(),
         device_path.c_str());
  return nullptr;
}

Entry* VirtualFileSystem::ResolveBasePath(const std::string& path) {
  auto base_path = xe::find_base_path(path);
  return ResolvePath(base_path);
}

Entry* VirtualFileSystem::CreatePath(const std::string& path,
                                     uint32_t attributes) {
  // Create all required directories recursively.
  auto path_parts = xe::split_path(path);
  if (path_parts.empty()) {
    return nullptr;
  }
  auto partial_path = path_parts[0];
  auto partial_entry = ResolvePath(partial_path);
  if (!partial_entry) {
    return nullptr;
  }
  auto parent_entry = partial_entry;
  for (size_t i = 1; i < path_parts.size() - 1; ++i) {
    partial_path = xe::join_paths(partial_path, path_parts[i]);
    auto child_entry = ResolvePath(partial_path);
    if (!child_entry) {
      child_entry =
          parent_entry->CreateEntry(path_parts[i], kFileAttributeDirectory);
    }
    if (!child_entry) {
      return nullptr;
    }
    parent_entry = child_entry;
  }
  return parent_entry->CreateEntry(path_parts[path_parts.size() - 1],
                                   attributes);
}

bool VirtualFileSystem::DeletePath(const std::string& path) {
  auto entry = ResolvePath(path);
  if (!entry) {
    return false;
  }
  auto parent = entry->parent();
  if (!parent) {
    // Can't delete root.
    return false;
  }
  return parent->Delete(entry);
}

X_STATUS VirtualFileSystem::OpenFile(const std::string& path,
                                     FileDisposition creation_disposition,
                                     uint32_t desired_access, bool is_directory,
                                     File** out_file, FileAction* out_action) {
  // TODO(gibbed): should 'is_directory' remain as a bool or should it be
  // flipped to a generic FileAttributeFlags?

  // Cleanup access.
  if (desired_access & FileAccess::kGenericRead) {
    desired_access |= FileAccess::kFileReadData;
  }
  if (desired_access & FileAccess::kGenericWrite) {
    desired_access |= FileAccess::kFileWriteData;
  }
  if (desired_access & FileAccess::kGenericAll) {
    desired_access |= FileAccess::kFileReadData | FileAccess::kFileWriteData;
  }

  // Lookup host device/parent path.
  // If no device or parent, fail.
  Entry* parent_entry = nullptr;
  Entry* entry = nullptr;
  if (!xe::find_base_path(path).empty()) {
    parent_entry = ResolveBasePath(path);
    if (!parent_entry) {
      *out_action = FileAction::kDoesNotExist;
      return X_STATUS_NO_SUCH_FILE;
    }

    auto file_name = xe::find_name_from_path(path);
    entry = parent_entry->GetChild(file_name);
  } else {
    entry = ResolvePath(path);
  }

  // Check if exists (if we need it to), or that it doesn't (if it shouldn't).
  switch (creation_disposition) {
    case FileDisposition::kOpen:
    case FileDisposition::kOverwrite:
      // Must exist.
      if (!entry) {
        *out_action = FileAction::kDoesNotExist;
        return X_STATUS_NO_SUCH_FILE;
      }
      break;
    case FileDisposition::kCreate:
      // Must not exist.
      if (entry) {
        *out_action = FileAction::kExists;
        return X_STATUS_OBJECT_NAME_COLLISION;
      }
      break;
    default:
      // Either way, ok.
      break;
  }

  // Verify permissions.
  bool wants_write = desired_access & FileAccess::kFileWriteData ||
                     desired_access & FileAccess::kFileAppendData;
  if (wants_write && ((parent_entry && parent_entry->is_read_only()) ||
                      (entry && entry->is_read_only()))) {
    // Fail if read only device and wants write.
    // return X_STATUS_ACCESS_DENIED;
    // TODO(benvanik): figure out why games are opening read-only files with
    // write modes.
    assert_always();
    XELOGW("Attempted to open the file/dir for create/write");
    desired_access = FileAccess::kGenericRead | FileAccess::kFileReadData;
  }

  bool created = false;
  if (!entry) {
    // Remember that we are creating this new, instead of replacing.
    created = true;
    *out_action = FileAction::kCreated;
  } else {
    // May need to delete, if it exists.
    switch (creation_disposition) {
      case FileDisposition::kCreate:
        // Shouldn't be possible to hit this.
        assert_always();
        return X_STATUS_ACCESS_DENIED;
      case FileDisposition::kSuperscede:
        // Replace (by delete + recreate).
        if (!entry->Delete()) {
          return X_STATUS_ACCESS_DENIED;
        }
        entry = nullptr;
        *out_action = FileAction::kSuperseded;
        break;
      case FileDisposition::kOpen:
      case FileDisposition::kOpenIf:
        // Normal open.
        *out_action = FileAction::kOpened;
        break;
      case FileDisposition::kOverwrite:
      case FileDisposition::kOverwriteIf:
        // Overwrite (we do by delete + recreate).
        if (!entry->Delete()) {
          return X_STATUS_ACCESS_DENIED;
        }
        entry = nullptr;
        *out_action = FileAction::kOverwritten;
        break;
    }
  }
  if (!entry) {
    // Create if needed (either new or as a replacement).
    entry = CreatePath(
        path, !is_directory ? kFileAttributeNormal : kFileAttributeDirectory);
    if (!entry) {
      return X_STATUS_ACCESS_DENIED;
    }
  }

  // Open.
  auto result = entry->Open(desired_access, out_file);
  if (XFAILED(result)) {
    *out_action = FileAction::kDoesNotExist;
  }
  return result;
}

}  // namespace vfs
}  // namespace xe
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include "DocumentDBServlet.h"

using namespace stx;

namespace zbase {

DocumentDBServlet::DocumentDBServlet(
    DocumentDB* docdb) :
    docdb_(docdb) {}

void DocumentDBServlet::handle(
    const AnalyticsSession& session,
    const stx::http::HTTPRequest* req,
    stx::http::HTTPResponse* res) {
  static const String kPathPrefix = "/api/v1/documents";
  URI uri(req->uri());

  // LIST
  if (req->method() == http::HTTPMessage::M_GET &&
      uri.path() == kPathPrefix) {
    listDocuments(session, req, res);
    return;
  }

  // GET
  if (req->method() == http::HTTPMessage::M_GET &&
      StringUtil::beginsWith(uri.path(), kPathPrefix)) {
    auto docid = SHA1Hash::fromHexString(
        uri.path().substr(kPathPrefix.size() + 1));

    fetchDocument(docid, uri, session, req, res);
    return;
  }

  // CREATE
  if (req->method() == http::HTTPMessage::M_POST &&
      uri.path() == kPathPrefix) {
    createDocument(uri, session, req, res);
    return;
  }

  // UPDATE
  if (req->method() == http::HTTPMessage::M_POST &&
      StringUtil::beginsWith(uri.path(), kPathPrefix)) {
    auto docid = SHA1Hash::fromHexString(
        uri.path().substr(kPathPrefix.size() + 1));

    updateDocument(docid, uri, session, req, res);
    return;
  }

  res->setStatus(stx::http::kStatusNotFound);
  res->addBody("not found");
}

void DocumentDBServlet::fetchDocument(
    const SHA1Hash& uuid,
    const URI& uri,
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  const auto& params = uri.queryParams();

  bool return_content = true;
  String no_content_str;
  if (URI::getParam(params, "no_content", &no_content_str)) {
    return_content = false;
  }

  Document doc;
  if (docdb_->fetchDocument(session.customer(), session.userid(), uuid, &doc)) {
    Buffer buf;
    renderDocument(session, doc, &buf, return_content);
    res->setStatus(http::kStatusOK);
    res->addBody(buf);
  } else {
    res->setStatus(http::kStatusNotFound);
    res->addBody("not found");
  }
}

void DocumentDBServlet::createDocument(
    const URI& uri,
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  URI::ParamList params;
  URI::parseQueryString(req->body().toString(), &params);

  String name;
  if (!URI::getParam(params, "name", &name)) {
    res->setStatus(http::kStatusBadRequest);
    res->addBody("missing ?name=... parameter");
  }

  String type;
  if (!URI::getParam(params, "type", &type)) {
    res->setStatus(http::kStatusBadRequest);
    res->addBody("missing ?type=... parameter");
  }

  auto now = WallClock::unixMicros();

  Document doc;
  doc.set_uuid(Random::singleton()->sha1().toString());
  doc.set_name(name);
  doc.set_type(type);
  doc.set_version(0);
  doc.set_ctime(now);
  doc.set_mtime(now);
  doc.set_atime(now);

  setDefaultDocumentACLs(&doc, session.userid());

  docdb_->createDocument(session.customer(), doc);

  Buffer buf;
  renderDocument(session, doc, &buf);
  res->setStatus(http::kStatusCreated);
  res->addBody(buf);
}

void DocumentDBServlet::updateDocument(
    const SHA1Hash& uuid,
    const URI& uri,
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  URI::ParamList params;
  URI::parseQueryString(req->body().toString(), &params);

  Vector<Function<void ()>> tx;

  for (const auto& p : params) {

    if (p.first == "content") {
      if (!p.second.empty()) {
        tx.emplace_back([this, &session, &uuid, p] () {
          docdb_->updateDocumentContent(
              session.customer(),
              session.userid(),
              uuid,
              p.second);
        });
      }

      continue;
    }

    if (p.first == "name") {
      if (!p.second.empty()) {
        tx.emplace_back([this, &session, &uuid, p] () {
          docdb_->updateDocumentName(
              session.customer(),
              session.userid(),
              uuid,
              p.second);
        });
      }

      continue;
    }

    if (p.first == "acl_policy") {
      if (!p.second.empty()) {
        DocumentACLPolicy policy;
        if (!DocumentACLPolicy_Parse(p.second, &policy)) {
          res->setStatus(http::kStatusBadRequest);
          res->addBody(StringUtil::format("invalid policy: '$0'", p.second));
          return;
        }

        tx.emplace_back([this, &session, &uuid, policy] () {
          docdb_->updateDocumentACLPolicy(
              session.customer(),
              session.userid(),
              uuid,
              policy);
        });
      }

      continue;
    }

    res->setStatus(http::kStatusBadRequest);
    res->addBody(StringUtil::format("invalid parameter: '$0'", p.first));
    return;
  }

  for (const auto& fn : tx) {
    fn();
  }

  res->setStatus(http::kStatusCreated);
}

void DocumentDBServlet::listDocuments(
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  Buffer buf;
  json::JSONOutputStream json(BufferOutputStream::fromBuffer(&buf));

  json.beginObject();
  json.addObjectEntry("documents");
  json.beginArray();

  size_t i = 0;
  docdb_->listDocuments(
      session.customer(),
      session.userid(),
      [&i, &json, &session] (const Document& doc) -> bool {
    if (++i > 1) {
      json.addComma();
    }

    json.beginObject();

    json.addObjectEntry("uuid");
    json.addString(doc.uuid());
    json.addComma();

    json.addObjectEntry("name");
    json.addString(doc.name());
    json.addComma();

    json.addObjectEntry("type");
    json.addString(doc.type());

    json.endObject();

    return true;
  });

  json.endArray();
  json.endObject();

  res->setStatus(http::kStatusOK);
  res->setHeader("Content-Type", "application/json; charset=utf-8");
  res->addBody(buf);
}

void DocumentDBServlet::renderDocument(
    const AnalyticsSession& session,
    const Document& doc,
    Buffer* buf,
    bool return_content /* = true */) {
  json::JSONOutputStream json(BufferOutputStream::fromBuffer(buf));

  json.beginObject();

  json.addObjectEntry("uuid");
  json.addString(doc.uuid());
  json.addComma();

  json.addObjectEntry("name");
  json.addString(doc.name());
  json.addComma();

  json.addObjectEntry("is_readable");
  json.addBool(isDocumentReadableForUser(doc, session.userid()));
  json.addComma();

  json.addObjectEntry("is_writable");
  json.addBool(isDocumentWritableForUser(doc, session.userid()));

  if (return_content) {
    json.addComma();
    json.addObjectEntry("content");
    json.addString(doc.content());
  }

  json.endObject();
}

} // namespace zbase
<commit_msg>add acl_policy to doc api json response<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include "DocumentDBServlet.h"

using namespace stx;

namespace zbase {

DocumentDBServlet::DocumentDBServlet(
    DocumentDB* docdb) :
    docdb_(docdb) {}

void DocumentDBServlet::handle(
    const AnalyticsSession& session,
    const stx::http::HTTPRequest* req,
    stx::http::HTTPResponse* res) {
  static const String kPathPrefix = "/api/v1/documents";
  URI uri(req->uri());

  // LIST
  if (req->method() == http::HTTPMessage::M_GET &&
      uri.path() == kPathPrefix) {
    listDocuments(session, req, res);
    return;
  }

  // GET
  if (req->method() == http::HTTPMessage::M_GET &&
      StringUtil::beginsWith(uri.path(), kPathPrefix)) {
    auto docid = SHA1Hash::fromHexString(
        uri.path().substr(kPathPrefix.size() + 1));

    fetchDocument(docid, uri, session, req, res);
    return;
  }

  // CREATE
  if (req->method() == http::HTTPMessage::M_POST &&
      uri.path() == kPathPrefix) {
    createDocument(uri, session, req, res);
    return;
  }

  // UPDATE
  if (req->method() == http::HTTPMessage::M_POST &&
      StringUtil::beginsWith(uri.path(), kPathPrefix)) {
    auto docid = SHA1Hash::fromHexString(
        uri.path().substr(kPathPrefix.size() + 1));

    updateDocument(docid, uri, session, req, res);
    return;
  }

  res->setStatus(stx::http::kStatusNotFound);
  res->addBody("not found");
}

void DocumentDBServlet::fetchDocument(
    const SHA1Hash& uuid,
    const URI& uri,
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  const auto& params = uri.queryParams();

  bool return_content = true;
  String no_content_str;
  if (URI::getParam(params, "no_content", &no_content_str)) {
    return_content = false;
  }

  Document doc;
  if (docdb_->fetchDocument(session.customer(), session.userid(), uuid, &doc)) {
    Buffer buf;
    renderDocument(session, doc, &buf, return_content);
    res->setStatus(http::kStatusOK);
    res->addBody(buf);
  } else {
    res->setStatus(http::kStatusNotFound);
    res->addBody("not found");
  }
}

void DocumentDBServlet::createDocument(
    const URI& uri,
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  URI::ParamList params;
  URI::parseQueryString(req->body().toString(), &params);

  String name;
  if (!URI::getParam(params, "name", &name)) {
    res->setStatus(http::kStatusBadRequest);
    res->addBody("missing ?name=... parameter");
  }

  String type;
  if (!URI::getParam(params, "type", &type)) {
    res->setStatus(http::kStatusBadRequest);
    res->addBody("missing ?type=... parameter");
  }

  auto now = WallClock::unixMicros();

  Document doc;
  doc.set_uuid(Random::singleton()->sha1().toString());
  doc.set_name(name);
  doc.set_type(type);
  doc.set_version(0);
  doc.set_ctime(now);
  doc.set_mtime(now);
  doc.set_atime(now);

  setDefaultDocumentACLs(&doc, session.userid());

  docdb_->createDocument(session.customer(), doc);

  Buffer buf;
  renderDocument(session, doc, &buf);
  res->setStatus(http::kStatusCreated);
  res->addBody(buf);
}

void DocumentDBServlet::updateDocument(
    const SHA1Hash& uuid,
    const URI& uri,
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  URI::ParamList params;
  URI::parseQueryString(req->body().toString(), &params);

  Vector<Function<void ()>> tx;

  for (const auto& p : params) {

    if (p.first == "content") {
      if (!p.second.empty()) {
        tx.emplace_back([this, &session, &uuid, p] () {
          docdb_->updateDocumentContent(
              session.customer(),
              session.userid(),
              uuid,
              p.second);
        });
      }

      continue;
    }

    if (p.first == "name") {
      if (!p.second.empty()) {
        tx.emplace_back([this, &session, &uuid, p] () {
          docdb_->updateDocumentName(
              session.customer(),
              session.userid(),
              uuid,
              p.second);
        });
      }

      continue;
    }

    if (p.first == "acl_policy") {
      if (!p.second.empty()) {
        DocumentACLPolicy policy;
        if (!DocumentACLPolicy_Parse(p.second, &policy)) {
          res->setStatus(http::kStatusBadRequest);
          res->addBody(StringUtil::format("invalid policy: '$0'", p.second));
          return;
        }

        tx.emplace_back([this, &session, &uuid, policy] () {
          docdb_->updateDocumentACLPolicy(
              session.customer(),
              session.userid(),
              uuid,
              policy);
        });
      }

      continue;
    }

    res->setStatus(http::kStatusBadRequest);
    res->addBody(StringUtil::format("invalid parameter: '$0'", p.first));
    return;
  }

  for (const auto& fn : tx) {
    fn();
  }

  res->setStatus(http::kStatusCreated);
}

void DocumentDBServlet::listDocuments(
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  Buffer buf;
  json::JSONOutputStream json(BufferOutputStream::fromBuffer(&buf));

  json.beginObject();
  json.addObjectEntry("documents");
  json.beginArray();

  size_t i = 0;
  docdb_->listDocuments(
      session.customer(),
      session.userid(),
      [&i, &json, &session] (const Document& doc) -> bool {
    if (++i > 1) {
      json.addComma();
    }

    json.beginObject();

    json.addObjectEntry("uuid");
    json.addString(doc.uuid());
    json.addComma();

    json.addObjectEntry("name");
    json.addString(doc.name());
    json.addComma();

    json.addObjectEntry("type");
    json.addString(doc.type());

    json.endObject();

    return true;
  });

  json.endArray();
  json.endObject();

  res->setStatus(http::kStatusOK);
  res->setHeader("Content-Type", "application/json; charset=utf-8");
  res->addBody(buf);
}

void DocumentDBServlet::renderDocument(
    const AnalyticsSession& session,
    const Document& doc,
    Buffer* buf,
    bool return_content /* = true */) {
  json::JSONOutputStream json(BufferOutputStream::fromBuffer(buf));

  json.beginObject();

  json.addObjectEntry("uuid");
  json.addString(doc.uuid());
  json.addComma();

  json.addObjectEntry("name");
  json.addString(doc.name());
  json.addComma();

  json.addObjectEntry("acl_policy");
  json.addString(DocumentACLPolicy_Name(doc.acl_policy()));
  json.addComma();

  json.addObjectEntry("is_readable");
  json.addBool(isDocumentReadableForUser(doc, session.userid()));
  json.addComma();

  json.addObjectEntry("is_writable");
  json.addBool(isDocumentWritableForUser(doc, session.userid()));

  if (return_content) {
    json.addComma();
    json.addObjectEntry("content");
    json.addString(doc.content());
  }

  json.endObject();
}

} // namespace zbase
<|endoftext|>


<commit_before>// RUN: rm -rf %t
// RUN: cd %S
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -emit-module -fmodule-name=m00 -o %t/m00.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -emit-module -fmodule-name=m00 -o %t/m00_check.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// RUN: diff %t/m00.pcm %t/m00_check.pcm
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -emit-module -fmodule-name=m01 -o %t/m01.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -emit-module -fmodule-name=m02 -o %t/m02.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -emit-module -fmodule-name=m03 -o %t/m03.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -fmodule-file=%t/m00.pcm \
// RUN:   -fmodule-file=%t/m01.pcm \
// RUN:   -fmodule-file=%t/m02.pcm \
// RUN:   -fmodule-file=%t/m03.pcm \
// RUN:   -emit-module -fmodule-name=merge00 -o %t/merge00.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -fmodule-file=%t/m00.pcm \
// RUN:   -fmodule-file=%t/m01.pcm \
// RUN:   -fmodule-file=%t/m02.pcm \
// RUN:   -fmodule-file=%t/m03.pcm \
// RUN:   -emit-module -fmodule-name=merge00 -o %t/merge00_check.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// FIXME: diff %t/merge00.pcm %t/merge00_check.pcm
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -fmodule-map-file=Inputs/stress1/module.modulemap \
// RUN:   -fmodule-file=%t/m00.pcm \
// RUN:   -fmodule-file=%t/m01.pcm \
// RUN:   -fmodule-file=%t/m02.pcm \
// RUN:   -fmodule-file=%t/m03.pcm \
// RUN:   -fmodule-file=%t/merge00.pcm \
// RUN:   -verify stress1.cpp -S -emit-llvm -o %t/stress1.ll
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -fmodule-map-file=Inputs/stress1/module.modulemap \
// RUN:   -fmodule-file=%t/m00.pcm \
// RUN:   -fmodule-file=%t/m01.pcm \
// RUN:   -fmodule-file=%t/m02.pcm \
// RUN:   -fmodule-file=%t/m03.pcm \
// RUN:   -fmodule-file=%t/merge00.pcm \
// RUN:   -verify stress1.cpp -S -emit-llvm -o %t/stress1_check.ll
//
// RUN: diff -u %t/stress1.ll %t/stress1_check.ll
//
// expected-no-diagnostics

#include "m00.h"
#include "m01.h"
#include "m02.h"
#include "m03.h"

#include "merge00.h"

int f() { return N01::S00('a').method00('b') + (int)N00::S00(42) + function00(42) + g(); }
<commit_msg>Temporarily disable one more non-determinism flag.<commit_after>// RUN: rm -rf %t
// RUN: cd %S
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -emit-module -fmodule-name=m00 -o %t/m00.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -emit-module -fmodule-name=m00 -o %t/m00_check.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// FIXME: diff %t/m00.pcm %t/m00_check.pcm
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -emit-module -fmodule-name=m01 -o %t/m01.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -emit-module -fmodule-name=m02 -o %t/m02.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -emit-module -fmodule-name=m03 -o %t/m03.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -fmodule-file=%t/m00.pcm \
// RUN:   -fmodule-file=%t/m01.pcm \
// RUN:   -fmodule-file=%t/m02.pcm \
// RUN:   -fmodule-file=%t/m03.pcm \
// RUN:   -emit-module -fmodule-name=merge00 -o %t/merge00.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -fmodule-file=%t/m00.pcm \
// RUN:   -fmodule-file=%t/m01.pcm \
// RUN:   -fmodule-file=%t/m02.pcm \
// RUN:   -fmodule-file=%t/m03.pcm \
// RUN:   -emit-module -fmodule-name=merge00 -o %t/merge00_check.pcm \
// RUN:   Inputs/stress1/module.modulemap
//
// FIXME: diff %t/merge00.pcm %t/merge00_check.pcm
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -fmodule-map-file=Inputs/stress1/module.modulemap \
// RUN:   -fmodule-file=%t/m00.pcm \
// RUN:   -fmodule-file=%t/m01.pcm \
// RUN:   -fmodule-file=%t/m02.pcm \
// RUN:   -fmodule-file=%t/m03.pcm \
// RUN:   -fmodule-file=%t/merge00.pcm \
// RUN:   -verify stress1.cpp -S -emit-llvm -o %t/stress1.ll
//
// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 \
// RUN:   -I Inputs/stress1 \
// RUN:   -fno-implicit-modules -fno-modules-implicit-maps \
// RUN:   -fmodule-map-file-home-is-cwd \
// RUN:   -fmodule-map-file=Inputs/stress1/module.modulemap \
// RUN:   -fmodule-file=%t/m00.pcm \
// RUN:   -fmodule-file=%t/m01.pcm \
// RUN:   -fmodule-file=%t/m02.pcm \
// RUN:   -fmodule-file=%t/m03.pcm \
// RUN:   -fmodule-file=%t/merge00.pcm \
// RUN:   -verify stress1.cpp -S -emit-llvm -o %t/stress1_check.ll
//
// RUN: diff -u %t/stress1.ll %t/stress1_check.ll
//
// expected-no-diagnostics

#include "m00.h"
#include "m01.h"
#include "m02.h"
#include "m03.h"

#include "merge00.h"

int f() { return N01::S00('a').method00('b') + (int)N00::S00(42) + function00(42) + g(); }
<|endoftext|>


<commit_before>#include <ir/index_manager/index/Indexer.h>
#include <ir/index_manager/index/CollectionIndexer.h>
#include <ir/index_manager/index/TermReader.h>
#include <ir/index_manager/index/IndexBarrelWriter.h>
#include <ir/index_manager/index/IndexerPropertyConfig.h>

#include <ir/index_manager/utility/StringUtils.h>

#include <ir/index_manager/store/IndexOutput.h>

#include <boost/variant.hpp>
#include <boost/shared_ptr.hpp>

#include <algorithm>
#include <deque>
#include <cstring>

using namespace std;
using namespace izenelib::util;

using namespace izenelib::ir::indexmanager;

CollectionIndexer::CollectionIndexer(collectionid_t id, MemCache* pCache, Indexer* pIndexer)
        :colID_(id)
        ,pMemCache_(pCache)
        ,pIndexer_(pIndexer)
        ,pDocLengthWriter_(NULL)
        ,docLengthWidth_(0)
{
    pFieldsInfo_ = new FieldsInfo();
}

CollectionIndexer::~CollectionIndexer()
{
    delete pFieldsInfo_;
    pMemCache_ = NULL;
    pIndexer_ = NULL;
    if (pDocLengthWriter_)
    {
        delete pDocLengthWriter_;
        pDocLengthWriter_ = NULL;
    }
}

void CollectionIndexer::setSchema(const IndexerCollectionMeta& schema)
{
    pFieldsInfo_->setSchema(schema);
    if (pIndexer_->getIndexManagerConfig()->indexStrategy_.indexDocLength_)
    {
        pDocLengthWriter_ = new DocLengthWriter(schema.getDocumentSchema(), pIndexer_->getDirectory());
        docLengthWidth_ = pDocLengthWriter_->get_num_properties();
    }
}

void CollectionIndexer::setFieldIndexers()
{
    size_t memCacheSize = (size_t)pIndexer_->getIndexManagerConfig()->indexStrategy_.memory_;

    pFieldsInfo_->startIterator();
    FieldInfo* pFieldInfo = NULL;
    size_t indexedProperties = 0;
    while (pFieldsInfo_->hasNext())
    {
        pFieldInfo = pFieldsInfo_->next();
        if (pFieldInfo->isIndexed()&&pFieldInfo->isAnalyzed())
            indexedProperties++;
    }

    memCacheSize = (memCacheSize/indexedProperties) < 50*1024*1024 ?
                              50*1024*1024:(memCacheSize/indexedProperties) ;

    pFieldsInfo_->startIterator();

    while (pFieldsInfo_->hasNext())
    {
        pFieldInfo = pFieldsInfo_->next();
        if (pFieldInfo->isIndexed()&&pFieldInfo->isAnalyzed())
        {
            FieldIndexer* pFieldIndexer = new FieldIndexer(pFieldInfo->getName(), pMemCache_,pIndexer_);
            fieldIndexerMap_.insert(make_pair(pFieldInfo->getName(),pFieldIndexer));
            pFieldIndexer->setHitBuffer(memCacheSize);
        }
    }
}

void CollectionIndexer::addDocument(IndexerDocument& doc)
{
    DocId uniqueID;
    doc.getDocId(uniqueID);

    map<IndexerPropertyConfig, IndexerDocumentPropertyType> propertyValueList;
    doc.getPropertyList(propertyValueList);

    doclen_t docLength[docLengthWidth_];
    memset(docLength, 0, docLengthWidth_*sizeof(doclen_t));

    for (map<IndexerPropertyConfig, IndexerDocumentPropertyType>::iterator iter
                            = propertyValueList.begin(); iter != propertyValueList.end(); ++iter)
    {
        if (!iter->first.isIndex())
            continue;

        if (iter->first.isFilter())
        {
            if(iter->first.isMultiValue())
            {
                MultiValuePropertyType prop;
                if (iter->first.isAnalyzed())
                    prop = boost::get<MultiValueIndexPropertyType >(iter->second).second;
                else
                    prop = boost::get<MultiValuePropertyType>(iter->second);

                for(MultiValuePropertyType::iterator it = prop.begin(); it != prop.end(); ++it)
                    pIndexer_->getBTreeIndexer()->add(uniqueID.colId, iter->first.getPropertyId(), *it, uniqueID.docId);
            }
            else
            {
                PropertyType prop;
                if (iter->first.isAnalyzed())
                    prop = boost::get<IndexPropertyType >(iter->second).second;
                else
                    prop = boost::get<PropertyType>(iter->second);

                pIndexer_->getBTreeIndexer()->add(uniqueID.colId, iter->first.getPropertyId(), prop, uniqueID.docId);
            }
        }

        if (iter->first.isAnalyzed())
        {
            map<string, boost::shared_ptr<FieldIndexer> >::iterator it = fieldIndexerMap_.find(iter->first.getName());
            if (it == fieldIndexerMap_.end())
                // This field is not indexed.
                continue;

            boost::shared_ptr<LAInput> laInput;
            if (iter->first.isFilter())
                if(iter->first.isMultiValue())
                    laInput = boost::get<MultiValueIndexPropertyType >(iter->second).first;
                else
                    laInput = boost::get<IndexPropertyType >(iter->second).first;
            else
                laInput = boost::get<boost::shared_ptr<LAInput> >(iter->second);

            it->second->addField(uniqueID.docId, laInput);

            if (pDocLengthWriter_ && iter->first.isStoreDocLen())
                pDocLengthWriter_->fill(iter->first.getPropertyId(), laInput->size(), docLength);
        }
    }

    if (pDocLengthWriter_)
        pDocLengthWriter_->add(uniqueID.docId, docLength);
}

void CollectionIndexer::write(OutputDescriptor* desc)
{
    IndexOutput* pVocOutput = desc->getVocOutput();
    IndexOutput* pDOutput = desc->getDPostingOutput();
    IndexOutput* pPOutput = desc->getPPostingOutput();

    fileoffset_t vocOff1,vocOff2,dfiOff1,dfiOff2,ptiOff1,ptiOff2;
    fileoffset_t vocOffset;

    FieldIndexer* pFieldIndexer;
    for (map<string, boost::shared_ptr<FieldIndexer> >::iterator iter =
                    fieldIndexerMap_.begin(); iter != fieldIndexerMap_.end(); ++iter)
    {
        pFieldIndexer = iter->second.get();
        if (pFieldIndexer == NULL)
            continue;
        vocOff1 = pVocOutput->getFilePointer();
        dfiOff1 = pDOutput->getFilePointer();
        ptiOff1 = pPOutput->getFilePointer();
        vocOffset = pFieldIndexer->write(desc);///write field index data

        pFieldsInfo_->setDistinctNumTerms(iter->first,pFieldIndexer->distinctNumTerms());
        pFieldsInfo_->setFieldOffset(iter->first,vocOffset);

        vocOff2 = pVocOutput->getFilePointer();
        dfiOff2 = pDOutput->getFilePointer();
        ptiOff2 = pPOutput->getFilePointer();

        pFieldsInfo_->getField(iter->first)->
                setLength(vocOff2-vocOff1,dfiOff2-dfiOff1,ptiOff2-ptiOff1);
    }
    if (pDocLengthWriter_)
        pDocLengthWriter_->flush();
}

void CollectionIndexer::reset()
{
    for (map<string, boost::shared_ptr<FieldIndexer> >::iterator iter =
                fieldIndexerMap_.begin(); iter != fieldIndexerMap_.end(); ++iter)
    {
        iter->second->reset();
    }
}

FieldIndexer* CollectionIndexer::getFieldIndexer(const char* field)
{
    string fieldstr(field);
    FieldIndexer* fieldIndexer = fieldIndexerMap_[fieldstr].get();
    return fieldIndexer;
}

<commit_msg>min memory pool size for each property is reduced from 50M to 10M<commit_after>#include <ir/index_manager/index/Indexer.h>
#include <ir/index_manager/index/CollectionIndexer.h>
#include <ir/index_manager/index/TermReader.h>
#include <ir/index_manager/index/IndexBarrelWriter.h>
#include <ir/index_manager/index/IndexerPropertyConfig.h>

#include <ir/index_manager/utility/StringUtils.h>

#include <ir/index_manager/store/IndexOutput.h>

#include <boost/variant.hpp>
#include <boost/shared_ptr.hpp>

#include <algorithm>
#include <deque>
#include <cstring>

using namespace std;
using namespace izenelib::util;

using namespace izenelib::ir::indexmanager;

CollectionIndexer::CollectionIndexer(collectionid_t id, MemCache* pCache, Indexer* pIndexer)
        :colID_(id)
        ,pMemCache_(pCache)
        ,pIndexer_(pIndexer)
        ,pDocLengthWriter_(NULL)
        ,docLengthWidth_(0)
{
    pFieldsInfo_ = new FieldsInfo();
}

CollectionIndexer::~CollectionIndexer()
{
    delete pFieldsInfo_;
    pMemCache_ = NULL;
    pIndexer_ = NULL;
    if (pDocLengthWriter_)
    {
        delete pDocLengthWriter_;
        pDocLengthWriter_ = NULL;
    }
}

void CollectionIndexer::setSchema(const IndexerCollectionMeta& schema)
{
    pFieldsInfo_->setSchema(schema);
    if (pIndexer_->getIndexManagerConfig()->indexStrategy_.indexDocLength_)
    {
        pDocLengthWriter_ = new DocLengthWriter(schema.getDocumentSchema(), pIndexer_->getDirectory());
        docLengthWidth_ = pDocLengthWriter_->get_num_properties();
    }
}

void CollectionIndexer::setFieldIndexers()
{
    size_t memCacheSize = (size_t)pIndexer_->getIndexManagerConfig()->indexStrategy_.memory_;

    pFieldsInfo_->startIterator();
    FieldInfo* pFieldInfo = NULL;
    size_t indexedProperties = 0;
    while (pFieldsInfo_->hasNext())
    {
        pFieldInfo = pFieldsInfo_->next();
        if (pFieldInfo->isIndexed()&&pFieldInfo->isAnalyzed())
            indexedProperties++;
    }

    memCacheSize = (memCacheSize/indexedProperties) < 10*1024*1024 ?
                              10*1024*1024:(memCacheSize/indexedProperties) ;

    pFieldsInfo_->startIterator();

    while (pFieldsInfo_->hasNext())
    {
        pFieldInfo = pFieldsInfo_->next();
        if (pFieldInfo->isIndexed()&&pFieldInfo->isAnalyzed())
        {
            FieldIndexer* pFieldIndexer = new FieldIndexer(pFieldInfo->getName(), pMemCache_,pIndexer_);
            fieldIndexerMap_.insert(make_pair(pFieldInfo->getName(),pFieldIndexer));
            pFieldIndexer->setHitBuffer(memCacheSize);
        }
    }
}

void CollectionIndexer::addDocument(IndexerDocument& doc)
{
    DocId uniqueID;
    doc.getDocId(uniqueID);

    map<IndexerPropertyConfig, IndexerDocumentPropertyType> propertyValueList;
    doc.getPropertyList(propertyValueList);

    doclen_t docLength[docLengthWidth_];
    memset(docLength, 0, docLengthWidth_*sizeof(doclen_t));

    for (map<IndexerPropertyConfig, IndexerDocumentPropertyType>::iterator iter
                            = propertyValueList.begin(); iter != propertyValueList.end(); ++iter)
    {
        if (!iter->first.isIndex())
            continue;

        if (iter->first.isFilter())
        {
            if(iter->first.isMultiValue())
            {
                MultiValuePropertyType prop;
                if (iter->first.isAnalyzed())
                    prop = boost::get<MultiValueIndexPropertyType >(iter->second).second;
                else
                    prop = boost::get<MultiValuePropertyType>(iter->second);

                for(MultiValuePropertyType::iterator it = prop.begin(); it != prop.end(); ++it)
                    pIndexer_->getBTreeIndexer()->add(uniqueID.colId, iter->first.getPropertyId(), *it, uniqueID.docId);
            }
            else
            {
                PropertyType prop;
                if (iter->first.isAnalyzed())
                    prop = boost::get<IndexPropertyType >(iter->second).second;
                else
                    prop = boost::get<PropertyType>(iter->second);

                pIndexer_->getBTreeIndexer()->add(uniqueID.colId, iter->first.getPropertyId(), prop, uniqueID.docId);
            }
        }

        if (iter->first.isAnalyzed())
        {
            map<string, boost::shared_ptr<FieldIndexer> >::iterator it = fieldIndexerMap_.find(iter->first.getName());
            if (it == fieldIndexerMap_.end())
                // This field is not indexed.
                continue;

            boost::shared_ptr<LAInput> laInput;
            if (iter->first.isFilter())
                if(iter->first.isMultiValue())
                    laInput = boost::get<MultiValueIndexPropertyType >(iter->second).first;
                else
                    laInput = boost::get<IndexPropertyType >(iter->second).first;
            else
                laInput = boost::get<boost::shared_ptr<LAInput> >(iter->second);

            it->second->addField(uniqueID.docId, laInput);

            if (pDocLengthWriter_ && iter->first.isStoreDocLen())
                pDocLengthWriter_->fill(iter->first.getPropertyId(), laInput->size(), docLength);
        }
    }

    if (pDocLengthWriter_)
        pDocLengthWriter_->add(uniqueID.docId, docLength);
}

void CollectionIndexer::write(OutputDescriptor* desc)
{
    IndexOutput* pVocOutput = desc->getVocOutput();
    IndexOutput* pDOutput = desc->getDPostingOutput();
    IndexOutput* pPOutput = desc->getPPostingOutput();

    fileoffset_t vocOff1,vocOff2,dfiOff1,dfiOff2,ptiOff1,ptiOff2;
    fileoffset_t vocOffset;

    FieldIndexer* pFieldIndexer;
    for (map<string, boost::shared_ptr<FieldIndexer> >::iterator iter =
                    fieldIndexerMap_.begin(); iter != fieldIndexerMap_.end(); ++iter)
    {
        pFieldIndexer = iter->second.get();
        if (pFieldIndexer == NULL)
            continue;
        vocOff1 = pVocOutput->getFilePointer();
        dfiOff1 = pDOutput->getFilePointer();
        ptiOff1 = pPOutput->getFilePointer();
        vocOffset = pFieldIndexer->write(desc);///write field index data

        pFieldsInfo_->setDistinctNumTerms(iter->first,pFieldIndexer->distinctNumTerms());
        pFieldsInfo_->setFieldOffset(iter->first,vocOffset);

        vocOff2 = pVocOutput->getFilePointer();
        dfiOff2 = pDOutput->getFilePointer();
        ptiOff2 = pPOutput->getFilePointer();

        pFieldsInfo_->getField(iter->first)->
                setLength(vocOff2-vocOff1,dfiOff2-dfiOff1,ptiOff2-ptiOff1);
    }
    if (pDocLengthWriter_)
        pDocLengthWriter_->flush();
}

void CollectionIndexer::reset()
{
    for (map<string, boost::shared_ptr<FieldIndexer> >::iterator iter =
                fieldIndexerMap_.begin(); iter != fieldIndexerMap_.end(); ++iter)
    {
        iter->second->reset();
    }
}

FieldIndexer* CollectionIndexer::getFieldIndexer(const char* field)
{
    string fieldstr(field);
    FieldIndexer* fieldIndexer = fieldIndexerMap_[fieldstr].get();
    return fieldIndexer;
}

<|endoftext|>


<commit_before>/** \brief A MARC-21 filter utility that can remove characters from a set of subfields.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2016 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <memory>
#include <unordered_set>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "DirectoryEntry.h"
#include "FileUtil.h"
#include "Leader.h"
#include "MarcUtil.h"
#include "MarcXmlWriter.h"
#include "MediaTypeUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

void Usage() {
    std::cerr << "usage: " << progname << " marc_input marc_output subfield_spec1:subfield_spec2:...:subfield_specN "
              << " characters_to_delete\n"
              << "       where \"subfieldspec\" must be a MARC tag followed by a single-character\n"
              << "       subfield code and \"characters_to_delete\" is list of characters that will be removed\n"
              << "       from the contents of the specified subfields.\n\n";

    std::exit(EXIT_FAILURE);
}

std::string GetSubfieldCodes(const std::string &tag, const std::vector<std::string> &subfield_specs) {
    std::string subfield_codes;

    for (const auto &subfield_spec : subfield_specs) {
        if (subfield_spec.substr(0, DirectoryEntry::TAG_LENGTH) == tag)
            subfield_codes += subfield_spec[DirectoryEntry::TAG_LENGTH];
    }

    return subfield_codes;
}

void Filter(File * const input, File * const output, const std::vector<std::string> &subfield_specs,
            const std::string &filter_chars)
{
    MarcXmlWriter xml_writer(output);

    unsigned total_count(0), modified_record_count(0), modified_field_count(0);
    while (MarcUtil::Record record = MarcUtil::Record::XmlFactory(input)) {
        ++total_count;
        record.setRecordWillBeWrittenAsXml(true);

        const std::vector<DirectoryEntry> &dir_entries(record.getDirEntries());
        const std::vector<std::string> &fields(record.getFields());

        for (std::vector<DirectoryEntry>::const_iterator dir_entry(dir_entries.cbegin());
             dir_entry != dir_entries.cend(); ++dir_entry)
        {
            const std::string subfield_codes(GetSubfieldCodes(dir_entry->getTag(), subfield_specs));
            if (subfield_codes.empty()) {
                record.write(&xml_writer);
                continue;
            }

            bool modified_at_least_one(false);
            const auto field_index(dir_entry - dir_entries.cbegin());
            Subfields subfields(fields[field_index]);
            for (const auto subfield_code : subfield_codes) {
                const auto begin_end(subfields.getIterators(subfield_code));
                for (auto subfield(begin_end.first); subfield != begin_end.second; ++subfield) {
                    const auto old_length(subfield->second.length());
                    StringUtil::RemoveChars(filter_chars, &(subfield->second));
                    if (subfield->second.length() != old_length) {
                        ++modified_field_count;
                        modified_at_least_one = true;
                    }
                }
            }

            if (modified_at_least_one) {
                record.replaceField(field_index, subfields.toString());
                ++modified_record_count;
            }

            record.write(&xml_writer);
        }
    }

    std::cerr << "Modified " << modified_record_count << " (" << modified_field_count << " fields) of "
              << total_count << " record(s).\n";
}

// Sanity check.
bool ArePlausibleSubfieldSpecs(const std::vector<std::string> &subfield_specs) {
    if (subfield_specs.empty())
        return false;

    for (const auto &subfield_spec : subfield_specs) {
        if (subfield_spec.length() != (DirectoryEntry::TAG_LENGTH + 1))
            return false;
    }

    return true;
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 5)
        Usage();

    std::unique_ptr<File> input(FileUtil::OpenInputFileOrDie(argv[1]));
    std::unique_ptr<File> output(FileUtil::OpenOutputFileOrDie(argv[2]));

    std::vector<std::string> subfield_specs;
    StringUtil::Split(argv[3], ':', &subfield_specs);
    if (not ArePlausibleSubfieldSpecs(subfield_specs))
        Error("bad subfield specifications!");

    const std::string filter_chars(argv[4]);
    if (filter_chars.empty())
        Error("missing characters to be filtered!");

    try {
        Filter(input.get(), output.get(), subfield_specs, filter_chars);
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Fixed some fatally flawed logic which led to a single record being written out multiple times.<commit_after>/** \brief A MARC-21 filter utility that can remove characters from a set of subfields.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2016 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <memory>
#include <unordered_set>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "DirectoryEntry.h"
#include "FileUtil.h"
#include "Leader.h"
#include "MarcUtil.h"
#include "MarcXmlWriter.h"
#include "MediaTypeUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

void Usage() {
    std::cerr << "usage: " << progname << " marc_input marc_output subfield_spec1:subfield_spec2:...:subfield_specN "
              << " characters_to_delete\n"
              << "       where \"subfieldspec\" must be a MARC tag followed by a single-character\n"
              << "       subfield code and \"characters_to_delete\" is list of characters that will be removed\n"
              << "       from the contents of the specified subfields.\n\n";

    std::exit(EXIT_FAILURE);
}

std::string GetSubfieldCodes(const std::string &tag, const std::vector<std::string> &subfield_specs) {
    std::string subfield_codes;

    for (const auto &subfield_spec : subfield_specs) {
        if (subfield_spec.substr(0, DirectoryEntry::TAG_LENGTH) == tag)
            subfield_codes += subfield_spec[DirectoryEntry::TAG_LENGTH];
    }

    return subfield_codes;
}

void Filter(File * const input, File * const output, const std::vector<std::string> &subfield_specs,
            const std::string &filter_chars)
{
    MarcXmlWriter xml_writer(output);

    unsigned total_count(0), modified_record_count(0), modified_field_count(0);
    while (MarcUtil::Record record = MarcUtil::Record::XmlFactory(input)) {
        ++total_count;
        record.setRecordWillBeWrittenAsXml(true);

        const std::vector<DirectoryEntry> &dir_entries(record.getDirEntries());
        const std::vector<std::string> &fields(record.getFields());

        bool modified_at_least_one_field(false);
        for (std::vector<DirectoryEntry>::const_iterator dir_entry(dir_entries.cbegin());
             dir_entry != dir_entries.cend(); ++dir_entry)
        {
            const std::string subfield_codes(GetSubfieldCodes(dir_entry->getTag(), subfield_specs));
            if (subfield_codes.empty())
                continue;

            bool modified_at_least_one_subfield(false);
            const auto field_index(dir_entry - dir_entries.cbegin());
            Subfields subfields(fields[field_index]);
            for (const auto subfield_code : subfield_codes) {
                const auto begin_end(subfields.getIterators(subfield_code));
                for (auto subfield(begin_end.first); subfield != begin_end.second; ++subfield) {
                    const auto old_length(subfield->second.length());
                    StringUtil::RemoveChars(filter_chars, &(subfield->second));
                    if (subfield->second.length() != old_length) {
                        ++modified_field_count;
                        modified_at_least_one_subfield = true;
                    }
                }
            }

            if (modified_at_least_one_subfield) {
                modified_at_least_one_field = true;
                record.replaceField(field_index, subfields.toString());
            }
        }

        if (modified_at_least_one_field)
            ++modified_record_count;
        record.write(&xml_writer);
    }

    std::cerr << "Modified " << modified_record_count << " (" << modified_field_count << " fields) of "
              << total_count << " record(s).\n";
}

// Sanity check.
bool ArePlausibleSubfieldSpecs(const std::vector<std::string> &subfield_specs) {
    if (subfield_specs.empty())
        return false;

    for (const auto &subfield_spec : subfield_specs) {
        if (subfield_spec.length() != (DirectoryEntry::TAG_LENGTH + 1))
            return false;
    }

    return true;
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 5)
        Usage();

    std::unique_ptr<File> input(FileUtil::OpenInputFileOrDie(argv[1]));
    std::unique_ptr<File> output(FileUtil::OpenOutputFileOrDie(argv[2]));

    std::vector<std::string> subfield_specs;
    StringUtil::Split(argv[3], ':', &subfield_specs);
    if (not ArePlausibleSubfieldSpecs(subfield_specs))
        Error("bad subfield specifications!");

    const std::string filter_chars(argv[4]);
    if (filter_chars.empty())
        Error("missing characters to be filtered!");

    try {
        Filter(input.get(), output.get(), subfield_specs, filter_chars);
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2006 Peter Kmmel
// Permission to use, copy, modify, distribute and sell this software for any
//     purpose is hereby granted without fee, provided that the above copyright
//     notice appear in all copies and that both that copyright notice and this
//     permission notice appear in supporting documentation.
// The author makes no representations about the
//     suitability of this software for any purpose. It is provided "as is"
//     without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////

// $Header:

#include <loki/ScopeGuard.h>
#include <vector>
#include <string>
#include <iostream>

struct UserDatabase
{
    void AddFriend(const std::string&, const std::string&)
    {
        throw 55;
    }
};

class User
{
public:
    User(UserDatabase* db) : pDB_(db){}

    std::string GetName();

    void AddFriend(User& newFriend);
    void AddFriendGuarded(User& newFriend);

    size_t countFriends();

private:
    typedef std::vector<User*> UserCont;
    UserCont friends_;
    UserDatabase* pDB_;
};

std::string User::GetName()
{
    return "A name";
}

size_t User::countFriends()
{
    return friends_.size();
}

void User::AddFriend(User& newFriend)
{
    friends_.push_back(&newFriend);
    pDB_->AddFriend(GetName(), newFriend.GetName());
}

void User::AddFriendGuarded(User& newFriend)
{
    friends_.push_back(&newFriend);
    Loki::ScopeGuard guard = Loki::MakeObjGuard(friends_, &UserCont::pop_back);
    pDB_->AddFriend(GetName(), newFriend.GetName());
    guard.Dismiss();
}

int main()
{
    UserDatabase db;

    User u1(&db);
    User u2(&db);

    try{ u1.AddFriend(u2); }
    catch (...){}
    std::cout << "u1 countFriends: " << u1.countFriends() << "\n";

    try{ u2.AddFriendGuarded(u1); }
    catch (...){}
    std::cout << "u2 countFriends: " << u2.countFriends() << "\n";

#if defined(__BORLANDC__) || defined(_MSC_VER)
    system("PAUSE");
#endif

}
<commit_msg>add ScopeGuard ByRef test<commit_after>////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2006 Peter Kmmel
// Permission to use, copy, modify, distribute and sell this software for any
//     purpose is hereby granted without fee, provided that the above copyright
//     notice appear in all copies and that both that copyright notice and this
//     permission notice appear in supporting documentation.
// The author makes no representations about the
//     suitability of this software for any purpose. It is provided "as is"
//     without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////

// $Header:

#include <loki/ScopeGuard.h>
#include <vector>
#include <string>
#include <iostream>

void Decrement(int& x)
{
	--x;
}

struct UserDatabase
{
    void AddFriend(const std::string&, const std::string&)
    {
        throw 55;
    }
};

class User
{
public:
    User(UserDatabase* db) : fCount(0), pDB_(db)
	{}

    std::string GetName();

    void AddFriend(User& newFriend);
    void AddFriendGuarded(User& newFriend);

    size_t countFriends();

    int fCount;

private:
    typedef std::vector<User*> UserCont;
    UserCont friends_;
    UserDatabase* pDB_;
};

std::string User::GetName()
{
    return "A name";
}

size_t User::countFriends()
{
    return friends_.size();
}

void User::AddFriend(User& newFriend)
{
    friends_.push_back(&newFriend);
    fCount++;
    pDB_->AddFriend(GetName(), newFriend.GetName());
}

void User::AddFriendGuarded(User& newFriend)
{
    friends_.push_back(&newFriend);
    Loki::ScopeGuard guard = Loki::MakeObjGuard(friends_, &UserCont::pop_back);

    fCount++;
    Loki::ScopeGuard guardRef = Loki::MakeGuard(Decrement, Loki::ByRef(fCount));
    (void) guardRef;

    pDB_->AddFriend(GetName(), newFriend.GetName());
    guard.Dismiss();
}

int main()
{
    UserDatabase db;

    User u1(&db);
    User u2(&db);

    try{ u1.AddFriend(u2); }
    catch (...){}
    std::cout << "u1 countFriends: " << u1.countFriends() << "\n";
	std::cout << "u1 fCount      : " << u1.fCount << "\n";

    try{ u2.AddFriendGuarded(u1); }
    catch (...){}
    std::cout << "u2 countFriends: " << u2.countFriends() << "\n";
	std::cout << "u2 fCount      : " << u2.fCount << "\n";

#if defined(__BORLANDC__) || defined(_MSC_VER)
    system("PAUSE");
#endif

}
<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
  Copyright (c) 2008, Ken Zhao <kentoo.zhao@gmail.com>

  This program is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2, or (at your option) any
  later version.

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  -------------------------------------------------------------------------*/

ostream &operator<<(ostream &s, Cloud p){
    s << "Cloud('" <<
        domain << "', '" <<
        port << "', '" <<
        path << "', '" <<
        registerProcedure << "', '" <<
        protocol << "')";
    return s;
};

ostream &operator<<(ostream &s, Image p){
    s << "Image('" << url << "', '" << title << "', '" << link << "', '" << width << "', '" << height << "')";
    return s;
};

ostream &operator<<(ostream &s, TextInput p){
    s <<  "TextInput('" <<
        title << "', '" <<
        description << "', '" <<
        name << "', '" <<
        link << "')";
    return s;
};

ostream &operator<<(ostream &s, Item p)
{
    s << "Item('" <<
        title << "', '" <<
        link << "', '" <<
        description << "', '" <<
        author << "', '" <<
        category << "', '" <<
        comments << "', '" <<
        enclosure << "', '" <<
        guid << "', '" <<
        pubdate << "', '" <<
        source << "', '" <<
        image << "')";
    return s;
};

Channel::Channel() {
    itemList = new List<Item>();
};

void Channel::AddItem(Item item) {
        itemList.Add(item);
};

ostream &operator<<(ostream &s, Channel p)
{
    s << "Channel: '" << title << "'\n" <<
        "\tlink: '" << link << "'\n" <<
        "\tdescription: '" << description << "'\n" <<
        "\tlanguage: '" << language << "'\n" <<
        "\tcopyright: '" << copyright << "'\n" <<
        "\tmanagingEditor: '" << managingEditor << "'\n" <<
        "\twebMaster: '" << webMaster << "'\n" <<
        "\tpubDate: '" << pubDate << "'\n" <<
        "\tlastBuildDate: '" << lastBuildDate << "'\n" <<
        "\tcategory: '" << category << "'\n" <<
        "\tgenerator: '" << generator << "'\n" <<
        "\tdocs: '" << docs << "'\n" <<
        "\tcloud: '" << cloud << "'\n" <<
        "\tttl: '" << ttl << "'\n" <<
        "\timage: '" << image << "'\n" <<
        "\trating: '" << rating << "'\n" <<
        "\ttextInput: '" << textInput << "'\n" <<
        "\tskipHours: '" << skipHours << "'\n" <<
        "\tskipDays: '" << skipDays << "'\n";
    foreach (Item i in itemList) {
        s << s << "\t" << i << "\n";
    }
    return s;
};

Rss::Rss() {
    channelList = new List<Channel>();
}

void Rss::AddChannel(Channel channel) {
        channelList.Add(channel);
}

ostream &operator<<(ostream &s, Rss p)
{
    string s = "";
    foreach (Channel c in channelList) {
        s = s << c << "\n";
    }
    return s;
}
<commit_msg>rename the class name to avoid name conflict<commit_after>/*-------------------------------------------------------------------------
  Copyright (c) 2008, Ken Zhao <kentoo.zhao@gmail.com>

  This program is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2, or (at your option) any
  later version.

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  -------------------------------------------------------------------------*/
#include <ostream>
#include <iostream>
#include "RSSData.hxx"

ostream &operator<<(ostream &s, CloudClass p){
    s << "Cloud('" <<
        p.domain << "', '" <<
        p.port << "', '" <<
        p.path << "', '" <<
        p.registerProcedure << "', '" <<
        p.protocol << "')";
    return s;
};

ostream &operator<<(ostream &s, ImageClass p){
    s << "Image('" << p.url << "', '" << p.title << "', '" << p.link << "', '" << p.width << "', '" << p.height << "')";
    return s;
};

ostream &operator<<(ostream &s, TextInputClass p){
    s <<  "TextInput('" <<
        p.title << "', '" <<
        p.description << "', '" <<
        p.name << "', '" <<
        p.link << "')";
    return s;
};

ostream &operator<<(ostream &s, ItemClass p)
{
    s << "Item('" <<
        p.title << "', '" <<
        p.link << "', '" <<
        p.description << "', '" <<
        p.author << "', '" <<
        p.category << "', '" <<
        p.comments << "', '" <<
        p.enclosure << "', '" <<
        p.guid << "', '" <<
        p.pubdate << "', '" <<
        p.source << "', '" <<
        p.image << "')";
    return s;
};

ChannelClass::ChannelClass() {
    itemList = new list<ItemClass*>();
};

void ChannelClass::AddItem(ItemClass *item) {
        itemList->push_back(item);
};

ostream &operator<<(ostream &s, ChannelClass p)
{
    s << "Channel: '" << p.title << "'\n" <<
        "\tlink: '" << p.link << "'\n" <<
        "\tdescription: '" << p.description << "'\n" <<
        "\tlanguage: '" << p.language << "'\n" <<
        "\tcopyright: '" << p.copyright << "'\n" <<
        "\tmanagingEditor: '" << p.managingEditor << "'\n" <<
        "\twebMaster: '" << p.webMaster << "'\n" <<
        "\tpubDate: '" << p.pubDate << "'\n" <<
        "\tlastBuildDate: '" << p.lastBuildDate << "'\n" <<
        "\tcategory: '" << p.category << "'\n" <<
        "\tgenerator: '" << p.generator << "'\n" <<
        "\tdocs: '" << p.docs << "'\n" <<
        "\tcloud: '" << p.cloud << "'\n" <<
        "\tttl: '" << p.ttl << "'\n" <<
        "\timage: '" << p.image << "'\n" <<
        "\trating: '" << p.rating << "'\n" <<
        "\ttextInput: '" << p.textInput << "'\n" <<
        "\tskipHours: '" << p.skipHours << "'\n" <<
        "\tskipDays: '" << p.skipDays << "'\n";
#if 0
    foreach (Item i in itemList) {
        s << s << "\t" << i << "\n";
    }
#endif
    return s;
};

RssClass::RssClass() {
    channelList = new list<ChannelClass*>();
};

void RssClass::AddChannel(ChannelClass* channel) {
        channelList->push_back(channel);
};

ostream &operator<<(ostream &s, RssClass p)
{
#if 0
    string s = "";
    foreach (Channel c in channelList) {
        s = s << c << "\n";
    }
#endif
    s<<"???";
    return s;
}
<|endoftext|>


<commit_before>#include "calculator/cell/total_aggregated_fission_source.h"

#include "system/moments/spherical_harmonic_i.h"
#include "domain/definition_i.h"
#include "calculator/cell/integrated_fission_source_i.h"

namespace bart {

namespace calculator {

namespace cell {

template<int dim>
double TotalAggregatedFissionSource<dim>::AggreatedFissionSource(
    system::moments::SphericalHarmonicI *system_moments_ptr) const {

  auto cells = domain_ptr_->Cells();
  double fission_source = 0;

  for (auto& cell : cells) {
    fission_source += cell_fission_source_ptr_->CellValue(cell, system_moments_ptr);
  }

  return fission_source;
}

template class TotalAggregatedFissionSource<1>;
template class TotalAggregatedFissionSource<2>;
template class TotalAggregatedFissionSource<3>;

} // namespace cell

} // namespace calculator

} // namespace bart<commit_msg>fixed implementation for MPI<commit_after>#include "calculator/cell/total_aggregated_fission_source.h"

#include <deal.II/base/utilities.h>

#include "system/moments/spherical_harmonic_i.h"
#include "domain/definition_i.h"
#include "calculator/cell/integrated_fission_source_i.h"

namespace bart {

namespace calculator {

namespace cell {

template<int dim>
double TotalAggregatedFissionSource<dim>::AggreatedFissionSource(
    system::moments::SphericalHarmonicI *system_moments_ptr) const {

  auto cells = domain_ptr_->Cells();
  double fission_source = 0;

  for (auto& cell : cells) {
    fission_source += cell_fission_source_ptr_->CellValue(cell, system_moments_ptr);
  }

  return dealii::Utilities::MPI::sum(fission_source, MPI_COMM_WORLD);
}

template class TotalAggregatedFissionSource<1>;
template class TotalAggregatedFissionSource<2>;
template class TotalAggregatedFissionSource<3>;

} // namespace cell

} // namespace calculator

} // namespace bart<|endoftext|>


<commit_before>/* application_layer.cc
   Mathieu Stefani, 11 June 2014
   Copyright (c) 2042 Datacratic Inc.  All rights reserved.

   application layers implementation.
*/

#include "application_layer.h"
#include <type_traits>

using namespace std;

namespace RTBKIT {

template<typename Result>
std::shared_ptr<HttpClientSimpleCallbacks>
makeCallback(std::string functionName,
             std::function<void (std::exception_ptr, Result &&)> onDone)
{
    //static_assert(std::is_default_constructible<Result>::value,
    //              "Result is not default constructible");

    return std::make_shared<HttpClientSimpleCallbacks>(
        [=](const HttpRequest &,
            HttpClientError error, int statusCode,
            std::string &&, std::string &&body) {
        JML_TRACE_EXCEPTIONS(false);
        if (!onDone) {
            return;
        }

        if (error != HttpClientError::None) {
            std::ostringstream oss;
            oss << error;
            onDone(std::make_exception_ptr(ML::Exception("HTTP Request failed in '%s': %s",
                                                         functionName.c_str(), oss.str().c_str())),
                   Result { });
        }
        else {
            decodeRestResponseJson<Result>(functionName, nullptr, statusCode, body, onDone);
        }
    });
}

void
ApplicationLayer::
topupTransfer(const AccountKey &account,
              AccountType accountType,
              CurrencyPool amount,
              const BudgetController::OnBudgetResult &onResult)
{
    topupTransfer(account.toString(), accountType, amount, onResult);
}

void
HttpLayer::
init(std::string bankerUri, int activeConnections /* = 4 */)
{
    if (bankerUri.empty())
        throw ML::Exception("bankerUri can not be empty");

    if (bankerUri.compare(0, 7, "http://"))
        bankerUri = "http://" + bankerUri;

    // Since we send one HttpRequest per account when syncing, this is a good idea
    // to keep a fairly large queue size in order to avoid deadlocks
    httpClient.reset(new HttpClient(bankerUri, activeConnections));
    addSource("HttpLayer::httpClient", httpClient);
}

void
HttpLayer::
addAccount(const AccountKey &account,
           const BudgetController::OnBudgetResult &onResult)
{
    httpClient->post("/v1/accounts", budgetResultCallback(onResult),
                     { },
                     { { "accountName", account.toString() },
                         { "accountType", "budget" }});
}

void
HttpLayer::
topupTransfer(const std::string &accountStr,
              AccountType accountType,
              CurrencyPool amount,
              const BudgetController::OnBudgetResult &onResult)
{
    httpClient->put("/v1/accounts/" + accountStr + "/balance",
                    budgetResultCallback(onResult),
                    amount.toJson(),
                    { { "accountType", AccountTypeToString(accountType) } });
}

void
HttpLayer::
setBudget(const std::string &topLevelAccount,
          CurrencyPool amount,
          const BudgetController::OnBudgetResult &onResult)
{
    httpClient->put("/v1/accounts/" + topLevelAccount + "/budget",
                    budgetResultCallback(onResult),
                    amount.toJson());
}

void
HttpLayer::
getAccountSummary(
    const AccountKey &account,
    int depth,
    std::function<void (std::exception_ptr, AccountSummary &&)>
    onResult)
{
    httpClient->get("/v1/accounts/" + account.toString() + "/summary",
                    makeCallback<AccountSummary>(
                        "HttpLayer::getAccountSummary",
                        onResult),
                    { { "depth", to_string(depth) } });
}

void
HttpLayer::
getAccount(const AccountKey &account,
           std::function<void (std::exception_ptr, Account &&)> onResult)
{
    httpClient->get("/v1/accounts/" + account.toString(),
                    makeCallback<Account>(
                        "HttpLayer::getAccount",
                        onResult));
}

void
HttpLayer::
addSpendAccount(const std::string &shadowStr,
                std::function<void (std::exception_ptr, Account &&)> onDone)
{
    httpClient->post("/v1/accounts",
                     makeCallback<Account>("HttpLayer::addSpendAccount", onDone),
                     { },
                     {
                         { "accountName", shadowStr },
                         { "accountType", "spend" }
                     });
}

void
HttpLayer::
syncAccount(const ShadowAccount &account, const std::string &shadowStr,
            std::function<void (std::exception_ptr, Account &&)> onDone)
{

    httpClient->put("/v1/accounts/" + shadowStr + "/shadow",
                    makeCallback<Account>("HttpLayer::syncAcount", onDone),
                    account.toJson());
}

void
HttpLayer::
request(std::string method, const std::string &resource,
        const RestParams &params, const std::string &content, OnRequestResult onResult)
{
    std::transform(begin(method), end(method), begin(method), [](char c) { return ::tolower(c); });

    auto onDone = std::make_shared<HttpClientSimpleCallbacks>(
        [=](const HttpRequest &,
            HttpClientError error, int statusCode,
            std::string &&, std::string &&body) {
        if (error != HttpClientError::None) {
            std::ostringstream oss;
            oss << error;
            onResult(std::make_exception_ptr(
                         ML::Exception("HTTP Request failed with return code %s", oss.str().c_str())),
                     statusCode, "");
        }
        else {
            onResult(nullptr, statusCode, body);
        }
    });

    if (method == "post") {
        httpClient->post(resource, onDone, content, params);
    }
    else if (method == "put") {
        httpClient->put(resource, onDone, content, params);
    }
    else if (method == "get") {
        httpClient->get(resource, onDone, params);
    }
    else {
        throw ML::Exception("Unknown method '%s'", method.c_str());
    }
}

std::shared_ptr<HttpClientSimpleCallbacks>
HttpLayer::
budgetResultCallback(const BudgetController::OnBudgetResult &onResult)
{
    return std::make_shared<HttpClientSimpleCallbacks>(
        [=](const HttpRequest &,
            HttpClientError error, int statusCode,
            std::string &&, std::string &&body) {
        if (error != HttpClientError::None) {
            std::ostringstream oss;
            oss << error;
            onResult(std::make_exception_ptr(
                         ML::Exception("HTTP Request failed with return code %s", oss.str().c_str())));
        }
        else {
            onResult(nullptr);
        }
    });
}

void
ZmqLayer::
init(const std::shared_ptr<ServiceProxies> &services,
     const std::string &bankerServiceName)
{
    if (bankerServiceName.empty())
        throw ML::Exception("bankerServiceName can not be empty");

    proxy.reset(new RestProxy(services->zmqContext));
    proxy->initServiceClass(services->config, bankerServiceName, "zeromq", false /* local */);
    addSource("ZmqLayer::proxy", proxy);
}

void
ZmqLayer::
addAccount(const AccountKey &account,
           const BudgetController::OnBudgetResult &onResult)
{
    proxy->push(budgetResultCallback(onResult),
                "POST", "/v1/accounts",
                { {"accountName", account.toString()},
                    { "accountType", "budget" } });
}

void
ZmqLayer::
topupTransfer(const std::string &accountStr,
              AccountType accountType,
              CurrencyPool amount,
              const BudgetController::OnBudgetResult &onResult)
{
    proxy->push(budgetResultCallback(onResult),
                "PUT", "/v1/accounts/" + accountStr + "/balance",
                { { "accountType", AccountTypeToString(accountType) } },
                amount.toJson().toString());
}

void
ZmqLayer::
setBudget(const std::string &topLevelAccount,
          CurrencyPool amount,
          const BudgetController::OnBudgetResult &onResult)
{
    proxy->push(budgetResultCallback(onResult),
                "PUT", "/v1/accounts/" + topLevelAccount + "/budget",
                { /* {"amount", amount.toString()}*/ },
                amount.toJson().toString());
}

void
ZmqLayer::
getAccountSummary(
    const AccountKey &account,
    int depth,
    std::function<void (std::exception_ptr, AccountSummary &&)>
    onResult)
{
    proxy->push(makeRestResponseJsonDecoder<AccountSummary>("ZmqLayer::getAccountSummary", onResult),
                "GET", "/v1/accounts/" + account.toString() + "/summary",
                { {"depth", to_string(depth)} },
                "");
}

void
ZmqLayer::
getAccount(const AccountKey &account,
           std::function<void (std::exception_ptr, Account &&)> onResult)
{
    proxy->push(makeRestResponseJsonDecoder<Account>("ZmqLayer::getAccount", onResult),
                "GET", "/v1/accounts/" + account.toString());
}

void
ZmqLayer::
addSpendAccount(const std::string &shadowStr,
                std::function<void (std::exception_ptr, Account &&)> onDone)
{
    proxy->push(makeRestResponseJsonDecoder<Account>("ZmqLayer::addSpendAccount", onDone),
                "POST",
                "/v1/accounts",
                {
                    { "accountName", shadowStr },
                    { "accountType", "spend" }
                },
                "");
}

void
ZmqLayer::
syncAccount(const ShadowAccount &account, const std::string &shadowStr,
            std::function<void (std::exception_ptr, Account &&)> onDone)
{
    proxy->push(makeRestResponseJsonDecoder<Account>("ZmqLayer::syncAccount", onDone),
                "PUT",
                "/v1/accounts/" + shadowStr + "/shadow",
                {},
                account.toJson().toString());
}

void
ZmqLayer::
request(std::string method, const std::string &resource,
        const RestParams &params, const std::string &content, OnRequestResult onResult)
{
    proxy->push(onResult, method, resource, params, content);
}

RestProxy::OnDone
ZmqLayer::
budgetResultCallback(const BudgetController::OnBudgetResult &onResult)
{
    return [=] (std::exception_ptr ptr, int resultCode, string body) {
        //cerr << "got budget result callback with resultCode "
        //     << resultCode << " body " << body << endl;
        onResult(ptr);
    };
}

} // namespace RTBKIT
<commit_msg>Removed an obsolete comment in the HttpLayer<commit_after>/* application_layer.cc
   Mathieu Stefani, 11 June 2014
   Copyright (c) 2042 Datacratic Inc.  All rights reserved.

   application layers implementation.
*/

#include "application_layer.h"
#include <type_traits>

using namespace std;

namespace RTBKIT {

template<typename Result>
std::shared_ptr<HttpClientSimpleCallbacks>
makeCallback(std::string functionName,
             std::function<void (std::exception_ptr, Result &&)> onDone)
{
    //static_assert(std::is_default_constructible<Result>::value,
    //              "Result is not default constructible");

    return std::make_shared<HttpClientSimpleCallbacks>(
        [=](const HttpRequest &,
            HttpClientError error, int statusCode,
            std::string &&, std::string &&body) {
        JML_TRACE_EXCEPTIONS(false);
        if (!onDone) {
            return;
        }

        if (error != HttpClientError::None) {
            std::ostringstream oss;
            oss << error;
            onDone(std::make_exception_ptr(ML::Exception("HTTP Request failed in '%s': %s",
                                                         functionName.c_str(), oss.str().c_str())),
                   Result { });
        }
        else {
            decodeRestResponseJson<Result>(functionName, nullptr, statusCode, body, onDone);
        }
    });
}

void
ApplicationLayer::
topupTransfer(const AccountKey &account,
              AccountType accountType,
              CurrencyPool amount,
              const BudgetController::OnBudgetResult &onResult)
{
    topupTransfer(account.toString(), accountType, amount, onResult);
}

void
HttpLayer::
init(std::string bankerUri, int activeConnections /* = 4 */)
{
    if (bankerUri.empty())
        throw ML::Exception("bankerUri can not be empty");

    if (bankerUri.compare(0, 7, "http://"))
        bankerUri = "http://" + bankerUri;

    httpClient.reset(new HttpClient(bankerUri, activeConnections));
    addSource("HttpLayer::httpClient", httpClient);
}

void
HttpLayer::
addAccount(const AccountKey &account,
           const BudgetController::OnBudgetResult &onResult)
{
    httpClient->post("/v1/accounts", budgetResultCallback(onResult),
                     { },
                     { { "accountName", account.toString() },
                         { "accountType", "budget" }});
}

void
HttpLayer::
topupTransfer(const std::string &accountStr,
              AccountType accountType,
              CurrencyPool amount,
              const BudgetController::OnBudgetResult &onResult)
{
    httpClient->put("/v1/accounts/" + accountStr + "/balance",
                    budgetResultCallback(onResult),
                    amount.toJson(),
                    { { "accountType", AccountTypeToString(accountType) } });
}

void
HttpLayer::
setBudget(const std::string &topLevelAccount,
          CurrencyPool amount,
          const BudgetController::OnBudgetResult &onResult)
{
    httpClient->put("/v1/accounts/" + topLevelAccount + "/budget",
                    budgetResultCallback(onResult),
                    amount.toJson());
}

void
HttpLayer::
getAccountSummary(
    const AccountKey &account,
    int depth,
    std::function<void (std::exception_ptr, AccountSummary &&)>
    onResult)
{
    httpClient->get("/v1/accounts/" + account.toString() + "/summary",
                    makeCallback<AccountSummary>(
                        "HttpLayer::getAccountSummary",
                        onResult),
                    { { "depth", to_string(depth) } });
}

void
HttpLayer::
getAccount(const AccountKey &account,
           std::function<void (std::exception_ptr, Account &&)> onResult)
{
    httpClient->get("/v1/accounts/" + account.toString(),
                    makeCallback<Account>(
                        "HttpLayer::getAccount",
                        onResult));
}

void
HttpLayer::
addSpendAccount(const std::string &shadowStr,
                std::function<void (std::exception_ptr, Account &&)> onDone)
{
    httpClient->post("/v1/accounts",
                     makeCallback<Account>("HttpLayer::addSpendAccount", onDone),
                     { },
                     {
                         { "accountName", shadowStr },
                         { "accountType", "spend" }
                     });
}

void
HttpLayer::
syncAccount(const ShadowAccount &account, const std::string &shadowStr,
            std::function<void (std::exception_ptr, Account &&)> onDone)
{

    httpClient->put("/v1/accounts/" + shadowStr + "/shadow",
                    makeCallback<Account>("HttpLayer::syncAcount", onDone),
                    account.toJson());
}

void
HttpLayer::
request(std::string method, const std::string &resource,
        const RestParams &params, const std::string &content, OnRequestResult onResult)
{
    std::transform(begin(method), end(method), begin(method), [](char c) { return ::tolower(c); });

    auto onDone = std::make_shared<HttpClientSimpleCallbacks>(
        [=](const HttpRequest &,
            HttpClientError error, int statusCode,
            std::string &&, std::string &&body) {
        if (error != HttpClientError::None) {
            std::ostringstream oss;
            oss << error;
            onResult(std::make_exception_ptr(
                         ML::Exception("HTTP Request failed with return code %s", oss.str().c_str())),
                     statusCode, "");
        }
        else {
            onResult(nullptr, statusCode, body);
        }
    });

    if (method == "post") {
        httpClient->post(resource, onDone, content, params);
    }
    else if (method == "put") {
        httpClient->put(resource, onDone, content, params);
    }
    else if (method == "get") {
        httpClient->get(resource, onDone, params);
    }
    else {
        throw ML::Exception("Unknown method '%s'", method.c_str());
    }
}

std::shared_ptr<HttpClientSimpleCallbacks>
HttpLayer::
budgetResultCallback(const BudgetController::OnBudgetResult &onResult)
{
    return std::make_shared<HttpClientSimpleCallbacks>(
        [=](const HttpRequest &,
            HttpClientError error, int statusCode,
            std::string &&, std::string &&body) {
        if (error != HttpClientError::None) {
            std::ostringstream oss;
            oss << error;
            onResult(std::make_exception_ptr(
                         ML::Exception("HTTP Request failed with return code %s", oss.str().c_str())));
        }
        else {
            onResult(nullptr);
        }
    });
}

void
ZmqLayer::
init(const std::shared_ptr<ServiceProxies> &services,
     const std::string &bankerServiceName)
{
    if (bankerServiceName.empty())
        throw ML::Exception("bankerServiceName can not be empty");

    proxy.reset(new RestProxy(services->zmqContext));
    proxy->initServiceClass(services->config, bankerServiceName, "zeromq", false /* local */);
    addSource("ZmqLayer::proxy", proxy);
}

void
ZmqLayer::
addAccount(const AccountKey &account,
           const BudgetController::OnBudgetResult &onResult)
{
    proxy->push(budgetResultCallback(onResult),
                "POST", "/v1/accounts",
                { {"accountName", account.toString()},
                    { "accountType", "budget" } });
}

void
ZmqLayer::
topupTransfer(const std::string &accountStr,
              AccountType accountType,
              CurrencyPool amount,
              const BudgetController::OnBudgetResult &onResult)
{
    proxy->push(budgetResultCallback(onResult),
                "PUT", "/v1/accounts/" + accountStr + "/balance",
                { { "accountType", AccountTypeToString(accountType) } },
                amount.toJson().toString());
}

void
ZmqLayer::
setBudget(const std::string &topLevelAccount,
          CurrencyPool amount,
          const BudgetController::OnBudgetResult &onResult)
{
    proxy->push(budgetResultCallback(onResult),
                "PUT", "/v1/accounts/" + topLevelAccount + "/budget",
                { /* {"amount", amount.toString()}*/ },
                amount.toJson().toString());
}

void
ZmqLayer::
getAccountSummary(
    const AccountKey &account,
    int depth,
    std::function<void (std::exception_ptr, AccountSummary &&)>
    onResult)
{
    proxy->push(makeRestResponseJsonDecoder<AccountSummary>("ZmqLayer::getAccountSummary", onResult),
                "GET", "/v1/accounts/" + account.toString() + "/summary",
                { {"depth", to_string(depth)} },
                "");
}

void
ZmqLayer::
getAccount(const AccountKey &account,
           std::function<void (std::exception_ptr, Account &&)> onResult)
{
    proxy->push(makeRestResponseJsonDecoder<Account>("ZmqLayer::getAccount", onResult),
                "GET", "/v1/accounts/" + account.toString());
}

void
ZmqLayer::
addSpendAccount(const std::string &shadowStr,
                std::function<void (std::exception_ptr, Account &&)> onDone)
{
    proxy->push(makeRestResponseJsonDecoder<Account>("ZmqLayer::addSpendAccount", onDone),
                "POST",
                "/v1/accounts",
                {
                    { "accountName", shadowStr },
                    { "accountType", "spend" }
                },
                "");
}

void
ZmqLayer::
syncAccount(const ShadowAccount &account, const std::string &shadowStr,
            std::function<void (std::exception_ptr, Account &&)> onDone)
{
    proxy->push(makeRestResponseJsonDecoder<Account>("ZmqLayer::syncAccount", onDone),
                "PUT",
                "/v1/accounts/" + shadowStr + "/shadow",
                {},
                account.toJson().toString());
}

void
ZmqLayer::
request(std::string method, const std::string &resource,
        const RestParams &params, const std::string &content, OnRequestResult onResult)
{
    proxy->push(onResult, method, resource, params, content);
}

RestProxy::OnDone
ZmqLayer::
budgetResultCallback(const BudgetController::OnBudgetResult &onResult)
{
    return [=] (std::exception_ptr ptr, int resultCode, string body) {
        //cerr << "got budget result callback with resultCode "
        //     << resultCode << " body " << body << endl;
        onResult(ptr);
    };
}

} // namespace RTBKIT
<|endoftext|>