Commit 80683af9 authored by Yumin Yuan's avatar Yumin Yuan
Browse files

Adding methods and operators for saving session models and meshes

Instead of having a SessionIOJSON class in every session for SessionIO support, the base
Session class now will handle export and import sessions, and writing and loading native
models by invoking "write" and "read" operators of the session. Also Made exodus SessionIOJSON
use new SessionIO methods
parent f164badc
......@@ -652,12 +652,8 @@ bool Session::ensureChildParentMapEntry(vtkDataObject* child, vtkDataObject* par
// ++ 12 ++
SessionIOPtr Session::createIODelegate(const std::string& format)
{
if (format == "json")
{
return SessionIOJSON::create();
}
return SessionIOPtr();
// Currently the DefaultSession is handling this.
return this->Superclass::createIODelegate(format);
}
// -- 12 --
......
......@@ -29,6 +29,20 @@ int SessionIOJSON::importJSON(ManagerPtr modelMgr, cJSON* sessionRec)
}
// -- 2 --
/**\brief Decode information from \a sessionRec for the given \a modelMgr.
*
* Subclasses should return 1 on success and 0 on failure.
*/
int SessionIOJSON::importJSON(ManagerPtr modelMgr,
const SessionPtr& session,
cJSON* sessionRec)
{
(void)modelMgr;
(void)session;
(void)sessionRec;
return 1;
}
/**\brief Encode information into \a sessionRec for the given \a modelMgr.
*
* Subclasses should return 1 on success and 0 on failure.
......@@ -48,9 +62,11 @@ int SessionIOJSON::exportJSON(ManagerPtr modelMgr, cJSON* sessionRec)
* This variant should export only information for the given models.
*/
// ++ 3 ++
int SessionIOJSON::exportJSON(ManagerPtr modelMgr, const common::UUIDs& modelIds, cJSON* sessionRec)
int SessionIOJSON::exportJSON(ManagerPtr modelMgr, const SessionPtr& session,
const common::UUIDs &modelIds, cJSON* sessionRec)
{
(void)modelMgr;
(void)session;
(void)modelIds;
(void)sessionRec;
return 1;
......
......@@ -30,9 +30,12 @@ public:
smtkCreateMacro(SessionIOJSON);
virtual ~SessionIOJSON() { }
virtual int importJSON(SessionRef modelMgr, cJSON* sessionRec);
virtual int exportJSON(SessionRef modelMgr, cJSON* sessionRec);
virtual int exportJSON(ManagerPtr modelMgr, const common::UUIDs& modelIds, cJSON* sessionRec);
virtual int importJSON(ManagerPtr modelMgr, cJSON* sessionRec);
virtual int importJSON(ManagerPtr modelMgr, const SessionPtr& session,
cJSON* sessionRec);
virtual int exportJSON(ManagerPtr modelMgr, cJSON* sessionRec);
virtual int exportJSON(ManagerPtr modelMgr, const SessionPtr& session,
const common::UUIDs &modelIds, cJSON* sessionRec);
};
// -- 1 --
......
......@@ -486,7 +486,9 @@ int ExportJSON::forManagerIntegerProperties(const smtk::common::UUID& uid, cJSON
return ExportJSON::forIntegerData(dict, entIt->second);
}
int ExportJSON::forManagerSession(const smtk::common::UUID& uid, cJSON* node, ManagerPtr modelMgr)
int ExportJSON::forManagerSession(const smtk::common::UUID& uid,
cJSON* node,
ManagerPtr modelMgr)
{
int status = 1;
SessionPtr session = SessionRef(modelMgr, uid).session();
......@@ -506,25 +508,25 @@ int ExportJSON::forManagerSession(const smtk::common::UUID& uid, cJSON* node, Ma
return status;
}
int ExportJSON::forManagerSessionPartial(const smtk::common::UUID& uid,
int ExportJSON::forManagerSessionPartial(const smtk::common::UUID& sessionid,
const smtk::common::UUIDs& modelIds,
cJSON* node,
ManagerPtr modelMgr)
{
int status = 1;
SessionPtr session = SessionRef(modelMgr, uid).session();
SessionPtr session = SessionRef(modelMgr, sessionid).session();
if (!session)
return status;
cJSON* sess = cJSON_CreateObject();
cJSON_AddItemToObject(node, uid.toString().c_str(), sess);
cJSON_AddStringToObject(sess, "type", "session");
cJSON_AddItemToObject(node, sessionid.toString().c_str(), sess);
cJSON_AddStringToObject(sess, "name", session->name().c_str());
SessionIOJSONPtr delegate =
smtk::dynamic_pointer_cast<SessionIOJSON>(
session->createIODelegate("json"));
if (delegate)
status &= delegate->exportJSON(modelMgr, modelIds, sess);
status &= delegate->exportJSON(modelMgr, session, modelIds, sess);
status &= ExportJSON::forOperatorDefinitions(session->operatorSystem(), sess);
return status;
}
......
......@@ -827,7 +827,24 @@ int ImportJSON::ofLocalSession(cJSON* node, ManagerPtr context)
sref.session()->createIODelegate("json"));
if (delegate)
{
status = delegate->importJSON(context, node);
status = delegate->importJSON(context, sref.session(), node);
}
return status;
}
/**\brief Create local sessions and import JSON into the sessions.
*
* This iterates over the session child nodes in parent json \a node,
* and then call ofLocalSession to import the json description into
* each session.
*/
int ImportJSON::ofLocalSessions(cJSON* node, ManagerPtr context)
{
int status = 0;
cJSON* sessentry;
for (sessentry = node->child; sessentry; sessentry = sessentry->next)
{
status &= ImportJSON::ofLocalSession(sessentry, context);
}
return status;
}
......
......@@ -46,6 +46,8 @@ public:
static int forManagerMeshes(smtk::mesh::ManagerPtr meshes, cJSON*, smtk::model::ManagerPtr modelMgr);
static int ofRemoteSession(cJSON*, smtk::model::DefaultSessionPtr destSession, smtk::model::ManagerPtr context);
static int ofLocalSession(cJSON*, smtk::model::ManagerPtr context);
static int ofLocalSessions(cJSON*, smtk::model::ManagerPtr context);
static int ofOperator(cJSON* node, smtk::model::OperatorPtr& op, smtk::model::ManagerPtr context);
static int ofOperatorResult(cJSON* node, smtk::model::OperatorResult& resOut, smtk::model::RemoteOperatorPtr op);
static int ofDanglingEntities(cJSON* node, smtk::model::ManagerPtr context);
......
......@@ -48,6 +48,8 @@ set(modelSrcs
operators/CloseModel.cxx
operators/SetProperty.cxx
operators/ExportModelJSON.cxx
operators/ExportSMTKModel.cxx
operators/ImportSMTKModel.cxx
)
set(modelHeaders
......@@ -112,6 +114,8 @@ smtk_session_json("${CMAKE_CURRENT_SOURCE_DIR}/DefaultSession.json" defSessionJS
smtk_operator_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/CloseModel.sbt" defOpXML)
smtk_operator_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/SetProperty.sbt" defOpXML)
smtk_operator_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/ExportModelJSON.sbt" defOpXML)
smtk_operator_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/ExportSMTKModel.sbt" defOpXML)
smtk_operator_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/ImportSMTKModel.sbt" defOpXML)
#install the headers
smtk_public_headers(${modelHeaders})
......
......@@ -4,7 +4,8 @@
{
"name": "native",
"filetypes": [
".json (Native SMTK model)"
".smtk (SMTK JSON model)",
".json (SMTK JSON model)"
]
}
]
......
......@@ -9,7 +9,7 @@
//=========================================================================
#include "smtk/model/Session.h"
#include "smtk/model/SessionIO.h"
#include "smtk/model/SessionIOJSON.h"
#include "smtk/model/Manager.h"
#include "smtk/model/RemoteOperator.h"
#include "smtk/model/ArrangementHelper.h"
......@@ -806,7 +806,11 @@ OperatorConstructor Session::findOperatorConstructorInternal(
*/
SessionIOPtr Session::createIODelegate(const std::string& format)
{
(void)format;
if (format == "json")
{
return SessionIOJSON::create();
}
return SessionIOPtr();
}
......
......@@ -9,10 +9,20 @@
//=========================================================================
#include "smtk/model/SessionIOJSON.h"
#include "smtk/attribute/FileItem.h"
#include "smtk/attribute/IntItem.h"
#include "smtk/common/UUID.h"
#include "smtk/io/ExportJSON.h"
#include "smtk/io/ExportJSON.txx"
#include "smtk/io/ImportJSON.h"
#include "smtk/model/Manager.h"
#include "smtk/model/Operator.h"
#include "boost/filesystem.hpp"
#include "cJSON.h"
using namespace boost::filesystem;
namespace smtk {
namespace model {
......@@ -20,6 +30,7 @@ namespace smtk {
*
* Subclasses should return 1 on success and 0 on failure.
*/
// ++ 2 ++
int SessionIOJSON::importJSON(ManagerPtr modelMgr, cJSON* sessionRec)
{
(void)modelMgr;
......@@ -27,6 +38,80 @@ int SessionIOJSON::importJSON(ManagerPtr modelMgr, cJSON* sessionRec)
return 1;
}
/**\brief Decode information from \a sessionRec for the given \a modelMgr.
*
* Subclasses should return 1 on success and 0 on failure.
*/
int SessionIOJSON::importJSON(ManagerPtr modelMgr,
const SessionPtr& session,
cJSON* sessionRec)
{
int status = 0;
smtk::common::UUIDs models =
modelMgr->entitiesMatchingFlags(smtk::model::MODEL_ENTITY);
cJSON* modelentry;
// import all model entites, should only have meta info
for (modelentry = sessionRec->child; modelentry; modelentry = modelentry->next)
{
smtk::common::UUID modelid = smtk::common::UUID(modelentry->string);
if (modelid.isNull())
{
smtkInfoMacro(modelMgr->log(), "Invalid model uuid, skipping!");
continue;
}
// import native model if the model does not exist;
// NOTE: what should we do if it already exists? erase then re-load
// the original model from file (stored in string property "url")?
// Else, just import meta info
if(models.find(modelid) == models.end())
{
// find the model entry, and get the native model file name if it exists,
// by looking at "output_native_url" property
for (cJSON* curChild = modelentry->child; curChild; curChild = curChild->next)
{
if (!curChild->string || !curChild->string[0])
{
continue;
}
// find the model id in dictionary
if (smtk::common::UUID(curChild->string) != modelid)
{
continue;
}
// failed to load properties is still OK
smtk::io::ImportJSON::ofManagerStringProperties(modelid, curChild, modelMgr);
break;
}
std::string nativemodelfile;
std::string nativefilekey = modelMgr->hasStringProperty(modelid, "output_native_url") ?
"output_native_url" :
(modelMgr->hasStringProperty(modelid, "url") ? "url" : "");
if (!nativefilekey.empty())
{
smtk::model::StringList const& nprop(modelMgr->stringProperty(modelid, nativefilekey));
if (!nprop.empty())
{
nativemodelfile = nprop[0];
}
}
if(!nativemodelfile.empty())
{
// failed to load native model is still ok
this->loadNativeModel(modelMgr, session, nativemodelfile);
}
}
// model meta info
status &= smtk::io::ImportJSON::ofManager(modelentry, modelMgr);
// mesh collections related to this model
status &= smtk::io::ImportJSON::ofMeshesOfModel(modelentry, modelMgr, true);
}
return status;
}
/**\brief Encode information into \a sessionRec for the given \a modelMgr.
*
* Subclasses should return 1 on success and 0 on failure.
......@@ -42,13 +127,145 @@ int SessionIOJSON::exportJSON(ManagerPtr modelMgr, cJSON* sessionRec)
*
* Subclasses should return 1 on success and 0 on failure.
*/
int SessionIOJSON::exportJSON(ManagerPtr modelMgr, const smtk::common::UUIDs& modelIds, cJSON* sessionRec)
int SessionIOJSON::exportJSON(ManagerPtr modelMgr,
const SessionPtr& session,
const smtk::common::UUIDs& modelIds,
cJSON* sessionRec)
{
(void)modelMgr;
(void)modelIds;
(void)sessionRec;
// we will write each model seperately
smtk::common::UUIDs::const_iterator modit;
for(modit = modelIds.begin(); modit != modelIds.end(); ++modit)
{
smtk::model::Model model(modelMgr, *modit);
std::string outNativeFile;
if(this->writeNativeModel(
modelMgr, session, model, outNativeFile))
{
modelMgr->setStringProperty(*modit, "output_native_url", outNativeFile);
}
cJSON* jmodel = cJSON_CreateObject();
cJSON_AddStringToObject(jmodel, "type", "model");
cJSON_AddStringToObject(jmodel, "name", model.name().c_str());
// Write out all entities of the model, only the meta data
smtk::model::Models currentmodels;
currentmodels.push_back(model);
smtk::io::ExportJSON::forEntities(jmodel, currentmodels,
smtk::model::ITERATE_MODELS,
smtk::io::JSON_CLIENT_DATA);
// Write out related mesh collections.
// When writing a single collection, all its MeshSets will also be written out.
smtk::io::ExportJSON::forModelMeshes(*modit, jmodel, modelMgr);
cJSON_AddItemToObject(sessionRec, modit->toString().c_str(), jmodel);
}
return 1;
}
/**\brief Create and write to a file (\a outNativeFile) for the given \a model.
*
* Return 1 on success and 0 on failure.
*/
int SessionIOJSON::writeNativeModel(smtk::model::ManagerPtr modelMgr,
const smtk::model::SessionPtr& sess,
const smtk::model::Model& model,
std::string& outNativeFile)
{
// if this is not a valid session, return;
if(!sess)
{
smtkInfoMacro(modelMgr->log(), "Expecting a valid session!");
return 0;
}
std::string smtkfilepath, smtkfilename, origfilename, origfileext;
if (modelMgr->hasStringProperty(model.entity(), "smtk_url"))
{
smtk::model::StringList const& nprop(modelMgr->stringProperty(model.entity(), "smtk_url"));
if (!nprop.empty())
{
smtkfilepath = path(nprop[0]).parent_path().string();
smtkfilename = path(nprop[0]).stem().string();
}
}
if (modelMgr->hasStringProperty(model.entity(), "url"))
{
smtk::model::StringList const& nprop(modelMgr->stringProperty(model.entity(), "url"));
if (!nprop.empty())
{
origfilename = path(nprop[0]).stem().string();
origfileext = path(nprop[0]).extension().string();
}
}
if (smtkfilename.empty() && !origfilename.empty())
smtkfilename = origfilename;
if (smtkfilename.empty())
smtkfilename = sess->name();
std::ostringstream outfilename;
outfilename << smtkfilename << "_native" << origfileext;
outNativeFile = (path(smtkfilepath) / path(outfilename.str())).string();
smtk::model::OperatorPtr writeOp = sess->op("write");
if (!writeOp)
{
smtkInfoMacro(modelMgr->log(), "Failed to create a write operator to write the model for native kernel!");
return 0;
}
writeOp->specification()->findFile("filename")->setValue(outNativeFile);
writeOp->specification()->associateEntity(model);
smtk::model::OperatorResult opresult = writeOp->operate();
if (opresult->findInt("outcome")->value() !=
smtk::model::OPERATION_SUCCEEDED)
{
smtkInfoMacro(modelMgr->log(), "Failed to write the model for native kernel!");
return 0;
}
return 1;
}
/**\brief Load the native model given the filename (\a inNativeFile).
*
* Return 1 on success and 0 on failure.
*/
int SessionIOJSON::loadNativeModel(smtk::model::ManagerPtr modelMgr,
const smtk::model::SessionPtr& sess,
const std::string& inNativeFile)
{
// if this is not a valid session, return;
if(!sess)
{
smtkInfoMacro(modelMgr->log(), "Expecting a valid session!");
return 0;
}
if (!inNativeFile.empty())
{
smtk::model::OperatorPtr readOp = sess->op("read");
if (!readOp)
{
smtkInfoMacro(modelMgr->log(), "Failed to create a read operator to read the model for native kernel!");
return 0;
}
readOp->specification()->findFile("filename")->setValue(inNativeFile);
smtk::model::OperatorResult opresult = readOp->operate();
if (opresult->findInt("outcome")->value() !=
smtk::model::OPERATION_SUCCEEDED)
{
smtkInfoMacro(modelMgr->log(), "Failed to read the model for native kernel!");
return 0;
}
return 1;
}
return 0;
}
} // namespace model
} // namespace smtk
......@@ -28,9 +28,23 @@ public:
smtkTypeMacro(SessionIOJSON);
smtkCreateMacro(SessionIOJSON);
virtual ~SessionIOJSON() { }
virtual int importJSON(ManagerPtr modelMgr, cJSON* sessionRec);
virtual int importJSON(ManagerPtr modelMgr, const SessionPtr& session,
cJSON* sessionRec);
virtual int exportJSON(ManagerPtr modelMgr, cJSON* sessionRec);
virtual int exportJSON(ManagerPtr modelMgr, const common::UUIDs &modelIds, cJSON* sessionRec);
virtual int exportJSON(ManagerPtr modelMgr, const SessionPtr& session,
const common::UUIDs &modelIds, cJSON* sessionRec);
protected:
virtual int writeNativeModel(smtk::model::ManagerPtr modelMgr,
const smtk::model::SessionPtr& sess,
const smtk::model::Model& model,
std::string& outNativeFile);
virtual int loadNativeModel(smtk::model::ManagerPtr modelMgr,
const smtk::model::SessionPtr& sess,
const std::string& inNativeFile);
};
} // namespace model
......
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#include "smtk/model/operators/ExportSMTKModel.h"
#include "smtk/model/Session.h"
#include "smtk/model/CellEntity.h"
#include "smtk/model/Manager.h"
#include "smtk/model/Model.h"
#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/FileItem.h"
#include "smtk/attribute/IntItem.h"
#include "smtk/attribute/ModelEntityItem.h"
#include "smtk/io/ExportJSON.h"
#include "smtk/io/ExportJSON.txx"
#include "cJSON.h"
#include <fstream>
using namespace smtk::model;
using smtk::attribute::FileItem;
using smtk::attribute::IntItem;
using smtk::io::JSONFlags;
namespace smtk {
namespace model {
smtk::model::OperatorResult ExportSMTKModel::operateInternal()
{
smtk::attribute::FileItemPtr filenameItem = this->findFile("filename");
smtk::attribute::IntItemPtr flagsItem = this->findInt("flags");
smtk::common::UUIDs models = this->m_specification->associatedModelEntityIds();
if (models.empty())
{
smtkErrorMacro(this->log(), "No valid models selected for export.");
return this->createResult(smtk::model::OPERATION_FAILED);
}
std::string filename = filenameItem->value();
if (filename.empty())
{
smtkErrorMacro(this->log(), "A filename must be provided.");
return this->createResult(smtk::model::OPERATION_FAILED);
}
std::ofstream jsonFile(filename.c_str(), std::ios::trunc);
if (!jsonFile.good())
{
smtkErrorMacro(this->log(), "Could not open file \"" << filename << "\".");
return this->createResult(smtk::model::OPERATION_FAILED);
}
cJSON* top = cJSON_CreateObject();
cJSON_AddItemToObject(top, "type", cJSON_CreateString("Session"));
// Add the output smtk model name to the model "smtk_url", so that the individual session can
// use that name to construct a filename for saving native models of the session.
smtk::common::UUIDs::const_iterator modit;
for(modit = models.begin(); modit != models.end(); ++modit)
{
this->manager()->setStringProperty(*modit, "smtk_url", filename);
}
smtk::io::ExportJSON::forManagerSessionPartial(this->session()->sessionId(),
models, top, this->manager());
char* json = cJSON_Print(top);
jsonFile << json;
free(json);
cJSON_Delete(top);
jsonFile.close();
return this->createResult(smtk::model::OPERATION_SUCCEEDED);
}
} //namespace model
} // namespace smtk
#include "smtk/model/ExportSMTKModel_xml.h"
smtkImplementsModelOperator(
SMTKCORE_EXPORT,
smtk::model::ExportSMTKModel,
export_smtk_model,
"export smtk model",
ExportSMTKModel_xml,
smtk::model::Session);
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#ifndef __smtk_model_ExportSMTKModel_h
#define __smtk_model_ExportSMTKModel_h
#include "smtk/model/Operator.h"
namespace smtk {
namespace model {
class SMTKCORE_EXPORT ExportSMTKModel : public Operator
{
public:
smtkTypeMacro(ExportSMTKModel);
smtkCreateMacro(ExportSMTKModel);
smtkSharedFromThisMacro(Operator);
smtkDeclareModelOperator();
protected:
virtual smtk::model::OperatorResult operateInternal();
};