diff options
author | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2014-05-15 19:55:13 (GMT) |
---|---|---|
committer | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2014-05-15 19:55:13 (GMT) |
commit | f9a620340ddce2a17fd775d1e210268cac13377b (patch) | |
tree | 58d8dad794e5a34237c2738fe77c151d0810624f /src/uscxml | |
parent | 49127140ed2ad91bfcf532b3d2265582cb80b0db (diff) | |
download | uscxml-f9a620340ddce2a17fd775d1e210268cac13377b.zip uscxml-f9a620340ddce2a17fd775d1e210268cac13377b.tar.gz uscxml-f9a620340ddce2a17fd775d1e210268cac13377b.tar.bz2 |
Introduced interpreter.step()
Diffstat (limited to 'src/uscxml')
-rw-r--r-- | src/uscxml/Interpreter.cpp | 184 | ||||
-rw-r--r-- | src/uscxml/Interpreter.h | 19 | ||||
-rw-r--r-- | src/uscxml/debug/Debugger.cpp | 4 | ||||
-rw-r--r-- | src/uscxml/debug/SCXMLDotWriter.cpp | 12 | ||||
-rw-r--r-- | src/uscxml/interpreter/InterpreterDraft6.cpp | 484 | ||||
-rw-r--r-- | src/uscxml/interpreter/InterpreterDraft6.h | 5 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp | 4 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp | 4 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp | 2 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp | 4 | ||||
-rw-r--r-- | src/uscxml/plugins/element/respond/RespondElement.cpp | 4 | ||||
-rw-r--r-- | src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp | 5 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToFSM.cpp | 8 |
13 files changed, 467 insertions, 272 deletions
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 75d44c1..e2ee1da 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -292,9 +292,11 @@ InterpreterImpl::InterpreterImpl() { _running = false; _destroyed = false; _done = true; + _stable = false; _isInitialized = false; _httpServlet = NULL; _factory = NULL; + _sessionId = UUID::getUUID(); _capabilities = CAN_BASIC_HTTP | CAN_GENERIC_HTTP; _domEventListener._interpreter = this; @@ -389,7 +391,7 @@ Interpreter Interpreter::fromInputSource(Arabica::SAX::InputSource<std::string>& if (parser.parse(source) && parser.getDocument() && parser.getDocument().hasChildNodes()) { interpreterImpl->setNameSpaceInfo(parser.nameSpace); interpreterImpl->_document = parser.getDocument(); - interpreterImpl->init(); +// interpreterImpl->init(); interpreter = Interpreter(interpreterImpl); _instances[interpreterImpl->getSessionId()] = interpreterImpl; } else { @@ -473,6 +475,7 @@ InterpreterImpl::~InterpreterImpl() { // tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); if (_thread) { if (_thread->get_id() != tthread::this_thread::get_id()) { + // unblock event queue Event event; event.name = "unblock.and.die"; @@ -488,8 +491,6 @@ InterpreterImpl::~InterpreterImpl() { if (_sendQueue) delete _sendQueue; -// if (_httpServlet) -// delete _httpServlet; } void InterpreterImpl::start() { @@ -550,52 +551,116 @@ bool InterpreterImpl::runOnMainThread(int fps, bool blocking) { } void InterpreterImpl::init() { - if (_document) { - NodeList<std::string> scxmls; - if (_nsInfo.nsURL.size() == 0) { - scxmls = _document.getElementsByTagName("scxml"); - } else { - scxmls = _document.getElementsByTagNameNS(_nsInfo.nsURL, "scxml"); - } - if (scxmls.getLength() > 0) { - _scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0); + if (!_document) { + LOG(ERROR) << "Interpreter has no DOM at all!" << std::endl; + _done = true; + return; + } + + // find scxml element + NodeList<std::string> scxmls; + if (_nsInfo.nsURL.size() == 0) { + scxmls = _document.getElementsByTagName("scxml"); + } 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()); + // setup xpath and check that it works + if (_nsInfo.getNSContext() != NULL) + _xpath.setNamespaceContext(*_nsInfo.getNSContext()); - if (_name.length() == 0) - _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : UUID::getUUID()); + if (_name.length() == 0) + _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : UUID::getUUID()); - normalize(_scxml); + // normalize document + normalize(_scxml); - // setup event queue for delayed send - _sendQueue = new DelayedEventQueue(); - _sendQueue->start(); + // 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); + // 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); - if (_factory == NULL) - _factory = Factory::getInstance(); + if (_factory == NULL) + _factory = Factory::getInstance(); - } else { - LOG(ERROR) << "Cannot find SCXML element" << std::endl; - _done = true; - return; - } } else { - LOG(ERROR) << "Interpreter has no DOM at all!" << std::endl; + LOG(ERROR) << "Cannot find SCXML element" << std::endl; _done = true; + return; } - + if (_sessionId.length() == 0) _sessionId = UUID::getUUID(); + + setupIOProcessors(); + + std::string datamodelName; + 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); + if (!_dataModel) { + Event e; + e.data.compound["cause"] = Data("Cannot instantiate datamodel", Data::VERBATIM); + throw e; + } + } else { + _dataModel = _factory->createDataModel("null", this); + } + + _dataModel.assign("_x.args", _cmdLineOptions); + + _running = true; +#if VERBOSE + std::cout << "running " << this << std::endl; +#endif + + _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY); + + // @TODO: Reread http://www.w3.org/TR/scxml/#DataBinding + + if (_binding == EARLY) { + // initialize all data elements + NodeSet<std::string> dataElems = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "data", _scxml).asNodeSet(); + for (unsigned int i = 0; i < dataElems.size(); i++) { + // do not process data elements of nested documents from invokers + if (!getAncestorElement(dataElems[i], _nsInfo.xmlNSPrefix + "invoke")) + if (dataElems[i].getNodeType() == Node_base::ELEMENT_NODE) { + initializeData(Element<std::string>(dataElems[i])); + } + } + } else { + // initialize current data elements + NodeSet<std::string> topDataElems = filterChildElements(_nsInfo.xmlNSPrefix + "data", filterChildElements(_nsInfo.xmlNSPrefix + "datamodel", _scxml)); + for (unsigned int i = 0; i < topDataElems.size(); i++) { + if (topDataElems[i].getNodeType() == Node_base::ELEMENT_NODE) + initializeData(Element<std::string>(topDataElems[i])); + } + } + + // executeGlobalScriptElements + NodeSet<std::string> globalScriptElems = filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml); + for (unsigned int i = 0; i < globalScriptElems.size(); i++) { + if (_dataModel) { + executeContent(globalScriptElems[i]); + } + } + _isInitialized = true; + _stable = false; } /** @@ -641,11 +706,13 @@ 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 and set isFirstEntry to true (replaced by _alreadyEntered NodeSet) - Arabica::XPath::NodeSet<std::string> states = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "state", _scxml).asNodeSet(); + // 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]); -// stateElem.setAttribute("isFirstEntry", "true"); if (!stateElem.hasAttribute("id")) { stateElem.setAttribute("id", UUID::getUUID()); } @@ -658,45 +725,25 @@ void InterpreterImpl::normalize(Arabica::DOM::Element<std::string>& scxml) { if (!invokeElem.hasAttribute("id") && !invokeElem.hasAttribute("idlocation")) { invokeElem.setAttribute("id", UUID::getUUID()); } -// // make sure every finalize element contained has the invoke id as an attribute -// Arabica::XPath::NodeSet<std::string> finalizes = _xpath.evaluate("" + _xpathPrefix + "finalize", invokeElem).asNodeSet(); -// for (int j = 0; j < finalizes.size(); j++) { -// Arabica::DOM::Element<std::string> finalizeElem = Arabica::DOM::Element<std::string>(finalizes[j]); -// finalizeElem.setAttribute("invokeid", invokeElem.getAttribute("id")); -// } - } - - Arabica::XPath::NodeSet<std::string> finals = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "final", _scxml).asNodeSet(); - for (int i = 0; i < finals.size(); i++) { - Arabica::DOM::Element<std::string> finalElem = Arabica::DOM::Element<std::string>(finals[i]); -// finalElem.setAttribute("isFirstEntry", "true"); - if (!finalElem.hasAttribute("id")) { - finalElem.setAttribute("id", UUID::getUUID()); - } - } - - Arabica::XPath::NodeSet<std::string> histories = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "history", _scxml).asNodeSet(); - for (int i = 0; i < histories.size(); i++) { - Arabica::DOM::Element<std::string> historyElem = Arabica::DOM::Element<std::string>(histories[i]); - if (!historyElem.hasAttribute("id")) { - historyElem.setAttribute("id", UUID::getUUID()); - } } if (!scxml.hasAttribute("id")) { scxml.setAttribute("id", UUID::getUUID()); } - } void InterpreterImpl::receiveInternal(const Event& event) { -// std::cout << _name << " receiveInternal: " << event.name << std::endl; +#if VERBOSE + std::cout << _name << " receiveInternal: " << event.name << std::endl; +#endif _internalQueue.push_back(event); // _condVar.notify_all(); } void InterpreterImpl::receive(const Event& event, bool toFront) { -// std::cout << _name << " receive: " << event.name << std::endl; +#if VERBOSE + std::cout << _name << " receive: " << event.name << std::endl; +#endif if (toFront) { _externalQueue.push_front(event); } else { @@ -1562,11 +1609,16 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node<std::string>& cont if (_dataModel) { if (HAS_ATTR(content, "src")) { URL scriptUrl(ATTR(content, "src")); - if (!scriptUrl.toAbsolute(_baseURI)) { + if (!scriptUrl.isAbsolute() && !_baseURI) { LOG(ERROR) << "script element has relative URI " << ATTR(content, "src") << " with no base URI set for interpreter"; return; } + if (!scriptUrl.toAbsolute(_baseURI)) { + LOG(ERROR) << "Failed to convert relative script URI " << ATTR(content, "src") << " to absolute with base URI " << _baseURI.asString(); + return; + } + std::stringstream srcContent; try { if (_cachedURLs.find(scriptUrl.asString()) != _cachedURLs.end() && false) { @@ -2434,7 +2486,7 @@ void InterpreterImpl::DOMEventListener::handleEvent(Arabica::DOM::Events::Event< if (event.getType().compare("DOMAttrModified") == 0) // we do not care about attributes return; Node<std::string> target = Arabica::DOM::Node<std::string>(event.getTarget()); - NodeSet<std::string> childs = Interpreter::filterChildElements(_interpreter->_nsInfo.xmlNSPrefix + "state", target); + NodeSet<std::string> childs = InterpreterImpl::filterChildElements(_interpreter->_nsInfo.xmlNSPrefix + "state", target); for (int i = 0; i < childs.size(); i++) { if (HAS_ATTR(childs[i], "id")) { _interpreter->_cachedStates.erase(ATTR(childs[i], "id")); diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 6a11c46..93062e6 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -188,6 +188,16 @@ 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 +}; + class USCXML_API InterpreterImpl : public boost::enable_shared_from_this<InterpreterImpl> { public: @@ -214,7 +224,8 @@ public: } /// This one ought to be pure, but SWIG will generate gibberish if it is - virtual void interpret() {}; + virtual void interpret() = 0; + virtual InterpreterState step(bool blocking = false) = 0; void addMonitor(InterpreterMonitor* monitor) { _monitors.insert(monitor); @@ -535,6 +546,10 @@ public: _impl->interpret(); }; + InterpreterState step(bool blocking = false) { + return _impl->step(blocking); + }; + void addMonitor(InterpreterMonitor* monitor) { return _impl->addMonitor(monitor); } @@ -684,6 +699,7 @@ public: return _impl->isLegalConfiguration(config); } +#if 0 static bool isState(const Arabica::DOM::Node<std::string>& state) { return InterpreterImpl::isState(state); } @@ -773,6 +789,7 @@ public: 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; diff --git a/src/uscxml/debug/Debugger.cpp b/src/uscxml/debug/Debugger.cpp index d1a8068..b74b2a9 100644 --- a/src/uscxml/debug/Debugger.cpp +++ b/src/uscxml/debug/Debugger.cpp @@ -66,8 +66,8 @@ std::list<Breakpoint> getQualifiedInvokeBreakpoints(Interpreter interpreter, con std::list<Breakpoint> getQualifiedTransBreakpoints(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, Breakpoint breakpointTemplate) { std::list<Breakpoint> breakpoints; - Arabica::DOM::Element<std::string> source(interpreter.getSourceState(transition)); - Arabica::XPath::NodeSet<std::string> targets = interpreter.getTargetStates(transition); + Arabica::DOM::Element<std::string> source(interpreter.getImpl()->getSourceState(transition)); + Arabica::XPath::NodeSet<std::string> targets = interpreter.getImpl()->getTargetStates(transition); for (int j = 0; j < targets.size(); j++) { Arabica::DOM::Element<std::string> target(targets[j]); diff --git a/src/uscxml/debug/SCXMLDotWriter.cpp b/src/uscxml/debug/SCXMLDotWriter.cpp index 2058d72..93f09ab 100644 --- a/src/uscxml/debug/SCXMLDotWriter.cpp +++ b/src/uscxml/debug/SCXMLDotWriter.cpp @@ -110,7 +110,7 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Arabica::DOM::Ele return; _knownIds.insert(elemId); - bool subgraph = Interpreter::isCompound(elem) || Interpreter::isParallel(elem); + bool subgraph = InterpreterImpl::isCompound(elem) || InterpreterImpl::isParallel(elem); if (subgraph) { _indentation++; os << getPrefix() << "subgraph \"cluster_" << elemId << "\" {" << std::endl; @@ -122,11 +122,11 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Arabica::DOM::Ele os << "label=<<b>State</b><br />" << nameForNode(elem) << ">,"; // is the state initial? - if (_interpreter.isInitial(elem)) + if (_interpreter.getImpl()->isInitial(elem)) os << "style=filled, fillcolor=lightgrey, "; // is this state final? - if (_interpreter.isFinal(elem)) + if (_interpreter.getImpl()->isFinal(elem)) os << "shape=doublecircle,"; // is the current state in the basic configuration? @@ -176,7 +176,7 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Arabica::DOM::Ele os << "]" << std::endl; } } - if (Interpreter::isState(childElems.item(i))) { + if (InterpreterImpl::isState(childElems.item(i))) { writeStateElement(os, (Arabica::DOM::Element<std::string>)childElems.item(i)); } if (childElems.item(i).getNodeType() == Node_base::ELEMENT_NODE && iequals(TAGNAME(childElems.item(i)), "initial")) { @@ -200,7 +200,7 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Arabica::DOM::Ele void SCXMLDotWriter::writeTransitionElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem) { std::string elemId = idForNode(elem); - Arabica::XPath::NodeSet<std::string> targetStates = _interpreter.getTargetStates(elem); + Arabica::XPath::NodeSet<std::string> targetStates = _interpreter.getImpl()->getTargetStates(elem); bool active = (elem == _transition); @@ -256,7 +256,7 @@ std::string SCXMLDotWriter::getDetailedLabel(const Arabica::DOM::Element<std::st if (childElems.item(i).getNodeType() != Node_base::ELEMENT_NODE) continue; - if (Interpreter::isState(childElems.item(i)) || + if (InterpreterImpl::isState(childElems.item(i)) || iequals(TAGNAME(childElems.item(i)), "transition") || iequals(TAGNAME(childElems.item(i)), "initial") || false) diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index f80ad24..8be2634 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -31,152 +31,321 @@ using namespace Arabica::XPath; using namespace Arabica::DOM; // see: http://www.w3.org/TR/scxml/#AlgorithmforSCXMLInterpretation + void InterpreterDraft6::interpret() { - try { - tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); - if (!_isInitialized) - init(); + InterpreterState state; + while(true) { + state = step(true); + + switch (state) { + case uscxml::INIT_FAILED: + case uscxml::FINISHED: + case uscxml::INTERRUPTED: + // 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: + + // process invokers on main thread + if(_thread == NULL) { + runOnMainThread(200); + } - if (!_scxml) { - return; + // process next step + break; } - // dump(); - - // just make sure we have a session id - assert(_sessionId.length() > 0); + } +} - setupIOProcessors(); +// setup / fetch the documents initial transitions +NodeSet<std::string> InterpreterDraft6::getDocumentInitialTransitions() { + NodeSet<std::string> initialTransitions; + + if (_userDefinedStartConfiguration.size() > 0) { + // we emulate entering a given configuration by creating a pseudo deep history + Element<std::string> initHistory = _document.createElementNS(_nsInfo.nsURL, "history"); + _nsInfo.setPrefix(initHistory); + + initHistory.setAttribute("id", UUID::getUUID()); + initHistory.setAttribute("type", "deep"); + _scxml.insertBefore(initHistory, _scxml.getFirstChild()); + + std::string histId = ATTR(initHistory, "id"); + NodeSet<std::string> histStates; + for (int i = 0; i < _userDefinedStartConfiguration.size(); i++) { + histStates.push_back(getState(_userDefinedStartConfiguration[i])); + } + _historyValue[histId] = histStates; + + Element<std::string> initialElem = _document.createElementNS(_nsInfo.nsURL, "initial"); + _nsInfo.setPrefix(initialElem); + + initialElem.setAttribute("generated", "true"); + Element<std::string> transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition"); + _nsInfo.setPrefix(transitionElem); + + transitionElem.setAttribute("target", histId); + initialElem.appendChild(transitionElem); + _scxml.appendChild(initialElem); + initialTransitions.push_back(transitionElem); + + } else { + // try to get initial transition from initial element + initialTransitions = _xpath.evaluate("/" + _nsInfo.xpathPrefix + "initial/" + _nsInfo.xpathPrefix + "transition", _scxml).asNodeSet(); + if (initialTransitions.size() == 0) { + Arabica::XPath::NodeSet<std::string> initialStates; + // fetch per draft + initialStates = getInitialStates(); + assert(initialStates.size() > 0); + for (int i = 0; i < initialStates.size(); i++) { + Element<std::string> initialElem = _document.createElementNS(_nsInfo.nsURL, "initial"); + _nsInfo.setPrefix(initialElem); + + initialElem.setAttribute("generated", "true"); + Element<std::string> transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition"); + _nsInfo.setPrefix(transitionElem); + + transitionElem.setAttribute("target", ATTR(initialStates[i], "id")); + initialElem.appendChild(transitionElem); + _scxml.appendChild(initialElem); + initialTransitions.push_back(transitionElem); + } + } + } + return initialTransitions; +} + +// a macrostep +InterpreterState InterpreterDraft6::step(bool blocking) { + try { - std::string datamodelName; - if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "datamodel")) - datamodelName = ATTR(_scxml, "datamodel"); - if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "profile")) // SCION SCXML uses profile to specify datamodel - datamodelName = ATTR(_scxml, "profile"); - if(datamodelName.length() > 0) { - _dataModel = _factory->createDataModel(datamodelName, this); - if (!_dataModel) { - Event e; - e.data.compound["cause"] = Data("Cannot instantiate datamodel", Data::VERBATIM); - throw e; + monIter_t monIter; + 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 (!_running) + return FINISHED; + + // read an external event and react + if (blocking) { + // wait until an event becomes available + while(_externalQueue.isEmpty()) { + _condVar.wait(_mutex); } } else { - _dataModel = _factory->createDataModel("null", this); - } - if(datamodelName.length() > 0 && !_dataModel) { - LOG(ERROR) << "No datamodel for " << datamodelName << " registered"; + // return immediately if external queue is empty + if (_externalQueue.isEmpty()) + return NOTHING_TODO; } + _currEvent = _externalQueue.pop(); - if (_dataModel) { - _dataModel.assign("_x.args", _cmdLineOptions); + #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; + } else { + std::cout << "Aborting " << this << std::endl; } + #endif + _currEvent.eventType = Event::EXTERNAL; // make sure it is set to external - _running = true; -#if VERBOSE - std::cout << "running " << this << std::endl; -#endif - - _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY); - - // @TODO: Reread http://www.w3.org/TR/scxml/#DataBinding - - if (_dataModel && _binding == EARLY) { - // initialize all data elements - NodeSet<std::string> dataElems = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "data", _scxml).asNodeSet(); - for (unsigned int i = 0; i < dataElems.size(); i++) { - // do not process data elements of nested documents from invokers - if (!getAncestorElement(dataElems[i], _nsInfo.xmlNSPrefix + "invoke")) - if (dataElems[i].getNodeType() == Node_base::ELEMENT_NODE) { - initializeData(Element<std::string>(dataElems[i])); - } - } - } else if(_dataModel) { - // initialize current data elements - NodeSet<std::string> topDataElems = filterChildElements(_nsInfo.xmlNSPrefix + "data", filterChildElements(_nsInfo.xmlNSPrefix + "datamodel", _scxml)); - for (unsigned int i = 0; i < topDataElems.size(); i++) { - if (topDataElems[i].getNodeType() == Node_base::ELEMENT_NODE) - initializeData(Element<std::string>(topDataElems[i])); + // when we were blocking on destructor invocation + if (!_running) { + goto EXIT_INTERPRETER; + return INTERRUPTED; + } + // --- MONITOR: beforeProcessingEvent ------------------------------ + for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) { + try { + (*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent); } + USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent) + } + + if (iequals(_currEvent.name, "cancel.invoke." + _sessionId)) + return INTERRUPTED; + + try { + _dataModel.setEvent(_currEvent); + } catch (Event e) { + LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl << _currEvent; } - // executeGlobalScriptElements - NodeSet<std::string> globalScriptElems = filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml); - for (unsigned int i = 0; i < globalScriptElems.size(); i++) { - if (_dataModel) { - executeContent(globalScriptElems[i]); + 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; + } } } - NodeSet<std::string> initialTransitions; - - if (_userDefinedStartConfiguration.size() > 0) { - // we emulate entering a given configuration by creating a pseudo deep history - Element<std::string> initHistory = _document.createElementNS(_nsInfo.nsURL, "history"); - _nsInfo.setPrefix(initHistory); - - initHistory.setAttribute("id", UUID::getUUID()); - initHistory.setAttribute("type", "deep"); - _scxml.insertBefore(initHistory, _scxml.getFirstChild()); + + // run internal processing until we reach a stable configuration again + enabledTransitions = selectTransitions(_currEvent.name); + if (!enabledTransitions.empty()) { + // test 403b + enabledTransitions.to_document_order(); + microstep(enabledTransitions); + } - std::string histId = ATTR(initHistory, "id"); - NodeSet<std::string> histStates; - for (int i = 0; i < _userDefinedStartConfiguration.size(); i++) { - histStates.push_back(getState(_userDefinedStartConfiguration[i])); + stabilize(); + return PROCESSED; + + 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) } - _historyValue[histId] = histStates; - - Element<std::string> initialElem = _document.createElementNS(_nsInfo.nsURL, "initial"); - _nsInfo.setPrefix(initialElem); - - initialElem.setAttribute("generated", "true"); - Element<std::string> transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition"); - _nsInfo.setPrefix(transitionElem); - - transitionElem.setAttribute("target", histId); - initialElem.appendChild(transitionElem); - _scxml.appendChild(initialElem); - initialTransitions.push_back(transitionElem); - - } else { - // try to get initial transition from initial element - initialTransitions = _xpath.evaluate("/" + _nsInfo.xpathPrefix + "initial/" + _nsInfo.xpathPrefix + "transition", _scxml).asNodeSet(); - if (initialTransitions.size() == 0) { - Arabica::XPath::NodeSet<std::string> initialStates; - // fetch per draft - initialStates = getInitialStates(); - assert(initialStates.size() > 0); - for (int i = 0; i < initialStates.size(); i++) { - Element<std::string> initialElem = _document.createElementNS(_nsInfo.nsURL, "initial"); - _nsInfo.setPrefix(initialElem); - - initialElem.setAttribute("generated", "true"); - Element<std::string> transitionElem = _document.createElementNS(_nsInfo.nsURL, "transition"); - _nsInfo.setPrefix(transitionElem); - - transitionElem.setAttribute("target", ATTR(initialStates[i], "id")); - initialElem.appendChild(transitionElem); - _scxml.appendChild(initialElem); - initialTransitions.push_back(transitionElem); + + 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) } + return FINISHED; } + + assert(hasLegalConfiguration()); + _mutex.unlock(); - assert(initialTransitions.size() > 0); + // remove datamodel + if(_dataModel) + _dataModel = DataModel(); - enterStates(initialTransitions); - // _mutex.unlock(); - - // assert(hasLegalConfiguration()); - mainEventLoop(); + return PROCESSED; + } catch (boost::bad_weak_ptr e) { LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl; + return INTERRUPTED; } + // set datamodel to null from this thread if(_dataModel) _dataModel = DataModel(); } +// process transitions until we are in a stable configuration again +void InterpreterDraft6::stabilize() { + + monIter_t monIter; + NodeSet<std::string> enabledTransitions; + _stable = false; + + if (_configuration.size() == 0) { + // goto initial configuration + NodeSet<std::string> initialTransitions = getDocumentInitialTransitions(); + assert(initialTransitions.size() > 0); + enterStates(initialTransitions); + } + + do { // process microsteps for enabled transitions until there are no more left + + enabledTransitions = selectEventlessTransitions(); + + if (enabledTransitions.size() == 0) { + if (_internalQueue.size() == 0) { + _stable = true; + } else { + _currEvent = _internalQueue.front(); + _internalQueue.pop_front(); +#if VERBOSE + 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) + } + + if (_dataModel) + _dataModel.setEvent(_currEvent); + enabledTransitions = selectTransitions(_currEvent.name); + } + } + + if (!enabledTransitions.empty()) { + // test 403b + enabledTransitions.to_document_order(); + 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) + } + + // 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]); + } + } + } + _statesToInvoke = NodeSet<std::string>(); + +} +#if 0 void InterpreterDraft6::mainEventLoop() { monIter_t monIter; @@ -234,24 +403,15 @@ void InterpreterDraft6::mainEventLoop() { } } } - _statesToInvoke = NodeSet<std::string>(); + if (!_internalQueue.empty()) continue; // assume that we have a legal configuration as soon as the internal queue is empty assert(hasLegalConfiguration()); -#if 0 - std::cout << "Configuration: "; - for (int i = 0; i < _configuration.size(); i++) { - std::cout << ATTR(_configuration[i], "id") << ", "; - } - std::cout << std::endl; -#endif - monIter = _monitors.begin(); -// if (!_sendQueue || _sendQueue->isEmpty()) { // --- MONITOR: onStableConfiguration ------------------------------ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) { @@ -261,9 +421,8 @@ void InterpreterDraft6::mainEventLoop() { USCXML_MONITOR_CATCH_BLOCK(onStableConfiguration) } -// } - _mutex.unlock(); + // whenever we have a stable configuration, run the mainThread hooks with 200fps while(_externalQueue.isEmpty() && _thread == NULL) { runOnMainThread(200); @@ -304,46 +463,6 @@ void InterpreterDraft6::mainEventLoop() { LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl << _currEvent; } } -#if 0 - for (unsigned int i = 0; i < _configuration.size(); i++) { - NodeSet<std::string> invokes = filterChildElements(_xmlNSPrefix + "invoke", _configuration[i]); - for (unsigned int j = 0; j < invokes.size(); j++) { - Element<std::string> invokeElem = (Element<std::string>)invokes[j]; - std::string invokeId; - if (HAS_ATTR(invokeElem, "id")) { - invokeId = ATTR(invokeElem, "id"); - } else { - if (HAS_ATTR(invokeElem, "idlocation") && _dataModel) { - try { - invokeId = _dataModel.evalAsString(ATTR(invokeElem, "idlocation")); - } catch(Event e) { - LOG(ERROR) << "Syntax error while assigning idlocation from invoke:" << std::endl << e << std::endl; - } - } - } - std::string autoForward = invokeElem.getAttribute("autoforward"); - if (iequals(invokeId, _currEvent.invokeid)) { - - Arabica::XPath::NodeSet<std::string> finalizes = filterChildElements(_xmlNSPrefix + "finalize", invokeElem); - for (int k = 0; k < finalizes.size(); k++) { - Element<std::string> finalizeElem = Element<std::string>(finalizes[k]); - executeContent(finalizeElem); - } - - } - if (iequals(autoForward, "true")) { - 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")) - _invokers[invokeId].send(_currEvent); - } catch(...) { - LOG(ERROR) << "Exception caught while sending event to invoker " << invokeId; - } - } - } - } -#else for (std::map<std::string, Invoker>::iterator invokeIter = _invokers.begin(); invokeIter != _invokers.end(); invokeIter++) { @@ -365,7 +484,6 @@ void InterpreterDraft6::mainEventLoop() { } } } -#endif enabledTransitions = selectTransitions(_currEvent.name); if (!enabledTransitions.empty()) { // test 403b @@ -401,7 +519,8 @@ EXIT_INTERPRETER: } } - +#endif + Arabica::XPath::NodeSet<std::string> InterpreterDraft6::selectTransitions(const std::string& event) { Arabica::XPath::NodeSet<std::string> enabledTransitions; @@ -627,7 +746,7 @@ NEXT_ANCESTOR: } void InterpreterDraft6::microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { -#if 0 +#if VERBOSE std::cout << "Transitions: "; for (int i = 0; i < enabledTransitions.size(); i++) { std::cout << ((Element<std::string>)getSourceState(enabledTransitions[i])).getAttribute("id") << " -> " << std::endl; @@ -685,6 +804,9 @@ void InterpreterDraft6::microstep(const Arabica::XPath::NodeSet<std::string>& en } void InterpreterDraft6::exitInterpreter() { +#if VERBOSE + std::cout << "Exiting interpreter " << _name << std::endl; +#endif NodeSet<std::string> statesToExit = _configuration; statesToExit.forward(false); statesToExit.sort(); @@ -712,7 +834,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e monIter_t monIter; #if VERBOSE - std::cout << "Enabled exit transitions: " << std::endl; + std::cout << _name << ": Enabled exit transitions: " << std::endl; for (int i = 0; i < enabledTransitions.size(); i++) { std::cout << enabledTransitions[i] << std::endl; } @@ -741,7 +863,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e tmpStates.push_back(source); tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end()); #if VERBOSE - std::cout << "tmpStates: "; + std::cout << _name << ": tmpStates: "; for (int i = 0; i < tmpStates.size(); i++) { std::cout << ATTR(tmpStates[i], "id") << ", "; } @@ -750,7 +872,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e ancestor = findLCCA(tmpStates); } #if VERBOSE - std::cout << "Ancestor: " << ATTR(ancestor, "id") << std::endl;; + std::cout << _name << ": Ancestor: " << ATTR(ancestor, "id") << std::endl;; #endif for (int j = 0; j < _configuration.size(); j++) { if (isDescendant(_configuration[j], ancestor)) @@ -772,7 +894,7 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e statesToExit.sort(); #if VERBOSE - std::cout << "States to exit: "; + std::cout << _name << ": States to exit: "; for (int i = 0; i < statesToExit.size(); i++) { std::cout << LOCALNAME(statesToExit[i]) << ":" << ATTR(statesToExit[i], "id") << ", "; } @@ -795,8 +917,8 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e } } _historyValue[historyElem.getAttribute("id")] = historyNodes; -#if 0 - std::cout << "History node " << ATTR(historyElem, "id") << " contains: "; +#if VERBOSE + std::cout << _name << ": History node " << ATTR(historyElem, "id") << " contains: "; for (int i = 0; i < historyNodes.size(); i++) { std::cout << ATTR(historyNodes[i], "id") << ", "; } @@ -857,9 +979,9 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& monIter_t monIter; #if VERBOSE - std::cout << "Enabled enter transitions: " << std::endl; + std::cout << _name << ": Enabled enter transitions: " << std::endl; for (int i = 0; i < enabledTransitions.size(); i++) { - std::cout << enabledTransitions[i] << std::endl; + std::cout << "\t" << enabledTransitions[i] << std::endl; } std::cout << std::endl; #endif @@ -871,7 +993,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& NodeSet<std::string> tStates = getTargetStates(transition); #if VERBOSE - std::cout << "Target States: "; + std::cout << _name << ": Target States: "; for (int i = 0; i < tStates.size(); i++) { std::cout << ATTR(tStates[i], "id") << ", "; } @@ -881,7 +1003,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& Node<std::string> ancestor; Node<std::string> source = getSourceState(transition); #if VERBOSE - std::cout << "Source States: " << ATTR(source, "id") << std::endl; + std::cout << _name << ": Source States: " << ATTR(source, "id") << std::endl; #endif assert(source); @@ -905,7 +1027,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& } #if VERBOSE - std::cout << "Ancestor: " << ATTR(ancestor, "id") << std::endl; + std::cout << _name << ": Ancestor: " << ATTR(ancestor, "id") << std::endl; #endif for (int j = 0; j < tStates.size(); j++) { @@ -913,7 +1035,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& } #if VERBOSE - std::cout << "States to enter: "; + std::cout << _name << ": States to enter: "; for (int i = 0; i < statesToEnter.size(); i++) { std::cout << LOCALNAME(statesToEnter[i]) << ":" << ATTR(statesToEnter[i], "id") << ", "; } @@ -924,7 +1046,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& NodeSet<std::string> ancestors = getProperAncestors(tStates[j], ancestor); #if VERBOSE - std::cout << "Proper Ancestors of " << ATTR(tStates[j], "id") << " and " << ATTR(ancestor, "id") << ": "; + std::cout << _name << ": Proper Ancestors of " << ATTR(tStates[j], "id") << " and " << ATTR(ancestor, "id") << ": "; for (int i = 0; i < ancestors.size(); i++) { std::cout << ATTR(ancestors[i], "id") << ", "; } @@ -955,7 +1077,7 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& statesToEnter.to_document_order(); #if VERBOSE - std::cout << "States to enter: "; + std::cout << _name << ": States to enter: "; for (int i = 0; i < statesToEnter.size(); i++) { std::cout << ATTR(statesToEnter[i], "id") << ", "; } diff --git a/src/uscxml/interpreter/InterpreterDraft6.h b/src/uscxml/interpreter/InterpreterDraft6.h index 7550124..a958b47 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.h +++ b/src/uscxml/interpreter/InterpreterDraft6.h @@ -27,7 +27,8 @@ namespace uscxml { class InterpreterDraft6 : public InterpreterImpl { protected: void interpret(); - void mainEventLoop(); + InterpreterState step(bool blocking); + void stabilize(); void microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); void enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); @@ -44,6 +45,8 @@ protected: bool isPreemptingTransition(const Arabica::DOM::Node<std::string>& t1, const Arabica::DOM::Node<std::string>& t2); bool isEnabledTransition(const Arabica::DOM::Node<std::string>& transition, const std::string& event); + Arabica::XPath::NodeSet<std::string> getDocumentInitialTransitions(); + bool isCrossingBounds(const Arabica::DOM::Node<std::string>& transition); bool isWithinParallel(const Arabica::DOM::Node<std::string>& transition); Arabica::DOM::Node<std::string> findLCPA(const Arabica::XPath::NodeSet<std::string>& states); diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp index 3130d42..a064394 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp @@ -230,7 +230,7 @@ void JSCDataModel::setEvent(const Event& event) { handleException(exception); } else { JSStringRef propName = JSStringCreateWithUTF8CString("data"); - JSStringRef contentStr = JSStringCreateWithUTF8CString(Interpreter::spaceNormalize(event.content).c_str()); + JSStringRef contentStr = JSStringCreateWithUTF8CString(InterpreterImpl::spaceNormalize(event.content).c_str()); JSObjectSetProperty(_ctx, eventObj, propName, JSValueMakeString(_ctx, contentStr), 0, &exception); JSStringRelease(propName); JSStringRelease(contentStr); @@ -566,7 +566,7 @@ void JSCDataModel::assign(const Element<std::string>& assignElem, try { evalAsValue(key + " = " + content); } catch (...) { - evalAsValue(key + " = " + "\"" + Interpreter::spaceNormalize(content) + "\""); + evalAsValue(key + " = " + "\"" + InterpreterImpl::spaceNormalize(content) + "\""); } } else { JSObjectSetProperty(_ctx, JSContextGetGlobalObject(_ctx), JSStringCreateWithUTF8CString(key.c_str()), JSValueMakeUndefined(_ctx), 0, &exception); diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index bddea83..ec9557e 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -236,7 +236,7 @@ void V8DataModel::setEvent(const Event& event) { if (json) { eventObj->Set(v8::String::New("data"), getDataAsValue(json)); } else { - eventObj->Set(v8::String::New("data"), v8::String::New(Interpreter::spaceNormalize(event.content).c_str())); + eventObj->Set(v8::String::New("data"), v8::String::New(InterpreterImpl::spaceNormalize(event.content).c_str())); } } else { // _event.data is KVP @@ -603,7 +603,7 @@ void V8DataModel::assign(const Element<std::string>& assignElem, try { evalAsValue(key + " = " + content); } catch (...) { - evalAsValue(key + " = " + "\"" + Interpreter::spaceNormalize(content) + "\""); + evalAsValue(key + " = " + "\"" + InterpreterImpl::spaceNormalize(content) + "\""); } } else { global->Set(v8::String::New(key.c_str()), v8::Undefined()); diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp index 0ad6030..4cbe8f5 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp @@ -275,7 +275,7 @@ void SWIDataModel::setEvent(const Event& event) { dataInitStr << "load_xml_file('" << domUrl.asLocalFile(".pl") << "', XML), copy_term(XML,DATA), assert(event(data(DATA)))"; PlCall(dataInitStr.str().c_str()); } else if (event.content.size() > 0) { - PlCall("assert", PlCompound("event", PlCompound("data", PlString(Interpreter::spaceNormalize(event.content).c_str())))); + PlCall("assert", PlCompound("event", PlCompound("data", PlString(InterpreterImpl::spaceNormalize(event.content).c_str())))); } else if (event.data) { assertFromData(event.data, "event(data(", 2); } diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp index bf32bf9..4d9854b 100644 --- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp @@ -195,7 +195,7 @@ void XPathDataModel::setEvent(const Event& event) { } if (event.content.size() > 0) { - Text<std::string> textNode = _doc.createTextNode(Interpreter::spaceNormalize(event.content).c_str()); + Text<std::string> textNode = _doc.createTextNode(InterpreterImpl::spaceNormalize(event.content).c_str()); eventDataElem.appendChild(textNode); } if (event.dom) { @@ -501,7 +501,7 @@ void XPathDataModel::assign(const Element<std::string>& assignElem, } assign(key, nodeSet, assignElem); } else if (content.length() > 0) { - Text<std::string> textNode = _doc.createTextNode(Interpreter::spaceNormalize(content)); + Text<std::string> textNode = _doc.createTextNode(InterpreterImpl::spaceNormalize(content)); nodeSet.push_back(textNode); assign(key, nodeSet, assignElem); } else if (HAS_ATTR(assignElem, "expr")) { diff --git a/src/uscxml/plugins/element/respond/RespondElement.cpp b/src/uscxml/plugins/element/respond/RespondElement.cpp index f415b19..4fe0d2e 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 = Interpreter::filterChildElements(_interpreter->getXMLPrefixForNS(getNamespace()) + "content", node); + Arabica::XPath::NodeSet<std::string> contents = InterpreterImpl::filterChildElements(_interpreter->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 = Interpreter::filterChildElements(_interpreter->getXMLPrefixForNS(getNamespace()) + "header", node); + Arabica::XPath::NodeSet<std::string> headers = InterpreterImpl::filterChildElements(_interpreter->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/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp index d89d8ac..f232e52 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp @@ -43,7 +43,8 @@ USCXMLInvoker::~USCXMLInvoker() { _cancelled = true; Event event; event.name = "unblock.and.die"; - _invokedInterpreter.receive(event); + if (_invokedInterpreter) + _invokedInterpreter.receive(event); }; boost::shared_ptr<InvokerImpl> USCXMLInvoker::create(InterpreterImpl* interpreter) { @@ -84,6 +85,7 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) { if (_invokedInterpreter) { DataModel dataModel(_invokedInterpreter.getImpl()->getDataModel()); _invokedInterpreter.getImpl()->setParentQueue(&_parentQueue); + // transfer namespace prefixes _invokedInterpreter.setNameSpaceInfo(_parentInterpreter->getNameSpaceInfo()); _invokedInterpreter.getImpl()->_sessionId = req.invokeid; @@ -92,7 +94,6 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) { _invokedInterpreter.getImpl()->setInvokeRequest(req); _invokedInterpreter.start(); -// tthread::this_thread::sleep_for(tthread::chrono::seconds(1)); } else { /// test 530 _parentInterpreter->receive(Event("done.invoke." + _invokeId, Event::PLATFORM)); diff --git a/src/uscxml/transform/ChartToFSM.cpp b/src/uscxml/transform/ChartToFSM.cpp index 8b1725c..7f38397 100644 --- a/src/uscxml/transform/ChartToFSM.cpp +++ b/src/uscxml/transform/ChartToFSM.cpp @@ -902,7 +902,7 @@ GlobalState::GlobalState(const Arabica::XPath::NodeSet<std::string>& activeState std::ostringstream idSS; idSS << "active-"; for (int i = 0; i < activeStates.size(); i++) { - if (!Interpreter::isFinal(activeStates[i])) + if (!InterpreterImpl::isFinal(activeStates[i])) isFinal = false; idSS << ATTR(activeStates[i], "id") << "-"; } @@ -1043,7 +1043,7 @@ std::list<std::string> GlobalTransition::getCommonEvents(const NodeSet<std::stri for (int i = 0; i < transitions.size(); i++) { // for every transition - std::list<std::string> eventNames = Interpreter::tokenizeIdRefs(ATTR(transitions[i], "event")); + std::list<std::string> eventNames = InterpreterImpl::tokenizeIdRefs(ATTR(transitions[i], "event")); for (std::list<std::string>::iterator eventNameIter = eventNames.begin(); eventNameIter != eventNames.end(); @@ -1062,7 +1062,7 @@ std::list<std::string> GlobalTransition::getCommonEvents(const NodeSet<std::stri // check if token would activate all other transitions if (i == j) continue; - if (!Interpreter::nameMatch(ATTR(transitions[j], "event"), eventName)) { + if (!InterpreterImpl::nameMatch(ATTR(transitions[j], "event"), eventName)) { isMatching = false; break; } @@ -1080,7 +1080,7 @@ std::list<std::string> GlobalTransition::getCommonEvents(const NodeSet<std::stri for (std::list<std::string>::iterator innerEventNameIter = prefixes.begin(); innerEventNameIter != prefixes.end(); innerEventNameIter++) { - if (!iequals(*outerEventNameIter, *innerEventNameIter) && Interpreter::nameMatch(*outerEventNameIter, *innerEventNameIter)) { + if (!iequals(*outerEventNameIter, *innerEventNameIter) && InterpreterImpl::nameMatch(*outerEventNameIter, *innerEventNameIter)) { goto IS_PREFIX; } } |