summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-01-17 20:35:34 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-01-17 20:35:34 (GMT)
commit3d790497c67b07149f8563dbae39856aa961e74d (patch)
tree8d3922848f68f2e0b2449019b6fe6ca74051ec95
parent134f488db5d2c230fb13349cab18b350ed2c98a3 (diff)
downloaduscxml-3d790497c67b07149f8563dbae39856aa961e74d.zip
uscxml-3d790497c67b07149f8563dbae39856aa961e74d.tar.gz
uscxml-3d790497c67b07149f8563dbae39856aa961e74d.tar.bz2
Polished umundo invoker, prolog datamodel and several bugfixes
-rw-r--r--contrib/cmake/FindUMUNDO.cmake6
-rw-r--r--docs/BUILDING.md3
-rw-r--r--src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp525
-rw-r--r--src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp120
-rw-r--r--src/uscxml/plugins/invoker/umundo/UmundoInvoker.h11
-rw-r--r--src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp4
-rw-r--r--src/uscxml/server/InterpreterServlet.cpp8
-rw-r--r--test/samples/uscxml/test-umundo-s11n-chat.scxml13
8 files changed, 366 insertions, 324 deletions
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 <Pluma/Connector.hpp>
#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<DataModelImpl> SWIDataModel::create(InterpreterImpl* interpreter) {
- boost::shared_ptr<SWIDataModel> dm = boost::shared_ptr<SWIDataModel>(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<DataModelImpl>();
- }
+ try {
+ boost::shared_ptr<SWIDataModel> dm = boost::shared_ptr<SWIDataModel>(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<DataModelImpl>();
+ }
- 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<std::string, IOProcessor>::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<std::string, IOProcessor>::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<std::string> 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<std::string> 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<std::string, PlTerm> vars = resolveAtoms(compound, orig);
- std::map<std::string, PlTerm>::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<std::string, PlTerm> vars = resolveAtoms(compound, orig);
+ std::map<std::string, PlTerm>::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<std::string>& 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<std::string>& 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<std::string, PlTerm> vars = resolveAtoms(compound, orig);
- if (vars.size() == 1) {
- ss << (char *)vars.begin()->second;
- } else {
- std::map<std::string, PlTerm>::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<std::string, PlTerm> vars = resolveAtoms(compound, orig);
+ if (vars.size() == 1) {
+ ss << (char *)vars.begin()->second;
+ } else {
+ std::map<std::string, PlTerm>::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<std::string, PlTerm> SWIDataModel::resolveAtoms(PlTerm& term, PlTerm& orig) {
SET_PL_CONTEXT
- std::map<std::string, PlTerm> 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<std::string, PlTerm> result = resolveAtoms(newTerm, newOrig);
- atoms.insert(result.begin(), result.end());
+ try {
+ std::map<std::string, PlTerm> 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<std::string, PlTerm> result = resolveAtoms(newTerm, newOrig);
+ atoms.insert(result.begin(), result.end());
+ }
+ break;
+ }
+ return atoms;
+ } RETHROW_PLEX_AS_EVENT
}
void SWIDataModel::assign(const Element<std::string>& assignElem,
const Node<std::string>& 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<std::string> 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<std::string> 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<InvokeRequest::params_t::const_iterator, InvokeRequest::params_t::const_iterator> 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<std::string> type;
+ Event::getParam(req.params, "type", type);
+ std::list<std::string>::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<InvokeRequest::params_t::const_iterator, InvokeRequest::params_t::const_iterator> 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<std::string> types;
+ Event::getParam(req.params, "type", types);
+ std::list<std::string>::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<std::string, std::pair<std::string, boost::weak_ptr<umundo::Node> > > UmundoInvoker::_nodes;
-boost::shared_ptr<umundo::Node> 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<umundo::Node> node = it->second.second.lock();
- if (node)
- return node;
- }
- }
- // create a new node
- boost::shared_ptr<umundo::Node> node = boost::shared_ptr<umundo::Node>(new umundo::Node(domain));
- std::pair<std::string, std::pair<std::string, boost::weak_ptr<umundo::Node> > > 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<umundo::Node> _node;
+ umundo::Node* _node;
+ umundo::Discovery* _discovery;
umundo::TypedPublisher* _pub;
umundo::TypedSubscriber* _sub;
umundo::ServiceFilter* _svcFilter;
umundo::ServiceManager* _svcMgr;
std::map<umundo::ServiceDescription, umundo::ServiceStub*> _svcs;
-
- static std::multimap<std::string, std::pair<std::string, boost::weak_ptr<umundo::Node> > > _nodes;
- typedef std::multimap<std::string, std::pair<std::string, boost::weak_ptr<umundo::Node> > > _nodes_t;
- static boost::shared_ptr<umundo::Node> 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<IOProcessorImpl> 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 @@
+<scxml datamodel="prolog">
+ <state id="start">
+ <invoke type="umundo" id="umundo">
+ <param name="type" expr="'/Users/sradomski/Documents/TK/Code/umundo/examples/cpp/s11n/chat/proto/ChatS11N.proto'" />
+ <param name="channel" expr="'s11nChat'" />
+ <finalize><log label="index" expr="event(X)" /></finalize>
+ </invoke>
+ <onentry>
+ <log expr="'Entering start'" />
+ <!-- send target="#_scxml.umundo" delay="0s" event="send" / -->
+ </onentry>
+ </state>
+</scxml> \ No newline at end of file