Commit fc7d5387 authored by David Thompson's avatar David Thompson
Browse files

WIP: Broken progress on Read.

parent 4ad6c3d8
......@@ -31,10 +31,11 @@ Component::~Component() = default;
void Component::initialize(const nlohmann::json& data, json::Helper& helper)
{
(void)helper;
std::cout << "init comp " << this << " with " << data.dump(2) << "\n";
auto it = data.find("name");
if (it != data.end())
{
m_name = it->get<std::string>();
this->setName(it->get<std::string>());
}
}
......
......@@ -26,8 +26,8 @@ class SMTKMARKUP_EXPORT DomainMap
public:
DomainMap() = default;
~DomainMap() = default;
DomainMap(const DomainMap&) = delete;
void operator = (const DomainMap&) = delete;
DomainMap(const DomainMap&) = default;
DomainMap& operator = (const DomainMap&) = default;
/// Return true if the \a space exists in this map.
bool contains(const smtk::string::Token& space) const;
......
......@@ -14,6 +14,8 @@
#include "smtk/markup/Exports.h"
#include "nlohmann/json.hpp"
namespace smtk
{
/// Markup resource
......@@ -49,10 +51,10 @@ public:
virtual ~Resource() = default;
// Wrap this method (instead of create()) to avoid name conflict in MSVC.
template <typename componentT>
smtk::shared_ptr<componentT> createNode()
template <typename componentT, typename... Args>
smtk::shared_ptr<componentT> createNode(Args&&... args)
{
return GraphResource::create<componentT>();
return GraphResource::create<componentT>(std::forward<Args>(args)...);
}
/// Return a boolean functor that classifies components according to \a query.
......@@ -79,6 +81,7 @@ public:
protected:
friend class Component;
friend void from_json(const nlohmann::json& j, Ptr& resource);
Resource(const smtk::common::UUID&, smtk::resource::Manager::Ptr manager = nullptr);
Resource(smtk::resource::Manager::Ptr manager = nullptr);
......
......@@ -17,45 +17,7 @@
#include "smtk/string/json/jsonManager.h"
#include "smtk/string/json/jsonToken.h"
#if 0
namespace nlohmann
{
template<typename Src, typename Dst, typename ArcType>
struct adl_serializer<smtk::graph::Arcs<Src, Dst, ArcType>>
{
static smtk::graph::Arcs<Src, Dst, ArcType> from_json(const json& j)
{
auto resource = smtk::markup::json::Helper::instance().resource();
auto fromNode = std::dynamic_pointer_cast<Src>(
resource->find(j.at("from").get<smtk::common::UUID>()));
smtk::graph::Arcs<Src, Dst, ArcType> result(fromNode);
for (const auto& jTo : j.at("to"))
{
auto toNode = std::dynamic_pointer_cast<Dst>(resource->find(jTo.get<smtk::common::UUID>()));
if (toNode)
{
result.to().insert(toNode);
}
}
return result;
}
static void to_json(json& j, const smtk::graph::Arcs<Src, Dst, ArcType>& arcs)
{
j["from"] = arcs.from().id();
std::vector<smtk::common::UUID> toIds;
toIds.reserve(arcs.to().size());
for (const auto& to : arcs.to())
{
toIds.push_back(to);
}
j["to"] = toIds;
}
};
} // namespace nlohmann
#endif
using ArcMap = smtk::graph::ArcMap;
namespace smtk
{
......@@ -80,6 +42,130 @@ void to_json(nlohmann::json& j, const smtk::graph::Arcs<Src, Dst, ArcType>& arcs
}
}
template<typename Src, typename Dst, typename ArcType>
void from_json(const nlohmann::json& j, smtk::graph::Arc<Src, Dst, ArcType>& arc)
{
auto resource = json::Helper::instance().resource();
auto from = std::dynamic_pointer_cast<Src>(resource->find(j.at("from").get<smtk::common::UUID>()));
auto to = std::dynamic_pointer_cast<Dst>(resource->find(j.at("to").get<smtk::common::UUID>()));
arc = ArcType(from, to);
}
template<typename Src, typename Dst, typename ArcType>
void from_json(const nlohmann::json& j, smtk::graph::Arcs<Src, Dst, ArcType>& arcs)
{
auto resource = json::Helper::instance().resource();
auto from = std::dynamic_pointer_cast<Src>(resource->find(j.at("from").get<smtk::common::UUID>()));
arcs = ArcType(from);
for (const auto& jto : j.at("to"))
{
auto to = std::dynamic_pointer_cast<Dst>(resource->find(jto.get<smtk::common::UUID>()));
arcs.insert(to);
}
}
template<typename Src, typename Dst, typename ArcType>
void from_json(const nlohmann::json& j, smtk::graph::OrderedArcs<Src, Dst, ArcType>& arcs)
{
auto resource = json::Helper::instance().resource();
auto from = std::dynamic_pointer_cast<Src>(resource->find(j.at("from").get<smtk::common::UUID>()));
arcs = ArcType(from);
const auto& jAllTo = j.at("to");
arcs.to().reserve(jAllTo.size());
for (const auto& jto : jAllTo)
{
auto to = std::dynamic_pointer_cast<Dst>(resource->find(jto.get<smtk::common::UUID>()));
arcs.insert(to);
}
}
template<std::size_t I, typename Tuple, typename ResourceType>
inline typename std::enable_if<I != std::tuple_size<Tuple>::value, void>::type deserializeArcsOfType(
const nlohmann::json& jj,
const std::shared_ptr<ResourceType>& resource,
ArcMap& arcMap)
{
using ArcType = typename std::tuple_element<I, Tuple>::type;
auto arcType = smtk::common::typeName<ArcType>();
auto it = jj.find(arcType);
if (it != jj.end())
{
/*
if (!resource->arcs().template contains<ArcType>(arcType))
{
// FIXME: URHERE Cannot construct ArcType without a from node? But I want to insert a TypeMapEntry<UUID, ArcType>?
resource->arcs().template insert<ArcType>(arcType, ArcType{});
}
auto& arcEntry(resource->arcs().template get<ArcType>());
*/
std::vector<smtk::WeakReferenceWrapper<typename ArcType::ToType>> toNodes;
for (const auto jarc : *it)
{
toNodes.clear();
smtk::common::UUID fromId = jarc.at("from").template get<smtk::common::UUID>();
auto fromNode = std::dynamic_pointer_cast<typename ArcType::FromType>(resource->find(fromId));
if (fromNode)
{
toNodes.reserve(jarc.size());
for (const auto jto : jarc.at("to"))
{
smtk::common::UUID toId = jto;
auto toNode = std::dynamic_pointer_cast<typename ArcType::ToType>(resource->find(toId));
if (toNode)
{
std::weak_ptr<typename ArcType::ToType> weakRef(toNode);
toNodes.push_back(weakRef);
}
}
fromNode->template set<ArcType>(toNodes.begin(), toNodes.end());
// std::cout << "Extract arc of type " << arcType << " from " << fromId << "\n";
// ArcType value(fromId);
// from_json(jarc, value);
// arcEntry.emplace(value.from(), value);
}
else
{
smtkErrorMacro(smtk::io::Logger::instance(),
"Could not find node " << fromId << ". Skipping.");
}
}
}
// Now process the next entry in the tuple:
deserializeArcsOfType<I + 1, Tuple>(jj, resource, arcMap);
}
template<std::size_t I, typename Tuple, typename ResourceType>
inline typename std::enable_if<I == std::tuple_size<Tuple>::value, void>::type deserializeArcsOfType(
const nlohmann::json& jj,
const std::shared_ptr<ResourceType>& resource,
ArcMap& arcMap)
{
(void)jj;
(void)resource;
(void)arcMap;
}
template<typename ResourceType>
void deserializeArcs(
const nlohmann::json& jj,
const std::shared_ptr<ResourceType>& resource,
ArcMap& arcMap)
{
deserializeArcsOfType<0, typename ResourceType::TypeTraits::ArcTypes>(jj, resource, arcMap);
}
void from_json(const nlohmann::json& jj, ArcMap& arcMap)
{
// Erase all pre-existing arcs
arcMap.data().clear();
// Keep track of visited arc types. At the end, we'll signal an error if there
// were arc types present in the JSON that this resource's traits do not handle.
std::set<std::string> visitedArcTypes;
auto resource = json::Helper::instance().resource();
deserializeArcs(jj, resource, arcMap);
}
template<std::size_t I, typename Tuple, typename ResourceType>
inline typename std::enable_if<I != std::tuple_size<Tuple>::value, void>::type serializeArcsOfType(
const std::shared_ptr<ResourceType>& resource, nlohmann::json& arcs)
......@@ -164,20 +250,35 @@ void to_json(nlohmann::json& j, const smtk::markup::Resource::Ptr& resource)
void from_json(const nlohmann::json& j, smtk::markup::Resource::Ptr& resource)
{
if (!resource)
{
resource = smtk::markup::Resource::create();
}
auto tmp = std::static_pointer_cast<smtk::resource::Resource>(resource);
smtk::resource::from_json(j, tmp);
// resource->m_domains = j.at("domains")
// resource->arcs() = j.at("arcs");
// Insert nodes, then initialize them (so they can freely assume
// other nodes are present when configuring themselves).
resource->m_domains = j.at("domains");
// I. Insert nodes. Initialize them later (so they can freely
// assume other nodes are present when configuring themselves).
for (const auto& jnode : j.at("nodes"))
{
auto node = resource->nodeFactory().makeFromName(
jnode.at("type").get<std::string>(),
resource,
jnode.at("id").get<smtk::common::UUID>());
resource->add(node);
auto nodeType = jnode.at("type").get<std::string>();
auto nodeId = jnode.at("id").get<smtk::common::UUID>();
// std::cout << " Create " << nodeType << " " << (smtk::markup::Resource::nodeFactory().contains(nodeType) ? "Y" : "N") << "\n";
auto node = smtk::markup::Resource::nodeFactory().makeFromName(nodeType, resource, nodeId);
std::cout << "Create " << nodeType << " id " << nodeId << " " << node << "\n";
if (node)
{
resource->add(node);
}
}
// II. Insert arcs. Arcs should be added before initializing nodes.
smtk::markup::from_json(j.at("arcs"), resource->arcs());
// III. Initialize nodes.
// Initializers can assume that other nodes in the resource exist
// and that arcs are in a valid state (making it possible to
// find pointers to relevant nodes by following arcs).
auto& helper = json::Helper::instance();
for (const auto& jnode : j.at("nodes"))
{
......
......@@ -74,15 +74,13 @@ Read::Result Read::operateInternal()
resource->setLocation(filename);
// Deserialize resource from a set of JSON records:
json::Helper::pushInstance(resource);
resource = jj;
/*
smtk::common::UUID resourceId = j.at("id").get<smtk::common::UUID>();
resource->setId(resourceId);
*/
smtk::markup::from_json(jj, resource);
// std::string fileDirectory = smtk::common::Paths::directory(rsrc->location()) + "/";
return this->createResult(smtk::operation::Operation::Outcome::SUCCEEDED);
auto result = this->createResult(smtk::operation::Operation::Outcome::SUCCEEDED);
result->findResource("resource")->appendValue(resource);
return result;
}
const char* Read::xmlDescription() const
......@@ -90,15 +88,22 @@ const char* Read::xmlDescription() const
return Read_xml;
}
void Read::markModifiedResources(Read::Result& /*unused*/)
void Read::markModifiedResources(Read::Result& result)
{
auto resourceItem = this->parameters()->associations();
for (auto rit = resourceItem->begin(); rit != resourceItem->end(); ++rit)
auto resourceItem = result->findResource("resource");
for (std::size_t ii = 0; ii < resourceItem->numberOfValues(); ++ii)
{
auto resource = std::dynamic_pointer_cast<smtk::resource::Resource>(*rit);
if (!resourceItem->isSet(ii))
{
continue;
}
auto resource = std::dynamic_pointer_cast<smtk::markup::Resource>(resourceItem->value(ii));
// Set the resource as unmodified from its persistent (i.e. on-disk) state
resource->setClean(true);
if (resource)
{
resource->setClean(true);
}
}
}
......
......@@ -2,29 +2,70 @@
#include "smtk/markup/Component.h"
#include "smtk/markup/Label.h"
#include "smtk/markup/Group.h"
#include "smtk/markup/Registrar.h"
#include "smtk/markup/Resource.h"
#include "smtk/markup/operators/Read.h"
#include "smtk/markup/operators/Write.h"
#include "smtk/plugin/Registry.h"
#include "smtk/operation/Manager.h"
#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/FileItem.h"
#include "smtk/attribute/IntItem.h"
#include "smtk/attribute/ReferenceItem.h"
#include "smtk/attribute/ResourceItem.h"
#include "smtk/resource/Manager.h"
#include "smtk/common/Managers.h"
#include "smtk/common/UUID.h"
#include "smtk/common/testing/cxx/helpers.h"
#include "nlohmann/json.hpp"
#include <cstdio>
#include <iostream>
#include <sstream>
using namespace smtk::markup;
using namespace json;
int TestResource(int argc, char** argv)
namespace
{
smtk::common::Managers::Ptr testRegistrar()
{
auto managers = smtk::common::Managers::create();
auto resourceManager = smtk::resource::Manager::create();
auto operationManager = smtk::operation::Manager::create();
managers->insert_or_assign(resourceManager);
managers->insert_or_assign(operationManager);
auto markupRegistry =
smtk::plugin::addToManagers<smtk::markup::Registrar>(
resourceManager, operationManager);
// Register the resource manager to the operation manager (newly created
// resources will be automatically registered to the resource manager).
operationManager->registerResourceManager(resourceManager);
return managers;
}
std::string testCreateAndWrite()
{
auto resource = smtk::markup::Resource::create();
resource->setLocation("/tmp/markup.smtk");
std::ostringstream filename;
filename << tmpnam(nullptr) << ".smtk";
resource->setLocation(filename.str());
auto label = resource->createNode<Label>();
label->setName("foo");
auto group = std::make_shared<Group>(resource, smtk::common::UUID::random());
group->setName("barf");
resource->add(group);
group->setName("barf");
/*
auto group = resource->createNode<Group>();
group->setName("barf");
......@@ -42,8 +83,13 @@ int TestResource(int argc, char** argv)
nn = components.size();
std::cout << "Found " << nn << " labels\n";
// resource->connect<LabelSubject>(*label, *group);
auto anotherLabel = resource->createNode<Label>(
R"({"name": "This is a really long descriptive label with no purpose."})"_json);
auto anotherGroup = resource->createNode<Group>(
R"({"name": "baz"})"_json);
label->get<LabelSubject>().insert(*group);
resource->connect<LabelSubject>(*anotherLabel, *anotherGroup);
// group->get<Labels>().insert(*label);
// Verify that both arcs (Labels and LabelSubject) were created.
......@@ -51,9 +97,60 @@ int TestResource(int argc, char** argv)
test(group->get<Labels>().count() == 1, "Group has no label or multiple labels.");
test(group->get<Labels>().to().find(*label) != group->get<Labels>().to().end(), "Group does not have label.");
test(anotherLabel->get<LabelSubject>().to().id() == anotherGroup->id(), "AnotherLabel has no subject.");
test(anotherGroup->get<Labels>().count() == 1, "AnotherGroup has no label or multiple labels.");
test(
anotherGroup->get<Labels>().to().find(*anotherLabel) !=
anotherGroup->get<Labels>().to().end(),
"AnotherGroup does not have label.");
std::cout << "Writing " << filename.str() << "\n";
auto write = smtk::markup::Write::create();
write->parameters()->associations()->appendValue(resource);
write->operate();
return filename.str(); // or resource->location();
}
std::string testReadAndWrite(const std::string& filename1)
{
bool ok = true;
auto read = smtk::markup::Read::create();
ok = read->parameters()->findFile("filename")->setValue(filename1);
test(ok, "Could not set filename.");
std::cout << "Reading " << read->parameters()->findFile("filename")->value() << "\n";
auto result = read->operate();
auto resource = result->findResource("resource")->valueAs<smtk::markup::Resource>();
std::cout << "Read " << result->findInt("outcome")->value() << " " << resource << "\n";
// Rename the file we just read to make room for the second generation copy.
std::ostringstream filename2;
filename2 << tmpnam(nullptr) << ".smtk";
std::cout << "Rename " << filename2.str() << "\n";
std::rename(filename1.c_str(), filename2.str().c_str());
// Write our resource back to filename1.
auto write = smtk::markup::Write::create();
write->parameters()->associations()->appendValue(resource);
result = write->operate();
std::cout << "Wrote " << result->findInt("outcome")->value() << " " << resource << "\n";
// std::cout << "Wrote " << resource->location() << "? " << result->findInt("outcome")->value() << "\n";
return 0;
return filename2.str();
}
bool testFileContentsMatch(const std::string& filename1, const std::string& filename2)
{
return true;
}
} // anonymous namespace
int TestResource(int argc, char** argv)
{
auto managers = testRegistrar();
std::string filename1 = testCreateAndWrite();
std::string filename2 = testReadAndWrite(filename1);
bool ok = testFileContentsMatch(filename1, filename2);
return ok ? 0 : 1;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment