#ifndef RUNTIME_H_SQ1MBKGN #define RUNTIME_H_SQ1MBKGN #include "uscxml/Common.h" #include "uscxml/URL.h" #include #include #include #include #include #include #include #include #include #include #include "uscxml/concurrency/tinythread.h" #include "uscxml/concurrency/eventqueue/DelayedEventQueue.h" #include "uscxml/concurrency/BlockingQueue.h" #include "uscxml/Message.h" #include "uscxml/Factory.h" namespace uscxml { class NumAttr { public: NumAttr(const std::string& str) { size_t valueStart = str.find_first_of("0123456789."); if (valueStart != std::string::npos) { size_t valueEnd = str.find_last_of("0123456789."); if (valueEnd != std::string::npos) { value = str.substr(valueStart, (valueEnd - valueStart) + 1); size_t unitStart = str.find_first_not_of(" \t", valueEnd + 1); if (unitStart != std::string::npos) { size_t unitEnd = str.find_last_of(" \t"); if (unitEnd != std::string::npos && unitEnd > unitStart) { unit = str.substr(unitStart, unitEnd - unitStart); } else { unit = str.substr(unitStart, str.length() - unitStart); } } } } } std::string value; std::string unit; }; class Interpreter : protected Arabica::SAX2DOM::Parser { public: enum Binding { EARLY = 0, LATE = 1 }; virtual ~Interpreter(); static Interpreter* fromDOM(const Arabica::DOM::Node& node); static Interpreter* fromXML(const std::string& xml); static Interpreter* fromURI(const std::string& uri); static Interpreter* fromInputSource(Arabica::SAX::InputSource& source); virtual void startPrefixMapping(const std::string& /* prefix */, const std::string& /* uri */); void start(); static void run(void*); void join() { if (_thread != NULL) _thread->join(); }; void interpret(); bool validate(); void setBaseURI(std::string baseURI) { _baseURI = URL(baseURI); } URL getBaseURI() { return _baseURI; } DataModel getDataModel() { return _dataModel; } Invoker getInvoker() { return _invoker; } void setInvoker(const Invoker& invoker) { _invoker = invoker; } std::string getNSPrefix() { return _nsPrefix; } Arabica::XPath::StandardNamespaceContext& getNSContext() { return _nsContext; } void waitForStabilization(); void receive(Event& event) { _externalQueue.push(event); } void receiveInternal(Event& event) { _internalQueue.push_back(event); } Arabica::XPath::NodeSet getConfiguration() { return _configuration; } Arabica::DOM::Node getState(const std::string& stateId); Arabica::DOM::Document& getDocument() { return _document; } const std::string& getName() { return _name; } const std::string& getSessionId() { return _sessionId; } bool runOnMainThread(int fps, bool blocking = true); static bool isMember(const Arabica::DOM::Node& node, const Arabica::XPath::NodeSet& set); void dump(); static void dump(const Arabica::DOM::Node& node, int lvl = 0); static bool isState(const Arabica::DOM::Node& state); static bool isPseudoState(const Arabica::DOM::Node& state); static bool isTransitionTarget(const Arabica::DOM::Node& elem); static bool isTargetless(const Arabica::DOM::Node& transition); static bool isAtomic(const Arabica::DOM::Node& state); static bool isFinal(const Arabica::DOM::Node& state); static bool isHistory(const Arabica::DOM::Node& state); static bool isParallel(const Arabica::DOM::Node& state); static bool isCompound(const Arabica::DOM::Node& state); static bool isDescendant(const Arabica::DOM::Node& s1, const Arabica::DOM::Node& s2); bool isInitial(const Arabica::DOM::Node& state); Arabica::DOM::Node getInitialState(Arabica::DOM::Node state = Arabica::DOM::Node()); static Arabica::XPath::NodeSet getChildStates(const Arabica::DOM::Node& state); Arabica::XPath::NodeSet getTargetStates(const Arabica::DOM::Node& transition); static Arabica::XPath::NodeSet filterChildElements(const std::string& tagname, const Arabica::DOM::Node& node); static Arabica::XPath::NodeSet filterChildElements(const std::string& tagName, const Arabica::XPath::NodeSet& nodeSet); static const std::string getUUID(); protected: Interpreter(); void init(); void normalize(const Arabica::DOM::Document& node); void setupIOProcessors(); void mainEventLoop(); bool _stable; tthread::thread* _thread; tthread::mutex _mutex; tthread::condition_variable _stabilized; URL _baseURI; Arabica::DOM::Document _document; Arabica::DOM::Element _scxml; Arabica::XPath::XPath _xpath; Arabica::XPath::StandardNamespaceContext _nsContext; std::string _nsPrefix; bool _running; Binding _binding; Arabica::XPath::NodeSet _configuration; Arabica::XPath::NodeSet _statesToInvoke; DataModel _dataModel; std::map > _historyValue; std::list _internalQueue; uscxml::concurrency::BlockingQueue _externalQueue; DelayedEventQueue* _sendQueue; Invoker _invoker; static URL toBaseURI(const URL& url); bool toAbsoluteURI(URL& uri); void microstep(const Arabica::XPath::NodeSet& enabledTransitions); void exitStates(const Arabica::XPath::NodeSet& enabledTransitions); void enterStates(const Arabica::XPath::NodeSet& enabledTransitions); void executeTransitionContent(const Arabica::XPath::NodeSet& enabledTransitions); void executeContent(const Arabica::DOM::Node& content); void executeContent(const Arabica::DOM::NodeList& content); void initializeData(const Arabica::DOM::Node& data); void exitInterpreter(); void addStatesToEnter(const Arabica::DOM::Node& state, Arabica::XPath::NodeSet& statesToEnter, Arabica::XPath::NodeSet& statesForDefaultEntry); Arabica::XPath::NodeSet selectEventlessTransitions(); Arabica::XPath::NodeSet selectTransitions(const std::string& event); Arabica::DOM::Node getSourceState(const Arabica::DOM::Node& transition); Arabica::DOM::Node findLCCA(const Arabica::XPath::NodeSet& states); static Arabica::XPath::NodeSet getProperAncestors(const Arabica::DOM::Node& s1, const Arabica::DOM::Node& s2); void send(const Arabica::DOM::Node& element); void invoke(const Arabica::DOM::Node& element); void cancelInvoke(const Arabica::DOM::Node& element); void returnDoneEvent(const Arabica::DOM::Node& state); void internalDoneSend(const Arabica::DOM::Node& state); static void delayedSend(void* userdata, std::string eventName); static bool nameMatch(const std::string& transitionEvent, const std::string& event); Arabica::XPath::NodeSet filterPreempted(const Arabica::XPath::NodeSet& enabledTransitions); bool hasConditionMatch(const Arabica::DOM::Node& conditional); bool isPreemptingTransition(const Arabica::DOM::Node& t1, const Arabica::DOM::Node& t2); bool isInFinalState(const Arabica::DOM::Node& state); bool isWithinSameChild(const Arabica::DOM::Node& transition); bool parentIsScxmlState(Arabica::DOM::Node state); static std::vector tokenizeIdRefs(const std::string& idRefs); static boost::uuids::random_generator uuidGen; long _lastRunOnMainThread; std::string _name; std::string _sessionId; IOProcessor getIOProcessor(const std::string& type); // IOProcessor* getIOProcessorForId(const std::string& sendId); std::map _ioProcessors; std::map > _sendIds; std::map _invokers; /// We need to remember to adapt them when the DOM is operated upon std::map > _cachedStates; }; } #endif