/** * @file * @author 2012-2013 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 . * @endcond */ #ifndef RUNTIME_H_SQ1MBKGN #define RUNTIME_H_SQ1MBKGN // this has to be the first include or MSVC will run amok #include "uscxml/config.h" #include "uscxml/Common.h" #include "uscxml/util/String.h" #include // arabica xpath uses cerr without iostream #include #include #include #include "uscxml/InterpreterInfo.h" #include #include #include "uscxml/concurrency/BlockingQueue.h" #include "uscxml/messages/Data.h" #include "uscxml/messages/SendRequest.h" #include "uscxml/debug/InterpreterIssue.h" #include "uscxml/URL.h" #include "uscxml/plugins/DataModel.h" #include "uscxml/plugins/IOProcessor.h" #include "uscxml/plugins/Invoker.h" #include "uscxml/plugins/ExecutableContent.h" #include "dom/DOMUtils.h" #ifndef TIME_BLOCK # ifdef BUILD_PROFILING # include "uscxml/concurrency/Timer.h" # define TIME_BLOCK Measurement msm(&timer); # else # define TIME_BLOCK # endif #endif #define ERROR_PLATFORM_THROW(msg) \ Event e; \ e.name = "error.platform"; \ e.data.compound["cause"] = Data(msg, Data::VERBATIM); \ throw e; \ #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 occurred when calling " #callback " on monitors"; \ } \ if (_state == 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 { class HTTPServletInvoker; class InterpreterMonitor; class InterpreterHTTPServlet; class InterpreterWebSocketServlet; class Factory; class DelayedEventQueue; enum Capabilities { CAN_NOTHING = 0, CAN_BASIC_HTTP = 1, CAN_GENERIC_HTTP = 2, }; class USCXML_API InterpreterOptions { public: InterpreterOptions() : withDebugger(false), verbose(false), checking(false), withHTTP(true), withHTTPS(true), withWS(true), logLevel(0), httpPort(5080), httpsPort(5443), wsPort(5081) { } bool withDebugger; bool verbose; bool checking; bool withHTTP; bool withHTTPS; bool withWS; int logLevel; unsigned short httpPort; unsigned short httpsPort; unsigned short wsPort; std::string pluginPath; std::string certificate; std::string privateKey; std::string publicKey; std::vector > interpreters; std::map additionalParameters; std::string error; operator bool() { return error.length() == 0; } static void printUsageAndExit(const char* progName); static InterpreterOptions fromCmdLine(int argc, char** argv); unsigned int getCapabilities(); }; enum InterpreterState { USCXML_DESTROYED = -2, ///< destructor ran - users should never see this one USCXML_FINISHED = -1, ///< machine reached a final configuration and is done USCXML_IDLE = 0, ///< stable configuration and queues empty USCXML_INITIALIZED = 1, ///< DOM is setup and all external components instantiated USCXML_INSTANTIATED = 2, ///< nothing really, just instantiated USCXML_MICROSTEPPED = 3, ///< processed one transition set USCXML_MACROSTEPPED = 4, ///< processed all transition sets and reached a stable configuration }; USCXML_API std::ostream& operator<< (std::ostream& os, const InterpreterState& interpreterState); class USCXML_API InterpreterImpl : public InterpreterInfo, public boost::enable_shared_from_this { public: typedef std::set::iterator monIter_t; enum Binding { EARLY = 0, LATE = 1 }; virtual ~InterpreterImpl(); void cloneFrom(InterpreterImpl* other); void cloneFrom(boost::shared_ptr other); virtual void writeTo(std::ostream& stream); // TODO: We need to move the destructor to the implementations to make these pure virtual virtual InterpreterState interpret(); virtual InterpreterState step(int waitForMS = 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); } void removeMonitor(InterpreterMonitor* monitor) { _monitors.erase(monitor); } void setSourceURL(std::string sourceURL) { _sourceURL = URL(sourceURL); if (_scxml) { URL baseURL(sourceURL); URL::toBaseURL(baseURL); _baseURL[_scxml] = baseURL; } } std::string getSourceURL() { return _sourceURL.asString(); } std::string getBaseURL() { return getBaseURLForNode(_scxml); } std::string getBaseURL(const Arabica::DOM::Node& refNode) { return getBaseURLForNode(refNode); } std::string getBaseURL(const std::string& xpathExpr) { Arabica::XPath::NodeSet roots = _xpath.evaluate(xpathExpr, _scxml).asNodeSet(); if (roots.size() > 0) { return getBaseURLForNode(roots[0]); } return ""; } void setCmdLineOptions(std::map params); Data getCmdLineOptions() { return _cmdLineOptions; } InterpreterHTTPServlet* getHTTPServlet() { return _httpServlet; } void setParentQueue(uscxml::concurrency::BlockingQueue* parentQueue) { _parentQueue = parentQueue; } void setFactory(Factory* factory) { _factory = factory; } Factory* getFactory() { return _factory; } Arabica::XPath::NodeSet getNodeSetForXPath(const std::string& xpathExpr) { return _xpath.evaluate(xpathExpr, _scxml).asNodeSet(); } void setNameSpaceInfo(const NameSpaceInfo& nsInfo) { _nsInfo = nsInfo; _xpath.setNamespaceContext(*_nsInfo.getNSContext()); } NameSpaceInfo getNameSpaceInfo() const { return _nsInfo; } void receiveInternal(const Event& event); void receive(const Event& event, bool toFront = false); Event getCurrentEvent() { tthread::lock_guard lock(_mutex); return _currEvent; } virtual bool isInState(const std::string& stateId); Arabica::XPath::NodeSet getConfiguration() { tthread::lock_guard lock(_mutex); return _configuration; } Arabica::XPath::NodeSet getBasicConfiguration() { tthread::lock_guard lock(_mutex); Arabica::XPath::NodeSet basicConfig; for (size_t i = 0; i < _configuration.size(); i++) { if (isAtomic(Arabica::DOM::Element(_configuration[i]))) basicConfig.push_back(_configuration[i]); } return basicConfig; } void setInitalConfiguration(const std::list& states) { _startConfiguration = states; } void setInvokeRequest(const InvokeRequest& req) { _invokeReq = req; } virtual Arabica::DOM::Document getDocument() const { return _document; } void setCapabilities(unsigned int capabilities) { _capabilities = capabilities; } void setName(const std::string& name); const std::string& getName() { return _name; } const std::string& getSessionId() { return _sessionId; } DelayedEventQueue* getDelayQueue() { return _sendQueue; } void addIOProcessor(IOProcessor ioProc) { std::list names = ioProc.getNames(); std::list::iterator nameIter = names.begin(); while(nameIter != names.end()) { _ioProcessors[*nameIter] = ioProc; _ioProcessors[*nameIter].setType(names.front()); _ioProcessors[*nameIter].setInterpreter(this); nameIter++; } } const std::map& getIOProcessors() { return _ioProcessors; } void setDataModel(const DataModel& dataModel) { _userSuppliedDataModel = true; _dataModel = dataModel; } DataModel getDataModel() { return _dataModel; } void addDataModelExtension(DataModelExtension* ext) { _dataModelExtensions.insert(ext); } void setInvoker(const std::string& invokeId, Invoker invoker) { _dontDestructOnUninvoke.insert(invokeId); _invokers[invokeId] = invoker; _invokers[invokeId].setInterpreter(this); _invokers[invokeId].setInvokeId(invokeId); } const std::map& getInvokers() { return _invokers; } bool runOnMainThread(int fps, bool blocking = true); static bool isMember(const Arabica::DOM::Node& node, const Arabica::XPath::NodeSet& set); bool hasLegalConfiguration(); bool isLegalConfiguration(const Arabica::XPath::NodeSet&); bool isLegalConfiguration(const std::list&); static bool isState(const Arabica::DOM::Element& state); static bool isPseudoState(const Arabica::DOM::Element& state); static bool isTransitionTarget(const Arabica::DOM::Element& elem); static bool isTargetless(const Arabica::DOM::Element& transition); static bool isAtomic(const Arabica::DOM::Element& state); static bool isFinal(const Arabica::DOM::Element& state); static bool isHistory(const Arabica::DOM::Element& state); static bool isParallel(const Arabica::DOM::Element& state); static bool isCompound(const Arabica::DOM::Element& state); static bool isDescendant(const Arabica::DOM::Node& s1, const Arabica::DOM::Node& s2); static bool isInEmbeddedDocument(const Arabica::DOM::Node& node); bool isInitial(const Arabica::DOM::Element& state); static std::string stateToString(InterpreterState state); Arabica::DOM::Element getState(const std::string& stateId); Arabica::XPath::NodeSet getStates(const std::list& stateIds); Arabica::XPath::NodeSet getAllStates(); Arabica::XPath::NodeSet getDocumentInitialTransitions(); Arabica::XPath::NodeSet getInitialStates(Arabica::DOM::Element state = Arabica::DOM::Element()); Arabica::XPath::NodeSet getReachableStates(); static Arabica::XPath::NodeSet getChildStates(const Arabica::DOM::Node& state); static Arabica::XPath::NodeSet getChildStates(const Arabica::XPath::NodeSet& state); static Arabica::DOM::Element getParentState(const Arabica::DOM::Node& element); static Arabica::DOM::Node getAncestorElement(const Arabica::DOM::Node& node, const std::string tagName); virtual Arabica::XPath::NodeSet getTargetStates(const Arabica::DOM::Element& transition); virtual Arabica::XPath::NodeSet getTargetStates(const Arabica::XPath::NodeSet& transitions); virtual Arabica::DOM::Node getSourceState(const Arabica::DOM::Element& transition); Arabica::DOM::Node findLCCA(const Arabica::XPath::NodeSet& states); virtual Arabica::XPath::NodeSet getProperAncestors(const Arabica::DOM::Node& s1, const Arabica::DOM::Node& s2); virtual void handleDOMEvent(Arabica::DOM::Events::Event& event); std::vector getReachableTargets() { std::vector e; tthread::lock_guard lock(_mutex); Arabica::XPath::NodeSet possibleTransitions = DOMUtils::filterChildElements( "transition", _configuration, false); for( size_t i = 0; i < possibleTransitions.size(); i++ ) { Arabica::DOM::Node transitions = possibleTransitions[ i ]; Arabica::DOM::NamedNodeMap attributes = transitions.getAttributes(); Arabica::DOM::Node events = attributes.getNamedItem("target"); e.push_back( std::string( events.getNodeValue() ) ); } return e; } std::vector getEventDescriptors() { std::vector e; tthread::lock_guard lock(_mutex); Arabica::XPath::NodeSet possibleTransitions = DOMUtils::filterChildElements( "transition", _configuration, false); for( size_t i = 0; i < possibleTransitions.size(); i++ ) { Arabica::DOM::Node transitions = possibleTransitions[ i ]; Arabica::DOM::NamedNodeMap attributes = transitions.getAttributes(); Arabica::DOM::Node events = attributes.getNamedItem("event"); e.push_back( std::string( events.getNodeValue() ) ); } return e; } protected: static void run(void*); // static method for thread to run class DOMEventListener : public Arabica::DOM::Events::EventListener { public: DOMEventListener() : _interpreter(NULL) {} void handleEvent(Arabica::DOM::Events::Event& event); InterpreterImpl* _interpreter; }; InterpreterImpl(); void init(); void setupDOM(); void resolveXIncludes(); void resolveXIncludes(std::list includeChain, std::map& mergedNS, const std::string& xIncludeNS, const URL& baseURL, const Arabica::DOM::Element& xinclude); virtual void setupIOProcessors(); std::list validate(); void initializeData(const Arabica::DOM::Element& data); void finalizeAndAutoForwardCurrentEvent(); void stabilize(); void microstep(const Arabica::XPath::NodeSet& enabledTransitions); void exitInterpreter(); virtual Arabica::XPath::NodeSet selectEventlessTransitions(); virtual Arabica::XPath::NodeSet selectTransitions(const std::string& event); virtual bool isEnabledTransition(const Arabica::DOM::Element& transition, const std::string& event); void setInterpreterState(InterpreterState newState); bool _stable; tthread::thread* _thread; tthread::recursive_mutex _mutex; tthread::condition_variable _condVar; tthread::recursive_mutex _pluginMutex; // to be overwritten by implementations - these ought to be pure, but impl destructor runs first virtual void enterStates(const Arabica::XPath::NodeSet& enabledTransitions) {} virtual void exitStates(const Arabica::XPath::NodeSet& enabledTransitions) {} virtual Arabica::XPath::NodeSet removeConflictingTransitions(const Arabica::XPath::NodeSet& enabledTransitions) { return enabledTransitions; } InterpreterState _state; URL _sourceURL; std::map, URL> _baseURL; // with xi:include, we might have different base URLs Arabica::DOM::Document _document; Arabica::DOM::Element _scxml; Arabica::XPath::XPath _xpath; NameSpaceInfo _nsInfo; bool _topLevelFinalReached; bool _isInitialized; bool _domIsSetup; bool _userSuppliedDataModel; std::set _dontDestructOnUninvoke; bool _isStarted; bool _isRunning; InterpreterImpl::Binding _binding; Arabica::XPath::NodeSet _configuration; Arabica::XPath::NodeSet _alreadyEntered; Arabica::XPath::NodeSet _statesToInvoke; std::list _startConfiguration; InvokeRequest _invokeReq; DataModel _dataModel; std::map > _historyValue; std::list _internalQueue; uscxml::concurrency::BlockingQueue _externalQueue; uscxml::concurrency::BlockingQueue* _parentQueue; DelayedEventQueue* _sendQueue; DOMEventListener _domEventListener; Event _currEvent; Factory* _factory; InterpreterHTTPServlet* _httpServlet; InterpreterWebSocketServlet* _wsServlet; std::set _monitors; std::set _microstepConfigurations; long _lastRunOnMainThread; std::string _name; std::string _sessionId; unsigned int _capabilities; Data _cmdLineOptions; virtual void executeContent(const Arabica::DOM::Element& content, bool rethrow = false); virtual void executeContent(const Arabica::DOM::NodeList& content, bool rethrow = false); virtual void executeContent(const Arabica::XPath::NodeSet& content, bool rethrow = false); void processContentElement(const Arabica::DOM::Element& element, Arabica::DOM::Node& dom, std::string& text, std::string& expr); void processParamChilds(const Arabica::DOM::Element& element, std::multimap& params); void processDOMorText(const Arabica::DOM::Element& element, Arabica::DOM::Node& dom, std::string& text); virtual void send(const Arabica::DOM::Element& element); virtual void invoke(const Arabica::DOM::Element& element); virtual void cancelInvoke(const Arabica::DOM::Element& element); virtual void internalDoneSend(const Arabica::DOM::Element& state, const Arabica::DOM::Element& doneData); static void delayedSend(void* userdata, std::string eventName); void returnDoneEvent(const Arabica::DOM::Node& state); bool hasConditionMatch(const Arabica::DOM::Element& conditional); bool isInFinalState(const Arabica::DOM::Element& state); bool parentIsScxmlState(const Arabica::DOM::Element& state); IOProcessor getIOProcessor(const std::string& type); const URL& getBaseURLForNode(const Arabica::DOM::Node& node); std::map _ioProcessors; std::map > _sendIds; std::map _invokers; std::map, ExecutableContent> _executableContent; std::set _dataModelExtensions; std::map, Arabica::DOM::Node >, Arabica::XPath::NodeSet > _cachedProperAncestors; std::map, Arabica::XPath::NodeSet > _cachedTargets; std::map > _cachedStates; std::map _cachedURLs; friend class USCXMLInvoker; friend class SCXMLIOProcessor; friend class Interpreter; friend class InterpreterIssue; }; class USCXML_API Interpreter { public: static Interpreter fromDOM(const Arabica::DOM::Document& dom, const NameSpaceInfo& nameSpaceInfo, const std::string& sourceURL); static Interpreter fromXML(const std::string& xml, const std::string& sourceURL); static Interpreter fromURL(const std::string& URL); static Interpreter fromClone(const Interpreter& other); Interpreter() : _impl() {} // the empty, invalid interpreter Interpreter(boost::shared_ptr const impl) : _impl(impl) { } Interpreter(const Interpreter& other) : _impl(other._impl) { } virtual ~Interpreter() {}; operator bool() const { return (!!_impl && _impl->_state != USCXML_DESTROYED); } bool operator< (const Interpreter& other) const { return _impl < other._impl; } bool operator==(const Interpreter& other) const { return _impl == other._impl; } bool operator!=(const Interpreter& other) const { return _impl != other._impl; } Interpreter& operator= (const Interpreter& other) { _impl = other._impl; return *this; } virtual void writeTo(std::ostream& stream) { TIME_BLOCK return _impl->writeTo(stream); } void reset() { #ifdef BUILD_PROFILING timer = Timer(); #endif return _impl->reset(); } std::vector getReachableTargets() { return _impl->getReachableTargets(); } std::vector getEventDescriptors() { return _impl->getEventDescriptors(); } void start() { return _impl->start(); } void stop() { return _impl->stop(); } // void join() { // return _impl->join(); // }; bool isRunning() { return _impl->isRunning(); } void interpret() { _impl->interpret(); }; InterpreterState step(int waitForMS = 0) { TIME_BLOCK return _impl->step(waitForMS); }; InterpreterState step(bool blocking) { TIME_BLOCK if (blocking) return _impl->step(-1); return _impl->step(0); }; std::list validate() { TIME_BLOCK return _impl->validate(); } InterpreterState getState() { return _impl->getInterpreterState(); } void addMonitor(InterpreterMonitor* monitor) { return _impl->addMonitor(monitor); } void removeMonitor(InterpreterMonitor* monitor) { return _impl->removeMonitor(monitor); } void setSourceURL(std::string sourceURL) { return _impl->setSourceURL(sourceURL); } std::string getSourceURL() { return _impl->getSourceURL(); } std::string getBaseURL() { return _impl->getBaseURL(); } std::string getBaseURL(const std::string& xpathExpr) { return _impl->getBaseURL(xpathExpr); } std::string getBaseURL(const Arabica::DOM::Node& refNode) { return _impl->getBaseURL(refNode); } void setNameSpaceInfo(const NameSpaceInfo& nsInfo) { _impl->setNameSpaceInfo(nsInfo); } NameSpaceInfo getNameSpaceInfo() const { return _impl->getNameSpaceInfo(); } void setCmdLineOptions(std::map params) { return _impl->setCmdLineOptions(params); } Data getCmdLineOptions() { return _impl->getCmdLineOptions(); } InterpreterHTTPServlet* getHTTPServlet() { return _impl->getHTTPServlet(); } void setDataModel(const DataModel& dataModel) { _impl->setDataModel(dataModel); } DataModel getDataModel() { return _impl->getDataModel(); } void addIOProcessor(IOProcessor ioProc) { _impl->addIOProcessor(ioProc); } const std::map& getIOProcessors() { return _impl->getIOProcessors(); } void setInvoker(const std::string& invokeId, Invoker invoker) { _impl->setInvoker(invokeId, invoker); } const std::map& getInvokers() { return _impl->getInvokers(); } void addDataModelExtension(DataModelExtension* ext) { _impl->addDataModelExtension(ext); } void setParentQueue(uscxml::concurrency::BlockingQueue* parentQueue) { return _impl->setParentQueue(parentQueue); } void setFactory(Factory* factory) { return _impl->setFactory(factory); } Factory* getFactory() { return _impl->getFactory(); } Arabica::XPath::NodeSet getNodeSetForXPath(const std::string& xpathExpr) { TIME_BLOCK return _impl->getNodeSetForXPath(xpathExpr); } void inline receiveInternal(const Event& event) { TIME_BLOCK return _impl->receiveInternal(event); } void receive(const Event& event, bool toFront = false) { TIME_BLOCK return _impl->receive(event, toFront); } Event getCurrentEvent() { TIME_BLOCK return _impl->getCurrentEvent(); } bool isInState(const std::string& stateId) { TIME_BLOCK return _impl->isInState(stateId); } Arabica::XPath::NodeSet getConfiguration() { TIME_BLOCK return _impl->getConfiguration(); } Arabica::XPath::NodeSet getBasicConfiguration() { TIME_BLOCK return _impl->getBasicConfiguration(); } void setInitalConfiguration(const std::list& states) { TIME_BLOCK return _impl->setInitalConfiguration(states); } // Arabica::DOM::Node getState(const std::string& stateId) { // return _impl->getState(stateId); // } // Arabica::XPath::NodeSet getStates(const std::list& stateIds) { // return _impl->getStates(stateIds); // } // Arabica::XPath::NodeSet getAllStates() { // return _impl->getAllStates(); // } Arabica::DOM::Document getDocument() const { return _impl->getDocument(); } void setCapabilities(unsigned int capabilities) { return _impl->setCapabilities(capabilities); } void setName(const std::string& name) { return _impl->setName(name); } const std::string& getName() { return _impl->getName(); } const std::string& getSessionId() { return _impl->getSessionId(); } DelayedEventQueue* getDelayQueue() { return _impl->getDelayQueue(); } bool runOnMainThread(int fps, bool blocking = true) { TIME_BLOCK return _impl->runOnMainThread(fps, blocking); } bool hasLegalConfiguration() { TIME_BLOCK return _impl->hasLegalConfiguration(); } bool isLegalConfiguration(const Arabica::XPath::NodeSet& config) { TIME_BLOCK return _impl->isLegalConfiguration(config); } bool isLegalConfiguration(const std::list& config) { TIME_BLOCK return _impl->isLegalConfiguration(config); } boost::shared_ptr getImpl() const { return _impl; } static std::map > getInstances(); static void addInstance(boost::shared_ptr instance); #ifdef BUILD_PROFILING Timer timer; #endif protected: void setInvokeRequest(const InvokeRequest& req) { return _impl->setInvokeRequest(req); } // we use a void ptr here as Arabica::SAX::InputSource complicates includes static Interpreter fromInputSource(void* source, const std::string& sourceURL); boost::shared_ptr _impl; static std::map > _instances; static tthread::recursive_mutex _instanceMutex; }; class USCXML_API InterpreterMonitor { public: InterpreterMonitor() : _copyToInvokers(false) {} virtual ~InterpreterMonitor() {} virtual void beforeProcessingEvent(Interpreter interpreter, const Event& event) {} virtual void beforeMicroStep(Interpreter interpreter) {} virtual void beforeExitingState(Interpreter interpreter, const Arabica::DOM::Element& state, bool moreComing) {} virtual void afterExitingState(Interpreter interpreter, const Arabica::DOM::Element& state, bool moreComing) {} virtual void beforeExecutingContent(Interpreter interpreter, const Arabica::DOM::Element& element) {} virtual void afterExecutingContent(Interpreter interpreter, const Arabica::DOM::Element& element) {} virtual void beforeUninvoking(Interpreter interpreter, const Arabica::DOM::Element& invokeElem, const std::string& invokeid) {} virtual void afterUninvoking(Interpreter interpreter, const Arabica::DOM::Element& invokeElem, const std::string& invokeid) {} virtual void beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element& transition, bool moreComing) {} virtual void afterTakingTransition(Interpreter interpreter, const Arabica::DOM::Element& transition, bool moreComing) {} virtual void beforeEnteringState(Interpreter interpreter, const Arabica::DOM::Element& state, bool moreComing) {} virtual void afterEnteringState(Interpreter interpreter, const Arabica::DOM::Element& state, bool moreComing) {} virtual void beforeInvoking(Interpreter interpreter, const Arabica::DOM::Element& invokeElem, const std::string& invokeid) {} virtual void afterInvoking(Interpreter interpreter, const Arabica::DOM::Element& invokeElem, const std::string& invokeid) {} virtual void afterMicroStep(Interpreter interpreter) {} virtual void onStableConfiguration(Interpreter interpreter) {} virtual void beforeCompletion(Interpreter interpreter) {} virtual void afterCompletion(Interpreter interpreter) {} virtual void reportIssue(Interpreter interpreter, const InterpreterIssue& issue) {} void copyToInvokers(bool copy) { _copyToInvokers = copy; } bool copyToInvokers() { return _copyToInvokers; } protected: bool _copyToInvokers; }; class StateTransitionMonitor : public uscxml::InterpreterMonitor { public: virtual void beforeTakingTransition(uscxml::Interpreter interpreter, const Arabica::DOM::Element& transition, bool moreComing); virtual void beforeExecutingContent(Interpreter interpreter, const Arabica::DOM::Element& element); virtual void onStableConfiguration(uscxml::Interpreter interpreter); virtual void beforeProcessingEvent(uscxml::Interpreter interpreter, const uscxml::Event& event); virtual void beforeExitingState(uscxml::Interpreter interpreter, const Arabica::DOM::Element& state, bool moreComing); virtual void beforeEnteringState(uscxml::Interpreter interpreter, const Arabica::DOM::Element& state, bool moreComing); virtual void beforeMicroStep(uscxml::Interpreter interpreter); protected: static tthread::recursive_mutex _mutex; void printNodeSet(const Arabica::XPath::NodeSet& config); Arabica::XPath::NodeSet exitingStates; Arabica::XPath::NodeSet enteringStates; }; } #endif