summaryrefslogtreecommitdiffstats
path: root/src/uscxml
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-06-23 23:38:20 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-06-23 23:38:20 (GMT)
commitfebde41c4c69d8f38967d5c195328d468834d037 (patch)
tree4580a433d410e91a6f8df9203c20693e7a21128d /src/uscxml
parenteb6e9807cdb43b408de45ae789916cdf3bebe6f0 (diff)
downloaduscxml-febde41c4c69d8f38967d5c195328d468834d037.zip
uscxml-febde41c4c69d8f38967d5c195328d468834d037.tar.gz
uscxml-febde41c4c69d8f38967d5c195328d468834d037.tar.bz2
Updated tests for IRP and work on bindings
Diffstat (limited to 'src/uscxml')
-rw-r--r--src/uscxml/Factory.cpp22
-rw-r--r--src/uscxml/Interpreter.cpp445
-rw-r--r--src/uscxml/Interpreter.h358
-rw-r--r--src/uscxml/Message.cpp23
-rw-r--r--src/uscxml/Message.h10
-rw-r--r--src/uscxml/concurrency/tinythread.h25
-rw-r--r--src/uscxml/debug/Breakpoint.cpp2
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.cpp4
-rw-r--r--src/uscxml/interpreter/InterpreterDraft6.cpp418
-rw-r--r--src/uscxml/interpreter/InterpreterDraft6.h7
-rw-r--r--src/uscxml/interpreter/InterpreterRC.cpp118
-rw-r--r--src/uscxml/interpreter/InterpreterRC.h4
-rw-r--r--src/uscxml/plugins/datamodel/CMakeLists.txt15
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp8
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp17
-rw-r--r--src/uscxml/plugins/element/respond/RespondElement.cpp4
-rw-r--r--src/uscxml/plugins/invoker/CMakeLists.txt24
-rw-r--r--src/uscxml/plugins/invoker/sample/SampleInvoker.cpp2
-rw-r--r--src/uscxml/plugins/invoker/sample/SampleInvoker.h2
-rw-r--r--src/uscxml/plugins/invoker/webrtc/WebRTCInvoker.cpp64
-rw-r--r--src/uscxml/plugins/invoker/webrtc/WebRTCInvoker.h59
-rw-r--r--src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp26
-rw-r--r--src/uscxml/server/HTTPServer.cpp1
-rw-r--r--src/uscxml/transform/ChartToFSM.cpp5
-rw-r--r--src/uscxml/transform/ChartToFSM.h2
25 files changed, 944 insertions, 721 deletions
diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp
index c63fc0d..5b7426f 100644
--- a/src/uscxml/Factory.cpp
+++ b/src/uscxml/Factory.cpp
@@ -24,6 +24,8 @@
#include "uscxml/Interpreter.h"
#include <glog/logging.h>
+#include "uscxml/plugins/datamodel/null/NULLDataModel.h"
+
// see http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system
#ifdef BUILD_AS_PLUGINS
@@ -100,7 +102,6 @@
# include "uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h"
# endif
-#include "uscxml/plugins/datamodel/null/NULLDataModel.h"
#include "uscxml/plugins/datamodel/xpath/XPathDataModel.h"
#include "uscxml/plugins/datamodel/promela/PromelaDataModel.h"
@@ -142,8 +143,6 @@ std::string Factory::getDefaultPluginPath() {
}
void Factory::registerPlugins() {
-#ifdef BUILD_AS_PLUGINS
- // these are part of core
{
InterpreterHTTPServlet* ioProcessor = new InterpreterHTTPServlet();
registerIOProcessor(ioProcessor);
@@ -152,6 +151,13 @@ void Factory::registerPlugins() {
InterpreterWebSocketServlet* ioProcessor = new InterpreterWebSocketServlet();
registerIOProcessor(ioProcessor);
}
+ {
+ NULLDataModel* dataModel = new NULLDataModel();
+ registerDataModel(dataModel);
+ }
+
+#ifdef BUILD_AS_PLUGINS
+ // these are part of core
if (_pluginPath.length() == 0) {
// try to read USCXML_PLUGIN_PATH environment variable
@@ -291,14 +297,12 @@ void Factory::registerPlugins() {
}
#endif
-#if 1
#if (defined BUILD_DM_PROMELA)
{
PromelaDataModel* dataModel = new PromelaDataModel();
registerDataModel(dataModel);
}
#endif
-#endif
#ifdef BUILD_DM_XPATH
{
@@ -323,10 +327,6 @@ void Factory::registerPlugins() {
#endif
// these are always available
- {
- NULLDataModel* dataModel = new NULLDataModel();
- registerDataModel(dataModel);
- }
#if 1
{
XHTMLInvoker* invoker = new XHTMLInvoker();
@@ -690,7 +690,7 @@ void EventHandlerImpl::returnEvent(Event& event) {
void DataModelImpl::throwErrorExecution(const std::string& cause) {
uscxml::Event exc;
- exc.data.compound["exception"] = uscxml::Data(cause, uscxml::Data::VERBATIM);
+ exc.data.compound["cause"] = uscxml::Data(cause, uscxml::Data::VERBATIM);
exc.name = "error.execution";
exc.eventType = uscxml::Event::PLATFORM;
throw exc;
@@ -698,7 +698,7 @@ void DataModelImpl::throwErrorExecution(const std::string& cause) {
void DataModelImpl::throwErrorPlatform(const std::string& cause) {
uscxml::Event exc;
- exc.data.compound["exception"] = uscxml::Data(cause, uscxml::Data::VERBATIM);
+ exc.data.compound["cause"] = uscxml::Data(cause, uscxml::Data::VERBATIM);
exc.name = "error.platform";
exc.eventType = uscxml::Event::PLATFORM;
throw exc;
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index 3d3c181..f3d30de 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -50,6 +50,47 @@
#define VERBOSE 0
+/// valid interpreter state transitions
+#define VALID_FROM_INSTANTIATED(newState) ( \
+ newState == InterpreterState::USCXML_FAULTED || \
+ newState == InterpreterState::USCXML_MICROSTEPPED || \
+ newState == InterpreterState::USCXML_DESTROYED\
+)
+
+#define VALID_FROM_FAULTED(newState) ( \
+ newState == InterpreterState::USCXML_DESTROYED\
+)
+
+#define VALID_FROM_INITIALIZED(newState) ( \
+ newState == InterpreterState::USCXML_MICROSTEPPED || \
+ newState == InterpreterState::USCXML_FINISHED \
+)
+
+#define VALID_FROM_MICROSTEPPED(newState) ( \
+ newState == InterpreterState::USCXML_DESTROYED || \
+ newState == InterpreterState::USCXML_MACROSTEPPED || \
+ newState == InterpreterState::USCXML_MICROSTEPPED || \
+ newState == InterpreterState::USCXML_FINISHED \
+)
+
+#define VALID_FROM_MACROSTEPPED(newState) ( \
+ newState == InterpreterState::USCXML_DESTROYED || \
+ newState == InterpreterState::USCXML_MICROSTEPPED || \
+ newState == InterpreterState::USCXML_IDLE || \
+ newState == InterpreterState::USCXML_FINISHED \
+)
+
+#define VALID_FROM_IDLE(newState) ( \
+ newState == InterpreterState::USCXML_DESTROYED || \
+ newState == InterpreterState::USCXML_MICROSTEPPED \
+)
+
+#define VALID_FROM_FINISHED(newState) ( \
+ newState == InterpreterState::USCXML_DESTROYED || \
+ newState == InterpreterState::USCXML_INSTANTIATED \
+)
+
+
/// macro to catch exceptions in executeContent
#define CATCH_AND_DISTRIBUTE(msg) \
catch (Event e) {\
@@ -169,7 +210,7 @@ InterpreterOptions InterpreterOptions::fromCmdLine(int argc, char** argv) {
}
switch(option) {
- // cases without short option
+ // cases without short option
case 0: {
if (boost::equals(longOptions[optionInd].name, "disable-http")) {
currOptions->withHTTP = false;
@@ -269,7 +310,7 @@ void NameSpaceInfo::init(const std::map<std::string, std::string>& namespaceInfo
nsIter++;
}
}
-
+
std::map<std::string, boost::weak_ptr<InterpreterImpl> > Interpreter::_instances;
tthread::recursive_mutex Interpreter::_instanceMutex;
@@ -288,15 +329,16 @@ std::map<std::string, boost::weak_ptr<InterpreterImpl> > Interpreter::getInstanc
InterpreterImpl::InterpreterImpl() {
+ _state.state = InterpreterState::USCXML_INSTANTIATED;
+ _state.thread = 0;
_lastRunOnMainThread = 0;
_thread = NULL;
_sendQueue = NULL;
_parentQueue = NULL;
- _running = false;
- _destroyed = false;
- _done = true;
+ _topLevelFinalReached = false;
_stable = false;
_isInitialized = false;
+ _domIsSetup = false;
_httpServlet = NULL;
_factory = NULL;
_sessionId = UUID::getUUID();
@@ -317,7 +359,7 @@ Interpreter Interpreter::fromDOM(const Arabica::DOM::Document<std::string>& dom,
interpreterImpl->setNameSpaceInfo(nameSpaceInfo);
interpreterImpl->_document = dom;
- interpreterImpl->init();
+// interpreterImpl->init();
_instances[interpreterImpl->getSessionId()] = interpreterImpl;
return interpreter;
}
@@ -389,20 +431,17 @@ Interpreter Interpreter::fromInputSource(Arabica::SAX::InputSource<std::string>&
}
boost::shared_ptr<INTERPRETER_IMPL> interpreterImpl = boost::shared_ptr<INTERPRETER_IMPL>(new INTERPRETER_IMPL);
- Interpreter interpreter;
+ Interpreter interpreter(interpreterImpl);
+ _instances[interpreterImpl->getSessionId()] = interpreterImpl;
+
NameSpacingParser parser;
if (parser.parse(source) && parser.getDocument() && parser.getDocument().hasChildNodes()) {
interpreterImpl->setNameSpaceInfo(parser.nameSpace);
interpreterImpl->_document = parser.getDocument();
-// interpreterImpl->init();
- interpreter = Interpreter(interpreterImpl);
- _instances[interpreterImpl->getSessionId()] = interpreterImpl;
} else {
- if (parser.errorsReported()) {
- LOG(ERROR) << parser.errors();
- }
+// assert(parser.errorsReported());
+ interpreterImpl->setInterpreterState(InterpreterState::USCXML_FAULTED, parser.errors());
}
- // interpreter->init();
return interpreter;
}
@@ -459,20 +498,15 @@ void InterpreterImpl::copyTo(boost::shared_ptr<InterpreterImpl> other) {
copyTo(other.get());
}
-
void InterpreterImpl::setName(const std::string& name) {
- if (!_running) {
- _name = name;
- } else {
- LOG(ERROR) << "Cannot change name of running interpreter";
- }
+ _name = name;
}
InterpreterImpl::~InterpreterImpl() {
{
// make sure we are done with setting up with early abort
tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
- _running = false;
+ stop(); // unset started bit
}
// std::cout << "stopped " << this << std::endl;
// tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
@@ -488,27 +522,53 @@ InterpreterImpl::~InterpreterImpl() {
delete(_thread);
} else {
// this can happen with a shared_from_this at an interpretermonitor
- _destroyed = true;
+ setInterpreterState(InterpreterState::USCXML_DESTROYED);
}
}
+ join();
if (_sendQueue)
delete _sendQueue;
}
void InterpreterImpl::start() {
- _done = false;
+ _state.thread |= InterpreterState::USCXML_THREAD_STARTED;
_thread = new tthread::thread(InterpreterImpl::run, this);
}
void InterpreterImpl::stop() {
- _running = false;
+ _state.thread &= ~InterpreterState::USCXML_THREAD_STARTED;
}
+void InterpreterImpl::join() {
+ stop();
+ if (_thread != NULL) _thread->join();
+};
+
+bool InterpreterImpl::isRunning() {
+ // return _running || !_topLevelFinalReached;
+ return _state.thread & InterpreterState::USCXML_THREAD_RUNNING;
+}
void InterpreterImpl::run(void* instance) {
+ InterpreterImpl* interpreter = ((InterpreterImpl*)instance);
+ interpreter->_state.thread |= InterpreterState::USCXML_THREAD_RUNNING;
+
try {
- ((InterpreterImpl*)instance)->interpret();
+ InterpreterState state;
+ while(interpreter->_state.thread & InterpreterState::USCXML_THREAD_STARTED) {
+ state = interpreter->step(-1);
+
+ switch (state & InterpreterState::USCXML_INTERPRETER_MASK) {
+ case uscxml::InterpreterState::USCXML_FAULTED:
+ case uscxml::InterpreterState::USCXML_FINISHED:
+ case uscxml::InterpreterState::USCXML_DESTROYED:
+ // return as we finished
+ goto DONE_THREAD;
+ default:
+ break;
+ }
+ }
} catch (Event e) {
LOG(ERROR) << e;
} catch(boost::bad_lexical_cast e) {
@@ -516,12 +576,73 @@ void InterpreterImpl::run(void* instance) {
} catch (...) {
LOG(ERROR) << "InterpreterImpl::run catched unknown exception";
}
- ((InterpreterImpl*)instance)->_done = true;
- ((InterpreterImpl*)instance)->_running = false;
+DONE_THREAD:
+ ((InterpreterImpl*)instance)->_state.thread &= ~InterpreterState::USCXML_THREAD_RUNNING;
+ ((InterpreterImpl*)instance)->_state.thread &= ~InterpreterState::USCXML_THREAD_STARTED;
+}
+
+InterpreterState InterpreterImpl::getInterpreterState() {
+ return _state;
+}
+
+void InterpreterImpl::setInterpreterState(InterpreterState::State newState) {
+ setInterpreterState(newState, Event());
}
+void InterpreterImpl::setInterpreterState(InterpreterState::State newState, const std::string& error) {
+ Event e;
+ e.name = "error.platform";
+ e.data.compound["cause"] = Data(error, Data::VERBATIM);
+ setInterpreterState(newState, e);
+}
+
+void InterpreterImpl::setInterpreterState(InterpreterState::State newState, const Event& error) {
+ switch (_state) {
+ case InterpreterState::USCXML_INSTANTIATED:
+ if (VALID_FROM_INSTANTIATED(newState))
+ break;
+ assert(false);
+ break;
+ case InterpreterState::USCXML_FAULTED:
+ if (VALID_FROM_FAULTED(newState))
+ break;
+ assert(false);
+ break;
+ case InterpreterState::USCXML_MICROSTEPPED:
+ if (VALID_FROM_MICROSTEPPED(newState))
+ break;
+ assert(false);
+ break;
+ case InterpreterState::USCXML_MACROSTEPPED:
+ if (VALID_FROM_MACROSTEPPED(newState))
+ break;
+ assert(false);
+ break;
+ case InterpreterState::USCXML_IDLE:
+ if (VALID_FROM_IDLE(newState))
+ break;
+ assert(false);
+ break;
+ case InterpreterState::USCXML_FINISHED:
+ if (VALID_FROM_FINISHED(newState))
+ break;
+ assert(false);
+ break;
+ case InterpreterState::USCXML_DESTROYED:
+ assert(false);
+ break;
+
+ default:
+ break;
+ }
+
+ _state.state = newState;
+ _state.msg = error;
+}
+
bool InterpreterImpl::runOnMainThread(int fps, bool blocking) {
- if (_done)
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+ if (_state == InterpreterState::USCXML_FINISHED || _state == InterpreterState::USCXML_FAULTED || _state == InterpreterState::USCXML_DESTROYED)
return false;
if (fps > 0) {
@@ -553,13 +674,31 @@ bool InterpreterImpl::runOnMainThread(int fps, bool blocking) {
return (_thread != NULL);
}
-void InterpreterImpl::init() {
- if (!_document) {
- LOG(ERROR) << "Interpreter has no DOM at all!" << std::endl;
- _done = true;
+void InterpreterImpl::reset() {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+
+ _externalQueue.clear();
+ _internalQueue.clear();
+ _historyValue.clear();
+
+ _alreadyEntered = NodeSet<std::string>();
+ _configuration = NodeSet<std::string>();
+ _topLevelFinalReached = false;
+ _isInitialized = false;
+
+ setInterpreterState(InterpreterState::USCXML_INSTANTIATED);
+}
+
+void InterpreterImpl::setupAndNormalizeDOM() {
+ if (_domIsSetup)
return;
- }
+ if (!_document) {
+ Event error("error.platform");
+ error.data.compound["cause"] = Data("Interpreter has no DOM", Data::VERBATIM);
+ throw error;
+ }
+
// find scxml element
NodeList<std::string> scxmls;
if (_nsInfo.nsURL.size() == 0) {
@@ -567,54 +706,79 @@ void InterpreterImpl::init() {
} else {
scxmls = _document.getElementsByTagNameNS(_nsInfo.nsURL, "scxml");
}
-
- if (scxmls.getLength() > 0) {
- _scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0);
- // setup xpath and check that it works
- if (_nsInfo.getNSContext() != NULL)
- _xpath.setNamespaceContext(*_nsInfo.getNSContext());
+ if (scxmls.getLength() == 0) {
+ Event error("error.platform");
+ error.data.compound["cause"] = Data("Cannot find SCXML element in DOM", Data::VERBATIM);
+ throw error;
+ }
- if (_name.length() == 0)
- _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : UUID::getUUID());
+ _scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0);
- // normalize document
- normalize(_scxml);
+ if (_nsInfo.getNSContext() != NULL)
+ _xpath.setNamespaceContext(*_nsInfo.getNSContext());
- // setup event queue for delayed send
- _sendQueue = new DelayedEventQueue();
- _sendQueue->start();
-
- // register for dom events to manage cached states
- Arabica::DOM::Events::EventTarget<std::string> eventTarget(_scxml);
- eventTarget.addEventListener("DOMNodeInserted", _domEventListener, true);
- eventTarget.addEventListener("DOMNodeRemoved", _domEventListener, true);
- eventTarget.addEventListener("DOMSubtreeModified", _domEventListener, true);
+ // normalize document
+ // TODO: Resolve XML includes
+
+ // make sure every state has an id
+ Arabica::XPath::NodeSet<std::string> states;
+ states.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "state", _scxml).asNodeSet());
+ states.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "final", _scxml).asNodeSet());
+ states.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "history", _scxml).asNodeSet());
+ for (int i = 0; i < states.size(); i++) {
+ Arabica::DOM::Element<std::string> stateElem = Arabica::DOM::Element<std::string>(states[i]);
+ if (!stateElem.hasAttribute("id")) {
+ stateElem.setAttribute("id", UUID::getUUID());
+ }
+ }
+
+ // make sure every invoke has an idlocation or id
+ Arabica::XPath::NodeSet<std::string> invokes = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "invoke", _scxml).asNodeSet();
+ for (int i = 0; i < invokes.size(); i++) {
+ Arabica::DOM::Element<std::string> invokeElem = Arabica::DOM::Element<std::string>(invokes[i]);
+ if (!invokeElem.hasAttribute("id") && !invokeElem.hasAttribute("idlocation")) {
+ invokeElem.setAttribute("id", UUID::getUUID());
+ }
+ }
+
+ // add an id to the scxml element
+ if (!_scxml.hasAttribute("id")) {
+ _scxml.setAttribute("id", UUID::getUUID());
+ }
- if (_factory == NULL)
- _factory = Factory::getInstance();
+ // register for dom events to manage cached states
+ Arabica::DOM::Events::EventTarget<std::string> eventTarget(_scxml);
+ eventTarget.addEventListener("DOMNodeInserted", _domEventListener, true);
+ eventTarget.addEventListener("DOMNodeRemoved", _domEventListener, true);
+ eventTarget.addEventListener("DOMSubtreeModified", _domEventListener, true);
- } else {
- LOG(ERROR) << "Cannot find SCXML element" << std::endl;
- _done = true;
- return;
- }
+}
- if (_sessionId.length() == 0)
- _sessionId = UUID::getUUID();
+void InterpreterImpl::init() {
+ // make sure we have a factory if none was set before
+ if (_factory == NULL)
+ _factory = Factory::getInstance();
+ // setup and normalize DOM
+ setupAndNormalizeDOM();
+ // get our name or generate as UUID
+ if (_name.length() == 0)
+ _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : UUID::getUUID());
+
+ // setup event queue for delayed send
+ if (!_sendQueue) {
+ _sendQueue = new DelayedEventQueue();
+ _sendQueue->start();
+ }
+
+ // start io processoes
setupIOProcessors();
- std::string datamodelName;
+ // instantiate datamodel
if (HAS_ATTR(_scxml, "datamodel")) {
- datamodelName = ATTR(_scxml, "datamodel");
- } else if (HAS_ATTR(_scxml, "profile")) {// SCION SCXML uses profile to specify datamodel
- datamodelName = ATTR(_scxml, "profile");
- }
-
- if(datamodelName.length() > 0) {
- _dataModel = _factory->createDataModel(datamodelName, this);
+ _dataModel = _factory->createDataModel(ATTR(_scxml, "datamodel"), this);
if (!_dataModel) {
Event e;
e.data.compound["cause"] = Data("Cannot instantiate datamodel", Data::VERBATIM);
@@ -623,10 +787,10 @@ void InterpreterImpl::init() {
} else {
_dataModel = _factory->createDataModel("null", this);
}
-
+
_dataModel.assign("_x.args", _cmdLineOptions);
- _running = true;
+// _running = true;
#if VERBOSE
std::cout << "running " << this << std::endl;
#endif
@@ -706,35 +870,6 @@ void InterpreterImpl::initializeData(const Element<std::string>& data) {
}
}
-void InterpreterImpl::normalize(Arabica::DOM::Element<std::string>& scxml) {
- // TODO: Resolve XML includes
-
- // make sure every state has an id
- Arabica::XPath::NodeSet<std::string> states;
- states.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "state", _scxml).asNodeSet());
- states.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "final", _scxml).asNodeSet());
- states.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "history", _scxml).asNodeSet());
- for (int i = 0; i < states.size(); i++) {
- Arabica::DOM::Element<std::string> stateElem = Arabica::DOM::Element<std::string>(states[i]);
- if (!stateElem.hasAttribute("id")) {
- stateElem.setAttribute("id", UUID::getUUID());
- }
- }
-
- // make sure every invoke has an idlocation or id
- Arabica::XPath::NodeSet<std::string> invokes = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "invoke", _scxml).asNodeSet();
- for (int i = 0; i < invokes.size(); i++) {
- Arabica::DOM::Element<std::string> invokeElem = Arabica::DOM::Element<std::string>(invokes[i]);
- if (!invokeElem.hasAttribute("id") && !invokeElem.hasAttribute("idlocation")) {
- invokeElem.setAttribute("id", UUID::getUUID());
- }
- }
-
- if (!scxml.hasAttribute("id")) {
- scxml.setAttribute("id", UUID::getUUID());
- }
-}
-
void InterpreterImpl::receiveInternal(const Event& event) {
#if VERBOSE
std::cout << _name << " receiveInternal: " << event.name << std::endl;
@@ -1249,24 +1384,12 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node<std::string>& element) {
_invokers[invokeReq.invokeid] = invoker;
try {
- // --- MONITOR: beforeInvoking ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeInvoking(shared_from_this(), Element<std::string>(element), invokeReq.invokeid);
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeInvoking)
- }
+ USCXML_MONITOR_CALLBACK3(beforeInvoking, Arabica::DOM::Element<std::string>(element), invokeReq.invokeid);
invoker.invoke(invokeReq);
LOG(INFO) << "Added invoker " << invokeReq.type << " at " << invokeReq.invokeid;
- // --- MONITOR: afterInvoking ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterInvoking(shared_from_this(), Element<std::string>(element), invokeReq.invokeid);
- }
- USCXML_MONITOR_CATCH_BLOCK(afterInvoking)
- }
+ USCXML_MONITOR_CALLBACK3(afterInvoking, Arabica::DOM::Element<std::string>(element), invokeReq.invokeid)
// this is out of draft but so useful to know when an invoker started
// Event invSuccess;
@@ -1316,23 +1439,11 @@ void InterpreterImpl::cancelInvoke(const Arabica::DOM::Node<std::string>& elemen
}
}
- // --- MONITOR: beforeUninvoking ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeUninvoking(shared_from_this(), Element<std::string>(element), invokeId);
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeUninvoking)
- }
+ USCXML_MONITOR_CALLBACK3(beforeUninvoking, Element<std::string>(element), invokeId)
_invokers.erase(invokeId);
- // --- MONITOR: afterUninvoking ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterUninvoking(shared_from_this(), Element<std::string>(element), invokeId);
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeUninvoking)
- }
+ USCXML_MONITOR_CALLBACK3(beforeUninvoking, Element<std::string>(element), invokeId)
} else {
LOG(ERROR) << "Cannot cancel invoke for id " << invokeId << ": no such invokation";
@@ -1388,10 +1499,6 @@ bool InterpreterImpl::nameMatch(const std::string& transitionEvent, const std::s
bool InterpreterImpl::hasConditionMatch(const Arabica::DOM::Node<std::string>& conditional) {
if (HAS_ATTR(conditional, "cond") && ATTR(conditional, "cond").length() > 0) {
- if (!_dataModel) {
- LOG(ERROR) << "Cannot check a condition without a datamodel";
- return false;
- }
try {
return _dataModel.evalAsBool(ATTR_NODE(conditional, "cond"), ATTR(conditional, "cond"));
} catch (Event e) {
@@ -1445,13 +1552,7 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node<std::string>& cont
return;
}
- // --- MONITOR: beforeExecutingContent ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeExecutingContent(shared_from_this(), Element<std::string>(content));
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeExecutingContent)
- }
+ USCXML_MONITOR_CALLBACK2(beforeExecutingContent, Element<std::string>(content))
if (false) {
} else if (iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "raise")) {
@@ -1712,14 +1813,32 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node<std::string>& cont
execContent.exitElement(content);
}
- // --- MONITOR: afterExecutingContent ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterExecutingContent(shared_from_this(), Element<std::string>(content));
+ USCXML_MONITOR_CALLBACK2(afterExecutingContent, Element<std::string>(content))
+
+}
+
+void InterpreterImpl::finalizeAndAutoForwardCurrentEvent() {
+ for (std::map<std::string, Invoker>::iterator invokeIter = _invokers.begin();
+ invokeIter != _invokers.end();
+ invokeIter++) {
+ if (iequals(invokeIter->first, _currEvent.invokeid)) {
+ Arabica::XPath::NodeSet<std::string> finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", invokeIter->second.getElement());
+ for (int k = 0; k < finalizes.size(); k++) {
+ Element<std::string> finalizeElem = Element<std::string>(finalizes[k]);
+ executeContent(finalizeElem);
+ }
+ }
+ if (HAS_ATTR(invokeIter->second.getElement(), "autoforward") && DOMUtils::attributeIsTrue(ATTR(invokeIter->second.getElement(), "autoforward"))) {
+ try {
+ // do not autoforward to invokers that send to #_parent from the SCXML IO Processor!
+ // Yes do so, see test229!
+ // if (!boost::equals(_currEvent.getOriginType(), "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"))
+ invokeIter->second.send(_currEvent);
+ } catch(...) {
+ LOG(ERROR) << "Exception caught while sending event to invoker " << invokeIter->first;
+ }
}
- USCXML_MONITOR_CATCH_BLOCK(afterExecutingContent)
}
-
}
void InterpreterImpl::returnDoneEvent(const Arabica::DOM::Node<std::string>& state) {
@@ -2497,10 +2616,38 @@ void InterpreterImpl::DOMEventListener::handleEvent(Arabica::DOM::Events::Event<
}
}
-void InterpreterImpl::dump() {
- if (!_document)
- return;
- std::cout << _document;
+std::ostream& operator<< (std::ostream& os, const InterpreterState& interpreterState) {
+ os << "[" << InterpreterState::stateToString(interpreterState.state) << "]:" << std::endl;
+ os << interpreterState.msg;
+ return os;
+}
+
+std::string InterpreterState::stateToString(int32_t state) {
+ std::stringstream ss;
+
+ switch(state & USCXML_INTERPRETER_MASK) {
+ case USCXML_INSTANTIATED: ss << "INSTANTIATED"; break;
+ case USCXML_FAULTED: ss << "FAULTED"; break;
+ case USCXML_MICROSTEPPED: ss << "MICROSTEPPED"; break;
+ case USCXML_MACROSTEPPED: ss << "MACROSTEPPED"; break;
+ case USCXML_IDLE: ss << "IDLE"; break;
+ case USCXML_FINISHED: ss << "FINISHED"; break;
+ case USCXML_DESTROYED: ss << "DESTROYED"; break;
+ default: ss << "INVALID"; break;
+ }
+
+ if (state & USCXML_THREAD_STARTED) {
+ ss << ", " << "STARTED";
+ } else {
+ ss << ", " << "STOPPED";
+ }
+ if (state & USCXML_THREAD_RUNNING) {
+ ss << ", " << "RUNNING";
+ } else {
+ ss << ", " << "JOINED";
+ }
+
+ return ss.str();
}
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
index 3a02cb7..81ccdb9 100644
--- a/src/uscxml/Interpreter.h
+++ b/src/uscxml/Interpreter.h
@@ -48,16 +48,41 @@
#include "uscxml/server/InterpreterServlet.h"
-#define USCXML_MONITOR_CATCH_BLOCK(callback)\
-catch (Event e) {\
- LOG(ERROR) << "Syntax error when calling " #callback " on monitors: " << std::endl << e << std::endl;\
-} catch (boost::bad_weak_ptr e) {\
- LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;\
-} catch (...) {\
- LOG(ERROR) << "An exception occured when calling " #callback " on monitors";\
-}\
-if (_destroyed) {\
- throw boost::bad_weak_ptr();\
+#define USCXML_MONITOR_CATCH(callback) \
+catch (Event e) { \
+ LOG(ERROR) << "Syntax error when calling " #callback " on monitors: " << std::endl << e << std::endl; \
+} catch (boost::bad_weak_ptr e) { \
+ LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl; \
+} catch (...) { \
+ LOG(ERROR) << "An exception occured when calling " #callback " on monitors"; \
+} \
+if (_state == InterpreterState::USCXML_DESTROYED) { \
+ throw boost::bad_weak_ptr(); \
+} \
+
+
+#define USCXML_MONITOR_CALLBACK(callback)\
+for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) { \
+ try { \
+ (*monIter)->callback(shared_from_this()); \
+ } \
+ USCXML_MONITOR_CATCH(callback) \
+}
+
+#define USCXML_MONITOR_CALLBACK2(callback, arg1)\
+for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) { \
+ try { \
+ (*monIter)->callback(shared_from_this(), arg1); \
+ } \
+ USCXML_MONITOR_CATCH(callback) \
+}
+
+#define USCXML_MONITOR_CALLBACK3(callback, arg1, arg2)\
+for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) { \
+ try { \
+ (*monIter)->callback(shared_from_this(), arg1, arg2); \
+ } \
+ USCXML_MONITOR_CATCH(callback) \
}
namespace uscxml {
@@ -172,6 +197,12 @@ public:
attribute.setPrefix(nsToPrefix[nsURL]);
}
+ std::string getXMLPrefixForNS(const std::string& ns) const {
+ if (nsToPrefix.find(ns) != nsToPrefix.end() && nsToPrefix.at(ns).size())
+ return nsToPrefix.at(ns) + ":";
+ return "";
+ }
+
const Arabica::XPath::StandardNamespaceContext<std::string>* getNSContext() {
return nsContext;
}
@@ -188,16 +219,56 @@ private:
void init(const std::map<std::string, std::string>& nsInfo);
};
-// values larger than 0 indicate that you ought to step again
-enum InterpreterState {
- FINISHED = 0, // machine reached a final configuration
- INIT_FAILED = -1, // could not initialize interpreter
- INTERRUPTED = -2, // machine was interrupted
- NOTHING_TODO = 4, // when non-blocking returns nothing to do
- PROCESSED = 8, // an event was processed
- INITIALIZED = 16 // initial stable configuration was assumed
-};
+struct USCXML_API InterpreterState {
+ // see: http://stackoverflow.com/questions/18591924/how-to-use-bitmask
+ enum State {
+ USCXML_DESTROYED = 0x0001, //
+ USCXML_INSTANTIATED = 0x0002, // nothing really, just instantiated
+ USCXML_MICROSTEPPED = 0x0004, //
+ USCXML_MACROSTEPPED = 0x0008, //
+ USCXML_IDLE = 0x0010, //
+ USCXML_FAULTED = 0x0020, // something went very wrong
+ USCXML_FINISHED = 0x0040, // machine reached a final configuration
+ };
+
+ enum ThreadState {
+ USCXML_THREAD_RUNNING = 0x0100, //
+ USCXML_THREAD_STARTED = 0x0200, //
+ };
+
+ enum BitMask {
+ USCXML_THREAD_MASK = 0xff00,
+ USCXML_INTERPRETER_MASK = 0x00ff,
+ };
+
+ bool operator==(const InterpreterState& other) const {
+ return state == other.state && msg == other.msg;
+ }
+ bool operator!=(const InterpreterState& other) const {
+ return !(*this == other);
+ }
+
+ operator int() {
+ return (int)(state | thread);
+ }
+
+ Event getMessage() {
+ return msg;
+ }
+
+ static std::string stateToString(int32_t state);
+
+ friend USCXML_API std::ostream& operator<< (std::ostream& os, const InterpreterState& interpreterState);
+ friend USCXML_API class InterpreterImpl;
+protected:
+ int32_t thread;
+ State state;
+ Event msg;
+};
+
+USCXML_API std::ostream& operator<< (std::ostream& os, const InterpreterState& interpreterState);
+
class USCXML_API InterpreterImpl : public boost::enable_shared_from_this<InterpreterImpl> {
public:
@@ -213,20 +284,18 @@ public:
void copyTo(InterpreterImpl* other);
void copyTo(boost::shared_ptr<InterpreterImpl> other);
- void start();
- void stop();
- static void run(void*);
- void join() {
- if (_thread != NULL) _thread->join();
- };
- bool isRunning() {
- return _running || !_done;
- }
+ // TODO: Look into that pure virtual issue and make these abstract!
+ virtual InterpreterState interpret() { return _state; } ///< Start interpreter blockingly
+ virtual InterpreterState step(int waitForMS = 0) { return _state; }; ///< Perform a single step
- /// This one ought to be pure, but SWIG will generate gibberish if it is
- virtual void interpret() = 0;
- virtual InterpreterState step(bool blocking = false) = 0;
+ void start(); ///< Start interpretation in a thread
+ void stop(); ///< Stop interpreter thread
+ void reset(); ///< Reset state machine
+ void join();
+ bool isRunning();
+ InterpreterState getInterpreterState();
+
void addMonitor(InterpreterMonitor* monitor) {
_monitors.insert(monitor);
}
@@ -261,9 +330,11 @@ public:
DataModel getDataModel() {
return _dataModel;
}
+
void setParentQueue(uscxml::concurrency::BlockingQueue<SendRequest>* parentQueue) {
_parentQueue = parentQueue;
}
+
void setFactory(Factory* factory) {
_factory = factory;
}
@@ -275,12 +346,6 @@ public:
return _xpath.evaluate(xpathExpr, _scxml).asNodeSet();
}
- std::string getXMLPrefixForNS(const std::string& ns) const {
- if (_nsInfo.nsToPrefix.find(ns) != _nsInfo.nsToPrefix.end() && _nsInfo.nsToPrefix.at(ns).size())
- return _nsInfo.nsToPrefix.at(ns) + ":";
- return "";
- }
-
void setNameSpaceInfo(const NameSpaceInfo& nsInfo) {
_nsInfo = nsInfo;
_xpath.setNamespaceContext(*_nsInfo.getNSContext());
@@ -314,17 +379,13 @@ public:
return basicConfig;
}
- void setConfiguration(const std::vector<std::string>& states) {
+ void setInitalConfiguration(const std::vector<std::string>& states) {
_userDefinedStartConfiguration = states;
}
void setInvokeRequest(const InvokeRequest& req) {
_invokeReq = req;
}
- Arabica::DOM::Node<std::string> getState(const std::string& stateId);
- Arabica::XPath::NodeSet<std::string> getStates(const std::list<std::string>& stateIds);
- Arabica::XPath::NodeSet<std::string> getAllStates();
-
virtual Arabica::DOM::Document<std::string> getDocument() const {
return _document;
}
@@ -357,7 +418,6 @@ public:
static bool isMember(const Arabica::DOM::Node<std::string>& node, const Arabica::XPath::NodeSet<std::string>& set);
- void dump();
bool hasLegalConfiguration();
bool isLegalConfiguration(const Arabica::XPath::NodeSet<std::string>&);
bool isLegalConfiguration(const std::vector<std::string>&);
@@ -372,13 +432,13 @@ public:
static bool isParallel(const Arabica::DOM::Node<std::string>& state);
static bool isCompound(const Arabica::DOM::Node<std::string>& state);
static bool isDescendant(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2);
-
- static std::list<std::string> tokenizeIdRefs(const std::string& idRefs);
- static std::string spaceNormalize(const std::string& text);
- static bool nameMatch(const std::string& transitionEvent, const std::string& event);
-
bool isInEmbeddedDocument(const Arabica::DOM::Node<std::string>& node);
bool isInitial(const Arabica::DOM::Node<std::string>& state);
+
+ Arabica::DOM::Node<std::string> getState(const std::string& stateId);
+ Arabica::XPath::NodeSet<std::string> getStates(const std::list<std::string>& stateIds);
+ Arabica::XPath::NodeSet<std::string> getAllStates();
+
Arabica::XPath::NodeSet<std::string> getInitialStates(Arabica::DOM::Node<std::string> state = Arabica::DOM::Node<std::string>());
static Arabica::XPath::NodeSet<std::string> getChildStates(const Arabica::DOM::Node<std::string>& state);
static Arabica::XPath::NodeSet<std::string> getChildStates(const Arabica::XPath::NodeSet<std::string>& state);
@@ -392,11 +452,17 @@ public:
static Arabica::XPath::NodeSet<std::string> filterChildElements(const std::string& tagName, const Arabica::XPath::NodeSet<std::string>& nodeSet, bool recurse = false);
static Arabica::XPath::NodeSet<std::string> filterChildType(const Arabica::DOM::Node_base::Type type, const Arabica::DOM::Node<std::string>& node, bool recurse = false);
static Arabica::XPath::NodeSet<std::string> filterChildType(const Arabica::DOM::Node_base::Type type, const Arabica::XPath::NodeSet<std::string>& nodeSet, bool recurse = false);
+
+ static std::list<std::string> tokenizeIdRefs(const std::string& idRefs);
+ static std::string spaceNormalize(const std::string& text);
+ static bool nameMatch(const std::string& transitionEvent, const std::string& event);
Arabica::DOM::Node<std::string> findLCCA(const Arabica::XPath::NodeSet<std::string>& states);
virtual Arabica::XPath::NodeSet<std::string> getProperAncestors(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2);
protected:
+ static void run(void*); // static method for thread to run
+
class DOMEventListener : public Arabica::DOM::Events::EventListener<std::string> {
public:
void handleEvent(Arabica::DOM::Events::Event<std::string>& event);
@@ -405,17 +471,23 @@ protected:
InterpreterImpl();
void init();
+ void setupAndNormalizeDOM();
+ virtual void setupIOProcessors();
- void normalize(Arabica::DOM::Element<std::string>& scxml);
void initializeData(const Arabica::DOM::Element<std::string>& data);
- virtual void setupIOProcessors();
+ void finalizeAndAutoForwardCurrentEvent();
+ void setInterpreterState(InterpreterState::State newState, const std::string& error);
+ void setInterpreterState(InterpreterState::State newState, const Event& error);
+ void setInterpreterState(InterpreterState::State newState);
+
bool _stable;
tthread::thread* _thread;
tthread::recursive_mutex _mutex;
tthread::condition_variable _condVar;
tthread::recursive_mutex _pluginMutex;
+ InterpreterState _state;
URL _baseURI;
URL _sourceURI;
Arabica::DOM::Document<std::string> _document;
@@ -423,10 +495,10 @@ protected:
Arabica::XPath::XPath<std::string> _xpath;
NameSpaceInfo _nsInfo;
- bool _running;
- bool _done;
- bool _destroyed; // see comment in destructor
+ bool _topLevelFinalReached;
bool _isInitialized;
+ bool _domIsSetup;
+
InterpreterImpl::Binding _binding;
Arabica::XPath::NodeSet<std::string> _configuration;
Arabica::XPath::NodeSet<std::string> _alreadyEntered;
@@ -450,6 +522,13 @@ protected:
InterpreterWebSocketServlet* _wsServlet;
std::set<InterpreterMonitor*> _monitors;
+ long _lastRunOnMainThread;
+ std::string _name;
+ std::string _sessionId;
+ unsigned int _capabilities;
+
+ Data _cmdLineOptions;
+
virtual void executeContent(const Arabica::DOM::Node<std::string>& content, bool rethrow = false);
virtual void executeContent(const Arabica::DOM::NodeList<std::string>& content, bool rethrow = false);
virtual void executeContent(const Arabica::XPath::NodeSet<std::string>& content, bool rethrow = false);
@@ -475,13 +554,6 @@ protected:
bool isInFinalState(const Arabica::DOM::Node<std::string>& state);
bool parentIsScxmlState(const Arabica::DOM::Node<std::string>& state);
- long _lastRunOnMainThread;
- std::string _name;
- std::string _sessionId;
- unsigned int _capabilities;
-
- Data _cmdLineOptions;
-
IOProcessor getIOProcessor(const std::string& type);
std::map<std::string, IOProcessor> _ioProcessors;
@@ -489,7 +561,7 @@ protected:
std::map<std::string, Invoker> _invokers;
std::map<Arabica::DOM::Node<std::string>, ExecutableContent> _executableContent;
- /// TODO: We need to remember to adapt them when the DOM is operated upon
+ /// TODO: We need to adapt them when the DOM is operated upon
std::map<std::string, Arabica::DOM::Node<std::string> > _cachedStates;
std::map<std::string, URL> _cachedURLs;
@@ -504,7 +576,6 @@ public:
const NameSpaceInfo& nameSpaceInfo);
static Interpreter fromXML(const std::string& xml);
static Interpreter fromURI(const std::string& uri);
- static Interpreter fromInputSource(Arabica::SAX::InputSource<std::string>& source);
static Interpreter fromClone(const Interpreter& other);
Interpreter() : _impl() {} // the empty, invalid interpreter
@@ -513,7 +584,9 @@ public:
virtual ~Interpreter() {};
operator bool() const {
- return _impl;
+ return (_impl &&
+ _impl->_state != InterpreterState::USCXML_FAULTED &&
+ _impl->_state != InterpreterState::USCXML_DESTROYED);
}
bool operator< (const Interpreter& other) const {
return _impl < other._impl;
@@ -529,15 +602,19 @@ public:
return *this;
}
+ void reset() {
+ return _impl->reset();
+ }
+
void start() {
return _impl->start();
}
void stop() {
return _impl->stop();
}
- void join() {
- return _impl->join();
- };
+// void join() {
+// return _impl->join();
+// };
bool isRunning() {
return _impl->isRunning();
}
@@ -546,10 +623,20 @@ public:
_impl->interpret();
};
- InterpreterState step(bool blocking = false) {
- return _impl->step(blocking);
+ InterpreterState step(int waitForMS = 0) {
+ return _impl->step(waitForMS);
+ };
+
+ InterpreterState step(bool blocking) {
+ if (blocking)
+ return _impl->step(-1);
+ return _impl->step(0);
};
+ InterpreterState getState() {
+ return _impl->getInterpreterState();
+ }
+
void addMonitor(InterpreterMonitor* monitor) {
return _impl->addMonitor(monitor);
}
@@ -568,10 +655,6 @@ public:
return _impl->getBaseURI();
}
- std::string getXMLPrefixForNS(const std::string& ns) const {
- return _impl->getXMLPrefixForNS(ns);
- }
-
void setNameSpaceInfo(const NameSpaceInfo& nsInfo) {
_impl->setNameSpaceInfo(nsInfo);
}
@@ -629,22 +712,19 @@ public:
return _impl->getBasicConfiguration();
}
- void setConfiguration(const std::vector<std::string>& states) {
- return _impl->setConfiguration(states);
- }
- void setInvokeRequest(const InvokeRequest& req) {
- return _impl->setInvokeRequest(req);
+ void setInitalConfiguration(const std::vector<std::string>& states) {
+ return _impl->setInitalConfiguration(states);
}
- Arabica::DOM::Node<std::string> getState(const std::string& stateId) {
- return _impl->getState(stateId);
- }
- Arabica::XPath::NodeSet<std::string> getStates(const std::list<std::string>& stateIds) {
- return _impl->getStates(stateIds);
- }
- Arabica::XPath::NodeSet<std::string> getAllStates() {
- return _impl->getAllStates();
- }
+// Arabica::DOM::Node<std::string> getState(const std::string& stateId) {
+// return _impl->getState(stateId);
+// }
+// Arabica::XPath::NodeSet<std::string> getStates(const std::list<std::string>& stateIds) {
+// return _impl->getStates(stateIds);
+// }
+// Arabica::XPath::NodeSet<std::string> getAllStates() {
+// return _impl->getAllStates();
+// }
Arabica::DOM::Document<std::string> getDocument() const {
return _impl->getDocument();
@@ -680,13 +760,6 @@ public:
return _impl->runOnMainThread(fps, blocking);
}
- static bool isMember(const Arabica::DOM::Node<std::string>& node, const Arabica::XPath::NodeSet<std::string>& set) {
- return InterpreterImpl::isMember(node, set);
- }
-
- void dump() {
- return _impl->dump();
- }
bool hasLegalConfiguration() {
return _impl->hasLegalConfiguration();
}
@@ -699,98 +772,6 @@ public:
return _impl->isLegalConfiguration(config);
}
-#if 0
- static bool isState(const Arabica::DOM::Node<std::string>& state) {
- return InterpreterImpl::isState(state);
- }
- static bool isPseudoState(const Arabica::DOM::Node<std::string>& state) {
- return InterpreterImpl::isPseudoState(state);
- }
- static bool isTransitionTarget(const Arabica::DOM::Node<std::string>& elem) {
- return InterpreterImpl::isTransitionTarget(elem);
- }
- static bool isTargetless(const Arabica::DOM::Node<std::string>& transition) {
- return InterpreterImpl::isTargetless(transition);
- }
- static bool isAtomic(const Arabica::DOM::Node<std::string>& state) {
- return InterpreterImpl::isAtomic(state);
- }
- static bool isFinal(const Arabica::DOM::Node<std::string>& state) {
- return InterpreterImpl::isFinal(state);
- }
- static bool isHistory(const Arabica::DOM::Node<std::string>& state) {
- return InterpreterImpl::isHistory(state);
- }
- static bool isParallel(const Arabica::DOM::Node<std::string>& state) {
- return InterpreterImpl::isParallel(state);
- }
- static bool isCompound(const Arabica::DOM::Node<std::string>& state) {
- return InterpreterImpl::isCompound(state);
- }
- static bool isDescendant(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2) {
- return InterpreterImpl::isDescendant(s1, s2);
- }
-
- static std::list<std::string> tokenizeIdRefs(const std::string& idRefs) {
- return InterpreterImpl::tokenizeIdRefs(idRefs);
- }
- static bool nameMatch(const std::string& transitionEvent, const std::string& event) {
- return InterpreterImpl::nameMatch(transitionEvent, event);
- }
-
- static std::string spaceNormalize(const std::string& text) {
- return InterpreterImpl::spaceNormalize(text);
- }
-
- bool isInitial(const Arabica::DOM::Node<std::string>& state) {
- return _impl->isInitial(state);
- }
- Arabica::XPath::NodeSet<std::string> getInitialStates(Arabica::DOM::Node<std::string> state = Arabica::DOM::Node<std::string>()) {
- return _impl->getInitialStates(state);
- }
- static Arabica::XPath::NodeSet<std::string> getChildStates(const Arabica::DOM::Node<std::string>& state) {
- return InterpreterImpl::getChildStates(state);
- }
- static Arabica::XPath::NodeSet<std::string> getChildStates(const Arabica::XPath::NodeSet<std::string>& state) {
- return InterpreterImpl::getChildStates(state);
- }
- static Arabica::DOM::Node<std::string> getParentState(const Arabica::DOM::Node<std::string>& element) {
- return InterpreterImpl::getParentState(element);
- }
- static Arabica::DOM::Node<std::string> getAncestorElement(const Arabica::DOM::Node<std::string>& node, const std::string tagName) {
- return InterpreterImpl::getAncestorElement(node, tagName);
- }
- Arabica::XPath::NodeSet<std::string> getTargetStates(const Arabica::DOM::Node<std::string>& transition) {
- return _impl->getTargetStates(transition);
- }
- Arabica::XPath::NodeSet<std::string> getTargetStates(const Arabica::XPath::NodeSet<std::string>& transitions) {
- return _impl->getTargetStates(transitions);
- }
- Arabica::DOM::Node<std::string> getSourceState(const Arabica::DOM::Node<std::string>& transition) {
- return _impl->getSourceState(transition);
- }
-
- static Arabica::XPath::NodeSet<std::string> filterChildElements(const std::string& tagname, const Arabica::DOM::Node<std::string>& node, bool recurse = false) {
- return InterpreterImpl::filterChildElements(tagname, node, recurse);
- }
- static Arabica::XPath::NodeSet<std::string> filterChildElements(const std::string& tagName, const Arabica::XPath::NodeSet<std::string>& nodeSet, bool recurse = false) {
- return InterpreterImpl::filterChildElements(tagName, nodeSet, recurse);
- }
- static Arabica::XPath::NodeSet<std::string> filterChildType(const Arabica::DOM::Node_base::Type type, const Arabica::DOM::Node<std::string>& node, bool recurse = false) {
- return InterpreterImpl::filterChildType(type, node, recurse);
- }
- static Arabica::XPath::NodeSet<std::string> filterChildType(const Arabica::DOM::Node_base::Type type, const Arabica::XPath::NodeSet<std::string>& nodeSet, bool recurse = false) {
- return InterpreterImpl::filterChildType(type, nodeSet, recurse);
- }
-
- Arabica::DOM::Node<std::string> findLCCA(const Arabica::XPath::NodeSet<std::string>& states) {
- return _impl->findLCCA(states);
- }
- Arabica::XPath::NodeSet<std::string> getProperAncestors(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2) {
- return _impl->getProperAncestors(s1, s2);
- }
-#endif
-
boost::shared_ptr<InterpreterImpl> getImpl() const {
return _impl;
}
@@ -798,6 +779,13 @@ public:
static std::map<std::string, boost::weak_ptr<InterpreterImpl> > getInstances();
protected:
+
+ void setInvokeRequest(const InvokeRequest& req) {
+ return _impl->setInvokeRequest(req);
+ }
+
+ static Interpreter fromInputSource(Arabica::SAX::InputSource<std::string>& source);
+
boost::shared_ptr<InterpreterImpl> _impl;
static std::map<std::string, boost::weak_ptr<InterpreterImpl> > _instances;
static tthread::recursive_mutex _instanceMutex;
diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp
index 0a0eed0..1ac3573 100644
--- a/src/uscxml/Message.cpp
+++ b/src/uscxml/Message.cpp
@@ -673,6 +673,29 @@ std::ostream& operator<< (std::ostream& os, const Event& event) {
os << indent << " origin: " << event.origin << std::endl;
if (event.origintype.size() > 0)
os << indent << " origintype: " << event.origintype << std::endl;
+ if (event.params.size() > 0) {
+ std::multimap<std::string, Data>::const_iterator paramIter = event.params.begin();
+ os << indent << " params:" << std::endl;
+ _dataIndentation++;
+ while(paramIter != event.params.end()) {
+ os << indent << " " << paramIter->first << ": ";
+ os << indent << paramIter->second << std::endl;
+ paramIter++;
+ }
+ _dataIndentation--;
+ }
+ if (event.namelist.size() > 0) {
+ std::map<std::string, Data>::const_iterator namelistIter = event.namelist.begin();
+ os << indent << " namelist:" << std::endl;
+ _dataIndentation++;
+ while(namelistIter != event.namelist.end()) {
+ os << indent << " " << namelistIter->first << ": ";
+ os << indent << namelistIter->second << std::endl;
+ namelistIter++;
+ }
+ _dataIndentation--;
+
+ }
_dataIndentation++;
os << indent << " data: " << event.data << std::endl;
_dataIndentation--;
diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h
index 27b2ac5..44d9207 100644
--- a/src/uscxml/Message.h
+++ b/src/uscxml/Message.h
@@ -279,6 +279,16 @@ public:
return this < &other;
}
+ bool operator==(const Event& other) const {
+ return (this->name == other.name &&
+ this->sendid == other.sendid &&
+ this->invokeid == other.invokeid &&
+ this->data == other.data);
+ }
+ bool operator!=(const Event& other) const {
+ return !(*this == other);
+ }
+
std::string getName() {
return name;
}
diff --git a/src/uscxml/concurrency/tinythread.h b/src/uscxml/concurrency/tinythread.h
index 0490e4d..a47b46a 100644
--- a/src/uscxml/concurrency/tinythread.h
+++ b/src/uscxml/concurrency/tinythread.h
@@ -428,6 +428,31 @@ public:
#endif
}
+ template <class _mutexT>
+ inline void wait_for(_mutexT &aMutex, unsigned int ms) {
+#if defined(_TTHREAD_WIN32_)
+ // Increment number of waiters
+ EnterCriticalSection(&mWaitersCountLock);
+ ++ mWaitersCount;
+ LeaveCriticalSection(&mWaitersCountLock);
+
+ // Release the mutex while waiting for the condition (will decrease
+ // the number of waiters when done)...
+ aMutex.unlock();
+ _wait(ms);
+ aMutex.lock();
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ struct timespec ts;
+ ts.tv_sec = tv.tv_sec + (ms / 1000);
+ ts.tv_nsec = (tv.tv_usec * 1000); // convert tv microseconds to nanoseconds
+ ts.tv_nsec += (ms % 1000) * 1000000; // add millisecond part of wait time
+ pthread_cond_timedwait(&mHandle, &aMutex.mHandle, &ts);
+#endif
+ }
+
/// Notify one thread that is waiting for the condition.
/// If at least one thread is blocked waiting for this condition variable,
/// one will be woken up.
diff --git a/src/uscxml/debug/Breakpoint.cpp b/src/uscxml/debug/Breakpoint.cpp
index 54f5d75..e66e0fb 100644
--- a/src/uscxml/debug/Breakpoint.cpp
+++ b/src/uscxml/debug/Breakpoint.cpp
@@ -238,7 +238,7 @@ bool Breakpoint::matches(Interpreter interpreter, const Breakpoint& other) const
} catch (...) {
return false;
}
- return Interpreter::isMember(other.element, nodes);
+ return InterpreterImpl::isMember(other.element, nodes);
}
if(transSourceId.length() > 0 && transSourceId != other.transSourceId) {
diff --git a/src/uscxml/debug/SCXMLDotWriter.cpp b/src/uscxml/debug/SCXMLDotWriter.cpp
index 93f09ab..2bccb14 100644
--- a/src/uscxml/debug/SCXMLDotWriter.cpp
+++ b/src/uscxml/debug/SCXMLDotWriter.cpp
@@ -130,13 +130,13 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Arabica::DOM::Ele
os << "shape=doublecircle,";
// is the current state in the basic configuration?
- if (_interpreter.isMember(elem, _interpreter.getBasicConfiguration()))
+ if (InterpreterImpl::isMember(elem, _interpreter.getBasicConfiguration()))
os << "color=red, penwidth=3,";
// is the current state a target state?
#if 0
for (int i = 0; i < _transitions.size(); i++) {
- if (_interpreter.isMember(elem, _interpreter.getTargetStates(_transitions[i]))) {
+ if (InterpreterImpl::isMember(elem, _interpreter.getTargetStates(_transitions[i]))) {
os << "color=red, penwidth=3,";
break;
}
diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp
index 12d6123..5e64e66 100644
--- a/src/uscxml/interpreter/InterpreterDraft6.cpp
+++ b/src/uscxml/interpreter/InterpreterDraft6.cpp
@@ -32,22 +32,18 @@ using namespace Arabica::DOM;
// see: http://www.w3.org/TR/scxml/#AlgorithmforSCXMLInterpretation
-void InterpreterDraft6::interpret() {
+InterpreterState InterpreterDraft6::interpret() {
InterpreterState state;
while(true) {
- state = step(true);
+ state = step(-1);
- switch (state) {
- case uscxml::INIT_FAILED:
- case uscxml::FINISHED:
- case uscxml::INTERRUPTED:
+ switch (state & InterpreterState::USCXML_INTERPRETER_MASK) {
+ case uscxml::InterpreterState::USCXML_FAULTED:
+ case uscxml::InterpreterState::USCXML_FINISHED:
+ case uscxml::InterpreterState::USCXML_DESTROYED:
// return as we finished
- return;
- case uscxml::NOTHING_TODO:
- // die as this can never happen with a blocking call
- assert(false);
- case uscxml::INITIALIZED:
- case uscxml::PROCESSED:
+ return state;
+ default:
// process invokers on main thread
if(_thread == NULL) {
@@ -58,6 +54,7 @@ void InterpreterDraft6::interpret() {
break;
}
}
+ return state;
}
// setup / fetch the documents initial transitions
@@ -117,74 +114,130 @@ NodeSet<std::string> InterpreterDraft6::getDocumentInitialTransitions() {
}
return initialTransitions;
}
-
-// a macrostep
-InterpreterState InterpreterDraft6::step(bool blocking) {
+
+InterpreterState InterpreterDraft6::step(int waitForMS = 0) {
try {
tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
- monIter_t monIter;
+ if (_state & InterpreterState::USCXML_FINISHED ||
+ _state & InterpreterState::USCXML_FAULTED ||
+ _state & InterpreterState::USCXML_DESTROYED) {
+ return _state;
+ }
+
NodeSet<std::string> enabledTransitions;
// setup document and interpreter
- if (!_isInitialized)
- init();
-
- // if we failed return false
- if (!_isInitialized)
- return INIT_FAILED;
-
- // run initial transitions
- if (!_stable) {
- stabilize();
- // we might only need a single step
- if (!_running)
- goto EXIT_INTERPRETER;
- return INITIALIZED;
+ if (!_isInitialized) {
+ init(); // will throw
}
- if (!_running)
- return FINISHED;
+ if (_configuration.size() == 0) {
+ // goto initial configuration
+ NodeSet<std::string> initialTransitions = getDocumentInitialTransitions();
+ assert(initialTransitions.size() > 0);
+ enterStates(initialTransitions);
+ }
+
+ _stable = false;
- // read an external event and react
- if (blocking) {
+ // are there spontaneous transitions?
+ enabledTransitions = selectEventlessTransitions();
+ if (!enabledTransitions.empty()) {
+ // test 403b
+ enabledTransitions.to_document_order();
+ microstep(enabledTransitions);
- // wait until an event becomes available
- while(_externalQueue.isEmpty()) {
- _condVar.wait(_mutex);
- }
- } else {
- // return immediately if external queue is empty
- if (_externalQueue.isEmpty())
- return NOTHING_TODO;
+ setInterpreterState(InterpreterState::USCXML_MICROSTEPPED);
+ return _state;
}
- _currEvent = _externalQueue.pop();
- #if VERBOSE
- std::cout << "Received externalEvent event " << _currEvent.name << std::endl;
- if (_running && _currEvent.name == "unblock.and.die") {
- std::cout << "Still running " << this << std::endl;
+ // test415
+ if (_topLevelFinalReached)
+ goto EXIT_INTERPRETER;
+
+ // process internal event
+ if (!_internalQueue.empty()) {
+ _currEvent = _internalQueue.front();
+ _internalQueue.pop_front();
+
+ USCXML_MONITOR_CALLBACK2(beforeProcessingEvent, _currEvent)
+
+ if (_dataModel)
+ _dataModel.setEvent(_currEvent);
+ enabledTransitions = selectTransitions(_currEvent.name);
+
+ if (!enabledTransitions.empty()) {
+ // test 403b
+ enabledTransitions.to_document_order();
+ microstep(enabledTransitions);
+ }
+
+ // test 319 - even if we do not enable transitions, consider it a microstep
+ setInterpreterState(InterpreterState::USCXML_MICROSTEPPED);
+ return _state;
+
} else {
- std::cout << "Aborting " << this << std::endl;
+ _stable = true;
}
- #endif
- _currEvent.eventType = Event::EXTERNAL; // make sure it is set to external
+ // even if we did nothing - count as microstep
+ setInterpreterState(InterpreterState::USCXML_MICROSTEPPED);
- // when we were blocking on destructor invocation
- if (!_running) {
+ if (_topLevelFinalReached)
goto EXIT_INTERPRETER;
- return INTERRUPTED;
+
+ setInterpreterState(InterpreterState::USCXML_MACROSTEPPED);
+ USCXML_MONITOR_CALLBACK(onStableConfiguration)
+
+ // when we reach a stable configuration, invoke
+ for (unsigned int i = 0; i < _statesToInvoke.size(); i++) {
+ NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _statesToInvoke[i]);
+ for (unsigned int j = 0; j < invokes.size(); j++) {
+ if (!HAS_ATTR(invokes[j], "persist") || !DOMUtils::attributeIsTrue(ATTR(invokes[j], "persist"))) {
+ invoke(invokes[j]);
+ }
+ }
}
- // --- MONITOR: beforeProcessingEvent ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
+ _statesToInvoke = NodeSet<std::string>();
+
+ if (_externalQueue.isEmpty()) {
+ setInterpreterState(InterpreterState::USCXML_IDLE);
+
+ if (waitForMS < 0) {
+ // wait blockingly for an event forever
+ while(_externalQueue.isEmpty()) {
+ _condVar.wait(_mutex);
+ }
+ }
+
+ if (waitForMS > 0) {
+ // wait given number of milliseconds max
+ uint64_t now = tthread::chrono::system_clock::now();
+ uint64_t then = now + waitForMS;
+ while(_externalQueue.isEmpty() && now < then) {
+ _condVar.wait_for(_mutex, then - now);
+ now = tthread::chrono::system_clock::now();
+ }
+ }
+
+ if (_externalQueue.isEmpty()) {
+ return _state;
}
- USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
+
+ setInterpreterState(InterpreterState::USCXML_MACROSTEPPED);
}
- if (iequals(_currEvent.name, "cancel.invoke." + _sessionId))
- return INTERRUPTED;
+ _currEvent = _externalQueue.pop();
+ _currEvent.eventType = Event::EXTERNAL; // make sure it is set to external
+
+ if (_topLevelFinalReached)
+ goto EXIT_INTERPRETER;
+
+ USCXML_MONITOR_CALLBACK2(beforeProcessingEvent, _currEvent)
+
+ if (iequals(_currEvent.name, "cancel.invoke." + _sessionId)) {
+ goto EXIT_INTERPRETER;
+ }
try {
_dataModel.setEvent(_currEvent);
@@ -192,28 +245,7 @@ InterpreterState InterpreterDraft6::step(bool blocking) {
LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl << _currEvent;
}
- for (std::map<std::string, Invoker>::iterator invokeIter = _invokers.begin();
- invokeIter != _invokers.end();
- invokeIter++) {
- if (iequals(invokeIter->first, _currEvent.invokeid)) {
- Arabica::XPath::NodeSet<std::string> finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", invokeIter->second.getElement());
- for (int k = 0; k < finalizes.size(); k++) {
- Element<std::string> finalizeElem = Element<std::string>(finalizes[k]);
- executeContent(finalizeElem);
- }
- }
- if (HAS_ATTR(invokeIter->second.getElement(), "autoforward") && DOMUtils::attributeIsTrue(ATTR(invokeIter->second.getElement(), "autoforward"))) {
- try {
- // do not autoforward to invokers that send to #_parent from the SCXML IO Processor!
- // Yes do so, see test229!
- // if (!boost::equals(_currEvent.getOriginType(), "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"))
- invokeIter->second.send(_currEvent);
- } catch(...) {
- LOG(ERROR) << "Exception caught while sending event to invoker " << invokeIter->first;
- }
- }
- }
-
+ finalizeAndAutoForwardCurrentEvent();
// run internal processing until we reach a stable configuration again
enabledTransitions = selectTransitions(_currEvent.name);
@@ -223,50 +255,42 @@ InterpreterState InterpreterDraft6::step(bool blocking) {
microstep(enabledTransitions);
}
- stabilize();
- return PROCESSED;
+ if (_topLevelFinalReached)
+ goto EXIT_INTERPRETER;
+ return _state;
+
EXIT_INTERPRETER:
- if (!_running) {
- // --- MONITOR: beforeCompletion ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeCompletion(shared_from_this());
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeCompletion)
- }
-
- exitInterpreter();
- if (_sendQueue) {
- std::map<std::string, std::pair<InterpreterImpl*, SendRequest> >::iterator sendIter = _sendIds.begin();
- while(sendIter != _sendIds.end()) {
- _sendQueue->cancelEvent(sendIter->first);
- sendIter++;
- }
- }
-
- // --- MONITOR: afterCompletion ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterCompletion(shared_from_this());
- }
- USCXML_MONITOR_CATCH_BLOCK(afterCompletion)
+ USCXML_MONITOR_CALLBACK(beforeCompletion)
+
+ exitInterpreter();
+ if (_sendQueue) {
+ std::map<std::string, std::pair<InterpreterImpl*, SendRequest> >::iterator sendIter = _sendIds.begin();
+ while(sendIter != _sendIds.end()) {
+ _sendQueue->cancelEvent(sendIter->first);
+ sendIter++;
}
- return FINISHED;
}
- assert(hasLegalConfiguration());
+ USCXML_MONITOR_CALLBACK(afterCompletion)
+
+// assert(hasLegalConfiguration());
_mutex.unlock();
// remove datamodel
if(_dataModel)
_dataModel = DataModel();
- return PROCESSED;
+ setInterpreterState(InterpreterState::USCXML_FINISHED);
+ return _state;
+ } catch (Event e) {
+ setInterpreterState(InterpreterState::USCXML_FAULTED, e);
+ return _state;
} catch (boost::bad_weak_ptr e) {
LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
- return INTERRUPTED;
+ setInterpreterState(InterpreterState::USCXML_DESTROYED);
+ return _state;
}
// set datamodel to null from this thread
@@ -278,7 +302,6 @@ InterpreterState InterpreterDraft6::step(bool blocking) {
// process transitions until we are in a stable configuration again
void InterpreterDraft6::stabilize() {
- monIter_t monIter;
NodeSet<std::string> enabledTransitions;
_stable = false;
@@ -303,13 +326,7 @@ void InterpreterDraft6::stabilize() {
std::cout << "Received internal event " << _currEvent.name << std::endl;
#endif
- // --- MONITOR: beforeProcessingEvent ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
- }
+ USCXML_MONITOR_CALLBACK2(beforeProcessingEvent, _currEvent)
if (_dataModel)
_dataModel.setEvent(_currEvent);
@@ -323,16 +340,8 @@ void InterpreterDraft6::stabilize() {
microstep(enabledTransitions);
}
} while(!_internalQueue.empty() || !_stable);
-
- monIter = _monitors.begin();
-
- // --- MONITOR: onStableConfiguration ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->onStableConfiguration(shared_from_this());
- }
- USCXML_MONITOR_CATCH_BLOCK(onStableConfiguration)
- }
+
+ USCXML_MONITOR_CALLBACK(onStableConfiguration)
// when we reach a stable configuration, invoke
for (unsigned int i = 0; i < _statesToInvoke.size(); i++) {
@@ -349,7 +358,6 @@ void InterpreterDraft6::stabilize() {
#if 0
void InterpreterDraft6::mainEventLoop() {
- monIter_t monIter;
while(_running) {
NodeSet<std::string> enabledTransitions;
@@ -377,13 +385,7 @@ void InterpreterDraft6::mainEventLoop() {
std::cout << "Received internal event " << _currEvent.name << std::endl;
#endif
- // --- MONITOR: beforeProcessingEvent ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
- }
+ USCXML_MONITOR_CALLBACK(beforeProcessingEvent)
if (_dataModel)
_dataModel.setEvent(_currEvent);
@@ -413,15 +415,7 @@ void InterpreterDraft6::mainEventLoop() {
// assume that we have a legal configuration as soon as the internal queue is empty
assert(hasLegalConfiguration());
- monIter = _monitors.begin();
-
- // --- MONITOR: onStableConfiguration ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->onStableConfiguration(shared_from_this());
- }
- USCXML_MONITOR_CATCH_BLOCK(onStableConfiguration)
- }
+ USCXML_MONITOR_CALLBACK(onStableConfiguration)
_mutex.unlock();
@@ -447,13 +441,7 @@ void InterpreterDraft6::mainEventLoop() {
if (!_running)
goto EXIT_INTERPRETER;
- // --- MONITOR: beforeProcessingEvent ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
- }
+ USCXML_MONITOR_CALLBACK(beforeProcessingEvent)
if (_dataModel && iequals(_currEvent.name, "cancel.invoke." + _sessionId))
break;
@@ -495,13 +483,7 @@ void InterpreterDraft6::mainEventLoop() {
}
EXIT_INTERPRETER:
- // --- MONITOR: beforeCompletion ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeCompletion(shared_from_this());
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeCompletion)
- }
+ USCXML_MONITOR_CALLBACK(beforeCompletion)
exitInterpreter();
if (_sendQueue) {
@@ -512,13 +494,7 @@ EXIT_INTERPRETER:
}
}
- // --- MONITOR: afterCompletion ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterCompletion(shared_from_this());
- }
- USCXML_MONITOR_CATCH_BLOCK(afterCompletion)
- }
+ USCXML_MONITOR_CALLBACK(afterCompletion)
}
#endif
@@ -760,48 +736,23 @@ void InterpreterDraft6::microstep(const Arabica::XPath::NodeSet<std::string>& en
std::cout << std::endl;
#endif
- // --- MONITOR: beforeMicroStep ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeMicroStep(shared_from_this());
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeMicroStep)
- }
+ USCXML_MONITOR_CALLBACK(beforeMicroStep)
exitStates(enabledTransitions);
- monIter_t monIter;
for (int i = 0; i < enabledTransitions.size(); i++) {
Element<std::string> transition(enabledTransitions[i]);
- // --- MONITOR: beforeTakingTransitions ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeTakingTransition(shared_from_this(), transition, (i + 1 < enabledTransitions.size()));
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeTakingTransitions)
- }
+ USCXML_MONITOR_CALLBACK3(beforeTakingTransition, transition, (i + 1 < enabledTransitions.size()))
executeContent(transition);
- // --- MONITOR: afterTakingTransitions ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterTakingTransition(shared_from_this(), transition, (i + 1 < enabledTransitions.size()));
- }
- USCXML_MONITOR_CATCH_BLOCK(afterTakingTransitions)
- }
+ USCXML_MONITOR_CALLBACK3(afterTakingTransition, transition, (i + 1 < enabledTransitions.size()))
}
enterStates(enabledTransitions);
- // --- MONITOR: afterMicroStep ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterMicroStep(shared_from_this());
- }
- USCXML_MONITOR_CATCH_BLOCK(afterMicroStep)
- }
+ USCXML_MONITOR_CALLBACK(afterMicroStep)
}
@@ -833,7 +784,6 @@ void InterpreterDraft6::exitInterpreter() {
void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
NodeSet<std::string> statesToExit;
- monIter_t monIter;
#if VERBOSE
std::cout << _name << ": Enabled exit transitions: " << std::endl;
@@ -864,7 +814,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
NodeSet<std::string> tmpStates;
tmpStates.push_back(source);
tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end());
-#if VERBOSE
+#if 1
std::cout << _name << ": tmpStates: ";
for (int i = 0; i < tmpStates.size(); i++) {
std::cout << ATTR(tmpStates[i], "id") << ", ";
@@ -873,7 +823,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
#endif
ancestor = findLCCA(tmpStates);
}
-#if VERBOSE
+#if 1
std::cout << _name << ": Ancestor: " << ATTR(ancestor, "id") << std::endl;;
#endif
for (int j = 0; j < _configuration.size(); j++) {
@@ -895,7 +845,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
statesToExit.forward(false);
statesToExit.sort();
-#if VERBOSE
+#if 0
std::cout << _name << ": States to exit: ";
for (int i = 0; i < statesToExit.size(); i++) {
std::cout << LOCALNAME(statesToExit[i]) << ":" << ATTR(statesToExit[i], "id") << ", ";
@@ -931,13 +881,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
}
for (int i = 0; i < statesToExit.size(); i++) {
- // --- MONITOR: beforeExitingState ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeExitingState(shared_from_this(), Element<std::string>(statesToExit[i]), (i + 1 < statesToExit.size()));
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeExitingState)
- }
+ USCXML_MONITOR_CALLBACK3(beforeExitingState, Element<std::string>(statesToExit[i]), (i + 1 < statesToExit.size()))
NodeSet<std::string> onExits = filterChildElements(_nsInfo.xmlNSPrefix + "onExit", statesToExit[i]);
for (int j = 0; j < onExits.size(); j++) {
@@ -945,13 +889,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
executeContent(onExitElem);
}
- // --- MONITOR: afterExitingState ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterExitingState(shared_from_this(), Element<std::string>(statesToExit[i]), (i + 1 < statesToExit.size()));
- }
- USCXML_MONITOR_CATCH_BLOCK(afterExitingState)
- }
+ USCXML_MONITOR_CALLBACK3(afterExitingState, Element<std::string>(statesToExit[i]), (i + 1 < statesToExit.size()))
NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", statesToExit[i]);
for (int j = 0; j < invokes.size(); j++) {
@@ -978,7 +916,8 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
NodeSet<std::string> statesToEnter;
NodeSet<std::string> statesForDefaultEntry;
- monIter_t monIter;
+ // initialize the temporary table for default content in history states
+ NodeSet<std::string> defaultHistoryContent;
#if VERBOSE
std::cout << _name << ": Enabled enter transitions: " << std::endl;
@@ -1033,7 +972,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
#endif
for (int j = 0; j < tStates.size(); j++) {
- addStatesToEnter(tStates[j], statesToEnter, statesForDefaultEntry);
+ addStatesToEnter(tStates[j], statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
#if VERBOSE
@@ -1068,7 +1007,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
}
}
if (!someIsDescendant) {
- addStatesToEnter(childs[l], statesToEnter, statesForDefaultEntry);
+ addStatesToEnter(childs[l], statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
}
}
@@ -1099,13 +1038,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
}
}
- // --- MONITOR: beforeEnteringState ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeEnteringState(shared_from_this(), stateElem, (i + 1 < statesToEnter.size()));
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeEnteringState)
- }
+ USCXML_MONITOR_CALLBACK3(beforeEnteringState, stateElem, (i + 1 < statesToEnter.size()))
// extension for flattened SCXML documents, we will need an explicit uninvoke element
NodeSet<std::string> uninvokes = filterChildElements(_nsInfo.xmlNSPrefix + "uninvoke", statesToEnter[i]);
@@ -1134,13 +1067,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
NodeSet<std::string> onEntryElems = filterChildElements(_nsInfo.xmlNSPrefix + "onEntry", stateElem);
executeContent(onEntryElems, false);
- // --- MONITOR: afterEnteringState ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterEnteringState(shared_from_this(), stateElem, (i + 1 < statesToEnter.size()));
- }
- USCXML_MONITOR_CATCH_BLOCK(afterEnteringState)
- }
+ USCXML_MONITOR_CALLBACK3(afterEnteringState, stateElem, (i + 1 < statesToEnter.size()))
if (isMember(stateElem, statesForDefaultEntry)) {
// execute initial transition content for compound states
@@ -1150,6 +1077,16 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
}
}
+#if 0
+ // not working yet
+ if (isMember(stateElem, defaultHistoryContent)) {
+ // execute history transition
+ Arabica::XPath::NodeSet<std::string> transitions = _xpath.evaluate("" + _nsInfo.xpathPrefix + "history/" + _nsInfo.xpathPrefix + "transition", stateElem).asNodeSet();
+ for (int j = 0; j < transitions.size(); j++) {
+ executeContent(transitions[j]);
+ }
+ }
+#endif
if (isFinal(stateElem)) {
internalDoneSend(stateElem);
Element<std::string> parent = (Element<std::string>)stateElem.getParentNode();
@@ -1174,15 +1111,15 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
for (int i = 0; i < _configuration.size(); i++) {
Element<std::string> stateElem = (Element<std::string>)_configuration[i];
if (isFinal(stateElem) && parentIsScxmlState(stateElem)) {
- _running = false;
- _done = true;
+ _topLevelFinalReached = true;
}
}
}
void InterpreterDraft6::addStatesToEnter(const Node<std::string>& state,
- Arabica::XPath::NodeSet<std::string>& statesToEnter,
- Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
+ Arabica::XPath::NodeSet<std::string>& statesToEnter,
+ Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry,
+ Arabica::XPath::NodeSet<std::string>& defaultHistoryContent) {
std::string stateId = ((Element<std::string>)state).getAttribute("id");
#if VERBOSE
@@ -1201,7 +1138,7 @@ void InterpreterDraft6::addStatesToEnter(const Node<std::string>& state,
#endif
for (int i = 0; i < historyValue.size(); i++) {
- addStatesToEnter(historyValue[i], statesToEnter, statesForDefaultEntry);
+ addStatesToEnter(historyValue[i], statesToEnter, statesForDefaultEntry, defaultHistoryContent);
NodeSet<std::string> ancestors = getProperAncestors(historyValue[i], state);
#if VERBOSE
@@ -1217,11 +1154,12 @@ void InterpreterDraft6::addStatesToEnter(const Node<std::string>& state,
}
}
} else {
+ defaultHistoryContent.push_back(getParentState(state));
NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", state);
for (int i = 0; i < transitions.size(); i++) {
NodeSet<std::string> targets = getTargetStates(transitions[i]);
for (int j = 0; j < targets.size(); j++) {
- addStatesToEnter(targets[j], statesToEnter, statesForDefaultEntry);
+ addStatesToEnter(targets[j], statesToEnter, statesForDefaultEntry, defaultHistoryContent);
// Modifications from chris nuernberger
NodeSet<std::string> ancestors = getProperAncestors(targets[j], state);
@@ -1238,7 +1176,7 @@ void InterpreterDraft6::addStatesToEnter(const Node<std::string>& state,
NodeSet<std::string> tStates = getInitialStates(state);
for (int i = 0; i < tStates.size(); i++) {
- addStatesToEnter(tStates[i], statesToEnter, statesForDefaultEntry);
+ addStatesToEnter(tStates[i], statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
// addStatesToEnter(getInitialState(state), statesToEnter, statesForDefaultEntry);
@@ -1247,7 +1185,7 @@ void InterpreterDraft6::addStatesToEnter(const Node<std::string>& state,
} else if(isParallel(state)) {
NodeSet<std::string> childStates = getChildStates(state);
for (int i = 0; i < childStates.size(); i++) {
- addStatesToEnter(childStates[i], statesToEnter, statesForDefaultEntry);
+ addStatesToEnter(childStates[i], statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
}
}
diff --git a/src/uscxml/interpreter/InterpreterDraft6.h b/src/uscxml/interpreter/InterpreterDraft6.h
index 2ab588e..25b096d 100644
--- a/src/uscxml/interpreter/InterpreterDraft6.h
+++ b/src/uscxml/interpreter/InterpreterDraft6.h
@@ -26,15 +26,16 @@ namespace uscxml {
class USCXML_API InterpreterDraft6 : public InterpreterImpl {
protected:
- void interpret();
- InterpreterState step(bool blocking);
+ InterpreterState interpret();
+ InterpreterState step(int blocking);
void stabilize();
void microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
void enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
void addStatesToEnter(const Arabica::DOM::Node<std::string>& state,
Arabica::XPath::NodeSet<std::string>& statesToEnter,
- Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry);
+ Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry,
+ Arabica::XPath::NodeSet<std::string>& defaultHistoryContent);
void exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
void exitInterpreter();
diff --git a/src/uscxml/interpreter/InterpreterRC.cpp b/src/uscxml/interpreter/InterpreterRC.cpp
index 10c41d0..d651389 100644
--- a/src/uscxml/interpreter/InterpreterRC.cpp
+++ b/src/uscxml/interpreter/InterpreterRC.cpp
@@ -45,15 +45,12 @@ procedure interpret(doc):
enterStates([doc.initial.transition])
mainEventLoop()
*/
-void InterpreterRC::interpret() {
+InterpreterState InterpreterRC::interpret() {
try {
tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
if (!_isInitialized)
init();
- if (!_scxml) {
- return;
- }
// dump();
// just make sure we have a session id
@@ -84,7 +81,6 @@ void InterpreterRC::interpret() {
_dataModel.assign("_x.args", _cmdLineOptions);
}
- _running = true;
_binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY);
// @TODO: Reread http://www.w3.org/TR/scxml/#DataBinding
@@ -184,6 +180,7 @@ void InterpreterRC::interpret() {
if(_dataModel)
_dataModel = DataModel();
+ return _state;
}
/**
@@ -237,7 +234,6 @@ procedure mainEventLoop():
exitInterpreter()
*/
void InterpreterRC::mainEventLoop() {
- monIter_t monIter;
while(_running) {
NodeSet<std::string> enabledTransitions;
@@ -255,13 +251,7 @@ void InterpreterRC::mainEventLoop() {
_currEvent = _internalQueue.front();
_internalQueue.pop_front();
- // --- MONITOR: beforeProcessingEvent ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
- }
+ USCXML_MONITOR_CALLBACK2(beforeProcessingEvent, _currEvent)
if (_dataModel)
_dataModel.setEvent(_currEvent);
@@ -299,16 +289,9 @@ void InterpreterRC::mainEventLoop() {
}
assert(hasLegalConfiguration());
- monIter = _monitors.begin();
// if (!_sendQueue || _sendQueue->isEmpty()) {
- // --- MONITOR: onStableConfiguration ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->onStableConfiguration(shared_from_this());
- }
- USCXML_MONITOR_CATCH_BLOCK(onStableConfiguration)
- }
+ USCXML_MONITOR_CALLBACK(onStableConfiguration)
// }
@@ -334,13 +317,7 @@ void InterpreterRC::mainEventLoop() {
if (!_running)
goto EXIT_INTERPRETER;
- // --- MONITOR: beforeProcessingEvent ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
- }
+ USCXML_MONITOR_CALLBACK2(beforeProcessingEvent, _currEvent)
if (_dataModel && iequals(_currEvent.name, "cancel.invoke." + _sessionId))
break;
@@ -399,13 +376,7 @@ void InterpreterRC::mainEventLoop() {
}
EXIT_INTERPRETER:
- // --- MONITOR: beforeCompletion ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeCompletion(shared_from_this());
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeCompletion)
- }
+ USCXML_MONITOR_CALLBACK(beforeCompletion)
exitInterpreter();
if (_sendQueue) {
@@ -416,13 +387,7 @@ EXIT_INTERPRETER:
}
}
- // --- MONITOR: afterCompletion ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterCompletion(shared_from_this());
- }
- USCXML_MONITOR_CATCH_BLOCK(afterCompletion)
- }
+ USCXML_MONITOR_CALLBACK(afterCompletion)
}
@@ -670,48 +635,23 @@ procedure microstep(enabledTransitions):
*/
void InterpreterRC::microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
- // --- MONITOR: beforeMicroStep ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeMicroStep(shared_from_this());
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeMicroStep)
- }
+ USCXML_MONITOR_CALLBACK(beforeMicroStep)
exitStates(enabledTransitions);
- monIter_t monIter;
for (int i = 0; i < enabledTransitions.size(); i++) {
Element<std::string> transition(enabledTransitions[i]);
- // --- MONITOR: beforeTakingTransitions ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeTakingTransition(shared_from_this(), transition, (i + 1 < enabledTransitions.size()));
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeTakingTransitions)
- }
+ USCXML_MONITOR_CALLBACK3(beforeTakingTransition, transition, (i + 1 < enabledTransitions.size()))
executeContent(transition);
- // --- MONITOR: afterTakingTransitions ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterTakingTransition(shared_from_this(), transition, (i + 1 < enabledTransitions.size()));
- }
- USCXML_MONITOR_CATCH_BLOCK(afterTakingTransitions)
- }
+ USCXML_MONITOR_CALLBACK3(afterTakingTransition, transition, (i + 1 < enabledTransitions.size()))
}
enterStates(enabledTransitions);
- // --- MONITOR: afterMicroStep ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterMicroStep(shared_from_this());
- }
- USCXML_MONITOR_CATCH_BLOCK(afterMicroStep)
- }
+ USCXML_MONITOR_CALLBACK(afterMicroStep)
}
@@ -736,7 +676,6 @@ procedure exitStates(enabledTransitions):
configuration.delete(s)
*/
void InterpreterRC::exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
- monIter_t monIter;
NodeSet<std::string> statesToExit = computeExitSet(enabledTransitions);
// remove statesToExit from _statesToInvoke
@@ -772,13 +711,7 @@ void InterpreterRC::exitStates(const Arabica::XPath::NodeSet<std::string>& enabl
}
for (int i = 0; i < statesToExit.size(); i++) {
- // --- MONITOR: beforeExitingState ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeExitingState(shared_from_this(), Element<std::string>(statesToExit[i]), (i + 1 < statesToExit.size()));
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeExitingState)
- }
+ USCXML_MONITOR_CALLBACK3(beforeExitingState, Element<std::string>(statesToExit[i]), (i + 1 < statesToExit.size()))
NodeSet<std::string> onExits = filterChildElements(_nsInfo.xmlNSPrefix + "onExit", statesToExit[i]);
for (int j = 0; j < onExits.size(); j++) {
@@ -786,13 +719,7 @@ void InterpreterRC::exitStates(const Arabica::XPath::NodeSet<std::string>& enabl
executeContent(onExitElem);
}
- // --- MONITOR: afterExitingState ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterExitingState(shared_from_this(), Element<std::string>(statesToExit[i]), (i + 1 < statesToExit.size()));
- }
- USCXML_MONITOR_CATCH_BLOCK(afterExitingState)
- }
+ USCXML_MONITOR_CALLBACK3(afterExitingState, Element<std::string>(statesToExit[i]), (i + 1 < statesToExit.size()))
NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", statesToExit[i]);
for (int j = 0; j < invokes.size(); j++) {
@@ -888,7 +815,6 @@ void InterpreterRC::enterStates(const Arabica::XPath::NodeSet<std::string>& enab
NodeSet<std::string> statesForDefaultEntry;
// initialize the temporary table for default content in history states
std::map<std::string, Arabica::DOM::Node<std::string> > defaultHistoryContent;
- monIter_t monIter;
computeEntrySet(enabledTransitions, statesToEnter, statesForDefaultEntry, defaultHistoryContent);
statesToEnter.to_document_order();
@@ -896,13 +822,7 @@ void InterpreterRC::enterStates(const Arabica::XPath::NodeSet<std::string>& enab
for (int i = 0; i < statesToEnter.size(); i++) {
Element<std::string> s = (Element<std::string>)statesToEnter[i];
- // --- MONITOR: beforeEnteringState ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->beforeEnteringState(shared_from_this(), s, (i + 1 < statesToEnter.size()));
- }
- USCXML_MONITOR_CATCH_BLOCK(beforeEnteringState)
- }
+ USCXML_MONITOR_CALLBACK3(beforeEnteringState, s, i + 1 < statesToEnter.size())
_configuration.push_back(s);
_statesToInvoke.push_back(s);
@@ -924,13 +844,7 @@ void InterpreterRC::enterStates(const Arabica::XPath::NodeSet<std::string>& enab
NodeSet<std::string> onEntryElems = filterChildElements(_nsInfo.xmlNSPrefix + "onEntry", s);
executeContent(onEntryElems, false);
- // --- MONITOR: afterEnteringState ------------------------------
- for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
- try {
- (*monIter)->afterEnteringState(shared_from_this(), s, (i + 1 < statesToEnter.size()));
- }
- USCXML_MONITOR_CATCH_BLOCK(afterEnteringState)
- }
+ USCXML_MONITOR_CALLBACK3(afterEnteringState, s, i + 1 < statesToEnter.size())
if (isMember(s, statesForDefaultEntry)) {
// execute initial transition content for compound states
@@ -961,7 +875,7 @@ void InterpreterRC::enterStates(const Arabica::XPath::NodeSet<std::string>& enab
internalDoneSend(s);
if (parentIsScxmlState(s)) {
_running = false;
- _done = true;
+ _topLevelFinalReached = true;
} else {
Element<std::string> parent = (Element<std::string>)s.getParentNode();
Element<std::string> grandParent = (Element<std::string>)parent.getParentNode();
diff --git a/src/uscxml/interpreter/InterpreterRC.h b/src/uscxml/interpreter/InterpreterRC.h
index 0a09c36..2cd2662 100644
--- a/src/uscxml/interpreter/InterpreterRC.h
+++ b/src/uscxml/interpreter/InterpreterRC.h
@@ -25,7 +25,7 @@
namespace uscxml {
class InterpreterRC : public InterpreterImpl {
- void interpret();
+ InterpreterState interpret();
void mainEventLoop();
void exitInterpreter();
@@ -78,6 +78,8 @@ class InterpreterRC : public InterpreterImpl {
Arabica::XPath::NodeSet<std::string> getChildStates(const Arabica::DOM::Node<std::string>& state);
#endif
+ bool _running;
+
};
}
diff --git a/src/uscxml/plugins/datamodel/CMakeLists.txt b/src/uscxml/plugins/datamodel/CMakeLists.txt
index f04cb78..1b2a047 100644
--- a/src/uscxml/plugins/datamodel/CMakeLists.txt
+++ b/src/uscxml/plugins/datamodel/CMakeLists.txt
@@ -69,25 +69,14 @@ if (BUILD_DM_ECMA)
endif()
-# NULL datamodel
+# NULL datamodel (not useful as plugin)
set(USCXML_DATAMODELS "null ${USCXML_DATAMODELS}")
file(GLOB NULL_DATAMODEL
null/*.cpp
null/*.h
)
-if (BUILD_AS_PLUGINS)
- source_group("" FILES ${NULL_DATAMODEL})
- add_library(datamodel_null SHARED ${NULL_DATAMODEL} "../Plugins.cpp")
- target_link_libraries(datamodel_null uscxml)
- set_target_properties(datamodel_null PROPERTIES FOLDER "Plugin DataModel")
- set_target_properties(datamodel_null PROPERTIES COMPILE_FLAGS "-DPLUMA_EXPORTS")
- set_target_properties(datamodel_null PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${OUTPUT_DIR}/lib")
-
-
-else()
- list (APPEND USCXML_FILES ${NULL_DATAMODEL})
-endif()
+list (APPEND USCXML_FILES ${NULL_DATAMODEL})
# XPath datamodel
diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp
index a6909b5..72252e4 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp
+++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp
@@ -212,6 +212,12 @@ void JSCDataModel::setEvent(const Event& event) {
JSValueRef exception = NULL;
+ if (event.raw.size() == 0) {
+ std::stringstream ssRaw;
+ ssRaw << event;
+ privData->nativeObj->raw = ssRaw.str();
+ }
+
if (event.dom) {
JSStringRef propName = JSStringCreateWithUTF8CString("data");
JSObjectSetProperty(_ctx, eventObj, propName, getNodeAsValue(event.dom), 0, &exception);
@@ -555,6 +561,8 @@ void JSCDataModel::assign(const Element<std::string>& assignElem,
throw Event("error.execution", Event::PLATFORM);
if (key.compare("_invokers") == 0)
throw Event("error.execution", Event::PLATFORM);
+ if (key.compare("_event") == 0)
+ throw Event("error.execution", Event::PLATFORM);
if (HAS_ATTR(assignElem, "expr")) {
evalAsValue(key + " = " + ATTR(assignElem, "expr"));
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
index 2bdd796..8b222f7 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
@@ -228,6 +228,12 @@ void V8DataModel::setEvent(const Event& event) {
eventObj->SetInternalField(0, V8DOM::toExternal(privData));
eventObj.MakeWeak(0, V8SCXMLEvent::jsDestructor);
+ if (event.raw.size() == 0) {
+ std::stringstream ssRaw;
+ ssRaw << event;
+ privData->nativeObj->raw = ssRaw.str();
+ }
+
if (event.dom) {
eventObj->Set(v8::String::New("data"), getNodeAsValue(event.dom));
} else if (event.content.length() > 0) {
@@ -595,6 +601,17 @@ void V8DataModel::assign(const Element<std::string>& assignElem,
if (key.length() == 0)
throw Event("error.execution", Event::PLATFORM);
+ if (key.compare("_sessionid") == 0) // test 322
+ throw Event("error.execution", Event::PLATFORM);
+ if (key.compare("_name") == 0)
+ throw Event("error.execution", Event::PLATFORM);
+ if (key.compare("_ioprocessors") == 0) // test 326
+ throw Event("error.execution", Event::PLATFORM);
+ if (key.compare("_invokers") == 0)
+ throw Event("error.execution", Event::PLATFORM);
+ if (key.compare("_event") == 0)
+ throw Event("error.execution", Event::PLATFORM);
+
if (HAS_ATTR(assignElem, "expr")) {
evalAsValue(key + " = " + ATTR(assignElem, "expr"));
} else if (node) {
diff --git a/src/uscxml/plugins/element/respond/RespondElement.cpp b/src/uscxml/plugins/element/respond/RespondElement.cpp
index 4fe0d2e..3eb55ed 100644
--- a/src/uscxml/plugins/element/respond/RespondElement.cpp
+++ b/src/uscxml/plugins/element/respond/RespondElement.cpp
@@ -78,7 +78,7 @@ void RespondElement::enterElement(const Arabica::DOM::Node<std::string>& node) {
httpReply.status = strTo<int>(statusStr);;
// extract the content
- Arabica::XPath::NodeSet<std::string> contents = InterpreterImpl::filterChildElements(_interpreter->getXMLPrefixForNS(getNamespace()) + "content", node);
+ Arabica::XPath::NodeSet<std::string> contents = InterpreterImpl::filterChildElements(_interpreter->getNameSpaceInfo().getXMLPrefixForNS(getNamespace()) + "content", node);
if (contents.size() > 0) {
if (HAS_ATTR(contents[0], "expr")) { // -- content is evaluated string from datamodel ------
if (_interpreter->getDataModel()) {
@@ -141,7 +141,7 @@ void RespondElement::enterElement(const Arabica::DOM::Node<std::string>& node) {
}
// process headers
- Arabica::XPath::NodeSet<std::string> headers = InterpreterImpl::filterChildElements(_interpreter->getXMLPrefixForNS(getNamespace()) + "header", node);
+ Arabica::XPath::NodeSet<std::string> headers = InterpreterImpl::filterChildElements(_interpreter->getNameSpaceInfo().getXMLPrefixForNS(getNamespace()) + "header", node);
for (int i = 0; i < headers.size(); i++) {
std::string name;
if (HAS_ATTR(headers[i], "name")) {
diff --git a/src/uscxml/plugins/invoker/CMakeLists.txt b/src/uscxml/plugins/invoker/CMakeLists.txt
index f12a7a6..3f63ea3 100644
--- a/src/uscxml/plugins/invoker/CMakeLists.txt
+++ b/src/uscxml/plugins/invoker/CMakeLists.txt
@@ -271,6 +271,30 @@ if (LIBICAL_FOUND)
endif()
+# webrtc invoker
+
+if (LIBJINGLE_FOUND)
+ set(USCXML_INVOKERS "webrtc ${USCXML_INVOKERS}")
+ file(GLOB_RECURSE WEBRTC_INVOKER
+ webrtc/*.cpp
+ webrtc/*.h
+ )
+ if (BUILD_AS_PLUGINS)
+ source_group("" FILES ${WEBRTC_INVOKER})
+ add_library(
+ invoker_webrtc SHARED
+ ${WEBRTC_INVOKER}
+ "../Plugins.cpp")
+ target_link_libraries(invoker_webrtc uscxml ${LIBJINGLE_LIBRARIES})
+ set_target_properties(invoker_webrtc PROPERTIES FOLDER "Plugin Invoker")
+ set_target_properties(invoker_webrtc PROPERTIES COMPILE_FLAGS "-DPLUMA_EXPORTS")
+ set_target_properties(invoker_webrtc PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${OUTPUT_DIR}/lib")
+ else()
+ list (APPEND USCXML_FILES ${WEBRTC_INVOKER})
+ endif()
+endif()
+
+
# location invoker
if (CORELOCATION_LIBRARY AND OFF)
diff --git a/src/uscxml/plugins/invoker/sample/SampleInvoker.cpp b/src/uscxml/plugins/invoker/sample/SampleInvoker.cpp
index 0777c62..d91b14c 100644
--- a/src/uscxml/plugins/invoker/sample/SampleInvoker.cpp
+++ b/src/uscxml/plugins/invoker/sample/SampleInvoker.cpp
@@ -1,6 +1,6 @@
/**
* @file
- * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
* @copyright Simplified BSD
*
* @cond
diff --git a/src/uscxml/plugins/invoker/sample/SampleInvoker.h b/src/uscxml/plugins/invoker/sample/SampleInvoker.h
index 562ebd6..f7bcb24 100644
--- a/src/uscxml/plugins/invoker/sample/SampleInvoker.h
+++ b/src/uscxml/plugins/invoker/sample/SampleInvoker.h
@@ -1,6 +1,6 @@
/**
* @file
- * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
* @copyright Simplified BSD
*
* @cond
diff --git a/src/uscxml/plugins/invoker/webrtc/WebRTCInvoker.cpp b/src/uscxml/plugins/invoker/webrtc/WebRTCInvoker.cpp
new file mode 100644
index 0000000..2d871c8
--- /dev/null
+++ b/src/uscxml/plugins/invoker/webrtc/WebRTCInvoker.cpp
@@ -0,0 +1,64 @@
+/**
+ * @file
+ * @author 2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#include "WebRTCInvoker.h"
+#include <glog/logging.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
+//#include "talk/app/webrtc/peerconnection.h"
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool pluginConnect(pluma::Host& host) {
+ host.add( new WebRTCInvokerProvider() );
+ return true;
+}
+#endif
+
+WebRTCInvoker::WebRTCInvoker() {
+}
+
+WebRTCInvoker::~WebRTCInvoker() {
+};
+
+boost::shared_ptr<InvokerImpl> WebRTCInvoker::create(InterpreterImpl* interpreter) {
+ boost::shared_ptr<WebRTCInvoker> invoker = boost::shared_ptr<WebRTCInvoker>(new WebRTCInvoker());
+ return invoker;
+}
+
+Data WebRTCInvoker::getDataModelVariables() {
+ Data data;
+ return data;
+}
+
+void WebRTCInvoker::send(const SendRequest& req) {
+}
+
+void WebRTCInvoker::cancel(const std::string sendId) {
+}
+
+void WebRTCInvoker::invoke(const InvokeRequest& req) {
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/plugins/invoker/webrtc/WebRTCInvoker.h b/src/uscxml/plugins/invoker/webrtc/WebRTCInvoker.h
new file mode 100644
index 0000000..e4d7775
--- /dev/null
+++ b/src/uscxml/plugins/invoker/webrtc/WebRTCInvoker.h
@@ -0,0 +1,59 @@
+/**
+ * @file
+ * @author 2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#ifndef WEBRTCINVOKER_H_1E704623
+#define WEBRTCINVOKER_H_1E704623
+
+#include <uscxml/Interpreter.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
+namespace uscxml {
+
+class WebRTCInvoker : public InvokerImpl {
+public:
+ WebRTCInvoker();
+ virtual ~WebRTCInvoker();
+ virtual boost::shared_ptr<InvokerImpl> create(InterpreterImpl* interpreter);
+
+ virtual std::list<std::string> getNames() {
+ std::list<std::string> names;
+ names.push_back("webrtc");
+ names.push_back("http://uscxml.tk.informatik.tu-darmstadt.de/#webrtc");
+ 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(WebRTCInvoker, InvokerImpl);
+#endif
+
+}
+
+
+#endif /* end of include guard: WEBRTCINVOKER_H_1E704623 */
diff --git a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp
index 7d9fcb8..b6dadc9 100644
--- a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp
+++ b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp
@@ -124,13 +124,27 @@ bool BasicHTTPIOProcessor::httpRecvRequest(const HTTPServer::Request& req) {
*/
// this will call the const subscript operator
- if (req.data.at("content").hasKey("_scxmleventname")) {
- reqEvent.name = req.data.at("content").at("_scxmleventname").atom;
- }
- if (req.data.at("content").hasKey("content")) {
- reqEvent.content = req.data.at("content").at("content").atom;
+// if (req.data.at("content").hasKey("_scxmleventname")) {
+// reqEvent.name = req.data.at("content").at("_scxmleventname").atom;
+// }
+// if (req.data.at("content").hasKey("content")) {
+// reqEvent.content = req.data.at("content").at("content").atom;
+// }
+
+ if (req.data.hasKey("content")) {
+ const Data& data = req.data["content"];
+ for(std::map<std::string, Data>::const_iterator compIter = data.compound.begin();
+ compIter!= data.compound.end(); compIter++) {
+ if (compIter->first == "_scxmleventname") {
+ reqEvent.name = compIter->second.atom;
+ } else if (compIter->first == "content") {
+ reqEvent.content = compIter->second.atom;
+ } else {
+ reqEvent.data[compIter->first] = compIter->second;
+ }
+ }
}
-
+
// check whether we can parse it as XML
if (reqEvent.content.length() > 0) {
NameSpacingParser parser = NameSpacingParser::fromXML(reqEvent.content);
diff --git a/src/uscxml/server/HTTPServer.cpp b/src/uscxml/server/HTTPServer.cpp
index 3e7920c..e5c83d7 100644
--- a/src/uscxml/server/HTTPServer.cpp
+++ b/src/uscxml/server/HTTPServer.cpp
@@ -179,7 +179,6 @@ tthread::recursive_mutex HTTPServer::_instanceMutex;
HTTPServer* HTTPServer::getInstance(unsigned short port, unsigned short wsPort, SSLConfig* sslConf) {
// tthread::lock_guard<tthread::recursive_mutex> lock(_instanceMutex);
if (_instance == NULL) {
- std::cout << "Instantiating new HTTPServer" << std::endl;
#ifdef _WIN32
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
diff --git a/src/uscxml/transform/ChartToFSM.cpp b/src/uscxml/transform/ChartToFSM.cpp
index 49519dc..581ba85 100644
--- a/src/uscxml/transform/ChartToFSM.cpp
+++ b/src/uscxml/transform/ChartToFSM.cpp
@@ -26,7 +26,7 @@
#include <math.h>
#include <string.h>
#include <algorithm>
-#undef max
+#undef max
#include <limits>
namespace uscxml {
@@ -101,7 +101,7 @@ Document<std::string> FlatteningInterpreter::getDocument() const {
return _flatDoc;
}
-void FlatteningInterpreter::interpret() {
+InterpreterState FlatteningInterpreter::interpret() {
init();
setupIOProcessors();
@@ -177,6 +177,7 @@ void FlatteningInterpreter::interpret() {
#endif
createDocument();
+ return _state;
}
void FlatteningInterpreter::executeContent(const Arabica::DOM::Node<std::string>& content, bool rethrow) {
diff --git a/src/uscxml/transform/ChartToFSM.h b/src/uscxml/transform/ChartToFSM.h
index ef80a6a..07531e2 100644
--- a/src/uscxml/transform/ChartToFSM.h
+++ b/src/uscxml/transform/ChartToFSM.h
@@ -105,7 +105,7 @@ public:
virtual ~FlatteningInterpreter();
Arabica::DOM::Document<std::string> getDocument() const; // overwrite to return flat FSM
- void interpret();
+ InterpreterState interpret();
protected:
// gather executable content per microstep