From 71a3ca4fd78d7a9cca844e81f29f48b9c36bd4c7 Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Fri, 8 Feb 2013 13:26:42 +0100 Subject: Fixed history --- CMakeLists.txt | 21 ++ apps/mmi-browser.cpp | 10 +- apps/samples/vrml-server.scxml | 46 ++++ contrib/cmake/FindSqlite3.cmake | 21 ++ src/uscxml/Factory.cpp | 7 +- src/uscxml/Interpreter.cpp | 244 ++++++++++++++++----- src/uscxml/Interpreter.h | 11 + src/uscxml/Message.cpp | 121 +++++++++- src/uscxml/Message.h | 14 +- src/uscxml/URL.cpp | 2 +- .../datamodel/ecmascript/v8/V8DataModel.cpp | 8 +- .../graphics/openscenegraph/OSGConverter.cpp | 48 ++++ .../invoker/graphics/openscenegraph/OSGConverter.h | 42 ++++ .../plugins/invoker/heartbeat/HeartbeatInvoker.cpp | 1 + .../plugins/invoker/sqlite3/Sqlite3Invoker.cpp | 44 ++++ .../plugins/invoker/sqlite3/Sqlite3Invoker.h | 40 ++++ .../basichttp/libevent/EventIOProcessor.cpp | 34 +-- .../basichttp/libevent/EventIOProcessor.h | 12 +- test/run-scxml-test-framework.sh | 18 +- test/samples/uscxml/test-communication.scxml | 10 +- test/samples/uscxml/test-umundo-pingpong.scxml | 21 ++ .../test/history/history0.json | 6 +- test/src/scxml-test-framework-client.cpp | 48 +++- 23 files changed, 709 insertions(+), 120 deletions(-) create mode 100644 apps/samples/vrml-server.scxml create mode 100644 src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp create mode 100644 src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h create mode 100644 src/uscxml/plugins/invoker/sqlite3/Sqlite3Invoker.cpp create mode 100644 src/uscxml/plugins/invoker/sqlite3/Sqlite3Invoker.h create mode 100644 test/samples/uscxml/test-umundo-pingpong.scxml diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e92bd9..f9d8864 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -472,6 +472,27 @@ else() endif() +# SQLite3 SQL Invoker + +find_package(Sqlite3) +if (SQLITE3_FOUND) + file(GLOB_RECURSE SQLITE3_INVOKER + src/uscxml/plugins/invoker/sqlite3/*.cpp + src/uscxml/plugins/invoker/sqlite3/*.h + ) + source_group("Invoker" FILES ${SQLITE3_INVOKER}) + if (BUILD_AS_PLUGINS) + add_library( + invoker_sqlite3 SHARED + ${SQLITE3_INVOKER}) + target_link_libraries(invoker_sqlite3 uscxml) + set_target_properties(invoker_sqlite3 PROPERTIES FOLDER "Plugin Invoker") + else() + list (APPEND USCXML_FILES ${SQLITE3_INVOKER}) + endif() +endif() + + # JavaScriptCore ecmascript datamodel if (APPLE AND IOS AND OFF) FIND_LIBRARY(JSC_LIBRARY JavaScriptCore) diff --git a/apps/mmi-browser.cpp b/apps/mmi-browser.cpp index c423871..3ebe153 100644 --- a/apps/mmi-browser.cpp +++ b/apps/mmi-browser.cpp @@ -27,6 +27,7 @@ int main(int argc, char** argv) { printUsageAndExit(); } + opterr = 0; int option; while ((option = getopt(argc, argv, "l:p:")) != -1) { switch(option) { @@ -36,6 +37,8 @@ int main(int argc, char** argv) { case 'p': uscxml::Factory::pluginPath = optarg; break; + case '?': + break; default: printUsageAndExit(); break; @@ -44,11 +47,12 @@ int main(int argc, char** argv) { // for (int i = 0; i < argc; i++) // std::cout << argv[i] << std::endl; +// std::cout << optind << std::endl; + - Factory::getInstance(); - - Interpreter* interpreter = Interpreter::fromURI(argv[argc - 1]); + Interpreter* interpreter = Interpreter::fromURI(argv[optind]); if (interpreter) { + interpreter->setCmdLineOptions(argc, argv); interpreter->start(); while(interpreter->runOnMainThread(25)); } diff --git a/apps/samples/vrml-server.scxml b/apps/samples/vrml-server.scxml new file mode 100644 index 0000000..82560ef --- /dev/null +++ b/apps/samples/vrml-server.scxml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/cmake/FindSqlite3.cmake b/contrib/cmake/FindSqlite3.cmake index e69de29..36c98b0 100644 --- a/contrib/cmake/FindSqlite3.cmake +++ b/contrib/cmake/FindSqlite3.cmake @@ -0,0 +1,21 @@ +FIND_PATH(SQLITE3_INCLUDE_DIR sqlite3.h) + +FIND_LIBRARY(SQLITE3_LIBRARY_RELEASE NAMES sqlite3) + +if (SQLITE3_LIBRARY_RELEASE) + list(APPEND SQLITE3_LIBRARY optimized ${SQLITE3_LIBRARY_RELEASE}) +endif() + +FIND_LIBRARY(SQLITE3_LIBRARY_DEBUG NAMES sqlite3_d) + +if (SQLITE3_LIBRARY_DEBUG) + list(APPEND SQLITE3_LIBRARY debug ${SQLITE3_LIBRARY_DEBUG}) +else() + if(NOT WIN32) + list(APPEND SQLITE3_LIBRARY debug ${SQLITE3_LIBRARY_RELEASE}) + endif() +endif() + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Sqlite3 DEFAULT_MSG SQLITE3_LIBRARY SQLITE3_INCLUDE_DIR) +MARK_AS_ADVANCED(SQLITE3_LIBRARY SQLITE3_INCLUDE_DIR) diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp index 623dbaf..4481257 100644 --- a/src/uscxml/Factory.cpp +++ b/src/uscxml/Factory.cpp @@ -20,6 +20,7 @@ # ifdef OPENSCENEGRAPH_FOUND # include "uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.h" +# include "uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h" # endif # ifdef MILES_FOUND @@ -95,6 +96,10 @@ Factory::Factory() { OSGInvoker* invoker = new OSGInvoker(); registerInvoker(invoker); } + { + OSGConverter* invoker = new OSGConverter(); + registerInvoker(invoker); + } #endif #ifdef V8_FOUND @@ -252,7 +257,7 @@ void IOProcessorImpl::returnEvent(Event& event) { _interpreter->receive(event); } - + Factory* Factory::_instance = NULL; std::string Factory::pluginPath; } \ No newline at end of file diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 04604fd..5b947a7 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -117,7 +117,9 @@ bool Interpreter::toAbsoluteURI(URL& uri) { } void Interpreter::startPrefixMapping(const std::string& prefix, const std::string& uri) { +#if 0 std::cout << "starting prefix mapping " << prefix << ": " << uri << std::endl; +#endif if (boost::iequals(uri, "http://www.w3.org/2005/07/scxml")) { _nsURL = uri; if (prefix.size() == 0) { @@ -253,6 +255,9 @@ void Interpreter::interpret() { LOG(ERROR) << "No datamodel for " << datamodelName << " registered"; } + if (_dataModel) + _dataModel.assign("_x.args", _cmdLineOptions); + setupIOProcessors(); _running = true; @@ -269,7 +274,6 @@ void Interpreter::interpret() { } else if(_dataModel) { // initialize current data elements NodeSet topDataElems = filterChildElements(_xmlNSPrefix + "data", filterChildElements(_xmlNSPrefix + "datamodel", _scxml)); - // NodeSet topDataElems = _xpath.evaluate("/" + _xpathPrefix + "scxml/" + _xpathPrefix + "datamodel/" + _xpathPrefix + "data", _document).asNodeSet(); for (unsigned int i = 0; i < topDataElems.size(); i++) { initializeData(topDataElems[i]); } @@ -278,7 +282,6 @@ void Interpreter::interpret() { // executeGlobalScriptElements NodeSet globalScriptElems = _xpath.evaluate("/" + _xpathPrefix + "scxml/" + _xpathPrefix + "script", _document).asNodeSet(); for (unsigned int i = 0; i < globalScriptElems.size(); i++) { - // std::cout << globalScriptElems[i].getFirstChild().getNodeValue() << std::endl; if (_dataModel) executeContent(globalScriptElems[i]); } @@ -344,7 +347,6 @@ void Interpreter::initializeData(const Arabica::DOM::Node& data) { break; } } -// std::cout << value << std::endl; } } catch (Event e) { @@ -429,7 +431,7 @@ void Interpreter::mainEventLoop() { } std::cout << std::endl; #endif - std::set::iterator monIter = _monitors.begin(); + monIter = _monitors.begin(); while(monIter != _monitors.end()) { (*monIter)->beforeMicroStep(this); monIter++; @@ -450,12 +452,18 @@ void Interpreter::mainEventLoop() { enabledTransitions = selectTransitions(internalEvent.name); } } - if (!enabledTransitions.empty()) + if (!enabledTransitions.empty()) { + monIter = _monitors.begin(); + while(monIter != _monitors.end()) { + (*monIter)->beforeTakingTransitions(this, enabledTransitions); + monIter++; + } microstep(enabledTransitions); + } } for (unsigned int i = 0; i < _statesToInvoke.size(); i++) { - NodeSet invokes = _xpath.evaluate("" + _xpathPrefix + "invoke", _statesToInvoke[i]).asNodeSet(); + NodeSet invokes = filterChildElements(_xmlNSPrefix + "invoke", _statesToInvoke[i]); for (unsigned int j = 0; j < invokes.size(); j++) { invoke(invokes[j]); } @@ -491,24 +499,27 @@ void Interpreter::mainEventLoop() { LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl; } for (unsigned int i = 0; i < _configuration.size(); i++) { - NodeSet invokes = _xpath.evaluate("" + _xpathPrefix + "invoke", _configuration[i]).asNodeSet(); + NodeSet invokes = filterChildElements(_xmlNSPrefix + "invoke", _configuration[i]); for (unsigned int j = 0; j < invokes.size(); j++) { Arabica::DOM::Element invokeElem = (Arabica::DOM::Element)invokes[j]; - std::string invokeId = invokeElem.getAttribute("id"); + std::string invokeId; + if (HAS_ATTR(invokeElem, "id")) + invokeId = ATTR(invokeElem, "id"); + if (HAS_ATTR(invokeElem, "idlocation") && _dataModel) + invokeId = _dataModel.evalAsString(ATTR(invokeElem, "idlocation")); + std::string autoForward = invokeElem.getAttribute("autoforward"); if (boost::iequals(invokeId, externalEvent.invokeid)) { - Arabica::XPath::NodeSet finalizes = _xpath.evaluate("" + _xpathPrefix + "finalize", invokeElem).asNodeSet(); + Arabica::XPath::NodeSet finalizes = filterChildElements(_xmlNSPrefix + "finalize", invokeElem); for (int k = 0; k < finalizes.size(); k++) { Arabica::DOM::Element finalizeElem = Arabica::DOM::Element(finalizes[k]); executeContent(finalizeElem); } - } - if (autoForward.length() > 0) { - // @TODO -// send(invokeId, externalEvent); + if (boost::iequals(autoForward, "true")) { + _invokers[invokeId].send(externalEvent); } } } @@ -540,7 +551,7 @@ void Interpreter::internalDoneSend(const Arabica::DOM::Node& state) Arabica::DOM::Element parent = (Arabica::DOM::Element)stateElem.getParentNode(); Event event; - Arabica::XPath::NodeSet doneDatas = _xpath.evaluate("" + _xpathPrefix + "donedata", stateElem).asNodeSet(); + Arabica::XPath::NodeSet doneDatas = filterChildElements(_xmlNSPrefix + "donedata", stateElem); if (doneDatas.size() > 0) { // only process first donedata element Arabica::DOM::Node doneData = doneDatas[0]; @@ -668,10 +679,10 @@ void Interpreter::send(const Arabica::DOM::Node& element) { } // params - NodeSet params = _xpath.evaluate("" + _xpathPrefix + "param", element).asNodeSet(); + NodeSet params = filterChildElements(_xmlNSPrefix + "param", element); for (int i = 0; i < params.size(); i++) { if (!HAS_ATTR(params[i], "name")) { - LOG(ERROR) << "param element is missing name attribut"; + LOG(ERROR) << "param element is missing name attribute"; continue; } std::string paramValue; @@ -683,11 +694,13 @@ void Interpreter::send(const Arabica::DOM::Node& element) { LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; continue; } - sendReq.params.insert(std::make_pair(ATTR(params[i], "name"), paramValue)); + std::string paramKey = ATTR(params[i], "name"); + boost::algorithm::to_lower(paramKey); + sendReq.params.insert(std::make_pair(paramKey, paramValue)); } // content - NodeSet contents = _xpath.evaluate("" + _xpathPrefix + "content", element).asNodeSet(); + NodeSet contents = filterChildElements(_xmlNSPrefix + "content", element); if (contents.size() > 1) LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; if (contents.size() > 0) { @@ -792,7 +805,10 @@ void Interpreter::invoke(const Arabica::DOM::Node& element) { // namelist if (HAS_ATTR(element, "namelist")) { - invokeReq.namelist = ATTR(element, "namelist"); + std::vector names = tokenizeIdRefs(ATTR(element, "namelist")); + for (int i = 0; i < names.size(); i++) { + invokeReq.namelist[names[i]] = _dataModel.evalAsString(names[i]); + } } // autoforward @@ -805,7 +821,7 @@ void Interpreter::invoke(const Arabica::DOM::Node& element) { } // params - NodeSet params = _xpath.evaluate("" + _xpathPrefix + "param", element).asNodeSet(); + NodeSet params = filterChildElements(_xmlNSPrefix + "param", element); for (int i = 0; i < params.size(); i++) { if (!HAS_ATTR(params[i], "name")) { LOG(ERROR) << "param element is missing name attribut"; @@ -824,16 +840,17 @@ void Interpreter::invoke(const Arabica::DOM::Node& element) { LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; continue; } - invokeReq.params.insert(std::make_pair(ATTR(params[i], "name"), paramValue)); + std::string paramKey = ATTR(params[i], "name"); + boost::algorithm::to_lower(paramKey); + invokeReq.params.insert(std::make_pair(paramKey, paramValue)); } // content - NodeSet contents = _xpath.evaluate("" + _xpathPrefix + "content", element).asNodeSet(); + NodeSet contents = filterChildElements(_xmlNSPrefix + "content", element); if (contents.size() > 1) LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; if (contents.size() > 0) { - //std::cout << contents[0] << std::endl; invokeReq.content = contents[0].getNodeValue(); } @@ -846,6 +863,9 @@ void Interpreter::invoke(const Arabica::DOM::Node& element) { _invokers[invokeReq.invokeid] = invoker; LOG(INFO) << "Added invoker " << invokeReq.type << " at " << invokeReq.invokeid; invoker.invoke(invokeReq); + if (_dataModel) { + _dataModel.assign("_invokers['" + invokeReq.invokeid + "']", invoker.getDataModelVariables()); + } } else { LOG(ERROR) << "No invoker known for type " << invokeReq.type; } @@ -866,6 +886,14 @@ void Interpreter::cancelInvoke(const Arabica::DOM::Node& element) { } if (_invokers.find(invokeId) != _invokers.end()) { LOG(INFO) << "Removed invoker at " << invokeId; + if (_dataModel) { + try { + _dataModel.assign("_invokers['" + invokeId + "']", "''"); + } catch (Event e) { + LOG(ERROR) << "Syntax when removing invoker:" << std::endl << e << std::endl; + } + + } _invokers.erase(invokeId); } else { LOG(ERROR) << "Cannot cancel invoke for id " << invokeId << ": no soch invokation"; @@ -886,7 +914,7 @@ Arabica::XPath::NodeSet Interpreter::selectTransitions(const std::s NodeSet ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node()); ancestors.push_back(atomicStates[i]); for (unsigned int j = 0; j < ancestors.size(); j++) { - NodeSet transitions = _xpath.evaluate("" + _xpathPrefix + "transition", ancestors[j]).asNodeSet(); + NodeSet transitions = filterChildElements(_xmlNSPrefix + "transition", ancestors[j]); for (unsigned int k = 0; k < transitions.size(); k++) { if (((Arabica::DOM::Element)transitions[k]).hasAttribute("event") && nameMatch(((Arabica::DOM::Element)transitions[k]).getAttribute("event"), event) && @@ -958,7 +986,7 @@ Arabica::XPath::NodeSet Interpreter::selectEventlessTransitions() { NodeSet ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node()); ancestors.push_back(atomicStates[i]); for (unsigned int j = 0; j < ancestors.size(); j++) { - NodeSet transitions = filterChildElements("transition", ancestors[j]); + NodeSet transitions = filterChildElements(_xmlNSPrefix + "transition", ancestors[j]); for (unsigned int k = 0; k < transitions.size(); k++) { if (!((Arabica::DOM::Element)transitions[k]).hasAttribute("event") && hasConditionMatch(transitions[k])) { enabledTransitions.push_back(transitions[k]); @@ -967,7 +995,7 @@ Arabica::XPath::NodeSet Interpreter::selectEventlessTransitions() { } #if 0 - NodeSet transitions = _xpath.evaluate("" + _xpathPrefix + "transition", ancestors[j]).asNodeSet(); + NodeSet transitions = filterChildElements(_xmlNSPrefix + "transition", ancestors[j]); for (unsigned int k = 0; k < transitions.size(); k++) { if (!((Arabica::DOM::Element)transitions[k]).hasAttribute("event") && hasConditionMatch(transitions[k])) { enabledTransitions.push_back(transitions[k]); @@ -1047,11 +1075,11 @@ void Interpreter::exitInterpreter() { statesToExit.reverse(); for (int i = 0; i < statesToExit.size(); i++) { - Arabica::XPath::NodeSet onExitElems = _xpath.evaluate("" + _xpathPrefix + "onexit", statesToExit[i]).asNodeSet(); + Arabica::XPath::NodeSet onExitElems = filterChildElements(_xmlNSPrefix + "onexit", statesToExit[i]); for (int j = 0; j < onExitElems.size(); j++) { executeContent(onExitElems[j]); } - Arabica::XPath::NodeSet invokeElems = _xpath.evaluate("" + _xpathPrefix + "invoke", statesToExit[i]).asNodeSet(); + Arabica::XPath::NodeSet invokeElems = filterChildElements(_xmlNSPrefix + "invoke", statesToExit[i]); for (int j = 0; j < invokeElems.size(); j++) { cancelInvoke(invokeElems[j]); } @@ -1252,6 +1280,8 @@ void Interpreter::returnDoneEvent(const Arabica::DOM::Node& state) void Interpreter::exitStates(const Arabica::XPath::NodeSet& enabledTransitions) { NodeSet statesToExit; + std::set::iterator monIter; + for (int i = 0; i < enabledTransitions.size(); i++) { Arabica::DOM::Element transition = ((Arabica::DOM::Element)enabledTransitions[i]); if (!isTargetless(transition)) { @@ -1298,8 +1328,14 @@ void Interpreter::exitStates(const Arabica::XPath::NodeSet& enabled statesToExit.to_document_order(); statesToExit.reverse(); + monIter = _monitors.begin(); + while(monIter != _monitors.end()) { + (*monIter)->beforeExitingStates(this, statesToExit); + monIter++; + } + for (int i = 0; i < statesToExit.size(); i++) { - NodeSet histories = filterChildElements("history", statesToExit[i]); + NodeSet histories = filterChildElements(_xmlNSPrefix + "history", statesToExit[i]); for (int j = 0; j < histories.size(); j++) { Arabica::DOM::Element historyElem = (Arabica::DOM::Element)histories[j]; std::string historyType = (historyElem.hasAttribute("type") ? historyElem.getAttribute("type") : "shallow"); @@ -1318,24 +1354,18 @@ void Interpreter::exitStates(const Arabica::XPath::NodeSet& enabled } for (int i = 0; i < statesToExit.size(); i++) { - NodeSet onExits = filterChildElements("onExit", statesToExit[i]); + NodeSet onExits = filterChildElements(_xmlNSPrefix + "onExit", statesToExit[i]); for (int j = 0; j < onExits.size(); j++) { Arabica::DOM::Element onExitElem = (Arabica::DOM::Element)onExits[j]; executeContent(onExitElem); } - NodeSet invokes = filterChildElements("invoke", statesToExit[i]); + NodeSet invokes = filterChildElements(_xmlNSPrefix + "invoke", statesToExit[i]); for (int j = 0; j < invokes.size(); j++) { Arabica::DOM::Element invokeElem = (Arabica::DOM::Element)invokes[j]; cancelInvoke(invokeElem); } } -// std::cout << "States to Exit: "; -// for (int i = 0; i < statesToExit.size(); i++) { -// std::cout << ((Arabica::DOM::Element)statesToExit[i]).getAttribute("id") << ", "; -// } -// std::cout << std::endl; - // remove statesToExit from _configuration tmp.clear(); for (int i = 0; i < _configuration.size(); i++) { @@ -1346,20 +1376,38 @@ void Interpreter::exitStates(const Arabica::XPath::NodeSet& enabled _configuration = NodeSet(); _configuration.insert(_configuration.end(), tmp.begin(), tmp.end()); + monIter = _monitors.begin(); + while(monIter != _monitors.end()) { + (*monIter)->afterExitingStates(this); + monIter++; + } } void Interpreter::enterStates(const Arabica::XPath::NodeSet& enabledTransitions) { NodeSet statesToEnter; NodeSet statesForDefaultEntry; + std::set::iterator monIter; for (int i = 0; i < enabledTransitions.size(); i++) { Arabica::DOM::Element transition = ((Arabica::DOM::Element)enabledTransitions[i]); if (!isTargetless(transition)) { std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external"); NodeSet tStates = getTargetStates(transition); + +#if 0 + std::cout << "Target States: "; + for (int i = 0; i < tStates.size(); i++) { + std::cout << ATTR(tStates[i], "id") << ", "; + } + std::cout << std::endl; +#endif + Arabica::DOM::Node ancestor; Arabica::DOM::Node source = getSourceState(transition); +#if 0 + std::cout << "Source States: " << ATTR(source, "id") << std::endl; +#endif assert(source); bool allDescendants = true; @@ -1381,13 +1429,26 @@ void Interpreter::enterStates(const Arabica::XPath::NodeSet& enable ancestor = findLCCA(tmpStates); } +#if 0 + std::cout << "Ancestor: " << ATTR(ancestor, "id") << std::endl; +#endif + for (int j = 0; j < tStates.size(); j++) { addStatesToEnter(tStates[j], statesToEnter, statesForDefaultEntry); } for (int j = 0; j < tStates.size(); j++) { NodeSet ancestors = getProperAncestors(tStates[j], ancestor); - for (int k = 0; k < ancestors.size(); k++) { + +#if 0 + std::cout << "Proper Ancestors of " << ATTR(tStates[j], "id") << " and " << ATTR(ancestor, "id") << ": "; + for (int i = 0; i < ancestors.size(); i++) { + std::cout << ATTR(ancestors[i], "id") << ", "; + } + std::cout << std::endl; +#endif + + for (int k = 0; k < ancestors.size(); k++) { statesToEnter.push_back(ancestors[k]); if(isParallel(ancestors[k])) { NodeSet childs = getChildStates(ancestors[k]); @@ -1409,22 +1470,21 @@ void Interpreter::enterStates(const Arabica::XPath::NodeSet& enable } } statesToEnter.to_document_order(); -#if 0 - std::cout << "Entering states: "; - for (int i = 0; i < statesToEnter.size(); i++) { - std::cout << ATTR(statesToEnter[i], "id") << ", "; - } - std::cout << std::endl; -#endif + + monIter = _monitors.begin(); + while(monIter != _monitors.end()) { + (*monIter)->beforeEnteringStates(this, statesToEnter); + monIter++; + } for (int i = 0; i < statesToEnter.size(); i++) { Arabica::DOM::Element stateElem = (Arabica::DOM::Element)statesToEnter[i]; _configuration.push_back(stateElem); _statesToInvoke.push_back(stateElem); if (_binding == LATE && stateElem.getAttribute("isFirstEntry").size() > 0) { - NodeSet dataModelElems = filterChildElements("datamodel", stateElem); + NodeSet dataModelElems = filterChildElements(_xmlNSPrefix + "datamodel", stateElem); if(dataModelElems.size() > 0 && _dataModel) { - Arabica::XPath::NodeSet dataElems = filterChildElements("data", dataModelElems[0]); + Arabica::XPath::NodeSet dataElems = filterChildElements(_xmlNSPrefix + "data", dataModelElems[0]); for (int j = 0; j < dataElems.size(); j++) { initializeData(dataElems[j]); } @@ -1432,7 +1492,7 @@ void Interpreter::enterStates(const Arabica::XPath::NodeSet& enable stateElem.setAttribute("isFirstEntry", ""); } // execute onentry executable content - NodeSet onEntryElems = filterChildElements("onEntry", stateElem); + NodeSet onEntryElems = filterChildElements(_xmlNSPrefix + "onEntry", stateElem); for (int j = 0; j < onEntryElems.size(); j++) { executeContent(onEntryElems[j]); } @@ -1472,6 +1532,13 @@ void Interpreter::enterStates(const Arabica::XPath::NodeSet& enable _done = true; } } + + monIter = _monitors.begin(); + while(monIter != _monitors.end()) { + (*monIter)->afterEnteringStates(this); + monIter++; + } + } bool Interpreter::parentIsScxmlState(Arabica::DOM::Node state) { @@ -1483,7 +1550,6 @@ bool Interpreter::parentIsScxmlState(Arabica::DOM::Node state) { } bool Interpreter::isInFinalState(const Arabica::DOM::Node& state) { -// std::cout << ATTR(state, "id") << std::endl; if (isCompound(state)) { Arabica::XPath::NodeSet childs = getChildStates(state); for (int i = 0; i < childs.size(); i++) { @@ -1516,15 +1582,35 @@ void Interpreter::addStatesToEnter(const Arabica::DOM::Node& state, if (isHistory(state)) { if (_historyValue.find(stateId) != _historyValue.end()) { Arabica::XPath::NodeSet historyValue = _historyValue[stateId]; + +#if 0 + std::cout << "History States: "; + for (int i = 0; i < historyValue.size(); i++) { + std::cout << ATTR(historyValue[i], "id") << ", "; + } + std::cout << std::endl; +#endif + for (int i = 0; i < historyValue.size(); i++) { addStatesToEnter(historyValue[i], statesToEnter, statesForDefaultEntry); NodeSet ancestors = getProperAncestors(historyValue[i], state); + +#if 0 + std::cout << "Proper Ancestors: "; + for (int i = 0; i < ancestors.size(); i++) { + std::cout << ATTR(ancestors[i], "id") << ", "; + } + std::cout << std::endl; +#endif + for (int j = 0; j < ancestors.size(); j++) { + if (boost::iequals(TAGNAME(ancestors[j]), _xmlNSPrefix + "scxml")) // do not add the scxml element itself + continue; statesToEnter.push_back(ancestors[j]); } } } else { - NodeSet transitions = _xpath.evaluate("" + _xpathPrefix + "transition", state).asNodeSet(); + NodeSet transitions = filterChildElements(_xmlNSPrefix + "transition", state); for (int i = 0; i < transitions.size(); i++) { NodeSet targets = getTargetStates(transitions[i]); for (int j = 0; j < targets.size(); j++) { @@ -1567,18 +1653,22 @@ Arabica::XPath::NodeSet Interpreter::getChildStates(const Arabica:: } Arabica::DOM::Node Interpreter::findLCCA(const Arabica::XPath::NodeSet& states) { -// std::cout << "findLCCA: "; -// for (int i = 0; i < states.size(); i++) { -// std::cout << ATTR(states[i], "id") << " - " << TAGNAME(states[i]) << ", "; -// } -// std::cout << std::endl << std::flush; - +#if 0 + std::cout << "findLCCA: "; + for (int i = 0; i < states.size(); i++) { + std::cout << ATTR(states[i], "id") << " - " << TAGNAME(states[i]) << ", "; + } + std::cout << std::endl << std::flush; +#endif + Arabica::XPath::NodeSet ancestors = getProperAncestors(states[0], Arabica::DOM::Node()); ancestors.push_back(states[0]); // state[0] may already be the ancestor - bug in W3C spec? Arabica::DOM::Node ancestor; for (int i = 0; i < ancestors.size(); i++) { for (int j = 0; j < states.size(); j++) { -// std::cout << "Checking " << TAGNAME(states[j]) << " and " << TAGNAME(ancestors[i]) << std::endl; +#if 0 + std::cout << "Checking " << TAGNAME(states[j]) << " and " << TAGNAME(ancestors[i]) << std::endl; +#endif if (!isDescendant(states[j], ancestors[i]) && (states[j] != ancestors[i])) goto NEXT_ANCESTOR; } @@ -1588,7 +1678,9 @@ NEXT_ANCESTOR: ; } assert(ancestor); -// std::cout << " -> " << ATTR(ancestor, "id") << " " << ancestor.getLocalName() << std::endl; +#if 0 + std::cout << " -> " << ATTR(ancestor, "id") << " " << ancestor.getLocalName() << std::endl; +#endif return ancestor; } @@ -1613,6 +1705,13 @@ Arabica::DOM::Node Interpreter::getState(const std::string& stateId if (target.size() > 0) goto FOUND; + // now history states + target = _xpath.evaluate("//" + _xpathPrefix + "history[@id='" + stateId + "']", _document).asNodeSet(); + if (target.size() > 0) + goto FOUND; + + LOG(ERROR) << "No state with id " << stateId << " found!"; + FOUND: if (target.size() > 0) { assert(target.size() == 1); @@ -1652,7 +1751,7 @@ Arabica::DOM::Node Interpreter::getInitialState(Arabica::DOM::Node< } // initial element as child - but not the implicit generated one - NodeSet initialStates = _xpath.evaluate("" + _xpathPrefix + "initial", state).asNodeSet(); + NodeSet initialStates = filterChildElements(_xmlNSPrefix + "initial", state); if(initialStates.size() == 1 && !boost::iequals(ATTR(initialStates[0], "generated"), "true")) return initialStates[0]; @@ -1786,6 +1885,8 @@ bool Interpreter::isState(const Arabica::DOM::Node& state) { return true; if (boost::iequals("parallel", tagName)) return true; + if (boost::iequals("history", tagName)) + return true; if (boost::iequals("final", tagName)) return true; return false; @@ -1824,7 +1925,7 @@ bool Interpreter::isPseudoState(const Arabica::DOM::Node& state) { } bool Interpreter::isTransitionTarget(const Arabica::DOM::Node& elem) { - return (isState(elem) || boost::iequals(LOCALNAME(elem), "history")); + return (isState(elem) || boost::iequals(LOCALNAME(elem), "history")); // TODO: history is a state } bool Interpreter::isAtomic(const Arabica::DOM::Node& state) { @@ -1903,6 +2004,29 @@ IOProcessor Interpreter::getIOProcessor(const std::string& type) { return _ioProcessors[type]; } +void Interpreter::setCmdLineOptions(int argc, char** argv) { + char* key = NULL; + char* value = NULL; + for (int i = 0; i < argc; i++) { + if (false) { + } else if (strlen(argv[i]) > 2 && strncmp(&argv[i][0], "-", 1) == 0 && strncmp(&argv[i][1], "-", 1) == 0) { + // longopt + key = &argv[i][2]; + } else if (strlen(argv[i]) > 1 && strncmp(&argv[i][0], "-", 1) == 0 && strncmp(&argv[i][1], "-", 1) != 0) { + // shortopt + key = &argv[i][1]; + } + if (key != NULL) { + if (i + 1 < argc && strncmp(&argv[i + 1][0], "-", 1) != 0) { + value = argv[++i]; + _cmdLineOptions.compound[key] = Data(value, Data::VERBATIM); + } else { + _cmdLineOptions.compound[key] = Data("true"); + } + } + } +} + void Interpreter::dump() { if (!_document) return; diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 334b2ad..ab58ec3 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -33,6 +33,11 @@ public: virtual void beforeCompletion(Interpreter* interpreter) {} virtual void afterCompletion(Interpreter* interpreter) {} virtual void beforeMicroStep(Interpreter* interpreter) {} + virtual void beforeTakingTransitions(Interpreter* interpreter, const Arabica::XPath::NodeSet& transitions) {} + virtual void beforeEnteringStates(Interpreter* interpreter, const Arabica::XPath::NodeSet& statesToEnter) {} + virtual void afterEnteringStates(Interpreter* interpreter) {} + virtual void beforeExitingStates(Interpreter* interpreter, const Arabica::XPath::NodeSet& statesToExit) {} + virtual void afterExitingStates(Interpreter* interpreter) {} }; class NumAttr { @@ -100,6 +105,9 @@ public: } bool toAbsoluteURI(URL& uri); + void setCmdLineOptions(int argc, char** argv); + Data getCmdLineOptions() { return _cmdLineOptions; } + DataModel getDataModel() { return _dataModel; } @@ -247,12 +255,15 @@ protected: std::string _name; std::string _sessionId; + Data _cmdLineOptions; + IOProcessor getIOProcessor(const std::string& type); // IOProcessor* getIOProcessorForId(const std::string& sendId); std::map _ioProcessors; std::map > _sendIds; std::map _invokers; + std::map _autoForwardees; /// We need to remember to adapt them when the DOM is operated upon std::map > _cachedStates; diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp index a78937f..9453508 100644 --- a/src/uscxml/Message.cpp +++ b/src/uscxml/Message.cpp @@ -157,7 +157,6 @@ Arabica::DOM::Document SendRequest::toDocument() { } - scxmlMsg.setAttribute("sendid", sendid); return document; @@ -217,10 +216,7 @@ Data Data::fromJSON(const std::string& jsonString) { // there are no more tokens if (t[currTok].end == 0 || tokenStack.empty()) break; - -// std::cout << "Token Stack: [" << tokenStack.back().start << ", " << tokenStack.back().end << "]" << std::endl; -// std::cout << "Token Curr: [" << t[currTok].start << ", " << t[currTok].end << "]" << std::endl; - + // next token starts after current one => pop if (t[currTok].end > tokenStack.back().end) tokenStack.pop_back(); @@ -240,7 +236,7 @@ Data Data::fromJSON(const std::string& jsonString) { return data; } - Event Event::fromXML(const std::string& xmlString) { +Event Event::fromXML(const std::string& xmlString) { Arabica::SAX2DOM::Parser eventParser; Arabica::SAX::CatchErrorHandler errorHandler; eventParser.setErrorHandler(errorHandler); @@ -296,17 +292,116 @@ InvokeRequest InvokeRequest::fromXML(const std::string& xmlString) { } #ifndef SWIGJAVA +std::ostream& operator<< (std::ostream& os, const InvokeRequest& invokeReq) { + + std::string indent; + for (int i = 0; i < _dataIndentation; i++) { + indent += " "; + } + + os << indent << "InvokeReq" << (invokeReq.autoForward ? " with autoforward" : "") << std::endl; + + if (invokeReq.type.size() > 0) + os << indent << " type: " << invokeReq.type << std::endl; + + if (invokeReq.src.size() > 0) + os<< indent << " src: " << invokeReq.src << std::endl; + + if (invokeReq.namelist.size() > 0) { + os << indent << " namelist: " << std::endl; + InvokeRequest::namelist_t::const_iterator namelistIter = invokeReq.namelist.begin(); + while(namelistIter != invokeReq.namelist.end()) { + os << indent << " " << namelistIter->first << ": " << namelistIter->second << std::endl; + namelistIter++; + } + } + + if (invokeReq.params.size() > 0) { + os << indent << " params: " << std::endl; + SendRequest::params_t::const_iterator paramIter = invokeReq.params.begin(); + while(paramIter != invokeReq.params.end()) { + os << indent << " " << paramIter->first << ": " << paramIter->second << std::endl; + paramIter++; + } + } + + if (invokeReq.content.size() > 0) + os << indent << " content: " << invokeReq.content << std::endl; + + _dataIndentation++; + os << (Event)invokeReq; + _dataIndentation--; + return os; + +} +#endif + + +#ifndef SWIGJAVA +std::ostream& operator<< (std::ostream& os, const SendRequest& sendReq) { + + std::string indent; + for (int i = 0; i < _dataIndentation; i++) { + indent += " "; + } + + os << indent<< "SendReq" << std::endl; + + if (sendReq.target.size() > 0) + os << indent << " target: " << sendReq.target << std::endl; + + if (sendReq.type.size() > 0) + os << indent << " type: " << sendReq.type << std::endl; + + if (sendReq.delayMs > 0) + os<< indent << " delay: " << sendReq.delayMs << std::endl; + + if (sendReq.namelist.size() > 0) { + os << indent << " namelist: " << std::endl; + SendRequest::namelist_t::const_iterator namelistIter = sendReq.namelist.begin(); + while(namelistIter != sendReq.namelist.end()) { + os << indent << " " << namelistIter->first << ": " << namelistIter->second << std::endl; + namelistIter++; + } + } + + if (sendReq.params.size() > 0) { + os << indent << " params: " << std::endl; + SendRequest::params_t::const_iterator paramIter = sendReq.params.begin(); + while(paramIter != sendReq.params.end()) { + os << indent << " " << paramIter->first << ": " << paramIter->second << std::endl; + paramIter++; + } + } + + if (sendReq.content.size() > 0) + os << indent << " content: " << sendReq.content << std::endl; + + _dataIndentation++; + os << (Event)sendReq; + _dataIndentation--; + return os; + +} +#endif + +#ifndef SWIGJAVA std::ostream& operator<< (std::ostream& os, const Event& event) { - os << (event.type == Event::EXTERNAL ? "External" : "Internal") << " Event " /* << (event.dom ? "with DOM attached" : "")*/ << std::endl; + std::string indent; + for (int i = 0; i < _dataIndentation; i++) { + indent += " "; + } + + os << indent << (event.type == Event::EXTERNAL ? "External" : "Internal") << " Event " << (event.dom ? "with DOM attached" : "") << std::endl; if (event.name.size() > 0) - os << " name: " << event.name << std::endl; + os << indent << " name: " << event.name << std::endl; if (event.origin.size() > 0) - os << " origin: " << event.origin << std::endl; + os << indent << " origin: " << event.origin << std::endl; if (event.origintype.size() > 0) - os << " origintype: " << event.origintype << std::endl; + os << indent << " origintype: " << event.origintype << std::endl; _dataIndentation++; - os << " data: " << (Data)event << std::endl; + os << indent << " data: " << (Data)event << std::endl; _dataIndentation--; return os; } @@ -362,7 +457,9 @@ std::ostream& operator<< (std::ostream& os, const Data& data) { } else { os << data.atom; } - } + } else { + os << "undefined"; + } return os; } #endif diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index 68e8151..43eecdf 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -86,9 +86,11 @@ public: class InvokeRequest : public Event { public: + InvokeRequest(Event event) : Event(event) {} + InvokeRequest() {} std::string type; std::string src; - std::string namelist; + std::map namelist; typedef std::map namelist_t; bool autoForward; std::multimap params; @@ -104,10 +106,16 @@ public: return ss.str(); } +#ifndef SWIGJAVA + friend std::ostream& operator<< (std::ostream& os, const InvokeRequest& sendReq); +#endif + }; class SendRequest : public Event { public: + SendRequest() {} + SendRequest(Event event) : Event(event) {} std::string target; std::string type; uint32_t delayMs; @@ -125,6 +133,10 @@ public: // std::cout << ss.str() << std::endl; return ss.str(); } + +#ifndef SWIGJAVA + friend std::ostream& operator<< (std::ostream& os, const SendRequest& sendReq); +#endif }; diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp index 4a8ead7..015ed6c 100644 --- a/src/uscxml/URL.cpp +++ b/src/uscxml/URL.cpp @@ -162,7 +162,7 @@ std::ostream & operator<<(std::ostream & stream, const URL& url) { // std::replace( urlString.begin(), urlString.end(), '/', '\\'); #endif } - LOG(ERROR) << "Trying to open " << urlString; +// LOG(ERROR) << "Trying to open " << urlString; URL_FILE *handle = url_fopen(urlString.c_str(), "r"); if(!handle) { diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index 9f04670..d8a3c8d 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -63,6 +63,8 @@ boost::shared_ptr V8DataModel::create(Interpreter* interpreter) { dm->setName(interpreter->getName()); dm->setSessionId(interpreter->getSessionId()); dm->eval("_ioprocessors = {};"); + dm->eval("_invokers = {};"); + dm->eval("_x = {};"); return dm; } @@ -183,7 +185,7 @@ Data V8DataModel::getValueAsData(const v8::Handle& value) { } else if(value->IsUint32()) { LOG(ERROR) << "IsUint32 is unimplemented" << std::endl; } else if(value->IsUndefined()) { - LOG(ERROR) << "IsUndefined is unimplemented" << std::endl; + data.atom = "undefined"; } return data; } @@ -269,6 +271,10 @@ std::string V8DataModel::evalAsString(const std::string& expr) { v8::HandleScope handleScope; v8::Context::Scope contextScope(_contexts.back()); v8::Handle result = evalAsValue(expr); + if (result->IsObject()) { + Data data = getValueAsData(result); + return toStr(data); + } v8::String::AsciiValue data(result->ToString()); return std::string(*data); } diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp new file mode 100644 index 0000000..eb3d810 --- /dev/null +++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp @@ -0,0 +1,48 @@ +#include "OSGConverter.h" +#include + +#ifdef BUILD_AS_PLUGINS +#include +#endif + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host) { + host.add( new OSGConverterProvider() ); + return true; +} +#endif + +OSGConverter::OSGConverter() { +} + +OSGConverter::~OSGConverter() { +}; + +boost::shared_ptr OSGConverter::create(Interpreter* interpreter) { + boost::shared_ptr invoker = boost::shared_ptr(new OSGConverter()); + invoker->_interpreter = interpreter; + return invoker; +} + +Data OSGConverter::getDataModelVariables() { + Data data; + return data; +} + +void OSGConverter::send(const SendRequest& req) { + std::cout << req << std::endl; + Event event; + event.name = "error"; + returnEvent(event); +} + +void OSGConverter::cancel(const std::string sendId) { +} + +void OSGConverter::invoke(const InvokeRequest& req) { +} + +} \ No newline at end of file diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h new file mode 100644 index 0000000..c52b1ee --- /dev/null +++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h @@ -0,0 +1,42 @@ +#ifndef OSGCONVERTER_H_W09J90F0 +#define OSGCONVERTER_H_W09J90F0 + +#include + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class OSGConverter : public InvokerImpl { +public: + OSGConverter(); + virtual ~OSGConverter(); + virtual boost::shared_ptr create(Interpreter* interpreter); + + virtual std::set getNames() { + std::set names; + names.insert("osgconverter"); + names.insert("osgconvert"); + names.insert("http://uscxml.tk.informatik.tu-darmstadt.de/#osgconverter"); + names.insert("http://uscxml.tk.informatik.tu-darmstadt.de/#osgconvert"); + return names; + } + + virtual Data getDataModelVariables(); + virtual void send(const SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(const InvokeRequest& req); + +protected: +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(OSGConverter, Invoker); +#endif + +} + + +#endif /* end of include guard: OSGCONVERTER_H_W09J90F0 */ diff --git a/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp b/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp index 1f08378..0272ca8 100644 --- a/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp +++ b/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp @@ -19,6 +19,7 @@ HeartbeatInvoker::HeartbeatInvoker() { } HeartbeatInvoker::~HeartbeatInvoker() { + cancel(""); }; boost::shared_ptr HeartbeatInvoker::create(Interpreter* interpreter) { diff --git a/src/uscxml/plugins/invoker/sqlite3/Sqlite3Invoker.cpp b/src/uscxml/plugins/invoker/sqlite3/Sqlite3Invoker.cpp new file mode 100644 index 0000000..e217eaa --- /dev/null +++ b/src/uscxml/plugins/invoker/sqlite3/Sqlite3Invoker.cpp @@ -0,0 +1,44 @@ +#include "Sqlite3Invoker.h" +#include + +#ifdef BUILD_AS_PLUGINS +#include +#endif + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host) { + host.add( new Sqlite3InvokerProvider() ); + return true; +} +#endif + +Sqlite3Invoker::Sqlite3Invoker() { +} + +Sqlite3Invoker::~Sqlite3Invoker() { +}; + +boost::shared_ptr Sqlite3Invoker::create(Interpreter* interpreter) { + boost::shared_ptr invoker = boost::shared_ptr(new Sqlite3Invoker()); + invoker->_interpreter = interpreter; + return invoker; +} + +Data Sqlite3Invoker::getDataModelVariables() { + Data data; + return data; +} + +void Sqlite3Invoker::send(const SendRequest& req) { +} + +void Sqlite3Invoker::cancel(const std::string sendId) { +} + +void Sqlite3Invoker::invoke(const InvokeRequest& req) { +} + +} \ No newline at end of file diff --git a/src/uscxml/plugins/invoker/sqlite3/Sqlite3Invoker.h b/src/uscxml/plugins/invoker/sqlite3/Sqlite3Invoker.h new file mode 100644 index 0000000..f2ae915 --- /dev/null +++ b/src/uscxml/plugins/invoker/sqlite3/Sqlite3Invoker.h @@ -0,0 +1,40 @@ +#ifndef SQLITE3INVOKER_H_W09J90F0 +#define SQLITE3INVOKER_H_W09J90F0 + +#include + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class Sqlite3Invoker : public InvokerImpl { +public: + Sqlite3Invoker(); + virtual ~Sqlite3Invoker(); + virtual boost::shared_ptr create(Interpreter* interpreter); + + virtual std::set getNames() { + std::set names; + names.insert("sqlite3"); + names.insert("http://uscxml.tk.informatik.tu-darmstadt.de/#sqlite3"); + return names; + } + + virtual Data getDataModelVariables(); + virtual void send(const SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(const InvokeRequest& req); + +protected: +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(Sqlite3Invoker, Invoker); +#endif + +} + + +#endif /* end of include guard: SQLITE3INVOKER_H_W09J90F0 */ diff --git a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp index 3ed39d6..98d08b3 100644 --- a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp @@ -75,14 +75,15 @@ Data EventIOProcessor::getDataModelVariables() { void EventIOProcessor::send(const SendRequest& req) { - // I cant figure out how to copy the reference into the struct :( - _sendData[req.sendid].req = req; - _sendData[req.sendid].ioProcessor = this; + + _sendData[req.sendid] = new SendData(); + _sendData[req.sendid]->scxmlReq = req; + _sendData[req.sendid]->ioProcessor = this; int err = 0; char uriBuf[1024]; - struct evhttp_uri* targetURI = evhttp_uri_parse(_sendData[req.sendid].req.target.c_str()); + struct evhttp_uri* targetURI = evhttp_uri_parse(_sendData[req.sendid]->scxmlReq.target.c_str()); if (evhttp_uri_get_port(targetURI) < 0) evhttp_uri_set_port(targetURI, 80); const char* hostName = evhttp_uri_get_host(targetURI); @@ -108,11 +109,14 @@ void EventIOProcessor::send(const SendRequest& req) { ssLocalURI << evhttp_uri_get_path(targetURI) << evhttp_uri_get_fragment(targetURI); std::string localURI = ssLocalURI.str(); - if (_httpConnections.find(endPoint) == _httpConnections.end()) - _httpConnections[endPoint] = evhttp_connection_base_new(_asyncQueue._eventLoop, _dns, evhttp_uri_get_host(targetURI), evhttp_uri_get_port(targetURI)); + if (_httpConnections.find(endPoint) == _httpConnections.end()) { + struct evhttp_connection* conn = evhttp_connection_base_new(_asyncQueue._eventLoop, _dns, evhttp_uri_get_host(targetURI), evhttp_uri_get_port(targetURI)); + evhttp_connection_set_retries(conn, 3); + _httpConnections[endPoint] = conn; + } struct evhttp_connection* httpConn = _httpConnections[endPoint]; - struct evhttp_request* httpReq = evhttp_request_new(EventIOServer::httpSendReqDoneCallback, this); + struct evhttp_request* httpReq = evhttp_request_new(EventIOServer::httpSendReqDoneCallback, _sendData[req.sendid]); // event name if (req.name.size() > 0) { @@ -163,6 +167,15 @@ void EventIOProcessor::send(const SendRequest& req) { } } +void EventIOProcessor::httpSendReqDone(struct SendData* sendData) { + if (sendData->httpReq == NULL || evhttp_request_get_response_code(sendData->httpReq) != 200) { + Event failureEvent; + failureEvent.name = "error.communication"; + sendData->ioProcessor->returnEvent(failureEvent); + } + delete _sendData[sendData->scxmlReq.sendid]; +} + void EventIOProcessor::httpRecvReq(struct evhttp_request *req) { const char *cmdtype; @@ -246,12 +259,6 @@ void EventIOProcessor::httpRecvReq(struct evhttp_request *req) { evhttp_send_reply(req, 200, "OK", NULL); } -void EventIOProcessor::httpSendReqDone(struct evhttp_request *req) { - if (req) { - LOG(INFO) << "got return code " << evhttp_request_get_response_code(req) << std::endl; - } -} - EventIOServer::EventIOServer(unsigned short port) { _port = port; _base = event_base_new(); @@ -333,7 +340,6 @@ void EventIOServer::start() { void EventIOServer::run(void* instance) { EventIOServer* INSTANCE = (EventIOServer*)instance; - LOG(INFO) << "HTTP Server started" << std::endl; while(INSTANCE->_isRunning) { event_base_dispatch(INSTANCE->_base); } diff --git a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h index 783332e..7dd1c41 100644 --- a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h +++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h @@ -23,7 +23,8 @@ class EventIOProcessor : public IOProcessorImpl { public: struct SendData { EventIOProcessor* ioProcessor; - uscxml::SendRequest req; + uscxml::SendRequest scxmlReq; + evhttp_request* httpReq; }; EventIOProcessor(); @@ -48,11 +49,11 @@ public: static void run(void* instance); virtual std::string getPath() { return _interpreter->getName(); } - virtual void httpSendReqDone(struct evhttp_request *req); + virtual void httpSendReqDone(struct SendData* sendData); virtual void httpRecvReq(struct evhttp_request *req); protected: - std::map _sendData; + std::map _sendData; std::string _url; @@ -82,9 +83,10 @@ private: void determineAddress(); static std::string syncResolve(const std::string& hostname); - static void httpSendReqDoneCallback(struct evhttp_request *req, void *cb_arg) { - ((EventIOProcessor*)cb_arg)->httpSendReqDone(req); + EventIOProcessor::SendData* sendData = (EventIOProcessor::SendData*)cb_arg; + sendData->httpReq = req; + sendData->ioProcessor->httpSendReqDone(sendData); } static void httpRecvReqCallback(struct evhttp_request *req, void *cb_arg) { ((EventIOProcessor*)cb_arg)->httpRecvReq(req); diff --git a/test/run-scxml-test-framework.sh b/test/run-scxml-test-framework.sh index 34f804d..2182e79 100755 --- a/test/run-scxml-test-framework.sh +++ b/test/run-scxml-test-framework.sh @@ -24,11 +24,11 @@ TESTS="" # TESTS="${TESTS} scxml-test-framework/test/actionSend/send1.scxml" # passed # TESTS="${TESTS} scxml-test-framework/test/actionSend/send2.scxml" # passed # TESTS="${TESTS} scxml-test-framework/test/actionSend/send3.scxml" # passed -# TESTS="${TESTS} scxml-test-framework/test/actionSend/send4.scxml" # failed -# TESTS="${TESTS} scxml-test-framework/test/actionSend/send5.scxml" # failed -# TESTS="${TESTS} scxml-test-framework/test/actionSend/send6.scxml" # failed -# TESTS="${TESTS} scxml-test-framework/test/actionSend/send7.scxml" # failed -# TESTS="${TESTS} scxml-test-framework/test/actionSend/send8.scxml" # failed +# TESTS="${TESTS} scxml-test-framework/test/actionSend/send4.scxml" # won't support +# TESTS="${TESTS} scxml-test-framework/test/actionSend/send5.scxml" # won't support +# TESTS="${TESTS} scxml-test-framework/test/actionSend/send6.scxml" # won't support +# TESTS="${TESTS} scxml-test-framework/test/actionSend/send7.scxml" # won't support +# TESTS="${TESTS} scxml-test-framework/test/actionSend/send8.scxml" # won't support # TESTS="${TESTS} scxml-test-framework/test/assign-current-small-step/test0.scxml" # passed # TESTS="${TESTS} scxml-test-framework/test/assign-current-small-step/test1.scxml" # passed @@ -74,7 +74,7 @@ TESTS="" # TESTS="${TESTS} scxml-test-framework/test/hierarchy+documentOrder/test0.scxml" # failed # TESTS="${TESTS} scxml-test-framework/test/hierarchy+documentOrder/test1.scxml" # failed -# TESTS="${TESTS} scxml-test-framework/test/history/history0.scxml" # segfault +TESTS="${TESTS} scxml-test-framework/test/history/history0.scxml" # segfault # TESTS="${TESTS} scxml-test-framework/test/history/history1.scxml" # segfault # TESTS="${TESTS} scxml-test-framework/test/history/history2.scxml" # segfault # TESTS="${TESTS} scxml-test-framework/test/history/history3.scxml" # failed @@ -158,9 +158,9 @@ TESTS="" # TESTS="${TESTS} scxml-test-framework/test/targetless-transition/test3.scxml" # failed -trap 'killall ${SCXML_TEST_FRAMEWORK_NAME}' 0 -$SCXML_TEST_FRAMEWORK_FULL & -sleep 1 +#trap 'killall ${SCXML_TEST_FRAMEWORK_NAME}' 0 +#$SCXML_TEST_FRAMEWORK_FULL & +#sleep 1 cd $DIR node scxml-test-framework --test-server-url http://localhost:8080/test $TESTS diff --git a/test/samples/uscxml/test-communication.scxml b/test/samples/uscxml/test-communication.scxml index 8b1b380..4811a3f 100644 --- a/test/samples/uscxml/test-communication.scxml +++ b/test/samples/uscxml/test-communication.scxml @@ -43,7 +43,15 @@ This is some content you got there dude! - + + + + + + + + + diff --git a/test/samples/uscxml/test-umundo-pingpong.scxml b/test/samples/uscxml/test-umundo-pingpong.scxml new file mode 100644 index 0000000..93be19d --- /dev/null +++ b/test/samples/uscxml/test-umundo-pingpong.scxml @@ -0,0 +1,21 @@ + +