diff options
-rw-r--r-- | src/uscxml/Interpreter.cpp | 41 | ||||
-rw-r--r-- | src/uscxml/Interpreter.h | 1 | ||||
-rw-r--r-- | src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp | 2 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToFSM.cpp | 57 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToFSM.h | 6 | ||||
-rw-r--r-- | src/uscxml/transform/FlatStateIdentifier.h | 39 | ||||
-rw-r--r-- | test/src/test-flat-stateid.cpp | 4 | ||||
-rw-r--r-- | test/src/test-w3c.cpp | 2 |
8 files changed, 101 insertions, 51 deletions
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 7a8b807..b9b5d94 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -23,6 +23,7 @@ #include "uscxml/URL.h" #include "uscxml/UUID.h" #include "uscxml/DOMUtils.h" +#include "uscxml/transform/FlatStateIdentifier.h" #include "uscxml/transform/ChartToFSM.h" // only for testing #include "getopt.h" @@ -371,8 +372,20 @@ Interpreter Interpreter::fromDOM(const Arabica::DOM::Document<std::string>& dom, tthread::lock_guard<tthread::recursive_mutex> lock(_instanceMutex); boost::shared_ptr<INTERPRETER_IMPL> interpreterImpl = boost::shared_ptr<INTERPRETER_IMPL>(new INTERPRETER_IMPL); Interpreter interpreter(interpreterImpl); + + // *copy* the given DOM to get rid of event listeners + + DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); + interpreterImpl->_document = domFactory.createDocument(dom.getNamespaceURI(), "", 0); + + Node<std::string> child = dom.getFirstChild(); + while (child) { + Node<std::string> newNode = interpreterImpl->_document.importNode(child, true); + interpreterImpl->_document.appendChild(newNode); + child = child.getNextSibling(); + } + interpreterImpl->setNameSpaceInfo(nameSpaceInfo); - interpreterImpl->_document = dom; interpreterImpl->setupDOM(); // interpreterImpl->init(); @@ -759,7 +772,6 @@ void InterpreterImpl::setupDOM() { eventTarget.addEventListener("DOMNodeInserted", _domEventListener, true); eventTarget.addEventListener("DOMNodeRemoved", _domEventListener, true); eventTarget.addEventListener("DOMSubtreeModified", _domEventListener, true); - _domIsSetup = true; } @@ -1262,6 +1274,8 @@ void InterpreterImpl::delayedSend(void* userdata, std::string eventName) { ioProc.send(sendReq); } catch(Event e) { throw e; + } catch (const std::exception &e) { + LOG(ERROR) << "Exception caught while sending event to ioprocessor " << sendReq.type << ":" << e.what(); } catch(...) { LOG(ERROR) << "Exception caught while sending event to ioprocessor " << sendReq.type; } @@ -1425,11 +1439,15 @@ void InterpreterImpl::invoke(const Arabica::DOM::Element<std::string>& element) } catch(boost::bad_lexical_cast e) { LOG(ERROR) << "Exception caught while sending invoke request to invoker " << invokeReq.invokeid << ": " << e.what(); + } catch (const std::exception &e) { + LOG(ERROR) << "Unknown exception caught while sending invoke request to invoker " << invokeReq.invokeid << ": " << e.what(); } catch(...) { LOG(ERROR) << "Unknown exception caught while sending invoke request to invoker " << invokeReq.invokeid; } try { // _dataModel.assign("_invokers['" + invokeReq.invokeid + "']", invoker.getDataModelVariables()); + } catch (const std::exception &e) { + LOG(ERROR) << "Exception caught while assigning datamodel variables from invoker " << invokeReq.invokeid << ": " << e.what(); } catch(...) { LOG(ERROR) << "Exception caught while assigning datamodel variables from invoker " << invokeReq.invokeid; } @@ -1906,6 +1924,8 @@ void InterpreterImpl::finalizeAndAutoForwardCurrentEvent() { // Yes do so, see test229! // if (!boost::equals(_currEvent.getOriginType(), "http://www.w3.org/TR/scxml/#SCXMLEventProcessor")) invokeIter->second.send(_currEvent); + } catch (const std::exception &e) { + LOG(ERROR) << "Exception caught while sending event to invoker " << invokeIter->first << ": " << e.what(); } catch(...) { LOG(ERROR) << "Exception caught while sending event to invoker " << invokeIter->first; } @@ -2718,18 +2738,10 @@ bool InterpreterImpl::isInState(const std::string& stateId) { // extension for flattened SCXML documents if (_configuration.size() > 0 && HAS_ATTR_CAST(_configuration[0], "id")) { // all states are encoded in the current statename - std::string encStateList = ATTR_CAST(_configuration[0], "id"); - size_t startActive = encStateList.find_first_of("-"); - size_t endActive = encStateList.find_first_of(";"); - encStateList = encStateList.substr(startActive, endActive - startActive); - std::stringstream ss(encStateList); - std::string unencodedStateId; - while(std::getline(ss, unencodedStateId, '-')) { - if (unencodedStateId.length() == 0) - continue; - if (iequals(unencodedStateId, stateId)) { + FlatStateIdentifier flatId(ATTR_CAST(_configuration[0], "id")); + for (std::list<std::string>::const_iterator iter = flatId.getActive().begin(); iter != flatId.getActive().end(); iter++) { + if (iequals(stateId, *iter)) return true; - } } } return false; @@ -2765,7 +2777,8 @@ void InterpreterImpl::handleDOMEvent(Arabica::DOM::Events::Event<std::string>& e } void InterpreterImpl::DOMEventListener::handleEvent(Arabica::DOM::Events::Event<std::string>& event) { - _interpreter->handleDOMEvent(event); + if (_interpreter) + _interpreter->handleDOMEvent(event); } std::ostream& operator<< (std::ostream& os, const InterpreterState& interpreterState) { diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index c3acc98..66379f9 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -443,6 +443,7 @@ protected: class DOMEventListener : public Arabica::DOM::Events::EventListener<std::string> { public: + DOMEventListener() : _interpreter(NULL) {} void handleEvent(Arabica::DOM::Events::Event<std::string>& event); InterpreterImpl* _interpreter; }; diff --git a/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp index 00b47f4..9ba3e63 100644 --- a/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp @@ -162,6 +162,8 @@ void SCXMLIOProcessor::send(const SendRequest& req) { } catch(Event e) { // Is this the right thing to do? _interpreter->receive(e); + } catch (const std::exception &e) { + LOG(ERROR) << "Exception caught while sending event to invoker " << invokeId << ": " << e.what(); } catch(...) { LOG(ERROR) << "Exception caught while sending event to invoker " << invokeId; } diff --git a/src/uscxml/transform/ChartToFSM.cpp b/src/uscxml/transform/ChartToFSM.cpp index 9665b56..073805f 100644 --- a/src/uscxml/transform/ChartToFSM.cpp +++ b/src/uscxml/transform/ChartToFSM.cpp @@ -19,6 +19,7 @@ #include "uscxml/transform/ChartToFSM.h" #include "uscxml/transform/FlatStateIdentifier.h" +#include "uscxml/Convenience.h" #include "uscxml/Factory.h" #include <DOM/io/Stream.hpp> @@ -202,9 +203,11 @@ InterpreterState FlatteningInterpreter::interpret() { _currGlobalTransition = NULL; // very first state - _start = new GlobalState(_configuration, _alreadyEntered, _historyValue); + GlobalState::gIndex = 0; + _start = new GlobalState(_configuration, _alreadyEntered, _historyValue, _nsInfo.xmlNSPrefix); _globalConf[_start->stateId] = _start; - + _globalConf[_start->stateId]->index = GlobalState::gIndex++; + NodeSet<std::string> initialTransitions; // enter initial configuration @@ -246,13 +249,16 @@ InterpreterState FlatteningInterpreter::interpret() { #endif createDocument(); - + NodeSet<std::string> elements = InterpreterImpl::filterChildType(Node_base::ELEMENT_NODE, _scxml, true); uint64_t nrStates = 0; for (int i = 0; i < elements.size(); i++) { - Element<std::string> stateElem = Element<std::string>(elements[i]); - if (isState(stateElem) && !HAS_ATTR(stateElem, "transient")) + Element<std::string> elem = Element<std::string>(elements[i]); + if (isState(elem) && !HAS_ATTR(elem, "transient")) nrStates++; + if (elem.getLocalName() == "transition" && elem.hasAttribute("id")) { + elem.removeAttribute("id"); + } } std::cout << "Actual Complexity: " << nrStates << std::endl; @@ -442,7 +448,7 @@ void FlatteningInterpreter::explode() { std::map<std::string, Arabica::XPath::NodeSet<std::string> > historyValue = _historyValue; // create current state from global configuration - GlobalState* globalState = new GlobalState(configuration, alreadyEntered, historyValue); + GlobalState* globalState = new GlobalState(configuration, alreadyEntered, historyValue, _nsInfo.xmlNSPrefix); // remember that the last transition lead here if (_currGlobalTransition) { @@ -465,10 +471,14 @@ void FlatteningInterpreter::explode() { delete globalState; return; // we have already been here } + _globalConf[globalState->stateId] = globalState; - + _globalConf[globalState->stateId]->index = GlobalState::gIndex++; assert(isLegalConfiguration(configuration)); + if(_globalConf[globalState->stateId]->isFinal) + return; // done in this branch + // get all transition elements from states in the current configuration NodeSet<std::string> allTransitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", configuration); @@ -673,6 +683,10 @@ NEXT_DEPTH: } } +static bool sortStatesByIndex(const std::pair<std::string,GlobalState*>& s1, const std::pair<std::string,GlobalState*>& s2) { + return s1.second->index < s2.second->index; +} + void FlatteningInterpreter::createDocument() { Element<std::string> _origSCXML = _scxml; @@ -720,8 +734,12 @@ void FlatteningInterpreter::createDocument() { _scxml.appendChild(imported); } - for (std::map<std::string, GlobalState*>::iterator confIter = _globalConf.begin(); - confIter != _globalConf.end(); + std::vector<std::pair<std::string,GlobalState*> > sortedStates; + sortedStates.insert(sortedStates.begin(), _globalConf.begin(), _globalConf.end()); + std::sort(sortedStates.begin(), sortedStates.end(), sortStatesByIndex); + + for (std::vector<std::pair<std::string,GlobalState*> >::iterator confIter = sortedStates.begin(); + confIter != sortedStates.end(); confIter++) { Node<std::string> state = globalStateToNode(confIter->second); _scxml.appendChild(state); @@ -739,6 +757,8 @@ Node<std::string> FlatteningInterpreter::globalStateToNode(GlobalState* globalSt if (globalState->isFinal) state.setAttribute("final", "true"); +// state.setAttribute("index", toStr(globalState->index)); + std::list<GlobalTransition*> transitionList; for (std::map<std::string, GlobalTransition*>::iterator outIter = globalState->outgoing.begin(); outIter != globalState->outgoing.end(); @@ -985,22 +1005,27 @@ void FlatteningInterpreter::beforeEnteringState(Interpreter interpreter, const A void FlatteningInterpreter::beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, bool moreComing) { } - +int GlobalState::gIndex = 0; GlobalState::GlobalState(const Arabica::XPath::NodeSet<std::string>& activeStates_, const Arabica::XPath::NodeSet<std::string>& alreadyEnteredStates_, // we need to remember for binding=late - const std::map<std::string, Arabica::XPath::NodeSet<std::string> >& historyStates_) { + const std::map<std::string, Arabica::XPath::NodeSet<std::string> >& historyStates_, + const std::string& xmlNSPrefix) { // make copies and sort activeStates = activeStates_; alreadyEnteredStates = alreadyEnteredStates_; historyStates = historyStates_; - isFinal = true; // is set to false if we contain a non-final state + isFinal = false; - // start state is not final - if (activeStates.size() == 0) { - isFinal = false; + for(int i = 0; i < activeStates.size(); i++) { + Arabica::DOM::Element<std::string> state = Arabica::DOM::Element<std::string>(activeStates[i]); + Arabica::DOM::Element<std::string> parentElem = (Arabica::DOM::Element<std::string>)state.getParentNode(); + if(InterpreterImpl::isFinal(state) && iequals(parentElem.getTagName(), xmlNSPrefix + "scxml")) { + isFinal = true; + break; + } } - + // sort configuration activeStates.to_document_order(); alreadyEnteredStates.to_document_order(); diff --git a/src/uscxml/transform/ChartToFSM.h b/src/uscxml/transform/ChartToFSM.h index aeeb058..5ee5c8e 100644 --- a/src/uscxml/transform/ChartToFSM.h +++ b/src/uscxml/transform/ChartToFSM.h @@ -38,7 +38,8 @@ public: GlobalState() {} GlobalState(const Arabica::XPath::NodeSet<std::string>& activeStates, const Arabica::XPath::NodeSet<std::string>& alreadyEnteredStates, // we need to remember for binding=late - const std::map<std::string, Arabica::XPath::NodeSet<std::string> >& historyStates); + const std::map<std::string, Arabica::XPath::NodeSet<std::string> >& historyStates, + const std::string& xmlNSPrefix); Arabica::XPath::NodeSet<std::string> activeStates; Arabica::XPath::NodeSet<std::string> alreadyEnteredStates; @@ -48,6 +49,9 @@ public: std::map<std::string, GlobalTransition*> outgoing; std::string stateId; + static int gIndex; + + int index; bool isFinal; }; diff --git a/src/uscxml/transform/FlatStateIdentifier.h b/src/uscxml/transform/FlatStateIdentifier.h index 3a9ee49..61d0f1b 100644 --- a/src/uscxml/transform/FlatStateIdentifier.h +++ b/src/uscxml/transform/FlatStateIdentifier.h @@ -142,34 +142,39 @@ protected: std::stringstream stateIdSS; std::string seperator; + stateIdSS << "active:{"; for (std::list<std::string>::const_iterator actIter = active.begin(); actIter != active.end(); actIter++) { stateIdSS << seperator << *actIter; seperator = ","; } - stateIdSS << "};"; + stateIdSS << "}"; - seperator = ""; - stateIdSS << "entered:{"; - for (std::list<std::string>::const_iterator visitIter = visited.begin(); visitIter != visited.end(); visitIter++) { - stateIdSS << seperator << *visitIter; - seperator = ","; + if (visited.size() > 0) { + seperator = ""; + stateIdSS << ";entered:{"; + for (std::list<std::string>::const_iterator visitIter = visited.begin(); visitIter != visited.end(); visitIter++) { + stateIdSS << seperator << *visitIter; + seperator = ","; + } + stateIdSS << "}"; } - stateIdSS << "};"; - seperator = ""; - stateIdSS << "history:{"; - for (std::map<std::string, std::list<std::string> >::const_iterator histIter = histories.begin(); histIter != histories.end(); histIter++) { - stateIdSS << seperator << histIter->first << ":{"; - seperator = ","; - std::string itemSeperator; - for (std::list<std::string>::const_iterator histItemIter = histIter->second.begin(); histItemIter != histIter->second.end(); histItemIter++) { - stateIdSS << itemSeperator << *histItemIter; - itemSeperator = ","; + if (histories.size() > 0) { + seperator = ""; + stateIdSS << ";history:{"; + for (std::map<std::string, std::list<std::string> >::const_iterator histIter = histories.begin(); histIter != histories.end(); histIter++) { + stateIdSS << seperator << histIter->first << ":{"; + seperator = ","; + std::string itemSeperator; + for (std::list<std::string>::const_iterator histItemIter = histIter->second.begin(); histItemIter != histIter->second.end(); histItemIter++) { + stateIdSS << itemSeperator << *histItemIter; + itemSeperator = ","; + } + stateIdSS << "}"; } stateIdSS << "}"; } - stateIdSS << "}"; stateId = stateIdSS.str(); } diff --git a/test/src/test-flat-stateid.cpp b/test/src/test-flat-stateid.cpp index 7bc826c..6eb1ed8 100644 --- a/test/src/test-flat-stateid.cpp +++ b/test/src/test-flat-stateid.cpp @@ -5,7 +5,7 @@ int main(int argc, char** argv) { std::list<std::string>::const_iterator listIter; { - std::string stateId = "active:{};entered:{};history:{}"; + std::string stateId = "active:{}"; uscxml::FlatStateIdentifier flat1(stateId); assert(flat1.getActive().size() == 0); assert(flat1.getVisited().size() == 0); @@ -16,7 +16,7 @@ int main(int argc, char** argv) { } { - std::string stateId = "active:{s1};entered:{s1,s2};history:{}"; + std::string stateId = "active:{s1};entered:{s1,s2}"; uscxml::FlatStateIdentifier flat1(stateId); assert(flat1.getActive().size() == 1); assert(flat1.getVisited().size() == 2); diff --git a/test/src/test-w3c.cpp b/test/src/test-w3c.cpp index 7eb54a7..6a3294d 100644 --- a/test/src/test-w3c.cpp +++ b/test/src/test-w3c.cpp @@ -145,7 +145,7 @@ class W3CStatusMonitor : public uscxml::InterpreterMonitor { if (config.size() == 1) { if (withFlattening) { std::cout << ATTR_CAST(config[0], "id") << std::endl; - if (boost::starts_with(ATTR_CAST(config[0], "id"), "active-pass")) { + if (boost::starts_with(ATTR_CAST(config[0], "id"), "active:{pass")) { std::cout << "TEST SUCCEEDED" << std::endl; exit(EXIT_SUCCESS); } |