From 3d790497c67b07149f8563dbae39856aa961e74d Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Fri, 17 Jan 2014 21:35:34 +0100 Subject: Polished umundo invoker, prolog datamodel and several bugfixes --- contrib/cmake/FindUMUNDO.cmake | 6 + docs/BUILDING.md | 3 + .../plugins/datamodel/prolog/swi/SWIDataModel.cpp | 525 +++++++++++---------- .../plugins/invoker/umundo/UmundoInvoker.cpp | 120 +++-- src/uscxml/plugins/invoker/umundo/UmundoInvoker.h | 11 +- .../plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp | 4 +- src/uscxml/server/InterpreterServlet.cpp | 8 +- test/samples/uscxml/test-umundo-s11n-chat.scxml | 13 + 8 files changed, 366 insertions(+), 324 deletions(-) create mode 100644 test/samples/uscxml/test-umundo-s11n-chat.scxml diff --git a/contrib/cmake/FindUMUNDO.cmake b/contrib/cmake/FindUMUNDO.cmake index 65e5463..437f861 100644 --- a/contrib/cmake/FindUMUNDO.cmake +++ b/contrib/cmake/FindUMUNDO.cmake @@ -112,6 +112,12 @@ foreach (_UMUNDO_COMPONENT ${_UMUNDO_COMPONENTS_TO_PROCESS}) ) if (${_CURR_COMPONENT}_DEBUG) list(APPEND UMUNDO_LIBRARIES debug ${${_CURR_COMPONENT}_DEBUG}) + else() + if (NOT WIN32 AND ${_CURR_COMPONENT}) + list(APPEND UMUNDO_LIBRARIES debug ${${_CURR_COMPONENT}}) + else() + message(STATUS "Could not find umundo component ${_UMUNDO_COMPONENT}") + endif() endif() endif() diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 20334ee..01a52d7 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -200,6 +200,9 @@ This is sufficient to get uscxml to build. If you want some more functionality, # expect invoker $ sudo yum install expect-devel tk-devel + # instant messaging invoker + $ sudo yum install libpurple-devel + ### Console / Make Instructions are a literal copy of building uscxml for MacOSX on the console from above: diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp index 4786903..9d9dda8 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp @@ -30,6 +30,14 @@ #include #endif +#define RETHROW_PLEX_AS_EVENT \ +catch (PlException plex) { \ + Event e; \ + e.name = "error.execution"; \ + e.data.compound["cause"] = (char*)plex; \ + throw e; \ +} \ + #define SET_PL_CONTEXT \ _dmPtr = this; @@ -66,121 +74,127 @@ SWIDataModel::SWIDataModel() { } SWIDataModel::~SWIDataModel() { - if (_swiEngines.find(this) != _swiEngines.end()) { - PL_destroy_engine(_swiEngines[this]); - _swiEngines.erase(this); - } + try { + if (_swiEngines.find(this) != _swiEngines.end()) { + PL_destroy_engine(_swiEngines[this]); + _swiEngines.erase(this); + } + } RETHROW_PLEX_AS_EVENT; } boost::shared_ptr SWIDataModel::create(InterpreterImpl* interpreter) { - boost::shared_ptr dm = boost::shared_ptr(new SWIDataModel()); - dm->_interpreter = interpreter; - - const char* swibin = getenv("SWI_BINARY"); - if (swibin == NULL) - swibin = SWI_BINARY; - const char* quiet = "--quiet"; - - int argc = 2; - static char * av[] = { - (char*)swibin, - (char*)quiet, - NULL - }; - - PL_engine_t engine; - - if (!PL_is_initialised(NULL, NULL)) { - if(!PL_initialise(argc,av)) { - LOG(ERROR) << "Error intializing prolog engine"; - PL_halt(1); - return boost::shared_ptr(); - } + try { + boost::shared_ptr dm = boost::shared_ptr(new SWIDataModel()); + dm->_interpreter = interpreter; + + const char* swibin = getenv("SWI_BINARY"); + if (swibin == NULL) + swibin = SWI_BINARY; + const char* quiet = "--quiet"; + + int argc = 2; + static char * av[] = { + (char*)swibin, + (char*)quiet, + NULL + }; + + PL_engine_t engine; + + if (!PL_is_initialised(NULL, NULL)) { + if(!PL_initialise(argc,av)) { + LOG(ERROR) << "Error intializing prolog engine"; + PL_halt(1); + return boost::shared_ptr(); + } - PL_set_engine(PL_ENGINE_CURRENT, &engine); + PL_set_engine(PL_ENGINE_CURRENT, &engine); - // load SWI XML parser - try { - PlCall("use_module", PlCompound("library", PlTerm("sgml"))); - } catch (PlException plex) { + // load SWI XML parser + try { + PlCall("use_module", PlCompound("library", PlTerm("sgml"))); + } catch (PlException plex) { - LOG(ERROR) << "Cannot load prolog sgml module - make sure you have it installed in your prolog runtime: " << (char*)plex; - throw plex; - } + LOG(ERROR) << "Cannot load prolog sgml module - make sure you have it installed in your prolog runtime: " << (char*)plex; + throw plex; + } - // load json parser - try { - PlCall("use_module", PlCompound("library", PlTerm("http/json"))); - PlCall("use_module", PlCompound("library", PlTerm("http/json_convert"))); - } catch (PlException plex) { - LOG(ERROR) << "Cannot load prolog json module or json_convert - make sure you have it installed in your prolog runtime: " << (char*)plex; - throw plex; + // load json parser + try { + PlCall("use_module", PlCompound("library", PlTerm("http/json"))); + PlCall("use_module", PlCompound("library", PlTerm("http/json_convert"))); + } catch (PlException plex) { + LOG(ERROR) << "Cannot load prolog json module or json_convert - make sure you have it installed in your prolog runtime: " << (char*)plex; + throw plex; + } + + } else { + LOG(WARNING) << "Instantiating more than one SWI prolog datamodel will lead to weird effects as I cannot seperate the environments"; + engine = PL_create_engine(NULL); } - } else { - LOG(WARNING) << "Instantiating more than one SWI prolog datamodel will lead to weird effects as I cannot seperate the environments"; - engine = PL_create_engine(NULL); - } + assert(engine); + _swiEngines[dm.get()] = engine; + _dmPtr = dm.get(); + + int rc = PL_set_engine(engine, NULL); + assert(rc == PL_ENGINE_SET); + (void)rc; + + _plModule = boost::replace_all_copy(interpreter->getSessionId(), "-", ""); + boost::replace_all(_plModule, "0", "g"); + boost::replace_all(_plModule, "1", "h"); + boost::replace_all(_plModule, "2", "i"); + boost::replace_all(_plModule, "3", "j"); + boost::replace_all(_plModule, "4", "k"); + boost::replace_all(_plModule, "5", "l"); + boost::replace_all(_plModule, "6", "m"); + boost::replace_all(_plModule, "7", "n"); + boost::replace_all(_plModule, "8", "o"); + boost::replace_all(_plModule, "9", "p"); + + // use atoms for double quoted + PlCall("set_prolog_flag(double_quotes,atom)."); + + // set system variables + PlCall("assert", PlCompound("sessionid", PlTerm(PlString(dm->_interpreter->getSessionId().c_str())))); + PlCall("assert", PlCompound("name", PlTerm(PlString(dm->_interpreter->getName().c_str())))); + + std::map::const_iterator ioProcIter = dm->_interpreter->getIOProcessors().begin(); + while(ioProcIter != dm->_interpreter->getIOProcessors().end()) { + Data ioProcData = ioProcIter->second.getDataModelVariables(); + + if (ioProcIter->first.find_first_of(":/'") == std::string::npos) { + std::stringstream ioProcShortCall; + ioProcShortCall << "assert(ioprocessors(" << ioProcIter->first << "(location('" << ioProcData.compound["location"].atom << "'))))"; + PlCall(ioProcShortCall.str().c_str()); + } + std::stringstream ioProcCall; + ioProcCall << "assert(ioprocessors(name('" << ioProcIter->first << "'), location('" << ioProcData.compound["location"].atom << "')))"; + PlCall(ioProcCall.str().c_str()); - assert(engine); - _swiEngines[dm.get()] = engine; - _dmPtr = dm.get(); - - int rc = PL_set_engine(engine, NULL); - assert(rc == PL_ENGINE_SET); - (void)rc; - - _plModule = boost::replace_all_copy(interpreter->getSessionId(), "-", ""); - boost::replace_all(_plModule, "0", "g"); - boost::replace_all(_plModule, "1", "h"); - boost::replace_all(_plModule, "2", "i"); - boost::replace_all(_plModule, "3", "j"); - boost::replace_all(_plModule, "4", "k"); - boost::replace_all(_plModule, "5", "l"); - boost::replace_all(_plModule, "6", "m"); - boost::replace_all(_plModule, "7", "n"); - boost::replace_all(_plModule, "8", "o"); - boost::replace_all(_plModule, "9", "p"); - - // use atoms for double quoted - PlCall("set_prolog_flag(double_quotes,atom)."); - - // set system variables - PlCall("assert", PlCompound("sessionid", PlTerm(PlString(dm->_interpreter->getSessionId().c_str())))); - PlCall("assert", PlCompound("name", PlTerm(PlString(dm->_interpreter->getName().c_str())))); - - std::map::const_iterator ioProcIter = dm->_interpreter->getIOProcessors().begin(); - while(ioProcIter != dm->_interpreter->getIOProcessors().end()) { - Data ioProcData = ioProcIter->second.getDataModelVariables(); - - if (ioProcIter->first.find_first_of(":/'") == std::string::npos) { - std::stringstream ioProcShortCall; - ioProcShortCall << "assert(ioprocessors(" << ioProcIter->first << "(location('" << ioProcData.compound["location"].atom << "'))))"; - PlCall(ioProcShortCall.str().c_str()); + ioProcIter++; } - std::stringstream ioProcCall; - ioProcCall << "assert(ioprocessors(name('" << ioProcIter->first << "'), location('" << ioProcData.compound["location"].atom << "')))"; - PlCall(ioProcCall.str().c_str()); - - ioProcIter++; - } - // the in predicate - PlRegister("user", "in", 1, SWIDataModel::inPredicate); - return dm; + // the in predicate + PlRegister("user", "in", 1, SWIDataModel::inPredicate); + return dm; + } RETHROW_PLEX_AS_EVENT; } foreign_t SWIDataModel::inPredicate(term_t a0, int arity, void* context) { - char *s; - if ( PL_get_atom_chars(a0, &s) ) { - NodeSet config = _dmPtr->_interpreter->getConfiguration(); - for (int i = 0; i < config.size(); i++) { - if (HAS_ATTR(config[i], "id") && strcmp(ATTR(config[i], "id").c_str(), s) == 0) { - return TRUE; + try { + char *s; + if ( PL_get_atom_chars(a0, &s) ) { + NodeSet config = _dmPtr->_interpreter->getConfiguration(); + for (int i = 0; i < config.size(); i++) { + if (HAS_ATTR(config[i], "id") && strcmp(ATTR(config[i], "id").c_str(), s) == 0) { + return TRUE; + } } } - } - return FALSE; + return FALSE; + } RETHROW_PLEX_AS_EVENT; } void SWIDataModel::registerIOProcessor(const std::string& name, const IOProcessor& ioprocessor) { @@ -210,6 +224,7 @@ void SWIDataModel::initialize() { } void SWIDataModel::setEvent(const Event& event) { + SET_PL_CONTEXT; // remove old event try { @@ -287,9 +302,7 @@ void SWIDataModel::setEvent(const Event& event) { paramIter = lastValueIter; } } - } catch(PlException e) { - LOG(ERROR) << e.operator const char *(); - } + } RETHROW_PLEX_AS_EVENT; } Data SWIDataModel::getStringAsData(const std::string& content) { @@ -307,16 +320,18 @@ bool SWIDataModel::validate(const std::string& location, const std::string& sche uint32_t SWIDataModel::getLength(const std::string& expr) { SET_PL_CONTEXT - PlCompound compound(expr.c_str()); - PlTermv termv(compound.arity()); - for (int i = 0; i < compound.arity(); i++) { - termv[i] = compound[i + 1]; - } - PlQuery query(compound.name(), termv); - uint32_t length = 0; - while(query.next_solution() > 0) - length++; - return length; + try { + PlCompound compound(expr.c_str()); + PlTermv termv(compound.arity()); + for (int i = 0; i < compound.arity(); i++) { + termv[i] = compound[i + 1]; + } + PlQuery query(compound.name(), termv); + uint32_t length = 0; + while(query.next_solution() > 0) + length++; + return length; + } RETHROW_PLEX_AS_EVENT; } void SWIDataModel::setForeach(const std::string& item, @@ -324,40 +339,44 @@ void SWIDataModel::setForeach(const std::string& item, const std::string& index, uint32_t iteration) { SET_PL_CONTEXT - PlCompound compound(array.c_str()); - PlCompound orig(array.c_str()); - PlTermv termv(compound.arity()); - for (int i = 0; i < compound.arity(); i++) { - termv[i] = compound[i + 1]; - } - { - int tmp = iteration + 1; - PlQuery query(compound.name(), termv); - while (tmp) { - query.next_solution(); - tmp--; + try { + PlCompound compound(array.c_str()); + PlCompound orig(array.c_str()); + PlTermv termv(compound.arity()); + for (int i = 0; i < compound.arity(); i++) { + termv[i] = compound[i + 1]; } - } - PlCall("retractall", PlCompound(index.c_str(), 1)); - PlCall("retractall", PlCompound(item.c_str(), 1)); - PlCall("assert", PlCompound(index.c_str(), PlTerm((long)iteration))); - - std::map vars = resolveAtoms(compound, orig); - std::map::iterator varIter = vars.begin(); - while(varIter != vars.end()) { - PlCall("assert", PlCompound(item.c_str(), varIter->second)); - varIter++; - } + { + int tmp = iteration + 1; + PlQuery query(compound.name(), termv); + while (tmp) { + query.next_solution(); + tmp--; + } + } + PlCall("retractall", PlCompound(index.c_str(), 1)); + PlCall("retractall", PlCompound(item.c_str(), 1)); + PlCall("assert", PlCompound(index.c_str(), PlTerm((long)iteration))); + + std::map vars = resolveAtoms(compound, orig); + std::map::iterator varIter = vars.begin(); + while(varIter != vars.end()) { + PlCall("assert", PlCompound(item.c_str(), varIter->second)); + varIter++; + } + } RETHROW_PLEX_AS_EVENT; } void SWIDataModel::eval(const Element& scriptElem, const std::string& expr) { SET_PL_CONTEXT - if (scriptElem && HAS_ATTR(scriptElem, "type") && iequals(ATTR(scriptElem, "type"), "query")) { - evalAsBool(expr); - } else { - URL localPLFile = URL::toLocalFile(expr, ".pl"); - PlCall("user", "load_files", PlTermv(localPLFile.asLocalFile(".pl").c_str())) || LOG(ERROR) << "Could not execute prolog from file"; - } + try { + if (scriptElem && HAS_ATTR(scriptElem, "type") && iequals(ATTR(scriptElem, "type"), "query")) { + evalAsBool(expr); + } else { + URL localPLFile = URL::toLocalFile(expr, ".pl"); + PlCall("user", "load_files", PlTermv(localPLFile.asLocalFile(".pl").c_str())) || LOG(ERROR) << "Could not execute prolog from file"; + } + } RETHROW_PLEX_AS_EVENT; } bool SWIDataModel::evalAsBool(const std::string& expr) { @@ -381,136 +400,142 @@ bool SWIDataModel::evalAsBool(const Arabica::DOM::Node& node, const std::string SWIDataModel::evalAsString(const std::string& expr) { SET_PL_CONTEXT - PlCompound orig(expr.c_str()); // keep the original to find variables - PlCompound compound(expr.c_str()); - if (strlen(compound.name())) { - PlTermv termv(compound.arity()); - for (int i = 0; i < compound.arity(); i++) { - termv[i] = compound[i + 1]; - } - PlQuery query(compound.name(), termv); - - std::stringstream ss; - const char* separator = ""; - while (query.next_solution()) { - std::map vars = resolveAtoms(compound, orig); - if (vars.size() == 1) { - ss << (char *)vars.begin()->second; - } else { - std::map::const_iterator varIter = vars.begin(); - while(varIter != vars.end()) { - ss << separator << (char *)varIter->second; - separator = ", "; - varIter++; + try { + PlCompound orig(expr.c_str()); // keep the original to find variables + PlCompound compound(expr.c_str()); + if (strlen(compound.name())) { + PlTermv termv(compound.arity()); + for (int i = 0; i < compound.arity(); i++) { + termv[i] = compound[i + 1]; + } + PlQuery query(compound.name(), termv); + + std::stringstream ss; + const char* separator = ""; + while (query.next_solution()) { + std::map vars = resolveAtoms(compound, orig); + if (vars.size() == 1) { + ss << (char *)vars.begin()->second; + } else { + std::map::const_iterator varIter = vars.begin(); + while(varIter != vars.end()) { + ss << separator << (char *)varIter->second; + separator = ", "; + varIter++; + } } } + return ss.str(); } - return ss.str(); - } - return std::string(compound); + return std::string(compound); + } RETHROW_PLEX_AS_EVENT } // this is similar to http://etalis.googlecode.com/svn/eEtalis/src/term.c std::map SWIDataModel::resolveAtoms(PlTerm& term, PlTerm& orig) { SET_PL_CONTEXT - std::map atoms; - switch (orig.type()) { - case PL_VARIABLE: { - atoms[(char *)orig] = term; - break; - } - case PL_ATOM: - break; - case PL_STRING: - break; - case PL_INTEGER: - break; - case PL_TERM: - for (int i = 1; i <= orig.arity(); i++) { - PlTerm newTerm = term[i]; - PlTerm newOrig = orig[i]; - std::map result = resolveAtoms(newTerm, newOrig); - atoms.insert(result.begin(), result.end()); + try { + std::map atoms; + switch (orig.type()) { + case PL_VARIABLE: { + atoms[(char *)orig] = term; + break; } - break; - } - return atoms; + case PL_ATOM: + break; + case PL_STRING: + break; + case PL_INTEGER: + break; + case PL_TERM: + for (int i = 1; i <= orig.arity(); i++) { + PlTerm newTerm = term[i]; + PlTerm newOrig = orig[i]; + std::map result = resolveAtoms(newTerm, newOrig); + atoms.insert(result.begin(), result.end()); + } + break; + } + return atoms; + } RETHROW_PLEX_AS_EVENT } void SWIDataModel::assign(const Element& assignElem, const Node& node, const std::string& content) { SET_PL_CONTEXT - std::string expr = content; - std::string predicate; - if (HAS_ATTR(assignElem, "expr")) { - expr = ATTR(assignElem, "expr"); - } - if (HAS_ATTR(assignElem, "id")) - predicate = ATTR(assignElem, "id"); - if (HAS_ATTR(assignElem, "location")) - predicate = ATTR(assignElem, "location"); - - if (predicate.size() > 0) { - std::string callAssert = "assert"; - std::string type; - if (HAS_ATTR(assignElem, "type")) { - type = ATTR(assignElem, "type"); - if(iequals(type, "append")) { - callAssert = "assertz"; - } else if(iequals(type, "prepend")) { - callAssert = "asserta"; - } + try { + std::string expr = content; + std::string predicate; + if (HAS_ATTR(assignElem, "expr")) { + expr = ATTR(assignElem, "expr"); } - - URL domUrl; - Data json; - if (!node) - json = Data::fromJSON(expr); - if (node) { - std::stringstream dataInitStr; - std::stringstream xmlDoc; - Node child = node; - while(child) { - xmlDoc << child; - child = child.getNextSibling(); + if (HAS_ATTR(assignElem, "id")) + predicate = ATTR(assignElem, "id"); + if (HAS_ATTR(assignElem, "location")) + predicate = ATTR(assignElem, "location"); + + if (predicate.size() > 0) { + std::string callAssert = "assert"; + std::string type; + if (HAS_ATTR(assignElem, "type")) { + type = ATTR(assignElem, "type"); + if(iequals(type, "append")) { + callAssert = "assertz"; + } else if(iequals(type, "prepend")) { + callAssert = "asserta"; + } } - domUrl = URL::toLocalFile(xmlDoc.str(), ".pl"); - if (iequals(type, "retract")) - PlCall("retractall", PlCompound(predicate.c_str(), 1)); - dataInitStr << "load_xml_file('" << domUrl.asLocalFile(".pl") << "', XML), copy_term(XML,DATA), " << callAssert << "(" << predicate << "(DATA))"; - PlCall(dataInitStr.str().c_str()); - } else if (json) { - std::stringstream dataInitStr; - if (iequals(type, "retract")) - PlCall("retractall", PlCompound(predicate.c_str(), 1)); - dataInitStr << "json_to_prolog(" << expr << ", JSON), assert(" << predicate << "(JSON))"; - PlCall(dataInitStr.str().c_str()); - } else { - // treat content as . seperated facts - std::stringstream factStream(content); - std::string item; - while(std::getline(factStream, item, '.')) { - std::string fact = boost::trim_copy(item); - if (fact.length() == 0) - continue; - PlCall((callAssert + "(" + predicate + "(" + fact + "))").c_str()); + + URL domUrl; + Data json; + if (!node) + json = Data::fromJSON(expr); + if (node) { + std::stringstream dataInitStr; + std::stringstream xmlDoc; + Node child = node; + while(child) { + xmlDoc << child; + child = child.getNextSibling(); + } + domUrl = URL::toLocalFile(xmlDoc.str(), ".pl"); + if (iequals(type, "retract")) + PlCall("retractall", PlCompound(predicate.c_str(), 1)); + dataInitStr << "load_xml_file('" << domUrl.asLocalFile(".pl") << "', XML), copy_term(XML,DATA), " << callAssert << "(" << predicate << "(DATA))"; + PlCall(dataInitStr.str().c_str()); + } else if (json) { + std::stringstream dataInitStr; + if (iequals(type, "retract")) + PlCall("retractall", PlCompound(predicate.c_str(), 1)); + dataInitStr << "json_to_prolog(" << expr << ", JSON), assert(" << predicate << "(JSON))"; + PlCall(dataInitStr.str().c_str()); + } else { + // treat content as . seperated facts + std::stringstream factStream(content); + std::string item; + while(std::getline(factStream, item, '.')) { + std::string fact = boost::trim_copy(item); + if (fact.length() == 0) + continue; + PlCall((callAssert + "(" + predicate + "(" + fact + "))").c_str()); + } } - } - } else if (expr.length() > 0) { - if (boost::equals(TAGNAME(assignElem), "data")) { - eval(assignElem, expr); - } else { - std::stringstream exprStream(expr); - std::string item; - while(std::getline(exprStream, item, '.')) { - std::string plExpr = boost::trim_copy(item); - if (plExpr.length() == 0) - continue; - PlCall(plExpr.c_str()); + } else if (expr.length() > 0) { + if (boost::equals(TAGNAME(assignElem), "data")) { + eval(assignElem, expr); + } else { + std::stringstream exprStream(expr); + std::string item; + while(std::getline(exprStream, item, '.')) { + std::string plExpr = boost::trim_copy(item); + if (plExpr.length() == 0) + continue; + PlCall(plExpr.c_str()); + } } } - } + } RETHROW_PLEX_AS_EVENT } void SWIDataModel::assign(const std::string& location, const Data& data) { diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp index f81f47f..a09f3af 100644 --- a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp +++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp @@ -37,19 +37,20 @@ bool pluginConnect(pluma::Host& host) { } #endif -UmundoInvoker::UmundoInvoker() : _pub(NULL), _sub(NULL) { +UmundoInvoker::UmundoInvoker() : _pub(NULL), _sub(NULL), _node(NULL) { } UmundoInvoker::~UmundoInvoker() { if (_node) { -// if (_sub) { -// _node->removeSubscriber(*_sub); -// delete _sub; -// } -// if (_pub) { -// _node->removePublisher(*_pub); -// delete _pub; -// } + if (_sub) { + _node->removeSubscriber(*_sub); + delete _sub; + } + if (_pub) { + _node->removePublisher(*_pub); + delete _pub; + } + delete(_node); } }; @@ -172,33 +173,40 @@ void UmundoInvoker::invoke(const InvokeRequest& req) { if (req.params.find("domain") != req.params.end()) { domain = req.params.find("domain")->second.atom; } - _node = getNode(_interpreter, domain); + _node = new umundo::Node(); + umundo::MDNSDiscoveryOptions discOpts; + _discovery = new umundo::Discovery(umundo::Discovery::MDNS, &discOpts); + + _discovery->add(*_node); + // add type from .proto or .desc files - if (req.params.find("type") != req.params.end()) { - std::pair typeRange = req.params.equal_range("types"); - for (InvokeRequest::params_t::const_iterator it = typeRange.first; it != typeRange.second; it++) { - URL typeURI(it->second.atom); - if (typeURI.toAbsolute(_interpreter->getBaseURI())) { - std::string filename = typeURI.asLocalFile(".proto"); - umundo::PBSerializer::addProto(filename); - } else { - LOG(ERROR) << "umundo invoker has relative type src but nor baseURI set with interpreter."; - } + std::list type; + Event::getParam(req.params, "type", type); + std::list::const_iterator typeIter = type.begin(); + while(typeIter != type.end()) { + URL typeURI(*typeIter); + if (typeURI.toAbsolute(_interpreter->getBaseURI())) { + std::string filename = typeURI.asLocalFile(".proto"); + umundo::PBSerializer::addProto(filename); + } else { + LOG(ERROR) << "umundo invoker has relative type src but nor baseURI set with interpreter."; } + typeIter++; } - + // add directory with .proto or .desc files - if (req.params.find("types") != req.params.end()) { - std::pair typeRange = req.params.equal_range("types"); - for (InvokeRequest::params_t::const_iterator it = typeRange.first; it != typeRange.second; it++) { - URL typeURI(it->second.atom); - if (typeURI.toAbsolute(_interpreter->getBaseURI()) && typeURI.scheme().compare("file") == 0) { - umundo::PBSerializer::addProto(typeURI.path()); - } else { - LOG(ERROR) << "invoke element has relative src URI with no baseURI set."; - } + std::list types; + Event::getParam(req.params, "type", types); + std::list::const_iterator typesIter = types.begin(); + while(typesIter != types.end()) { + URL typeURI(*typesIter); + if (typeURI.toAbsolute(_interpreter->getBaseURI())) { + umundo::PBSerializer::addProto(typeURI.path()); + } else { + LOG(ERROR) << "invoke element has relative src URI with no baseURI set."; } + typesIter++; } if (!_isService) { @@ -220,23 +228,21 @@ void UmundoInvoker::invoke(const InvokeRequest& req) { } } -void UmundoInvoker::welcome(umundo::TypedPublisher pub, const std::string& nodeId, const std::string& subId) { +void UmundoInvoker::welcome(umundo::TypedPublisher atPub, const umundo::SubscriberStub& sub) { Event event; event.name = "umundo.sub.added"; - event.data.compound["nodeId"] = Data(nodeId, Data::VERBATIM); - event.data.compound["subId"] = Data(subId, Data::VERBATIM); - event.data.compound["channel"] = Data(pub.getChannelName(), Data::VERBATIM); - event.data.compound["totalSubs"] = Data(toStr(pub.waitForSubscribers(0)), Data::VERBATIM); + event.data.compound["subId"] = Data(sub.getUUID(), Data::VERBATIM); + event.data.compound["channel"] = Data(atPub.getChannelName(), Data::VERBATIM); + event.data.compound["totalSubs"] = Data(toStr(atPub.waitForSubscribers(0)), Data::VERBATIM); returnEvent(event); } -void UmundoInvoker::farewell(umundo::TypedPublisher pub, const std::string& nodeId, const std::string& subId) { +void UmundoInvoker::farewell(umundo::TypedPublisher fromPub, const umundo::SubscriberStub& sub) { Event event; event.name = "umundo.sub.removed"; - event.data.compound["nodeId"] = Data(nodeId, Data::VERBATIM); - event.data.compound["subId"] = Data(subId, Data::VERBATIM); - event.data.compound["channel"] = Data(pub.getChannelName(), Data::VERBATIM); - event.data.compound["totalSubs"] = Data(toStr(pub.waitForSubscribers(0)), Data::VERBATIM); + event.data.compound["subId"] = Data(sub.getUUID(), Data::VERBATIM); + event.data.compound["channel"] = Data(fromPub.getChannelName(), Data::VERBATIM); + event.data.compound["totalSubs"] = Data(toStr(fromPub.waitForSubscribers(0)), Data::VERBATIM); returnEvent(event); } @@ -253,9 +259,6 @@ void UmundoInvoker::receive(void* object, umundo::Message* msg) { event.origintype = "umundo"; event.eventType = Event::EXTERNAL; -// if (msg->getMeta().find("um.s11n.type") != msg->getMeta().end()) -// event.compound["class"] = msg->getMeta("um.s11n.type"); - if (object != NULL) { if (msg->getMeta().find("um.s11n.type") != msg->getMeta().end() && boost::equals(msg->getMeta().find("um.s11n.type")->second, "JSON")) { @@ -276,6 +279,10 @@ void UmundoInvoker::receive(void* object, umundo::Message* msg) { metaIter++; } + if (msg->size() > 0) { + event.data.compound["protobuf"] = Data(msg->data(), msg->size(), "application/x-protobuf"); + } + returnEvent(event); } @@ -330,23 +337,6 @@ void UmundoInvoker::removed(umundo::ServiceDescription desc) { void UmundoInvoker::changed(umundo::ServiceDescription desc) { } -std::multimap > > UmundoInvoker::_nodes; -boost::shared_ptr UmundoInvoker::getNode(InterpreterImpl* interpreter, const std::string& domain) { - std::pair<_nodes_t::iterator, _nodes_t::iterator> range = _nodes.equal_range(interpreter->getName()); - for (_nodes_t::iterator it = range.first; it != range.second; it++) { - if (it->second.first.compare(domain) == 0) { - boost::shared_ptr node = it->second.second.lock(); - if (node) - return node; - } - } - // create a new node - boost::shared_ptr node = boost::shared_ptr(new umundo::Node(domain)); - std::pair > > pair = std::make_pair(interpreter->getName(), std::make_pair(domain, node)); - _nodes.insert(pair); - return node; -} - bool UmundoInvoker::jsonbufToData(Data& data, const JSONProto& json) { if (json.compound_size() > 0) { if (json.compound(0).key().size() > 0) { @@ -418,7 +408,15 @@ bool UmundoInvoker::protobufToData(Data& data, const google::protobuf::Message& } break; case google::protobuf::FieldDescriptor::TYPE_ENUM: - LOG(ERROR) << "TYPE_ENUM is unimplemented" << std::endl; + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + const google::protobuf::EnumValueDescriptor* enumDesc = reflect->GetRepeatedEnum(msg, fieldDesc, j); + data.compound[key].array.push_back(Data(toStr(enumDesc->name()), Data::VERBATIM)); + } + } else { + const google::protobuf::EnumValueDescriptor* enumDesc = reflect->GetEnum(msg, fieldDesc); + data.compound[key] = Data(enumDesc->name(), Data::VERBATIM); + } break; case google::protobuf::FieldDescriptor::TYPE_FIXED32: case google::protobuf::FieldDescriptor::TYPE_UINT32: diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h index 4b28bfe..9c64886 100644 --- a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h +++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h @@ -62,8 +62,8 @@ public: virtual void removed(umundo::ServiceDescription); virtual void changed(umundo::ServiceDescription); - virtual void welcome(umundo::TypedPublisher, const std::string& nodeId, const std::string& subId); - virtual void farewell(umundo::TypedPublisher, const std::string& nodeId, const std::string& subId); + virtual void welcome(umundo::TypedPublisher atPub, const umundo::SubscriberStub& sub); + virtual void farewell(umundo::TypedPublisher fromPub, const umundo::SubscriberStub& sub); protected: bool _isService; @@ -74,17 +74,14 @@ protected: bool jsonbufToData(Data& data, const JSONProto& json); bool protobufToData(Data& data, const google::protobuf::Message& msg); - boost::shared_ptr _node; + umundo::Node* _node; + umundo::Discovery* _discovery; umundo::TypedPublisher* _pub; umundo::TypedSubscriber* _sub; umundo::ServiceFilter* _svcFilter; umundo::ServiceManager* _svcMgr; std::map _svcs; - - static std::multimap > > _nodes; - typedef std::multimap > > _nodes_t; - static boost::shared_ptr getNode(InterpreterImpl* interpreter, const std::string& domain); }; #ifdef BUILD_AS_PLUGINS diff --git a/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp index 5ae76a9..8c3f1da 100644 --- a/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp @@ -81,8 +81,8 @@ boost::shared_ptr SCXMLIOProcessor::create(InterpreterImpl* int Data SCXMLIOProcessor::getDataModelVariables() { Data data; - assert(_url.length() > 0); - data.compound["location"] = Data(_url, Data::VERBATIM); + if(_url.length() > 0); + data.compound["location"] = Data(_url, Data::VERBATIM); return data; } diff --git a/src/uscxml/server/InterpreterServlet.cpp b/src/uscxml/server/InterpreterServlet.cpp index 01c8f07..a62a6eb 100644 --- a/src/uscxml/server/InterpreterServlet.cpp +++ b/src/uscxml/server/InterpreterServlet.cpp @@ -76,8 +76,8 @@ bool InterpreterHTTPServlet::httpRecvRequest(const HTTPServer::Request& req) { Data InterpreterHTTPServlet::getDataModelVariables() { Data data; - assert(_url.length() > 0); - data.compound["location"] = Data(_url, Data::VERBATIM); + if(_url.length() > 0) + data.compound["location"] = Data(_url, Data::VERBATIM); return data; } @@ -138,8 +138,8 @@ bool InterpreterWebSocketServlet::wsRecvRequest(struct evws_connection *conn, co Data InterpreterWebSocketServlet::getDataModelVariables() { Data data; - assert(_url.length() > 0); - data.compound["location"] = Data(_url, Data::VERBATIM); + if(_url.length() > 0); + data.compound["location"] = Data(_url, Data::VERBATIM); return data; } diff --git a/test/samples/uscxml/test-umundo-s11n-chat.scxml b/test/samples/uscxml/test-umundo-s11n-chat.scxml new file mode 100644 index 0000000..df645a1 --- /dev/null +++ b/test/samples/uscxml/test-umundo-s11n-chat.scxml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file -- cgit v0.12