diff options
Diffstat (limited to 'src/uscxml')
54 files changed, 2347 insertions, 1917 deletions
diff --git a/src/uscxml/CMakeLists.txt b/src/uscxml/CMakeLists.txt index da620fb..c38bcbf 100644 --- a/src/uscxml/CMakeLists.txt +++ b/src/uscxml/CMakeLists.txt @@ -25,6 +25,13 @@ file(GLOB_RECURSE USCXML_CONCURRENCY source_group("Interpreter" FILES ${USCXML_CONCURRENCY}) list (APPEND USCXML_FILES ${USCXML_CONCURRENCY}) +file(GLOB_RECURSE USCXML_MESSAGES + messages/*.cpp + messages/*.h +) +source_group("Interpreter" FILES ${USCXML_MESSAGES}) +list (APPEND USCXML_FILES ${USCXML_MESSAGES}) + file(GLOB_RECURSE USCXML_DEBUG debug/*.cpp debug/*.h @@ -63,6 +70,16 @@ file(GLOB USCXML_CORE source_group("Interpreter" FILES ${USCXML_CORE}) list (APPEND USCXML_FILES ${USCXML_CORE}) +file(GLOB USCXML_PLUGINS + plugins/DataModel.h + plugins/EventHandler.h + plugins/ExecutableContent.h + plugins/Invoker.h + plugins/IOProcessor.h +) +source_group("Interpreter" FILES ${USCXML_PLUGINS}) +list (APPEND USCXML_FILES ${USCXML_PLUGINS}) + if (BUILD_AS_PLUGINS) list (APPEND USCXML_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/plugins) file(GLOB PLUMA diff --git a/src/uscxml/Convenience.h b/src/uscxml/Convenience.h index fcc696c..54e62c3 100644 --- a/src/uscxml/Convenience.h +++ b/src/uscxml/Convenience.h @@ -22,6 +22,7 @@ #include <inttypes.h> #include <boost/detail/endian.hpp> +#include <boost/lexical_cast.hpp> namespace uscxml { inline bool isnan(double x) { diff --git a/src/uscxml/DOMUtils.h b/src/uscxml/DOMUtils.h index 178f32a..7748f48 100644 --- a/src/uscxml/DOMUtils.h +++ b/src/uscxml/DOMUtils.h @@ -24,6 +24,7 @@ #include <DOM/SAX2DOM/SAX2DOM.hpp> #include <SAX/helpers/DefaultHandler.hpp> #include <SAX/helpers/CatchErrorHandler.hpp> +#include <DOM/io/Stream.hpp> // operator<< for nodes #define TAGNAME(elem) ((Arabica::DOM::Element<std::string>)elem).getTagName() #define LOCALNAME(elem) ((Arabica::DOM::Element<std::string>)elem).getLocalName() @@ -40,6 +41,31 @@ public: static bool attributeIsTrue(const::std::string& value); }; +class USCXML_API 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 ScriptEntityResolver : public Arabica::SAX::EntityResolver<std::string> { virtual InputSourceT resolveEntity(const std::string& publicId, const std::string& systemId) { Arabica::SAX::InputSource<std::string> is; diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp index 8edaf07..3556aba 100644 --- a/src/uscxml/Factory.cpp +++ b/src/uscxml/Factory.cpp @@ -24,6 +24,8 @@ #include "uscxml/Interpreter.h" #include <glog/logging.h> +#include "uscxml/server/InterpreterServlet.h" + #include "uscxml/plugins/datamodel/null/NULLDataModel.h" // see http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system diff --git a/src/uscxml/Factory.h b/src/uscxml/Factory.h index ff08754..a0f5178 100644 --- a/src/uscxml/Factory.h +++ b/src/uscxml/Factory.h @@ -21,8 +21,13 @@ #define FACTORY_H_5WKLGPRB #include "uscxml/Common.h" -#include "uscxml/Message.h" -#include "uscxml/Convenience.h" + +#include "uscxml/plugins/ExecutableContent.h" +#include "uscxml/plugins/EventHandler.h" +#include "uscxml/plugins/IOProcessor.h" +#include "uscxml/plugins/Invoker.h" +#include "uscxml/plugins/DataModel.h" + #include <string.h> #ifdef BUILD_AS_PLUGINS @@ -38,404 +43,6 @@ namespace uscxml { class InterpreterImpl; -class USCXML_API ExecutableContentImpl { -public: - ExecutableContentImpl() {}; - virtual ~ExecutableContentImpl() {}; - virtual boost::shared_ptr<ExecutableContentImpl> create(InterpreterImpl* interpreter) = 0; - - virtual void setInterpreter(InterpreterImpl* interpreter) { - _interpreter = interpreter; - } - - virtual std::string getLocalName() = 0; ///< The name of the element. - virtual std::string getNamespace() { - return "http://www.w3.org/2005/07/scxml"; ///< The namespace of the element. - } - virtual void enterElement(const Arabica::DOM::Node<std::string>& node) = 0; ///< Invoked when entering the element as part of evaluating executable content. - virtual void exitElement(const Arabica::DOM::Node<std::string>& node) = 0; ///< Invoked when exiting the element as part of evaluating executable content. - virtual bool processChildren() = 0; ///< Whether or not the interpreter should process this elements children. - -protected: - InterpreterImpl* _interpreter; -}; - -class USCXML_API ExecutableContent { -public: - ExecutableContent() : _impl() {} - ExecutableContent(boost::shared_ptr<ExecutableContentImpl> const impl) : _impl(impl) { } - ExecutableContent(const ExecutableContent& other) : _impl(other._impl) { } - virtual ~ExecutableContent() {}; - - operator bool() const { - return _impl; - } - bool operator< (const ExecutableContent& other) const { - return _impl < other._impl; - } - bool operator==(const ExecutableContent& other) const { - return _impl == other._impl; - } - bool operator!=(const ExecutableContent& other) const { - return _impl != other._impl; - } - ExecutableContent& operator= (const ExecutableContent& other) { - _impl = other._impl; - return *this; - } - - void setInterpreter(InterpreterImpl* interpreter) { - _impl->setInterpreter(interpreter); - } - - std::string getLocalName() { - return _impl->getLocalName(); - } - std::string getNamespace() { - return _impl->getNamespace(); - } - void enterElement(const Arabica::DOM::Node<std::string>& node) { - return _impl->enterElement(node); - } - void exitElement(const Arabica::DOM::Node<std::string>& node) { - return _impl->exitElement(node); - } - bool processChildren() { - return _impl->processChildren(); - } -protected: - boost::shared_ptr<ExecutableContentImpl> _impl; - -}; - -class USCXML_API EventHandlerImpl { -public: - virtual ~EventHandlerImpl() {} - - virtual std::list<std::string> getNames() = 0; - - virtual void setInterpreter(InterpreterImpl* interpreter) { - _interpreter = interpreter; - } - void setInvokeId(const std::string& invokeId) { - _invokeId = invokeId; - } - void setType(const std::string& type) { - _type = type; - } - - void setElement(const Arabica::DOM::Element<std::string>& element) { - _element = element; - } - - Arabica::DOM::Element<std::string> getElement() { - return _element; - } - - virtual Data getDataModelVariables() = 0; - virtual void send(const SendRequest& req) = 0; - - virtual void runOnMainThread() {}; - void returnEvent(Event& event); - void returnErrorExecution(const std::string&); - void returnErrorPlatform(const std::string&); - -protected: - InterpreterImpl* _interpreter; - Arabica::DOM::Element<std::string> _element; - std::string _invokeId; - std::string _type; - -}; - -class USCXML_API EventHandler { -public: - EventHandler() : _impl() {} - EventHandler(boost::shared_ptr<EventHandlerImpl> const impl) : _impl(impl) { } - EventHandler(const EventHandler& other) : _impl(other._impl) { } - virtual ~EventHandler() {}; - - virtual std::list<std::string> getNames() { - return _impl->getNames(); - } - - virtual Data getDataModelVariables() const { - return _impl->getDataModelVariables(); - }; - virtual void send(const SendRequest& req) { - return _impl->send(req); - }; - virtual void runOnMainThread() { - return _impl->runOnMainThread(); - } - - void setInterpreter(InterpreterImpl* interpreter) { - _impl->setInterpreter(interpreter); - } - void setInvokeId(const std::string& invokeId) { - _impl->setInvokeId(invokeId); - } - void setType(const std::string& type) { - _impl->setType(type); - } - - void setElement(const Arabica::DOM::Element<std::string>& element) { - _impl->setElement(element); - } - - Arabica::DOM::Element<std::string> getElement() { - return _impl->getElement(); - } - -protected: - boost::shared_ptr<EventHandlerImpl> _impl; - friend class InterpreterImpl; -}; - -class USCXML_API IOProcessorImpl : public EventHandlerImpl { -public: - IOProcessorImpl() {}; - virtual ~IOProcessorImpl() {}; - virtual boost::shared_ptr<IOProcessorImpl> create(InterpreterImpl* interpreter) = 0; -}; - -class USCXML_API IOProcessor : public EventHandler { -public: - IOProcessor() : _impl() {} - IOProcessor(boost::shared_ptr<IOProcessorImpl> const impl) : EventHandler(impl), _impl(impl) { } - IOProcessor(const IOProcessor& other) : EventHandler(other._impl), _impl(other._impl) { } - virtual ~IOProcessor() {}; - - operator bool() const { - return _impl; - } - bool operator< (const IOProcessor& other) const { - return _impl < other._impl; - } - bool operator==(const IOProcessor& other) const { - return _impl == other._impl; - } - bool operator!=(const IOProcessor& other) const { - return _impl != other._impl; - } - IOProcessor& operator= (const IOProcessor& other) { - _impl = other._impl; - EventHandler::_impl = _impl; - return *this; - } - -protected: - boost::shared_ptr<IOProcessorImpl> _impl; - friend class InterpreterImpl; -}; - -class USCXML_API InvokerImpl : public EventHandlerImpl { -public: - virtual ~InvokerImpl() {} - virtual void invoke(const InvokeRequest& req) = 0; - virtual boost::shared_ptr<InvokerImpl> create(InterpreterImpl* interpreter) = 0; -}; - -class USCXML_API Invoker : public EventHandler { -public: - Invoker() : _impl() {} - Invoker(boost::shared_ptr<InvokerImpl> const impl) : EventHandler(impl), _impl(impl) { } - Invoker(const Invoker& other) : EventHandler(other._impl), _impl(other._impl) { } - virtual ~Invoker() {}; - - operator bool() const { - return _impl; - } - bool operator< (const Invoker& other) const { - return _impl < other._impl; - } - bool operator==(const Invoker& other) const { - return _impl == other._impl; - } - bool operator!=(const Invoker& other) const { - return _impl != other._impl; - } - Invoker& operator= (const Invoker& other) { - _impl = other._impl; - EventHandler::_impl = _impl; - return *this; - } - - virtual void invoke(InvokeRequest& req) { - _impl->invoke(req); - } - -protected: - boost::shared_ptr<InvokerImpl> _impl; -}; - -class USCXML_API DataModelImpl { -public: - virtual ~DataModelImpl() {} - virtual boost::shared_ptr<DataModelImpl> create(InterpreterImpl* interpreter) = 0; - virtual std::list<std::string> getNames() = 0; - - virtual bool validate(const std::string& location, const std::string& schema) = 0; - virtual void setEvent(const Event& event) = 0; - virtual Data getStringAsData(const std::string& content) = 0; - - size_t replaceExpressions(std::string& content); - - // foreach - virtual uint32_t getLength(const std::string& expr) = 0; - virtual void setForeach(const std::string& item, - const std::string& array, - const std::string& index, - uint32_t iteration) = 0; - virtual void pushContext() = 0; - virtual void popContext() = 0; - - virtual void eval(const Arabica::DOM::Element<std::string>& scriptElem, - const std::string& expr) = 0; - - virtual std::string evalAsString(const std::string& expr) = 0; - - virtual bool evalAsBool(const Arabica::DOM::Node<std::string>& scriptNode, - const std::string& expr) = 0; - virtual bool evalAsBool(const std::string& expr) { - return evalAsBool(Arabica::DOM::Node<std::string>(), expr); - } - - virtual bool isDeclared(const std::string& expr) = 0; - - virtual void assign(const Arabica::DOM::Element<std::string>& assignElem, - const Arabica::DOM::Node<std::string>& node, - const std::string& content) = 0; - virtual void assign(const std::string& location, const Data& data) = 0; - - virtual void init(const Arabica::DOM::Element<std::string>& dataElem, - const Arabica::DOM::Node<std::string>& node, - const std::string& content) = 0; - virtual void init(const std::string& location, const Data& data) = 0; - - virtual void setInterpreter(InterpreterImpl* interpreter) { - _interpreter = interpreter; - } - - virtual std::string andExpressions(std::list<std::string>) { - return ""; - } - - static void throwErrorExecution(const std::string& cause); - static void throwErrorPlatform(const std::string& cause); - - // we need it public for various static functions -protected: - InterpreterImpl* _interpreter; -}; - -class USCXML_API DataModel { -public: - DataModel() : _impl() {} - DataModel(const boost::shared_ptr<DataModelImpl> impl) : _impl(impl) { } - DataModel(const DataModel& other) : _impl(other._impl) { } - virtual ~DataModel() {}; - - operator bool() const { - return _impl; - } - bool operator< (const DataModel& other) const { - return _impl < other._impl; - } - bool operator==(const DataModel& other) const { - return _impl == other._impl; - } - bool operator!=(const DataModel& other) const { - return _impl != other._impl; - } - DataModel& operator= (const DataModel& other) { - _impl = other._impl; - return *this; - } - - virtual std::list<std::string> getNames() { - return _impl->getNames(); - } - - virtual bool validate(const std::string& location, const std::string& schema) { - return _impl->validate(location, schema); - } - virtual void setEvent(const Event& event) { - return _impl->setEvent(event); - } - virtual Data getStringAsData(const std::string& content) { - return _impl->getStringAsData(content); - } - - virtual void pushContext() { - return _impl->pushContext(); - } - virtual void popContext() { - return _impl->popContext(); - } - - virtual void eval(const Arabica::DOM::Element<std::string>& scriptElem, - const std::string& expr) { - return _impl->eval(scriptElem, expr); - } - virtual std::string evalAsString(const std::string& expr) { - return _impl->evalAsString(expr); - } - virtual bool evalAsBool(const std::string& expr) { - return _impl->evalAsBool(expr); - } - virtual bool evalAsBool(const Arabica::DOM::Node<std::string>& scriptNode, - const std::string& expr) { - return _impl->evalAsBool(scriptNode, expr); - } - - virtual uint32_t getLength(const std::string& expr) { - return _impl->getLength(expr); - } - virtual void setForeach(const std::string& item, - const std::string& array, - const std::string& index, - uint32_t iteration) { - return _impl->setForeach(item, array, index, iteration); - } - - virtual void assign(const Arabica::DOM::Element<std::string>& assignElem, - const Arabica::DOM::Node<std::string>& node, - const std::string& content) { - return _impl->assign(assignElem, node, content); - } - virtual void assign(const std::string& location, const Data& data) { - return _impl->assign(location, data); - } - - virtual void init(const Arabica::DOM::Element<std::string>& dataElem, - const Arabica::DOM::Node<std::string>& node, - const std::string& content) { - return _impl->init(dataElem, node, content); - } - virtual void init(const std::string& location, const Data& data) { - return _impl->init(location, data); - } - - virtual bool isDeclared(const std::string& expr) { - return _impl->isDeclared(expr); - } - - size_t replaceExpressions(std::string& content) { - return _impl->replaceExpressions(content); - } - - std::string andExpressions(std::list<std::string> expressions) { - return _impl->andExpressions(expressions); - } - - virtual void setInterpreter(InterpreterImpl* interpreter) { - _impl->setInterpreter(interpreter); - } - -protected: - boost::shared_ptr<DataModelImpl> _impl; -}; class USCXML_API Factory { public: diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index f5aaf77..22fb79e 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -25,22 +25,30 @@ #include "uscxml/DOMUtils.h" #include "uscxml/transform/ChartToFSM.h" // only for testing +#include "getopt.h" + #include "uscxml/plugins/invoker/http/HTTPServletInvoker.h" +#include "uscxml/server/InterpreterServlet.h" +#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h" #include <DOM/Simple/DOMImplementation.hpp> #include <SAX/helpers/InputSourceResolver.hpp> +#include <DOM/io/Stream.hpp> #include <boost/lexical_cast.hpp> #include <boost/tokenizer.hpp> #include <boost/algorithm/string.hpp> #include <glog/logging.h> +#include <iostream> +#include <io/uri.hpp> #include <assert.h> #include <algorithm> #include "uscxml/interpreter/InterpreterDraft6.h" #include "uscxml/interpreter/InterpreterRC.h" +#include "uscxml/Factory.h" #if 1 #define INTERPRETER_IMPL InterpreterDraft6 @@ -52,43 +60,42 @@ /// valid interpreter state transitions #define VALID_FROM_INSTANTIATED(newState) ( \ - newState == InterpreterState::USCXML_FAULTED || \ - newState == InterpreterState::USCXML_MICROSTEPPED || \ - newState == InterpreterState::USCXML_DESTROYED\ + newState == USCXML_MICROSTEPPED || \ + newState == USCXML_DESTROYED\ ) #define VALID_FROM_FAULTED(newState) ( \ - newState == InterpreterState::USCXML_DESTROYED\ + newState == USCXML_DESTROYED\ ) #define VALID_FROM_INITIALIZED(newState) ( \ - newState == InterpreterState::USCXML_MICROSTEPPED || \ - newState == InterpreterState::USCXML_FINISHED \ + newState == USCXML_MICROSTEPPED || \ + newState == USCXML_FINISHED \ ) #define VALID_FROM_MICROSTEPPED(newState) ( \ - newState == InterpreterState::USCXML_DESTROYED || \ - newState == InterpreterState::USCXML_MACROSTEPPED || \ - newState == InterpreterState::USCXML_MICROSTEPPED || \ - newState == InterpreterState::USCXML_FINISHED \ + newState == USCXML_DESTROYED || \ + newState == USCXML_MACROSTEPPED || \ + newState == USCXML_MICROSTEPPED || \ + newState == USCXML_FINISHED \ ) #define VALID_FROM_MACROSTEPPED(newState) ( \ - newState == InterpreterState::USCXML_DESTROYED || \ - newState == InterpreterState::USCXML_MICROSTEPPED || \ - newState == InterpreterState::USCXML_IDLE || \ - newState == InterpreterState::USCXML_FINISHED \ + newState == USCXML_DESTROYED || \ + newState == USCXML_MICROSTEPPED || \ + newState == USCXML_IDLE || \ + newState == USCXML_FINISHED \ ) #define VALID_FROM_IDLE(newState) ( \ - newState == InterpreterState::USCXML_DESTROYED || \ - newState == InterpreterState::USCXML_MICROSTEPPED || \ - newState == InterpreterState::USCXML_MACROSTEPPED \ + newState == USCXML_DESTROYED || \ + newState == USCXML_MICROSTEPPED || \ + newState == USCXML_MACROSTEPPED \ ) #define VALID_FROM_FINISHED(newState) ( \ - newState == InterpreterState::USCXML_DESTROYED || \ - newState == InterpreterState::USCXML_INSTANTIATED \ + newState == USCXML_DESTROYED || \ + newState == USCXML_INSTANTIATED \ ) #define THROW_ERROR_PLATFORM(msg) \ @@ -336,10 +343,12 @@ std::map<std::string, boost::weak_ptr<InterpreterImpl> > Interpreter::getInstanc InterpreterImpl::InterpreterImpl() { - _state.state = InterpreterState::USCXML_INSTANTIATED; - _state.thread = 0; + _state = USCXML_INSTANTIATED; + _lastRunOnMainThread = 0; _thread = NULL; + _isStarted = false; + _isRunning = false; _sendQueue = NULL; _parentQueue = NULL; _topLevelFinalReached = false; @@ -448,7 +457,7 @@ Interpreter Interpreter::fromInputSource(Arabica::SAX::InputSource<std::string>& THROW_ERROR_PLATFORM(parser.errors()) } else { THROW_ERROR_PLATFORM("Failed to create interpreter"); -// interpreterImpl->setInterpreterState(InterpreterState::USCXML_FAULTED, parser.errors()); +// interpreterImpl->setInterpreterState(USCXML_FAULTED, parser.errors()); } } return interpreter; @@ -531,7 +540,7 @@ InterpreterImpl::~InterpreterImpl() { delete(_thread); } else { // this can happen with a shared_from_this at an interpretermonitor - setInterpreterState(InterpreterState::USCXML_DESTROYED); + setInterpreterState(USCXML_DESTROYED); } } join(); @@ -541,12 +550,12 @@ InterpreterImpl::~InterpreterImpl() { } void InterpreterImpl::start() { - _state.thread |= InterpreterState::USCXML_THREAD_STARTED; + _isStarted = true; _thread = new tthread::thread(InterpreterImpl::run, this); } void InterpreterImpl::stop() { - _state.thread &= ~InterpreterState::USCXML_THREAD_STARTED; + _isStarted = false; } void InterpreterImpl::join() { @@ -555,23 +564,21 @@ void InterpreterImpl::join() { }; bool InterpreterImpl::isRunning() { - // return _running || !_topLevelFinalReached; - return (_state.thread & InterpreterState::USCXML_THREAD_RUNNING) > 0; + return _isRunning && !_topLevelFinalReached; } void InterpreterImpl::run(void* instance) { InterpreterImpl* interpreter = ((InterpreterImpl*)instance); - interpreter->_state.thread |= InterpreterState::USCXML_THREAD_RUNNING; + interpreter->_isRunning = true; try { InterpreterState state; - while(interpreter->_state.thread & InterpreterState::USCXML_THREAD_STARTED) { + while(interpreter->_isStarted) { state = interpreter->step(-1); - switch (state & InterpreterState::USCXML_INTERPRETER_MASK) { - case uscxml::InterpreterState::USCXML_FAULTED: - case uscxml::InterpreterState::USCXML_FINISHED: - case uscxml::InterpreterState::USCXML_DESTROYED: + switch (state) { + case uscxml::USCXML_FINISHED: + case uscxml::USCXML_DESTROYED: // return as we finished goto DONE_THREAD; default: @@ -586,58 +593,42 @@ void InterpreterImpl::run(void* instance) { LOG(ERROR) << "InterpreterImpl::run catched unknown exception"; } DONE_THREAD: - ((InterpreterImpl*)instance)->_state.thread &= ~InterpreterState::USCXML_THREAD_RUNNING; - ((InterpreterImpl*)instance)->_state.thread &= ~InterpreterState::USCXML_THREAD_STARTED; + ((InterpreterImpl*)instance)->_isRunning = false; + ((InterpreterImpl*)instance)->_isStarted = false; } InterpreterState InterpreterImpl::getInterpreterState() { return _state; } -void InterpreterImpl::setInterpreterState(InterpreterState::State newState) { - setInterpreterState(newState, Event()); -} - -void InterpreterImpl::setInterpreterState(InterpreterState::State newState, const std::string& error) { - Event e; - e.name = "error.platform"; - e.data.compound["cause"] = Data(error, Data::VERBATIM); - setInterpreterState(newState, e); -} - -void InterpreterImpl::setInterpreterState(InterpreterState::State newState, const Event& error) { +void InterpreterImpl::setInterpreterState(InterpreterState newState) { switch (_state) { - case InterpreterState::USCXML_INSTANTIATED: + case USCXML_INSTANTIATED: if (VALID_FROM_INSTANTIATED(newState)) break; assert(false); break; - case InterpreterState::USCXML_FAULTED: - if (VALID_FROM_FAULTED(newState)) - break; - assert(false); - break; - case InterpreterState::USCXML_MICROSTEPPED: + case USCXML_MICROSTEPPED: if (VALID_FROM_MICROSTEPPED(newState)) break; assert(false); break; - case InterpreterState::USCXML_MACROSTEPPED: + case USCXML_MACROSTEPPED: if (VALID_FROM_MACROSTEPPED(newState)) break; assert(false); break; - case InterpreterState::USCXML_IDLE: + case USCXML_IDLE: if (VALID_FROM_IDLE(newState)) break; assert(false); break; - case InterpreterState::USCXML_FINISHED: + case USCXML_FINISHED: if (VALID_FROM_FINISHED(newState)) break; assert(false); break; - case InterpreterState::USCXML_DESTROYED: + case USCXML_DESTROYED: assert(false); break; @@ -645,13 +636,11 @@ void InterpreterImpl::setInterpreterState(InterpreterState::State newState, cons break; } - _state.state = newState; - _state.msg = error; + _state = newState; } bool InterpreterImpl::runOnMainThread(int fps, bool blocking) { - tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); - if (_state == InterpreterState::USCXML_FINISHED || _state == InterpreterState::USCXML_FAULTED || _state == InterpreterState::USCXML_DESTROYED) + if (_state == USCXML_FINISHED || _state == USCXML_DESTROYED || !_isStarted) return false; if (fps > 0) { @@ -665,6 +654,7 @@ bool InterpreterImpl::runOnMainThread(int fps, bool blocking) { } } + tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); _lastRunOnMainThread = tthread::timeStamp(); { @@ -695,7 +685,7 @@ void InterpreterImpl::reset() { _topLevelFinalReached = false; _isInitialized = false; - setInterpreterState(InterpreterState::USCXML_INSTANTIATED); + setInterpreterState(USCXML_INSTANTIATED); } void InterpreterImpl::setupAndNormalizeDOM() { @@ -2475,12 +2465,12 @@ bool InterpreterImpl::hasLegalConfiguration() { return isLegalConfiguration(_configuration); } -bool InterpreterImpl::isLegalConfiguration(const std::vector<std::string>& config) { +bool InterpreterImpl::isLegalConfiguration(const std::list<std::string>& config) { NodeSet<std::string> states; - for (int i = 0; i < config.size(); i++) { - Node<std::string> state = getState(config[i]); + for (std::list<std::string>::const_iterator confIter = config.begin(); confIter != config.end(); confIter++) { + Node<std::string> state = getState(*confIter); if (!state) { - LOG(INFO) << "No state with id '" << config[i] << "'"; + LOG(INFO) << "No state with id '" << *confIter << "'"; return false; } states.push_back(state); @@ -2626,21 +2616,17 @@ void InterpreterImpl::DOMEventListener::handleEvent(Arabica::DOM::Events::Event< } std::ostream& operator<< (std::ostream& os, const InterpreterState& interpreterState) { - os << "[" << InterpreterState::stateToString(interpreterState.state) << "]:" << std::endl; - os << interpreterState.msg; + os << "[" << InterpreterImpl::stateToString(interpreterState) << "]" << std::endl; return os; } -std::string InterpreterState::stateToString(int32_t state) { +std::string InterpreterImpl::stateToString(InterpreterState state) { std::stringstream ss; - switch(state & USCXML_INTERPRETER_MASK) { + switch(state) { case USCXML_INSTANTIATED: ss << "INSTANTIATED"; break; - case USCXML_FAULTED: - ss << "FAULTED"; - break; case USCXML_MICROSTEPPED: ss << "MICROSTEPPED"; break; @@ -2661,17 +2647,6 @@ std::string InterpreterState::stateToString(int32_t state) { break; } - if (state & USCXML_THREAD_STARTED) { - ss << ", " << "STARTED"; - } else { - ss << ", " << "STOPPED"; - } - if (state & USCXML_THREAD_RUNNING) { - ss << ", " << "RUNNING"; - } else { - ss << ", " << "JOINED"; - } - return ss.str(); } diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 9a3e553..a07d9af 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -22,31 +22,31 @@ // this has to be the first include or MSVC will run amok #include "uscxml/Common.h" -#include "getopt.h" - -#include "uscxml/URL.h" +#include <iostream> // arabica xpath uses cerr without iostream #include <boost/shared_ptr.hpp> -#include <iostream> #include <set> #include <map> #include <XPath/XPath.hpp> #include <DOM/Document.hpp> -#include <io/uri.hpp> #include <DOM/SAX2DOM/SAX2DOM.hpp> #include <SAX/helpers/CatchErrorHandler.hpp> #include <DOM/Events/EventTarget.hpp> #include <DOM/Events/EventListener.hpp> -#include "uscxml/concurrency/tinythread.h" -#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h" #include "uscxml/concurrency/BlockingQueue.h" -#include "uscxml/Message.h" -#include "uscxml/Factory.h" +#include "uscxml/messages/Data.h" +#include "uscxml/messages/SendRequest.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 "uscxml/server/InterpreterServlet.h" #define USCXML_MONITOR_CATCH(callback) \ catch (Event e) { \ @@ -56,7 +56,7 @@ catch (Event e) { \ } catch (...) { \ LOG(ERROR) << "An exception occured when calling " #callback " on monitors"; \ } \ -if (_state == InterpreterState::USCXML_DESTROYED) { \ +if (_state == USCXML_DESTROYED) { \ throw boost::bad_weak_ptr(); \ } \ @@ -89,31 +89,10 @@ namespace uscxml { class HTTPServletInvoker; class InterpreterMonitor; - -class USCXML_API 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 InterpreterHTTPServlet; +class InterpreterWebSocketServlet; +class Factory; +class DelayedEventQueue; enum Capabilities { CAN_NOTHING = 0, @@ -219,54 +198,16 @@ private: void init(const std::map<std::string, std::string>& nsInfo); }; -struct USCXML_API InterpreterState { - // see: http://stackoverflow.com/questions/18591924/how-to-use-bitmask - enum State { - USCXML_DESTROYED = 0x0001, // - USCXML_INSTANTIATED = 0x0002, // nothing really, just instantiated - USCXML_MICROSTEPPED = 0x0004, // - USCXML_MACROSTEPPED = 0x0008, // - USCXML_IDLE = 0x0010, // - USCXML_FAULTED = 0x0020, // something went very wrong - USCXML_FINISHED = 0x0040, // machine reached a final configuration - }; - - enum ThreadState { - USCXML_THREAD_RUNNING = 0x0100, // - USCXML_THREAD_STARTED = 0x0200, // - }; - - enum BitMask { - USCXML_THREAD_MASK = 0xff00, - USCXML_INTERPRETER_MASK = 0x00ff, - }; - - bool operator==(const InterpreterState& other) const { - return state == other.state && msg == other.msg; - } - bool operator!=(const InterpreterState& other) const { - return !(*this == other); - } - - operator int() { - return (int)(state | thread); - } - - Event getMessage() { - return msg; - } - - static std::string stateToString(int32_t state); - - friend USCXML_API std::ostream& operator<< (std::ostream& os, const InterpreterState& interpreterState); - friend USCXML_API class InterpreterImpl; - -protected: - int32_t thread; - State state; - Event msg; +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_INSTANTIATED = 1, ///< nothing really, just instantiated + USCXML_MICROSTEPPED = 2, ///< 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 boost::enable_shared_from_this<InterpreterImpl> { @@ -383,8 +324,8 @@ public: return basicConfig; } - void setInitalConfiguration(const std::vector<std::string>& states) { - _userDefinedStartConfiguration = states; + void setInitalConfiguration(const std::list<std::string>& states) { + _startConfiguration = states; } void setInvokeRequest(const InvokeRequest& req) { _invokeReq = req; @@ -424,7 +365,7 @@ public: bool hasLegalConfiguration(); bool isLegalConfiguration(const Arabica::XPath::NodeSet<std::string>&); - bool isLegalConfiguration(const std::vector<std::string>&); + bool isLegalConfiguration(const std::list<std::string>&); static bool isState(const Arabica::DOM::Node<std::string>& state); static bool isPseudoState(const Arabica::DOM::Node<std::string>& state); @@ -439,6 +380,8 @@ public: bool isInEmbeddedDocument(const Arabica::DOM::Node<std::string>& node); bool isInitial(const Arabica::DOM::Node<std::string>& state); + static std::string stateToString(InterpreterState state); + Arabica::DOM::Node<std::string> getState(const std::string& stateId); Arabica::XPath::NodeSet<std::string> getStates(const std::list<std::string>& stateIds); Arabica::XPath::NodeSet<std::string> getAllStates(); @@ -481,9 +424,7 @@ protected: void initializeData(const Arabica::DOM::Element<std::string>& data); void finalizeAndAutoForwardCurrentEvent(); - void setInterpreterState(InterpreterState::State newState, const std::string& error); - void setInterpreterState(InterpreterState::State newState, const Event& error); - void setInterpreterState(InterpreterState::State newState); + void setInterpreterState(InterpreterState newState); bool _stable; tthread::thread* _thread; @@ -503,11 +444,14 @@ protected: bool _isInitialized; bool _domIsSetup; + bool _isStarted; + bool _isRunning; + InterpreterImpl::Binding _binding; Arabica::XPath::NodeSet<std::string> _configuration; Arabica::XPath::NodeSet<std::string> _alreadyEntered; Arabica::XPath::NodeSet<std::string> _statesToInvoke; - std::vector<std::string> _userDefinedStartConfiguration; + std::list<std::string> _startConfiguration; InvokeRequest _invokeReq; DataModel _dataModel; @@ -588,9 +532,7 @@ public: virtual ~Interpreter() {}; operator bool() const { - return (_impl && - _impl->_state != InterpreterState::USCXML_FAULTED && - _impl->_state != InterpreterState::USCXML_DESTROYED); + return (_impl && _impl->_state != USCXML_DESTROYED); } bool operator< (const Interpreter& other) const { return _impl < other._impl; @@ -716,7 +658,7 @@ public: return _impl->getBasicConfiguration(); } - void setInitalConfiguration(const std::vector<std::string>& states) { + void setInitalConfiguration(const std::list<std::string>& states) { return _impl->setInitalConfiguration(states); } @@ -772,7 +714,7 @@ public: return _impl->isLegalConfiguration(config); } - bool isLegalConfiguration(const std::vector<std::string>& config) { + bool isLegalConfiguration(const std::list<std::string>& config) { return _impl->isLegalConfiguration(config); } diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp index 1ac3573..465b4ba 100644 --- a/src/uscxml/Message.cpp +++ b/src/uscxml/Message.cpp @@ -28,769 +28,30 @@ #include <boost/algorithm/string.hpp> -#ifdef HAS_STRING_H -#include <string.h> -#endif - -extern "C" { -#include "jsmn.h" // minimal json parser -} namespace uscxml { -static int _dataIndentation = 1; - -Blob::~Blob() { - free(data); -} - -Blob::Blob(size_t _size) { - data = (char*)malloc(_size); - memset(data, 0, _size); - size = _size; -} - -Blob::Blob(void* _data, size_t _size, const std::string& _mimeType, bool adopt) { - if (adopt) { - data = (char*)_data; - } else { - data = (char*)malloc(_size); - memcpy(data, _data, _size); - } - mimeType = _mimeType; - size = _size; -} - -#if 0 -// this used to work base64 encoded images in a browser - can't check extensively just now -static const std::string base64_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - -std::string Blob::base64() { - - int in_len = size; - char const* bytes_to_encode = data; - - std::string ret; - int i = 0; - int j = 0; - unsigned char char_array_3[3]; - unsigned char char_array_4[4]; - - while (in_len--) { - char_array_3[i++] = *(bytes_to_encode++); - if (i == 3) { - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for(i = 0; (i <4) ; i++) - ret += base64_chars[char_array_4[i]]; - i = 0; - } - } - - if (i) { - for(j = i; j < 3; j++) - char_array_3[j] = '\0'; - - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (j = 0; (j < i + 1); j++) - ret += base64_chars[char_array_4[j]]; - - while((i++ < 3)) - ret += '='; - - } - - return ret; - -} -#else -std::string Blob::base64() { - return base64Encode((char* const)data, size); -} -#endif - -Data::Data(const char* _data, size_t _size, const std::string& mimeType, bool adopt) { - binary = boost::shared_ptr<Blob>(new Blob((void*)_data, _size, mimeType, adopt)); -} - -void Data::merge(const Data& other) { - if (other.compound.size() > 0) { - if (compound.size() == 0) { - compound = other.compound; - } else { - std::map<std::string, Data>::const_iterator compIter = other.compound.begin(); - while (compIter != other.compound.end()) { - if (compound.find(compIter->first) != compound.end()) { - // we do have the same key, merge - compound[compIter->first].merge(compIter->second); - } else { - compound[compIter->first] = compIter->second; - } - compIter++; - } - } - } - if (other.array.size() > 0) { - if (array.size() == 0) { - array = other.array; - } else { - std::list<Data>::const_iterator arrIter = other.array.begin(); - while(arrIter != other.array.end()) { - array.push_back(*arrIter); - arrIter++; - } - } - } - if (other.atom.size() > 0) { - atom = other.atom; - type = other.type; - } -} - -Data::Data(const Arabica::DOM::Node<std::string>& dom) { - // we may need to convert some keys to arrays if we have the same name as an element - std::map<std::string, std::list<Data> > arrays; -// Interpreter::dump(dom); - - if (dom.hasAttributes()) { - Arabica::DOM::NamedNodeMap<std::string> attributes = dom.getAttributes(); - for (int i = 0; i < attributes.getLength(); i++) { - Arabica::DOM::Node<std::string> attribute = attributes.item(i); -// Interpreter::dump(attribute); - - assert(attribute.getNodeType() == Arabica::DOM::Node_base::ATTRIBUTE_NODE); - std::string key = attribute.getLocalName(); - std::string value = attribute.getNodeValue(); - compound[key] = Data(value, VERBATIM); - } - } - - if (dom.hasChildNodes()) { - Arabica::DOM::NodeList<std::string> children = dom.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) { - Arabica::DOM::Node<std::string> child = children.item(i); -// Interpreter::dump(child); - std::string key; - switch (child.getNodeType()) { - case Arabica::DOM::Node_base::ELEMENT_NODE: - key = TAGNAME(child); - break; - case Arabica::DOM::Node_base::ATTRIBUTE_NODE: - key = ((Arabica::DOM::Attr<std::string>)child).getName(); - break; - case Arabica::DOM::Node_base::TEXT_NODE: - default: - break; - } - if (key.length() == 0) - continue; - - if (compound.find(key) != compound.end()) { - // we already have such a key .. make it an array after we processed all children - arrays[key].push_back(Data(child)); - } else { - compound[key] = Data(child); - } - } - } else { - atom = dom.getNodeValue(); - type = VERBATIM; - } - - std::map<std::string, std::list<Data> >::iterator arrayIter = arrays.begin(); - while(arrayIter != arrays.end()) { - assert(compound.find(arrayIter->first) != compound.end()); - Data arrayData; - arrays[arrayIter->first].push_front(compound[arrayIter->first]); - arrayData.array = arrays[arrayIter->first]; - compound[arrayIter->first] = arrayData; - } -} - -Arabica::DOM::Document<std::string> Data::toDocument() { - Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); - Arabica::DOM::Document<std::string> document = domFactory.createDocument("http://www.w3.org/2005/07/scxml", "message", 0); - Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement(); - scxmlMsg.setPrefix("scxml"); - scxmlMsg.setAttribute("version", "1.0"); - - if (compound.size() > 0 || array.size() > 0) { - Arabica::DOM::Element<std::string> payloadElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "payload"); - payloadElem.setPrefix("scxml"); - - scxmlMsg.appendChild(payloadElem); - - // we do not support nested attibutes - if (compound.size() > 0) { - std::map<std::string, Data>::iterator compoundIter = compound.begin(); - while(compoundIter != compound.end()) { - if (compoundIter->second.atom.size() > 0) { - Arabica::DOM::Element<std::string> propertyElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "property"); - propertyElem.setPrefix("scxml"); - - propertyElem.setAttribute("name", compoundIter->first); - Arabica::DOM::Text<std::string> textElem = document.createTextNode(compoundIter->second.atom); - propertyElem.appendChild(textElem); - payloadElem.appendChild(propertyElem); - } - compoundIter++; - } - } - } - return document; -} - -//Arabica::DOM::Node<std::string> Event::getFirstDOMElement() const { -// return getFirstDOMElement(dom); -//} -// -//Arabica::DOM::Document<std::string> Event::getStrippedDOM() const { -// return getStrippedDOM(dom); -//} - -//Arabica::DOM::Node<std::string> Event::getFirstDOMElement(const Arabica::DOM::Document<std::string> dom) { -// Arabica::DOM::Node<std::string> data = dom.getDocumentElement().getFirstChild(); -// while (data) { -// if (data.getNodeType() == Arabica::DOM::Node_base::TEXT_NODE) { -// std::string trimmed = boost::trim_copy(data.getNodeValue()); -// if (trimmed.length() == 0) { -// data = data.getNextSibling(); -// continue; -// } -// } -// break; -// } -// return data; -//} -// -//Arabica::DOM::Document<std::string> Event::getStrippedDOM(const Arabica::DOM::Document<std::string> dom) { -// Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); -// Arabica::DOM::Document<std::string> document = domFactory.createDocument("", "", 0); -// if (dom) { -// document.getDocumentElement().appendChild(document.importNode(getFirstDOMElement(dom), true)); -// } -// return document; -//} - -Arabica::DOM::Document<std::string> Event::toDocument() { - Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); - Arabica::DOM::Document<std::string> document = data.toDocument(); - Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement(); - - - scxmlMsg.setAttribute("source", origin); - scxmlMsg.setAttribute("name", name); - - return document; -} - -Arabica::DOM::Document<std::string> SendRequest::toDocument() { - Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); - Arabica::DOM::Document<std::string> document = Event::toDocument(); - Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement(); - - // add params and namelist - if (params.size() > 0 || namelist.size() > 0) { - Arabica::DOM::NodeList<std::string> payload = scxmlMsg.getElementsByTagName("scxml:payload"); - if (payload.getLength() == 0) { - Arabica::DOM::Element<std::string> payloadElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "payload"); - payloadElem.setPrefix("scxml"); - - scxmlMsg.appendChild(payloadElem); - } - Arabica::DOM::Node<std::string> payloadElem = scxmlMsg.getElementsByTagName("scxml:payload").item(0); - - // add parameters - std::multimap<std::string, Data>::iterator paramIter = params.begin(); - while(paramIter != params.end()) { - Arabica::DOM::Element<std::string> propertyElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "property"); - propertyElem.setPrefix("scxml"); - - propertyElem.setAttribute("name", paramIter->first); - // this is simplified - Data might be more elaborate than a simple string atom - Arabica::DOM::Text<std::string> textElem = document.createTextNode(paramIter->second.atom); - propertyElem.appendChild(textElem); - payloadElem.appendChild(propertyElem); - paramIter++; - } - - // add namelist elements - std::map<std::string, Data>::iterator namelistIter = namelist.begin(); - while(namelistIter != namelist.end()) { - Arabica::DOM::Element<std::string> propertyElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "property"); - propertyElem.setPrefix("scxml"); - - propertyElem.setAttribute("name", namelistIter->first); - // this is simplified - Data might be more elaborate than a simple string atom - Arabica::DOM::Text<std::string> textElem = document.createTextNode(namelistIter->second.atom); - propertyElem.appendChild(textElem); - payloadElem.appendChild(propertyElem); - namelistIter++; - } - - } - - scxmlMsg.setAttribute("sendid", sendid); - - return document; -} - -Arabica::DOM::Document<std::string> InvokeRequest::toDocument() { - Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); - Arabica::DOM::Document<std::string> document = Event::toDocument(); - Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement(); - scxmlMsg.setAttribute("invokeid", invokeid); - return document; -} -Data Data::fromXML(const std::string& xmlString) { - return Data(); -} -Data Data::fromJSON(const std::string& jsonString) { - Data data; - std::string trimmed = boost::trim_copy(jsonString); - if (trimmed.length() == 0) - return data; - if (trimmed.find_first_of("{[") != 0) - return data; - jsmn_parser p; - - jsmntok_t* t = NULL; - - // we do not know the number of tokens beforehand, start with something sensible and increase - int rv; - int frac = 16; // length/token ratio - do { - jsmn_init(&p); - - frac /= 2; - int nrTokens = trimmed.size() / frac; - if (t != NULL) { - free(t); -// LOG(INFO) << "Increasing JSON length to token ratio to 1/" << frac; - } - t = (jsmntok_t*)malloc((nrTokens + 1) * sizeof(jsmntok_t)); - if (t == NULL) { - LOG(ERROR) << "Cannot parse JSON, ran out of memory!"; - return data; - } - memset(t, 0, (nrTokens + 1) * sizeof(jsmntok_t)); - - rv = jsmn_parse(&p, trimmed.c_str(), t, nrTokens); - } while (rv == JSMN_ERROR_NOMEM && frac > 1); - - if (rv != 0) { - switch (rv) { - case JSMN_ERROR_NOMEM: - LOG(ERROR) << "Cannot parse JSON, not enough tokens were provided!"; - break; - case JSMN_ERROR_INVAL: - LOG(ERROR) << "Cannot parse JSON, invalid character inside JSON string!"; - break; - case JSMN_ERROR_PART: - LOG(ERROR) << "Cannot parse JSON, the string is not a full JSON packet, more bytes expected!"; - break; - default: - break; - } - free(t); - return data; - } - - if (t[0].end != trimmed.length()) - return data; - -// jsmntok_t* token = t; -// while(token->end) { -// std::cout << trimmed.substr(token->start, token->end - token->start) << std::endl; -// std::cout << "------" << std::endl; -// token++; -// } - - std::list<Data*> dataStack; - std::list<jsmntok_t> tokenStack; - dataStack.push_back(&data); - - size_t currTok = 0; - do { - // used for debugging -// jsmntok_t t2 = t[currTok]; -// std::string value = trimmed.substr(t[currTok].start, t[currTok].end - t[currTok].start); - switch (t[currTok].type) { - case JSMN_STRING: - dataStack.back()->type = Data::VERBATIM; - case JSMN_PRIMITIVE: { - std::string value = trimmed.substr(t[currTok].start, t[currTok].end - t[currTok].start); - if (dataStack.back()->type == Data::VERBATIM) { - boost::replace_all(value, "\\\"", "\""); - boost::replace_all(value, "\\n", "\n"); - } - dataStack.back()->atom = value; - dataStack.pop_back(); - currTok++; - break; - } - case JSMN_OBJECT: - case JSMN_ARRAY: - tokenStack.push_back(t[currTok]); - currTok++; - break; - } - // used for debugging -// t2 = t[currTok]; -// value = trimmed.substr(t[currTok].start, t[currTok].end - t[currTok].start); - - // there are no more tokens - if (t[currTok].end == 0 || tokenStack.empty()) - break; - - // next token starts after current one => pop - while (t[currTok].end > tokenStack.back().end) { - tokenStack.pop_back(); - dataStack.pop_back(); - } - - if (tokenStack.back().type == JSMN_OBJECT && (t[currTok].type == JSMN_PRIMITIVE || t[currTok].type == JSMN_STRING)) { - // grab key and push new data - std::string value = trimmed.substr(t[currTok].start, t[currTok].end - t[currTok].start); - dataStack.push_back(&(dataStack.back()->compound[value])); - currTok++; - } - if (tokenStack.back().type == JSMN_ARRAY) { - // push new index - dataStack.back()->array.push_back(Data()); - dataStack.push_back(&(dataStack.back()->array.back())); - } - - } while (true); - - free(t); - return data; -} - -void Event::initContent(const std::string& content) { - // try to parse as JSON - Data json = Data::fromJSON(content); - if (!json.empty()) { - data = json; - return; - } - - // try to parse as XML - Arabica::SAX2DOM::Parser<std::string> parser; - Arabica::SAX::CatchErrorHandler<std::string> errorHandler; - parser.setErrorHandler(errorHandler); - - std::istringstream is(content); - Arabica::SAX::InputSource<std::string> inputSource; - inputSource.setByteStream(is); - if (parser.parse(inputSource)) { - dom = parser.getDocument(); - return; - } - - this->content = content; -} - -Event Event::fromXML(const std::string& xmlString) { - Arabica::SAX2DOM::Parser<std::string> eventParser; - Arabica::SAX::CatchErrorHandler<std::string> errorHandler; - eventParser.setErrorHandler(errorHandler); - - std::istringstream is(xmlString); - Arabica::SAX::InputSource<std::string> inputSource; - inputSource.setByteStream(is); - - Event event; - if(eventParser.parse(inputSource) && eventParser.getDocument().hasChildNodes()) { - Arabica::DOM::Element<std::string> scxmlMsg = eventParser.getDocument().getDocumentElement(); - if (HAS_ATTR(scxmlMsg, "name")) - event.name = ATTR(scxmlMsg, "name"); - if (HAS_ATTR(scxmlMsg, "sendid")) - event.sendid = ATTR(scxmlMsg, "sendid"); - - Arabica::DOM::NodeList<std::string> payloads = scxmlMsg.getElementsByTagName("scxml:payload"); - if (payloads.getLength() > 0) { - Arabica::DOM::Node<std::string> payload = payloads.item(0); - if (payload.getNodeType() == Arabica::DOM::Node_base::ELEMENT_NODE) { - Arabica::DOM::Element<std::string> payloadElem = (Arabica::DOM::Element<std::string>)payload; - Arabica::DOM::NodeList<std::string> properties = payloadElem.getElementsByTagName("scxml:property"); - if (properties.getLength() > 0) { - for (int i = 0; i < properties.getLength(); i++) { - if (HAS_ATTR(properties.item(i), "name")) { - std::string key = ATTR(properties.item(i), "name"); - std::string value; - Arabica::DOM::NodeList<std::string> childs = properties.item(i).getChildNodes(); - for (int j = 0; j < childs.getLength(); j++) { - if (childs.item(j).getNodeType() == Arabica::DOM::Node_base::TEXT_NODE) { - value = childs.item(j).getNodeValue(); - break; - } - } - event.data.compound[key] = Data(value, Data::VERBATIM); - } - } - } - } - } - } - return event; -} - -SendRequest SendRequest::fromXML(const std::string& xmlString) { - Event::fromXML(xmlString); - return SendRequest(); -} - -InvokeRequest InvokeRequest::fromXML(const std::string& xmlString) { - Event::fromXML(xmlString); - return InvokeRequest(); -} #ifndef SWIGJAVA -std::ostream& operator<< (std::ostream& os, const InvokeRequest& invokeReq) { - - std::string indent; - for (int i = 0; i < _dataIndentation; i++) { - indent += " "; - } - - os << indent << "InvokeReq" << (invokeReq.autoForward ? " with autoforward" : "") << std::endl; - - if (invokeReq.type.size() > 0) - os << indent << " type: " << invokeReq.type << std::endl; - - if (invokeReq.src.size() > 0) - os<< indent << " src: " << invokeReq.src << std::endl; - - if (invokeReq.namelist.size() > 0) { - os << indent << " namelist: " << std::endl; - InvokeRequest::namelist_t::const_iterator namelistIter = invokeReq.namelist.begin(); - while(namelistIter != invokeReq.namelist.end()) { - os << indent << " " << namelistIter->first << ": " << namelistIter->second << std::endl; - namelistIter++; - } - } - - if (invokeReq.params.size() > 0) { - os << indent << " params: " << std::endl; - SendRequest::params_t::const_iterator paramIter = invokeReq.params.begin(); - while(paramIter != invokeReq.params.end()) { - os << indent << " " << paramIter->first << ": " << paramIter->second << std::endl; - paramIter++; - } - } - - if (invokeReq.content.size() > 0) - os << indent << " content: " << invokeReq.content << std::endl; - - _dataIndentation++; - os << (Event)invokeReq; - _dataIndentation--; - return os; - -} #endif #ifndef SWIGJAVA -std::ostream& operator<< (std::ostream& os, const SendRequest& sendReq) { - - std::string indent; - for (int i = 0; i < _dataIndentation; i++) { - indent += " "; - } - - os << indent << "SendReq" << std::endl; - - if (sendReq.target.size() > 0) - os << indent << " target: " << sendReq.target << std::endl; - - if (sendReq.type.size() > 0) - os << indent << " type: " << sendReq.type << std::endl; - - if (sendReq.delayMs > 0) - os<< indent << " delay: " << sendReq.delayMs << std::endl; - - if (sendReq.namelist.size() > 0) { - os << indent << " namelist: " << std::endl; - SendRequest::namelist_t::const_iterator namelistIter = sendReq.namelist.begin(); - while(namelistIter != sendReq.namelist.end()) { - os << indent << " " << namelistIter->first << ": " << namelistIter->second << std::endl; - namelistIter++; - } - } - - if (sendReq.params.size() > 0) { - os << indent << " params: " << std::endl; - SendRequest::params_t::const_iterator paramIter = sendReq.params.begin(); - while(paramIter != sendReq.params.end()) { - os << indent << " " << paramIter->first << ": " << paramIter->second << std::endl; - paramIter++; - } - } - - if (sendReq.content.size() > 0) - os << indent << " content: " << sendReq.content << std::endl; - - _dataIndentation++; - os << (Event)sendReq; - _dataIndentation--; - return os; - -} #endif #ifndef SWIGJAVA -std::ostream& operator<< (std::ostream& os, const Event& event) { - std::string indent; - for (int i = 0; i < _dataIndentation; i++) { - indent += " "; - } - - os << indent << (event.eventType == Event::EXTERNAL ? "External" : "Internal") << " Event " << (event.dom ? "with DOM attached" : "") << std::endl; - - if (event.name.size() > 0) - os << indent << " name: " << event.name << std::endl; - if (event.origin.size() > 0) - os << indent << " origin: " << event.origin << std::endl; - if (event.origintype.size() > 0) - os << indent << " origintype: " << event.origintype << std::endl; - if (event.params.size() > 0) { - std::multimap<std::string, Data>::const_iterator paramIter = event.params.begin(); - os << indent << " params:" << std::endl; - _dataIndentation++; - while(paramIter != event.params.end()) { - os << indent << " " << paramIter->first << ": "; - os << indent << paramIter->second << std::endl; - paramIter++; - } - _dataIndentation--; - } - if (event.namelist.size() > 0) { - std::map<std::string, Data>::const_iterator namelistIter = event.namelist.begin(); - os << indent << " namelist:" << std::endl; - _dataIndentation++; - while(namelistIter != event.namelist.end()) { - os << indent << " " << namelistIter->first << ": "; - os << indent << namelistIter->second << std::endl; - namelistIter++; - } - _dataIndentation--; - - } - _dataIndentation++; - os << indent << " data: " << event.data << std::endl; - _dataIndentation--; - return os; -} #endif #ifndef SWIGJAVA -std::ostream& operator<< (std::ostream& os, const Data& data) { - os << Data::toJSON(data); - return os; -} #endif -std::string Data::toJSON(const Data& data) { - std::stringstream os; - std::string indent; - for (int i = 0; i < _dataIndentation; i++) { - indent += " "; - } - if (false) { - } else if (data.compound.size() > 0) { - int longestKey = 0; - std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin(); - while(compoundIter != data.compound.end()) { - if (compoundIter->first.size() > longestKey) - longestKey = compoundIter->first.size(); - compoundIter++; - } - std::string keyPadding; - for (unsigned int i = 0; i < longestKey; i++) - keyPadding += " "; - - std::string seperator; - os << std::endl << indent << "{"; - compoundIter = data.compound.begin(); - while(compoundIter != data.compound.end()) { - os << seperator << std::endl << indent << " \"" << compoundIter->first << "\": " << keyPadding.substr(0, longestKey - compoundIter->first.size()); - _dataIndentation += 1; - os << compoundIter->second; - _dataIndentation -= 1; - seperator = ", "; - compoundIter++; - } - os << std::endl << indent << "}"; - } else if (data.array.size() > 0) { - - std::string seperator; - os << std::endl << indent << "["; - std::list<Data>::const_iterator arrayIter = data.array.begin(); - while(arrayIter != data.array.end()) { - _dataIndentation += 1; - os << seperator << *arrayIter; - _dataIndentation -= 1; - seperator = ", "; - arrayIter++; - } - os << "]"; - } else if (data.atom.size() > 0) { - // empty string is handled below - if (data.type == Data::VERBATIM) { - os << "\""; - for (int i = 0; i < data.atom.size(); i++) { - // escape string - if (false) { - } else if (data.atom[i] == '"') { - os << "\\\""; - } else if (data.atom[i] == '\n') { - os << "\\n"; - } else if (data.atom[i] == '\t') { - os << "\\t"; - } else { - os << data.atom[i]; - } - } - os << "\""; - } else { - os << data.atom; - } - } else if (data.node) { - std::ostringstream xmlSerSS; - xmlSerSS << data.node; - std::string xmlSer = xmlSerSS.str(); - boost::replace_all(xmlSer, "\"", "\\\""); - boost::replace_all(xmlSer, "\n", "\\n"); - boost::replace_all(xmlSer, "\t", "\\t"); - os << "\"" << xmlSer << "\""; - } else { - if (data.type == Data::VERBATIM) { - os << "\"\""; // empty string - } else { - os << "null"; - } - } - return os.str(); -} }
\ No newline at end of file diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index 05dc758..5732857 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -20,555 +20,11 @@ #ifndef EVENT_H_XZAQ4HR #define EVENT_H_XZAQ4HR -#include <map> -#include <list> -#include <set> -#include <vector> -#include <string> - -#include <DOM/Document.hpp> -#include <DOM/io/Stream.hpp> - -#include <boost/shared_ptr.hpp> -#include <boost/lexical_cast.hpp> -#include <inttypes.h> - -#include "uscxml/Common.h" - -#include "uscxml/Convenience.h" - -#include "uscxml/util/MD5.hpp" -#include "uscxml/util/Base64.hpp" - -namespace uscxml { - -class USCXML_API Blob { -public: - ~Blob(); - Blob(size_t size); - Blob(void* data, size_t size, const std::string& mimeType, bool adopt = false); - char* data; - size_t size; - std::string mimeType; - - std::string md5() { - return uscxml::md5(data, size); - } - - std::string base64(); - - Blob* fromBase64(const std::string base64) { - std::string decoded = base64Decode(base64); - return new Blob((void*)decoded.c_str(), decoded.length(), mimeType); - } -}; - -class USCXML_API Data { -public: - enum Type { - VERBATIM, - INTERPRETED, - }; - - Data() : type(INTERPRETED) {} - - // TODO: default INTERPRETED is unfortunate - Data(const std::string& atom_, Type type_ = INTERPRETED) : atom(atom_), type(type_) {} - Data(const char* data, size_t size, const std::string& mimeType, bool adopt = false); - - // convenience constructors - Data(short atom_) : atom(toStr(atom_)), type(INTERPRETED) {} - Data(int atom_) : atom(toStr(atom_)), type(INTERPRETED) {} - Data(unsigned int atom_) : atom(toStr(atom_)), type(INTERPRETED) {} - Data(long atom_) : atom(toStr(atom_)), type(INTERPRETED) {} - Data(unsigned long atom_) : atom(toStr(atom_)), type(INTERPRETED) {} - Data(float atom_) : atom(toStr(atom_)), type(INTERPRETED) {} - Data(double atom_) : atom(toStr(atom_)), type(INTERPRETED) {} - Data(bool atom_) : type(INTERPRETED) { - if (atom_) { - atom = "true"; - } else { - atom = "false"; - } - } - - template <typename T> Data(T value, Type type_) : atom(toStr(value)), type(type_) {} - -#if 0 - // constructor for arbitrary types, skip if type is subclass though (C++11) - // we will have to drop this constructor as it interferes with operator Data() and entails C++11 - template <typename T> - Data(T value, typename std::enable_if<! std::is_base_of<Data, T>::value>::type* = nullptr) - : atom(toStr(value)), type(INTERPRETED) {} -#endif - - - explicit Data(const Arabica::DOM::Node<std::string>& dom); - virtual ~Data() {} - - bool empty() const { - bool hasContent = (atom.length() > 0 || !compound.empty() || !array.empty() || binary || node); - return !hasContent; - } - - bool operator<(const Data& other) const { - std::string thisJSON = Data::toJSON(*this); - std::string otherJSON = Data::toJSON(other); - return (thisJSON < otherJSON); - } - - void merge(const Data& other); - - bool hasKey(const std::string& key) const { - return (!compound.empty() && compound.find(key) != compound.end()); - } - - Data& operator[](const std::string& key) { - return operator[](key.c_str()); - } - - const Data& operator[](const std::string& key) const { - return operator[](key.c_str()); - } - - Data& operator[](const char* key) { - return compound[key]; - } - - const Data& operator[](const char* key) const { - return compound.at(key); - } - - Data& operator[](const size_t index) { - while(array.size() < index) { - array.push_back(Data("", Data::VERBATIM)); - } - std::list<Data>::iterator arrayIter = array.begin(); - for (int i = 0; i < index; i++, arrayIter++) {} - return *arrayIter; - } - - const Data at(const std::string& key) const { - return at(key.c_str()); - } - - const Data at(const char* key) const { - if (hasKey(key)) - return compound.at(key); - Data data; - return data; - } - - const Data item(const size_t index) const { - if (array.size() < index) { - std::list<Data>::const_iterator arrayIter; - for (int i = 0; i < index; i++, arrayIter++) {} - return *arrayIter; - } - Data data; - return data; - } - - bool operator==(const Data &other) const { - if (other.atom.size() != atom.size()) - return false; - if (other.type != type) - return false; - if (other.binary != binary) - return false; - if (other.array.size() != array.size()) - return false; - if (other.compound.size() != compound.size()) - return false; - - if (other.atom != atom) - return false; - if (other.array != array) - return false; - if (other.compound != compound) - return false; - if (other.node != node) - return false; - - return true; - } - - bool operator!=(const Data &other) const { - return !(*this == other); - } - - operator std::string() const { - return atom; - } - - operator std::map<std::string, Data>() { - return compound; - } - - operator std::list<Data>() { - return array; - } - - static Data fromJSON(const std::string& jsonString); - static std::string toJSON(const Data& data); - static Data fromXML(const std::string& xmlString); - Arabica::DOM::Document<std::string> toDocument(); - std::string toXMLString() { - std::stringstream ss; - ss << toDocument(); - return ss.str(); - } - - std::map<std::string, Data> getCompound() { - return compound; - } - void setCompound(const std::map<std::string, Data>& compound) { - this->compound = compound; - } - - std::list<Data> getArray() { - return array; - } - void setArray(const std::list<Data>& array) { - this->array = array; - } - - std::string getAtom() { - return atom; - } - void setAtom(const std::string& atom) { - this->atom = atom; - } - - Type getType() { - return type; - } - void setType(const Type type) { - this->type = type; - } - - -#ifdef SWIGIMPORTED -protected: -#endif - - Arabica::DOM::Node<std::string> node; - std::map<std::string, Data> compound; - std::list<Data> array; - std::string atom; - boost::shared_ptr<Blob> binary; - Type type; - -protected: - Arabica::DOM::Document<std::string> toNode(const Arabica::DOM::Document<std::string>& factory, const Data& data); - friend USCXML_API std::ostream& operator<< (std::ostream& os, const Data& data); -}; - -class USCXML_API Event { -public: - enum Type { - INTERNAL = 1, - EXTERNAL = 2, - PLATFORM = 3 - }; - - Event() : eventType(INTERNAL), hideSendId(false) {} - Event(const std::string& name, Type type = INTERNAL) : name(name), eventType(type), hideSendId(false) {} - Event(const Arabica::DOM::Node<std::string>& xmlString) : eventType(INTERNAL), hideSendId(false) {}; - bool operator< (const Event& other) const { - return this < &other; - } - - bool operator==(const Event& other) const { - return (this->name == other.name && - this->sendid == other.sendid && - this->invokeid == other.invokeid && - this->data == other.data); - } - bool operator!=(const Event& other) const { - return !(*this == other); - } - - std::string getName() { - return name; - } - void setName(const std::string& name) { - this->name = name; - } - - Type getEventType() { - return eventType; - } - void setEventType(const Type type) { - this->eventType = type; - } - - std::string getOrigin() { - return origin; - } - void setOrigin(const std::string& origin) { - this->origin = origin; - } - - std::string getOriginType() { - return origintype; - } - void setOriginType(const std::string& originType) { - this->origintype = originType; - } - - Arabica::DOM::Node<std::string> getDOM() { - return dom; - } - void setDOM(const Arabica::DOM::Node<std::string>& dom) { - this->dom = dom; - } - -// Arabica::DOM::Node<std::string> getFirstDOMElement() const; -// Arabica::DOM::Document<std::string> getStrippedDOM() const; -// -// static Arabica::DOM::Node<std::string> getFirstDOMElement(const Arabica::DOM::Document<std::string> dom); -// static Arabica::DOM::Document<std::string> getStrippedDOM(const Arabica::DOM::Document<std::string> dom); - - std::string getRaw() { - return raw; - } - void setRaw(const std::string& raw) { - this->raw = raw; - } - - std::string getContent() { - return content; - } - void setContent(const std::string& content) { - this->content = content; - } - - std::string getXML() { - return xml; - } - void setXML(const std::string& xml) { - this->xml = xml; - } - - std::string getSendId() { - return sendid; - } - void setSendId(const std::string& sendId) { - this->sendid = sendId; - } - - std::string getInvokeId() { - return invokeid; - } - void setInvokeId(const std::string& invokeId) { - this->invokeid = invokeId; - } - - Data getData() { - return data; - } - void setData(const Data& data) { - this->data = data; - } - - void initContent(const std::string& content); - - static Event fromXML(const std::string& xmlString); - Arabica::DOM::Document<std::string> toDocument(); - std::string toXMLString() { - std::stringstream ss; - ss << toDocument(); - return ss.str(); - } - - std::map<std::string, Data>& getNameList() { - return namelist; - } - std::multimap<std::string, Data>& getParams() { - return params; - } - - typedef std::multimap<std::string, Data> params_t; - typedef std::map<std::string, Data> namelist_t; - - static bool getParam(params_t params, const std::string& name, Data& target) { - if (params.find(name) != params.end()) { - target = params.find(name)->second; - return true; - } - return false; - } - - static bool getParam(params_t params, const std::string& name, std::list<Data>& target) { - if (params.find(name) != params.end()) { - std::pair<params_t::iterator, params_t::iterator> rangeIter = params.equal_range(name); - while(rangeIter.first != rangeIter.second) { - target.push_back(rangeIter.first->second); - rangeIter.first++; - } - return true; - } - return false; - } - - template <typename T> static bool getParam(params_t params, const std::string& name, T& target) { - if (params.find(name) != params.end()) { - target = boost::lexical_cast<T>(params.find(name)->second.atom); - return true; - } - return false; - } - - static bool getParam(params_t params, const std::string& name, bool& target) { - if (params.find(name) != params.end()) { - target = true; - if (iequals(params.find(name)->second.atom, "false")) { - target = false; - } else if(iequals(params.find(name)->second.atom, "off")) { - target = false; - } else if(iequals(params.find(name)->second.atom, "no")) { - target = false; - } else if(iequals(params.find(name)->second.atom, "0")) { - target = false; - } - return true; - } - return false; - } - - template <typename T> static bool getParam(params_t params, const std::string& name, std::list<T>& target) { - if (params.find(name) != params.end()) { - std::pair<params_t::iterator, params_t::iterator> rangeIter = params.equal_range(name); - while(rangeIter.first != rangeIter.second) { - target.push_back(boost::lexical_cast<T>(rangeIter.first->second.atom)); - rangeIter.first++; - } - return true; - } - return false; - } - - -#ifdef SWIGIMPORTED -protected: -#endif - - std::string raw; - std::string xml; - std::string name; - Type eventType; - std::string origin; - std::string origintype; - Arabica::DOM::Node<std::string> dom; - std::string sendid; - bool hideSendId; - std::string invokeid; - Data data; - std::string content; - std::map<std::string, Data> namelist; - std::multimap<std::string, Data> params; - - friend USCXML_API std::ostream& operator<< (std::ostream& os, const Event& event); -}; - -class USCXML_API InvokeRequest : public Event { -public: - InvokeRequest(Event event) : Event(event) {} - InvokeRequest() {} - - std::string getType() { - return type; - } - void setType(const std::string& type) { - this->type = type; - } - - std::string getSource() { - return src; - } - void setSource(const std::string& src) { - this->src = src; - } - - bool isAutoForwarded() { - return autoForward; - } - void setAutoForwarded(bool autoForward) { - this->autoForward = autoForward; - } - - static InvokeRequest fromXML(const std::string& xmlString); - Arabica::DOM::Document<std::string> toDocument(); - std::string toXMLString() { - std::stringstream ss; - ss << toDocument(); - return ss.str(); - } - -#ifdef SWIGIMPORTED -protected: -#endif - std::string type; - std::string src; - bool autoForward; - - friend USCXML_API std::ostream& operator<< (std::ostream& os, const InvokeRequest& sendReq); - -}; - -class USCXML_API SendRequest : public Event { -public: - SendRequest() {} - SendRequest(Event event) : Event(event) {} - - std::string getTarget() { - return target; - } - void setTarget(const std::string& target) { - this->target = target; - } - - std::string getType() { - return type; - } - void setType(const std::string& type) { - this->type = type; - } - - uint32_t getDelayMs() { - return delayMs; - } - void setDelayMs(uint32_t delayMs) { - this->delayMs = delayMs; - } - - static SendRequest fromXML(const std::string& xmlString); - Arabica::DOM::Document<std::string> toDocument(); - std::string toXMLString() { - std::stringstream ss; - ss << toDocument(); - // std::cout << ss.str() << std::endl; - return ss.str(); - } - -#ifdef SWIGIMPORTED -protected: -#endif - std::string target; - std::string type; - uint32_t delayMs; - - friend USCXML_API std::ostream& operator<< (std::ostream& os, const SendRequest& sendReq); - -}; - -USCXML_API std::ostream& operator<< (std::ostream& os, const InvokeRequest& invokeReq); -USCXML_API std::ostream& operator<< (std::ostream& os, const SendRequest& sendReq); -USCXML_API std::ostream& operator<< (std::ostream& os, const Event& event); -USCXML_API std::ostream& operator<< (std::ostream& os, const Data& data); - -} +#include "uscxml/messages/Blob.h" +#include "uscxml/messages/Data.h" +#include "uscxml/messages/Event.h" +#include "uscxml/messages/SendRequest.h" +#include "uscxml/messages/InvokeRequest.h" #endif /* end of include guard: EVENT_H_XZAQ4HR */ diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp index 1ba8404..aaf4cde 100644 --- a/src/uscxml/URL.cpp +++ b/src/uscxml/URL.cpp @@ -21,6 +21,8 @@ #include "URL.h" #include "UUID.h" +#include <sys/stat.h> + #include "uscxml/config.h" #include <fstream> #include <boost/lexical_cast.hpp> @@ -39,6 +41,8 @@ #include <pwd.h> #endif +#include "uscxml/messages/Event.h" + #include <cstdlib> // mkstemp #ifdef HAS_UNISTD_H #include <unistd.h> // mkstemp legacy diff --git a/src/uscxml/URL.h b/src/uscxml/URL.h index fd89503..01f3e1b 100644 --- a/src/uscxml/URL.h +++ b/src/uscxml/URL.h @@ -23,14 +23,13 @@ #include <curl/curl.h> #include <string> #include <iostream> -#include <sstream> #include <map> #include <vector> #include <set> -#include "Message.h" + +#include "uscxml/messages/Data.h" #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> -#include <sys/stat.h> #include "uscxml/concurrency/tinythread.h" diff --git a/src/uscxml/UUID.cpp b/src/uscxml/UUID.cpp index 68f0d76..8647739 100644 --- a/src/uscxml/UUID.cpp +++ b/src/uscxml/UUID.cpp @@ -19,6 +19,7 @@ #include "UUID.h" #include <sstream> +#include <boost/uuid/uuid_io.hpp> namespace uscxml { boost::uuids::random_generator UUID::uuidGen; diff --git a/src/uscxml/UUID.h b/src/uscxml/UUID.h index c4ccaee..af129e7 100644 --- a/src/uscxml/UUID.h +++ b/src/uscxml/UUID.h @@ -21,10 +21,8 @@ #define UUID_H_8X65R2EI #include "uscxml/Common.h" -#include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid_generators.hpp> -#include <boost/uuid/uuid_io.hpp> -#include <ostream> +#include <string> namespace uscxml { diff --git a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp index 46c12e4..642c4a0 100644 --- a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp +++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp @@ -17,12 +17,13 @@ * @endcond */ -#include "uscxml/Message.h" #include "DelayedEventQueue.h" +#include "uscxml/messages/Event.h" + #include <glog/logging.h> -#include <assert.h> + #include <event2/event.h> -#include <sstream> +#include "event2/thread.h" namespace uscxml { diff --git a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h index 0059bb5..2248c47 100644 --- a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h +++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h @@ -22,15 +22,15 @@ #include "uscxml/concurrency/tinythread.h" -#include <event2/thread.h> -#include <event2/http.h> + +#include "uscxml/Common.h" +#include "event2/util.h" // for evutil_socket_t #include <event2/event.h> #include <inttypes.h> #include <map> #include <string> -#include <iostream> namespace uscxml { diff --git a/src/uscxml/concurrency/tinythread.h b/src/uscxml/concurrency/tinythread.h index 867f036..cf313d5 100644 --- a/src/uscxml/concurrency/tinythread.h +++ b/src/uscxml/concurrency/tinythread.h @@ -25,6 +25,7 @@ freely, subject to the following restrictions: #define _TINYTHREAD_H_ #include "uscxml/Common.h" +#include <ostream> /// @file /// @mainpage TinyThread++ API Reference diff --git a/src/uscxml/debug/Breakpoint.h b/src/uscxml/debug/Breakpoint.h index 5cf92a1..71308aa 100644 --- a/src/uscxml/debug/Breakpoint.h +++ b/src/uscxml/debug/Breakpoint.h @@ -20,8 +20,11 @@ #ifndef BREAKPOINT_H_VR7K7T1X #define BREAKPOINT_H_VR7K7T1X -#include "uscxml/Message.h" +#include <string> // for string #include "uscxml/Interpreter.h" +#include "DOM/Element.hpp" // for Element +#include "uscxml/Common.h" // for USCXML_API +#include "uscxml/messages/Data.h" // for Data namespace uscxml { diff --git a/src/uscxml/debug/Debugger.cpp b/src/uscxml/debug/Debugger.cpp index b74b2a9..cb4d522 100644 --- a/src/uscxml/debug/Debugger.cpp +++ b/src/uscxml/debug/Debugger.cpp @@ -19,6 +19,7 @@ #include "uscxml/debug/Debugger.h" #include "uscxml/DOMUtils.h" +#include "uscxml/debug/DebugSession.h" namespace uscxml { diff --git a/src/uscxml/debug/Debugger.h b/src/uscxml/debug/Debugger.h index 9adbae6..03846e5 100644 --- a/src/uscxml/debug/Debugger.h +++ b/src/uscxml/debug/Debugger.h @@ -20,13 +20,15 @@ #ifndef DEBUGGERMONITOR_H_Z050WPFH #define DEBUGGERMONITOR_H_Z050WPFH -#include "uscxml/Message.h" +#include "uscxml/messages/Data.h" // for Data +#include "uscxml/messages/Event.h" // for Event #include "uscxml/Interpreter.h" #include "uscxml/debug/Breakpoint.h" -#include "uscxml/debug/DebugSession.h" namespace uscxml { +class DebugSession; + class USCXML_API Debugger : public InterpreterMonitor { public: Debugger() { diff --git a/src/uscxml/debug/DebuggerServlet.cpp b/src/uscxml/debug/DebuggerServlet.cpp index d7528f0..49306a2 100644 --- a/src/uscxml/debug/DebuggerServlet.cpp +++ b/src/uscxml/debug/DebuggerServlet.cpp @@ -18,6 +18,7 @@ */ #include "uscxml/debug/DebuggerServlet.h" +#include "uscxml/debug/DebugSession.h" #include "uscxml/UUID.h" #include <boost/algorithm/string.hpp> diff --git a/src/uscxml/debug/DebuggerServlet.h b/src/uscxml/debug/DebuggerServlet.h index ce6f082..8abe741 100644 --- a/src/uscxml/debug/DebuggerServlet.h +++ b/src/uscxml/debug/DebuggerServlet.h @@ -21,11 +21,9 @@ #define DEBUGGERSERVLET_H_ATUMDA3G #include "uscxml/Common.h" -#include "getopt.h" #include <glog/logging.h> #include "uscxml/server/HTTPServer.h" -#include "uscxml/Interpreter.h" #include "uscxml/debug/Debugger.h" #include "uscxml/concurrency/tinythread.h" diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index e2ab620..dd23a87 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -18,6 +18,7 @@ */ #include "InterpreterDraft6.h" +#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h" #include <glog/logging.h> #include "uscxml/UUID.h" @@ -37,10 +38,9 @@ InterpreterState InterpreterDraft6::interpret() { while(true) { state = step(-1); - switch (state & InterpreterState::USCXML_INTERPRETER_MASK) { - case uscxml::InterpreterState::USCXML_FAULTED: - case uscxml::InterpreterState::USCXML_FINISHED: - case uscxml::InterpreterState::USCXML_DESTROYED: + switch (state) { + case uscxml::USCXML_FINISHED: + case uscxml::USCXML_DESTROYED: // return as we finished return state; default: @@ -61,7 +61,7 @@ InterpreterState InterpreterDraft6::interpret() { NodeSet<std::string> InterpreterDraft6::getDocumentInitialTransitions() { NodeSet<std::string> initialTransitions; - if (_userDefinedStartConfiguration.size() > 0) { + if (_startConfiguration.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); @@ -72,8 +72,8 @@ NodeSet<std::string> InterpreterDraft6::getDocumentInitialTransitions() { std::string histId = ATTR(initHistory, "id"); NodeSet<std::string> histStates; - for (int i = 0; i < _userDefinedStartConfiguration.size(); i++) { - histStates.push_back(getState(_userDefinedStartConfiguration[i])); + for (std::list<std::string>::const_iterator stateIter = _startConfiguration.begin(); stateIter != _startConfiguration.end(); stateIter++) { + histStates.push_back(getState(*stateIter)); } _historyValue[histId] = histStates; @@ -119,9 +119,7 @@ InterpreterState InterpreterDraft6::step(int waitForMS = 0) { try { tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); - if (_state & InterpreterState::USCXML_FINISHED || - _state & InterpreterState::USCXML_FAULTED || - _state & InterpreterState::USCXML_DESTROYED) { + if (_state == USCXML_FINISHED || _state == USCXML_DESTROYED) { return _state; } @@ -148,7 +146,7 @@ InterpreterState InterpreterDraft6::step(int waitForMS = 0) { enabledTransitions.to_document_order(); microstep(enabledTransitions); - setInterpreterState(InterpreterState::USCXML_MICROSTEPPED); + setInterpreterState(USCXML_MICROSTEPPED); return _state; } @@ -174,19 +172,19 @@ InterpreterState InterpreterDraft6::step(int waitForMS = 0) { } // test 319 - even if we do not enable transitions, consider it a microstep - setInterpreterState(InterpreterState::USCXML_MICROSTEPPED); + setInterpreterState(USCXML_MICROSTEPPED); return _state; } else { _stable = true; } // even if we did nothing - count as microstep - setInterpreterState(InterpreterState::USCXML_MICROSTEPPED); + setInterpreterState(USCXML_MICROSTEPPED); if (_topLevelFinalReached) goto EXIT_INTERPRETER; - setInterpreterState(InterpreterState::USCXML_MACROSTEPPED); + setInterpreterState(USCXML_MACROSTEPPED); USCXML_MONITOR_CALLBACK(onStableConfiguration) // when we reach a stable configuration, invoke @@ -201,7 +199,7 @@ InterpreterState InterpreterDraft6::step(int waitForMS = 0) { _statesToInvoke = NodeSet<std::string>(); if (_externalQueue.isEmpty()) { - setInterpreterState(InterpreterState::USCXML_IDLE); + setInterpreterState(USCXML_IDLE); if (waitForMS < 0) { // wait blockingly for an event forever @@ -224,7 +222,7 @@ InterpreterState InterpreterDraft6::step(int waitForMS = 0) { return _state; } - setInterpreterState(InterpreterState::USCXML_MACROSTEPPED); + setInterpreterState(USCXML_MACROSTEPPED); } _currEvent = _externalQueue.pop(); @@ -281,15 +279,11 @@ EXIT_INTERPRETER: if(_dataModel) _dataModel = DataModel(); - setInterpreterState(InterpreterState::USCXML_FINISHED); + setInterpreterState(USCXML_FINISHED); return _state; - } catch (Event e) { - setInterpreterState(InterpreterState::USCXML_FAULTED, e); - return _state; - } catch (boost::bad_weak_ptr e) { LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl; - setInterpreterState(InterpreterState::USCXML_DESTROYED); + setInterpreterState(USCXML_DESTROYED); return _state; } diff --git a/src/uscxml/interpreter/InterpreterRC.cpp b/src/uscxml/interpreter/InterpreterRC.cpp index 7f8c91c..53feae8 100644 --- a/src/uscxml/interpreter/InterpreterRC.cpp +++ b/src/uscxml/interpreter/InterpreterRC.cpp @@ -19,6 +19,9 @@ #include "InterpreterRC.h" +#include "uscxml/Factory.h" +#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h" + #include <glog/logging.h> #include "uscxml/UUID.h" #include "uscxml/DOMUtils.h" @@ -114,7 +117,7 @@ InterpreterState InterpreterRC::interpret() { NodeSet<std::string> initialTransitions; - if (_userDefinedStartConfiguration.size() > 0) { + if (_startConfiguration.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); @@ -125,8 +128,8 @@ InterpreterState InterpreterRC::interpret() { std::string histId = ATTR(initHistory, "id"); NodeSet<std::string> histStates; - for (int i = 0; i < _userDefinedStartConfiguration.size(); i++) { - histStates.push_back(getState(_userDefinedStartConfiguration[i])); + for (std::list<std::string>::const_iterator stateIter = _startConfiguration.begin(); stateIter != _startConfiguration.end(); stateIter++) { + histStates.push_back(getState(*stateIter)); } _historyValue[histId] = histStates; diff --git a/src/uscxml/messages/Blob.cpp b/src/uscxml/messages/Blob.cpp new file mode 100644 index 0000000..1d07e6a --- /dev/null +++ b/src/uscxml/messages/Blob.cpp @@ -0,0 +1,61 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#include "uscxml/messages/Blob.h" + +#include "uscxml/util/MD5.hpp" +#include "uscxml/util/Base64.hpp" + +namespace uscxml { + +Blob::~Blob() { + free(data); +} + +std::string Blob::md5() { + return uscxml::md5(data, size); +} + +Blob* Blob::fromBase64(const std::string base64) { + std::string decoded = base64Decode(base64); + return new Blob((void*)decoded.c_str(), decoded.length(), mimeType); +} + +Blob::Blob(size_t _size) { + data = (char*)malloc(_size); + memset(data, 0, _size); + size = _size; +} + +Blob::Blob(void* _data, size_t _size, const std::string& _mimeType, bool adopt) { + if (adopt) { + data = (char*)_data; + } else { + data = (char*)malloc(_size); + memcpy(data, _data, _size); + } + mimeType = _mimeType; + size = _size; +} + +std::string Blob::base64() { + return base64Encode((char* const)data, size); +} + +}
\ No newline at end of file diff --git a/src/uscxml/messages/Blob.h b/src/uscxml/messages/Blob.h new file mode 100644 index 0000000..b4fcd46 --- /dev/null +++ b/src/uscxml/messages/Blob.h @@ -0,0 +1,47 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#ifndef BLOB_H_E1B6D2C3 +#define BLOB_H_E1B6D2C3 + +#include <string> + +#include "uscxml/Common.h" + +namespace uscxml { + +class USCXML_API Blob { +public: + ~Blob(); + Blob(size_t size); + Blob(void* data, size_t size, const std::string& mimeType, bool adopt = false); + char* data; + size_t size; + std::string mimeType; + + std::string base64(); + + std::string md5(); + Blob* fromBase64(const std::string base64); + +}; + +} + +#endif /* end of include guard: BLOB_H_E1B6D2C3 */ diff --git a/src/uscxml/messages/Data.cpp b/src/uscxml/messages/Data.cpp new file mode 100644 index 0000000..6706253 --- /dev/null +++ b/src/uscxml/messages/Data.cpp @@ -0,0 +1,387 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#include "uscxml/messages/Data.h" +#include "uscxml/messages/Blob.h" + +#include <boost/algorithm/string.hpp> + +#include "uscxml/DOMUtils.h" +#include "glog/logging.h" + +#ifdef HAS_STRING_H +#include <string.h> +#endif + +extern "C" { +#include "jsmn.h" // minimal json parser +} + +namespace uscxml { + +Data::Data(const char* _data, size_t _size, const std::string& mimeType, bool adopt) { + binary = boost::shared_ptr<Blob>(new Blob((void*)_data, _size, mimeType, adopt)); +} + +void Data::merge(const Data& other) { + if (other.compound.size() > 0) { + if (compound.size() == 0) { + compound = other.compound; + } else { + std::map<std::string, Data>::const_iterator compIter = other.compound.begin(); + while (compIter != other.compound.end()) { + if (compound.find(compIter->first) != compound.end()) { + // we do have the same key, merge + compound[compIter->first].merge(compIter->second); + } else { + compound[compIter->first] = compIter->second; + } + compIter++; + } + } + } + if (other.array.size() > 0) { + if (array.size() == 0) { + array = other.array; + } else { + std::list<Data>::const_iterator arrIter = other.array.begin(); + while(arrIter != other.array.end()) { + array.push_back(*arrIter); + arrIter++; + } + } + } + if (other.atom.size() > 0) { + atom = other.atom; + type = other.type; + } +} + +Data::Data(const Arabica::DOM::Node<std::string>& dom) { + // we may need to convert some keys to arrays if we have the same name as an element + std::map<std::string, std::list<Data> > arrays; +// Interpreter::dump(dom); + + if (dom.hasAttributes()) { + Arabica::DOM::NamedNodeMap<std::string> attributes = dom.getAttributes(); + for (int i = 0; i < attributes.getLength(); i++) { + Arabica::DOM::Node<std::string> attribute = attributes.item(i); +// Interpreter::dump(attribute); + + assert(attribute.getNodeType() == Arabica::DOM::Node_base::ATTRIBUTE_NODE); + std::string key = attribute.getLocalName(); + std::string value = attribute.getNodeValue(); + compound[key] = Data(value, VERBATIM); + } + } + + if (dom.hasChildNodes()) { + Arabica::DOM::NodeList<std::string> children = dom.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Arabica::DOM::Node<std::string> child = children.item(i); +// Interpreter::dump(child); + std::string key; + switch (child.getNodeType()) { + case Arabica::DOM::Node_base::ELEMENT_NODE: + key = TAGNAME(child); + break; + case Arabica::DOM::Node_base::ATTRIBUTE_NODE: + key = ((Arabica::DOM::Attr<std::string>)child).getName(); + break; + case Arabica::DOM::Node_base::TEXT_NODE: + default: + break; + } + if (key.length() == 0) + continue; + + if (compound.find(key) != compound.end()) { + // we already have such a key .. make it an array after we processed all children + arrays[key].push_back(Data(child)); + } else { + compound[key] = Data(child); + } + } + } else { + atom = dom.getNodeValue(); + type = VERBATIM; + } + + std::map<std::string, std::list<Data> >::iterator arrayIter = arrays.begin(); + while(arrayIter != arrays.end()) { + assert(compound.find(arrayIter->first) != compound.end()); + Data arrayData; + arrays[arrayIter->first].push_front(compound[arrayIter->first]); + arrayData.array = arrays[arrayIter->first]; + compound[arrayIter->first] = arrayData; + } +} + +Arabica::DOM::Document<std::string> Data::toDocument() { + Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); + Arabica::DOM::Document<std::string> document = domFactory.createDocument("http://www.w3.org/2005/07/scxml", "message", 0); + Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement(); + scxmlMsg.setPrefix("scxml"); + scxmlMsg.setAttribute("version", "1.0"); + + if (compound.size() > 0 || array.size() > 0) { + Arabica::DOM::Element<std::string> payloadElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "payload"); + payloadElem.setPrefix("scxml"); + + scxmlMsg.appendChild(payloadElem); + + // we do not support nested attibutes + if (compound.size() > 0) { + std::map<std::string, Data>::iterator compoundIter = compound.begin(); + while(compoundIter != compound.end()) { + if (compoundIter->second.atom.size() > 0) { + Arabica::DOM::Element<std::string> propertyElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "property"); + propertyElem.setPrefix("scxml"); + + propertyElem.setAttribute("name", compoundIter->first); + Arabica::DOM::Text<std::string> textElem = document.createTextNode(compoundIter->second.atom); + propertyElem.appendChild(textElem); + payloadElem.appendChild(propertyElem); + } + compoundIter++; + } + } + } + return document; +} + +Data Data::fromXML(const std::string& xmlString) { + return Data(); +} + +Data Data::fromJSON(const std::string& jsonString) { + Data data; + + std::string trimmed = boost::trim_copy(jsonString); + + if (trimmed.length() == 0) + return data; + + if (trimmed.find_first_of("{[") != 0) + return data; + + jsmn_parser p; + + jsmntok_t* t = NULL; + + // we do not know the number of tokens beforehand, start with something sensible and increase + int rv; + int frac = 16; // length/token ratio + do { + jsmn_init(&p); + + frac /= 2; + int nrTokens = trimmed.size() / frac; + if (t != NULL) { + free(t); +// LOG(INFO) << "Increasing JSON length to token ratio to 1/" << frac; + } + t = (jsmntok_t*)malloc((nrTokens + 1) * sizeof(jsmntok_t)); + if (t == NULL) { + LOG(ERROR) << "Cannot parse JSON, ran out of memory!"; + return data; + } + memset(t, 0, (nrTokens + 1) * sizeof(jsmntok_t)); + + rv = jsmn_parse(&p, trimmed.c_str(), t, nrTokens); + } while (rv == JSMN_ERROR_NOMEM && frac > 1); + + if (rv != 0) { + switch (rv) { + case JSMN_ERROR_NOMEM: + LOG(ERROR) << "Cannot parse JSON, not enough tokens were provided!"; + break; + case JSMN_ERROR_INVAL: + LOG(ERROR) << "Cannot parse JSON, invalid character inside JSON string!"; + break; + case JSMN_ERROR_PART: + LOG(ERROR) << "Cannot parse JSON, the string is not a full JSON packet, more bytes expected!"; + break; + default: + break; + } + free(t); + return data; + } + + if (t[0].end != trimmed.length()) + return data; + +// jsmntok_t* token = t; +// while(token->end) { +// std::cout << trimmed.substr(token->start, token->end - token->start) << std::endl; +// std::cout << "------" << std::endl; +// token++; +// } + + std::list<Data*> dataStack; + std::list<jsmntok_t> tokenStack; + dataStack.push_back(&data); + + size_t currTok = 0; + do { + // used for debugging +// jsmntok_t t2 = t[currTok]; +// std::string value = trimmed.substr(t[currTok].start, t[currTok].end - t[currTok].start); + switch (t[currTok].type) { + case JSMN_STRING: + dataStack.back()->type = Data::VERBATIM; + case JSMN_PRIMITIVE: { + std::string value = trimmed.substr(t[currTok].start, t[currTok].end - t[currTok].start); + if (dataStack.back()->type == Data::VERBATIM) { + boost::replace_all(value, "\\\"", "\""); + boost::replace_all(value, "\\n", "\n"); + } + dataStack.back()->atom = value; + dataStack.pop_back(); + currTok++; + break; + } + case JSMN_OBJECT: + case JSMN_ARRAY: + tokenStack.push_back(t[currTok]); + currTok++; + break; + } + // used for debugging +// t2 = t[currTok]; +// value = trimmed.substr(t[currTok].start, t[currTok].end - t[currTok].start); + + // there are no more tokens + if (t[currTok].end == 0 || tokenStack.empty()) + break; + + // next token starts after current one => pop + while (t[currTok].end > tokenStack.back().end) { + tokenStack.pop_back(); + dataStack.pop_back(); + } + + if (tokenStack.back().type == JSMN_OBJECT && (t[currTok].type == JSMN_PRIMITIVE || t[currTok].type == JSMN_STRING)) { + // grab key and push new data + std::string value = trimmed.substr(t[currTok].start, t[currTok].end - t[currTok].start); + dataStack.push_back(&(dataStack.back()->compound[value])); + currTok++; + } + if (tokenStack.back().type == JSMN_ARRAY) { + // push new index + dataStack.back()->array.push_back(Data()); + dataStack.push_back(&(dataStack.back()->array.back())); + } + + } while (true); + + free(t); + return data; +} + +std::ostream& operator<< (std::ostream& os, const Data& data) { + os << Data::toJSON(data); + return os; +} + +std::string Data::toJSON(const Data& data) { + std::stringstream os; + std::string indent; + for (int i = 0; i < _dataIndentation; i++) { + indent += " "; + } + if (false) { + } else if (data.compound.size() > 0) { + int longestKey = 0; + std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin(); + while(compoundIter != data.compound.end()) { + if (compoundIter->first.size() > longestKey) + longestKey = compoundIter->first.size(); + compoundIter++; + } + std::string keyPadding; + for (unsigned int i = 0; i < longestKey; i++) + keyPadding += " "; + + std::string seperator; + os << std::endl << indent << "{"; + compoundIter = data.compound.begin(); + while(compoundIter != data.compound.end()) { + os << seperator << std::endl << indent << " \"" << compoundIter->first << "\": " << keyPadding.substr(0, longestKey - compoundIter->first.size()); + _dataIndentation += 1; + os << compoundIter->second; + _dataIndentation -= 1; + seperator = ", "; + compoundIter++; + } + os << std::endl << indent << "}"; + } else if (data.array.size() > 0) { + + std::string seperator; + os << std::endl << indent << "["; + std::list<Data>::const_iterator arrayIter = data.array.begin(); + while(arrayIter != data.array.end()) { + _dataIndentation += 1; + os << seperator << *arrayIter; + _dataIndentation -= 1; + seperator = ", "; + arrayIter++; + } + os << "]"; + } else if (data.atom.size() > 0) { + // empty string is handled below + if (data.type == Data::VERBATIM) { + os << "\""; + for (int i = 0; i < data.atom.size(); i++) { + // escape string + if (false) { + } else if (data.atom[i] == '"') { + os << "\\\""; + } else if (data.atom[i] == '\n') { + os << "\\n"; + } else if (data.atom[i] == '\t') { + os << "\\t"; + } else { + os << data.atom[i]; + } + } + os << "\""; + } else { + os << data.atom; + } + } else if (data.node) { + std::ostringstream xmlSerSS; + xmlSerSS << data.node; + std::string xmlSer = xmlSerSS.str(); + boost::replace_all(xmlSer, "\"", "\\\""); + boost::replace_all(xmlSer, "\n", "\\n"); + boost::replace_all(xmlSer, "\t", "\\t"); + os << "\"" << xmlSer << "\""; + } else { + if (data.type == Data::VERBATIM) { + os << "\"\""; // empty string + } else { + os << "null"; + } + } + return os.str(); +} + +}
\ No newline at end of file diff --git a/src/uscxml/messages/Data.h b/src/uscxml/messages/Data.h new file mode 100644 index 0000000..bf13409 --- /dev/null +++ b/src/uscxml/messages/Data.h @@ -0,0 +1,243 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#ifndef DATA_H_09E4D8E5 +#define DATA_H_09E4D8E5 + +#include <list> +#include <map> + +#include <boost/shared_ptr.hpp> + +#include "uscxml/Common.h" +#include "uscxml/Convenience.h" +#include <DOM/Document.hpp> + +namespace uscxml { + +class Blob; + +static int _dataIndentation = 1; + +class USCXML_API Data { +public: + enum Type { + VERBATIM, + INTERPRETED, + }; + + Data() : type(INTERPRETED) {} + + // TODO: default INTERPRETED is unfortunate + Data(const std::string& atom_, Type type_ = INTERPRETED) : atom(atom_), type(type_) {} + Data(const char* data, size_t size, const std::string& mimeType, bool adopt = false); + + // convenience constructors + Data(short atom_) : atom(toStr(atom_)), type(INTERPRETED) {} + Data(int atom_) : atom(toStr(atom_)), type(INTERPRETED) {} + Data(unsigned int atom_) : atom(toStr(atom_)), type(INTERPRETED) {} + Data(long atom_) : atom(toStr(atom_)), type(INTERPRETED) {} + Data(unsigned long atom_) : atom(toStr(atom_)), type(INTERPRETED) {} + Data(float atom_) : atom(toStr(atom_)), type(INTERPRETED) {} + Data(double atom_) : atom(toStr(atom_)), type(INTERPRETED) {} + Data(bool atom_) : type(INTERPRETED) { + if (atom_) { + atom = "true"; + } else { + atom = "false"; + } + } + + template <typename T> Data(T value, Type type_) : atom(toStr(value)), type(type_) {} + +#if 0 + // constructor for arbitrary types, skip if type is subclass though (C++11) + // we will have to drop this constructor as it interferes with operator Data() and entails C++11 + template <typename T> + Data(T value, typename std::enable_if<! std::is_base_of<Data, T>::value>::type* = nullptr) + : atom(toStr(value)), type(INTERPRETED) {} +#endif + + + explicit Data(const Arabica::DOM::Node<std::string>& dom); + virtual ~Data() {} + + bool empty() const { + bool hasContent = (atom.length() > 0 || !compound.empty() || !array.empty() || binary || node); + return !hasContent; + } + + bool operator<(const Data& other) const { + std::string thisJSON = Data::toJSON(*this); + std::string otherJSON = Data::toJSON(other); + return (thisJSON < otherJSON); + } + + void merge(const Data& other); + + bool hasKey(const std::string& key) const { + return (!compound.empty() && compound.find(key) != compound.end()); + } + + Data& operator[](const std::string& key) { + return operator[](key.c_str()); + } + + const Data& operator[](const std::string& key) const { + return operator[](key.c_str()); + } + + Data& operator[](const char* key) { + return compound[key]; + } + + const Data& operator[](const char* key) const { + return compound.at(key); + } + + Data& operator[](const size_t index) { + while(array.size() < index) { + array.push_back(Data("", Data::VERBATIM)); + } + std::list<Data>::iterator arrayIter = array.begin(); + for (int i = 0; i < index; i++, arrayIter++) {} + return *arrayIter; + } + + const Data at(const std::string& key) const { + return at(key.c_str()); + } + + const Data at(const char* key) const { + if (hasKey(key)) + return compound.at(key); + Data data; + return data; + } + + const Data item(const size_t index) const { + if (array.size() < index) { + std::list<Data>::const_iterator arrayIter; + for (int i = 0; i < index; i++, arrayIter++) {} + return *arrayIter; + } + Data data; + return data; + } + + bool operator==(const Data &other) const { + if (other.atom.size() != atom.size()) + return false; + if (other.type != type) + return false; + if (other.binary != binary) + return false; + if (other.array.size() != array.size()) + return false; + if (other.compound.size() != compound.size()) + return false; + + if (other.atom != atom) + return false; + if (other.array != array) + return false; + if (other.compound != compound) + return false; + if (other.node != node) + return false; + + return true; + } + + bool operator!=(const Data &other) const { + return !(*this == other); + } + + operator std::string() const { + return atom; + } + + operator std::map<std::string, Data>() { + return compound; + } + + operator std::list<Data>() { + return array; + } + + static Data fromJSON(const std::string& jsonString); + static std::string toJSON(const Data& data); + static Data fromXML(const std::string& xmlString); + Arabica::DOM::Document<std::string> toDocument(); + std::string toXMLString() { + std::stringstream ss; + ss << toDocument(); + return ss.str(); + } + + std::map<std::string, Data> getCompound() { + return compound; + } + void setCompound(const std::map<std::string, Data>& compound) { + this->compound = compound; + } + + std::list<Data> getArray() { + return array; + } + void setArray(const std::list<Data>& array) { + this->array = array; + } + + std::string getAtom() { + return atom; + } + void setAtom(const std::string& atom) { + this->atom = atom; + } + + Type getType() { + return type; + } + void setType(const Type type) { + this->type = type; + } + + +#ifdef SWIGIMPORTED +protected: +#endif + + Arabica::DOM::Node<std::string> node; + std::map<std::string, Data> compound; + std::list<Data> array; + std::string atom; + boost::shared_ptr<Blob> binary; + Type type; + +protected: + Arabica::DOM::Document<std::string> toNode(const Arabica::DOM::Document<std::string>& factory, const Data& data); + friend USCXML_API std::ostream& operator<< (std::ostream& os, const Data& data); +}; + +USCXML_API std::ostream& operator<< (std::ostream& os, const Data& data); + +} + +#endif /* end of include guard: DATA_H_09E4D8E5 */ diff --git a/src/uscxml/messages/Event.cpp b/src/uscxml/messages/Event.cpp new file mode 100644 index 0000000..a3e6a20 --- /dev/null +++ b/src/uscxml/messages/Event.cpp @@ -0,0 +1,187 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#include "uscxml/messages/Event.h" +#include "uscxml/DOMUtils.h" + +namespace uscxml { + +//Arabica::DOM::Node<std::string> Event::getFirstDOMElement() const { +// return getFirstDOMElement(dom); +//} +// +//Arabica::DOM::Document<std::string> Event::getStrippedDOM() const { +// return getStrippedDOM(dom); +//} + +//Arabica::DOM::Node<std::string> Event::getFirstDOMElement(const Arabica::DOM::Document<std::string> dom) { +// Arabica::DOM::Node<std::string> data = dom.getDocumentElement().getFirstChild(); +// while (data) { +// if (data.getNodeType() == Arabica::DOM::Node_base::TEXT_NODE) { +// std::string trimmed = boost::trim_copy(data.getNodeValue()); +// if (trimmed.length() == 0) { +// data = data.getNextSibling(); +// continue; +// } +// } +// break; +// } +// return data; +//} +// +//Arabica::DOM::Document<std::string> Event::getStrippedDOM(const Arabica::DOM::Document<std::string> dom) { +// Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); +// Arabica::DOM::Document<std::string> document = domFactory.createDocument("", "", 0); +// if (dom) { +// document.getDocumentElement().appendChild(document.importNode(getFirstDOMElement(dom), true)); +// } +// return document; +//} + +std::string Event::toXMLString() { + std::stringstream ss; + ss << toDocument(); + return ss.str(); +} + +Arabica::DOM::Document<std::string> Event::toDocument() { + Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); + Arabica::DOM::Document<std::string> document = data.toDocument(); + Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement(); + + + scxmlMsg.setAttribute("source", origin); + scxmlMsg.setAttribute("name", name); + + return document; +} + +void Event::initContent(const std::string& content) { + // try to parse as JSON + Data json = Data::fromJSON(content); + if (!json.empty()) { + data = json; + return; + } + + // try to parse as XML + Arabica::SAX2DOM::Parser<std::string> parser; + Arabica::SAX::CatchErrorHandler<std::string> errorHandler; + parser.setErrorHandler(errorHandler); + + std::istringstream is(content); + Arabica::SAX::InputSource<std::string> inputSource; + inputSource.setByteStream(is); + if (parser.parse(inputSource)) { + dom = parser.getDocument(); + return; + } + + this->content = content; +} + +Event Event::fromXML(const std::string& xmlString) { + Arabica::SAX2DOM::Parser<std::string> eventParser; + Arabica::SAX::CatchErrorHandler<std::string> errorHandler; + eventParser.setErrorHandler(errorHandler); + + std::istringstream is(xmlString); + Arabica::SAX::InputSource<std::string> inputSource; + inputSource.setByteStream(is); + + Event event; + if(eventParser.parse(inputSource) && eventParser.getDocument().hasChildNodes()) { + Arabica::DOM::Element<std::string> scxmlMsg = eventParser.getDocument().getDocumentElement(); + if (HAS_ATTR(scxmlMsg, "name")) + event.name = ATTR(scxmlMsg, "name"); + if (HAS_ATTR(scxmlMsg, "sendid")) + event.sendid = ATTR(scxmlMsg, "sendid"); + + Arabica::DOM::NodeList<std::string> payloads = scxmlMsg.getElementsByTagName("scxml:payload"); + if (payloads.getLength() > 0) { + Arabica::DOM::Node<std::string> payload = payloads.item(0); + if (payload.getNodeType() == Arabica::DOM::Node_base::ELEMENT_NODE) { + Arabica::DOM::Element<std::string> payloadElem = (Arabica::DOM::Element<std::string>)payload; + Arabica::DOM::NodeList<std::string> properties = payloadElem.getElementsByTagName("scxml:property"); + if (properties.getLength() > 0) { + for (int i = 0; i < properties.getLength(); i++) { + if (HAS_ATTR(properties.item(i), "name")) { + std::string key = ATTR(properties.item(i), "name"); + std::string value; + Arabica::DOM::NodeList<std::string> childs = properties.item(i).getChildNodes(); + for (int j = 0; j < childs.getLength(); j++) { + if (childs.item(j).getNodeType() == Arabica::DOM::Node_base::TEXT_NODE) { + value = childs.item(j).getNodeValue(); + break; + } + } + event.data.compound[key] = Data(value, Data::VERBATIM); + } + } + } + } + } + } + return event; +} + +std::ostream& operator<< (std::ostream& os, const Event& event) { + std::string indent; + for (int i = 0; i < _dataIndentation; i++) { + indent += " "; + } + + os << indent << (event.eventType == Event::EXTERNAL ? "External" : "Internal") << " Event " << (event.dom ? "with DOM attached" : "") << std::endl; + + if (event.name.size() > 0) + os << indent << " name: " << event.name << std::endl; + if (event.origin.size() > 0) + os << indent << " origin: " << event.origin << std::endl; + if (event.origintype.size() > 0) + os << indent << " origintype: " << event.origintype << std::endl; + if (event.params.size() > 0) { + std::multimap<std::string, Data>::const_iterator paramIter = event.params.begin(); + os << indent << " params:" << std::endl; + _dataIndentation++; + while(paramIter != event.params.end()) { + os << indent << " " << paramIter->first << ": "; + os << indent << paramIter->second << std::endl; + paramIter++; + } + _dataIndentation--; + } + if (event.namelist.size() > 0) { + std::map<std::string, Data>::const_iterator namelistIter = event.namelist.begin(); + os << indent << " namelist:" << std::endl; + _dataIndentation++; + while(namelistIter != event.namelist.end()) { + os << indent << " " << namelistIter->first << ": "; + os << indent << namelistIter->second << std::endl; + namelistIter++; + } + _dataIndentation--; + + } + _dataIndentation++; + os << indent << " data: " << event.data << std::endl; + _dataIndentation--; + return os; +} + +}
\ No newline at end of file diff --git a/src/uscxml/messages/Event.h b/src/uscxml/messages/Event.h new file mode 100644 index 0000000..1acfce7 --- /dev/null +++ b/src/uscxml/messages/Event.h @@ -0,0 +1,235 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#ifndef EVENT_H_6174D929 +#define EVENT_H_6174D929 + +#include "uscxml/messages/Data.h" + +namespace uscxml { + +class USCXML_API Event { +public: + enum Type { + INTERNAL = 1, + EXTERNAL = 2, + PLATFORM = 3 + }; + + Event() : eventType(INTERNAL), hideSendId(false) {} + Event(const std::string& name, Type type = INTERNAL) : name(name), eventType(type), hideSendId(false) {} + Event(const Arabica::DOM::Node<std::string>& xmlString) : eventType(INTERNAL), hideSendId(false) {}; + bool operator< (const Event& other) const { + return this < &other; + } + + bool operator==(const Event& other) const { + return (this->name == other.name && + this->sendid == other.sendid && + this->invokeid == other.invokeid && + this->data == other.data); + } + bool operator!=(const Event& other) const { + return !(*this == other); + } + + std::string getName() { + return name; + } + void setName(const std::string& name) { + this->name = name; + } + + Type getEventType() { + return eventType; + } + void setEventType(const Type type) { + this->eventType = type; + } + + std::string getOrigin() { + return origin; + } + void setOrigin(const std::string& origin) { + this->origin = origin; + } + + std::string getOriginType() { + return origintype; + } + void setOriginType(const std::string& originType) { + this->origintype = originType; + } + + Arabica::DOM::Node<std::string> getDOM() { + return dom; + } + void setDOM(const Arabica::DOM::Node<std::string>& dom) { + this->dom = dom; + } + +// Arabica::DOM::Node<std::string> getFirstDOMElement() const; +// Arabica::DOM::Document<std::string> getStrippedDOM() const; +// +// static Arabica::DOM::Node<std::string> getFirstDOMElement(const Arabica::DOM::Document<std::string> dom); +// static Arabica::DOM::Document<std::string> getStrippedDOM(const Arabica::DOM::Document<std::string> dom); + + std::string getRaw() { + return raw; + } + void setRaw(const std::string& raw) { + this->raw = raw; + } + + std::string getContent() { + return content; + } + void setContent(const std::string& content) { + this->content = content; + } + + std::string getXML() { + return xml; + } + void setXML(const std::string& xml) { + this->xml = xml; + } + + std::string getSendId() { + return sendid; + } + void setSendId(const std::string& sendId) { + this->sendid = sendId; + } + + std::string getInvokeId() { + return invokeid; + } + void setInvokeId(const std::string& invokeId) { + this->invokeid = invokeId; + } + + Data getData() { + return data; + } + void setData(const Data& data) { + this->data = data; + } + + void initContent(const std::string& content); + + static Event fromXML(const std::string& xmlString); + Arabica::DOM::Document<std::string> toDocument(); + std::string toXMLString(); + + std::map<std::string, Data>& getNameList() { + return namelist; + } + std::multimap<std::string, Data>& getParams() { + return params; + } + + typedef std::multimap<std::string, Data> params_t; + typedef std::map<std::string, Data> namelist_t; + + static bool getParam(params_t params, const std::string& name, Data& target) { + if (params.find(name) != params.end()) { + target = params.find(name)->second; + return true; + } + return false; + } + + static bool getParam(params_t params, const std::string& name, std::list<Data>& target) { + if (params.find(name) != params.end()) { + std::pair<params_t::iterator, params_t::iterator> rangeIter = params.equal_range(name); + while(rangeIter.first != rangeIter.second) { + target.push_back(rangeIter.first->second); + rangeIter.first++; + } + return true; + } + return false; + } + + template <typename T> static bool getParam(params_t params, const std::string& name, T& target) { + if (params.find(name) != params.end()) { + target = boost::lexical_cast<T>(params.find(name)->second.atom); + return true; + } + return false; + } + + static bool getParam(params_t params, const std::string& name, bool& target) { + if (params.find(name) != params.end()) { + target = true; + if (iequals(params.find(name)->second.atom, "false")) { + target = false; + } else if(iequals(params.find(name)->second.atom, "off")) { + target = false; + } else if(iequals(params.find(name)->second.atom, "no")) { + target = false; + } else if(iequals(params.find(name)->second.atom, "0")) { + target = false; + } + return true; + } + return false; + } + + template <typename T> static bool getParam(params_t params, const std::string& name, std::list<T>& target) { + if (params.find(name) != params.end()) { + std::pair<params_t::iterator, params_t::iterator> rangeIter = params.equal_range(name); + while(rangeIter.first != rangeIter.second) { + target.push_back(boost::lexical_cast<T>(rangeIter.first->second.atom)); + rangeIter.first++; + } + return true; + } + return false; + } + + +#ifdef SWIGIMPORTED +protected: +#endif + + std::string raw; + std::string xml; + std::string name; + Type eventType; + std::string origin; + std::string origintype; + Arabica::DOM::Node<std::string> dom; + std::string sendid; + bool hideSendId; + std::string invokeid; + Data data; + std::string content; + std::map<std::string, Data> namelist; + std::multimap<std::string, Data> params; + + friend USCXML_API std::ostream& operator<< (std::ostream& os, const Event& event); +}; + +USCXML_API std::ostream& operator<< (std::ostream& os, const Event& event); + +} + +#endif /* end of include guard: EVENT_H_6174D929 */ diff --git a/src/uscxml/messages/InvokeRequest.cpp b/src/uscxml/messages/InvokeRequest.cpp new file mode 100644 index 0000000..a39c8c6 --- /dev/null +++ b/src/uscxml/messages/InvokeRequest.cpp @@ -0,0 +1,91 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#include "uscxml/messages/InvokeRequest.h" +#include <DOM/Simple/DOMImplementation.hpp> +#include <DOM/Document.hpp> +#include <DOM/io/Stream.hpp> + +namespace uscxml { + +std::string InvokeRequest::toXMLString() { + std::stringstream ss; + ss << toDocument(); + return ss.str(); +} + +Arabica::DOM::Document<std::string> InvokeRequest::toDocument() { + Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); + Arabica::DOM::Document<std::string> document = Event::toDocument(); + Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement(); + + scxmlMsg.setAttribute("invokeid", invokeid); + + return document; +} + +InvokeRequest InvokeRequest::fromXML(const std::string& xmlString) { + Event::fromXML(xmlString); + return InvokeRequest(); +} + +std::ostream& operator<< (std::ostream& os, const InvokeRequest& invokeReq) { + + std::string indent; + for (int i = 0; i < _dataIndentation; i++) { + indent += " "; + } + + os << indent << "InvokeReq" << (invokeReq.autoForward ? " with autoforward" : "") << std::endl; + + if (invokeReq.type.size() > 0) + os << indent << " type: " << invokeReq.type << std::endl; + + if (invokeReq.src.size() > 0) + os<< indent << " src: " << invokeReq.src << std::endl; + + if (invokeReq.namelist.size() > 0) { + os << indent << " namelist: " << std::endl; + InvokeRequest::namelist_t::const_iterator namelistIter = invokeReq.namelist.begin(); + while(namelistIter != invokeReq.namelist.end()) { + os << indent << " " << namelistIter->first << ": " << namelistIter->second << std::endl; + namelistIter++; + } + } + + if (invokeReq.params.size() > 0) { + os << indent << " params: " << std::endl; + InvokeRequest::params_t::const_iterator paramIter = invokeReq.params.begin(); + while(paramIter != invokeReq.params.end()) { + os << indent << " " << paramIter->first << ": " << paramIter->second << std::endl; + paramIter++; + } + } + + if (invokeReq.content.size() > 0) + os << indent << " content: " << invokeReq.content << std::endl; + + _dataIndentation++; + os << (Event)invokeReq; + _dataIndentation--; + return os; + +} + +}
\ No newline at end of file diff --git a/src/uscxml/messages/InvokeRequest.h b/src/uscxml/messages/InvokeRequest.h new file mode 100644 index 0000000..ac5f6f7 --- /dev/null +++ b/src/uscxml/messages/InvokeRequest.h @@ -0,0 +1,72 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#ifndef INVOKEREQUEST_H_BAF058E2 +#define INVOKEREQUEST_H_BAF058E2 + +#include "uscxml/messages/Event.h" + +namespace uscxml { + +class USCXML_API InvokeRequest : public Event { +public: + InvokeRequest(Event event) : Event(event) {} + InvokeRequest() {} + + std::string getType() { + return type; + } + void setType(const std::string& type) { + this->type = type; + } + + std::string getSource() { + return src; + } + void setSource(const std::string& src) { + this->src = src; + } + + bool isAutoForwarded() { + return autoForward; + } + void setAutoForwarded(bool autoForward) { + this->autoForward = autoForward; + } + + static InvokeRequest fromXML(const std::string& xmlString); + Arabica::DOM::Document<std::string> toDocument(); + std::string toXMLString(); + +#ifdef SWIGIMPORTED +protected: +#endif + std::string type; + std::string src; + bool autoForward; + + friend USCXML_API std::ostream& operator<< (std::ostream& os, const InvokeRequest& sendReq); + +}; + +USCXML_API std::ostream& operator<< (std::ostream& os, const InvokeRequest& invokeReq); + +} + +#endif /* end of include guard: INVOKEREQUEST_H_BAF058E2 */ diff --git a/src/uscxml/messages/SendRequest.cpp b/src/uscxml/messages/SendRequest.cpp new file mode 100644 index 0000000..a8fbe13 --- /dev/null +++ b/src/uscxml/messages/SendRequest.cpp @@ -0,0 +1,135 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#include "uscxml/messages/SendRequest.h" +#include <DOM/Simple/DOMImplementation.hpp> +#include <DOM/Document.hpp> +#include <DOM/io/Stream.hpp> + +namespace uscxml { + +std::string SendRequest::toXMLString() { + std::stringstream ss; + ss << toDocument(); + return ss.str(); +} + +Arabica::DOM::Document<std::string> SendRequest::toDocument() { + Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); + Arabica::DOM::Document<std::string> document = Event::toDocument(); + Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement(); + + // add params and namelist + if (params.size() > 0 || namelist.size() > 0) { + Arabica::DOM::NodeList<std::string> payload = scxmlMsg.getElementsByTagName("scxml:payload"); + if (payload.getLength() == 0) { + Arabica::DOM::Element<std::string> payloadElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "payload"); + payloadElem.setPrefix("scxml"); + + scxmlMsg.appendChild(payloadElem); + } + Arabica::DOM::Node<std::string> payloadElem = scxmlMsg.getElementsByTagName("scxml:payload").item(0); + + // add parameters + std::multimap<std::string, Data>::iterator paramIter = params.begin(); + while(paramIter != params.end()) { + Arabica::DOM::Element<std::string> propertyElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "property"); + propertyElem.setPrefix("scxml"); + + propertyElem.setAttribute("name", paramIter->first); + // this is simplified - Data might be more elaborate than a simple string atom + Arabica::DOM::Text<std::string> textElem = document.createTextNode(paramIter->second.atom); + propertyElem.appendChild(textElem); + payloadElem.appendChild(propertyElem); + paramIter++; + } + + // add namelist elements + std::map<std::string, Data>::iterator namelistIter = namelist.begin(); + while(namelistIter != namelist.end()) { + Arabica::DOM::Element<std::string> propertyElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "property"); + propertyElem.setPrefix("scxml"); + + propertyElem.setAttribute("name", namelistIter->first); + // this is simplified - Data might be more elaborate than a simple string atom + Arabica::DOM::Text<std::string> textElem = document.createTextNode(namelistIter->second.atom); + propertyElem.appendChild(textElem); + payloadElem.appendChild(propertyElem); + namelistIter++; + } + + } + + scxmlMsg.setAttribute("sendid", sendid); + + return document; +} + +SendRequest SendRequest::fromXML(const std::string& xmlString) { + Event::fromXML(xmlString); + return SendRequest(); +} + +std::ostream& operator<< (std::ostream& os, const SendRequest& sendReq) { + + std::string indent; + for (int i = 0; i < _dataIndentation; i++) { + indent += " "; + } + + os << indent << "SendReq" << std::endl; + + if (sendReq.target.size() > 0) + os << indent << " target: " << sendReq.target << std::endl; + + if (sendReq.type.size() > 0) + os << indent << " type: " << sendReq.type << std::endl; + + if (sendReq.delayMs > 0) + os<< indent << " delay: " << sendReq.delayMs << std::endl; + + if (sendReq.namelist.size() > 0) { + os << indent << " namelist: " << std::endl; + SendRequest::namelist_t::const_iterator namelistIter = sendReq.namelist.begin(); + while(namelistIter != sendReq.namelist.end()) { + os << indent << " " << namelistIter->first << ": " << namelistIter->second << std::endl; + namelistIter++; + } + } + + if (sendReq.params.size() > 0) { + os << indent << " params: " << std::endl; + SendRequest::params_t::const_iterator paramIter = sendReq.params.begin(); + while(paramIter != sendReq.params.end()) { + os << indent << " " << paramIter->first << ": " << paramIter->second << std::endl; + paramIter++; + } + } + + if (sendReq.content.size() > 0) + os << indent << " content: " << sendReq.content << std::endl; + + _dataIndentation++; + os << (Event)sendReq; + _dataIndentation--; + return os; + +} + +}
\ No newline at end of file diff --git a/src/uscxml/messages/SendRequest.h b/src/uscxml/messages/SendRequest.h new file mode 100644 index 0000000..6bc3d91 --- /dev/null +++ b/src/uscxml/messages/SendRequest.h @@ -0,0 +1,72 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#ifndef SENDREQUEST_H_86B0F6A0 +#define SENDREQUEST_H_86B0F6A0 + +#include "uscxml/messages/Event.h" + +namespace uscxml { + +class USCXML_API SendRequest : public Event { +public: + SendRequest() {} + SendRequest(Event event) : Event(event) {} + + std::string getTarget() { + return target; + } + void setTarget(const std::string& target) { + this->target = target; + } + + std::string getType() { + return type; + } + void setType(const std::string& type) { + this->type = type; + } + + uint32_t getDelayMs() { + return delayMs; + } + void setDelayMs(uint32_t delayMs) { + this->delayMs = delayMs; + } + + static SendRequest fromXML(const std::string& xmlString); + Arabica::DOM::Document<std::string> toDocument(); + std::string toXMLString(); + +#ifdef SWIGIMPORTED +protected: +#endif + std::string target; + std::string type; + uint32_t delayMs; + + friend USCXML_API std::ostream& operator<< (std::ostream& os, const SendRequest& sendReq); + +}; + +USCXML_API std::ostream& operator<< (std::ostream& os, const SendRequest& sendReq); + +} + +#endif /* end of include guard: SENDREQUEST_H_86B0F6A0 */ diff --git a/src/uscxml/plugins/DataModel.h b/src/uscxml/plugins/DataModel.h new file mode 100644 index 0000000..57d4b14 --- /dev/null +++ b/src/uscxml/plugins/DataModel.h @@ -0,0 +1,209 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#ifndef DATAMODEL_H_F1F776F9 +#define DATAMODEL_H_F1F776F9 + +#include "uscxml/Common.h" +#include "uscxml/plugins/EventHandler.h" + +#include <list> +#include <boost/shared_ptr.hpp> +#include <string> +#include <sstream> + +#include "DOM/Document.hpp" + +namespace uscxml { + +class InterpreterImpl; + +class USCXML_API DataModelImpl { +public: + virtual ~DataModelImpl() {} + virtual boost::shared_ptr<DataModelImpl> create(InterpreterImpl* interpreter) = 0; + virtual std::list<std::string> getNames() = 0; + + virtual bool validate(const std::string& location, const std::string& schema) = 0; + virtual void setEvent(const Event& event) = 0; + virtual Data getStringAsData(const std::string& content) = 0; + + size_t replaceExpressions(std::string& content); + + // foreach + virtual uint32_t getLength(const std::string& expr) = 0; + virtual void setForeach(const std::string& item, + const std::string& array, + const std::string& index, + uint32_t iteration) = 0; + virtual void pushContext() = 0; + virtual void popContext() = 0; + + virtual void eval(const Arabica::DOM::Element<std::string>& scriptElem, + const std::string& expr) = 0; + + virtual std::string evalAsString(const std::string& expr) = 0; + + virtual bool evalAsBool(const Arabica::DOM::Node<std::string>& scriptNode, + const std::string& expr) = 0; + virtual bool evalAsBool(const std::string& expr) { + return evalAsBool(Arabica::DOM::Node<std::string>(), expr); + } + + virtual bool isDeclared(const std::string& expr) = 0; + + virtual void assign(const Arabica::DOM::Element<std::string>& assignElem, + const Arabica::DOM::Node<std::string>& node, + const std::string& content) = 0; + virtual void assign(const std::string& location, const Data& data) = 0; + + virtual void init(const Arabica::DOM::Element<std::string>& dataElem, + const Arabica::DOM::Node<std::string>& node, + const std::string& content) = 0; + virtual void init(const std::string& location, const Data& data) = 0; + + virtual void setInterpreter(InterpreterImpl* interpreter) { + _interpreter = interpreter; + } + + virtual std::string andExpressions(std::list<std::string>) { + return ""; + } + + static void throwErrorExecution(const std::string& cause); + static void throwErrorPlatform(const std::string& cause); + + // we need it public for various static functions +protected: + InterpreterImpl* _interpreter; +}; + +class USCXML_API DataModel { +public: + DataModel() : _impl() {} + DataModel(const boost::shared_ptr<DataModelImpl> impl) : _impl(impl) { } + DataModel(const DataModel& other) : _impl(other._impl) { } + virtual ~DataModel() {}; + + operator bool() const { + return _impl; + } + bool operator< (const DataModel& other) const { + return _impl < other._impl; + } + bool operator==(const DataModel& other) const { + return _impl == other._impl; + } + bool operator!=(const DataModel& other) const { + return _impl != other._impl; + } + DataModel& operator= (const DataModel& other) { + _impl = other._impl; + return *this; + } + + virtual std::list<std::string> getNames() { + return _impl->getNames(); + } + + virtual bool validate(const std::string& location, const std::string& schema) { + return _impl->validate(location, schema); + } + virtual void setEvent(const Event& event) { + return _impl->setEvent(event); + } + virtual Data getStringAsData(const std::string& content) { + return _impl->getStringAsData(content); + } + + virtual void pushContext() { + return _impl->pushContext(); + } + virtual void popContext() { + return _impl->popContext(); + } + + virtual void eval(const Arabica::DOM::Element<std::string>& scriptElem, + const std::string& expr) { + return _impl->eval(scriptElem, expr); + } + virtual std::string evalAsString(const std::string& expr) { + return _impl->evalAsString(expr); + } + virtual bool evalAsBool(const std::string& expr) { + return _impl->evalAsBool(expr); + } + virtual bool evalAsBool(const Arabica::DOM::Node<std::string>& scriptNode, + const std::string& expr) { + return _impl->evalAsBool(scriptNode, expr); + } + + virtual uint32_t getLength(const std::string& expr) { + return _impl->getLength(expr); + } + virtual void setForeach(const std::string& item, + const std::string& array, + const std::string& index, + uint32_t iteration) { + return _impl->setForeach(item, array, index, iteration); + } + + virtual void assign(const Arabica::DOM::Element<std::string>& assignElem, + const Arabica::DOM::Node<std::string>& node, + const std::string& content) { + return _impl->assign(assignElem, node, content); + } + virtual void assign(const std::string& location, const Data& data) { + return _impl->assign(location, data); + } + + virtual void init(const Arabica::DOM::Element<std::string>& dataElem, + const Arabica::DOM::Node<std::string>& node, + const std::string& content) { + return _impl->init(dataElem, node, content); + } + virtual void init(const std::string& location, const Data& data) { + return _impl->init(location, data); + } + + virtual bool isDeclared(const std::string& expr) { + return _impl->isDeclared(expr); + } + + size_t replaceExpressions(std::string& content) { + return _impl->replaceExpressions(content); + } + + std::string andExpressions(std::list<std::string> expressions) { + return _impl->andExpressions(expressions); + } + + virtual void setInterpreter(InterpreterImpl* interpreter) { + _impl->setInterpreter(interpreter); + } + +protected: + boost::shared_ptr<DataModelImpl> _impl; +}; + + +} + + +#endif /* end of include guard: DATAMODEL_H_F1F776F9 */ diff --git a/src/uscxml/plugins/EventHandler.h b/src/uscxml/plugins/EventHandler.h new file mode 100644 index 0000000..d30feb9 --- /dev/null +++ b/src/uscxml/plugins/EventHandler.h @@ -0,0 +1,125 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#ifndef EVENTHANDLER_H_2801243E +#define EVENTHANDLER_H_2801243E + +#include "uscxml/Common.h" + +#include <list> +#include <boost/shared_ptr.hpp> +#include <string> +#include <sstream> + +#include "DOM/Document.hpp" +#include "uscxml/messages/SendRequest.h" + +namespace uscxml { + +class InterpreterImpl; + +class USCXML_API EventHandlerImpl { +public: + virtual ~EventHandlerImpl() {} + + virtual std::list<std::string> getNames() = 0; + + virtual void setInterpreter(InterpreterImpl* interpreter) { + _interpreter = interpreter; + } + void setInvokeId(const std::string& invokeId) { + _invokeId = invokeId; + } + void setType(const std::string& type) { + _type = type; + } + + void setElement(const Arabica::DOM::Element<std::string>& element) { + _element = element; + } + + Arabica::DOM::Element<std::string> getElement() { + return _element; + } + + virtual Data getDataModelVariables() = 0; + virtual void send(const SendRequest& req) = 0; + + virtual void runOnMainThread() {}; + void returnEvent(Event& event); + void returnErrorExecution(const std::string&); + void returnErrorPlatform(const std::string&); + +protected: + InterpreterImpl* _interpreter; + Arabica::DOM::Element<std::string> _element; + std::string _invokeId; + std::string _type; + +}; + +class USCXML_API EventHandler { +public: + EventHandler() : _impl() {} + EventHandler(boost::shared_ptr<EventHandlerImpl> const impl) : _impl(impl) { } + EventHandler(const EventHandler& other) : _impl(other._impl) { } + virtual ~EventHandler() {}; + + virtual std::list<std::string> getNames() { + return _impl->getNames(); + } + + virtual Data getDataModelVariables() const { + return _impl->getDataModelVariables(); + }; + virtual void send(const SendRequest& req) { + return _impl->send(req); + }; + virtual void runOnMainThread() { + return _impl->runOnMainThread(); + } + + void setInterpreter(InterpreterImpl* interpreter) { + _impl->setInterpreter(interpreter); + } + void setInvokeId(const std::string& invokeId) { + _impl->setInvokeId(invokeId); + } + void setType(const std::string& type) { + _impl->setType(type); + } + + void setElement(const Arabica::DOM::Element<std::string>& element) { + _impl->setElement(element); + } + + Arabica::DOM::Element<std::string> getElement() { + return _impl->getElement(); + } + +protected: + boost::shared_ptr<EventHandlerImpl> _impl; + friend class InterpreterImpl; +}; + + +} + + +#endif /* end of include guard: EVENTHANDLER_H_2801243E */ diff --git a/src/uscxml/plugins/ExecutableContent.h b/src/uscxml/plugins/ExecutableContent.h new file mode 100644 index 0000000..6f4335b --- /dev/null +++ b/src/uscxml/plugins/ExecutableContent.h @@ -0,0 +1,105 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#ifndef EXECUTABLECONTENT_H_1E028A2D +#define EXECUTABLECONTENT_H_1E028A2D + +#include "uscxml/Common.h" +#include <boost/shared_ptr.hpp> +#include <string> +#include <sstream> +#include "DOM/Document.hpp" + +namespace uscxml { + +class InterpreterImpl; + +class USCXML_API ExecutableContentImpl { +public: + ExecutableContentImpl() {}; + virtual ~ExecutableContentImpl() {}; + virtual boost::shared_ptr<ExecutableContentImpl> create(InterpreterImpl* interpreter) = 0; + + virtual void setInterpreter(InterpreterImpl* interpreter) { + _interpreter = interpreter; + } + + virtual std::string getLocalName() = 0; ///< The name of the element. + virtual std::string getNamespace() { + return "http://www.w3.org/2005/07/scxml"; ///< The namespace of the element. + } + virtual void enterElement(const Arabica::DOM::Node<std::string>& node) = 0; ///< Invoked when entering the element as part of evaluating executable content. + virtual void exitElement(const Arabica::DOM::Node<std::string>& node) = 0; ///< Invoked when exiting the element as part of evaluating executable content. + virtual bool processChildren() = 0; ///< Whether or not the interpreter should process this elements children. + +protected: + InterpreterImpl* _interpreter; +}; + +class USCXML_API ExecutableContent { +public: + ExecutableContent() : _impl() {} + ExecutableContent(boost::shared_ptr<ExecutableContentImpl> const impl) : _impl(impl) { } + ExecutableContent(const ExecutableContent& other) : _impl(other._impl) { } + virtual ~ExecutableContent() {}; + + operator bool() const { + return _impl; + } + bool operator< (const ExecutableContent& other) const { + return _impl < other._impl; + } + bool operator==(const ExecutableContent& other) const { + return _impl == other._impl; + } + bool operator!=(const ExecutableContent& other) const { + return _impl != other._impl; + } + ExecutableContent& operator= (const ExecutableContent& other) { + _impl = other._impl; + return *this; + } + + void setInterpreter(InterpreterImpl* interpreter) { + _impl->setInterpreter(interpreter); + } + + std::string getLocalName() { + return _impl->getLocalName(); + } + std::string getNamespace() { + return _impl->getNamespace(); + } + void enterElement(const Arabica::DOM::Node<std::string>& node) { + return _impl->enterElement(node); + } + void exitElement(const Arabica::DOM::Node<std::string>& node) { + return _impl->exitElement(node); + } + bool processChildren() { + return _impl->processChildren(); + } +protected: + boost::shared_ptr<ExecutableContentImpl> _impl; + +}; + +} + +#endif /* end of include guard: EXECUTABLECONTENT_H_1E028A2D */ diff --git a/src/uscxml/plugins/IOProcessor.h b/src/uscxml/plugins/IOProcessor.h new file mode 100644 index 0000000..79f759b --- /dev/null +++ b/src/uscxml/plugins/IOProcessor.h @@ -0,0 +1,71 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#ifndef IOPROCESSOR_H_CF4F4135 +#define IOPROCESSOR_H_CF4F4135 + +#include "uscxml/Common.h" +#include "uscxml/plugins/EventHandler.h" + +namespace uscxml { + +class InterpreterImpl; + +class USCXML_API IOProcessorImpl : public EventHandlerImpl { +public: + IOProcessorImpl() {}; + virtual ~IOProcessorImpl() {}; + virtual boost::shared_ptr<IOProcessorImpl> create(InterpreterImpl* interpreter) = 0; +}; + +class USCXML_API IOProcessor : public EventHandler { +public: + IOProcessor() : _impl() {} + IOProcessor(boost::shared_ptr<IOProcessorImpl> const impl) : EventHandler(impl), _impl(impl) { } + IOProcessor(const IOProcessor& other) : EventHandler(other._impl), _impl(other._impl) { } + virtual ~IOProcessor() {}; + + operator bool() const { + return _impl; + } + bool operator< (const IOProcessor& other) const { + return _impl < other._impl; + } + bool operator==(const IOProcessor& other) const { + return _impl == other._impl; + } + bool operator!=(const IOProcessor& other) const { + return _impl != other._impl; + } + IOProcessor& operator= (const IOProcessor& other) { + _impl = other._impl; + EventHandler::_impl = _impl; + return *this; + } + +protected: + boost::shared_ptr<IOProcessorImpl> _impl; + friend class InterpreterImpl; +}; + + +} + + +#endif /* end of include guard: IOPROCESSOR_H_CF4F4135 */ diff --git a/src/uscxml/plugins/Invoker.h b/src/uscxml/plugins/Invoker.h new file mode 100644 index 0000000..c967331 --- /dev/null +++ b/src/uscxml/plugins/Invoker.h @@ -0,0 +1,76 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#ifndef INVOKER_H_CAC11892 +#define INVOKER_H_CAC11892 + + +#include "uscxml/Common.h" +#include "uscxml/plugins/EventHandler.h" +#include "uscxml/messages/InvokeRequest.h" + +namespace uscxml { + +class InterpreterImpl; + +class USCXML_API InvokerImpl : public EventHandlerImpl { +public: + virtual ~InvokerImpl() {} + virtual void invoke(const InvokeRequest& req) = 0; + virtual boost::shared_ptr<InvokerImpl> create(InterpreterImpl* interpreter) = 0; +}; + +class USCXML_API Invoker : public EventHandler { +public: + Invoker() : _impl() {} + Invoker(boost::shared_ptr<InvokerImpl> const impl) : EventHandler(impl), _impl(impl) { } + Invoker(const Invoker& other) : EventHandler(other._impl), _impl(other._impl) { } + virtual ~Invoker() {}; + + operator bool() const { + return _impl; + } + bool operator< (const Invoker& other) const { + return _impl < other._impl; + } + bool operator==(const Invoker& other) const { + return _impl == other._impl; + } + bool operator!=(const Invoker& other) const { + return _impl != other._impl; + } + Invoker& operator= (const Invoker& other) { + _impl = other._impl; + EventHandler::_impl = _impl; + return *this; + } + + virtual void invoke(InvokeRequest& req) { + _impl->invoke(req); + } + +protected: + boost::shared_ptr<InvokerImpl> _impl; +}; + + +} + + +#endif /* end of include guard: INVOKER_H_CAC11892 */ diff --git a/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp index 9594d5e..98d2dda 100644 --- a/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp +++ b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp @@ -112,23 +112,23 @@ bool NULLDataModel::evalAsBool(const Arabica::DOM::Node<std::string>& node, cons // split at comma std::stringstream ss(trimmedExpr.substr(start, end - start)); - std::vector<std::string> stateExprs; + std::list<std::string> stateExprs; std::string item; while(std::getline(ss, item, ',')) { stateExprs.push_back(item); } - for (unsigned int i = 0; i < stateExprs.size(); i++) { + for (std::list<std::string>::const_iterator stateIter = stateExprs.begin(); stateIter != stateExprs.end(); stateIter++) { // remove ticks - size_t start = stateExprs[i].find_first_of("'"); - size_t end = stateExprs[i].find_last_of("'"); + size_t start = stateIter->find_first_of("'"); + size_t end = stateIter->find_last_of("'"); std::string stateName; if (start != std::string::npos && end != std::string::npos && start < end) { start++; - stateName = stateExprs[i].substr(start, end - start); + stateName = stateIter->substr(start, end - start); } else { - stateName = stateExprs[i]; + stateName = *stateIter; } if (_interpreter->isInState(stateName)) { diff --git a/src/uscxml/plugins/datamodel/promela/PromelaParser.cpp b/src/uscxml/plugins/datamodel/promela/PromelaParser.cpp index a1edcae..cd3bbaf 100644 --- a/src/uscxml/plugins/datamodel/promela/PromelaParser.cpp +++ b/src/uscxml/plugins/datamodel/promela/PromelaParser.cpp @@ -20,6 +20,8 @@ #include "PromelaParser.h" #include "parser/promela.tab.hpp" +#include <iostream> + struct yy_buffer_state; typedef yy_buffer_state *YY_BUFFER_STATE; extern YY_BUFFER_STATE promela__scan_buffer(char *, size_t, void*); diff --git a/src/uscxml/plugins/element/file/FileElement.cpp b/src/uscxml/plugins/element/file/FileElement.cpp index 899c2d6..606cddc 100644 --- a/src/uscxml/plugins/element/file/FileElement.cpp +++ b/src/uscxml/plugins/element/file/FileElement.cpp @@ -22,6 +22,7 @@ #include <stdio.h> #include <vector> #include <boost/algorithm/string.hpp> +#include "uscxml/messages/Blob.h" #include "uscxml/DOMUtils.h" diff --git a/src/uscxml/plugins/element/respond/RespondElement.cpp b/src/uscxml/plugins/element/respond/RespondElement.cpp index 3eb55ed..06d89a7 100644 --- a/src/uscxml/plugins/element/respond/RespondElement.cpp +++ b/src/uscxml/plugins/element/respond/RespondElement.cpp @@ -19,6 +19,7 @@ #include "RespondElement.h" #include "uscxml/plugins/invoker/http/HTTPServletInvoker.h" +#include "uscxml/server/InterpreterServlet.h" #include "uscxml/DOMUtils.h" #include <glog/logging.h> diff --git a/src/uscxml/plugins/invoker/calendar/CalendarInvoker.cpp b/src/uscxml/plugins/invoker/calendar/CalendarInvoker.cpp index c6194c5..849845e 100644 --- a/src/uscxml/plugins/invoker/calendar/CalendarInvoker.cpp +++ b/src/uscxml/plugins/invoker/calendar/CalendarInvoker.cpp @@ -20,6 +20,8 @@ #include <boost/algorithm/string.hpp> #include "CalendarInvoker.h" +#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h" + #include <glog/logging.h> #ifdef BUILD_AS_PLUGINS diff --git a/src/uscxml/plugins/invoker/expect/ExpectInvoker.cpp b/src/uscxml/plugins/invoker/expect/ExpectInvoker.cpp index 7d66b10..22c7942 100644 --- a/src/uscxml/plugins/invoker/expect/ExpectInvoker.cpp +++ b/src/uscxml/plugins/invoker/expect/ExpectInvoker.cpp @@ -20,6 +20,8 @@ #include "ExpectInvoker.h" #include <glog/logging.h> +#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h" + #ifdef BUILD_AS_PLUGINS #include <Pluma/Connector.hpp> #endif diff --git a/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp index b6203d4..4a0ec00 100644 --- a/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp +++ b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp @@ -20,6 +20,8 @@ #include <boost/algorithm/string.hpp> #include "FFMPEGInvoker.h" +#include "uscxml/messages/Blob.h" + #include <glog/logging.h> #include <libavutil/imgutils.h> diff --git a/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp b/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp index cee98bd..f8b4904 100644 --- a/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp +++ b/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp @@ -20,6 +20,7 @@ #include <boost/algorithm/string.hpp> #include "HeartbeatInvoker.h" +#include "uscxml/DOMUtils.h" #include <glog/logging.h> #ifdef BUILD_AS_PLUGINS diff --git a/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.h b/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.h index a024181..ba4e9ef 100644 --- a/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.h +++ b/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.h @@ -21,6 +21,7 @@ #define HEARTBEATINVOKER_H_W09J90F0 #include <uscxml/Interpreter.h> +#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h" #ifdef BUILD_AS_PLUGINS #include "uscxml/plugins/Plugins.h" diff --git a/src/uscxml/plugins/invoker/im/IMInvoker.cpp b/src/uscxml/plugins/invoker/im/IMInvoker.cpp index d086a20..08d6a03 100644 --- a/src/uscxml/plugins/invoker/im/IMInvoker.cpp +++ b/src/uscxml/plugins/invoker/im/IMInvoker.cpp @@ -23,6 +23,8 @@ #include "uscxml/DOMUtils.h" #include <boost/algorithm/string.hpp> +#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h" + #ifdef BUILD_AS_PLUGINS #include <Pluma/Connector.hpp> #endif diff --git a/src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp b/src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp index 1248733..2a974ab 100644 --- a/src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp +++ b/src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp @@ -26,6 +26,7 @@ #include <boost/algorithm/string.hpp> #include "uscxml/UUID.h" +#include "uscxml/messages/Blob.h" namespace uscxml { diff --git a/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.h b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.h index b1a9c5a..773df31 100644 --- a/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.h +++ b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.h @@ -21,6 +21,7 @@ #define XHTMLINVOKER_H_W09J90F0 #include <uscxml/Interpreter.h> +#include "uscxml/server/HTTPServer.h" #ifdef BUILD_AS_PLUGINS #include "uscxml/plugins/Plugins.h" diff --git a/src/uscxml/plugins/ioprocessor/comet/CometIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/comet/CometIOProcessor.cpp index 007bd6f..9ec5c00 100644 --- a/src/uscxml/plugins/ioprocessor/comet/CometIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/comet/CometIOProcessor.cpp @@ -22,6 +22,7 @@ #include "uscxml/Message.h" #include <iostream> +#include <DOM/io/Stream.hpp> #include <string.h> #ifdef BUILD_AS_PLUGINS diff --git a/src/uscxml/server/InterpreterServlet.cpp b/src/uscxml/server/InterpreterServlet.cpp index 3c5c3a0..f90d111 100644 --- a/src/uscxml/server/InterpreterServlet.cpp +++ b/src/uscxml/server/InterpreterServlet.cpp @@ -20,6 +20,7 @@ #include "InterpreterServlet.h" #include "uscxml/Interpreter.h" #include <glog/logging.h> +#include <DOM/io/Stream.hpp> namespace uscxml { diff --git a/src/uscxml/server/InterpreterServlet.h b/src/uscxml/server/InterpreterServlet.h index 960ff8f..436574b 100644 --- a/src/uscxml/server/InterpreterServlet.h +++ b/src/uscxml/server/InterpreterServlet.h @@ -21,11 +21,12 @@ #define INTERPRETERSERVLET_H_XQLWNMH4 #include "HTTPServer.h" -#include "uscxml/Factory.h" +#include "uscxml/messages/SendRequest.h" // for SendRequest +#include "uscxml/plugins/IOProcessor.h" // for IOProcessorImpl namespace uscxml { -class Interpreter; +class InterpreterImpl; class InterpreterHTTPServlet : public HTTPServlet, public IOProcessorImpl { public: diff --git a/src/uscxml/transform/ChartToFSM.cpp b/src/uscxml/transform/ChartToFSM.cpp index 581ba85..3bce169 100644 --- a/src/uscxml/transform/ChartToFSM.cpp +++ b/src/uscxml/transform/ChartToFSM.cpp @@ -18,6 +18,8 @@ */ #include "uscxml/transform/ChartToFSM.h" +#include "uscxml/Factory.h" + #include <DOM/io/Stream.hpp> #include <glog/logging.h> |