diff options
author | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2012-12-20 21:34:09 (GMT) |
---|---|---|
committer | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2012-12-20 21:34:09 (GMT) |
commit | 498f6f80e9ca01236ca1491596875ab7eb4cd8c3 (patch) | |
tree | e627ae19475bb93a98dfa50db1950f6e3403f569 /src/uscxml | |
parent | d779abe6ff76a78f92d229fcf1f006f5cf1f9295 (diff) | |
download | uscxml-498f6f80e9ca01236ca1491596875ab7eb4cd8c3.zip uscxml-498f6f80e9ca01236ca1491596875ab7eb4cd8c3.tar.gz uscxml-498f6f80e9ca01236ca1491596875ab7eb4cd8c3.tar.bz2 |
Refactoring finished
Support datamodels, invokers and ioprocessors as plugins
Comply to HTTP1.1 by sending host header field
Started prolog datamodel
Diffstat (limited to 'src/uscxml')
39 files changed, 6122 insertions, 5915 deletions
diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp index 9f16503..0745f74 100644 --- a/src/uscxml/Factory.cpp +++ b/src/uscxml/Factory.cpp @@ -2,154 +2,185 @@ #include "uscxml/config.h" #include "uscxml/Factory.h" -#include "uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h" -#include "uscxml/plugins/invoker/scxml/USCXMLInvoker.h" +#include "uscxml/Message.h" -#ifdef UMUNDO_FOUND -#include "uscxml/plugins/invoker/umundo/UmundoInvoker.h" -#endif +#ifdef BUILD_AS_PLUGINS +# include "uscxml/plugins/Plugins.h" +#else -#ifdef MILES_FOUND -#include "uscxml/plugins/invoker/modality/miles/SpatialAudio.h" -#endif +# include "uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h" +# include "uscxml/plugins/invoker/scxml/USCXMLInvoker.h" + +# ifdef UMUNDO_FOUND +# include "uscxml/plugins/invoker/umundo/UmundoInvoker.h" +# endif + +# ifdef MILES_FOUND +# include "uscxml/plugins/invoker/modality/miles/SpatialAudio.h" +# endif + +# ifdef V8_FOUND +# include "uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h" +# endif + +# ifdef SWI_FOUND +# include "uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h" +# endif -#ifdef V8_FOUND -#include "uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h" #endif namespace uscxml { - - Factory::Factory() { + +Factory::Factory() { #ifdef BUILD_AS_PLUGINS - if (pluginPath.length() > 0) { - pluma.acceptProviderType<InvokerProvider>(); - pluma.acceptProviderType<IOProcessorProvider>(); - pluma.acceptProviderType<DataModelProvider>(); - pluma.loadFromFolder(pluginPath); - - std::vector<InvokerProvider*> invokerProviders; - pluma.getProviders(invokerProviders); - for (std::vector<InvokerProvider*>::iterator it = invokerProviders.begin() ; it != invokerProviders.end() ; ++it) { - Invoker* invoker = (*it)->create(); - registerInvoker(invoker); - } - - std::vector<IOProcessorProvider*> ioProcessorProviders; - pluma.getProviders(ioProcessorProviders); - for (std::vector<IOProcessorProvider*>::iterator it = ioProcessorProviders.begin() ; it != ioProcessorProviders.end() ; ++it) { - IOProcessor* ioProcessor = (*it)->create(); - registerIOProcessor(ioProcessor); - } - - std::vector<DataModelProvider*> dataModelProviders; - pluma.getProviders(dataModelProviders); - for (std::vector<DataModelProvider*>::iterator it = dataModelProviders.begin() ; it != dataModelProviders.end() ; ++it) { - DataModel* dataModel = (*it)->create(); - registerDataModel(dataModel); - } - - pluma.unloadAll(); - } -#else -#ifdef UMUNDO_FOUND - { - UmundoInvoker* invoker = new UmundoInvoker(); + if (pluginPath.length() == 0) { + // try to read USCXML_PLUGIN_PATH environment variable + pluginPath = (getenv("USCXML_PLUGIN_PATH") != NULL ? getenv("USCXML_PLUGIN_PATH") : ""); + } + if (pluginPath.length() > 0) { + pluma.acceptProviderType<InvokerProvider>(); + pluma.acceptProviderType<IOProcessorProvider>(); + pluma.acceptProviderType<DataModelProvider>(); + pluma.loadFromFolder(pluginPath); + + std::vector<InvokerProvider*> invokerProviders; + pluma.getProviders(invokerProviders); + for (std::vector<InvokerProvider*>::iterator it = invokerProviders.begin() ; it != invokerProviders.end() ; ++it) { + Invoker* invoker = (*it)->create(); registerInvoker(invoker); } + + std::vector<IOProcessorProvider*> ioProcessorProviders; + pluma.getProviders(ioProcessorProviders); + for (std::vector<IOProcessorProvider*>::iterator it = ioProcessorProviders.begin() ; it != ioProcessorProviders.end() ; ++it) { + IOProcessor* ioProcessor = (*it)->create(); + registerIOProcessor(ioProcessor); + } + + std::vector<DataModelProvider*> dataModelProviders; + pluma.getProviders(dataModelProviders); + for (std::vector<DataModelProvider*>::iterator it = dataModelProviders.begin() ; it != dataModelProviders.end() ; ++it) { + DataModel* dataModel = (*it)->create(); + registerDataModel(dataModel); + } + } +#else +#ifdef UMUNDO_FOUND + { + UmundoInvoker* invoker = new UmundoInvoker(); + registerInvoker(invoker); + } #endif #ifdef MILES_FOUND - { - SpatialAudio* invoker = new SpatialAudio(); - registerInvoker(invoker); - } + { + SpatialAudio* invoker = new SpatialAudio(); + registerInvoker(invoker); + } #endif #ifdef V8_FOUND - { - V8DataModel* dataModel = new V8DataModel(); - registerDataModel(dataModel); - } + { + V8DataModel* dataModel = new V8DataModel(); + registerDataModel(dataModel); + } #endif - // these are always available - { - USCXMLInvoker* invoker = new USCXMLInvoker(); - registerInvoker(invoker); - } - { - EventIOProcessor* ioProcessor = new EventIOProcessor(); - registerIOProcessor(ioProcessor); - } -#endif - } - - void Factory::registerIOProcessor(IOProcessor* ioProcessor) { - std::set<std::string> names = ioProcessor->getNames(); - std::set<std::string>::iterator nameIter = names.begin(); - while(nameIter != names.end()) { - _ioProcessors[*nameIter] = ioProcessor; - nameIter++; - } - } - - void Factory::registerDataModel(DataModel* dataModel) { - std::set<std::string> names = dataModel->getNames(); - std::set<std::string>::iterator nameIter = names.begin(); - while(nameIter != names.end()) { - _dataModels[*nameIter] = dataModel; - nameIter++; - } - } - - void Factory::registerInvoker(Invoker* invoker) { - std::set<std::string> names = invoker->getNames(); - std::set<std::string>::iterator nameIter = names.begin(); - while(nameIter != names.end()) { - _invokers[*nameIter] = invoker; - nameIter++; - } - } - - void Factory::registerExecutableContent(const std::string tag, ExecutableContent* executableContent) { - _executableContent[tag] = executableContent; - } - - Invoker* Factory::getInvoker(const std::string type, Interpreter* interpreter) { - if (Factory::getInstance()->_invokers.find(type) != getInstance()->_invokers.end()) { - return (Invoker*)getInstance()->_invokers[type]->create(interpreter); - } - return NULL; - } - - DataModel* Factory::getDataModel(const std::string type, Interpreter* interpreter) { - if (Factory::getInstance()->_dataModels.find(type) != getInstance()->_dataModels.end()) { - return getInstance()->_dataModels[type]->create(interpreter); - } - return NULL; - } - - IOProcessor* Factory::getIOProcessor(const std::string type, Interpreter* interpreter) { - if (getInstance()->_ioProcessors.find(type) != getInstance()->_ioProcessors.end()) { - return getInstance()->_ioProcessors[type]->create(interpreter); - } - return NULL; - } - - ExecutableContent* Factory::getExecutableContent(const std::string tag, Interpreter* interpreter) { - if (getInstance()->_executableContent.find(tag) != getInstance()->_executableContent.end()) { - return getInstance()->_executableContent[tag]->create(interpreter); - } - return NULL; - } - - Factory* Factory::getInstance() { - if (_instance == NULL) { - _instance = new Factory(); - } - return _instance; - } - - Factory* Factory::_instance = NULL; - std::string Factory::pluginPath; +#ifdef SWI_FOUND + { + SWIDataModel* dataModel = new SWIDataModel(); + registerDataModel(dataModel); + } +#endif + + // these are always available + { + USCXMLInvoker* invoker = new USCXMLInvoker(); + registerInvoker(invoker); + } + { + EventIOProcessor* ioProcessor = new EventIOProcessor(); + registerIOProcessor(ioProcessor); + } +#endif +} + +Factory::~Factory() { +#ifdef BUILD_AS_PLUGINS + pluma.unloadAll(); +#endif +} + +void Factory::registerIOProcessor(IOProcessor* ioProcessor) { + std::set<std::string> names = ioProcessor->getNames(); + std::set<std::string>::iterator nameIter = names.begin(); + while(nameIter != names.end()) { + _ioProcessors[*nameIter] = ioProcessor; + nameIter++; + } +} + +void Factory::registerDataModel(DataModel* dataModel) { + std::set<std::string> names = dataModel->getNames(); + std::set<std::string>::iterator nameIter = names.begin(); + while(nameIter != names.end()) { + _dataModels[*nameIter] = dataModel; + nameIter++; + } +} + +void Factory::registerInvoker(Invoker* invoker) { + std::set<std::string> names = invoker->getNames(); + std::set<std::string>::iterator nameIter = names.begin(); + while(nameIter != names.end()) { + _invokers[*nameIter] = invoker; + nameIter++; + } +} + +void Factory::registerExecutableContent(const std::string tag, ExecutableContent* executableContent) { + _executableContent[tag] = executableContent; +} + +Invoker* Factory::getInvoker(const std::string type, Interpreter* interpreter) { + Factory* factory = getInstance(); + if (factory->_invokers.find(type) != factory->_invokers.end()) { + return (Invoker*)factory->_invokers[type]->create(interpreter); + } + return NULL; +} + +DataModel* Factory::getDataModel(const std::string type, Interpreter* interpreter) { + Factory* factory = getInstance(); + if (factory->_dataModels.find(type) != factory->_dataModels.end()) { + return factory->_dataModels[type]->create(interpreter); + } + return NULL; +} + +IOProcessor* Factory::getIOProcessor(const std::string type, Interpreter* interpreter) { + Factory* factory = getInstance(); + if (factory->_ioProcessors.find(type) != factory->_ioProcessors.end()) { + return factory->_ioProcessors[type]->create(interpreter); + } + return NULL; +} + +ExecutableContent* Factory::getExecutableContent(const std::string tag, Interpreter* interpreter) { + Factory* factory = getInstance(); + if (factory->_executableContent.find(tag) != factory->_executableContent.end()) { + return factory->_executableContent[tag]->create(interpreter); + } + return NULL; +} + +Factory* Factory::getInstance() { + if (_instance == NULL) { + _instance = new Factory(); + } + return _instance; +} + +Factory* Factory::_instance = NULL; +std::string Factory::pluginPath; }
\ No newline at end of file diff --git a/src/uscxml/Factory.h b/src/uscxml/Factory.h index fcd907e..6385ba7 100644 --- a/src/uscxml/Factory.h +++ b/src/uscxml/Factory.h @@ -11,101 +11,106 @@ #include <set> namespace uscxml { - - // see http://stackoverflow.com/questions/228005/alternative-to-itoa-for-converting-integer-to-string-c - template <typename T> std::string toStr(T tmp) { - std::ostringstream out; - out << tmp; - return out.str(); - } - - template <typename T> T strTo(std::string tmp) { - T output; - std::istringstream in(tmp); - in >> output; - return output; - } - - class Interpreter; - - class ExecutableContent { - public: - ExecutableContent() {}; - virtual ExecutableContent* create(Interpreter* interpreter) = 0; - }; - - class IOProcessor { - public: - IOProcessor() {}; - virtual ~IOProcessor() {}; - virtual IOProcessor* create(Interpreter* interpreter) = 0; - virtual std::set<std::string> getNames() = 0; - - virtual void setInterpreter(Interpreter* interpreter) { _interpreter = interpreter; } - virtual Data getDataModelVariables() = 0; - virtual void send(SendRequest& req) = 0; - protected: - Interpreter* _interpreter; - }; - - class Invoker : public IOProcessor { - public: - virtual void invoke(InvokeRequest& req) = 0; - virtual void sendToParent(SendRequest& req) = 0; - }; - - class DataModel { - public: - virtual ~DataModel() {} - virtual DataModel* create(Interpreter* interpreter) = 0; - virtual std::set<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; - - // foreach - virtual uint32_t getLength(const std::string& expr) = 0; - virtual void pushContext() = 0; - virtual void popContext() = 0; - - virtual void eval(const std::string& expr) = 0; - virtual std::string evalAsString(const std::string& expr) = 0; - virtual bool evalAsBool(const std::string& expr) = 0; - virtual void assign(const std::string& location, const std::string& expr) = 0; - virtual void assign(const std::string& location, const Data& data) = 0; - }; - - class Factory { - public: - void registerIOProcessor(IOProcessor* ioProcessor); - void registerDataModel(DataModel* dataModel); - void registerInvoker(Invoker* invoker); - void registerExecutableContent(const std::string tag, ExecutableContent* executableContent); - - static DataModel* getDataModel(const std::string type, Interpreter* interpreter); - static IOProcessor* getIOProcessor(const std::string type, Interpreter* interpreter); - static ExecutableContent* getExecutableContent(const std::string tag, Interpreter* interpreter); - static Invoker* getInvoker(const std::string type, Interpreter* interpreter); - - static Factory* getInstance(); - - std::map<std::string, DataModel*> _dataModels; - std::map<std::string, IOProcessor*> _ioProcessors; - std::map<std::string, Invoker*> _invokers; - std::map<std::string, ExecutableContent*> _executableContent; - - static std::string pluginPath; - - protected: + +// see http://stackoverflow.com/questions/228005/alternative-to-itoa-for-converting-integer-to-string-c +template <typename T> std::string toStr(T tmp) { + std::ostringstream out; + out << tmp; + return out.str(); +} + +template <typename T> T strTo(std::string tmp) { + T output; + std::istringstream in(tmp); + in >> output; + return output; +} + +class Interpreter; + +class ExecutableContent { +public: + ExecutableContent() {}; + virtual ExecutableContent* create(Interpreter* interpreter) = 0; +}; + +class IOProcessor { +public: + IOProcessor() {}; + virtual ~IOProcessor() {}; + virtual IOProcessor* create(Interpreter* interpreter) = 0; + virtual std::set<std::string> getNames() = 0; + + virtual void setInterpreter(Interpreter* interpreter) { + _interpreter = interpreter; + } + virtual Data getDataModelVariables() = 0; + virtual void send(SendRequest& req) = 0; +protected: + Interpreter* _interpreter; +}; + +class Invoker : public IOProcessor { +public: + virtual void invoke(InvokeRequest& req) = 0; + virtual void sendToParent(SendRequest& req) = 0; +}; + +class DataModel { +public: + virtual ~DataModel() {} + virtual DataModel* create(Interpreter* interpreter) = 0; + virtual std::set<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; + + virtual void registerIOProcessor(const std::string& name, IOProcessor* ioprocessor) = 0; + + // foreach + virtual uint32_t getLength(const std::string& expr) = 0; + virtual void pushContext() = 0; + virtual void popContext() = 0; + + virtual void eval(const std::string& expr) = 0; + virtual std::string evalAsString(const std::string& expr) = 0; + virtual bool evalAsBool(const std::string& expr) = 0; + virtual void assign(const std::string& location, const std::string& expr) = 0; + virtual void assign(const std::string& location, const Data& data) = 0; +}; + +class Factory { +public: + void registerIOProcessor(IOProcessor* ioProcessor); + void registerDataModel(DataModel* dataModel); + void registerInvoker(Invoker* invoker); + void registerExecutableContent(const std::string tag, ExecutableContent* executableContent); + + static DataModel* getDataModel(const std::string type, Interpreter* interpreter); + static IOProcessor* getIOProcessor(const std::string type, Interpreter* interpreter); + static ExecutableContent* getExecutableContent(const std::string tag, Interpreter* interpreter); + static Invoker* getInvoker(const std::string type, Interpreter* interpreter); + + static Factory* getInstance(); + + std::map<std::string, DataModel*> _dataModels; + std::map<std::string, IOProcessor*> _ioProcessors; + std::map<std::string, Invoker*> _invokers; + std::map<std::string, ExecutableContent*> _executableContent; + + static std::string pluginPath; + +protected: #ifdef BUILD_AS_PLUGINS - pluma::Pluma pluma; + pluma::Pluma pluma; #endif - - Factory(); - static Factory* _instance; - }; + Factory(); + ~Factory(); + static Factory* _instance; + +}; } diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 17d499a..604921a 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -25,7 +25,7 @@ using namespace Arabica::DOM; boost::uuids::random_generator Interpreter::uuidGen; const std::string Interpreter::getUUID() { - return boost::lexical_cast<std::string>(uuidGen()); + return boost::lexical_cast<std::string>(uuidGen()); } Interpreter::Interpreter() { @@ -34,1166 +34,1171 @@ Interpreter::Interpreter() { WSAStartup(MAKEWORD(2, 2), &wsaData); #endif } - + Interpreter* Interpreter::fromDOM(const Arabica::DOM::Node<std::string>& node) { - Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); - Interpreter* interpreter = new Interpreter(); - interpreter->_doc = domFactory.createDocument("http://www.w3.org/2005/07/scxml", "scxml", 0); - interpreter->_doc.appendChild(node); - interpreter->init(); + Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); + Interpreter* interpreter = new Interpreter(); + interpreter->_doc = domFactory.createDocument("http://www.w3.org/2005/07/scxml", "scxml", 0); + interpreter->_doc.appendChild(node); + interpreter->init(); - return interpreter; + return interpreter; } Interpreter* Interpreter::fromXML(const std::string& xml) { - std::istringstream is(xml); - Arabica::SAX::InputSource<std::string> inputSource; - return fromInputSource(inputSource); + std::istringstream is(xml); + Arabica::SAX::InputSource<std::string> inputSource; + return fromInputSource(inputSource); } Interpreter* Interpreter::fromURI(const std::string& uri) { - Arabica::SAX::InputSource<std::string> inputSource(uri); - Interpreter* interpreter = fromInputSource(inputSource); + Arabica::SAX::InputSource<std::string> inputSource(uri); + Interpreter* interpreter = fromInputSource(inputSource); - // try to establish URI root for relative src attributes in document - interpreter->_baseURI = toBaseURI(Arabica::io::URI(uri)); - return interpreter; + // try to establish URI root for relative src attributes in document + interpreter->_baseURI = toBaseURI(Arabica::io::URI(uri)); + return interpreter; } Arabica::io::URI Interpreter::toBaseURI(const Arabica::io::URI& uri) { - std::stringstream ssBaseURI; - if (uri.scheme().size() > 0) { - ssBaseURI << uri.scheme() << "://"; - } else { - ssBaseURI << "file://"; - } - if (uri.host().size() > 0) { - ssBaseURI << uri.host(); - if (!boost::iequals(uri.port(), "0")) - ssBaseURI << ":" << uri.port(); - } - if (uri.path().size() > 0) { - std::string uriPath = uri.path(); - uriPath = uriPath.substr(0, uriPath.find_last_of("/\\")); - ssBaseURI << uriPath; - } - return Arabica::io::URI(ssBaseURI.str()); + std::stringstream ssBaseURI; + if (uri.scheme().size() > 0) { + ssBaseURI << uri.scheme() << "://"; + } else { + ssBaseURI << "file://"; + } + if (uri.host().size() > 0) { + ssBaseURI << uri.host(); + if (!boost::iequals(uri.port(), "0")) + ssBaseURI << ":" << uri.port(); + } + if (uri.path().size() > 0) { + std::string uriPath = uri.path(); + uriPath = uriPath.substr(0, uriPath.find_last_of("/\\")); + ssBaseURI << uriPath; + } + return Arabica::io::URI(ssBaseURI.str()); } bool Interpreter::makeAbsolute(Arabica::io::URI& uri) { - if (uri.is_absolute()) - return true; - - if (_baseURI.as_string().size() > 0) { - std::stringstream ssAbsoluteURI; - if (_baseURI.scheme().size() > 0) - ssAbsoluteURI << _baseURI.scheme() << "://"; - if (_baseURI.host().size() > 0) { - ssAbsoluteURI << _baseURI.host(); - if (!boost::iequals(_baseURI.port(), "0")) - ssAbsoluteURI << ":" << _baseURI.port(); - } - if (_baseURI.path().size() > 0) { - ssAbsoluteURI << _baseURI.path() << "/" << uri.path(); - } - uri = Arabica::io::URI(ssAbsoluteURI.str()); - return true; - } - return false; + if (uri.is_absolute()) + return true; + + if (_baseURI.as_string().size() > 0) { + std::stringstream ssAbsoluteURI; + if (_baseURI.scheme().size() > 0) + ssAbsoluteURI << _baseURI.scheme() << "://"; + if (_baseURI.host().size() > 0) { + ssAbsoluteURI << _baseURI.host(); + if (!boost::iequals(_baseURI.port(), "0")) + ssAbsoluteURI << ":" << _baseURI.port(); + } + if (_baseURI.path().size() > 0) { + ssAbsoluteURI << _baseURI.path() << "/" << uri.path(); + } + uri = Arabica::io::URI(ssAbsoluteURI.str()); + return true; + } + return false; } Interpreter* Interpreter::fromInputSource(Arabica::SAX::InputSource<std::string>& source) { - Interpreter* interpreter = new Interpreter(); - - Arabica::SAX2DOM::Parser<std::string> domParser; - Arabica::SAX::CatchErrorHandler<std::string> errorHandler; - domParser.setErrorHandler(errorHandler); - if(!domParser.parse(source) || !domParser.getDocument().hasChildNodes()) { - LOG(INFO) << "could not parse input:"; - if(errorHandler.errorsReported()) { - LOG(ERROR) << errorHandler.errors() << std::endl; - } else { - Arabica::SAX::InputSourceResolver resolver(source, Arabica::default_string_adaptor<std::string>()); - if (!resolver.resolve()) { - LOG(ERROR) << "no such file"; - } - } - } else { - interpreter->_doc = domParser.getDocument(); - } - interpreter->init(); - return interpreter; + Interpreter* interpreter = new Interpreter(); + + Arabica::SAX2DOM::Parser<std::string> domParser; + Arabica::SAX::CatchErrorHandler<std::string> errorHandler; + domParser.setErrorHandler(errorHandler); + if(!domParser.parse(source) || !domParser.getDocument().hasChildNodes()) { + LOG(INFO) << "could not parse input:"; + if(errorHandler.errorsReported()) { + LOG(ERROR) << errorHandler.errors() << std::endl; + } else { + Arabica::SAX::InputSourceResolver resolver(source, Arabica::default_string_adaptor<std::string>()); + if (!resolver.resolve()) { + LOG(ERROR) << "no such file"; + } + } + } else { + interpreter->_doc = domParser.getDocument(); + } + interpreter->init(); + return interpreter; } void Interpreter::init() { _thread = NULL; - _dataModel = NULL; - _invoker = NULL; - _running = false; - _sendQueue = new DelayedEventQueue(); - _sendQueue->start(); - if (_doc) { - // do we have a xmlns attribute? - std::string ns = _doc.getDocumentElement().getNamespaceURI(); - if(ns.size() > 0) { - _nsContext.addNamespaceDeclaration(ns, "sc"); - _xpath.setNamespaceContext(_nsContext); - _nsPrefix = "sc:"; - } - NodeList<std::string> scxmls = _doc.getElementsByTagName("scxml"); - if (scxmls.getLength() > 0) { - _scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0); - normalize(_doc); - _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : getUUID()); - } else { - LOG(ERROR) << "Cannot find SCXML element" << std::endl; - } - } + _dataModel = NULL; + _invoker = NULL; + _running = false; + _sendQueue = new DelayedEventQueue(); + _sendQueue->start(); + if (_doc) { + // do we have a xmlns attribute? + std::string ns = _doc.getDocumentElement().getNamespaceURI(); + if(ns.size() > 0) { + _nsContext.addNamespaceDeclaration(ns, "sc"); + _xpath.setNamespaceContext(_nsContext); + _nsPrefix = "sc:"; + } + NodeList<std::string> scxmls = _doc.getElementsByTagName("scxml"); + if (scxmls.getLength() > 0) { + _scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0); + normalize(_doc); + _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : getUUID()); + } else { + LOG(ERROR) << "Cannot find SCXML element" << std::endl; + } + } } Interpreter::~Interpreter() { - std::map<std::string, IOProcessor*>::iterator ioProcessorIter = _ioProcessors.begin(); - while(ioProcessorIter != _ioProcessors.end()) { - delete ioProcessorIter->second; - ioProcessorIter++; - } + std::map<std::string, IOProcessor*>::iterator ioProcessorIter = _ioProcessors.begin(); + while(ioProcessorIter != _ioProcessors.end()) { + delete ioProcessorIter->second; + ioProcessorIter++; + } if (_thread) { - _running = false; - _externalQueue.push(Event()); - _thread->join(); + _running = false; + _externalQueue.push(Event()); + _thread->join(); delete(_thread); } - delete _dataModel; - delete _sendQueue; + delete _dataModel; + delete _sendQueue; } void Interpreter::start() { - _thread = new tthread::thread(Interpreter::run, this); + _thread = new tthread::thread(Interpreter::run, this); } - + void Interpreter::run(void* instance) { ((Interpreter*)instance)->interpret(); } void Interpreter::waitForStabilization() { - tthread::lock_guard<tthread::mutex> lock(_mutex); - _stabilized.wait(_mutex); + tthread::lock_guard<tthread::mutex> lock(_mutex); + _stabilized.wait(_mutex); } - + // see: http://www.w3.org/TR/scxml/#AlgorithmforSCXMLInterpretation void Interpreter::interpret() { - if (!_scxml) - return; + if (!_scxml) + return; // dump(); - _sessionId = getUUID(); - - if(HAS_ATTR(_scxml, "datamodel")) { + _sessionId = getUUID(); + + if(HAS_ATTR(_scxml, "datamodel")) { _dataModel = Factory::getDataModel(ATTR(_scxml, "datamodel"), this); if(_dataModel == NULL) { - LOG(ERROR) << "No datamodel for " << ATTR(_scxml, "datamodel") << " registered"; - return; - } - } + LOG(ERROR) << "No datamodel for " << ATTR(_scxml, "datamodel") << " registered"; + return; + } + } - setupIOProcessors(); + setupIOProcessors(); - // executeGlobalScriptElements - NodeSet<std::string> globalScriptElems = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "script", _doc).asNodeSet(); - for (unsigned int i = 0; i < globalScriptElems.size(); i++) { + // executeGlobalScriptElements + NodeSet<std::string> globalScriptElems = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "script", _doc).asNodeSet(); + for (unsigned int i = 0; i < globalScriptElems.size(); i++) { // std::cout << globalScriptElems[i].getFirstChild().getNodeValue() << std::endl; - if (_dataModel) - executeContent(globalScriptElems[i]); - } - - _running = true; - - std::string binding = _xpath.evaluate("/" + _nsPrefix + "scxml/@binding", _doc).asString(); - _binding = (boost::iequals(binding, "late") ? LATE : EARLY); - - // initialize all data elements - if (_dataModel && _binding == EARLY) { - NodeSet<std::string> dataElems = _xpath.evaluate("//" + _nsPrefix + "data", _doc).asNodeSet(); - for (unsigned int i = 0; i < dataElems.size(); i++) { - initializeData(dataElems[i]); - } - } else if(_dataModel) { - NodeSet<std::string> topDataElems = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "datamodel/" + _nsPrefix + "data", _doc).asNodeSet(); - for (unsigned int i = 0; i < topDataElems.size(); i++) { - initializeData(topDataElems[i]); - } - } - - // we made sure during normalization that this element exists - NodeSet<std::string> initialTransitions = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "initial/" + _nsPrefix + "transition", _doc).asNodeSet(); - assert(initialTransitions.size() > 0); - initialTransitions.push_back(initialTransitions[0]); - enterStates(initialTransitions); - - mainEventLoop(); + if (_dataModel) + executeContent(globalScriptElems[i]); + } + + _running = true; + + std::string binding = _xpath.evaluate("/" + _nsPrefix + "scxml/@binding", _doc).asString(); + _binding = (boost::iequals(binding, "late") ? LATE : EARLY); + + // initialize all data elements + if (_dataModel && _binding == EARLY) { + NodeSet<std::string> dataElems = _xpath.evaluate("//" + _nsPrefix + "data", _doc).asNodeSet(); + for (unsigned int i = 0; i < dataElems.size(); i++) { + initializeData(dataElems[i]); + } + } else if(_dataModel) { + NodeSet<std::string> topDataElems = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "datamodel/" + _nsPrefix + "data", _doc).asNodeSet(); + for (unsigned int i = 0; i < topDataElems.size(); i++) { + initializeData(topDataElems[i]); + } + } + + // we made sure during normalization that this element exists + NodeSet<std::string> initialTransitions = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "initial/" + _nsPrefix + "transition", _doc).asNodeSet(); + assert(initialTransitions.size() > 0); + initialTransitions.push_back(initialTransitions[0]); + enterStates(initialTransitions); + + mainEventLoop(); } /** * Called with a single data element from the topmost datamodel element. */ void Interpreter::initializeData(const Arabica::DOM::Node<std::string>& data) { - if (!_dataModel) { - LOG(ERROR) << "Cannot initialize data when no datamodel is given!"; - return; - } - try { - if (!HAS_ATTR(data, "id")) - return; - - if (HAS_ATTR(data, "expr")) { - std::string value = ATTR(data, "expr"); - _dataModel->assign(ATTR(data, "id"), value); - } else if (HAS_ATTR(data, "src")) { - Arabica::SAX::InputSourceResolver resolver(Arabica::SAX::InputSource<std::string>(ATTR(data, "src")), - Arabica::default_string_adaptor<std::string>()); - std::string value = std::string(std::istreambuf_iterator<char>(*resolver.resolve()), std::istreambuf_iterator<char>()); - _dataModel->assign(ATTR(data, "id"), value); - } else if (data.hasChildNodes()) { - // search for the text node with the actual script - NodeList<std::string> dataChilds = data.getChildNodes(); - for (int i = 0; i < dataChilds.getLength(); i++) { - if (dataChilds.item(i).getNodeType() == Node_base::TEXT_NODE) { - Data value = Data(dataChilds.item(i).getNodeValue()); - _dataModel->assign(ATTR(data, "id"), value); - break; - } - } + if (!_dataModel) { + LOG(ERROR) << "Cannot initialize data when no datamodel is given!"; + return; + } + try { + if (!HAS_ATTR(data, "id")) + return; + + if (HAS_ATTR(data, "expr")) { + std::string value = ATTR(data, "expr"); + _dataModel->assign(ATTR(data, "id"), value); + } else if (HAS_ATTR(data, "src")) { + Arabica::SAX::InputSourceResolver resolver(Arabica::SAX::InputSource<std::string>(ATTR(data, "src")), + Arabica::default_string_adaptor<std::string>()); + std::string value = std::string(std::istreambuf_iterator<char>(*resolver.resolve()), std::istreambuf_iterator<char>()); + _dataModel->assign(ATTR(data, "id"), value); + } else if (data.hasChildNodes()) { + // search for the text node with the actual script + NodeList<std::string> dataChilds = data.getChildNodes(); + for (int i = 0; i < dataChilds.getLength(); i++) { + if (dataChilds.item(i).getNodeType() == Node_base::TEXT_NODE) { + Data value = Data(dataChilds.item(i).getNodeValue()); + _dataModel->assign(ATTR(data, "id"), value); + break; + } + } // std::cout << value << std::endl; - } - - } catch (Event e) { - LOG(ERROR) << "Syntax error in send element:" << std::endl << e << std::endl; - } + } + + } catch (Event e) { + LOG(ERROR) << "Syntax error in send element:" << std::endl << e << std::endl; + } } void Interpreter::normalize(const Arabica::DOM::Document<std::string>& node) { - // make sure every state has an id and set isFirstEntry to true - Arabica::XPath::NodeSet<std::string> states = _xpath.evaluate("//" + _nsPrefix + "state", _doc).asNodeSet(); - for (int i = 0; i < states.size(); i++) { - Arabica::DOM::Element<std::string> stateElem = Arabica::DOM::Element<std::string>(states[i]); - stateElem.setAttribute("isFirstEntry", "true"); - if (!stateElem.hasAttribute("id")) { - stateElem.setAttribute("id", getUUID()); - } - } - - // make sure every invoke has an idlocation or id - Arabica::XPath::NodeSet<std::string> invokes = _xpath.evaluate("//" + _nsPrefix + "invoke", _doc).asNodeSet(); - for (int i = 0; i < invokes.size(); i++) { - Arabica::DOM::Element<std::string> invokeElem = Arabica::DOM::Element<std::string>(invokes[i]); - if (!invokeElem.hasAttribute("id") && !invokeElem.hasAttribute("idlocation")) { - invokeElem.setAttribute("id", getUUID()); - } + // make sure every state has an id and set isFirstEntry to true + Arabica::XPath::NodeSet<std::string> states = _xpath.evaluate("//" + _nsPrefix + "state", _doc).asNodeSet(); + for (int i = 0; i < states.size(); i++) { + Arabica::DOM::Element<std::string> stateElem = Arabica::DOM::Element<std::string>(states[i]); + stateElem.setAttribute("isFirstEntry", "true"); + if (!stateElem.hasAttribute("id")) { + stateElem.setAttribute("id", getUUID()); + } + } + + // make sure every invoke has an idlocation or id + Arabica::XPath::NodeSet<std::string> invokes = _xpath.evaluate("//" + _nsPrefix + "invoke", _doc).asNodeSet(); + for (int i = 0; i < invokes.size(); i++) { + Arabica::DOM::Element<std::string> invokeElem = Arabica::DOM::Element<std::string>(invokes[i]); + if (!invokeElem.hasAttribute("id") && !invokeElem.hasAttribute("idlocation")) { + invokeElem.setAttribute("id", getUUID()); + } // // make sure every finalize element contained has the invoke id as an attribute // Arabica::XPath::NodeSet<std::string> finalizes = _xpath.evaluate("" + _nsPrefix + "finalize", invokeElem).asNodeSet(); // for (int j = 0; j < finalizes.size(); j++) { // Arabica::DOM::Element<std::string> finalizeElem = Arabica::DOM::Element<std::string>(finalizes[j]); // finalizeElem.setAttribute("invokeid", invokeElem.getAttribute("id")); // } - } - - Arabica::XPath::NodeSet<std::string> finals = _xpath.evaluate("//" + _nsPrefix + "final", _doc).asNodeSet(); - for (int i = 0; i < finals.size(); i++) { - Arabica::DOM::Element<std::string> finalElem = Arabica::DOM::Element<std::string>(finals[i]); - finalElem.setAttribute("isFirstEntry", "true"); - if (!finalElem.hasAttribute("id")) { - finalElem.setAttribute("id", getUUID()); - } - } - - Arabica::XPath::NodeSet<std::string> histories = _xpath.evaluate("//" + _nsPrefix + "history", _doc).asNodeSet(); - for (int i = 0; i < histories.size(); i++) { - Arabica::DOM::Element<std::string> historyElem = Arabica::DOM::Element<std::string>(histories[i]); - if (!historyElem.hasAttribute("id")) { - historyElem.setAttribute("id", getUUID()); - } - } - - Arabica::XPath::NodeSet<std::string> scxml = _xpath.evaluate("/" + _nsPrefix + "scxml", _doc).asNodeSet(); - if (!((Arabica::DOM::Element<std::string>)scxml[0]).hasAttribute("id")) { - ((Arabica::DOM::Element<std::string>)scxml[0]).setAttribute("id", getUUID()); - } - - // create a pseudo initial and transition element - Arabica::DOM::Element<std::string> initialState = (Arabica::DOM::Element<std::string>)getInitialState(); - Arabica::DOM::Element<std::string> initialElem = _doc.createElement("initial"); - Arabica::DOM::Element<std::string> transitionElem = _doc.createElement("transition"); - transitionElem.setAttribute("target", initialState.getAttribute("id")); - initialElem.appendChild(transitionElem); - _scxml.appendChild(initialElem); - -} - + } + + Arabica::XPath::NodeSet<std::string> finals = _xpath.evaluate("//" + _nsPrefix + "final", _doc).asNodeSet(); + for (int i = 0; i < finals.size(); i++) { + Arabica::DOM::Element<std::string> finalElem = Arabica::DOM::Element<std::string>(finals[i]); + finalElem.setAttribute("isFirstEntry", "true"); + if (!finalElem.hasAttribute("id")) { + finalElem.setAttribute("id", getUUID()); + } + } + + Arabica::XPath::NodeSet<std::string> histories = _xpath.evaluate("//" + _nsPrefix + "history", _doc).asNodeSet(); + for (int i = 0; i < histories.size(); i++) { + Arabica::DOM::Element<std::string> historyElem = Arabica::DOM::Element<std::string>(histories[i]); + if (!historyElem.hasAttribute("id")) { + historyElem.setAttribute("id", getUUID()); + } + } + + Arabica::XPath::NodeSet<std::string> scxml = _xpath.evaluate("/" + _nsPrefix + "scxml", _doc).asNodeSet(); + if (!((Arabica::DOM::Element<std::string>)scxml[0]).hasAttribute("id")) { + ((Arabica::DOM::Element<std::string>)scxml[0]).setAttribute("id", getUUID()); + } + + // create a pseudo initial and transition element + Arabica::DOM::Element<std::string> initialState = (Arabica::DOM::Element<std::string>)getInitialState(); + Arabica::DOM::Element<std::string> initialElem = _doc.createElement("initial"); + Arabica::DOM::Element<std::string> transitionElem = _doc.createElement("transition"); + transitionElem.setAttribute("target", initialState.getAttribute("id")); + initialElem.appendChild(transitionElem); + _scxml.appendChild(initialElem); + +} + void Interpreter::mainEventLoop() { - while(_running) { - NodeSet<std::string> enabledTransitions; - _stable = false; + while(_running) { + NodeSet<std::string> enabledTransitions; + _stable = false; - // Here we handle eventless transitions and transitions - // triggered by internal events until machine is stable - while(_running && !_stable) { + // Here we handle eventless transitions and transitions + // triggered by internal events until machine is stable + while(_running && !_stable) { #if 0 - std::cout << "Configuration: "; - for (int i = 0; i < _configuration.size(); i++) { - std::cout << ((Arabica::DOM::Element<std::string>)_configuration[i]).getAttribute("id") << ", "; - } - std::cout << std::endl; + std::cout << "Configuration: "; + for (int i = 0; i < _configuration.size(); i++) { + std::cout << ((Arabica::DOM::Element<std::string>)_configuration[i]).getAttribute("id") << ", "; + } + std::cout << std::endl; #endif - enabledTransitions = selectEventlessTransitions(); - if (enabledTransitions.size() == 0) { - if (_internalQueue.size() == 0) { - _stable = true; - } else { - Event internalEvent = _internalQueue.front(); - _internalQueue.pop_front(); + enabledTransitions = selectEventlessTransitions(); + if (enabledTransitions.size() == 0) { + if (_internalQueue.size() == 0) { + _stable = true; + } else { + Event internalEvent = _internalQueue.front(); + _internalQueue.pop_front(); #if 0 - std::cout << "Received internal event " << internalEvent.name << std::endl; + std::cout << "Received internal event " << internalEvent.name << std::endl; #endif - if (_dataModel) - _dataModel->setEvent(internalEvent); - enabledTransitions = selectTransitions(internalEvent.name); - } - } - if (!enabledTransitions.empty()) - microstep(enabledTransitions); - } - - for (unsigned int i = 0; i < _statesToInvoke.size(); i++) { - NodeSet<std::string> invokes = _xpath.evaluate("" + _nsPrefix + "invoke", _statesToInvoke[i]).asNodeSet(); - for (unsigned int j = 0; j < invokes.size(); j++) { - invoke(invokes[j]); - } - } - - _statesToInvoke = NodeSet<std::string>(); - if (!_internalQueue.empty()) - continue; - - { - tthread::lock_guard<tthread::mutex> lock(_mutex); - _stabilized.notify_all(); - } - - Event externalEvent = _externalQueue.pop(); - if (!_running) - exitInterpreter(); - - if (_dataModel && boost::iequals(externalEvent.name, "cancel.invoke." + _sessionId)) - break; - - if (_dataModel) - try { - _dataModel->setEvent(externalEvent); - } catch (Event e) { - LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl; - } - for (unsigned int i = 0; i < _configuration.size(); i++) { - NodeSet<std::string> invokes = _xpath.evaluate("" + _nsPrefix + "invoke", _configuration[i]).asNodeSet(); - for (unsigned int j = 0; j < invokes.size(); j++) { - Arabica::DOM::Element<std::string> invokeElem = (Arabica::DOM::Element<std::string>)invokes[j]; - std::string invokeId = invokeElem.getAttribute("id"); - std::string autoForward = invokeElem.getAttribute("autoforward"); - if (boost::iequals(invokeId, externalEvent.invokeid)) { - - Arabica::XPath::NodeSet<std::string> finalizes = _xpath.evaluate("" + _nsPrefix + "finalize", invokeElem).asNodeSet(); - for (int k = 0; k < finalizes.size(); k++) { - Arabica::DOM::Element<std::string> finalizeElem = Arabica::DOM::Element<std::string>(finalizes[k]); - executeContent(finalizeElem); - } - - - } - if (autoForward.length() > 0) { - // @TODO + if (_dataModel) + _dataModel->setEvent(internalEvent); + enabledTransitions = selectTransitions(internalEvent.name); + } + } + if (!enabledTransitions.empty()) + microstep(enabledTransitions); + } + + for (unsigned int i = 0; i < _statesToInvoke.size(); i++) { + NodeSet<std::string> invokes = _xpath.evaluate("" + _nsPrefix + "invoke", _statesToInvoke[i]).asNodeSet(); + for (unsigned int j = 0; j < invokes.size(); j++) { + invoke(invokes[j]); + } + } + + _statesToInvoke = NodeSet<std::string>(); + if (!_internalQueue.empty()) + continue; + + { + tthread::lock_guard<tthread::mutex> lock(_mutex); + _stabilized.notify_all(); + } + + Event externalEvent = _externalQueue.pop(); + if (!_running) + exitInterpreter(); + + if (_dataModel && boost::iequals(externalEvent.name, "cancel.invoke." + _sessionId)) + break; + + if (_dataModel) + try { + _dataModel->setEvent(externalEvent); + } catch (Event e) { + LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl; + } + for (unsigned int i = 0; i < _configuration.size(); i++) { + NodeSet<std::string> invokes = _xpath.evaluate("" + _nsPrefix + "invoke", _configuration[i]).asNodeSet(); + for (unsigned int j = 0; j < invokes.size(); j++) { + Arabica::DOM::Element<std::string> invokeElem = (Arabica::DOM::Element<std::string>)invokes[j]; + std::string invokeId = invokeElem.getAttribute("id"); + std::string autoForward = invokeElem.getAttribute("autoforward"); + if (boost::iequals(invokeId, externalEvent.invokeid)) { + + Arabica::XPath::NodeSet<std::string> finalizes = _xpath.evaluate("" + _nsPrefix + "finalize", invokeElem).asNodeSet(); + for (int k = 0; k < finalizes.size(); k++) { + Arabica::DOM::Element<std::string> finalizeElem = Arabica::DOM::Element<std::string>(finalizes[k]); + executeContent(finalizeElem); + } + + + } + if (autoForward.length() > 0) { + // @TODO // send(invokeId, externalEvent); - } - } - } - enabledTransitions = selectTransitions(externalEvent.name); - if (!enabledTransitions.empty()) - microstep(enabledTransitions); - } - exitInterpreter(); + } + } + } + enabledTransitions = selectTransitions(externalEvent.name); + if (!enabledTransitions.empty()) + microstep(enabledTransitions); + } + exitInterpreter(); } void Interpreter::internalDoneSend(const Arabica::DOM::Node<std::string>& state) { - if (!isState(state)) - return; - - Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state; - Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)stateElem.getParentNode(); - Event event; - - Arabica::XPath::NodeSet<std::string> doneDatas = _xpath.evaluate("" + _nsPrefix + "donedata", stateElem).asNodeSet(); - if (doneDatas.size() > 0) { - // only process first donedata element - Arabica::DOM::Node<std::string> doneData = doneDatas[0]; - NodeList<std::string> doneChilds = doneData.getChildNodes(); - for (int i = 0; i < doneChilds.getLength(); i++) { - if (!doneChilds.item(i).getNodeType() == Node_base::ELEMENT_NODE) - continue; - if (boost::iequals(TAGNAME(doneChilds.item(i)), "param")) { - if (!HAS_ATTR(doneChilds.item(i), "name")) { - LOG(ERROR) << "param element is missing name attribut"; - continue; - } - std::string paramValue; - if (HAS_ATTR(doneChilds.item(i), "expr") && _dataModel) { - std::string location = _dataModel->evalAsString(ATTR(doneChilds.item(i), "expr")); - paramValue = _dataModel->evalAsString(location); - } else if(HAS_ATTR(doneChilds.item(i), "location") && _dataModel) { - paramValue = _dataModel->evalAsString(ATTR(doneChilds.item(i), "location")); - } else { - LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; - continue; - } - event.compound[ATTR(doneChilds.item(i), "name")] = paramValue; - } - if (boost::iequals(TAGNAME(doneChilds.item(i)), "content")) { - if (HAS_ATTR(doneChilds.item(i), "expr")) { - if (_dataModel) { - event.compound["content"] = Data(_dataModel->evalAsString(ATTR(doneChilds.item(i), "expr")), Data::VERBATIM); - } else { - LOG(ERROR) << "content element has expr attribute but no datamodel is specified."; - } - } else if (doneChilds.item(i).hasChildNodes()) { - event.compound["content"] = Data(doneChilds.item(i).getFirstChild().getNodeValue(), Data::VERBATIM); - } else { - LOG(ERROR) << "content element does not specify any content."; - } - - } - } - } - - event.name = "done.state." + parent.getAttribute("id"); - _internalQueue.push_back(event); - -} - + if (!isState(state)) + return; + + Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state; + Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)stateElem.getParentNode(); + Event event; + + Arabica::XPath::NodeSet<std::string> doneDatas = _xpath.evaluate("" + _nsPrefix + "donedata", stateElem).asNodeSet(); + if (doneDatas.size() > 0) { + // only process first donedata element + Arabica::DOM::Node<std::string> doneData = doneDatas[0]; + NodeList<std::string> doneChilds = doneData.getChildNodes(); + for (int i = 0; i < doneChilds.getLength(); i++) { + if (!doneChilds.item(i).getNodeType() == Node_base::ELEMENT_NODE) + continue; + if (boost::iequals(TAGNAME(doneChilds.item(i)), "param")) { + if (!HAS_ATTR(doneChilds.item(i), "name")) { + LOG(ERROR) << "param element is missing name attribut"; + continue; + } + std::string paramValue; + if (HAS_ATTR(doneChilds.item(i), "expr") && _dataModel) { + std::string location = _dataModel->evalAsString(ATTR(doneChilds.item(i), "expr")); + paramValue = _dataModel->evalAsString(location); + } else if(HAS_ATTR(doneChilds.item(i), "location") && _dataModel) { + paramValue = _dataModel->evalAsString(ATTR(doneChilds.item(i), "location")); + } else { + LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; + continue; + } + event.compound[ATTR(doneChilds.item(i), "name")] = paramValue; + } + if (boost::iequals(TAGNAME(doneChilds.item(i)), "content")) { + if (HAS_ATTR(doneChilds.item(i), "expr")) { + if (_dataModel) { + event.compound["content"] = Data(_dataModel->evalAsString(ATTR(doneChilds.item(i), "expr")), Data::VERBATIM); + } else { + LOG(ERROR) << "content element has expr attribute but no datamodel is specified."; + } + } else if (doneChilds.item(i).hasChildNodes()) { + event.compound["content"] = Data(doneChilds.item(i).getFirstChild().getNodeValue(), Data::VERBATIM); + } else { + LOG(ERROR) << "content element does not specify any content."; + } + + } + } + } + + event.name = "done.state." + parent.getAttribute("id"); + _internalQueue.push_back(event); + +} + void Interpreter::send(const Arabica::DOM::Node<std::string>& element) { - SendRequest sendReq; - try { - // event - if (HAS_ATTR(element, "eventexpr") && _dataModel) { - sendReq.name = _dataModel->evalAsString(ATTR(element, "eventexpr")); - } else if (HAS_ATTR(element, "event")) { - sendReq.name = ATTR(element, "event"); - } - // target - if (HAS_ATTR(element, "targetexpr") && _dataModel) { - sendReq.target = _dataModel->evalAsString(ATTR(element, "targetexpr")); - } else if (HAS_ATTR(element, "target")) { - sendReq.target = ATTR(element, "target"); - } - // type - if (HAS_ATTR(element, "typeexpr") && _dataModel) { - sendReq.type = _dataModel->evalAsString(ATTR(element, "typeexpr")); - } else if (HAS_ATTR(element, "type")) { - sendReq.type = ATTR(element, "type"); - } else { - sendReq.type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; - } - // id - if (HAS_ATTR(element, "idlocation") && _dataModel) { - sendReq.sendid = _dataModel->evalAsString(ATTR(element, "idlocation")); - } else if (HAS_ATTR(element, "id")) { - sendReq.sendid = ATTR(element, "id"); - } else { - /* - * The ids for <send> and <invoke> are subtly different. In a conformant - * SCXML document, they must be unique within the session, but in the case - * where the author does not provide them, the processor must generate a - * new unique ID not at load time but each time the element is executed. - * Furthermore the attribute 'idlocation' can be used to capture this - * automatically generated id. Finally note that the automatically generated - * id for <invoke> has a special format. See 6.4.1 Attribute Details for - * details. The SCXML processor may generate all other ids in any format, - * as long as they are unique. - */ - sendReq.sendid = getUUID(); - } - /** @TODO: - * - * If 'idlocation' is present, the SCXML Processor must generate an id when - * the parent <send> element is evaluated and store it in this location. - * See 3.14 IDs for details. - * - */ - - // delay - std::string delay; - sendReq.delayMs = 0; - if (HAS_ATTR(element, "delayexpr") && _dataModel) { - delay = _dataModel->evalAsString(ATTR(element, "delayexpr")); - } else if (HAS_ATTR(element, "delay")) { - delay = ATTR(element, "delay"); - } - if (delay.size() > 0) { - boost::trim(delay); - std::stringstream delayTime; - if (delay.size() > 2 && boost::iequals("ms", delay.substr(delay.length() - 2, 2))) { - delayTime << delay.substr(0, delay.size() - 2); - delayTime >> sendReq.delayMs; - } else if (delay.size() > 1 && boost::iequals("s", delay.substr(delay.length() - 1, 1))) { - delayTime << delay.substr(0, delay.size() - 1); - delayTime >> sendReq.delayMs; - sendReq.delayMs *= 1000; - } else { - LOG(ERROR) << "Cannot make sense of delay value " << delay << ": does not end in 's' or 'ms'"; - } - } - // namelist - if (HAS_ATTR(element, "namelist")) { - std::vector<std::string> names = tokenizeIdRefs(ATTR(element, "namelist")); - for (int i = 0; i < names.size(); i++) { - sendReq.namelist[names[i]] = _dataModel->evalAsString(names[i]); - } - } - - // params - NodeSet<std::string> params = _xpath.evaluate("" + _nsPrefix + "param", element).asNodeSet(); - for (int i = 0; i < params.size(); i++) { - if (!HAS_ATTR(params[i], "name")) { - LOG(ERROR) << "param element is missing name attribut"; - continue; - } - std::string paramValue; - if (HAS_ATTR(params[i], "expr") && _dataModel) { - paramValue = _dataModel->evalAsString(ATTR(params[i], "expr")); - } else if(HAS_ATTR(params[i], "location") && _dataModel) { - paramValue = _dataModel->evalAsString(ATTR(params[i], "location")); - } else { - LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; - continue; - } - sendReq.params[ATTR(params[i], "name")].push_back(paramValue); - } - - // content - NodeSet<std::string> contents = _xpath.evaluate("" + _nsPrefix + "content", element).asNodeSet(); - if (contents.size() > 1) - LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; - if (contents.size() > 0) { - if (HAS_ATTR(contents[0], "expr")) { - if (_dataModel) { - sendReq.content = _dataModel->evalAsString(ATTR(contents[0], "expr")); - } else { - LOG(ERROR) << "content element has expr attribute but no datamodel is specified."; - } - } else if (contents[0].hasChildNodes()) { - sendReq.content = contents[0].getFirstChild().getNodeValue(); - } else { - LOG(ERROR) << "content element does not specify any content."; - } - } - - assert(_sendIds.find(sendReq.sendid) == _sendIds.end()); - _sendIds[sendReq.sendid] = std::make_pair(this, sendReq); - if (sendReq.delayMs > 0) { - _sendQueue->addEvent(sendReq.sendid, Interpreter::delayedSend, sendReq.delayMs, &_sendIds[sendReq.sendid]); - } else { - delayedSend(&_sendIds[sendReq.sendid], sendReq.name); - } - - } catch (Event e) { - LOG(ERROR) << "Syntax error in send element:" << std::endl << e << std::endl; - } + SendRequest sendReq; + try { + // event + if (HAS_ATTR(element, "eventexpr") && _dataModel) { + sendReq.name = _dataModel->evalAsString(ATTR(element, "eventexpr")); + } else if (HAS_ATTR(element, "event")) { + sendReq.name = ATTR(element, "event"); + } + // target + if (HAS_ATTR(element, "targetexpr") && _dataModel) { + sendReq.target = _dataModel->evalAsString(ATTR(element, "targetexpr")); + } else if (HAS_ATTR(element, "target")) { + sendReq.target = ATTR(element, "target"); + } + // type + if (HAS_ATTR(element, "typeexpr") && _dataModel) { + sendReq.type = _dataModel->evalAsString(ATTR(element, "typeexpr")); + } else if (HAS_ATTR(element, "type")) { + sendReq.type = ATTR(element, "type"); + } else { + sendReq.type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; + } + // id + if (HAS_ATTR(element, "idlocation") && _dataModel) { + sendReq.sendid = _dataModel->evalAsString(ATTR(element, "idlocation")); + } else if (HAS_ATTR(element, "id")) { + sendReq.sendid = ATTR(element, "id"); + } else { + /* + * The ids for <send> and <invoke> are subtly different. In a conformant + * SCXML document, they must be unique within the session, but in the case + * where the author does not provide them, the processor must generate a + * new unique ID not at load time but each time the element is executed. + * Furthermore the attribute 'idlocation' can be used to capture this + * automatically generated id. Finally note that the automatically generated + * id for <invoke> has a special format. See 6.4.1 Attribute Details for + * details. The SCXML processor may generate all other ids in any format, + * as long as they are unique. + */ + sendReq.sendid = getUUID(); + } + /** @TODO: + * + * If 'idlocation' is present, the SCXML Processor must generate an id when + * the parent <send> element is evaluated and store it in this location. + * See 3.14 IDs for details. + * + */ + + // delay + std::string delay; + sendReq.delayMs = 0; + if (HAS_ATTR(element, "delayexpr") && _dataModel) { + delay = _dataModel->evalAsString(ATTR(element, "delayexpr")); + } else if (HAS_ATTR(element, "delay")) { + delay = ATTR(element, "delay"); + } + if (delay.size() > 0) { + boost::trim(delay); + std::stringstream delayTime; + if (delay.size() > 2 && boost::iequals("ms", delay.substr(delay.length() - 2, 2))) { + delayTime << delay.substr(0, delay.size() - 2); + delayTime >> sendReq.delayMs; + } else if (delay.size() > 1 && boost::iequals("s", delay.substr(delay.length() - 1, 1))) { + delayTime << delay.substr(0, delay.size() - 1); + delayTime >> sendReq.delayMs; + sendReq.delayMs *= 1000; + } else { + LOG(ERROR) << "Cannot make sense of delay value " << delay << ": does not end in 's' or 'ms'"; + } + } + // namelist + if (HAS_ATTR(element, "namelist")) { + std::vector<std::string> names = tokenizeIdRefs(ATTR(element, "namelist")); + for (int i = 0; i < names.size(); i++) { + sendReq.namelist[names[i]] = _dataModel->evalAsString(names[i]); + } + } + + // params + NodeSet<std::string> params = _xpath.evaluate("" + _nsPrefix + "param", element).asNodeSet(); + for (int i = 0; i < params.size(); i++) { + if (!HAS_ATTR(params[i], "name")) { + LOG(ERROR) << "param element is missing name attribut"; + continue; + } + std::string paramValue; + if (HAS_ATTR(params[i], "expr") && _dataModel) { + paramValue = _dataModel->evalAsString(ATTR(params[i], "expr")); + } else if(HAS_ATTR(params[i], "location") && _dataModel) { + paramValue = _dataModel->evalAsString(ATTR(params[i], "location")); + } else { + LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; + continue; + } + sendReq.params.insert(std::make_pair(ATTR(params[i], "name"), paramValue)); + } + + // content + NodeSet<std::string> contents = _xpath.evaluate("" + _nsPrefix + "content", element).asNodeSet(); + if (contents.size() > 1) + LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; + if (contents.size() > 0) { + if (HAS_ATTR(contents[0], "expr")) { + if (_dataModel) { + sendReq.content = _dataModel->evalAsString(ATTR(contents[0], "expr")); + } else { + LOG(ERROR) << "content element has expr attribute but no datamodel is specified."; + } + } else if (contents[0].hasChildNodes()) { + sendReq.content = contents[0].getFirstChild().getNodeValue(); + } else { + LOG(ERROR) << "content element does not specify any content."; + } + } + + assert(_sendIds.find(sendReq.sendid) == _sendIds.end()); + _sendIds[sendReq.sendid] = std::make_pair(this, sendReq); + if (sendReq.delayMs > 0) { + _sendQueue->addEvent(sendReq.sendid, Interpreter::delayedSend, sendReq.delayMs, &_sendIds[sendReq.sendid]); + } else { + delayedSend(&_sendIds[sendReq.sendid], sendReq.name); + } + + } catch (Event e) { + LOG(ERROR) << "Syntax error in send element:" << std::endl << e << std::endl; + } } void Interpreter::delayedSend(void* userdata, std::string eventName) { - std::pair<Interpreter*, SendRequest>* data = (std::pair<Interpreter*, SendRequest>*)(userdata); - - Interpreter* INSTANCE = data->first; - SendRequest sendReq = data->second; - - if (boost::iequals(sendReq.target, "#_parent")) { - // send to parent scxml session - if (INSTANCE->_invoker != NULL) { - INSTANCE->_invoker->sendToParent(sendReq); - } else { - LOG(ERROR) << "Can not send to parent, we were not invoked" << std::endl; - } - } else if (sendReq.target.find_first_of("#_") == 0) { - // send to invoker - std::string invokeId = sendReq.target.substr(2, sendReq.target.length() - 2); - if (INSTANCE->_invokerIds.find(invokeId) != INSTANCE->_invokerIds.end()) { - INSTANCE->_invokerIds[invokeId]->send(sendReq); - } else { - LOG(ERROR) << "Can not send to invoked component " << invokeId << ", no such invokeId" << std::endl; - } - } else if (sendReq.target.length() == 0) { - INSTANCE->receive(sendReq); - } else { - IOProcessor* ioProc = INSTANCE->getIOProcessor(sendReq.type); - if (ioProc != NULL) { - ioProc->send(sendReq); - } - } - assert(INSTANCE->_sendIds.find(sendReq.sendid) != INSTANCE->_sendIds.end()); - INSTANCE->_sendIds.erase(sendReq.sendid); -} - + std::pair<Interpreter*, SendRequest>* data = (std::pair<Interpreter*, SendRequest>*)(userdata); + + Interpreter* INSTANCE = data->first; + SendRequest sendReq = data->second; + + if (boost::iequals(sendReq.target, "#_parent")) { + // send to parent scxml session + if (INSTANCE->_invoker != NULL) { + INSTANCE->_invoker->sendToParent(sendReq); + } else { + LOG(ERROR) << "Can not send to parent, we were not invoked" << std::endl; + } + } else if (sendReq.target.find_first_of("#_") == 0) { + // send to invoker + std::string invokeId = sendReq.target.substr(2, sendReq.target.length() - 2); + if (INSTANCE->_invokerIds.find(invokeId) != INSTANCE->_invokerIds.end()) { + INSTANCE->_invokerIds[invokeId]->send(sendReq); + } else { + LOG(ERROR) << "Can not send to invoked component " << invokeId << ", no such invokeId" << std::endl; + } + } else if (sendReq.target.length() == 0) { + INSTANCE->receive(sendReq); + } else { + IOProcessor* ioProc = INSTANCE->getIOProcessor(sendReq.type); + if (ioProc != NULL) { + ioProc->send(sendReq); + } + } + assert(INSTANCE->_sendIds.find(sendReq.sendid) != INSTANCE->_sendIds.end()); + INSTANCE->_sendIds.erase(sendReq.sendid); +} + void Interpreter::invoke(const Arabica::DOM::Node<std::string>& element) { - InvokeRequest invokeReq; - try { - // type - if (HAS_ATTR(element, "typeexpr") && _dataModel) { - invokeReq.type = _dataModel->evalAsString(ATTR(element, "typeexpr")); - } else if (HAS_ATTR(element, "type")) { - invokeReq.type = ATTR(element, "type"); - } else { - LOG(ERROR) << "invoke element is missing expr or typeexpr or no datamodel is specified"; - } - - // src - std::string source; - if (HAS_ATTR(element, "srcexpr") && _dataModel) { - source = _dataModel->evalAsString(ATTR(element, "srcexpr")); - } else if (HAS_ATTR(element, "src")) { - source = ATTR(element, "src"); - } - if (source.length() > 0) { - Arabica::io::URI srcURI(source); - if (!makeAbsolute(srcURI)) { - LOG(ERROR) << "invoke element has relative src URI with no baseURI set."; - return; - } - invokeReq.src = srcURI.as_string(); - } - - // id - if (HAS_ATTR(element, "idlocation") && _dataModel) { - invokeReq.invokeid = _dataModel->evalAsString(ATTR(element, "idlocation")); - } else if (HAS_ATTR(element, "id")) { - invokeReq.invokeid = ATTR(element, "id"); - } else { - assert(false); - } - - // namelist - if (HAS_ATTR(element, "namelist")) { - invokeReq.namelist = ATTR(element, "namelist"); - } - - // autoforward - if (HAS_ATTR(element, "autoforward")) { - if (boost::iequals(ATTR(element, "autoforward"), "true")) { - invokeReq.autoForward = true; - } - } else { - invokeReq.autoForward = false; - } - - // params - NodeSet<std::string> params = _xpath.evaluate("" + _nsPrefix + "param", element).asNodeSet(); - for (int i = 0; i < params.size(); i++) { - if (!HAS_ATTR(params[i], "name")) { - LOG(ERROR) << "param element is missing name attribut"; - continue; - } - std::string paramValue; - if (HAS_ATTR(params[i], "expr")) { - if (_dataModel) { - paramValue = _dataModel->evalAsString(ATTR(params[i], "expr")); - } else { - paramValue = ATTR(params[i], "expr"); - } - } else if(HAS_ATTR(params[i], "location") && _dataModel) { - paramValue = _dataModel->evalAsString(ATTR(params[i], "location")); - } else { - LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; - continue; - } - invokeReq.params[ATTR(params[i], "name")].push_back(paramValue); - } - - // content - NodeSet<std::string> contents = _xpath.evaluate("" + _nsPrefix + "content", element).asNodeSet(); - if (contents.size() > 1) - LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; - if (contents.size() > 0) { - invokeReq.content = contents[0].getNodeValue(); - } - - Invoker* invoker = Factory::getInvoker(invokeReq.type, this); - if (invoker != NULL) { - _invokerIds[invokeReq.invokeid] = invoker; - LOG(INFO) << "Added " << invokeReq.type << " at " << invokeReq.invokeid; - invoker->invoke(invokeReq); - } else { - LOG(ERROR) << "No invoker known for type " << invokeReq.type; - } - - } catch (Event e) { - LOG(ERROR) << "Syntax error in invoke element:" << std::endl << e << std::endl; - } -} - + InvokeRequest invokeReq; + try { + // type + if (HAS_ATTR(element, "typeexpr") && _dataModel) { + invokeReq.type = _dataModel->evalAsString(ATTR(element, "typeexpr")); + } else if (HAS_ATTR(element, "type")) { + invokeReq.type = ATTR(element, "type"); + } else { + LOG(ERROR) << "invoke element is missing expr or typeexpr or no datamodel is specified"; + } + + // src + std::string source; + if (HAS_ATTR(element, "srcexpr") && _dataModel) { + source = _dataModel->evalAsString(ATTR(element, "srcexpr")); + } else if (HAS_ATTR(element, "src")) { + source = ATTR(element, "src"); + } + if (source.length() > 0) { + Arabica::io::URI srcURI(source); + if (!makeAbsolute(srcURI)) { + LOG(ERROR) << "invoke element has relative src URI with no baseURI set."; + return; + } + invokeReq.src = srcURI.as_string(); + } + + // id + if (HAS_ATTR(element, "idlocation") && _dataModel) { + invokeReq.invokeid = _dataModel->evalAsString(ATTR(element, "idlocation")); + } else if (HAS_ATTR(element, "id")) { + invokeReq.invokeid = ATTR(element, "id"); + } else { + assert(false); + } + + // namelist + if (HAS_ATTR(element, "namelist")) { + invokeReq.namelist = ATTR(element, "namelist"); + } + + // autoforward + if (HAS_ATTR(element, "autoforward")) { + if (boost::iequals(ATTR(element, "autoforward"), "true")) { + invokeReq.autoForward = true; + } + } else { + invokeReq.autoForward = false; + } + + // params + NodeSet<std::string> params = _xpath.evaluate("" + _nsPrefix + "param", element).asNodeSet(); + for (int i = 0; i < params.size(); i++) { + if (!HAS_ATTR(params[i], "name")) { + LOG(ERROR) << "param element is missing name attribut"; + continue; + } + std::string paramValue; + if (HAS_ATTR(params[i], "expr")) { + if (_dataModel) { + paramValue = _dataModel->evalAsString(ATTR(params[i], "expr")); + } else { + paramValue = ATTR(params[i], "expr"); + } + } else if(HAS_ATTR(params[i], "location") && _dataModel) { + paramValue = _dataModel->evalAsString(ATTR(params[i], "location")); + } else { + LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; + continue; + } +// invokeReq.params[ATTR(params[i], "name")].push_back(paramValue); + invokeReq.params.insert(std::make_pair(ATTR(params[i], "name"), paramValue)); + + } + + // content + NodeSet<std::string> contents = _xpath.evaluate("" + _nsPrefix + "content", element).asNodeSet(); + if (contents.size() > 1) + LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; + if (contents.size() > 0) { + invokeReq.content = contents[0].getNodeValue(); + } + + Invoker* invoker = Factory::getInvoker(invokeReq.type, this); + if (invoker != NULL) { + _invokerIds[invokeReq.invokeid] = invoker; + LOG(INFO) << "Added " << invokeReq.type << " at " << invokeReq.invokeid; + invoker->invoke(invokeReq); + } else { + LOG(ERROR) << "No invoker known for type " << invokeReq.type; + } + + } catch (Event e) { + LOG(ERROR) << "Syntax error in invoke element:" << std::endl << e << std::endl; + } +} + void Interpreter::cancelInvoke(const Arabica::DOM::Node<std::string>& element) { - std::string invokeId; - if (HAS_ATTR(element, "idlocation") && _dataModel) { - invokeId = _dataModel->evalAsString(ATTR(element, "idlocation")); - } else if (HAS_ATTR(element, "id")) { - invokeId = ATTR(element, "id"); - } else { - assert(false); - } - if (_invokerIds.find(invokeId) != _invokerIds.end()) { - LOG(INFO) << "Removed invoker at " << invokeId; - delete (_invokerIds[invokeId]); - _invokerIds.erase(invokeId); - } else { - LOG(ERROR) << "Cannot cancel invoke for id " << invokeId << ": no soch invokation"; - } + std::string invokeId; + if (HAS_ATTR(element, "idlocation") && _dataModel) { + invokeId = _dataModel->evalAsString(ATTR(element, "idlocation")); + } else if (HAS_ATTR(element, "id")) { + invokeId = ATTR(element, "id"); + } else { + assert(false); + } + if (_invokerIds.find(invokeId) != _invokerIds.end()) { + LOG(INFO) << "Removed invoker at " << invokeId; + delete (_invokerIds[invokeId]); + _invokerIds.erase(invokeId); + } else { + LOG(ERROR) << "Cannot cancel invoke for id " << invokeId << ": no soch invokation"; + } } Arabica::XPath::NodeSet<std::string> Interpreter::selectTransitions(const std::string& event) { - Arabica::XPath::NodeSet<std::string> enabledTransitions; - - NodeSet<std::string> atomicStates; - for (unsigned int i = 0; i < _configuration.size(); i++) { - if (isAtomic(_configuration[i])) - atomicStates.push_back(_configuration[i]); - } - atomicStates.to_document_order(); - - for (unsigned int i = 0; i < atomicStates.size(); i++) { - NodeSet<std::string> ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node<std::string>()); - ancestors.push_back(atomicStates[i]); - for (unsigned int j = 0; j < ancestors.size(); j++) { - NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", ancestors[j]).asNodeSet(); - for (unsigned int k = 0; k < transitions.size(); k++) { - if (((Arabica::DOM::Element<std::string>)transitions[k]).hasAttribute("event") && - nameMatch(((Arabica::DOM::Element<std::string>)transitions[k]).getAttribute("event"), event) && - hasConditionMatch(transitions[k])) { - enabledTransitions.push_back(transitions[k]); - goto LOOP; - } - } - } - LOOP:; - } - return enabledTransitions; + Arabica::XPath::NodeSet<std::string> enabledTransitions; + + NodeSet<std::string> atomicStates; + for (unsigned int i = 0; i < _configuration.size(); i++) { + if (isAtomic(_configuration[i])) + atomicStates.push_back(_configuration[i]); + } + atomicStates.to_document_order(); + + for (unsigned int i = 0; i < atomicStates.size(); i++) { + NodeSet<std::string> ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node<std::string>()); + ancestors.push_back(atomicStates[i]); + for (unsigned int j = 0; j < ancestors.size(); j++) { + NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", ancestors[j]).asNodeSet(); + for (unsigned int k = 0; k < transitions.size(); k++) { + if (((Arabica::DOM::Element<std::string>)transitions[k]).hasAttribute("event") && + nameMatch(((Arabica::DOM::Element<std::string>)transitions[k]).getAttribute("event"), event) && + hasConditionMatch(transitions[k])) { + enabledTransitions.push_back(transitions[k]); + goto LOOP; + } + } + } +LOOP: + ; + } + return enabledTransitions; } // see: http://www.w3.org/TR/scxml/#EventDescriptors bool Interpreter::nameMatch(const std::string& transitionEvent, const std::string& event) { - assert(transitionEvent.size() > 0); - assert(event.size() > 0); - - // naive case of single descriptor and exact match - if (boost::equals(transitionEvent, event)) - return true; - - boost::char_separator<char> sep(" "); - boost::tokenizer<boost::char_separator<char> > tokens(transitionEvent, sep); - boost::tokenizer<boost::char_separator<char> >::iterator tokenIter = tokens.begin(); - - while(tokenIter != tokens.end()) { - std::string eventDesc(*tokenIter++); - - // remove optional trailing .* for CCXML compatibility - if (eventDesc.find("*", eventDesc.size() - 1) != std::string::npos) - eventDesc = eventDesc.substr(0, eventDesc.size() - 1); - if (eventDesc.find(".", eventDesc.size() - 1) != std::string::npos) - eventDesc = eventDesc.substr(0, eventDesc.size() - 1); - - // was eventDesc the * wildcard - if (eventDesc.size() == 0) - return true; - - // are they already equal? - if (boost::equals(eventDesc, event)) - return true; - - // eventDesc has to be a real prefix of event now and therefore shorter - if (eventDesc.size() >= event.size()) - continue; - - // it is a prefix of the event name and event continues with .something - if (eventDesc.compare(event.substr(0, eventDesc.size())) == 0) - if (event.find(".", eventDesc.size()) == eventDesc.size()) - return true; - } - return false; -} - + assert(transitionEvent.size() > 0); + assert(event.size() > 0); + + // naive case of single descriptor and exact match + if (boost::equals(transitionEvent, event)) + return true; + + boost::char_separator<char> sep(" "); + boost::tokenizer<boost::char_separator<char> > tokens(transitionEvent, sep); + boost::tokenizer<boost::char_separator<char> >::iterator tokenIter = tokens.begin(); + + while(tokenIter != tokens.end()) { + std::string eventDesc(*tokenIter++); + + // remove optional trailing .* for CCXML compatibility + if (eventDesc.find("*", eventDesc.size() - 1) != std::string::npos) + eventDesc = eventDesc.substr(0, eventDesc.size() - 1); + if (eventDesc.find(".", eventDesc.size() - 1) != std::string::npos) + eventDesc = eventDesc.substr(0, eventDesc.size() - 1); + + // was eventDesc the * wildcard + if (eventDesc.size() == 0) + return true; + + // are they already equal? + if (boost::equals(eventDesc, event)) + return true; + + // eventDesc has to be a real prefix of event now and therefore shorter + if (eventDesc.size() >= event.size()) + continue; + + // it is a prefix of the event name and event continues with .something + if (eventDesc.compare(event.substr(0, eventDesc.size())) == 0) + if (event.find(".", eventDesc.size()) == eventDesc.size()) + return true; + } + return false; +} + Arabica::XPath::NodeSet<std::string> Interpreter::selectEventlessTransitions() { - Arabica::XPath::NodeSet<std::string> enabledTransitions; - - NodeSet<std::string> atomicStates; - for (unsigned int i = 0; i < _configuration.size(); i++) { - if (isAtomic(_configuration[i])) - atomicStates.push_back(_configuration[i]); - } - atomicStates.to_document_order(); - - for (unsigned int i = 0; i < atomicStates.size(); i++) { - NodeSet<std::string> ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node<std::string>()); - ancestors.push_back(atomicStates[i]); - for (unsigned int j = 0; j < ancestors.size(); j++) { - NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", ancestors[j]).asNodeSet(); - for (unsigned int k = 0; k < transitions.size(); k++) { - if (!((Arabica::DOM::Element<std::string>)transitions[k]).hasAttribute("event") && hasConditionMatch(transitions[k])) { - enabledTransitions.push_back(transitions[k]); - goto LOOP; - } - } - } - LOOP:; - } - - enabledTransitions = filterPreempted(enabledTransitions); - return enabledTransitions; + Arabica::XPath::NodeSet<std::string> enabledTransitions; + + NodeSet<std::string> atomicStates; + for (unsigned int i = 0; i < _configuration.size(); i++) { + if (isAtomic(_configuration[i])) + atomicStates.push_back(_configuration[i]); + } + atomicStates.to_document_order(); + + for (unsigned int i = 0; i < atomicStates.size(); i++) { + NodeSet<std::string> ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node<std::string>()); + ancestors.push_back(atomicStates[i]); + for (unsigned int j = 0; j < ancestors.size(); j++) { + NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", ancestors[j]).asNodeSet(); + for (unsigned int k = 0; k < transitions.size(); k++) { + if (!((Arabica::DOM::Element<std::string>)transitions[k]).hasAttribute("event") && hasConditionMatch(transitions[k])) { + enabledTransitions.push_back(transitions[k]); + goto LOOP; + } + } + } +LOOP: + ; + } + + enabledTransitions = filterPreempted(enabledTransitions); + return enabledTransitions; } bool Interpreter::hasConditionMatch(const Arabica::DOM::Node<std::string>& conditional) { - try { - if (_dataModel && HAS_ATTR(conditional, "cond")) - return _dataModel->evalAsBool(ATTR(conditional, "cond")); - } catch (Event e) { - LOG(ERROR) << "Syntax error in cond attribute of " << TAGNAME(conditional) << " element:" << std::endl << e << std::endl; - return false; - } - return true; // no condition is always true + try { + if (_dataModel && HAS_ATTR(conditional, "cond")) + return _dataModel->evalAsBool(ATTR(conditional, "cond")); + } catch (Event e) { + LOG(ERROR) << "Syntax error in cond attribute of " << TAGNAME(conditional) << " element:" << std::endl << e << std::endl; + return false; + } + return true; // no condition is always true } Arabica::XPath::NodeSet<std::string> Interpreter::filterPreempted(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { - Arabica::XPath::NodeSet<std::string> filteredTransitions; - for (unsigned int i = 0; i < enabledTransitions.size(); i++) { - Arabica::DOM::Node<std::string> t = enabledTransitions[i]; - for (unsigned int j = i+1; j < enabledTransitions.size(); j++) { - Arabica::DOM::Node<std::string> t2 = enabledTransitions[j]; - if (isPreemptingTransition(t2, t)) - goto LOOP; - } - filteredTransitions.push_back(t); - LOOP:; - } - return filteredTransitions; + Arabica::XPath::NodeSet<std::string> filteredTransitions; + for (unsigned int i = 0; i < enabledTransitions.size(); i++) { + Arabica::DOM::Node<std::string> t = enabledTransitions[i]; + for (unsigned int j = i+1; j < enabledTransitions.size(); j++) { + Arabica::DOM::Node<std::string> t2 = enabledTransitions[j]; + if (isPreemptingTransition(t2, t)) + goto LOOP; + } + filteredTransitions.push_back(t); +LOOP: + ; + } + return filteredTransitions; } bool Interpreter::isPreemptingTransition(const Arabica::DOM::Node<std::string>& t1, const Arabica::DOM::Node<std::string>& t2) { - if (t1 == t2) - return false; - if (isWithinSameChild(t1) && (!isTargetless(t2) && !isWithinSameChild(t2))) - return true; - if (!isTargetless(t1) && !isWithinSameChild(t1)) - return true; - return false; + if (t1 == t2) + return false; + if (isWithinSameChild(t1) && (!isTargetless(t2) && !isWithinSameChild(t2))) + return true; + if (!isTargetless(t1) && !isWithinSameChild(t1)) + return true; + return false; } void Interpreter::microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { #if 0 - std::cout << "Transitions: "; - for (int i = 0; i < enabledTransitions.size(); i++) { - std::cout << ((Arabica::DOM::Element<std::string>)getSourceState(enabledTransitions[i])).getAttribute("id") << " -> " << std::endl; - NodeSet<std::string> targetSet = getTargetStates(enabledTransitions[i]); - for (int j = 0; j < targetSet.size(); j++) { - std::cout << " " << ((Arabica::DOM::Element<std::string>)targetSet[j]).getAttribute("id") << std::endl; - } - } - std::cout << std::endl; + std::cout << "Transitions: "; + for (int i = 0; i < enabledTransitions.size(); i++) { + std::cout << ((Arabica::DOM::Element<std::string>)getSourceState(enabledTransitions[i])).getAttribute("id") << " -> " << std::endl; + NodeSet<std::string> targetSet = getTargetStates(enabledTransitions[i]); + for (int j = 0; j < targetSet.size(); j++) { + std::cout << " " << ((Arabica::DOM::Element<std::string>)targetSet[j]).getAttribute("id") << std::endl; + } + } + std::cout << std::endl; #endif - exitStates(enabledTransitions); - executeTransitionContent(enabledTransitions); - enterStates(enabledTransitions); + exitStates(enabledTransitions); + executeTransitionContent(enabledTransitions); + enterStates(enabledTransitions); } void Interpreter::exitInterpreter() { - NodeSet<std::string> statesToExit = _configuration; - statesToExit.to_document_order(); - statesToExit.reverse(); - - for (int i = 0; i < statesToExit.size(); i++) { - Arabica::XPath::NodeSet<std::string> onExitElems = _xpath.evaluate("" + _nsPrefix + "onexit", statesToExit[i]).asNodeSet(); - for (int j = 0; j < onExitElems.size(); j++) { - executeContent(onExitElems[j]); - } - Arabica::XPath::NodeSet<std::string> invokeElems = _xpath.evaluate("" + _nsPrefix + "invoke", statesToExit[i]).asNodeSet(); - for (int j = 0; j < invokeElems.size(); j++) { - cancelInvoke(invokeElems[j]); - } - if (isFinal(statesToExit[i]) && parentIsScxmlState(statesToExit[i])) { - returnDoneEvent(statesToExit[i]); - } - } - _configuration = NodeSet<std::string>(); + NodeSet<std::string> statesToExit = _configuration; + statesToExit.to_document_order(); + statesToExit.reverse(); + + for (int i = 0; i < statesToExit.size(); i++) { + Arabica::XPath::NodeSet<std::string> onExitElems = _xpath.evaluate("" + _nsPrefix + "onexit", statesToExit[i]).asNodeSet(); + for (int j = 0; j < onExitElems.size(); j++) { + executeContent(onExitElems[j]); + } + Arabica::XPath::NodeSet<std::string> invokeElems = _xpath.evaluate("" + _nsPrefix + "invoke", statesToExit[i]).asNodeSet(); + for (int j = 0; j < invokeElems.size(); j++) { + cancelInvoke(invokeElems[j]); + } + if (isFinal(statesToExit[i]) && parentIsScxmlState(statesToExit[i])) { + returnDoneEvent(statesToExit[i]); + } + } + _configuration = NodeSet<std::string>(); } void Interpreter::executeTransitionContent(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { - for (int i = 0; i < enabledTransitions.size(); i++) { - executeContent(enabledTransitions[i]); - } + for (int i = 0; i < enabledTransitions.size(); i++) { + executeContent(enabledTransitions[i]); + } } void Interpreter::executeContent(const NodeList<std::string>& content) { - for (unsigned int i = 0; i < content.getLength(); i++) { - if (content.item(i).getNodeType() != Node_base::ELEMENT_NODE) - continue; - executeContent(content.item(i)); - } + for (unsigned int i = 0; i < content.getLength(); i++) { + if (content.item(i).getNodeType() != Node_base::ELEMENT_NODE) + continue; + executeContent(content.item(i)); + } } - + void Interpreter::executeContent(const Arabica::DOM::Node<std::string>& content) { - if (content.getNodeType() != Node_base::ELEMENT_NODE) - return; - - if (false) { - } else if (boost::iequals(TAGNAME(content), "raise")) { - // --- RAISE -------------------------- - if (HAS_ATTR(content, "event")) { - Event event; - event.name = ATTR(content, "event"); - _internalQueue.push_back(event); - } - } else if (boost::iequals(TAGNAME(content), "if")) { - // --- IF / ELSEIF / ELSE -------------- - Arabica::DOM::Element<std::string> ifElem = (Arabica::DOM::Element<std::string>)content; - if(hasConditionMatch(ifElem)) { - // condition is true, execute all content up to an elseif, else or end - if (ifElem.hasChildNodes()) { - NodeList<std::string> childs = ifElem.getChildNodes(); - for (unsigned int i = 0; i < childs.getLength(); i++) { - if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE) - continue; - if (boost::iequals(TAGNAME(childs.item(i)), "elsif") || - boost::iequals(TAGNAME(childs.item(i)), "else")) - break; - executeContent(childs.item(i)); - } - } - } else { - // condition does not match - do we have an elsif? - if (ifElem.hasChildNodes()) { - NodeList<std::string> elseifElem = ifElem.getElementsByTagName("elseif"); - for (unsigned int i = 0; i < elseifElem.getLength(); i++) { - if (hasConditionMatch(elseifElem.item(i))) { - executeContent(elseifElem.item(i).getChildNodes()); - goto ELSIF_ELEM_MATCH; - } - } - NodeList<std::string> elseElem = ifElem.getElementsByTagName("else"); - if (elseElem.getLength() > 0) - executeContent(elseElem.item(0).getChildNodes()); - } - } - ELSIF_ELEM_MATCH:; - } else if (boost::iequals(TAGNAME(content), "elseif")) { - std::cerr << "Found single elsif to evaluate!" << std::endl; - } else if (boost::iequals(TAGNAME(content), "else")) { - std::cerr << "Found single else to evaluate!" << std::endl; - } else if (boost::iequals(TAGNAME(content), "foreach")) { - // --- FOREACH -------------------------- - if (_dataModel) { - if (HAS_ATTR(content, "array") && HAS_ATTR(content, "item")) { - std::string array = ATTR(content, "array"); - std::string item = ATTR(content, "item"); - std::string index = (HAS_ATTR(content, "index") ? ATTR(content, "index") : ""); - uint32_t iterations = _dataModel->getLength(array); - _dataModel->pushContext(); // copy old and enter new context - for (uint32_t iteration = 0; iteration < iterations; iteration++) { - { - // assign array element to item - std::stringstream ss; - ss << array << "[" << iteration << "]"; - _dataModel->assign(item, ss.str()); - } - if (index.length() > 0) { - // assign iteration element to index - std::stringstream ss; - ss << iteration; - _dataModel->assign(index,ss.str()); - } - if (content.hasChildNodes()) - executeContent(content.getChildNodes()); - } - _dataModel->popContext(); // leave stacked context - } else { - LOG(ERROR) << "Expected array and item attributes with foreach element!" << std::endl; - } - } - } else if (boost::iequals(TAGNAME(content), "log")) { - // --- LOG -------------------------- - Arabica::DOM::Element<std::string> logElem = (Arabica::DOM::Element<std::string>)content; - if (logElem.hasAttribute("expr")) { - if (_dataModel) { - try { - std::cout << _dataModel->evalAsString(logElem.getAttribute("expr")) << std::endl; - } catch (Event e) { - LOG(ERROR) << "Syntax error in expr attribute of log element:" << std::endl << e << std::endl; - } - } else { - std::cout << logElem.getAttribute("expr") << std::endl; - } - } - } else if (boost::iequals(TAGNAME(content), "assign")) { - // --- ASSIGN -------------------------- - if (_dataModel && HAS_ATTR(content, "location") && HAS_ATTR(content, "expr")) { - try { - _dataModel->assign(ATTR(content, "location"), ATTR(content, "expr")); - } catch (Event e) { - LOG(ERROR) << "Syntax error in attributes of assign element:" << std::endl << e << std::endl; - } - } - } else if (boost::iequals(TAGNAME(content), "validate")) { - // --- VALIDATE -------------------------- - if (_dataModel) { - std::string location = (HAS_ATTR(content, "location") ? ATTR(content, "location") : ""); - std::string schema = (HAS_ATTR(content, "schema") ? ATTR(content, "schema") : ""); - _dataModel->validate(location, schema); - } - } else if (boost::iequals(TAGNAME(content), "script")) { - // --- SCRIPT -------------------------- - if (_dataModel) { - if (HAS_ATTR(content, "src")) { - Arabica::io::URI url(ATTR(content, "src")); - if (!makeAbsolute(url)) { - LOG(ERROR) << "script element has relative URI " << ATTR(content, "src") << " with no base URI set for interpreter"; - return; - } - - std::stringstream srcContent; - URL scriptUrl(url.as_string()); - srcContent << scriptUrl; - - try { - _dataModel->eval(srcContent.str()); - } catch (Event e) { - LOG(ERROR) << "Syntax error while executing script element from '" << ATTR(content, "src") << "':" << std::endl << e << std::endl; - } - } else { - if (content.hasChildNodes()) { - // search for the text node with the actual script - if (content.getFirstChild().getNodeType() == Node_base::TEXT_NODE) { - try { - _dataModel->eval(content.getFirstChild().getNodeValue()); - } catch (Event e) { - LOG(ERROR) << "Syntax error while executing script element" << std::endl << e << std::endl; - } - } - } - } - } - } else if (boost::iequals(TAGNAME(content), "send")) { - // --- SEND -------------------------- - send(content); - } else if (boost::iequals(TAGNAME(content), "cancel")) { - // --- CANCEL -------------------------- - std::string sendId; - try { - if (HAS_ATTR(content, "sendidexpr")) { - sendId = _dataModel->evalAsString(ATTR(content, "sendidexpr")); - } else if(HAS_ATTR(content, "sendid")) { - sendId = ATTR(content, "sendid"); - } else { - LOG(ERROR) << "Expected sendidexpr or sendid attribute in cancel element"; - return; - } - _sendQueue->cancelEvent(sendId); - - } catch (Event e) { - LOG(ERROR) << "Syntax error while executing cancel element" << std::endl << e << std::endl; - } - - } else if (boost::iequals(TAGNAME(content), "invoke")) { - // --- INVOKE -------------------------- - } else { - NodeList<std::string> executable = content.getChildNodes(); - for (int i = 0; i < executable.getLength(); i++) { - executeContent(executable.item(i)); - } - } + if (content.getNodeType() != Node_base::ELEMENT_NODE) + return; + + if (false) { + } else if (boost::iequals(TAGNAME(content), "raise")) { + // --- RAISE -------------------------- + if (HAS_ATTR(content, "event")) { + Event event; + event.name = ATTR(content, "event"); + _internalQueue.push_back(event); + } + } else if (boost::iequals(TAGNAME(content), "if")) { + // --- IF / ELSEIF / ELSE -------------- + Arabica::DOM::Element<std::string> ifElem = (Arabica::DOM::Element<std::string>)content; + if(hasConditionMatch(ifElem)) { + // condition is true, execute all content up to an elseif, else or end + if (ifElem.hasChildNodes()) { + NodeList<std::string> childs = ifElem.getChildNodes(); + for (unsigned int i = 0; i < childs.getLength(); i++) { + if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE) + continue; + if (boost::iequals(TAGNAME(childs.item(i)), "elsif") || + boost::iequals(TAGNAME(childs.item(i)), "else")) + break; + executeContent(childs.item(i)); + } + } + } else { + // condition does not match - do we have an elsif? + if (ifElem.hasChildNodes()) { + NodeList<std::string> elseifElem = ifElem.getElementsByTagName("elseif"); + for (unsigned int i = 0; i < elseifElem.getLength(); i++) { + if (hasConditionMatch(elseifElem.item(i))) { + executeContent(elseifElem.item(i).getChildNodes()); + goto ELSIF_ELEM_MATCH; + } + } + NodeList<std::string> elseElem = ifElem.getElementsByTagName("else"); + if (elseElem.getLength() > 0) + executeContent(elseElem.item(0).getChildNodes()); + } + } +ELSIF_ELEM_MATCH: + ; + } else if (boost::iequals(TAGNAME(content), "elseif")) { + std::cerr << "Found single elsif to evaluate!" << std::endl; + } else if (boost::iequals(TAGNAME(content), "else")) { + std::cerr << "Found single else to evaluate!" << std::endl; + } else if (boost::iequals(TAGNAME(content), "foreach")) { + // --- FOREACH -------------------------- + if (_dataModel) { + if (HAS_ATTR(content, "array") && HAS_ATTR(content, "item")) { + std::string array = ATTR(content, "array"); + std::string item = ATTR(content, "item"); + std::string index = (HAS_ATTR(content, "index") ? ATTR(content, "index") : ""); + uint32_t iterations = _dataModel->getLength(array); + _dataModel->pushContext(); // copy old and enter new context + for (uint32_t iteration = 0; iteration < iterations; iteration++) { + { + // assign array element to item + std::stringstream ss; + ss << array << "[" << iteration << "]"; + _dataModel->assign(item, ss.str()); + } + if (index.length() > 0) { + // assign iteration element to index + std::stringstream ss; + ss << iteration; + _dataModel->assign(index,ss.str()); + } + if (content.hasChildNodes()) + executeContent(content.getChildNodes()); + } + _dataModel->popContext(); // leave stacked context + } else { + LOG(ERROR) << "Expected array and item attributes with foreach element!" << std::endl; + } + } + } else if (boost::iequals(TAGNAME(content), "log")) { + // --- LOG -------------------------- + Arabica::DOM::Element<std::string> logElem = (Arabica::DOM::Element<std::string>)content; + if (logElem.hasAttribute("expr")) { + if (_dataModel) { + try { + std::cout << _dataModel->evalAsString(logElem.getAttribute("expr")) << std::endl; + } catch (Event e) { + LOG(ERROR) << "Syntax error in expr attribute of log element:" << std::endl << e << std::endl; + } + } else { + std::cout << logElem.getAttribute("expr") << std::endl; + } + } + } else if (boost::iequals(TAGNAME(content), "assign")) { + // --- ASSIGN -------------------------- + if (_dataModel && HAS_ATTR(content, "location") && HAS_ATTR(content, "expr")) { + try { + _dataModel->assign(ATTR(content, "location"), ATTR(content, "expr")); + } catch (Event e) { + LOG(ERROR) << "Syntax error in attributes of assign element:" << std::endl << e << std::endl; + } + } + } else if (boost::iequals(TAGNAME(content), "validate")) { + // --- VALIDATE -------------------------- + if (_dataModel) { + std::string location = (HAS_ATTR(content, "location") ? ATTR(content, "location") : ""); + std::string schema = (HAS_ATTR(content, "schema") ? ATTR(content, "schema") : ""); + _dataModel->validate(location, schema); + } + } else if (boost::iequals(TAGNAME(content), "script")) { + // --- SCRIPT -------------------------- + if (_dataModel) { + if (HAS_ATTR(content, "src")) { + Arabica::io::URI url(ATTR(content, "src")); + if (!makeAbsolute(url)) { + LOG(ERROR) << "script element has relative URI " << ATTR(content, "src") << " with no base URI set for interpreter"; + return; + } + + std::stringstream srcContent; + URL scriptUrl(url.as_string()); + srcContent << scriptUrl; + + try { + _dataModel->eval(srcContent.str()); + } catch (Event e) { + LOG(ERROR) << "Syntax error while executing script element from '" << ATTR(content, "src") << "':" << std::endl << e << std::endl; + } + } else { + if (content.hasChildNodes()) { + // search for the text node with the actual script + if (content.getFirstChild().getNodeType() == Node_base::TEXT_NODE) { + try { + _dataModel->eval(content.getFirstChild().getNodeValue()); + } catch (Event e) { + LOG(ERROR) << "Syntax error while executing script element" << std::endl << e << std::endl; + } + } + } + } + } + } else if (boost::iequals(TAGNAME(content), "send")) { + // --- SEND -------------------------- + send(content); + } else if (boost::iequals(TAGNAME(content), "cancel")) { + // --- CANCEL -------------------------- + std::string sendId; + try { + if (HAS_ATTR(content, "sendidexpr")) { + sendId = _dataModel->evalAsString(ATTR(content, "sendidexpr")); + } else if(HAS_ATTR(content, "sendid")) { + sendId = ATTR(content, "sendid"); + } else { + LOG(ERROR) << "Expected sendidexpr or sendid attribute in cancel element"; + return; + } + _sendQueue->cancelEvent(sendId); + + } catch (Event e) { + LOG(ERROR) << "Syntax error while executing cancel element" << std::endl << e << std::endl; + } + + } else if (boost::iequals(TAGNAME(content), "invoke")) { + // --- INVOKE -------------------------- + } else { + NodeList<std::string> executable = content.getChildNodes(); + for (int i = 0; i < executable.getLength(); i++) { + executeContent(executable.item(i)); + } + } } void Interpreter::returnDoneEvent(const Arabica::DOM::Node<std::string>& state) { } void Interpreter::exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { - NodeSet<std::string> statesToExit; - for (int i = 0; i < enabledTransitions.size(); i++) { - Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]); - if (!isTargetless(transition)) { - std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external"); - NodeSet<std::string> tStates = getTargetStates(transition); - Arabica::DOM::Node<std::string> ancestor; - Arabica::DOM::Node<std::string> source = getSourceState(transition); - - bool allDescendants = true; - for (int j = 0; j < tStates.size(); j++) { - if (!isDescendant(tStates[j], source)) { - allDescendants = false; - break; - } - } - if (boost::iequals(transitionType, "internal") && - isCompound(source) && - allDescendants) - { - ancestor = source; - } else { - NodeSet<std::string> tmpStates; - tmpStates.push_back(source); - tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end()); - - ancestor = findLCCA(tmpStates); - } - - for (int j = 0; j < _configuration.size(); j++) { - if (isDescendant(_configuration[j], ancestor)) - statesToExit.push_back(_configuration[j]); - } - } - } - // remove statesToExit from _statesToInvoke - std::list<Arabica::DOM::Node<std::string> > tmp; - for (int i = 0; i < _statesToInvoke.size(); i++) { - if (!isMember(_statesToInvoke[i], statesToExit)) { - tmp.push_back(_statesToInvoke[i]); - } - } - _statesToInvoke = NodeSet<std::string>(); - _statesToInvoke.insert(_statesToInvoke.end(), tmp.begin(), tmp.end()); - - statesToExit.to_document_order(); - statesToExit.reverse(); - - for (int i = 0; i < statesToExit.size(); i++) { - NodeSet<std::string> historyElems = _xpath.evaluate("" + _nsPrefix + "history", statesToExit[i]).asNodeSet(); - for (int j = 0; j < historyElems.size(); j++) { - Arabica::DOM::Element<std::string> historyElem = (Arabica::DOM::Element<std::string>)historyElems[j]; - std::string historyType = (historyElem.hasAttribute("type") ? historyElem.getAttribute("type") : "shallow"); - NodeSet<std::string> historyNodes; - for (int k = 0; k < _configuration.size(); k++) { - if (boost::iequals(historyType, "deep")) { - if (isAtomic(_configuration[k]) && isDescendant(_configuration[k], statesToExit[i])) - historyNodes.push_back(_configuration[k]); - } else { - if (_configuration[k].getParentNode() == statesToExit[i]) - historyNodes.push_back(_configuration[k]); - } - } - _historyValue[historyElem.getAttribute("id")] = historyNodes; - } - } - - for (int i = 0; i < statesToExit.size(); i++) { - Arabica::XPath::NodeSet<std::string> onExitElems = _xpath.evaluate("" + _nsPrefix + "onexit", statesToExit[i]).asNodeSet(); - for (int j = 0; j < onExitElems.size(); j++) { - executeContent(onExitElems[j]); - } - Arabica::XPath::NodeSet<std::string> invokeElems = _xpath.evaluate("" + _nsPrefix + "invoke", statesToExit[i]).asNodeSet(); - for (int j = 0; j < invokeElems.size(); j++) { - cancelInvoke(invokeElems[j]); - } - } + NodeSet<std::string> statesToExit; + for (int i = 0; i < enabledTransitions.size(); i++) { + Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]); + if (!isTargetless(transition)) { + std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external"); + NodeSet<std::string> tStates = getTargetStates(transition); + Arabica::DOM::Node<std::string> ancestor; + Arabica::DOM::Node<std::string> source = getSourceState(transition); + + bool allDescendants = true; + for (int j = 0; j < tStates.size(); j++) { + if (!isDescendant(tStates[j], source)) { + allDescendants = false; + break; + } + } + if (boost::iequals(transitionType, "internal") && + isCompound(source) && + allDescendants) { + ancestor = source; + } else { + NodeSet<std::string> tmpStates; + tmpStates.push_back(source); + tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end()); + + ancestor = findLCCA(tmpStates); + } + + for (int j = 0; j < _configuration.size(); j++) { + if (isDescendant(_configuration[j], ancestor)) + statesToExit.push_back(_configuration[j]); + } + } + } + // remove statesToExit from _statesToInvoke + std::list<Arabica::DOM::Node<std::string> > tmp; + for (int i = 0; i < _statesToInvoke.size(); i++) { + if (!isMember(_statesToInvoke[i], statesToExit)) { + tmp.push_back(_statesToInvoke[i]); + } + } + _statesToInvoke = NodeSet<std::string>(); + _statesToInvoke.insert(_statesToInvoke.end(), tmp.begin(), tmp.end()); + + statesToExit.to_document_order(); + statesToExit.reverse(); + + for (int i = 0; i < statesToExit.size(); i++) { + NodeSet<std::string> historyElems = _xpath.evaluate("" + _nsPrefix + "history", statesToExit[i]).asNodeSet(); + for (int j = 0; j < historyElems.size(); j++) { + Arabica::DOM::Element<std::string> historyElem = (Arabica::DOM::Element<std::string>)historyElems[j]; + std::string historyType = (historyElem.hasAttribute("type") ? historyElem.getAttribute("type") : "shallow"); + NodeSet<std::string> historyNodes; + for (int k = 0; k < _configuration.size(); k++) { + if (boost::iequals(historyType, "deep")) { + if (isAtomic(_configuration[k]) && isDescendant(_configuration[k], statesToExit[i])) + historyNodes.push_back(_configuration[k]); + } else { + if (_configuration[k].getParentNode() == statesToExit[i]) + historyNodes.push_back(_configuration[k]); + } + } + _historyValue[historyElem.getAttribute("id")] = historyNodes; + } + } + + for (int i = 0; i < statesToExit.size(); i++) { + Arabica::XPath::NodeSet<std::string> onExitElems = _xpath.evaluate("" + _nsPrefix + "onexit", statesToExit[i]).asNodeSet(); + for (int j = 0; j < onExitElems.size(); j++) { + executeContent(onExitElems[j]); + } + Arabica::XPath::NodeSet<std::string> invokeElems = _xpath.evaluate("" + _nsPrefix + "invoke", statesToExit[i]).asNodeSet(); + for (int j = 0; j < invokeElems.size(); j++) { + cancelInvoke(invokeElems[j]); + } + } // std::cout << "States to Exit: "; // for (int i = 0; i < statesToExit.size(); i++) { @@ -1201,533 +1206,531 @@ void Interpreter::exitStates(const Arabica::XPath::NodeSet<std::string>& enabled // } // std::cout << std::endl; - // remove statesToExit from _configuration - tmp.clear(); - for (int i = 0; i < _configuration.size(); i++) { - if (!isMember(_configuration[i], statesToExit)) { - tmp.push_back(_configuration[i]); - } - } - _configuration = NodeSet<std::string>(); - _configuration.insert(_configuration.end(), tmp.begin(), tmp.end()); + // remove statesToExit from _configuration + tmp.clear(); + for (int i = 0; i < _configuration.size(); i++) { + if (!isMember(_configuration[i], statesToExit)) { + tmp.push_back(_configuration[i]); + } + } + _configuration = NodeSet<std::string>(); + _configuration.insert(_configuration.end(), tmp.begin(), tmp.end()); + - } void Interpreter::enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { - NodeSet<std::string> statesToEnter; - NodeSet<std::string> statesForDefaultEntry; - - for (int i = 0; i < enabledTransitions.size(); i++) { - Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]); - if (!isTargetless(transition)) { - std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external"); - NodeSet<std::string> tStates = getTargetStates(transition); - Arabica::DOM::Node<std::string> ancestor; - Arabica::DOM::Node<std::string> source = getSourceState(transition); - assert(source); - - bool allDescendants = true; - for (int j = 0; j < tStates.size(); j++) { - if (!isDescendant(tStates[j], source)) { - allDescendants = false; - break; - } - } - if (boost::iequals(transitionType, "internal") && - isCompound(source) && - allDescendants) - { - ancestor = source; - } else { - NodeSet<std::string> tmpStates; - tmpStates.push_back(source); - tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end()); - - ancestor = findLCCA(tmpStates); - } - - for (int j = 0; j < tStates.size(); j++) { - addStatesToEnter(tStates[j], statesToEnter, statesForDefaultEntry); - } - - for (int j = 0; j < tStates.size(); j++) { - NodeSet<std::string> ancestors = getProperAncestors(tStates[j], ancestor); - for (int k = 0; k < ancestors.size(); k++) { - statesToEnter.push_back(ancestors[k]); - if(isParallel(ancestors[k])) { - NodeSet<std::string> childs = getChildStates(ancestors[k]); - for (int l = 0; l < childs.size(); l++) { - bool someIsDescendant = false; - for (int m = 0; m < statesToEnter.size(); m++) { - if (isDescendant(statesToEnter[m], childs[l])) { - someIsDescendant = true; - break; - } - } - if (!someIsDescendant) { - addStatesToEnter(childs[l], statesToEnter, statesForDefaultEntry); - } - } - } - } - } - } - } - statesToEnter.to_document_order(); - for (int i = 0; i < statesToEnter.size(); i++) { - Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)statesToEnter[i]; - _configuration.push_back(stateElem); - _statesToInvoke.push_back(stateElem); - if (_binding == LATE && stateElem.getAttribute("isFirstEntry").size() > 0) { - Arabica::XPath::NodeSet<std::string> dataModelElems = _xpath.evaluate("" + _nsPrefix + "datamodel", stateElem).asNodeSet(); - if(dataModelElems.size() > 0 && _dataModel) { - Arabica::XPath::NodeSet<std::string> dataElems = _xpath.evaluate("" + _nsPrefix + "data", dataModelElems[0]).asNodeSet(); - for (int j = 0; j < dataElems.size(); j++) { - initializeData(dataElems[j]); - } - } - stateElem.setAttribute("isFirstEntry", ""); - } - // execute onentry executable content - Arabica::XPath::NodeSet<std::string> onEntryElems = _xpath.evaluate("" + _nsPrefix + "onentry", stateElem).asNodeSet(); - for (int j = 0; j < onEntryElems.size(); j++) { - executeContent(onEntryElems[j]); - } - if (isMember(stateElem, statesForDefaultEntry)) { - // execute initial transition content for compund states - Arabica::XPath::NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "initial/" + _nsPrefix + "transition", stateElem).asNodeSet(); - for (int j = 0; j < transitions.size(); j++) { - executeContent(transitions[j]); - } - } - - if (isFinal(stateElem)) { - internalDoneSend(stateElem); - Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)stateElem.getParentNode(); - - if (isParallel(parent.getParentNode())) { - Arabica::DOM::Element<std::string> grandParent = (Arabica::DOM::Element<std::string>)parent.getParentNode(); - - Arabica::XPath::NodeSet<std::string> childs = getChildStates(grandParent); - bool inFinalState = true; - for (int j = 0; j < childs.size(); j++) { - if (!isInFinalState(childs[j])) { - inFinalState = false; - break; - } - } - if (inFinalState) { - internalDoneSend(parent); - } - } - } - } - for (int i = 0; i < _configuration.size(); i++) { - Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)_configuration[i]; - if (isFinal(stateElem) && parentIsScxmlState(stateElem)) - _running = false; - } + NodeSet<std::string> statesToEnter; + NodeSet<std::string> statesForDefaultEntry; + + for (int i = 0; i < enabledTransitions.size(); i++) { + Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]); + if (!isTargetless(transition)) { + std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external"); + NodeSet<std::string> tStates = getTargetStates(transition); + Arabica::DOM::Node<std::string> ancestor; + Arabica::DOM::Node<std::string> source = getSourceState(transition); + assert(source); + + bool allDescendants = true; + for (int j = 0; j < tStates.size(); j++) { + if (!isDescendant(tStates[j], source)) { + allDescendants = false; + break; + } + } + if (boost::iequals(transitionType, "internal") && + isCompound(source) && + allDescendants) { + ancestor = source; + } else { + NodeSet<std::string> tmpStates; + tmpStates.push_back(source); + tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end()); + + ancestor = findLCCA(tmpStates); + } + + for (int j = 0; j < tStates.size(); j++) { + addStatesToEnter(tStates[j], statesToEnter, statesForDefaultEntry); + } + + for (int j = 0; j < tStates.size(); j++) { + NodeSet<std::string> ancestors = getProperAncestors(tStates[j], ancestor); + for (int k = 0; k < ancestors.size(); k++) { + statesToEnter.push_back(ancestors[k]); + if(isParallel(ancestors[k])) { + NodeSet<std::string> childs = getChildStates(ancestors[k]); + for (int l = 0; l < childs.size(); l++) { + bool someIsDescendant = false; + for (int m = 0; m < statesToEnter.size(); m++) { + if (isDescendant(statesToEnter[m], childs[l])) { + someIsDescendant = true; + break; + } + } + if (!someIsDescendant) { + addStatesToEnter(childs[l], statesToEnter, statesForDefaultEntry); + } + } + } + } + } + } + } + statesToEnter.to_document_order(); + for (int i = 0; i < statesToEnter.size(); i++) { + Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)statesToEnter[i]; + _configuration.push_back(stateElem); + _statesToInvoke.push_back(stateElem); + if (_binding == LATE && stateElem.getAttribute("isFirstEntry").size() > 0) { + Arabica::XPath::NodeSet<std::string> dataModelElems = _xpath.evaluate("" + _nsPrefix + "datamodel", stateElem).asNodeSet(); + if(dataModelElems.size() > 0 && _dataModel) { + Arabica::XPath::NodeSet<std::string> dataElems = _xpath.evaluate("" + _nsPrefix + "data", dataModelElems[0]).asNodeSet(); + for (int j = 0; j < dataElems.size(); j++) { + initializeData(dataElems[j]); + } + } + stateElem.setAttribute("isFirstEntry", ""); + } + // execute onentry executable content + Arabica::XPath::NodeSet<std::string> onEntryElems = _xpath.evaluate("" + _nsPrefix + "onentry", stateElem).asNodeSet(); + for (int j = 0; j < onEntryElems.size(); j++) { + executeContent(onEntryElems[j]); + } + if (isMember(stateElem, statesForDefaultEntry)) { + // execute initial transition content for compund states + Arabica::XPath::NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "initial/" + _nsPrefix + "transition", stateElem).asNodeSet(); + for (int j = 0; j < transitions.size(); j++) { + executeContent(transitions[j]); + } + } + + if (isFinal(stateElem)) { + internalDoneSend(stateElem); + Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)stateElem.getParentNode(); + + if (isParallel(parent.getParentNode())) { + Arabica::DOM::Element<std::string> grandParent = (Arabica::DOM::Element<std::string>)parent.getParentNode(); + + Arabica::XPath::NodeSet<std::string> childs = getChildStates(grandParent); + bool inFinalState = true; + for (int j = 0; j < childs.size(); j++) { + if (!isInFinalState(childs[j])) { + inFinalState = false; + break; + } + } + if (inFinalState) { + internalDoneSend(parent); + } + } + } + } + for (int i = 0; i < _configuration.size(); i++) { + Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)_configuration[i]; + if (isFinal(stateElem) && parentIsScxmlState(stateElem)) + _running = false; + } } bool Interpreter::parentIsScxmlState(Arabica::DOM::Node<std::string> state) { - Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state; - Arabica::DOM::Element<std::string> parentElem = (Arabica::DOM::Element<std::string>)state.getParentNode(); - if (boost::iequals(parentElem.getTagName(), "scxml")) - return true; - return false; + Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state; + Arabica::DOM::Element<std::string> parentElem = (Arabica::DOM::Element<std::string>)state.getParentNode(); + if (boost::iequals(parentElem.getTagName(), "scxml")) + return true; + return false; } - + bool Interpreter::isInFinalState(const Arabica::DOM::Node<std::string>& state) { // std::cout << ATTR(state, "id") << std::endl; - if (isCompound(state)) { - Arabica::XPath::NodeSet<std::string> childs = getChildStates(state); - for (int i = 0; i < childs.size(); i++) { - if (isFinal(childs[i]) && isMember(childs[i], _configuration)) - return true; - } - } else if (isParallel(state)) { - Arabica::XPath::NodeSet<std::string> childs = getChildStates(state); - for (int i = 0; i < childs.size(); i++) { - if (!isInFinalState(childs[i])) - return false; - } - return true; - } - return false; + if (isCompound(state)) { + Arabica::XPath::NodeSet<std::string> childs = getChildStates(state); + for (int i = 0; i < childs.size(); i++) { + if (isFinal(childs[i]) && isMember(childs[i], _configuration)) + return true; + } + } else if (isParallel(state)) { + Arabica::XPath::NodeSet<std::string> childs = getChildStates(state); + for (int i = 0; i < childs.size(); i++) { + if (!isInFinalState(childs[i])) + return false; + } + return true; + } + return false; } bool Interpreter::isMember(const Arabica::DOM::Node<std::string>& node, const Arabica::XPath::NodeSet<std::string>& set) { - for (int i = 0; i < set.size(); i++) { - if (set[i] == node) - return true; - } - return false; + for (int i = 0; i < set.size(); i++) { + if (set[i] == node) + return true; + } + return false; } - + void Interpreter::addStatesToEnter(const Arabica::DOM::Node<std::string>& state, - Arabica::XPath::NodeSet<std::string>& statesToEnter, - Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) { - std::string stateId = ((Arabica::DOM::Element<std::string>)state).getAttribute("id"); - if (isHistory(state)) { - if (_historyValue.find(stateId) != _historyValue.end()) { - Arabica::XPath::NodeSet<std::string> historyValue = _historyValue[stateId]; - for (int i = 0; i < historyValue.size(); i++) { - addStatesToEnter(historyValue[i], statesToEnter, statesForDefaultEntry); - NodeSet<std::string> ancestors = getProperAncestors(historyValue[i], state); - for (int j = 0; j < ancestors.size(); j++) { - statesToEnter.push_back(ancestors[j]); - } - } - } else { - NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", state).asNodeSet(); - for (int i = 0; i < transitions.size(); i++) { - NodeSet<std::string> targets = getTargetStates(transitions[i]); - for (int j = 0; j < targets.size(); j++) { - addStatesToEnter(targets[j], statesToEnter, statesForDefaultEntry); - } - } - } - } else { - statesToEnter.push_back(state); - if (isCompound(state)) { - statesForDefaultEntry.push_back(state); + Arabica::XPath::NodeSet<std::string>& statesToEnter, + Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) { + std::string stateId = ((Arabica::DOM::Element<std::string>)state).getAttribute("id"); + if (isHistory(state)) { + if (_historyValue.find(stateId) != _historyValue.end()) { + Arabica::XPath::NodeSet<std::string> historyValue = _historyValue[stateId]; + for (int i = 0; i < historyValue.size(); i++) { + addStatesToEnter(historyValue[i], statesToEnter, statesForDefaultEntry); + NodeSet<std::string> ancestors = getProperAncestors(historyValue[i], state); + for (int j = 0; j < ancestors.size(); j++) { + statesToEnter.push_back(ancestors[j]); + } + } + } else { + NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", state).asNodeSet(); + for (int i = 0; i < transitions.size(); i++) { + NodeSet<std::string> targets = getTargetStates(transitions[i]); + for (int j = 0; j < targets.size(); j++) { + addStatesToEnter(targets[j], statesToEnter, statesForDefaultEntry); + } + } + } + } else { + statesToEnter.push_back(state); + if (isCompound(state)) { + statesForDefaultEntry.push_back(state); #if 0 - NodeSet<std::string> tStates = getTargetStates(getInitialState(state)); - for (int i = 0; i < tStates.size(); i++) { - addStatesToEnter(tStates[i], statesToEnter, statesForDefaultEntry); - } + NodeSet<std::string> tStates = getTargetStates(getInitialState(state)); + for (int i = 0; i < tStates.size(); i++) { + addStatesToEnter(tStates[i], statesToEnter, statesForDefaultEntry); + } #endif - addStatesToEnter(getInitialState(state), statesToEnter, statesForDefaultEntry); + addStatesToEnter(getInitialState(state), statesToEnter, statesForDefaultEntry); // NodeSet<std::string> tStates = getTargetStates(getInitialState(state)); - } else if(isParallel(state)) { - NodeSet<std::string> childStates = getChildStates(state); - for (int i = 0; i < childStates.size(); i++) { - addStatesToEnter(childStates[i], statesToEnter, statesForDefaultEntry); - } - } - } + } else if(isParallel(state)) { + NodeSet<std::string> childStates = getChildStates(state); + for (int i = 0; i < childStates.size(); i++) { + addStatesToEnter(childStates[i], statesToEnter, statesForDefaultEntry); + } + } + } } Arabica::XPath::NodeSet<std::string> Interpreter::getChildStates(const Arabica::DOM::Node<std::string>& state) { - Arabica::XPath::NodeSet<std::string> childs; - - Arabica::DOM::NodeList<std::string> childElems = state.getChildNodes(); - for (int i = 0; i < childElems.getLength(); i++) { - if (isState(childElems.item(i))) { - childs.push_back(childElems.item(i)); - } - } - return childs; -} - + Arabica::XPath::NodeSet<std::string> childs; + + Arabica::DOM::NodeList<std::string> childElems = state.getChildNodes(); + for (int i = 0; i < childElems.getLength(); i++) { + if (isState(childElems.item(i))) { + childs.push_back(childElems.item(i)); + } + } + return childs; +} + Arabica::DOM::Node<std::string> Interpreter::findLCCA(const Arabica::XPath::NodeSet<std::string>& states) { // std::cout << "findLCCA: "; // for (int i = 0; i < states.size(); i++) { // std::cout << ((Arabica::DOM::Element<std::string>)states[i]).getAttribute("id") << " - " << states[i].getLocalName() << ", "; // } // std::cout << std::flush; - - Arabica::XPath::NodeSet<std::string> ancestors = getProperAncestors(states[0], Arabica::DOM::Node<std::string>()); - ancestors.push_back(states[0]); // state[0] may already be the ancestor - bug in W3C spec? - Arabica::DOM::Node<std::string> ancestor; - for (int i = 0; i < ancestors.size(); i++) { - for (int j = 0; j < states.size(); j++) { + + Arabica::XPath::NodeSet<std::string> ancestors = getProperAncestors(states[0], Arabica::DOM::Node<std::string>()); + ancestors.push_back(states[0]); // state[0] may already be the ancestor - bug in W3C spec? + Arabica::DOM::Node<std::string> ancestor; + for (int i = 0; i < ancestors.size(); i++) { + for (int j = 0; j < states.size(); j++) { // std::cout << "Checking " << TAGNAME(state) << " and " << TAGNAME(ancestors[i]) << std::endl; - if (!isDescendant(states[j], ancestors[i]) && (states[j] != ancestors[i])) - goto NEXT_ANCESTOR; - } - ancestor = ancestors[i]; - break; - NEXT_ANCESTOR:; - } - assert(ancestor); + if (!isDescendant(states[j], ancestors[i]) && (states[j] != ancestors[i])) + goto NEXT_ANCESTOR; + } + ancestor = ancestors[i]; + break; +NEXT_ANCESTOR: + ; + } + assert(ancestor); // std::cout << " -> " << ((Arabica::DOM::Element<std::string>)ancestor).getAttribute("id") << " " << ancestor.getLocalName() << std::endl; - return ancestor; + return ancestor; } Arabica::DOM::Node<std::string> Interpreter::getState(const std::string& stateId) { - // first try atomic and compund states + // first try atomic and compund states // std::cout << _nsPrefix << stateId << std::endl; - NodeSet<std::string> target = _xpath.evaluate("//" + _nsPrefix + "state[@id='" + stateId + "']", _doc).asNodeSet(); - if (target.size() > 0) - goto FOUND; + NodeSet<std::string> target = _xpath.evaluate("//" + _nsPrefix + "state[@id='" + stateId + "']", _doc).asNodeSet(); + if (target.size() > 0) + goto FOUND; - // now parallel states - target = _xpath.evaluate("//" + _nsPrefix + "parallel[@id='" + stateId + "']", _doc).asNodeSet(); - if (target.size() > 0) - goto FOUND; + // now parallel states + target = _xpath.evaluate("//" + _nsPrefix + "parallel[@id='" + stateId + "']", _doc).asNodeSet(); + if (target.size() > 0) + goto FOUND; - // now final states - target = _xpath.evaluate("//" + _nsPrefix + "final[@id='" + stateId + "']", _doc).asNodeSet(); - if (target.size() > 0) - goto FOUND; + // now final states + target = _xpath.evaluate("//" + _nsPrefix + "final[@id='" + stateId + "']", _doc).asNodeSet(); + if (target.size() > 0) + goto FOUND; FOUND: - if (target.size() > 0) { - assert(target.size() == 1); - return target[0]; - } - // return the empty node - return Arabica::DOM::Node<std::string>(); + if (target.size() > 0) { + assert(target.size() == 1); + return target[0]; + } + // return the empty node + return Arabica::DOM::Node<std::string>(); } Arabica::DOM::Node<std::string> Interpreter::getSourceState(const Arabica::DOM::Node<std::string>& transition) { - if (boost::iequals(TAGNAME(transition.getParentNode()), "initial")) - return transition.getParentNode().getParentNode(); - return transition.getParentNode(); -} - - /** - * In a conformant SCXML document, a compound state may specify either an "initial" - * attribute or an <initial> element, but not both. See 3.6 <initial> for a - * discussion of the difference between the two notations. If neither the "initial" - * attribute nor an <initial> element is specified, the SCXML Processor must use - * the first child state in document order as the default initial state. - */ + if (boost::iequals(TAGNAME(transition.getParentNode()), "initial")) + return transition.getParentNode().getParentNode(); + return transition.getParentNode(); +} + +/** + * In a conformant SCXML document, a compound state may specify either an "initial" + * attribute or an <initial> element, but not both. See 3.6 <initial> for a + * discussion of the difference between the two notations. If neither the "initial" + * attribute nor an <initial> element is specified, the SCXML Processor must use + * the first child state in document order as the default initial state. + */ Arabica::DOM::Node<std::string> Interpreter::getInitialState(Arabica::DOM::Node<std::string> state) { - if (!state) { - state = _doc.getFirstChild(); - while(!isState(state)) - state = state.getNextSibling(); - } - - assert(isCompound(state) || isParallel(state)); - - // initial attribute at element - Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state; - if (stateElem.hasAttribute("initial")) { - return getState(stateElem.getAttribute("initial")); - } - - // initial element as child - NodeSet<std::string> initialStates = _xpath.evaluate("" + _nsPrefix + "initial", state).asNodeSet(); - if(initialStates.size() == 1) - return initialStates[0]; - - // first child state - NodeList<std::string> childs = state.getChildNodes(); - for (int i = 0; i < childs.getLength(); i++) { - if (isState(childs.item(i))) - return childs.item(i); - } - // nothing found - return Arabica::DOM::Node<std::string>(); + if (!state) { + state = _doc.getFirstChild(); + while(!isState(state)) + state = state.getNextSibling(); + } + + assert(isCompound(state) || isParallel(state)); + + // initial attribute at element + Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state; + if (stateElem.hasAttribute("initial")) { + return getState(stateElem.getAttribute("initial")); + } + + // initial element as child + NodeSet<std::string> initialStates = _xpath.evaluate("" + _nsPrefix + "initial", state).asNodeSet(); + if(initialStates.size() == 1) + return initialStates[0]; + + // first child state + NodeList<std::string> childs = state.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + if (isState(childs.item(i))) + return childs.item(i); + } + // nothing found + return Arabica::DOM::Node<std::string>(); } NodeSet<std::string> Interpreter::getTargetStates(const Arabica::DOM::Node<std::string>& transition) { - NodeSet<std::string> targetStates; - - // if we are called with a state, process all its transitions - if (isState(transition)) { - NodeList<std::string> childs = transition.getChildNodes(); - for (int i = 0; i < childs.getLength(); i++) { - if (childs.item(i).getNodeType() == Node_base::ELEMENT_NODE && boost::iequals(TAGNAME(childs.item(i)), "transition")) { - targetStates.push_back(getTargetStates(childs.item(i))); - } - } - return targetStates; - } - - std::string targetId = ((Arabica::DOM::Element<std::string>)transition).getAttribute("target"); - - std::vector<std::string> targetIds = Interpreter::tokenizeIdRefs(ATTR(transition, "target")); - for (int i = 0; i < targetIds.size(); i++) { - Arabica::DOM::Node<std::string> state = getState(targetIds[i]); - assert(HAS_ATTR(state, "id")); - targetStates.push_back(state); - } - return targetStates; + NodeSet<std::string> targetStates; + + // if we are called with a state, process all its transitions + if (isState(transition)) { + NodeList<std::string> childs = transition.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + if (childs.item(i).getNodeType() == Node_base::ELEMENT_NODE && boost::iequals(TAGNAME(childs.item(i)), "transition")) { + targetStates.push_back(getTargetStates(childs.item(i))); + } + } + return targetStates; + } + + std::string targetId = ((Arabica::DOM::Element<std::string>)transition).getAttribute("target"); + + std::vector<std::string> targetIds = Interpreter::tokenizeIdRefs(ATTR(transition, "target")); + for (int i = 0; i < targetIds.size(); i++) { + Arabica::DOM::Node<std::string> state = getState(targetIds[i]); + assert(HAS_ATTR(state, "id")); + targetStates.push_back(state); + } + return targetStates; } std::vector<std::string> Interpreter::tokenizeIdRefs(const std::string& idRefs) { - std::vector<std::string> ids; - - if (idRefs.length() > 0) { - std::istringstream iss(idRefs); - - std::copy(std::istream_iterator<std::string>(iss), - std::istream_iterator<std::string>(), - std::back_inserter<std::vector<std::string> >(ids)); - } - - return ids; -} - + std::vector<std::string> ids; + + if (idRefs.length() > 0) { + std::istringstream iss(idRefs); + + std::copy(std::istream_iterator<std::string>(iss), + std::istream_iterator<std::string>(), + std::back_inserter<std::vector<std::string> >(ids)); + } + + return ids; +} + NodeSet<std::string> Interpreter::getProperAncestors(const Arabica::DOM::Node<std::string>& s1, - const Arabica::DOM::Node<std::string>& s2) { - NodeSet<std::string> ancestors; - if (isState(s1)) { - Arabica::DOM::Node<std::string> node = s1; - while((node = node.getParentNode())) { - if (!isState(node)) - break; - if (!boost::iequals(TAGNAME(node), "parallel") && !boost::iequals(TAGNAME(node), "state") && !boost::iequals(TAGNAME(node), "scxml")) - break; - if (node == s2) - break; - ancestors.push_back(node); - } - } - return ancestors; + const Arabica::DOM::Node<std::string>& s2) { + NodeSet<std::string> ancestors; + if (isState(s1)) { + Arabica::DOM::Node<std::string> node = s1; + while((node = node.getParentNode())) { + if (!isState(node)) + break; + if (!boost::iequals(TAGNAME(node), "parallel") && !boost::iequals(TAGNAME(node), "state") && !boost::iequals(TAGNAME(node), "scxml")) + break; + if (node == s2) + break; + ancestors.push_back(node); + } + } + return ancestors; } bool Interpreter::isDescendant(const Arabica::DOM::Node<std::string>& s1, - const Arabica::DOM::Node<std::string>& s2) { - Arabica::DOM::Node<std::string> parent = s1.getParentNode(); - while(parent) { - if (s2 == parent) - return true; - parent = parent.getParentNode(); - } - return false; -} - + const Arabica::DOM::Node<std::string>& s2) { + Arabica::DOM::Node<std::string> parent = s1.getParentNode(); + while(parent) { + if (s2 == parent) + return true; + parent = parent.getParentNode(); + } + return false; +} + bool Interpreter::isTargetless(const Arabica::DOM::Node<std::string>& transition) { - if (transition.hasAttributes()) { - if (((Arabica::DOM::Element<std::string>)transition).hasAttribute("target")) - return false; - } - return true; + if (transition.hasAttributes()) { + if (((Arabica::DOM::Element<std::string>)transition).hasAttribute("target")) + return false; + } + return true; } bool Interpreter::isWithinSameChild(const Arabica::DOM::Node<std::string>& transition) { - if (!isTargetless(transition)) { - std::string target = ((Arabica::DOM::Element<std::string>)transition).getAttribute("target"); - Arabica::XPath::XPath<std::string> xpath; - // @todo: do we need to look at parallel as well? - if (xpath.evaluate("" + _nsPrefix + "state[id=\"" + target + "\"]", transition.getParentNode()).asNodeSet().size() > 0) - return true; - } - return false; + if (!isTargetless(transition)) { + std::string target = ((Arabica::DOM::Element<std::string>)transition).getAttribute("target"); + Arabica::XPath::XPath<std::string> xpath; + // @todo: do we need to look at parallel as well? + if (xpath.evaluate("" + _nsPrefix + "state[id=\"" + target + "\"]", transition.getParentNode()).asNodeSet().size() > 0) + return true; + } + return false; } bool Interpreter::isState(const Arabica::DOM::Node<std::string>& state) { - if (!state) - return false; - if (state.getNodeType() != Arabica::DOM::Node_base::ELEMENT_NODE) - return false; - - std::string tagName = TAGNAME(state); - if (boost::iequals("state", tagName)) - return true; - if (boost::iequals("scxml", tagName)) - return true; - if (boost::iequals("parallel", tagName)) - return true; - if (boost::iequals("final", tagName)) - return true; - return false; + if (!state) + return false; + if (state.getNodeType() != Arabica::DOM::Node_base::ELEMENT_NODE) + return false; + + std::string tagName = TAGNAME(state); + if (boost::iequals("state", tagName)) + return true; + if (boost::iequals("scxml", tagName)) + return true; + if (boost::iequals("parallel", tagName)) + return true; + if (boost::iequals("final", tagName)) + return true; + return false; } bool Interpreter::isFinal(const Arabica::DOM::Node<std::string>& state) { - std::string tagName = TAGNAME(state); - if (boost::iequals("final", tagName)) - return true; - if (HAS_ATTR(state, "final") && boost::iequals("true", ATTR(state, "final"))) - return true; - return false; + std::string tagName = TAGNAME(state); + if (boost::iequals("final", tagName)) + return true; + if (HAS_ATTR(state, "final") && boost::iequals("true", ATTR(state, "final"))) + return true; + return false; } bool Interpreter::isInitial(const Arabica::DOM::Node<std::string>& state) { - if (!isState(state)) - return false; - - Arabica::DOM::Node<std::string> parent = state.getParentNode(); - if (!isState(parent)) - return true; // scxml element - - if (getInitialState(parent) == state) - return true; // every nested node - - return false; + if (!isState(state)) + return false; + + Arabica::DOM::Node<std::string> parent = state.getParentNode(); + if (!isState(parent)) + return true; // scxml element + + if (getInitialState(parent) == state) + return true; // every nested node + + return false; } bool Interpreter::isPseudoState(const Arabica::DOM::Node<std::string>& state) { - std::string tagName = TAGNAME(state); - if (boost::iequals("initial", tagName)) - return true; - if (boost::iequals("history", tagName)) - return true; - return false; + std::string tagName = TAGNAME(state); + if (boost::iequals("initial", tagName)) + return true; + if (boost::iequals("history", tagName)) + return true; + return false; } bool Interpreter::isTransitionTarget(const Arabica::DOM::Node<std::string>& elem) { - return (isState(elem) || boost::iequals(TAGNAME(elem), "history")); + return (isState(elem) || boost::iequals(TAGNAME(elem), "history")); } bool Interpreter::isAtomic(const Arabica::DOM::Node<std::string>& state) { - if (boost::iequals("final", TAGNAME(state))) - return true; - - // I will assume that parallel states are not meant to be atomic. - if (boost::iequals("parallel", TAGNAME(state))) - return false; + if (boost::iequals("final", TAGNAME(state))) + return true; - Arabica::DOM::NodeList<std::string> childs = state.getChildNodes(); - for (unsigned int i = 0; i < childs.getLength(); i++) { - if (isState(childs.item(i))) - return false; - } - return true; + // I will assume that parallel states are not meant to be atomic. + if (boost::iequals("parallel", TAGNAME(state))) + return false; + + Arabica::DOM::NodeList<std::string> childs = state.getChildNodes(); + for (unsigned int i = 0; i < childs.getLength(); i++) { + if (isState(childs.item(i))) + return false; + } + return true; } bool Interpreter::isHistory(const Arabica::DOM::Node<std::string>& state) { - if (boost::iequals("history", TAGNAME(state))) - return true; - return false; + if (boost::iequals("history", TAGNAME(state))) + return true; + return false; } bool Interpreter::isParallel(const Arabica::DOM::Node<std::string>& state) { - if (!isState(state)) - return false; - if (boost::iequals("parallel", TAGNAME(state))) - return true; - return false; + if (!isState(state)) + return false; + if (boost::iequals("parallel", TAGNAME(state))) + return true; + return false; } - + bool Interpreter::isCompound(const Arabica::DOM::Node<std::string>& state) { - if (!isState(state)) - return false; + if (!isState(state)) + return false; + + if (boost::iequals(TAGNAME(state), "parallel")) + return false; - if (boost::iequals(TAGNAME(state), "parallel")) - return false; - - Arabica::DOM::NodeList<std::string> childs = state.getChildNodes(); - for (unsigned int i = 0; i < childs.getLength(); i++) { - if (isState(childs.item(i))) - return true; - } - return false; + Arabica::DOM::NodeList<std::string> childs = state.getChildNodes(); + for (unsigned int i = 0; i < childs.getLength(); i++) { + if (isState(childs.item(i))) + return true; + } + return false; } void Interpreter::setupIOProcessors() { - std::map<std::string, IOProcessor*>::iterator ioProcIter = Factory::getInstance()->_ioProcessors.begin(); - while(ioProcIter != Factory::getInstance()->_ioProcessors.end()) { - _ioProcessors[ioProcIter->first] = Factory::getIOProcessor(ioProcIter->first, this); - if (_dataModel) { - try { -// _dataModel->setData("_ioprocessors", ioProcIter->first, _ioProcessors[ioProcIter->first]->getDataModelVariables()); - _dataModel->assign("_ioprocessors['" + ioProcIter->first + "']", _ioProcessors[ioProcIter->first]->getDataModelVariables()); -// std::cout << _dataModel->evalAsString("_ioprocessors['basichttp'].location") << std::endl; - } catch (Event e) { - LOG(ERROR) << "Syntax error when setting _ioprocessors:" << std::endl << e << std::endl; - } - } else { - LOG(INFO) << "Not registering " << ioProcIter->first << " at _ioprocessors in datamodel, no datamodel specified"; - } - ioProcIter++; - } + std::map<std::string, IOProcessor*>::iterator ioProcIter = Factory::getInstance()->_ioProcessors.begin(); + while(ioProcIter != Factory::getInstance()->_ioProcessors.end()) { + _ioProcessors[ioProcIter->first] = Factory::getIOProcessor(ioProcIter->first, this); + if (_dataModel) { + try { + _dataModel->registerIOProcessor(ioProcIter->first, _ioProcessors[ioProcIter->first]); + } catch (Event e) { + LOG(ERROR) << "Syntax error when setting _ioprocessors:" << std::endl << e << std::endl; + } + } else { + LOG(INFO) << "Not registering " << ioProcIter->first << " at _ioprocessors in datamodel, no datamodel specified"; + } + ioProcIter++; + } } IOProcessor* Interpreter::getIOProcessor(const std::string& type) { - if (_ioProcessors.find(type) == _ioProcessors.end()) { - LOG(ERROR) << "No ioProcessor known for type " << type; - return NULL; - } - return _ioProcessors[type]; + if (_ioProcessors.find(type) == _ioProcessors.end()) { + LOG(ERROR) << "No ioProcessor known for type " << type; + return NULL; + } + return _ioProcessors[type]; } //IOProcessor* Interpreter::getIOProcessorForId(const std::string& sendId) { @@ -1737,237 +1740,237 @@ IOProcessor* Interpreter::getIOProcessor(const std::string& type) { // } // return _ioProcessorsIds[sendId]; //} - + bool Interpreter::validate() { - bool validationErrors = false; - - if (!_doc) { - LOG(ERROR) << "Document " << _baseURI.as_string() << " was not parsed successfully" << std::endl; - return false; - } - - // semantic issues ------------ - if ((_xpath.evaluate("/" + _nsPrefix + "scxml/@datamodel", _doc).asNodeSet().size() == 0) && - _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "script", _doc).asNodeSet().size() > 0) { - LOG(ERROR) << "Script elements used, but no datamodel specified" << std::endl; - } - - // element issues ------------ - Arabica::XPath::NodeSet<std::string> scxmlElems = _xpath.evaluate(_nsPrefix + "scxml", _doc).asNodeSet(); - if (scxmlElems.size() > 0) - LOG(ERROR) << "More than one scxml element found" << std::endl; - for (unsigned int i = 0; i < scxmlElems.size(); i++) { - if (!HAS_ATTR(scxmlElems[i], "xmlns")) - LOG(ERROR) << "scxml element has no xmlns attribute" << std::endl; - if (!HAS_ATTR(scxmlElems[i], "version")) - LOG(ERROR) << "scxml element has no version attribute" << std::endl; - NodeList<std::string> childs = scxmlElems[i].getChildNodes(); - for (unsigned int j = 0; j < childs.getLength(); j++) { - if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) - continue; - if (boost::iequals(TAGNAME(childs.item(j)), "state") || - boost::iequals(TAGNAME(childs.item(j)), "parallel") || - boost::iequals(TAGNAME(childs.item(j)), "final") || - boost::iequals(TAGNAME(childs.item(j)), "datamodel") || - boost::iequals(TAGNAME(childs.item(j)), "script")) { - LOG(ERROR) << "scxml element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; - } - } - } - - Arabica::XPath::NodeSet<std::string> stateElems = _xpath.evaluate(_nsPrefix + "state", _doc).asNodeSet(); - for (unsigned int i = 0; i < stateElems.size(); i++) { - NodeList<std::string> childs = stateElems[i].getChildNodes(); - for (unsigned int j = 0; j < childs.getLength(); j++) { - if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) - continue; - if (boost::iequals(TAGNAME(childs.item(j)), "onentry") || - boost::iequals(TAGNAME(childs.item(j)), "onexit") || - boost::iequals(TAGNAME(childs.item(j)), "transition") || - boost::iequals(TAGNAME(childs.item(j)), "initial") || - boost::iequals(TAGNAME(childs.item(j)), "state") || - boost::iequals(TAGNAME(childs.item(j)), "parallel") || - boost::iequals(TAGNAME(childs.item(j)), "final") || - boost::iequals(TAGNAME(childs.item(j)), "history") || - boost::iequals(TAGNAME(childs.item(j)), "datamodel") || - boost::iequals(TAGNAME(childs.item(j)), "invoke")) { - LOG(ERROR) << "state element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; - } - } - } - - Arabica::XPath::NodeSet<std::string> parallelElems = _xpath.evaluate(_nsPrefix + "parallel", _doc).asNodeSet(); - for (unsigned int i = 0; i < parallelElems.size(); i++) { - NodeList<std::string> childs = parallelElems[i].getChildNodes(); - for (unsigned int j = 0; j < childs.getLength(); j++) { - if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) - continue; - if (boost::iequals(TAGNAME(childs.item(j)), "onentry") || - boost::iequals(TAGNAME(childs.item(j)), "onexit") || - boost::iequals(TAGNAME(childs.item(j)), "transition") || - boost::iequals(TAGNAME(childs.item(j)), "state") || - boost::iequals(TAGNAME(childs.item(j)), "parallel") || - boost::iequals(TAGNAME(childs.item(j)), "history") || - boost::iequals(TAGNAME(childs.item(j)), "datamodel") || - boost::iequals(TAGNAME(childs.item(j)), "invoke")) { - LOG(ERROR) << "parallel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; - } - } - } - - Arabica::XPath::NodeSet<std::string> transitionElems = _xpath.evaluate(_nsPrefix + "transition", _doc).asNodeSet(); - for (unsigned int i = 0; i < transitionElems.size(); i++) { - if (HAS_ATTR(transitionElems[i], "cond") && - !HAS_ATTR(transitionElems[i], "event")) { - LOG(ERROR) << "transition element with cond attribute but without event attribute not allowed" << std::endl; - } - NodeList<std::string> childs = scxmlElems[i].getChildNodes(); - for (unsigned int j = 0; j < childs.getLength(); j++) { - if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) - continue; - } - } - - Arabica::XPath::NodeSet<std::string> initialElems = _xpath.evaluate(_nsPrefix + "initial", _doc).asNodeSet(); - for (unsigned int i = 0; i < initialElems.size(); i++) { - NodeList<std::string> childs = initialElems[i].getChildNodes(); - for (unsigned int j = 0; j < childs.getLength(); j++) { - if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) - continue; - if (boost::iequals(TAGNAME(childs.item(j)), "transition")) { - LOG(ERROR) << "initial element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; - } - } - } - - Arabica::XPath::NodeSet<std::string> finalElems = _xpath.evaluate(_nsPrefix + "final", _doc).asNodeSet(); - for (unsigned int i = 0; i < finalElems.size(); i++) { - NodeList<std::string> childs = finalElems[i].getChildNodes(); - for (unsigned int j = 0; j < childs.getLength(); j++) { - if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) - continue; - if (!boost::iequals(TAGNAME(childs.item(j)), "onentry") || - !boost::iequals(TAGNAME(childs.item(j)), "onexit") || - !boost::iequals(TAGNAME(childs.item(j)), "donedata")) { - LOG(ERROR) << "parallel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; - } - } - } - - Arabica::XPath::NodeSet<std::string> historyElems = _xpath.evaluate(_nsPrefix + "history", _doc).asNodeSet(); - for (unsigned int i = 0; i < historyElems.size(); i++) { - NodeList<std::string> childs = historyElems[i].getChildNodes(); - for (unsigned int j = 0; j < childs.getLength(); j++) { - if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) - continue; - if (boost::iequals(TAGNAME(childs.item(j)), "transition")) { - LOG(ERROR) << "history element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; - } - } - } - - Arabica::XPath::NodeSet<std::string> datamodelElems = _xpath.evaluate(_nsPrefix + "datamodel", _doc).asNodeSet(); - for (unsigned int i = 0; i < datamodelElems.size(); i++) { - NodeList<std::string> childs = datamodelElems[i].getChildNodes(); - for (unsigned int j = 0; j < childs.getLength(); j++) { - if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) - continue; - if (!boost::iequals(TAGNAME(childs.item(j)), "data")) { - LOG(ERROR) << "datamodel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; - } - } - } - - Arabica::XPath::NodeSet<std::string> dataElems = _xpath.evaluate(_nsPrefix + "data", _doc).asNodeSet(); - for (unsigned int i = 0; i < dataElems.size(); i++) { - if (!HAS_ATTR(dataElems[i], "id")) - LOG(ERROR) << "data element has no id attribute" << std::endl; - } - - return validationErrors; -} - + bool validationErrors = false; + + if (!_doc) { + LOG(ERROR) << "Document " << _baseURI.as_string() << " was not parsed successfully" << std::endl; + return false; + } + + // semantic issues ------------ + if ((_xpath.evaluate("/" + _nsPrefix + "scxml/@datamodel", _doc).asNodeSet().size() == 0) && + _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "script", _doc).asNodeSet().size() > 0) { + LOG(ERROR) << "Script elements used, but no datamodel specified" << std::endl; + } + + // element issues ------------ + Arabica::XPath::NodeSet<std::string> scxmlElems = _xpath.evaluate(_nsPrefix + "scxml", _doc).asNodeSet(); + if (scxmlElems.size() > 0) + LOG(ERROR) << "More than one scxml element found" << std::endl; + for (unsigned int i = 0; i < scxmlElems.size(); i++) { + if (!HAS_ATTR(scxmlElems[i], "xmlns")) + LOG(ERROR) << "scxml element has no xmlns attribute" << std::endl; + if (!HAS_ATTR(scxmlElems[i], "version")) + LOG(ERROR) << "scxml element has no version attribute" << std::endl; + NodeList<std::string> childs = scxmlElems[i].getChildNodes(); + for (unsigned int j = 0; j < childs.getLength(); j++) { + if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) + continue; + if (boost::iequals(TAGNAME(childs.item(j)), "state") || + boost::iequals(TAGNAME(childs.item(j)), "parallel") || + boost::iequals(TAGNAME(childs.item(j)), "final") || + boost::iequals(TAGNAME(childs.item(j)), "datamodel") || + boost::iequals(TAGNAME(childs.item(j)), "script")) { + LOG(ERROR) << "scxml element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; + } + } + } + + Arabica::XPath::NodeSet<std::string> stateElems = _xpath.evaluate(_nsPrefix + "state", _doc).asNodeSet(); + for (unsigned int i = 0; i < stateElems.size(); i++) { + NodeList<std::string> childs = stateElems[i].getChildNodes(); + for (unsigned int j = 0; j < childs.getLength(); j++) { + if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) + continue; + if (boost::iequals(TAGNAME(childs.item(j)), "onentry") || + boost::iequals(TAGNAME(childs.item(j)), "onexit") || + boost::iequals(TAGNAME(childs.item(j)), "transition") || + boost::iequals(TAGNAME(childs.item(j)), "initial") || + boost::iequals(TAGNAME(childs.item(j)), "state") || + boost::iequals(TAGNAME(childs.item(j)), "parallel") || + boost::iequals(TAGNAME(childs.item(j)), "final") || + boost::iequals(TAGNAME(childs.item(j)), "history") || + boost::iequals(TAGNAME(childs.item(j)), "datamodel") || + boost::iequals(TAGNAME(childs.item(j)), "invoke")) { + LOG(ERROR) << "state element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; + } + } + } + + Arabica::XPath::NodeSet<std::string> parallelElems = _xpath.evaluate(_nsPrefix + "parallel", _doc).asNodeSet(); + for (unsigned int i = 0; i < parallelElems.size(); i++) { + NodeList<std::string> childs = parallelElems[i].getChildNodes(); + for (unsigned int j = 0; j < childs.getLength(); j++) { + if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) + continue; + if (boost::iequals(TAGNAME(childs.item(j)), "onentry") || + boost::iequals(TAGNAME(childs.item(j)), "onexit") || + boost::iequals(TAGNAME(childs.item(j)), "transition") || + boost::iequals(TAGNAME(childs.item(j)), "state") || + boost::iequals(TAGNAME(childs.item(j)), "parallel") || + boost::iequals(TAGNAME(childs.item(j)), "history") || + boost::iequals(TAGNAME(childs.item(j)), "datamodel") || + boost::iequals(TAGNAME(childs.item(j)), "invoke")) { + LOG(ERROR) << "parallel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; + } + } + } + + Arabica::XPath::NodeSet<std::string> transitionElems = _xpath.evaluate(_nsPrefix + "transition", _doc).asNodeSet(); + for (unsigned int i = 0; i < transitionElems.size(); i++) { + if (HAS_ATTR(transitionElems[i], "cond") && + !HAS_ATTR(transitionElems[i], "event")) { + LOG(ERROR) << "transition element with cond attribute but without event attribute not allowed" << std::endl; + } + NodeList<std::string> childs = scxmlElems[i].getChildNodes(); + for (unsigned int j = 0; j < childs.getLength(); j++) { + if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) + continue; + } + } + + Arabica::XPath::NodeSet<std::string> initialElems = _xpath.evaluate(_nsPrefix + "initial", _doc).asNodeSet(); + for (unsigned int i = 0; i < initialElems.size(); i++) { + NodeList<std::string> childs = initialElems[i].getChildNodes(); + for (unsigned int j = 0; j < childs.getLength(); j++) { + if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) + continue; + if (boost::iequals(TAGNAME(childs.item(j)), "transition")) { + LOG(ERROR) << "initial element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; + } + } + } + + Arabica::XPath::NodeSet<std::string> finalElems = _xpath.evaluate(_nsPrefix + "final", _doc).asNodeSet(); + for (unsigned int i = 0; i < finalElems.size(); i++) { + NodeList<std::string> childs = finalElems[i].getChildNodes(); + for (unsigned int j = 0; j < childs.getLength(); j++) { + if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) + continue; + if (!boost::iequals(TAGNAME(childs.item(j)), "onentry") || + !boost::iequals(TAGNAME(childs.item(j)), "onexit") || + !boost::iequals(TAGNAME(childs.item(j)), "donedata")) { + LOG(ERROR) << "parallel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; + } + } + } + + Arabica::XPath::NodeSet<std::string> historyElems = _xpath.evaluate(_nsPrefix + "history", _doc).asNodeSet(); + for (unsigned int i = 0; i < historyElems.size(); i++) { + NodeList<std::string> childs = historyElems[i].getChildNodes(); + for (unsigned int j = 0; j < childs.getLength(); j++) { + if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) + continue; + if (boost::iequals(TAGNAME(childs.item(j)), "transition")) { + LOG(ERROR) << "history element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; + } + } + } + + Arabica::XPath::NodeSet<std::string> datamodelElems = _xpath.evaluate(_nsPrefix + "datamodel", _doc).asNodeSet(); + for (unsigned int i = 0; i < datamodelElems.size(); i++) { + NodeList<std::string> childs = datamodelElems[i].getChildNodes(); + for (unsigned int j = 0; j < childs.getLength(); j++) { + if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE) + continue; + if (!boost::iequals(TAGNAME(childs.item(j)), "data")) { + LOG(ERROR) << "datamodel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl; + } + } + } + + Arabica::XPath::NodeSet<std::string> dataElems = _xpath.evaluate(_nsPrefix + "data", _doc).asNodeSet(); + for (unsigned int i = 0; i < dataElems.size(); i++) { + if (!HAS_ATTR(dataElems[i], "id")) + LOG(ERROR) << "data element has no id attribute" << std::endl; + } + + return validationErrors; +} + void Interpreter::dump() { - if (!_doc) - return; - dump(_doc); + if (!_doc) + return; + dump(_doc); } void Interpreter::dump(const Arabica::DOM::Node<std::string>& node, int lvl) { - if (!node) - return; - - std::string indent = ""; - for (unsigned int i = 0; i < lvl; i++) - indent += " "; - - std::cout << indent; - switch(node.getNodeType()) { - case Arabica::DOM::Node_base::ELEMENT_NODE: { - std::cout << "ELEMENT_NODE: "; - Arabica::DOM::Element<std::string> elem = (Arabica::DOM::Element<std::string>)node; - break; - } - case Arabica::DOM::Node_base::ATTRIBUTE_NODE: - std::cout << "ATTRIBUTE_NODE: "; - break; - case Arabica::DOM::Node_base::TEXT_NODE: - std::cout << "TEXT_NODE: "; - break; - case Arabica::DOM::Node_base::CDATA_SECTION_NODE: - std::cout << "CDATA_SECTION_NODE: "; - break; - case Arabica::DOM::Node_base::ENTITY_REFERENCE_NODE: - std::cout << "ENTITY_REFERENCE_NODE: "; - break; - case Arabica::DOM::Node_base::ENTITY_NODE: - std::cout << "ENTITY_NODE: "; - break; - case Arabica::DOM::Node_base::PROCESSING_INSTRUCTION_NODE: - std::cout << "PROCESSING_INSTRUCTION_NODE: "; - break; - case Arabica::DOM::Node_base::COMMENT_NODE: - std::cout << "COMMENT_NODE: "; - break; - case Arabica::DOM::Node_base::DOCUMENT_NODE: - std::cout << "DOCUMENT_NODE: "; - break; - case Arabica::DOM::Node_base::DOCUMENT_TYPE_NODE: - std::cout << "DOCUMENT_TYPE_NODE: "; - break; - case Arabica::DOM::Node_base::DOCUMENT_FRAGMENT_NODE: - std::cout << "DOCUMENT_FRAGMENT_NODE: "; - break; - case Arabica::DOM::Node_base::NOTATION_NODE: - std::cout << "NOTATION_NODE: "; - break; - case Arabica::DOM::Node_base::MAX_TYPE: - std::cout << "MAX_TYPE: "; - break; - } - std::cout << node.getNamespaceURI() << " " << node.getNodeName() << std::endl; - - if (node.getNodeValue().length() > 0 && node.getNodeValue().find_first_not_of(" \t\n") != std::string::npos) - std::cout << indent << "Value: '" << node.getNodeValue() << "'" << std::endl; - - - if (node.hasAttributes()) { - Arabica::DOM::NamedNodeMap<std::string> attrs = node.getAttributes(); - for (unsigned int i = 0; i < attrs.getLength(); i++) { - std::cout << indent << " " << attrs.item(i).getLocalName() << " = " << attrs.item(i).getNodeValue() << " (" << std::endl; - std::cout << indent << " namespace: " << attrs.item(i).getNamespaceURI() << std::endl; - std::cout << indent << " nodeName: " << attrs.item(i).getNodeName() << std::endl; - std::cout << indent << " prefix: " << attrs.item(i).getPrefix() << std::endl; - std::cout << indent << " )" << std::endl; - } - } - - if (node.hasChildNodes()) { - Arabica::DOM::NodeList<std::string> childs = node.getChildNodes(); - for (unsigned int i = 0; i < childs.getLength(); i++) { - dump(childs.item(i), lvl+1); - } - } + if (!node) + return; + + std::string indent = ""; + for (unsigned int i = 0; i < lvl; i++) + indent += " "; + + std::cout << indent; + switch(node.getNodeType()) { + case Arabica::DOM::Node_base::ELEMENT_NODE: { + std::cout << "ELEMENT_NODE: "; + Arabica::DOM::Element<std::string> elem = (Arabica::DOM::Element<std::string>)node; + break; + } + case Arabica::DOM::Node_base::ATTRIBUTE_NODE: + std::cout << "ATTRIBUTE_NODE: "; + break; + case Arabica::DOM::Node_base::TEXT_NODE: + std::cout << "TEXT_NODE: "; + break; + case Arabica::DOM::Node_base::CDATA_SECTION_NODE: + std::cout << "CDATA_SECTION_NODE: "; + break; + case Arabica::DOM::Node_base::ENTITY_REFERENCE_NODE: + std::cout << "ENTITY_REFERENCE_NODE: "; + break; + case Arabica::DOM::Node_base::ENTITY_NODE: + std::cout << "ENTITY_NODE: "; + break; + case Arabica::DOM::Node_base::PROCESSING_INSTRUCTION_NODE: + std::cout << "PROCESSING_INSTRUCTION_NODE: "; + break; + case Arabica::DOM::Node_base::COMMENT_NODE: + std::cout << "COMMENT_NODE: "; + break; + case Arabica::DOM::Node_base::DOCUMENT_NODE: + std::cout << "DOCUMENT_NODE: "; + break; + case Arabica::DOM::Node_base::DOCUMENT_TYPE_NODE: + std::cout << "DOCUMENT_TYPE_NODE: "; + break; + case Arabica::DOM::Node_base::DOCUMENT_FRAGMENT_NODE: + std::cout << "DOCUMENT_FRAGMENT_NODE: "; + break; + case Arabica::DOM::Node_base::NOTATION_NODE: + std::cout << "NOTATION_NODE: "; + break; + case Arabica::DOM::Node_base::MAX_TYPE: + std::cout << "MAX_TYPE: "; + break; + } + std::cout << node.getNamespaceURI() << " " << node.getNodeName() << std::endl; + + if (node.getNodeValue().length() > 0 && node.getNodeValue().find_first_not_of(" \t\n") != std::string::npos) + std::cout << indent << "Value: '" << node.getNodeValue() << "'" << std::endl; + + + if (node.hasAttributes()) { + Arabica::DOM::NamedNodeMap<std::string> attrs = node.getAttributes(); + for (unsigned int i = 0; i < attrs.getLength(); i++) { + std::cout << indent << " " << attrs.item(i).getLocalName() << " = " << attrs.item(i).getNodeValue() << " (" << std::endl; + std::cout << indent << " namespace: " << attrs.item(i).getNamespaceURI() << std::endl; + std::cout << indent << " nodeName: " << attrs.item(i).getNodeName() << std::endl; + std::cout << indent << " prefix: " << attrs.item(i).getPrefix() << std::endl; + std::cout << indent << " )" << std::endl; + } + } + + if (node.hasChildNodes()) { + Arabica::DOM::NodeList<std::string> childs = node.getChildNodes(); + for (unsigned int i = 0; i < childs.getLength(); i++) { + dump(childs.item(i), lvl+1); + } + } } }
\ No newline at end of file diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 6890baf..58b2a51 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -25,320 +25,351 @@ namespace uscxml { - class Interpreter { - public: - enum Binding { - EARLY = 0, - LATE = 1 - }; - - virtual ~Interpreter(); - - static Interpreter* fromDOM(const Arabica::DOM::Node<std::string>& node); - static Interpreter* fromXML(const std::string& xml); - static Interpreter* fromURI(const std::string& uri); - static Interpreter* fromInputSource(Arabica::SAX::InputSource<std::string>& source); - - void start(); - static void run(void*); - void join() { if (_thread != NULL) _thread->join(); }; - - void interpret(); - bool validate(); - - void setBaseURI(std::string baseURI) { _baseURI = Arabica::io::URI(baseURI); } - Arabica::io::URI getBaseURI() { return _baseURI; } - bool makeAbsolute(Arabica::io::URI& uri); - - DataModel* getDataModel() { return _dataModel; } - Invoker* getInvoker() { return _invoker; } - void setInvoker(Invoker* invoker) { _invoker = invoker; } - std::string getNSPrefix() { return _nsPrefix; } - Arabica::XPath::XPath<std::string>& getXPath() { return _xpath; } - - void waitForStabilization(); - - void receive(Event& event) { _externalQueue.push(event); } - void receiveInternal(Event& event) { _internalQueue.push_back(event); } - Arabica::XPath::NodeSet<std::string> getConfiguration() { return _configuration; } - Arabica::DOM::Node<std::string> getState(const std::string& stateId); - Arabica::DOM::Document<std::string>& getDocument() { return _doc; } - - const std::string& getName() { return _name; } - const std::string& getSessionId() { return _sessionId; } - - static bool isMember(const Arabica::DOM::Node<std::string>& node, const Arabica::XPath::NodeSet<std::string>& set); - - void dump(); - static void dump(const Arabica::DOM::Node<std::string>& node, int lvl = 0); - - static bool isState(const Arabica::DOM::Node<std::string>& state); - static bool isPseudoState(const Arabica::DOM::Node<std::string>& state); - static bool isTransitionTarget(const Arabica::DOM::Node<std::string>& elem); - static bool isTargetless(const Arabica::DOM::Node<std::string>& transition); - static bool isAtomic(const Arabica::DOM::Node<std::string>& state); - static bool isFinal(const Arabica::DOM::Node<std::string>& state); - static bool isHistory(const Arabica::DOM::Node<std::string>& state); - static bool isParallel(const Arabica::DOM::Node<std::string>& state); - static bool isCompound(const Arabica::DOM::Node<std::string>& state); - static bool isDescendant(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2); - - bool isInitial(const Arabica::DOM::Node<std::string>& state); - Arabica::DOM::Node<std::string> getInitialState(Arabica::DOM::Node<std::string> state = Arabica::DOM::Node<std::string>()); - static Arabica::XPath::NodeSet<std::string> getChildStates(const Arabica::DOM::Node<std::string>& state); - Arabica::XPath::NodeSet<std::string> getTargetStates(const Arabica::DOM::Node<std::string>& transition); - - protected: - Interpreter(); - void init(); - - void normalize(const Arabica::DOM::Document<std::string>& node); - void setupIOProcessors(); - - void mainEventLoop(); - - bool _stable; - tthread::thread* _thread; - tthread::mutex _mutex; - tthread::condition_variable _stabilized; - - Arabica::io::URI _baseURI; - Arabica::DOM::Document<std::string> _doc; - Arabica::DOM::Element<std::string> _scxml; - Arabica::XPath::XPath<std::string> _xpath; - Arabica::XPath::StandardNamespaceContext<std::string> _nsContext; - std::string _nsPrefix; - - bool _running; - Binding _binding; - Arabica::XPath::NodeSet<std::string> _configuration; - Arabica::XPath::NodeSet<std::string> _statesToInvoke; - - DataModel* _dataModel; - std::map<std::string, Arabica::XPath::NodeSet<std::string> > _historyValue; - - std::list<Event > _internalQueue; - uscxml::concurrency::BlockingQueue<Event> _externalQueue; - DelayedEventQueue* _sendQueue; - Invoker* _invoker; - - static Arabica::io::URI toBaseURI(const Arabica::io::URI& uri); - - void microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); - void exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); - void enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); - void executeTransitionContent(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); - void executeContent(const Arabica::DOM::Node<std::string>& content); - void executeContent(const Arabica::DOM::NodeList<std::string>& content); - void initializeData(const Arabica::DOM::Node<std::string>& data); - void exitInterpreter(); - - void addStatesToEnter(const Arabica::DOM::Node<std::string>& state, - Arabica::XPath::NodeSet<std::string>& statesToEnter, - Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry); - - Arabica::XPath::NodeSet<std::string> selectEventlessTransitions(); - Arabica::XPath::NodeSet<std::string> selectTransitions(const std::string& event); - Arabica::DOM::Node<std::string> getSourceState(const Arabica::DOM::Node<std::string>& transition); - Arabica::DOM::Node<std::string> findLCCA(const Arabica::XPath::NodeSet<std::string>& states); - static Arabica::XPath::NodeSet<std::string> getProperAncestors(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2); - - - void send(const Arabica::DOM::Node<std::string>& element); - void invoke(const Arabica::DOM::Node<std::string>& element); - void cancelInvoke(const Arabica::DOM::Node<std::string>& element); - void returnDoneEvent(const Arabica::DOM::Node<std::string>& state); - void internalDoneSend(const Arabica::DOM::Node<std::string>& state); - static void delayedSend(void* userdata, std::string eventName); - - static bool nameMatch(const std::string& transitionEvent, const std::string& event); - Arabica::XPath::NodeSet<std::string> filterPreempted(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); - bool hasConditionMatch(const Arabica::DOM::Node<std::string>& conditional); - bool isPreemptingTransition(const Arabica::DOM::Node<std::string>& t1, const Arabica::DOM::Node<std::string>& t2); - bool isInFinalState(const Arabica::DOM::Node<std::string>& state); - bool isWithinSameChild(const Arabica::DOM::Node<std::string>& transition); - bool parentIsScxmlState(Arabica::DOM::Node<std::string> state); - - static std::vector<std::string> tokenizeIdRefs(const std::string& idRefs); - - static boost::uuids::random_generator uuidGen; - static const std::string getUUID(); - - std::string _name; - std::string _sessionId; - - IOProcessor* getIOProcessor(const std::string& type); +class Interpreter { +public: + enum Binding { + EARLY = 0, + LATE = 1 + }; + + virtual ~Interpreter(); + + static Interpreter* fromDOM(const Arabica::DOM::Node<std::string>& node); + static Interpreter* fromXML(const std::string& xml); + static Interpreter* fromURI(const std::string& uri); + static Interpreter* fromInputSource(Arabica::SAX::InputSource<std::string>& source); + + void start(); + static void run(void*); + void join() { + if (_thread != NULL) _thread->join(); + }; + + void interpret(); + bool validate(); + + void setBaseURI(std::string baseURI) { + _baseURI = Arabica::io::URI(baseURI); + } + Arabica::io::URI getBaseURI() { + return _baseURI; + } + bool makeAbsolute(Arabica::io::URI& uri); + + DataModel* getDataModel() { + return _dataModel; + } + Invoker* getInvoker() { + return _invoker; + } + void setInvoker(Invoker* invoker) { + _invoker = invoker; + } + std::string getNSPrefix() { + return _nsPrefix; + } + Arabica::XPath::XPath<std::string>& getXPath() { + return _xpath; + } + + void waitForStabilization(); + + void receive(Event& event) { + _externalQueue.push(event); + } + void receiveInternal(Event& event) { + _internalQueue.push_back(event); + } + Arabica::XPath::NodeSet<std::string> getConfiguration() { + return _configuration; + } + Arabica::DOM::Node<std::string> getState(const std::string& stateId); + Arabica::DOM::Document<std::string>& getDocument() { + return _doc; + } + + const std::string& getName() { + return _name; + } + const std::string& getSessionId() { + return _sessionId; + } + + static bool isMember(const Arabica::DOM::Node<std::string>& node, const Arabica::XPath::NodeSet<std::string>& set); + + void dump(); + static void dump(const Arabica::DOM::Node<std::string>& node, int lvl = 0); + + static bool isState(const Arabica::DOM::Node<std::string>& state); + static bool isPseudoState(const Arabica::DOM::Node<std::string>& state); + static bool isTransitionTarget(const Arabica::DOM::Node<std::string>& elem); + static bool isTargetless(const Arabica::DOM::Node<std::string>& transition); + static bool isAtomic(const Arabica::DOM::Node<std::string>& state); + static bool isFinal(const Arabica::DOM::Node<std::string>& state); + static bool isHistory(const Arabica::DOM::Node<std::string>& state); + static bool isParallel(const Arabica::DOM::Node<std::string>& state); + static bool isCompound(const Arabica::DOM::Node<std::string>& state); + static bool isDescendant(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2); + + bool isInitial(const Arabica::DOM::Node<std::string>& state); + Arabica::DOM::Node<std::string> getInitialState(Arabica::DOM::Node<std::string> state = Arabica::DOM::Node<std::string>()); + static Arabica::XPath::NodeSet<std::string> getChildStates(const Arabica::DOM::Node<std::string>& state); + Arabica::XPath::NodeSet<std::string> getTargetStates(const Arabica::DOM::Node<std::string>& transition); + +protected: + Interpreter(); + void init(); + + void normalize(const Arabica::DOM::Document<std::string>& node); + void setupIOProcessors(); + + void mainEventLoop(); + + bool _stable; + tthread::thread* _thread; + tthread::mutex _mutex; + tthread::condition_variable _stabilized; + + Arabica::io::URI _baseURI; + Arabica::DOM::Document<std::string> _doc; + Arabica::DOM::Element<std::string> _scxml; + Arabica::XPath::XPath<std::string> _xpath; + Arabica::XPath::StandardNamespaceContext<std::string> _nsContext; + std::string _nsPrefix; + + bool _running; + Binding _binding; + Arabica::XPath::NodeSet<std::string> _configuration; + Arabica::XPath::NodeSet<std::string> _statesToInvoke; + + DataModel* _dataModel; + std::map<std::string, Arabica::XPath::NodeSet<std::string> > _historyValue; + + std::list<Event > _internalQueue; + uscxml::concurrency::BlockingQueue<Event> _externalQueue; + DelayedEventQueue* _sendQueue; + Invoker* _invoker; + + static Arabica::io::URI toBaseURI(const Arabica::io::URI& uri); + + void microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); + void exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); + void enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); + void executeTransitionContent(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); + void executeContent(const Arabica::DOM::Node<std::string>& content); + void executeContent(const Arabica::DOM::NodeList<std::string>& content); + void initializeData(const Arabica::DOM::Node<std::string>& data); + void exitInterpreter(); + + void addStatesToEnter(const Arabica::DOM::Node<std::string>& state, + Arabica::XPath::NodeSet<std::string>& statesToEnter, + Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry); + + Arabica::XPath::NodeSet<std::string> selectEventlessTransitions(); + Arabica::XPath::NodeSet<std::string> selectTransitions(const std::string& event); + Arabica::DOM::Node<std::string> getSourceState(const Arabica::DOM::Node<std::string>& transition); + Arabica::DOM::Node<std::string> findLCCA(const Arabica::XPath::NodeSet<std::string>& states); + static Arabica::XPath::NodeSet<std::string> getProperAncestors(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2); + + + void send(const Arabica::DOM::Node<std::string>& element); + void invoke(const Arabica::DOM::Node<std::string>& element); + void cancelInvoke(const Arabica::DOM::Node<std::string>& element); + void returnDoneEvent(const Arabica::DOM::Node<std::string>& state); + void internalDoneSend(const Arabica::DOM::Node<std::string>& state); + static void delayedSend(void* userdata, std::string eventName); + + static bool nameMatch(const std::string& transitionEvent, const std::string& event); + Arabica::XPath::NodeSet<std::string> filterPreempted(const Arabica::XPath::NodeSet<std::string>& enabledTransitions); + bool hasConditionMatch(const Arabica::DOM::Node<std::string>& conditional); + bool isPreemptingTransition(const Arabica::DOM::Node<std::string>& t1, const Arabica::DOM::Node<std::string>& t2); + bool isInFinalState(const Arabica::DOM::Node<std::string>& state); + bool isWithinSameChild(const Arabica::DOM::Node<std::string>& transition); + bool parentIsScxmlState(Arabica::DOM::Node<std::string> state); + + static std::vector<std::string> tokenizeIdRefs(const std::string& idRefs); + + static boost::uuids::random_generator uuidGen; + static const std::string getUUID(); + + std::string _name; + std::string _sessionId; + + IOProcessor* getIOProcessor(const std::string& type); // IOProcessor* getIOProcessorForId(const std::string& sendId); - - std::map<std::string, IOProcessor*> _ioProcessors; - std::map<std::string, std::pair<Interpreter*, SendRequest> > _sendIds; - std::map<std::string, Invoker*> _invokerIds; - std::map<std::string, Invoker*> _invokers; - - }; - + + std::map<std::string, IOProcessor*> _ioProcessors; + std::map<std::string, std::pair<Interpreter*, SendRequest> > _sendIds; + std::map<std::string, Invoker*> _invokerIds; + std::map<std::string, Invoker*> _invokers; + +}; + #if 0 - class SCXMLParseHandler : - public Arabica::SAX::EntityResolver<std::string>, - public Arabica::SAX::DTDHandler<std::string>, - public Arabica::SAX::ContentHandler<std::string>, - public Arabica::SAX::CatchErrorHandler<std::string>, - public Arabica::SAX::LexicalHandler<std::string>, - public Arabica::SAX::DeclHandler<std::string> - { - public: - SCXMLParseHandler() { } - virtual ~SCXMLParseHandler() { } - - // EntityResolver - virtual InputSourceT resolveEntity(const std::string& publicId , const std::string& systemId) { - return InputSourceT(); - } - - // DTDHandler - virtual void notationDecl(const std::string& name, - const std::string& publicId, - const std::string& systemId) { - std::cout << "notationDecl" << std::endl; - std::cout << " name:" << name << std::endl; - std::cout << " publicId:" << publicId << std::endl; - std::cout << " systemId:" << systemId << std::endl; - } - virtual void unparsedEntityDecl(const std::string& name, - const std::string& publicId, - const std::string& systemId, - const std::string& notationName) { - std::cout << "unparsedEntityDecl" << std::endl; - std::cout << " name:" << name << std::endl; - std::cout << " publicId:" << publicId << std::endl; - std::cout << " systemId:" << systemId << std::endl; - std::cout << " notationName:" << notationName << std::endl; - } - - // ContentHandler - virtual void setDocumentLocator(const LocatorT& locator) { - std::cout << "setDocumentLocator" << std::endl; - } - virtual void startDocument() { - std::cout << "startDocument" << std::endl; - } - virtual void endDocument() { - std::cout << "endDocument" << std::endl; - } - virtual void startPrefixMapping(const std::string& prefix, const std::string& uri) { - std::cout << "startPrefixMapping" << std::endl; - std::cout << " prefix:" << prefix << std::endl; - std::cout << " uri:" << uri << std::endl; - } - virtual void endPrefixMapping(const std::string& prefix) { - std::cout << "endPrefixMapping" << std::endl; - std::cout << " prefix:" << prefix << std::endl; - } - virtual void startElement(const std::string& namespaceURI, const std::string& localName, - const std::string& qName, const AttributesT& atts) { - std::cout << "startElement" << std::endl; - std::cout << " namespaceURI:" << namespaceURI << std::endl; - std::cout << " localName:" << localName << std::endl; - std::cout << " qName:" << qName << std::endl; - std::cout << " atts:" << atts.getLength() << std::endl; - } - virtual void endElement(const std::string& namespaceURI, const std::string& localName, - const std::string& qName) { - std::cout << "endElement" << std::endl; - std::cout << " namespaceURI:" << namespaceURI << std::endl; - std::cout << " localName:" << localName << std::endl; - std::cout << " qName:" << qName << std::endl; - } - virtual void characters(const std::string& ch) { - std::cout << "characters" << std::endl; - std::cout << " ch:" << ch << std::endl; - } - virtual void ignorableWhitespace(const std::string& ch) { - std::cout << "ignorableWhitespace" << std::endl; - std::cout << " ch:" << ch << std::endl; - } - virtual void processingInstruction(const std::string& target, const std::string& data) { - std::cout << "processingInstruction" << std::endl; - std::cout << " target:" << target << std::endl; - std::cout << " data:" << data << std::endl; - } - virtual void skippedEntity(const std::string& name) { - std::cout << "skippedEntity" << std::endl; - std::cout << " name:" << name << std::endl; - } - - // ErrorHandler - virtual void warning(const SAXParseExceptionT& e) { Arabica::SAX::CatchErrorHandler<std::string>::warning(e); } - virtual void error(const SAXParseExceptionT& e) { Arabica::SAX::CatchErrorHandler<std::string>::error(e); } - virtual void fatalError(const SAXParseExceptionT& e) { - Arabica::SAX::CatchErrorHandler<std::string>::fatalError(e); - } - - // LexicalHandler - virtual void startDTD(const std::string& name, - const std::string& publicId, - const std::string& systemId) { - std::cout << "startDTD" << std::endl; - std::cout << " name:" << name << std::endl; - std::cout << " publicId:" << publicId << std::endl; - std::cout << " systemId:" << systemId << std::endl; - } - - virtual void endDTD() { - std::cout << "endDTD" << std::endl; - } - virtual void startEntity(const std::string& name) { - std::cout << "startEntity" << std::endl; - std::cout << " name:" << name << std::endl; - } - virtual void endEntity(const std::string& name) { - std::cout << "endEntity" << std::endl; - std::cout << " name:" << name << std::endl; - } - virtual void startCDATA() { - std::cout << "startCDATA" << std::endl; - } - virtual void endCDATA() { - std::cout << "endCDATA" << std::endl; - } - virtual void comment(const std::string& text) { - std::cout << "comment" << std::endl; - std::cout << " text:" << text << std::endl; - } - - // DeclHandler - virtual void elementDecl(const std::string& name, const std::string& model) { - std::cout << "elementDecl" << std::endl; - std::cout << " name:" << name << std::endl; - std::cout << " model:" << model << std::endl; - } - virtual void attributeDecl(const std::string& elementName, - const std::string& attributeName, - const std::string& type, - const std::string& valueDefault, - const std::string& value) { - std::cout << "attributeDecl" << std::endl; - std::cout << " elementName:" << elementName << std::endl; - std::cout << " attributeName:" << attributeName << std::endl; - std::cout << " type:" << type << std::endl; - std::cout << " valueDefault:" << valueDefault << std::endl; - std::cout << " value:" << value << std::endl; - } - virtual void internalEntityDecl(const std::string& name, const std::string& value) { - std::cout << "internalEntityDecl" << std::endl; - std::cout << " name:" << name << std::endl; - std::cout << " value:" << value << std::endl; - } - virtual void externalEntityDecl(const std::string& name, - const std::string& publicId, - const std::string& systemId) { - std::cout << "externalEntityDecl" << std::endl; - std::cout << " name:" << name << std::endl; - std::cout << " publicId:" << publicId << std::endl; - std::cout << " systemId:" << systemId << std::endl; - } - - }; +class SCXMLParseHandler : + public Arabica::SAX::EntityResolver<std::string>, + public Arabica::SAX::DTDHandler<std::string>, + public Arabica::SAX::ContentHandler<std::string>, + public Arabica::SAX::CatchErrorHandler<std::string>, + public Arabica::SAX::LexicalHandler<std::string>, + public Arabica::SAX::DeclHandler<std::string> { +public: + SCXMLParseHandler() { } + virtual ~SCXMLParseHandler() { } + + // EntityResolver + virtual InputSourceT resolveEntity(const std::string& publicId , const std::string& systemId) { + return InputSourceT(); + } + + // DTDHandler + virtual void notationDecl(const std::string& name, + const std::string& publicId, + const std::string& systemId) { + std::cout << "notationDecl" << std::endl; + std::cout << " name:" << name << std::endl; + std::cout << " publicId:" << publicId << std::endl; + std::cout << " systemId:" << systemId << std::endl; + } + virtual void unparsedEntityDecl(const std::string& name, + const std::string& publicId, + const std::string& systemId, + const std::string& notationName) { + std::cout << "unparsedEntityDecl" << std::endl; + std::cout << " name:" << name << std::endl; + std::cout << " publicId:" << publicId << std::endl; + std::cout << " systemId:" << systemId << std::endl; + std::cout << " notationName:" << notationName << std::endl; + } + + // ContentHandler + virtual void setDocumentLocator(const LocatorT& locator) { + std::cout << "setDocumentLocator" << std::endl; + } + virtual void startDocument() { + std::cout << "startDocument" << std::endl; + } + virtual void endDocument() { + std::cout << "endDocument" << std::endl; + } + virtual void startPrefixMapping(const std::string& prefix, const std::string& uri) { + std::cout << "startPrefixMapping" << std::endl; + std::cout << " prefix:" << prefix << std::endl; + std::cout << " uri:" << uri << std::endl; + } + virtual void endPrefixMapping(const std::string& prefix) { + std::cout << "endPrefixMapping" << std::endl; + std::cout << " prefix:" << prefix << std::endl; + } + virtual void startElement(const std::string& namespaceURI, const std::string& localName, + const std::string& qName, const AttributesT& atts) { + std::cout << "startElement" << std::endl; + std::cout << " namespaceURI:" << namespaceURI << std::endl; + std::cout << " localName:" << localName << std::endl; + std::cout << " qName:" << qName << std::endl; + std::cout << " atts:" << atts.getLength() << std::endl; + } + virtual void endElement(const std::string& namespaceURI, const std::string& localName, + const std::string& qName) { + std::cout << "endElement" << std::endl; + std::cout << " namespaceURI:" << namespaceURI << std::endl; + std::cout << " localName:" << localName << std::endl; + std::cout << " qName:" << qName << std::endl; + } + virtual void characters(const std::string& ch) { + std::cout << "characters" << std::endl; + std::cout << " ch:" << ch << std::endl; + } + virtual void ignorableWhitespace(const std::string& ch) { + std::cout << "ignorableWhitespace" << std::endl; + std::cout << " ch:" << ch << std::endl; + } + virtual void processingInstruction(const std::string& target, const std::string& data) { + std::cout << "processingInstruction" << std::endl; + std::cout << " target:" << target << std::endl; + std::cout << " data:" << data << std::endl; + } + virtual void skippedEntity(const std::string& name) { + std::cout << "skippedEntity" << std::endl; + std::cout << " name:" << name << std::endl; + } + + // ErrorHandler + virtual void warning(const SAXParseExceptionT& e) { + Arabica::SAX::CatchErrorHandler<std::string>::warning(e); + } + virtual void error(const SAXParseExceptionT& e) { + Arabica::SAX::CatchErrorHandler<std::string>::error(e); + } + virtual void fatalError(const SAXParseExceptionT& e) { + Arabica::SAX::CatchErrorHandler<std::string>::fatalError(e); + } + + // LexicalHandler + virtual void startDTD(const std::string& name, + const std::string& publicId, + const std::string& systemId) { + std::cout << "startDTD" << std::endl; + std::cout << " name:" << name << std::endl; + std::cout << " publicId:" << publicId << std::endl; + std::cout << " systemId:" << systemId << std::endl; + } + + virtual void endDTD() { + std::cout << "endDTD" << std::endl; + } + virtual void startEntity(const std::string& name) { + std::cout << "startEntity" << std::endl; + std::cout << " name:" << name << std::endl; + } + virtual void endEntity(const std::string& name) { + std::cout << "endEntity" << std::endl; + std::cout << " name:" << name << std::endl; + } + virtual void startCDATA() { + std::cout << "startCDATA" << std::endl; + } + virtual void endCDATA() { + std::cout << "endCDATA" << std::endl; + } + virtual void comment(const std::string& text) { + std::cout << "comment" << std::endl; + std::cout << " text:" << text << std::endl; + } + + // DeclHandler + virtual void elementDecl(const std::string& name, const std::string& model) { + std::cout << "elementDecl" << std::endl; + std::cout << " name:" << name << std::endl; + std::cout << " model:" << model << std::endl; + } + virtual void attributeDecl(const std::string& elementName, + const std::string& attributeName, + const std::string& type, + const std::string& valueDefault, + const std::string& value) { + std::cout << "attributeDecl" << std::endl; + std::cout << " elementName:" << elementName << std::endl; + std::cout << " attributeName:" << attributeName << std::endl; + std::cout << " type:" << type << std::endl; + std::cout << " valueDefault:" << valueDefault << std::endl; + std::cout << " value:" << value << std::endl; + } + virtual void internalEntityDecl(const std::string& name, const std::string& value) { + std::cout << "internalEntityDecl" << std::endl; + std::cout << " name:" << name << std::endl; + std::cout << " value:" << value << std::endl; + } + virtual void externalEntityDecl(const std::string& name, + const std::string& publicId, + const std::string& systemId) { + std::cout << "externalEntityDecl" << std::endl; + std::cout << " name:" << name << std::endl; + std::cout << " publicId:" << publicId << std::endl; + std::cout << " systemId:" << systemId << std::endl; + } + +}; #endif } diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp index 1b2c9e8..09676bf 100644 --- a/src/uscxml/Message.cpp +++ b/src/uscxml/Message.cpp @@ -9,211 +9,207 @@ namespace uscxml { static int _dataIndentation = 1; 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; + // 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); + 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); + 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; - } + 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", "scxml:payload"); - 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", "scxml:property"); - 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::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", "scxml:payload"); + 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", "scxml:property"); + 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::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::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", "scxml:payload"); - scxmlMsg.appendChild(payloadElem); - } - Arabica::DOM::Node<std::string> payloadElem = scxmlMsg.getElementsByTagName("scxml:payload").item(0); - - // add parameters - std::map<std::string, std::list<std::string> >::iterator paramsIter = params.begin(); - while(paramsIter != params.end()) { - std::list<std::string>::iterator paramIter = paramsIter->second.begin(); - while(paramIter != paramsIter->second.end()) { - Arabica::DOM::Element<std::string> propertyElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "scxml:property"); - propertyElem.setAttribute("name", paramsIter->first); - Arabica::DOM::Text<std::string> textElem = document.createTextNode(*paramIter); - propertyElem.appendChild(textElem); - payloadElem.appendChild(propertyElem); - paramIter++; - } - paramsIter++; - } - - // add namelist elements - std::map<std::string, std::string>::iterator namelistIter = namelist.begin(); - while(namelistIter != namelist.end()) { - Arabica::DOM::Element<std::string> propertyElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "scxml:property"); - propertyElem.setAttribute("name", namelistIter->first); - Arabica::DOM::Text<std::string> textElem = document.createTextNode(namelistIter->second); - propertyElem.appendChild(textElem); - payloadElem.appendChild(propertyElem); - namelistIter++; - } - - } - - - scxmlMsg.setAttribute("sendid", sendid); - - return document; + 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", "scxml:payload"); + scxmlMsg.appendChild(payloadElem); + } + Arabica::DOM::Node<std::string> payloadElem = scxmlMsg.getElementsByTagName("scxml:payload").item(0); + + // add parameters + std::multimap<std::string, std::string>::iterator paramIter = params.begin(); + while(paramIter != params.end()) { + Arabica::DOM::Element<std::string> propertyElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "scxml:property"); + propertyElem.setAttribute("name", paramIter->first); + Arabica::DOM::Text<std::string> textElem = document.createTextNode(paramIter->second); + propertyElem.appendChild(textElem); + payloadElem.appendChild(propertyElem); + paramIter++; + } + + // add namelist elements + std::map<std::string, std::string>::iterator namelistIter = namelist.begin(); + while(namelistIter != namelist.end()) { + Arabica::DOM::Element<std::string> propertyElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "scxml:property"); + propertyElem.setAttribute("name", namelistIter->first); + Arabica::DOM::Text<std::string> textElem = document.createTextNode(namelistIter->second); + 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; + 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(); } - + 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.compound[key] = Data(value, VERBATIM); - } - } - } - } - } - } - return event; + 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.compound[key] = Data(value, VERBATIM); + } + } + } + } + } + } + return event; } SendRequest SendRequest::fromXML(const std::string& xmlString) { @@ -228,68 +224,68 @@ InvokeRequest InvokeRequest::fromXML(const std::string& xmlString) { #ifndef SWIGJAVA std::ostream& operator<< (std::ostream& os, const Event& event) { - os << (event.type == Event::EXTERNAL ? "External" : "Internal") << " Event " /* << (event.dom ? "with DOM attached" : "")*/ << std::endl; - - if (event.name.size() > 0) - os << " name: " << event.name << std::endl; - if (event.origin.size() > 0) - os << " origin: " << event.origin << std::endl; - if (event.origintype.size() > 0) - os << " origintype: " << event.origintype << std::endl; - _dataIndentation++; - os << " data: " << (Data)event << std::endl; - _dataIndentation--; - return os; + os << (event.type == Event::EXTERNAL ? "External" : "Internal") << " Event " /* << (event.dom ? "with DOM attached" : "")*/ << std::endl; + + if (event.name.size() > 0) + os << " name: " << event.name << std::endl; + if (event.origin.size() > 0) + os << " origin: " << event.origin << std::endl; + if (event.origintype.size() > 0) + os << " origintype: " << event.origintype << std::endl; + _dataIndentation++; + os << " data: " << (Data)event << std::endl; + _dataIndentation--; + return os; } #endif #ifndef SWIGJAVA std::ostream& operator<< (std::ostream& os, const Data& data) { - 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 += " "; - - os << "{" << std::endl; - compoundIter = data.compound.begin(); - while(compoundIter != data.compound.end()) { - os << indent << " \"" << compoundIter->first << "\" " << keyPadding.substr(0, longestKey - compoundIter->first.size()) << ": "; - _dataIndentation += 2; - os << compoundIter->second << "," << std::endl; - _dataIndentation -= 2; - compoundIter++; - } - os << indent << "}" << std::endl; - } else if (data.array.size() > 0) { - os << "[" << std::endl; - std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin(); - while(compoundIter != data.compound.end()) { - _dataIndentation += 2; - os << indent << " " << compoundIter->second << "," << std::endl; - _dataIndentation -= 2; - compoundIter++; - } - os << indent << "]" << std::endl; - } else if (data.atom.size() > 0) { - if (data.type == Data::VERBATIM) { - os << indent << "\"" << data.atom << "\""; - } else { - os << indent << data.atom; - } - } - return 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 += " "; + + os << "{" << std::endl; + compoundIter = data.compound.begin(); + while(compoundIter != data.compound.end()) { + os << indent << " \"" << compoundIter->first << "\" " << keyPadding.substr(0, longestKey - compoundIter->first.size()) << ": "; + _dataIndentation += 2; + os << compoundIter->second << "," << std::endl; + _dataIndentation -= 2; + compoundIter++; + } + os << indent << "}" << std::endl; + } else if (data.array.size() > 0) { + os << "[" << std::endl; + std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin(); + while(compoundIter != data.compound.end()) { + _dataIndentation += 2; + os << indent << " " << compoundIter->second << "," << std::endl; + _dataIndentation -= 2; + compoundIter++; + } + os << indent << "]" << std::endl; + } else if (data.atom.size() > 0) { + if (data.type == Data::VERBATIM) { + os << indent << "\"" << data.atom << "\""; + } else { + os << indent << data.atom; + } + } + return os; } #endif diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index ecd2bf0..1644869 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -19,105 +19,110 @@ namespace uscxml { class Data { public: - enum Type { - VERBATIM, - INTERPRETED - }; - - Data() {} - Data(const std::string& atom_, Type type_ = INTERPRETED) : atom(atom_), type(type_) {} - Data(const Arabica::DOM::Node<std::string>& dom); - virtual ~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> compound; - std::list<Data> array; - std::string atom; - Type type; + enum Type { + VERBATIM, + INTERPRETED + }; + + Data() {} + Data(const std::string& atom_, Type type_ = INTERPRETED) : atom(atom_), type(type_) {} + Data(const Arabica::DOM::Node<std::string>& dom); + virtual ~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> compound; + std::list<Data> array; + std::string atom; + Type type; protected: - Arabica::DOM::Document<std::string> toNode(const Arabica::DOM::Document<std::string>& factory, const Data& data); + Arabica::DOM::Document<std::string> toNode(const Arabica::DOM::Document<std::string>& factory, const Data& data); #ifndef SWIGJAVA - friend std::ostream& operator<< (std::ostream& os, const Data& data); + friend std::ostream& operator<< (std::ostream& os, const Data& data); #endif }; class Event : public Data { public: - enum Type { - PLATFORM, - INTERNAL, - EXTERNAL - }; - - Event() : type(INTERNAL) {} - Event(const Arabica::DOM::Node<std::string>& xmlString) : type(INTERNAL) {}; - - std::string name; - Type type; - std::string origin; - std::string origintype; + enum Type { + PLATFORM, + INTERNAL, + EXTERNAL + }; + + Event() : type(INTERNAL) {} + Event(const Arabica::DOM::Node<std::string>& xmlString) : type(INTERNAL) {}; + + std::string name; + Type type; + std::string origin; + std::string origintype; // Arabica::DOM::Node<std::string> dom; - std::string sendid; - std::string invokeid; + std::string sendid; + std::string invokeid; - static Event fromXML(const std::string& xmlString); - Arabica::DOM::Document<std::string> toDocument(); - std::string toXMLString() { - std::stringstream ss; - ss << toDocument(); - return ss.str(); - } + static Event fromXML(const std::string& xmlString); + Arabica::DOM::Document<std::string> toDocument(); + std::string toXMLString() { + std::stringstream ss; + ss << toDocument(); + return ss.str(); + } #ifndef SWIGJAVA - friend std::ostream& operator<< (std::ostream& os, const Event& event); + friend std::ostream& operator<< (std::ostream& os, const Event& event); #endif }; class InvokeRequest : public Event { public: - std::string type; - std::string src; - std::string namelist; - bool autoForward; - std::map<std::string, std::list<std::string> > params; - std::string content; - - static InvokeRequest fromXML(const std::string& xmlString); - Arabica::DOM::Document<std::string> toDocument(); - std::string toXMLString() { - std::stringstream ss; - ss << toDocument(); - return ss.str(); - } + std::string type; + std::string src; + std::string namelist; + typedef std::map<std::string, std::string> namelist_t; + bool autoForward; + std::multimap<std::string, std::string> params; + typedef std::multimap<std::string, std::string> params_t; + + std::string content; + + static InvokeRequest fromXML(const std::string& xmlString); + Arabica::DOM::Document<std::string> toDocument(); + std::string toXMLString() { + std::stringstream ss; + ss << toDocument(); + return ss.str(); + } }; class SendRequest : public Event { public: - std::string target; - std::string type; - uint32_t delayMs; - std::map<std::string, std::string> namelist; - std::map<std::string, std::list<std::string> > params; - std::string content; - - static SendRequest fromXML(const std::string& xmlString); - Arabica::DOM::Document<std::string> toDocument(); - std::string toXMLString() { - std::stringstream ss; - ss << toDocument(); + std::string target; + std::string type; + uint32_t delayMs; + std::map<std::string, std::string> namelist; + typedef std::map<std::string, std::string> namelist_t; + std::multimap<std::string, std::string> params; + typedef std::multimap<std::string, std::string> params_t; + std::string content; + + 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(); - } + return ss.str(); + } }; diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp index 991c875..8631b52 100644 --- a/src/uscxml/URL.cpp +++ b/src/uscxml/URL.cpp @@ -13,7 +13,7 @@ #include "URL.h" namespace uscxml { - + std::ostream & operator<<(std::ostream & stream, const URL& url) { std::string urlString = url._urlString; @@ -30,366 +30,355 @@ std::ostream & operator<<(std::ostream & stream, const URL& url) { LOG(ERROR) << "Trying to open " << urlString; URL_FILE *handle = url_fopen(urlString.c_str(), "r"); - if(!handle) { - LOG(ERROR) << "Cannot open URL " << url._urlString; + if(!handle) { + LOG(ERROR) << "Cannot open URL " << url._urlString; return stream; - } - + } + int nread; - char buffer[256]; + char buffer[256]; - do { - nread = url_fread(buffer, 1,sizeof(buffer), handle); - stream.write(buffer, nread); - } while(nread); + do { + nread = url_fread(buffer, 1,sizeof(buffer), handle); + stream.write(buffer, nread); + } while(nread); - url_fclose(handle); + url_fclose(handle); return stream; } - -/* we use a global one for convenience */ + +/* we use a global one for convenience */ CURLM *multi_handle; -/* curl calls this routine to get more data */ +/* curl calls this routine to get more data */ static size_t write_callback(char *buffer, size_t size, size_t nitems, - void *userp) -{ - char *newbuff; - size_t rembuff; - - URL_FILE *url = (URL_FILE *)userp; - size *= nitems; - - rembuff=url->buffer_len - url->buffer_pos; /* remaining space in buffer */ - - if(size > rembuff) { - /* not enough space in buffer */ - newbuff=(char*)realloc(url->buffer,url->buffer_len + (size - rembuff)); - if(newbuff==NULL) { - fprintf(stderr,"callback buffer grow failed\n"); - size=rembuff; - } - else { - /* realloc suceeded increase buffer size*/ - url->buffer_len+=size - rembuff; - url->buffer=newbuff; - } - } - - memcpy(&url->buffer[url->buffer_pos], buffer, size); - url->buffer_pos += size; - - return size; + void *userp) { + char *newbuff; + size_t rembuff; + + URL_FILE *url = (URL_FILE *)userp; + size *= nitems; + + rembuff=url->buffer_len - url->buffer_pos; /* remaining space in buffer */ + + if(size > rembuff) { + /* not enough space in buffer */ + newbuff=(char*)realloc(url->buffer,url->buffer_len + (size - rembuff)); + if(newbuff==NULL) { + fprintf(stderr,"callback buffer grow failed\n"); + size=rembuff; + } else { + /* realloc suceeded increase buffer size*/ + url->buffer_len+=size - rembuff; + url->buffer=newbuff; + } + } + + memcpy(&url->buffer[url->buffer_pos], buffer, size); + url->buffer_pos += size; + + return size; } - -/* use to attempt to fill the read buffer up to requested number of bytes */ -static int fill_buffer(URL_FILE *file, size_t want) -{ - fd_set fdread; - fd_set fdwrite; - fd_set fdexcep; - struct timeval timeout; - int rc; - - /* only attempt to fill buffer if transactions still running and buffer - * doesnt exceed required size already - */ - if((!file->still_running) || (file->buffer_pos > want)) - return 0; - - /* attempt to fill buffer */ - do { - int maxfd = -1; - long curl_timeo = -1; - - FD_ZERO(&fdread); - FD_ZERO(&fdwrite); - FD_ZERO(&fdexcep); - - /* set a suitable timeout to fail on */ - timeout.tv_sec = 60; /* 1 minute */ - timeout.tv_usec = 0; - - curl_multi_timeout(multi_handle, &curl_timeo); - if(curl_timeo >= 0) { - timeout.tv_sec = curl_timeo / 1000; - if(timeout.tv_sec > 1) - timeout.tv_sec = 1; - else - timeout.tv_usec = (curl_timeo % 1000) * 1000; - } - - /* get file descriptors from the transfers */ - curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); - - /* In a real-world program you OF COURSE check the return code of the - function calls. On success, the value of maxfd is guaranteed to be - greater or equal than -1. We call select(maxfd + 1, ...), specially - in case of (maxfd == -1), we call select(0, ...), which is basically - equal to sleep. */ - - rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); - - switch(rc) { - case -1: - /* select error */ - break; - - case 0: - default: - /* timeout or readable/writable sockets */ - curl_multi_perform(multi_handle, &file->still_running); - break; - } - } while(file->still_running && (file->buffer_pos < want)); - return 1; + +/* use to attempt to fill the read buffer up to requested number of bytes */ +static int fill_buffer(URL_FILE *file, size_t want) { + fd_set fdread; + fd_set fdwrite; + fd_set fdexcep; + struct timeval timeout; + int rc; + + /* only attempt to fill buffer if transactions still running and buffer + * doesnt exceed required size already + */ + if((!file->still_running) || (file->buffer_pos > want)) + return 0; + + /* attempt to fill buffer */ + do { + int maxfd = -1; + long curl_timeo = -1; + + FD_ZERO(&fdread); + FD_ZERO(&fdwrite); + FD_ZERO(&fdexcep); + + /* set a suitable timeout to fail on */ + timeout.tv_sec = 60; /* 1 minute */ + timeout.tv_usec = 0; + + curl_multi_timeout(multi_handle, &curl_timeo); + if(curl_timeo >= 0) { + timeout.tv_sec = curl_timeo / 1000; + if(timeout.tv_sec > 1) + timeout.tv_sec = 1; + else + timeout.tv_usec = (curl_timeo % 1000) * 1000; + } + + /* get file descriptors from the transfers */ + curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); + + /* In a real-world program you OF COURSE check the return code of the + function calls. On success, the value of maxfd is guaranteed to be + greater or equal than -1. We call select(maxfd + 1, ...), specially + in case of (maxfd == -1), we call select(0, ...), which is basically + equal to sleep. */ + + rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); + + switch(rc) { + case -1: + /* select error */ + break; + + case 0: + default: + /* timeout or readable/writable sockets */ + curl_multi_perform(multi_handle, &file->still_running); + break; + } + } while(file->still_running && (file->buffer_pos < want)); + return 1; } - -/* use to remove want bytes from the front of a files buffer */ -static int use_buffer(URL_FILE *file,int want) -{ - /* sort out buffer */ - if((file->buffer_pos - want) <=0) { - /* ditch buffer - write will recreate */ - if(file->buffer) - free(file->buffer); - - file->buffer=NULL; - file->buffer_pos=0; - file->buffer_len=0; - } - else { - /* move rest down make it available for later */ - memmove(file->buffer, - &file->buffer[want], - (file->buffer_pos - want)); - - file->buffer_pos -= want; - } - return 0; + +/* use to remove want bytes from the front of a files buffer */ +static int use_buffer(URL_FILE *file,int want) { + /* sort out buffer */ + if((file->buffer_pos - want) <=0) { + /* ditch buffer - write will recreate */ + if(file->buffer) + free(file->buffer); + + file->buffer=NULL; + file->buffer_pos=0; + file->buffer_len=0; + } else { + /* move rest down make it available for later */ + memmove(file->buffer, + &file->buffer[want], + (file->buffer_pos - want)); + + file->buffer_pos -= want; + } + return 0; } - -URL_FILE *url_fopen(const char *url,const char *operation) -{ - /* this code could check for URLs or types in the 'url' and - basicly use the real fopen() for standard files */ - - URL_FILE *file; - (void)operation; - - file = (URL_FILE*)malloc(sizeof(URL_FILE)); - if(!file) - return NULL; - - memset(file, 0, sizeof(URL_FILE)); - - if((file->handle.file=fopen(url,operation))) - file->type = CFTYPE_FILE; /* marked as URL */ - - else { - file->type = CFTYPE_CURL; /* marked as URL */ - file->handle.curl = curl_easy_init(); - - curl_easy_setopt(file->handle.curl, CURLOPT_URL, url); - curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file); - curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0L); - curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback); - - if(!multi_handle) - multi_handle = curl_multi_init(); - - curl_multi_add_handle(multi_handle, file->handle.curl); - - /* lets start the fetch */ - curl_multi_perform(multi_handle, &file->still_running); - - if((file->buffer_pos == 0) && (!file->still_running)) { - /* if still_running is 0 now, we should return NULL */ - - /* make sure the easy handle is not in the multi handle anymore */ - curl_multi_remove_handle(multi_handle, file->handle.curl); - - /* cleanup */ - curl_easy_cleanup(file->handle.curl); - - free(file); - - file = NULL; - } - } - return file; + +URL_FILE *url_fopen(const char *url,const char *operation) { + /* this code could check for URLs or types in the 'url' and + basicly use the real fopen() for standard files */ + + URL_FILE *file; + (void)operation; + + file = (URL_FILE*)malloc(sizeof(URL_FILE)); + if(!file) + return NULL; + + memset(file, 0, sizeof(URL_FILE)); + + if((file->handle.file=fopen(url,operation))) + file->type = CFTYPE_FILE; /* marked as URL */ + + else { + file->type = CFTYPE_CURL; /* marked as URL */ + file->handle.curl = curl_easy_init(); + + curl_easy_setopt(file->handle.curl, CURLOPT_URL, url); + curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file); + curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback); + + if(!multi_handle) + multi_handle = curl_multi_init(); + + curl_multi_add_handle(multi_handle, file->handle.curl); + + /* lets start the fetch */ + curl_multi_perform(multi_handle, &file->still_running); + + if((file->buffer_pos == 0) && (!file->still_running)) { + /* if still_running is 0 now, we should return NULL */ + + /* make sure the easy handle is not in the multi handle anymore */ + curl_multi_remove_handle(multi_handle, file->handle.curl); + + /* cleanup */ + curl_easy_cleanup(file->handle.curl); + + free(file); + + file = NULL; + } + } + return file; } - -int url_fclose(URL_FILE *file) -{ - int ret=0;/* default is good return */ - - switch(file->type) { - case CFTYPE_FILE: - ret=fclose(file->handle.file); /* passthrough */ - break; - - case CFTYPE_CURL: - /* make sure the easy handle is not in the multi handle anymore */ - curl_multi_remove_handle(multi_handle, file->handle.curl); - - /* cleanup */ - curl_easy_cleanup(file->handle.curl); - break; - - default: /* unknown or supported type - oh dear */ - ret=EOF; - errno=EBADF; - break; - } - - if(file->buffer) - free(file->buffer);/* free any allocated buffer space */ - - free(file); - - return ret; + +int url_fclose(URL_FILE *file) { + int ret=0;/* default is good return */ + + switch(file->type) { + case CFTYPE_FILE: + ret=fclose(file->handle.file); /* passthrough */ + break; + + case CFTYPE_CURL: + /* make sure the easy handle is not in the multi handle anymore */ + curl_multi_remove_handle(multi_handle, file->handle.curl); + + /* cleanup */ + curl_easy_cleanup(file->handle.curl); + break; + + default: /* unknown or supported type - oh dear */ + ret=EOF; + errno=EBADF; + break; + } + + if(file->buffer) + free(file->buffer);/* free any allocated buffer space */ + + free(file); + + return ret; } - -int url_feof(URL_FILE *file) -{ - int ret=0; - - switch(file->type) { - case CFTYPE_FILE: - ret=feof(file->handle.file); - break; - - case CFTYPE_CURL: - if((file->buffer_pos == 0) && (!file->still_running)) - ret = 1; - break; - - default: /* unknown or supported type - oh dear */ - ret=-1; - errno=EBADF; - break; - } - return ret; + +int url_feof(URL_FILE *file) { + int ret=0; + + switch(file->type) { + case CFTYPE_FILE: + ret=feof(file->handle.file); + break; + + case CFTYPE_CURL: + if((file->buffer_pos == 0) && (!file->still_running)) + ret = 1; + break; + + default: /* unknown or supported type - oh dear */ + ret=-1; + errno=EBADF; + break; + } + return ret; } - -size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file) -{ - size_t want; - - switch(file->type) { - case CFTYPE_FILE: - want=fread(ptr,size,nmemb,file->handle.file); - break; - - case CFTYPE_CURL: - want = nmemb * size; - - fill_buffer(file,want); - - /* check if theres data in the buffer - if not fill_buffer() - * either errored or EOF */ - if(!file->buffer_pos) - return 0; - - /* ensure only available data is considered */ - if(file->buffer_pos < want) - want = file->buffer_pos; - - /* xfer data to caller */ - memcpy(ptr, file->buffer, want); - - use_buffer(file,want); - - want = want / size; /* number of items */ - break; - - default: /* unknown or supported type - oh dear */ - want=0; - errno=EBADF; - break; - - } - return want; + +size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file) { + size_t want; + + switch(file->type) { + case CFTYPE_FILE: + want=fread(ptr,size,nmemb,file->handle.file); + break; + + case CFTYPE_CURL: + want = nmemb * size; + + fill_buffer(file,want); + + /* check if theres data in the buffer - if not fill_buffer() + * either errored or EOF */ + if(!file->buffer_pos) + return 0; + + /* ensure only available data is considered */ + if(file->buffer_pos < want) + want = file->buffer_pos; + + /* xfer data to caller */ + memcpy(ptr, file->buffer, want); + + use_buffer(file,want); + + want = want / size; /* number of items */ + break; + + default: /* unknown or supported type - oh dear */ + want=0; + errno=EBADF; + break; + + } + return want; } - -char *url_fgets(char *ptr, size_t size, URL_FILE *file) -{ - size_t want = size - 1;/* always need to leave room for zero termination */ - size_t loop; - - switch(file->type) { - case CFTYPE_FILE: - ptr = fgets(ptr,size,file->handle.file); - break; - - case CFTYPE_CURL: - fill_buffer(file,want); - - /* check if theres data in the buffer - if not fill either errored or - * EOF */ - if(!file->buffer_pos) - return NULL; - - /* ensure only available data is considered */ - if(file->buffer_pos < want) - want = file->buffer_pos; - - /*buffer contains data */ - /* look for newline or eof */ - for(loop=0;loop < want;loop++) { - if(file->buffer[loop] == '\n') { - want=loop+1;/* include newline */ - break; - } - } - - /* xfer data to caller */ - memcpy(ptr, file->buffer, want); - ptr[want]=0;/* allways null terminate */ - - use_buffer(file,want); - - break; - - default: /* unknown or supported type - oh dear */ - ptr=NULL; - errno=EBADF; - break; - } - - return ptr;/*success */ + +char *url_fgets(char *ptr, size_t size, URL_FILE *file) { + size_t want = size - 1;/* always need to leave room for zero termination */ + size_t loop; + + switch(file->type) { + case CFTYPE_FILE: + ptr = fgets(ptr,size,file->handle.file); + break; + + case CFTYPE_CURL: + fill_buffer(file,want); + + /* check if theres data in the buffer - if not fill either errored or + * EOF */ + if(!file->buffer_pos) + return NULL; + + /* ensure only available data is considered */ + if(file->buffer_pos < want) + want = file->buffer_pos; + + /*buffer contains data */ + /* look for newline or eof */ + for(loop=0; loop < want; loop++) { + if(file->buffer[loop] == '\n') { + want=loop+1;/* include newline */ + break; + } + } + + /* xfer data to caller */ + memcpy(ptr, file->buffer, want); + ptr[want]=0;/* allways null terminate */ + + use_buffer(file,want); + + break; + + default: /* unknown or supported type - oh dear */ + ptr=NULL; + errno=EBADF; + break; + } + + return ptr;/*success */ } - -void url_rewind(URL_FILE *file) -{ - switch(file->type) { - case CFTYPE_FILE: - rewind(file->handle.file); /* passthrough */ - break; - - case CFTYPE_CURL: - /* halt transaction */ - curl_multi_remove_handle(multi_handle, file->handle.curl); - - /* restart */ - curl_multi_add_handle(multi_handle, file->handle.curl); - - /* ditch buffer - write will recreate - resets stream pos*/ - if(file->buffer) - free(file->buffer); - - file->buffer=NULL; - file->buffer_pos=0; - file->buffer_len=0; - - break; - - default: /* unknown or supported type - oh dear */ - break; - } + +void url_rewind(URL_FILE *file) { + switch(file->type) { + case CFTYPE_FILE: + rewind(file->handle.file); /* passthrough */ + break; + + case CFTYPE_CURL: + /* halt transaction */ + curl_multi_remove_handle(multi_handle, file->handle.curl); + + /* restart */ + curl_multi_add_handle(multi_handle, file->handle.curl); + + /* ditch buffer - write will recreate - resets stream pos*/ + if(file->buffer) + free(file->buffer); + + file->buffer=NULL; + file->buffer_pos=0; + file->buffer_len=0; + + break; + + default: /* unknown or supported type - oh dear */ + break; + } } }
\ No newline at end of file diff --git a/src/uscxml/URL.h b/src/uscxml/URL.h index 8438d3a..705fdb4 100644 --- a/src/uscxml/URL.h +++ b/src/uscxml/URL.h @@ -8,23 +8,22 @@ namespace uscxml { enum fcurl_type_e { - CFTYPE_NONE=0, - CFTYPE_FILE=1, - CFTYPE_CURL=2 + CFTYPE_NONE=0, + CFTYPE_FILE=1, + CFTYPE_CURL=2 }; -struct fcurl_data -{ - enum fcurl_type_e type; /* type of handle */ - union { - CURL *curl; - FILE *file; - } handle; /* handle */ - - char *buffer; /* buffer to store cached data*/ - size_t buffer_len; /* currently allocated buffers length */ - size_t buffer_pos; /* end of data in buffer*/ - int still_running; /* Is background url fetch still in progress */ +struct fcurl_data { + enum fcurl_type_e type; /* type of handle */ + union { + CURL *curl; + FILE *file; + } handle; /* handle */ + + char *buffer; /* buffer to store cached data*/ + size_t buffer_len; /* currently allocated buffers length */ + size_t buffer_pos; /* end of data in buffer*/ + int still_running; /* Is background url fetch still in progress */ }; typedef struct fcurl_data URL_FILE; @@ -42,7 +41,7 @@ public: private: std::string _urlString; - friend std::ostream & operator<<(std::ostream &stream, const URL& p); + friend std::ostream & operator<<(std::ostream &stream, const URL& p); }; std::ostream & operator<<(std::ostream &stream, const URL& url); diff --git a/src/uscxml/concurrency/BlockingQueue.h b/src/uscxml/concurrency/BlockingQueue.h index 90094bf..16c23d4 100644 --- a/src/uscxml/concurrency/BlockingQueue.h +++ b/src/uscxml/concurrency/BlockingQueue.h @@ -12,26 +12,26 @@ class BlockingQueue { public: BlockingQueue() {} virtual ~BlockingQueue() { - } + } void push(T elem) { - tthread::lock_guard<tthread::mutex> lock(_mutex); - _queue.push_back(elem); - _cond.notify_all(); - } - + tthread::lock_guard<tthread::mutex> lock(_mutex); + _queue.push_back(elem); + _cond.notify_all(); + } + T pop() { - tthread::lock_guard<tthread::mutex> lock(_mutex); - while (_queue.empty()) { - _cond.wait(_mutex); - } - T ret = _queue.front(); - _queue.pop_front(); - return ret; - } + tthread::lock_guard<tthread::mutex> lock(_mutex); + while (_queue.empty()) { + _cond.wait(_mutex); + } + T ret = _queue.front(); + _queue.pop_front(); + return ret; + } tthread::mutex _mutex; - tthread::condition_variable _cond; + tthread::condition_variable _cond; std::list<T> _queue; }; diff --git a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp index e2a89b2..e582c13 100644 --- a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp +++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp @@ -4,88 +4,89 @@ namespace uscxml { - DelayedEventQueue::DelayedEventQueue() { +DelayedEventQueue::DelayedEventQueue() { #ifndef _WIN32 - evthread_use_pthreads(); + evthread_use_pthreads(); #else - evthread_use_windows_threads(); + evthread_use_windows_threads(); #endif - _eventLoop = event_base_new(); - _thread = NULL; - } + _eventLoop = event_base_new(); + _thread = NULL; +} - DelayedEventQueue::~DelayedEventQueue() { +DelayedEventQueue::~DelayedEventQueue() { // std::cout << "Deleting DelayedEventQueue" << std::endl; - stop(); - if (_thread) - _thread->join(); - if(_eventLoop) - event_base_free(_eventLoop); - } - - void DelayedEventQueue::run(void* instance) { - DelayedEventQueue* THIS = (DelayedEventQueue*)instance; - int result; - while(THIS->_isStarted) { - { - //result = event_base_dispatch(THIS->_eventLoop); - result = event_base_loop(THIS->_eventLoop, EVLOOP_NO_EXIT_ON_EMPTY); - } - } - } - - void DelayedEventQueue::addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData) { - if(_callbackData.find(eventId) != _callbackData.end()) { - cancelEvent(eventId); - } - - struct timeval delay = {delayMs / 1000, (delayMs % 1000) * 1000}; - struct event* event = event_new(_eventLoop, -1, 0, DelayedEventQueue::timerCallback, &_callbackData[eventId]); - - _callbackData[eventId].eventId = eventId; - _callbackData[eventId].userData = userData; - _callbackData[eventId].eventQueue = this; - _callbackData[eventId].callback = callback; - _callbackData[eventId].event = event; - - event_add(event, &delay); - } - - void DelayedEventQueue::cancelEvent(std::string eventId) { - tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); - - if(_callbackData.find(eventId) != _callbackData.end()) { - event_del(_callbackData[eventId].event); - event_free(_callbackData[eventId].event); - _callbackData.erase(eventId); - } - } - - void DelayedEventQueue::start() { - _isStarted = true; - _thread = new tthread::thread(DelayedEventQueue::run, this); - } - - void DelayedEventQueue::stop() { - if (_isStarted) { - _isStarted = false; - event_base_loopbreak(_eventLoop); - _thread->join(); - delete _thread; - } - } - - void DelayedEventQueue::dummyCallback(evutil_socket_t fd, short what, void *arg) { - } - - void DelayedEventQueue::timerCallback(evutil_socket_t fd, short what, void *arg) { - struct callbackData *data = (struct callbackData*)arg; - tthread::lock_guard<tthread::recursive_mutex> lock(data->eventQueue->_mutex); - - std::string eventId = data->eventId; // copy eventId - event_free(data->event); - data->callback(data->userData, eventId); - data->eventQueue->_callbackData.erase(data->eventId); - } + stop(); + if (_thread) + _thread->join(); + if(_eventLoop) + event_base_free(_eventLoop); +} + +void DelayedEventQueue::run(void* instance) { + DelayedEventQueue* THIS = (DelayedEventQueue*)instance; + int result; + while(THIS->_isStarted) { + { + //result = event_base_dispatch(THIS->_eventLoop); + result = event_base_loop(THIS->_eventLoop, EVLOOP_NO_EXIT_ON_EMPTY); + (void)result; + } + } +} + +void DelayedEventQueue::addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData) { + if(_callbackData.find(eventId) != _callbackData.end()) { + cancelEvent(eventId); + } + + struct timeval delay = {delayMs / 1000, (delayMs % 1000) * 1000}; + struct event* event = event_new(_eventLoop, -1, 0, DelayedEventQueue::timerCallback, &_callbackData[eventId]); + + _callbackData[eventId].eventId = eventId; + _callbackData[eventId].userData = userData; + _callbackData[eventId].eventQueue = this; + _callbackData[eventId].callback = callback; + _callbackData[eventId].event = event; + + event_add(event, &delay); +} + +void DelayedEventQueue::cancelEvent(std::string eventId) { + tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); + + if(_callbackData.find(eventId) != _callbackData.end()) { + event_del(_callbackData[eventId].event); + event_free(_callbackData[eventId].event); + _callbackData.erase(eventId); + } +} + +void DelayedEventQueue::start() { + _isStarted = true; + _thread = new tthread::thread(DelayedEventQueue::run, this); +} + +void DelayedEventQueue::stop() { + if (_isStarted) { + _isStarted = false; + event_base_loopbreak(_eventLoop); + _thread->join(); + delete _thread; + } +} + +void DelayedEventQueue::dummyCallback(evutil_socket_t fd, short what, void *arg) { +} + +void DelayedEventQueue::timerCallback(evutil_socket_t fd, short what, void *arg) { + struct callbackData *data = (struct callbackData*)arg; + tthread::lock_guard<tthread::recursive_mutex> lock(data->eventQueue->_mutex); + + std::string eventId = data->eventId; // copy eventId + event_free(data->event); + data->callback(data->userData, eventId); + data->eventQueue->_callbackData.erase(data->eventId); +} }
\ No newline at end of file diff --git a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h index 024e353..8825c27 100644 --- a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h +++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h @@ -17,37 +17,36 @@ namespace uscxml { class DelayedEventQueue { public: - - struct callbackData - { - void *userData; - void (*callback)(void*, const std::string eventId); - std::string eventId; - struct event *event; - DelayedEventQueue* eventQueue; - }; + + struct callbackData { + void *userData; + void (*callback)(void*, const std::string eventId); + std::string eventId; + struct event *event; + DelayedEventQueue* eventQueue; + }; DelayedEventQueue(); virtual ~DelayedEventQueue(); - + void addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData); void cancelEvent(std::string eventId); - + void start(); void stop(); static void run(void*); - static void timerCallback(evutil_socket_t fd, short what, void *arg); - static void dummyCallback(evutil_socket_t fd, short what, void *arg); + static void timerCallback(evutil_socket_t fd, short what, void *arg); + static void dummyCallback(evutil_socket_t fd, short what, void *arg); - bool _isStarted; - tthread::thread* _thread; - tthread::recursive_mutex _mutex; - - std::map<std::string, callbackData> _callbackData; + bool _isStarted; + tthread::thread* _thread; + tthread::recursive_mutex _mutex; + + std::map<std::string, callbackData> _callbackData; struct event_base* _eventLoop; }; - + } diff --git a/src/uscxml/concurrency/tinythread.cpp b/src/uscxml/concurrency/tinythread.cpp index 690ecee..c4bab68 100644 --- a/src/uscxml/concurrency/tinythread.cpp +++ b/src/uscxml/concurrency/tinythread.cpp @@ -25,10 +25,10 @@ freely, subject to the following restrictions: #include "tinythread.h" #if defined(_TTHREAD_POSIX_) - #include <unistd.h> - #include <map> +#include <unistd.h> +#include <map> #elif defined(_TTHREAD_WIN32_) - #include <process.h> +#include <process.h> #endif @@ -49,73 +49,68 @@ namespace tthread { //------------------------------------------------------------------------------ #if defined(_TTHREAD_WIN32_) - #define _CONDITION_EVENT_ONE 0 - #define _CONDITION_EVENT_ALL 1 +#define _CONDITION_EVENT_ONE 0 +#define _CONDITION_EVENT_ALL 1 #endif #if defined(_TTHREAD_WIN32_) -condition_variable::condition_variable() : mWaitersCount(0) -{ - mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); - mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); - InitializeCriticalSection(&mWaitersCountLock); +condition_variable::condition_variable() : mWaitersCount(0) { + mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); + mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); + InitializeCriticalSection(&mWaitersCountLock); } #endif #if defined(_TTHREAD_WIN32_) -condition_variable::~condition_variable() -{ - CloseHandle(mEvents[_CONDITION_EVENT_ONE]); - CloseHandle(mEvents[_CONDITION_EVENT_ALL]); - DeleteCriticalSection(&mWaitersCountLock); +condition_variable::~condition_variable() { + CloseHandle(mEvents[_CONDITION_EVENT_ONE]); + CloseHandle(mEvents[_CONDITION_EVENT_ALL]); + DeleteCriticalSection(&mWaitersCountLock); } #endif #if defined(_TTHREAD_WIN32_) -void condition_variable::_wait() -{ - // Wait for either event to become signaled due to notify_one() or - // notify_all() being called - int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE); - - // Check if we are the last waiter - EnterCriticalSection(&mWaitersCountLock); - -- mWaitersCount; - bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && - (mWaitersCount == 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we are the last waiter to be notified to stop waiting, reset the event - if(lastWaiter) - ResetEvent(mEvents[_CONDITION_EVENT_ALL]); +void condition_variable::_wait() { + // Wait for either event to become signaled due to notify_one() or + // notify_all() being called + int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE); + + // Check if we are the last waiter + EnterCriticalSection(&mWaitersCountLock); + -- mWaitersCount; + bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && + (mWaitersCount == 0); + LeaveCriticalSection(&mWaitersCountLock); + + // If we are the last waiter to be notified to stop waiting, reset the event + if(lastWaiter) + ResetEvent(mEvents[_CONDITION_EVENT_ALL]); } #endif #if defined(_TTHREAD_WIN32_) -void condition_variable::notify_one() -{ - // Are there any waiters? - EnterCriticalSection(&mWaitersCountLock); - bool haveWaiters = (mWaitersCount > 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we have any waiting threads, send them a signal - if(haveWaiters) - SetEvent(mEvents[_CONDITION_EVENT_ONE]); +void condition_variable::notify_one() { + // Are there any waiters? + EnterCriticalSection(&mWaitersCountLock); + bool haveWaiters = (mWaitersCount > 0); + LeaveCriticalSection(&mWaitersCountLock); + + // If we have any waiting threads, send them a signal + if(haveWaiters) + SetEvent(mEvents[_CONDITION_EVENT_ONE]); } #endif #if defined(_TTHREAD_WIN32_) -void condition_variable::notify_all() -{ - // Are there any waiters? - EnterCriticalSection(&mWaitersCountLock); - bool haveWaiters = (mWaitersCount > 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we have any waiting threads, send them a signal - if(haveWaiters) - SetEvent(mEvents[_CONDITION_EVENT_ALL]); +void condition_variable::notify_all() { + // Are there any waiters? + EnterCriticalSection(&mWaitersCountLock); + bool haveWaiters = (mWaitersCount > 0); + LeaveCriticalSection(&mWaitersCountLock); + + // If we have any waiting threads, send them a signal + if(haveWaiters) + SetEvent(mEvents[_CONDITION_EVENT_ALL]); } #endif @@ -128,16 +123,15 @@ void condition_variable::notify_all() //------------------------------------------------------------------------------ #if defined(_TTHREAD_POSIX_) -static thread::id _pthread_t_to_ID(const pthread_t &aHandle) -{ - static mutex idMapLock; - static std::map<pthread_t, unsigned long int> idMap; - static unsigned long int idCount(1); - - lock_guard<mutex> guard(idMapLock); - if(idMap.find(aHandle) == idMap.end()) - idMap[aHandle] = idCount ++; - return thread::id(idMap[aHandle]); +static thread::id _pthread_t_to_ID(const pthread_t &aHandle) { + static mutex idMapLock; + static std::map<pthread_t, unsigned long int> idMap; + static unsigned long int idCount(1); + + lock_guard<mutex> guard(idMapLock); + if(idMap.find(aHandle) == idMap.end()) + idMap[aHandle] = idCount ++; + return thread::id(idMap[aHandle]); } #endif // _TTHREAD_POSIX_ @@ -148,9 +142,9 @@ static thread::id _pthread_t_to_ID(const pthread_t &aHandle) /// Information to pass to the new thread (what to run). struct _thread_start_info { - void (*mFunction)(void *); ///< Pointer to the function to be executed. - void * mArg; ///< Function argument for the thread function. - thread * mThread; ///< Pointer to the thread object. + void (*mFunction)(void *); ///< Pointer to the function to be executed. + void * mArg; ///< Function argument for the thread function. + thread * mThread; ///< Pointer to the thread object. }; // Thread wrapper function. @@ -160,129 +154,116 @@ unsigned WINAPI thread::wrapper_function(void * aArg) void * thread::wrapper_function(void * aArg) #endif { - // Get thread startup information - _thread_start_info * ti = (_thread_start_info *) aArg; - - try - { - // Call the actual client thread function - ti->mFunction(ti->mArg); - } - catch(...) - { - // Uncaught exceptions will terminate the application (default behavior - // according to C++11) - std::terminate(); - } - - // The thread is no longer executing - lock_guard<mutex> guard(ti->mThread->mDataMutex); - ti->mThread->mNotAThread = true; - - // The thread is responsible for freeing the startup information - delete ti; - - return 0; + // Get thread startup information + _thread_start_info * ti = (_thread_start_info *) aArg; + + try { + // Call the actual client thread function + ti->mFunction(ti->mArg); + } catch(...) { + // Uncaught exceptions will terminate the application (default behavior + // according to C++11) + std::terminate(); + } + + // The thread is no longer executing + lock_guard<mutex> guard(ti->mThread->mDataMutex); + ti->mThread->mNotAThread = true; + + // The thread is responsible for freeing the startup information + delete ti; + + return 0; } -thread::thread(void (*aFunction)(void *), void * aArg) -{ - // Serialize access to this thread structure - lock_guard<mutex> guard(mDataMutex); +thread::thread(void (*aFunction)(void *), void * aArg) { + // Serialize access to this thread structure + lock_guard<mutex> guard(mDataMutex); - // Fill out the thread startup information (passed to the thread wrapper, - // which will eventually free it) - _thread_start_info * ti = new _thread_start_info; - ti->mFunction = aFunction; - ti->mArg = aArg; - ti->mThread = this; + // Fill out the thread startup information (passed to the thread wrapper, + // which will eventually free it) + _thread_start_info * ti = new _thread_start_info; + ti->mFunction = aFunction; + ti->mArg = aArg; + ti->mThread = this; - // The thread is now alive - mNotAThread = false; + // The thread is now alive + mNotAThread = false; - // Create the thread + // Create the thread #if defined(_TTHREAD_WIN32_) - mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID); + mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID); #elif defined(_TTHREAD_POSIX_) - if(pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0) - mHandle = 0; + if(pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0) + mHandle = 0; #endif - // Did we fail to create the thread? - if(!mHandle) - { - mNotAThread = true; - delete ti; - } + // Did we fail to create the thread? + if(!mHandle) { + mNotAThread = true; + delete ti; + } } -thread::~thread() -{ - if(joinable()) - std::terminate(); +thread::~thread() { + if(joinable()) + std::terminate(); } -void thread::join() -{ - if(joinable()) - { +void thread::join() { + if(joinable()) { #if defined(_TTHREAD_WIN32_) - WaitForSingleObject(mHandle, INFINITE); - CloseHandle(mHandle); + WaitForSingleObject(mHandle, INFINITE); + CloseHandle(mHandle); #elif defined(_TTHREAD_POSIX_) - pthread_join(mHandle, NULL); + pthread_join(mHandle, NULL); #endif - } + } } -bool thread::joinable() const -{ - mDataMutex.lock(); - bool result = !mNotAThread; - mDataMutex.unlock(); - return result; +bool thread::joinable() const { + mDataMutex.lock(); + bool result = !mNotAThread; + mDataMutex.unlock(); + return result; } -void thread::detach() -{ - mDataMutex.lock(); - if(!mNotAThread) - { +void thread::detach() { + mDataMutex.lock(); + if(!mNotAThread) { #if defined(_TTHREAD_WIN32_) - CloseHandle(mHandle); + CloseHandle(mHandle); #elif defined(_TTHREAD_POSIX_) - pthread_detach(mHandle); + pthread_detach(mHandle); #endif - mNotAThread = true; - } - mDataMutex.unlock(); + mNotAThread = true; + } + mDataMutex.unlock(); } -thread::id thread::get_id() const -{ - if(!joinable()) - return id(); +thread::id thread::get_id() const { + if(!joinable()) + return id(); #if defined(_TTHREAD_WIN32_) - return id((unsigned long int) mWin32ThreadID); + return id((unsigned long int) mWin32ThreadID); #elif defined(_TTHREAD_POSIX_) - return _pthread_t_to_ID(mHandle); + return _pthread_t_to_ID(mHandle); #endif } -unsigned thread::hardware_concurrency() -{ +unsigned thread::hardware_concurrency() { #if defined(_TTHREAD_WIN32_) - SYSTEM_INFO si; - GetSystemInfo(&si); - return (int) si.dwNumberOfProcessors; + SYSTEM_INFO si; + GetSystemInfo(&si); + return (int) si.dwNumberOfProcessors; #elif defined(_SC_NPROCESSORS_ONLN) - return (int) sysconf(_SC_NPROCESSORS_ONLN); + return (int) sysconf(_SC_NPROCESSORS_ONLN); #elif defined(_SC_NPROC_ONLN) - return (int) sysconf(_SC_NPROC_ONLN); + return (int) sysconf(_SC_NPROC_ONLN); #else - // The standard requires this function to return zero if the number of - // hardware cores could not be determined. - return 0; + // The standard requires this function to return zero if the number of + // hardware cores could not be determined. + return 0; #endif } @@ -291,12 +272,11 @@ unsigned thread::hardware_concurrency() // this_thread //------------------------------------------------------------------------------ -thread::id this_thread::get_id() -{ +thread::id this_thread::get_id() { #if defined(_TTHREAD_WIN32_) - return thread::id((unsigned long int) GetCurrentThreadId()); + return thread::id((unsigned long int) GetCurrentThreadId()); #elif defined(_TTHREAD_POSIX_) - return _pthread_t_to_ID(pthread_self()); + return _pthread_t_to_ID(pthread_self()); #endif } diff --git a/src/uscxml/concurrency/tinythread.h b/src/uscxml/concurrency/tinythread.h index aed7b58..2e5caa0 100644 --- a/src/uscxml/concurrency/tinythread.h +++ b/src/uscxml/concurrency/tinythread.h @@ -57,30 +57,30 @@ freely, subject to the following restrictions: // Which platform are we on? #if !defined(_TTHREAD_PLATFORM_DEFINED_) - #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) - #define _TTHREAD_WIN32_ - #else - #define _TTHREAD_POSIX_ - #endif - #define _TTHREAD_PLATFORM_DEFINED_ +#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) +#define _TTHREAD_WIN32_ +#else +#define _TTHREAD_POSIX_ +#endif +#define _TTHREAD_PLATFORM_DEFINED_ #endif // Platform specific includes #if defined(_TTHREAD_WIN32_) - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #define __UNDEF_LEAN_AND_MEAN - #endif - #include <windows.h> - #ifdef __UNDEF_LEAN_AND_MEAN - #undef WIN32_LEAN_AND_MEAN - #undef __UNDEF_LEAN_AND_MEAN - #endif +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#define __UNDEF_LEAN_AND_MEAN +#endif +#include <windows.h> +#ifdef __UNDEF_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#undef __UNDEF_LEAN_AND_MEAN +#endif #else - #include <pthread.h> - #include <signal.h> - #include <sched.h> - #include <unistd.h> +#include <pthread.h> +#include <signal.h> +#include <sched.h> +#include <unistd.h> #endif // Generic includes @@ -95,21 +95,21 @@ freely, subject to the following restrictions: // Do we have a fully featured C++11 compiler? #if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L)) - #define _TTHREAD_CPP11_ +#define _TTHREAD_CPP11_ #endif // ...at least partial C++11? #if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__) - #define _TTHREAD_CPP11_PARTIAL_ +#define _TTHREAD_CPP11_PARTIAL_ #endif // Macro for disabling assignments of objects. #ifdef _TTHREAD_CPP11_PARTIAL_ - #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ +#define _TTHREAD_DISABLE_ASSIGNMENT(name) \ name(const name&) = delete; \ name& operator=(const name&) = delete; #else - #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ +#define _TTHREAD_DISABLE_ASSIGNMENT(name) \ name(const name&); \ name& operator=(const name&); #endif @@ -136,11 +136,11 @@ freely, subject to the following restrictions: /// @hideinitializer #if !defined(_TTHREAD_CPP11_) && !defined(thread_local) - #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) - #define thread_local __thread - #else - #define thread_local __declspec(thread) - #endif +#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) +#define thread_local __thread +#else +#define thread_local __declspec(thread) +#endif #endif @@ -157,89 +157,84 @@ namespace tthread { /// on that object). /// @see recursive_mutex class mutex { - public: - /// Constructor. - mutex() +public: + /// Constructor. + mutex() #if defined(_TTHREAD_WIN32_) - : mAlreadyLocked(false) + : mAlreadyLocked(false) #endif - { + { #if defined(_TTHREAD_WIN32_) - InitializeCriticalSection(&mHandle); + InitializeCriticalSection(&mHandle); #else - pthread_mutex_init(&mHandle, NULL); + pthread_mutex_init(&mHandle, NULL); #endif - } + } - /// Destructor. - ~mutex() - { + /// Destructor. + ~mutex() { #if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mHandle); + DeleteCriticalSection(&mHandle); #else - pthread_mutex_destroy(&mHandle); + pthread_mutex_destroy(&mHandle); #endif - } + } - /// Lock the mutex. - /// The method will block the calling thread until a lock on the mutex can - /// be obtained. The mutex remains locked until @c unlock() is called. - /// @see lock_guard - inline void lock() - { + /// Lock the mutex. + /// The method will block the calling thread until a lock on the mutex can + /// be obtained. The mutex remains locked until @c unlock() is called. + /// @see lock_guard + inline void lock() { #if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mHandle); - while(mAlreadyLocked) Sleep(1000); // Simulate deadlock... - mAlreadyLocked = true; + EnterCriticalSection(&mHandle); + while(mAlreadyLocked) Sleep(1000); // Simulate deadlock... + mAlreadyLocked = true; #else - pthread_mutex_lock(&mHandle); + pthread_mutex_lock(&mHandle); #endif - } - - /// Try to lock the mutex. - /// The method will try to lock the mutex. If it fails, the function will - /// return immediately (non-blocking). - /// @return @c true if the lock was acquired, or @c false if the lock could - /// not be acquired. - inline bool try_lock() - { + } + + /// Try to lock the mutex. + /// The method will try to lock the mutex. If it fails, the function will + /// return immediately (non-blocking). + /// @return @c true if the lock was acquired, or @c false if the lock could + /// not be acquired. + inline bool try_lock() { #if defined(_TTHREAD_WIN32_) - bool ret = (TryEnterCriticalSection(&mHandle) ? true : false); - if(ret && mAlreadyLocked) - { - LeaveCriticalSection(&mHandle); - ret = false; - } - return ret; + bool ret = (TryEnterCriticalSection(&mHandle) ? true : false); + if(ret && mAlreadyLocked) { + LeaveCriticalSection(&mHandle); + ret = false; + } + return ret; #else - return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; + return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; #endif - } + } - /// Unlock the mutex. - /// If any threads are waiting for the lock on this mutex, one of them will - /// be unblocked. - inline void unlock() - { + /// Unlock the mutex. + /// If any threads are waiting for the lock on this mutex, one of them will + /// be unblocked. + inline void unlock() { #if defined(_TTHREAD_WIN32_) - mAlreadyLocked = false; - LeaveCriticalSection(&mHandle); + mAlreadyLocked = false; + LeaveCriticalSection(&mHandle); #else - pthread_mutex_unlock(&mHandle); + pthread_mutex_unlock(&mHandle); #endif - } + } - _TTHREAD_DISABLE_ASSIGNMENT(mutex) + _TTHREAD_DISABLE_ASSIGNMENT(mutex) - private: +private: #if defined(_TTHREAD_WIN32_) - CRITICAL_SECTION mHandle; - bool mAlreadyLocked; + CRITICAL_SECTION mHandle; + bool mAlreadyLocked; #else - pthread_mutex_t mHandle; + pthread_mutex_t mHandle; #endif - friend class condition_variable; + friend class condition_variable; }; /// Recursive mutex class. @@ -249,79 +244,74 @@ class mutex { /// number of times). /// @see mutex class recursive_mutex { - public: - /// Constructor. - recursive_mutex() - { +public: + /// Constructor. + recursive_mutex() { #if defined(_TTHREAD_WIN32_) - InitializeCriticalSection(&mHandle); + InitializeCriticalSection(&mHandle); #else - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&mHandle, &attr); + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mHandle, &attr); #endif - } + } - /// Destructor. - ~recursive_mutex() - { + /// Destructor. + ~recursive_mutex() { #if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mHandle); + DeleteCriticalSection(&mHandle); #else - pthread_mutex_destroy(&mHandle); + pthread_mutex_destroy(&mHandle); #endif - } + } - /// Lock the mutex. - /// The method will block the calling thread until a lock on the mutex can - /// be obtained. The mutex remains locked until @c unlock() is called. - /// @see lock_guard - inline void lock() - { + /// Lock the mutex. + /// The method will block the calling thread until a lock on the mutex can + /// be obtained. The mutex remains locked until @c unlock() is called. + /// @see lock_guard + inline void lock() { #if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mHandle); + EnterCriticalSection(&mHandle); #else - pthread_mutex_lock(&mHandle); + pthread_mutex_lock(&mHandle); #endif - } - - /// Try to lock the mutex. - /// The method will try to lock the mutex. If it fails, the function will - /// return immediately (non-blocking). - /// @return @c true if the lock was acquired, or @c false if the lock could - /// not be acquired. - inline bool try_lock() - { + } + + /// Try to lock the mutex. + /// The method will try to lock the mutex. If it fails, the function will + /// return immediately (non-blocking). + /// @return @c true if the lock was acquired, or @c false if the lock could + /// not be acquired. + inline bool try_lock() { #if defined(_TTHREAD_WIN32_) - return TryEnterCriticalSection(&mHandle) ? true : false; + return TryEnterCriticalSection(&mHandle) ? true : false; #else - return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; + return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; #endif - } + } - /// Unlock the mutex. - /// If any threads are waiting for the lock on this mutex, one of them will - /// be unblocked. - inline void unlock() - { + /// Unlock the mutex. + /// If any threads are waiting for the lock on this mutex, one of them will + /// be unblocked. + inline void unlock() { #if defined(_TTHREAD_WIN32_) - LeaveCriticalSection(&mHandle); + LeaveCriticalSection(&mHandle); #else - pthread_mutex_unlock(&mHandle); + pthread_mutex_unlock(&mHandle); #endif - } + } - _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex) + _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex) - private: +private: #if defined(_TTHREAD_WIN32_) - CRITICAL_SECTION mHandle; + CRITICAL_SECTION mHandle; #else - pthread_mutex_t mHandle; + pthread_mutex_t mHandle; #endif - friend class condition_variable; + friend class condition_variable; }; /// Lock guard class. @@ -341,27 +331,25 @@ class recursive_mutex { template <class T> class lock_guard { - public: - typedef T mutex_type; - - lock_guard() : mMutex(0) {} - - /// The constructor locks the mutex. - explicit lock_guard(mutex_type &aMutex) - { - mMutex = &aMutex; - mMutex->lock(); - } - - /// The destructor unlocks the mutex. - ~lock_guard() - { - if(mMutex) - mMutex->unlock(); - } - - private: - mutex_type * mMutex; +public: + typedef T mutex_type; + + lock_guard() : mMutex(0) {} + + /// The constructor locks the mutex. + explicit lock_guard(mutex_type &aMutex) { + mMutex = &aMutex; + mMutex->lock(); + } + + /// The destructor unlocks the mutex. + ~lock_guard() { + if(mMutex) + mMutex->unlock(); + } + +private: + mutex_type * mMutex; }; /// Condition variable class. @@ -390,179 +378,173 @@ class lock_guard { /// } /// @endcode class condition_variable { - public: - /// Constructor. +public: + /// Constructor. #if defined(_TTHREAD_WIN32_) - condition_variable(); + condition_variable(); #else - condition_variable() - { - pthread_cond_init(&mHandle, NULL); - } + condition_variable() { + pthread_cond_init(&mHandle, NULL); + } #endif - /// Destructor. + /// Destructor. #if defined(_TTHREAD_WIN32_) - ~condition_variable(); + ~condition_variable(); #else - ~condition_variable() - { - pthread_cond_destroy(&mHandle); - } -#endif - - /// Wait for the condition. - /// The function will block the calling thread until the condition variable - /// is woken by @c notify_one(), @c notify_all() or a spurious wake up. - /// @param[in] aMutex A mutex that will be unlocked when the wait operation - /// starts, an locked again as soon as the wait operation is finished. - template <class _mutexT> - inline void wait(_mutexT &aMutex) - { + ~condition_variable() { + pthread_cond_destroy(&mHandle); + } +#endif + + /// Wait for the condition. + /// The function will block the calling thread until the condition variable + /// is woken by @c notify_one(), @c notify_all() or a spurious wake up. + /// @param[in] aMutex A mutex that will be unlocked when the wait operation + /// starts, an locked again as soon as the wait operation is finished. + template <class _mutexT> + inline void wait(_mutexT &aMutex) { #if defined(_TTHREAD_WIN32_) - // Increment number of waiters - EnterCriticalSection(&mWaitersCountLock); - ++ mWaitersCount; - LeaveCriticalSection(&mWaitersCountLock); - - // Release the mutex while waiting for the condition (will decrease - // the number of waiters when done)... - aMutex.unlock(); - _wait(); - aMutex.lock(); + // Increment number of waiters + EnterCriticalSection(&mWaitersCountLock); + ++ mWaitersCount; + LeaveCriticalSection(&mWaitersCountLock); + + // Release the mutex while waiting for the condition (will decrease + // the number of waiters when done)... + aMutex.unlock(); + _wait(); + aMutex.lock(); #else - pthread_cond_wait(&mHandle, &aMutex.mHandle); + pthread_cond_wait(&mHandle, &aMutex.mHandle); #endif - } + } - /// Notify one thread that is waiting for the condition. - /// If at least one thread is blocked waiting for this condition variable, - /// one will be woken up. - /// @note Only threads that started waiting prior to this call will be - /// woken up. + /// Notify one thread that is waiting for the condition. + /// If at least one thread is blocked waiting for this condition variable, + /// one will be woken up. + /// @note Only threads that started waiting prior to this call will be + /// woken up. #if defined(_TTHREAD_WIN32_) - void notify_one(); + void notify_one(); #else - inline void notify_one() - { - pthread_cond_signal(&mHandle); - } + inline void notify_one() { + pthread_cond_signal(&mHandle); + } #endif - /// Notify all threads that are waiting for the condition. - /// All threads that are blocked waiting for this condition variable will - /// be woken up. - /// @note Only threads that started waiting prior to this call will be - /// woken up. + /// Notify all threads that are waiting for the condition. + /// All threads that are blocked waiting for this condition variable will + /// be woken up. + /// @note Only threads that started waiting prior to this call will be + /// woken up. #if defined(_TTHREAD_WIN32_) - void notify_all(); + void notify_all(); #else - inline void notify_all() - { - pthread_cond_broadcast(&mHandle); - } + inline void notify_all() { + pthread_cond_broadcast(&mHandle); + } #endif - _TTHREAD_DISABLE_ASSIGNMENT(condition_variable) + _TTHREAD_DISABLE_ASSIGNMENT(condition_variable) - private: +private: #if defined(_TTHREAD_WIN32_) - void _wait(); - HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs. - unsigned int mWaitersCount; ///< Count of the number of waiters. - CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount. + void _wait(); + HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs. + unsigned int mWaitersCount; ///< Count of the number of waiters. + CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount. #else - pthread_cond_t mHandle; + pthread_cond_t mHandle; #endif }; /// Thread class. class thread { - public: +public: #if defined(_TTHREAD_WIN32_) - typedef HANDLE native_handle_type; + typedef HANDLE native_handle_type; #else - typedef pthread_t native_handle_type; + typedef pthread_t native_handle_type; #endif - class id; + class id; - /// Default constructor. - /// Construct a @c thread object without an associated thread of execution - /// (i.e. non-joinable). - thread() : mHandle(0), mNotAThread(true) + /// Default constructor. + /// Construct a @c thread object without an associated thread of execution + /// (i.e. non-joinable). + thread() : mHandle(0), mNotAThread(true) #if defined(_TTHREAD_WIN32_) - , mWin32ThreadID(0) -#endif - {} - - /// Thread starting constructor. - /// Construct a @c thread object with a new thread of execution. - /// @param[in] aFunction A function pointer to a function of type: - /// <tt>void fun(void * arg)</tt> - /// @param[in] aArg Argument to the thread function. - /// @note This constructor is not fully compatible with the standard C++ - /// thread class. It is more similar to the pthread_create() (POSIX) and - /// CreateThread() (Windows) functions. - thread(void (*aFunction)(void *), void * aArg); - - /// Destructor. - /// @note If the thread is joinable upon destruction, @c std::terminate() - /// will be called, which terminates the process. It is always wise to do - /// @c join() before deleting a thread object. - ~thread(); - - /// Wait for the thread to finish (join execution flows). - /// After calling @c join(), the thread object is no longer associated with - /// a thread of execution (i.e. it is not joinable, and you may not join - /// with it nor detach from it). - void join(); - - /// Check if the thread is joinable. - /// A thread object is joinable if it has an associated thread of execution. - bool joinable() const; - - /// Detach from the thread. - /// After calling @c detach(), the thread object is no longer assicated with - /// a thread of execution (i.e. it is not joinable). The thread continues - /// execution without the calling thread blocking, and when the thread - /// ends execution, any owned resources are released. - void detach(); - - /// Return the thread ID of a thread object. - id get_id() const; - - /// Get the native handle for this thread. - /// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this - /// is a @c pthread_t. - inline native_handle_type native_handle() - { - return mHandle; - } - - /// Determine the number of threads which can possibly execute concurrently. - /// This function is useful for determining the optimal number of threads to - /// use for a task. - /// @return The number of hardware thread contexts in the system. - /// @note If this value is not defined, the function returns zero (0). - static unsigned hardware_concurrency(); - - _TTHREAD_DISABLE_ASSIGNMENT(thread) - - private: - native_handle_type mHandle; ///< Thread handle. - mutable mutex mDataMutex; ///< Serializer for access to the thread private data. - bool mNotAThread; ///< True if this object is not a thread of execution. + , mWin32ThreadID(0) +#endif + {} + + /// Thread starting constructor. + /// Construct a @c thread object with a new thread of execution. + /// @param[in] aFunction A function pointer to a function of type: + /// <tt>void fun(void * arg)</tt> + /// @param[in] aArg Argument to the thread function. + /// @note This constructor is not fully compatible with the standard C++ + /// thread class. It is more similar to the pthread_create() (POSIX) and + /// CreateThread() (Windows) functions. + thread(void (*aFunction)(void *), void * aArg); + + /// Destructor. + /// @note If the thread is joinable upon destruction, @c std::terminate() + /// will be called, which terminates the process. It is always wise to do + /// @c join() before deleting a thread object. + ~thread(); + + /// Wait for the thread to finish (join execution flows). + /// After calling @c join(), the thread object is no longer associated with + /// a thread of execution (i.e. it is not joinable, and you may not join + /// with it nor detach from it). + void join(); + + /// Check if the thread is joinable. + /// A thread object is joinable if it has an associated thread of execution. + bool joinable() const; + + /// Detach from the thread. + /// After calling @c detach(), the thread object is no longer assicated with + /// a thread of execution (i.e. it is not joinable). The thread continues + /// execution without the calling thread blocking, and when the thread + /// ends execution, any owned resources are released. + void detach(); + + /// Return the thread ID of a thread object. + id get_id() const; + + /// Get the native handle for this thread. + /// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this + /// is a @c pthread_t. + inline native_handle_type native_handle() { + return mHandle; + } + + /// Determine the number of threads which can possibly execute concurrently. + /// This function is useful for determining the optimal number of threads to + /// use for a task. + /// @return The number of hardware thread contexts in the system. + /// @note If this value is not defined, the function returns zero (0). + static unsigned hardware_concurrency(); + + _TTHREAD_DISABLE_ASSIGNMENT(thread) + +private: + native_handle_type mHandle; ///< Thread handle. + mutable mutex mDataMutex; ///< Serializer for access to the thread private data. + bool mNotAThread; ///< True if this object is not a thread of execution. #if defined(_TTHREAD_WIN32_) - unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex). + unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex). #endif - // This is the internal thread wrapper function. + // This is the internal thread wrapper function. #if defined(_TTHREAD_WIN32_) - static unsigned WINAPI wrapper_function(void * aArg); + static unsigned WINAPI wrapper_function(void * aArg); #else - static void * wrapper_function(void * aArg); + static void * wrapper_function(void * aArg); #endif }; @@ -570,60 +552,52 @@ class thread { /// The thread ID is a unique identifier for each thread. /// @see thread::get_id() class thread::id { - public: - /// Default constructor. - /// The default constructed ID is that of thread without a thread of - /// execution. - id() : mId(0) {}; - - id(unsigned long int aId) : mId(aId) {}; - - id(const id& aId) : mId(aId.mId) {}; - - inline id & operator=(const id &aId) - { - mId = aId.mId; - return *this; - } - - inline friend bool operator==(const id &aId1, const id &aId2) - { - return (aId1.mId == aId2.mId); - } - - inline friend bool operator!=(const id &aId1, const id &aId2) - { - return (aId1.mId != aId2.mId); - } - - inline friend bool operator<=(const id &aId1, const id &aId2) - { - return (aId1.mId <= aId2.mId); - } - - inline friend bool operator<(const id &aId1, const id &aId2) - { - return (aId1.mId < aId2.mId); - } - - inline friend bool operator>=(const id &aId1, const id &aId2) - { - return (aId1.mId >= aId2.mId); - } - - inline friend bool operator>(const id &aId1, const id &aId2) - { - return (aId1.mId > aId2.mId); - } - - inline friend std::ostream& operator <<(std::ostream &os, const id &obj) - { - os << obj.mId; - return os; - } - - private: - unsigned long int mId; +public: + /// Default constructor. + /// The default constructed ID is that of thread without a thread of + /// execution. + id() : mId(0) {}; + + id(unsigned long int aId) : mId(aId) {}; + + id(const id& aId) : mId(aId.mId) {}; + + inline id & operator=(const id &aId) { + mId = aId.mId; + return *this; + } + + inline friend bool operator==(const id &aId1, const id &aId2) { + return (aId1.mId == aId2.mId); + } + + inline friend bool operator!=(const id &aId1, const id &aId2) { + return (aId1.mId != aId2.mId); + } + + inline friend bool operator<=(const id &aId1, const id &aId2) { + return (aId1.mId <= aId2.mId); + } + + inline friend bool operator<(const id &aId1, const id &aId2) { + return (aId1.mId < aId2.mId); + } + + inline friend bool operator>=(const id &aId1, const id &aId2) { + return (aId1.mId >= aId2.mId); + } + + inline friend bool operator>(const id &aId1, const id &aId2) { + return (aId1.mId > aId2.mId); + } + + inline friend std::ostream& operator <<(std::ostream &os, const id &obj) { + os << obj.mId; + return os; + } + +private: + unsigned long int mId; }; @@ -633,77 +607,76 @@ typedef long long __intmax_t; /// Minimal implementation of the @c ratio class. This class provides enough /// functionality to implement some basic @c chrono classes. template <__intmax_t N, __intmax_t D = 1> class ratio { - public: - static double _as_double() { return double(N) / double(D); } +public: + static double _as_double() { + return double(N) / double(D); + } }; /// Minimal implementation of the @c chrono namespace. /// The @c chrono namespace provides types for specifying time intervals. namespace chrono { - /// Duration template class. This class provides enough functionality to - /// implement @c this_thread::sleep_for(). - template <class _Rep, class _Period = ratio<1> > class duration { - private: - _Rep rep_; - public: - typedef _Rep rep; - typedef _Period period; - - /// Construct a duration object with the given duration. - template <class _Rep2> - explicit duration(const _Rep2& r) : rep_(r) {}; - - /// Return the value of the duration object. - rep count() const - { - return rep_; - } - }; - - // Standard duration types. - typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds. - typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds. - typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds. - typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds. - typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes. - typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours. +/// Duration template class. This class provides enough functionality to +/// implement @c this_thread::sleep_for(). +template <class _Rep, class _Period = ratio<1> > class duration { +private: + _Rep rep_; +public: + typedef _Rep rep; + typedef _Period period; + + /// Construct a duration object with the given duration. + template <class _Rep2> + explicit duration(const _Rep2& r) : rep_(r) {}; + + /// Return the value of the duration object. + rep count() const { + return rep_; + } +}; + +// Standard duration types. +typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds. +typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds. +typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds. +typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds. +typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes. +typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours. } /// The namespace @c this_thread provides methods for dealing with the /// calling thread. namespace this_thread { - /// Return the thread ID of the calling thread. - thread::id get_id(); - - /// Yield execution to another thread. - /// Offers the operating system the opportunity to schedule another thread - /// that is ready to run on the current processor. - inline void yield() - { +/// Return the thread ID of the calling thread. +thread::id get_id(); + +/// Yield execution to another thread. +/// Offers the operating system the opportunity to schedule another thread +/// that is ready to run on the current processor. +inline void yield() { #if defined(_TTHREAD_WIN32_) - Sleep(0); + Sleep(0); #else - sched_yield(); -#endif - } - - /// Blocks the calling thread for a period of time. - /// @param[in] aTime Minimum time to put the thread to sleep. - /// Example usage: - /// @code - /// // Sleep for 100 milliseconds - /// this_thread::sleep_for(chrono::milliseconds(100)); - /// @endcode - /// @note Supported duration types are: nanoseconds, microseconds, - /// milliseconds, seconds, minutes and hours. - template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period>& aTime) - { + sched_yield(); +#endif +} + +/// Blocks the calling thread for a period of time. +/// @param[in] aTime Minimum time to put the thread to sleep. +/// Example usage: +/// @code +/// // Sleep for 100 milliseconds +/// this_thread::sleep_for(chrono::milliseconds(100)); +/// @endcode +/// @note Supported duration types are: nanoseconds, microseconds, +/// milliseconds, seconds, minutes and hours. +template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period>& aTime) { #if defined(_TTHREAD_WIN32_) - Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5)); + Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5)); #else - usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5)); + usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5)); #endif - } +} } } diff --git a/src/uscxml/debug/SCXMLDotWriter.h b/src/uscxml/debug/SCXMLDotWriter.h index 7ebb916..0a3c2dc 100644 --- a/src/uscxml/debug/SCXMLDotWriter.h +++ b/src/uscxml/debug/SCXMLDotWriter.h @@ -11,33 +11,33 @@ class Interpreter; class SCXMLDotWriter { public: - - struct ElemDetails { - std::string name; - std::string details; - std::string content; - }; - + + struct ElemDetails { + std::string name; + std::string details; + std::string content; + }; + SCXMLDotWriter(Interpreter* interpreter); ~SCXMLDotWriter(); - - static void toDot(const std::string& filename, Interpreter* interpreter); - void writeSCXMLElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem); - void writeStateElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem); - void writeTransitionElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem); - - std::string getDetailedLabel(const Arabica::DOM::Element<std::string>& elem, int indentation = 0); - std::string colorForIndent(int indent); - - std::string idForNode(const Arabica::DOM::Node<std::string>& node); - std::string nameForNode(const Arabica::DOM::Node<std::string>& node); - - static std::string getPrefix(); - static std::string dotEscape(const std::string& text); - - Interpreter* _interpreter; - std::set<std::string> _knownIds; - static int _indentation; + + static void toDot(const std::string& filename, Interpreter* interpreter); + void writeSCXMLElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem); + void writeStateElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem); + void writeTransitionElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem); + + std::string getDetailedLabel(const Arabica::DOM::Element<std::string>& elem, int indentation = 0); + std::string colorForIndent(int indent); + + std::string idForNode(const Arabica::DOM::Node<std::string>& node); + std::string nameForNode(const Arabica::DOM::Node<std::string>& node); + + static std::string getPrefix(); + static std::string dotEscape(const std::string& text); + + Interpreter* _interpreter; + std::set<std::string> _knownIds; + static int _indentation; }; } diff --git a/src/uscxml/plugins/Plugins.cpp b/src/uscxml/plugins/Plugins.cpp index 4e819bb..04b5b99 100644 --- a/src/uscxml/plugins/Plugins.cpp +++ b/src/uscxml/plugins/Plugins.cpp @@ -7,5 +7,5 @@ PLUMA_PROVIDER_SOURCE(DataModel, 1, 1); PLUMA_PROVIDER_SOURCE(IOProcessor, 1, 1); PLUMA_PROVIDER_SOURCE(Invoker, 1, 1); #endif - + }
\ No newline at end of file diff --git a/src/uscxml/plugins/Pluma/DLibrary.cpp b/src/uscxml/plugins/Pluma/DLibrary.cpp index 9b617db..0cbf309 100755..100644 --- a/src/uscxml/plugins/Pluma/DLibrary.cpp +++ b/src/uscxml/plugins/Pluma/DLibrary.cpp @@ -31,75 +31,74 @@ #include <string>
-namespace pluma{
+namespace pluma {
////////////////////////////////////////////////////////////
-DLibrary* DLibrary::load(const std::string& path){
- if ( path.empty() ){
- fprintf(stderr, "Failed to load library: Empty path\n");
- return NULL;
- }
- void* handle = NULL;
+DLibrary* DLibrary::load(const std::string& path) {
+ if ( path.empty() ) {
+ fprintf(stderr, "Failed to load library: Empty path\n");
+ return NULL;
+ }
+ void* handle = NULL;
- // load library - OS dependent operation
- #ifdef PLUMA_SYS_WINDOWS
- handle = ::LoadLibraryA(path.c_str());
- if (!handle){
- fprintf(stderr, "Failed to load library \"%s\".\n", path.c_str());
- return NULL;
- }
- #else
- handle = ::dlopen(path.c_str(), RTLD_NOW);
- if (!handle){
- const char* errorString = ::dlerror();
- fprintf(stderr, "Failed to load library \"%s\".", path.c_str());
- if(errorString) fprintf(stderr, " OS returned error: \"%s\".", errorString);
- fprintf(stderr, "\n");
- return NULL;
- }
- #endif
- // return a DLibrary with the DLL handle
- return new DLibrary(handle);
+ // load library - OS dependent operation
+#ifdef PLUMA_SYS_WINDOWS
+ handle = ::LoadLibraryA(path.c_str());
+ if (!handle) {
+ fprintf(stderr, "Failed to load library \"%s\".\n", path.c_str());
+ return NULL;
+ }
+#else
+ handle = ::dlopen(path.c_str(), RTLD_NOW);
+ if (!handle) {
+ const char* errorString = ::dlerror();
+ fprintf(stderr, "Failed to load library \"%s\".", path.c_str());
+ if(errorString) fprintf(stderr, " OS returned error: \"%s\".", errorString);
+ fprintf(stderr, "\n");
+ return NULL;
+ }
+#endif
+ // return a DLibrary with the DLL handle
+ return new DLibrary(handle);
}
////////////////////////////////////////////////////////////
-DLibrary::~DLibrary(){
- if (handle){
- #ifdef PLUMA_SYS_WINDOWS
- ::FreeLibrary( (HMODULE)handle );
- #else
- ::dlclose(handle);
- #endif
- }
+DLibrary::~DLibrary() {
+ if (handle) {
+#ifdef PLUMA_SYS_WINDOWS
+ ::FreeLibrary( (HMODULE)handle );
+#else
+ ::dlclose(handle);
+#endif
+ }
}
////////////////////////////////////////////////////////////
-void* DLibrary::getSymbol(const std::string& symbol){
- if (!handle){
- fprintf(stderr, "Cannot inspect library symbols, library isn't loaded.\n");
- return NULL;
- }
- void* res;
- #ifdef PLUMA_SYS_WINDOWS
- res = (void*)(::GetProcAddress((HMODULE)handle, symbol.c_str()));
- #else
- res = (void*)(::dlsym(handle, symbol.c_str()));
- #endif
- if (!res){
- fprintf(stderr, "Library symbol \"%s\" not found.\n", symbol.c_str());
- return NULL;
- }
- return res;
+void* DLibrary::getSymbol(const std::string& symbol) {
+ if (!handle) {
+ fprintf(stderr, "Cannot inspect library symbols, library isn't loaded.\n");
+ return NULL;
+ }
+ void* res;
+#ifdef PLUMA_SYS_WINDOWS
+ res = (void*)(::GetProcAddress((HMODULE)handle, symbol.c_str()));
+#else
+ res = (void*)(::dlsym(handle, symbol.c_str()));
+#endif
+ if (!res) {
+ fprintf(stderr, "Library symbol \"%s\" not found.\n", symbol.c_str());
+ return NULL;
+ }
+ return res;
}
////////////////////////////////////////////////////////////
DLibrary::DLibrary(void* handle):
- handle(handle)
-{
- // Nothing to do
+ handle(handle) {
+ // Nothing to do
}
} // namespace pluma
diff --git a/src/uscxml/plugins/Pluma/Dir.cpp b/src/uscxml/plugins/Pluma/Dir.cpp index 860220e..73271ea 100755..100644 --- a/src/uscxml/plugins/Pluma/Dir.cpp +++ b/src/uscxml/plugins/Pluma/Dir.cpp @@ -32,68 +32,68 @@ #include <queue>
-namespace pluma{
+namespace pluma {
-namespace dir{
+namespace dir {
////////////////////////////////////////////////////////////
-void listFiles(std::list<std::string>& list, const std::string& folder, const std::string& extension, bool recursive){
- DIR* dir;
- DIR* subDir;
- struct dirent *ent;
- // try to open top folder
- dir = opendir(folder.c_str());
- if (dir == NULL){
- // could not open directory
- fprintf(stderr, "Could not open \"%s\" directory.\n", folder.c_str());
- return;
- }else{
- // close, we'll process it next
- closedir(dir);
- }
- // enqueue top folder
- std::queue<std::string> folders;
- folders.push(folder);
+void listFiles(std::list<std::string>& list, const std::string& folder, const std::string& extension, bool recursive) {
+ DIR* dir;
+ DIR* subDir;
+ struct dirent *ent;
+ // try to open top folder
+ dir = opendir(folder.c_str());
+ if (dir == NULL) {
+ // could not open directory
+ fprintf(stderr, "Could not open \"%s\" directory.\n", folder.c_str());
+ return;
+ } else {
+ // close, we'll process it next
+ closedir(dir);
+ }
+ // enqueue top folder
+ std::queue<std::string> folders;
+ folders.push(folder);
- // run while has queued folders
- while (!folders.empty()){
- std::string currFolder = folders.front();
- folders.pop();
- dir = opendir(currFolder.c_str());
- if (dir == NULL) continue;
- // iterate through all the files and directories
- while ((ent = readdir (dir)) != NULL) {
- std::string name(ent->d_name);
- // ignore "." and ".." directories
- if ( name.compare(".") == 0 || name.compare("..") == 0) continue;
- // add path to the file name
- std::string path = currFolder;
- path.append("/");
- path.append(name);
- // check if it's a folder by trying to open it
- subDir = opendir(path.c_str());
- if (subDir != NULL){
- // it's a folder: close, we can process it later
- closedir(subDir);
- if (recursive) folders.push(path);
- }else{
- // it's a file
- if (extension.empty()){
- list.push_back(path);
- }else{
- // check file extension
- size_t lastDot = name.find_last_of('.');
- std::string ext = name.substr(lastDot+1);
- if (ext.compare(extension) == 0){
- // match
- list.push_back(path);
- }
- } // endif (extension test)
- } // endif (folder test)
- } // endwhile (nextFile)
- closedir(dir);
- } // endwhile (queued folders)
+ // run while has queued folders
+ while (!folders.empty()) {
+ std::string currFolder = folders.front();
+ folders.pop();
+ dir = opendir(currFolder.c_str());
+ if (dir == NULL) continue;
+ // iterate through all the files and directories
+ while ((ent = readdir (dir)) != NULL) {
+ std::string name(ent->d_name);
+ // ignore "." and ".." directories
+ if ( name.compare(".") == 0 || name.compare("..") == 0) continue;
+ // add path to the file name
+ std::string path = currFolder;
+ path.append("/");
+ path.append(name);
+ // check if it's a folder by trying to open it
+ subDir = opendir(path.c_str());
+ if (subDir != NULL) {
+ // it's a folder: close, we can process it later
+ closedir(subDir);
+ if (recursive) folders.push(path);
+ } else {
+ // it's a file
+ if (extension.empty()) {
+ list.push_back(path);
+ } else {
+ // check file extension
+ size_t lastDot = name.find_last_of('.');
+ std::string ext = name.substr(lastDot+1);
+ if (ext.compare(extension) == 0) {
+ // match
+ list.push_back(path);
+ }
+ } // endif (extension test)
+ } // endif (folder test)
+ } // endwhile (nextFile)
+ closedir(dir);
+ } // endwhile (queued folders)
} // end listFiles
diff --git a/src/uscxml/plugins/Pluma/Host.cpp b/src/uscxml/plugins/Pluma/Host.cpp index eb37c33..73979a6 100755..100644 --- a/src/uscxml/plugins/Pluma/Host.cpp +++ b/src/uscxml/plugins/Pluma/Host.cpp @@ -30,149 +30,149 @@ #include <cstdio>
-namespace pluma{
+namespace pluma {
////////////////////////////////////////////////////////////
-Host::Host(){
- // Nothing to do
+Host::Host() {
+ // Nothing to do
}
////////////////////////////////////////////////////////////
-bool Host::add(Provider* provider){
- if (provider == NULL){
- fprintf(stderr, "Trying to add a null provider.\n");
- return false;
- }
- if (!validateProvider(provider)){
- delete provider;
- return false;
- }
- addRequests[ provider->plumaGetType() ].push_back(provider);
- return true;
+bool Host::add(Provider* provider) {
+ if (provider == NULL) {
+ fprintf(stderr, "Trying to add a null provider.\n");
+ return false;
+ }
+ if (!validateProvider(provider)) {
+ delete provider;
+ return false;
+ }
+ addRequests[ provider->plumaGetType() ].push_back(provider);
+ return true;
}
////////////////////////////////////////////////////////////
-Host::~Host(){
- clearProviders();
- // map frees itself
+Host::~Host() {
+ clearProviders();
+ // map frees itself
}
////////////////////////////////////////////////////////////
-void Host::clearProviders(){
- ProvidersMap::iterator it;
- for (it = knownTypes.begin() ; it != knownTypes.end() ; ++it){
- std::list<Provider*>& providers = it->second.providers;
- std::list<Provider*>::iterator provIt;
- for (provIt = providers.begin() ; provIt != providers.end() ; ++provIt){
- delete *provIt;
- }
- std::list<Provider*>().swap(providers);
- }
+void Host::clearProviders() {
+ ProvidersMap::iterator it;
+ for (it = knownTypes.begin() ; it != knownTypes.end() ; ++it) {
+ std::list<Provider*>& providers = it->second.providers;
+ std::list<Provider*>::iterator provIt;
+ for (provIt = providers.begin() ; provIt != providers.end() ; ++provIt) {
+ delete *provIt;
+ }
+ std::list<Provider*>().swap(providers);
+ }
}
////////////////////////////////////////////////////////////
-bool Host::knows(const std::string& type) const{
- return knownTypes.find(type) != knownTypes.end();
+bool Host::knows(const std::string& type) const {
+ return knownTypes.find(type) != knownTypes.end();
}
////////////////////////////////////////////////////////////
-unsigned int Host::getVersion(const std::string& type) const{
- ProvidersMap::const_iterator it = knownTypes.find(type);
- if (it != knownTypes.end())
- return it->second.version;
- return 0;
+unsigned int Host::getVersion(const std::string& type) const {
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return it->second.version;
+ return 0;
}
////////////////////////////////////////////////////////////
-unsigned int Host::getLowestVersion(const std::string& type) const{
- ProvidersMap::const_iterator it = knownTypes.find(type);
- if (it != knownTypes.end())
- return it->second.lowestVersion;
- return 0;
+unsigned int Host::getLowestVersion(const std::string& type) const {
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return it->second.lowestVersion;
+ return 0;
}
////////////////////////////////////////////////////////////
-void Host::registerType(const std::string& type, unsigned int version, unsigned int lowestVersion){
- if (!knows(type)){
- ProviderInfo pi;
- pi.version = version;
- pi.lowestVersion = lowestVersion;
- knownTypes[type] = pi;
- }
+void Host::registerType(const std::string& type, unsigned int version, unsigned int lowestVersion) {
+ if (!knows(type)) {
+ ProviderInfo pi;
+ pi.version = version;
+ pi.lowestVersion = lowestVersion;
+ knownTypes[type] = pi;
+ }
}
////////////////////////////////////////////////////////////
-const std::list<Provider*>* Host::getProviders(const std::string& type) const{
- ProvidersMap::const_iterator it = knownTypes.find(type);
- if (it != knownTypes.end())
- return &it->second.providers;
- return NULL;
+const std::list<Provider*>* Host::getProviders(const std::string& type) const {
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return &it->second.providers;
+ return NULL;
}
////////////////////////////////////////////////////////////
-bool Host::validateProvider(Provider* provider) const{
- const std::string& type = provider->plumaGetType();
- if ( !knows(type) ){
- fprintf(stderr, "%s provider type isn't registered.\n", type.c_str());
- return false;
- }
- if (!provider->isCompatible(*this)){
- fprintf(stderr, "Incompatible %s provider version.\n", type.c_str());
- return false;
- }
- return true;
+bool Host::validateProvider(Provider* provider) const {
+ const std::string& type = provider->plumaGetType();
+ if ( !knows(type) ) {
+ fprintf(stderr, "%s provider type isn't registered.\n", type.c_str());
+ return false;
+ }
+ if (!provider->isCompatible(*this)) {
+ fprintf(stderr, "Incompatible %s provider version.\n", type.c_str());
+ return false;
+ }
+ return true;
}
////////////////////////////////////////////////////////////
-bool Host::registerProvider(Provider* provider){
- if (!validateProvider(provider)){
- delete provider;
- return false;
- }
- knownTypes[ provider->plumaGetType() ].providers.push_back(provider);
- return true;
+bool Host::registerProvider(Provider* provider) {
+ if (!validateProvider(provider)) {
+ delete provider;
+ return false;
+ }
+ knownTypes[ provider->plumaGetType() ].providers.push_back(provider);
+ return true;
}
////////////////////////////////////////////////////////////
-void Host::cancelAddictions(){
- TempProvidersMap::iterator it;
- for( it = addRequests.begin() ; it != addRequests.end() ; ++it){
- std::list<Provider*> lst = it->second;
- std::list<Provider*>::iterator providerIt;
- for (providerIt = lst.begin() ; providerIt != lst.end() ; ++providerIt){
- delete *providerIt;
- }
- }
- // clear map
- TempProvidersMap().swap(addRequests);
+void Host::cancelAddictions() {
+ TempProvidersMap::iterator it;
+ for( it = addRequests.begin() ; it != addRequests.end() ; ++it) {
+ std::list<Provider*> lst = it->second;
+ std::list<Provider*>::iterator providerIt;
+ for (providerIt = lst.begin() ; providerIt != lst.end() ; ++providerIt) {
+ delete *providerIt;
+ }
+ }
+ // clear map
+ TempProvidersMap().swap(addRequests);
}
////////////////////////////////////////////////////////////
-bool Host::confirmAddictions(){
- if (addRequests.empty()) return false;
- TempProvidersMap::iterator it;
- for( it = addRequests.begin() ; it != addRequests.end() ; ++it){
- std::list<Provider*> lst = it->second;
- std::list<Provider*>::iterator providerIt;
- for (providerIt = lst.begin() ; providerIt != lst.end() ; ++providerIt){
- knownTypes[it->first].providers.push_back(*providerIt);
- }
- }
- // clear map
- TempProvidersMap().swap(addRequests);
- return true;
+bool Host::confirmAddictions() {
+ if (addRequests.empty()) return false;
+ TempProvidersMap::iterator it;
+ for( it = addRequests.begin() ; it != addRequests.end() ; ++it) {
+ std::list<Provider*> lst = it->second;
+ std::list<Provider*>::iterator providerIt;
+ for (providerIt = lst.begin() ; providerIt != lst.end() ; ++providerIt) {
+ knownTypes[it->first].providers.push_back(*providerIt);
+ }
+ }
+ // clear map
+ TempProvidersMap().swap(addRequests);
+ return true;
}
diff --git a/src/uscxml/plugins/Pluma/PluginManager.cpp b/src/uscxml/plugins/Pluma/PluginManager.cpp index 1124505..60cb46e 100755..100644 --- a/src/uscxml/plugins/Pluma/PluginManager.cpp +++ b/src/uscxml/plugins/Pluma/PluginManager.cpp @@ -31,168 +31,168 @@ #include <Pluma/Dir.hpp>
#include <cstdio>
-namespace pluma{
+namespace pluma {
////////////////////////////////////////////////////////////
-PluginManager::PluginManager(){
- // Nothing to do
+PluginManager::PluginManager() {
+ // Nothing to do
}
////////////////////////////////////////////////////////////
-PluginManager::~PluginManager(){
- unloadAll();
+PluginManager::~PluginManager() {
+ unloadAll();
}
////////////////////////////////////////////////////////////
-bool PluginManager::load(const std::string& path){
- std::string plugName = getPluginName(path);
- std::string realPath = resolvePathExtension(path);
- DLibrary* lib = DLibrary::load(realPath);
- if (!lib) return false;
-
- fnRegisterPlugin* registerFunction;
- registerFunction = reinterpret_cast<fnRegisterPlugin*>(lib->getSymbol("connect"));
-
- if(!registerFunction){
- fprintf(stderr, "Failed to initialize plugin \"%s\": connect function not found\n", plugName.c_str());
- delete lib;
- return false;
- }
- // try to initialize plugin:
- if (!registerFunction(host)){
- // plugin decided to fail
- fprintf(stderr, "Self registry failed on plugin \"%s\".\n", plugName.c_str());
- host.cancelAddictions();
- delete lib;
- return false;
- }
- // Store the library if addictions are confirmed
- if (host.confirmAddictions())
- libraries[plugName] = lib;
- else{
- // otherwise nothing was registered
- fprintf(stderr, "Nothing registered by plugin \"%s\".\n", plugName.c_str());
- delete lib;
- return false;
- }
- return true;
+bool PluginManager::load(const std::string& path) {
+ std::string plugName = getPluginName(path);
+ std::string realPath = resolvePathExtension(path);
+ DLibrary* lib = DLibrary::load(realPath);
+ if (!lib) return false;
+
+ fnRegisterPlugin* registerFunction;
+ registerFunction = reinterpret_cast<fnRegisterPlugin*>(lib->getSymbol("connect"));
+
+ if(!registerFunction) {
+ fprintf(stderr, "Failed to initialize plugin \"%s\": connect function not found\n", plugName.c_str());
+ delete lib;
+ return false;
+ }
+ // try to initialize plugin:
+ if (!registerFunction(host)) {
+ // plugin decided to fail
+ fprintf(stderr, "Self registry failed on plugin \"%s\".\n", plugName.c_str());
+ host.cancelAddictions();
+ delete lib;
+ return false;
+ }
+ // Store the library if addictions are confirmed
+ if (host.confirmAddictions())
+ libraries[plugName] = lib;
+ else {
+ // otherwise nothing was registered
+ fprintf(stderr, "Nothing registered by plugin \"%s\".\n", plugName.c_str());
+ delete lib;
+ return false;
+ }
+ return true;
}
////////////////////////////////////////////////////////////
-bool PluginManager::load(const std::string& folder, const std::string& pluginName){
- if (folder.empty())
- return load(pluginName);
- else if (folder[folder.size()-1] == '/' || folder[folder.size()-1] == '\\')
- return load(folder + pluginName);
- return load(folder + '/' + pluginName);
+bool PluginManager::load(const std::string& folder, const std::string& pluginName) {
+ if (folder.empty())
+ return load(pluginName);
+ else if (folder[folder.size()-1] == '/' || folder[folder.size()-1] == '\\')
+ return load(folder + pluginName);
+ return load(folder + '/' + pluginName);
}
////////////////////////////////////////////////////////////
-int PluginManager::loadFromFolder(const std::string& folder, bool recursive){
- std::list<std::string> files;
- dir::listFiles(files, folder, PLUMA_LIB_EXTENSION, recursive);
- // try to load every library
- int res = 0;
- std::list<std::string>::const_iterator it;
- for (it = files.begin() ; it != files.end() ; ++it){
- if ( load(*it) ) ++res;
- }
- return res;
+int PluginManager::loadFromFolder(const std::string& folder, bool recursive) {
+ std::list<std::string> files;
+ dir::listFiles(files, folder, PLUMA_LIB_EXTENSION, recursive);
+ // try to load every library
+ int res = 0;
+ std::list<std::string>::const_iterator it;
+ for (it = files.begin() ; it != files.end() ; ++it) {
+ if ( load(*it) ) ++res;
+ }
+ return res;
}
////////////////////////////////////////////////////////////
-bool PluginManager::unload(const std::string& pluginName){
- std::string plugName = getPluginName(pluginName);
- LibMap::iterator it = libraries.find(plugName);
- if( it != libraries.end() ) {
- delete it->second;
- libraries.erase(it);
- return true;
- }
- return false;
+bool PluginManager::unload(const std::string& pluginName) {
+ std::string plugName = getPluginName(pluginName);
+ LibMap::iterator it = libraries.find(plugName);
+ if( it != libraries.end() ) {
+ delete it->second;
+ libraries.erase(it);
+ return true;
+ }
+ return false;
}
////////////////////////////////////////////////////////////
-void PluginManager::unloadAll(){
+void PluginManager::unloadAll() {
- host.clearProviders();
- LibMap::iterator it;
- for (it = libraries.begin() ; it != libraries.end() ; ++it){
- delete it->second;
- }
- libraries.clear();
+ host.clearProviders();
+ LibMap::iterator it;
+ for (it = libraries.begin() ; it != libraries.end() ; ++it) {
+ delete it->second;
+ }
+ libraries.clear();
}
////////////////////////////////////////////////////////////
-std::string PluginManager::getPluginName(const std::string& path){
- size_t lastDash = path.find_last_of("/\\");
- size_t lastDot = path.find_last_of('.');
- if (lastDash == std::string::npos) lastDash = 0;
- else ++lastDash;
- if (lastDot < lastDash || lastDot == std::string::npos){
- // path without extension
- lastDot = path.length();
- }
- return path.substr(lastDash, lastDot-lastDash);
+std::string PluginManager::getPluginName(const std::string& path) {
+ size_t lastDash = path.find_last_of("/\\");
+ size_t lastDot = path.find_last_of('.');
+ if (lastDash == std::string::npos) lastDash = 0;
+ else ++lastDash;
+ if (lastDot < lastDash || lastDot == std::string::npos) {
+ // path without extension
+ lastDot = path.length();
+ }
+ return path.substr(lastDash, lastDot-lastDash);
}
////////////////////////////////////////////////////////////
-std::string PluginManager::resolvePathExtension(const std::string& path){
- size_t lastDash = path.find_last_of("/\\");
- size_t lastDot = path.find_last_of('.');
- if (lastDash == std::string::npos) lastDash = 0;
- else ++lastDash;
- if (lastDot < lastDash || lastDot == std::string::npos){
- // path without extension, add it
- return path + "." + PLUMA_LIB_EXTENSION;
- }
- return path;
+std::string PluginManager::resolvePathExtension(const std::string& path) {
+ size_t lastDash = path.find_last_of("/\\");
+ size_t lastDot = path.find_last_of('.');
+ if (lastDash == std::string::npos) lastDash = 0;
+ else ++lastDash;
+ if (lastDot < lastDash || lastDot == std::string::npos) {
+ // path without extension, add it
+ return path + "." + PLUMA_LIB_EXTENSION;
+ }
+ return path;
}
////////////////////////////////////////////////////////////
-void PluginManager::registerType(const std::string& type, unsigned int version, unsigned int lowestVersion){
- host.registerType(type, version, lowestVersion);
+void PluginManager::registerType(const std::string& type, unsigned int version, unsigned int lowestVersion) {
+ host.registerType(type, version, lowestVersion);
}
////////////////////////////////////////////////////////////
-bool PluginManager::addProvider(Provider* provider){
- if (provider == NULL){
- fprintf(stderr, "Trying to add null provider\n");
- return false;
- }
- return host.registerProvider(provider);
+bool PluginManager::addProvider(Provider* provider) {
+ if (provider == NULL) {
+ fprintf(stderr, "Trying to add null provider\n");
+ return false;
+ }
+ return host.registerProvider(provider);
}
////////////////////////////////////////////////////////////
-void PluginManager::getLoadedPlugins(std::vector<const std::string*>& pluginNames) const{
- pluginNames.reserve(pluginNames.size()+libraries.size());
- LibMap::const_iterator it;
- for(it = libraries.begin() ; it != libraries.end() ; ++it){
- pluginNames.push_back(&(it->first));
- }
+void PluginManager::getLoadedPlugins(std::vector<const std::string*>& pluginNames) const {
+ pluginNames.reserve(pluginNames.size()+libraries.size());
+ LibMap::const_iterator it;
+ for(it = libraries.begin() ; it != libraries.end() ; ++it) {
+ pluginNames.push_back(&(it->first));
+ }
}
////////////////////////////////////////////////////////////
-bool PluginManager::isLoaded(const std::string& pluginName) const{
- return libraries.find(getPluginName(pluginName)) != libraries.end();
+bool PluginManager::isLoaded(const std::string& pluginName) const {
+ return libraries.find(getPluginName(pluginName)) != libraries.end();
}
////////////////////////////////////////////////////////////
-const std::list<Provider*>* PluginManager::getProviders(const std::string& type) const{
- return host.getProviders(type);
+const std::list<Provider*>* PluginManager::getProviders(const std::string& type) const {
+ return host.getProviders(type);
}
diff --git a/src/uscxml/plugins/Pluma/Provider.cpp b/src/uscxml/plugins/Pluma/Provider.cpp index 36d4da3..7691eb1 100755..100644 --- a/src/uscxml/plugins/Pluma/Provider.cpp +++ b/src/uscxml/plugins/Pluma/Provider.cpp @@ -30,23 +30,23 @@ #include <Pluma/Host.hpp>
-namespace pluma{
+namespace pluma {
////////////////////////////////////////////////////////////
-Provider::~Provider(){
- // Nothing to do
+Provider::~Provider() {
+ // Nothing to do
}
////////////////////////////////////////////////////////////
-bool Provider::isCompatible(const Host& host) const{
- // check compatibility with host
- const std::string& type = this->plumaGetType();
- if (!host.knows(type)) return false;
- unsigned int lowest = host.getLowestVersion(type);
- unsigned int current = host.getVersion(type);
- unsigned int myVersion = this->getVersion();
- return lowest <= myVersion && myVersion <= current;
+bool Provider::isCompatible(const Host& host) const {
+ // check compatibility with host
+ const std::string& type = this->plumaGetType();
+ if (!host.knows(type)) return false;
+ unsigned int lowest = host.getLowestVersion(type);
+ unsigned int current = host.getVersion(type);
+ unsigned int myVersion = this->getVersion();
+ return lowest <= myVersion && myVersion <= current;
}
} // namespace pluma
diff --git a/src/uscxml/plugins/Pluma/uce-dirent.h b/src/uscxml/plugins/Pluma/uce-dirent.h index ecf78eb..8cbd0e5 100755..100644 --- a/src/uscxml/plugins/Pluma/uce-dirent.h +++ b/src/uscxml/plugins/Pluma/uce-dirent.h @@ -1,8 +1,8 @@ /* * uce-dirent.h - operating system independent dirent implementation - * + * * Copyright (C) 1998-2002 Toni Ronkko - * + * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * ``Software''), to deal in the Software without restriction, including @@ -10,10 +10,10 @@ * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -21,8 +21,8 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. - * - * + * + * * May 28 1998, Toni Ronkko <tronkko@messi.uku.fi> * * $Id: uce-dirent.h,v 1.7 2002/05/13 10:48:35 tr Exp $ @@ -58,7 +58,7 @@ * Revision 1.1 1998/07/04 16:27:51 tr * Initial revision * - * + * * MSVC 1.0 scans automatic dependencies incorrectly when your project * contains this very header. The problem is that MSVC cannot handle * include directives inside #if..#endif block those are never entered. @@ -105,12 +105,12 @@ */ #if !defined(HAVE_DIRENT_H) && !defined(HAVE_DIRECT_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_NDIR_H) && !defined(HAVE_DIR_H) # if defined(_MSC_VER) /* Microsoft C/C++ */ - /* no dirent.h */ +/* no dirent.h */ # elif defined(__BORLANDC__) /* Borland C/C++ */ # define HAVE_DIRENT_H # define VOID_CLOSEDIR # elif defined(__TURBOC__) /* Borland Turbo C */ - /* no dirent.h */ +/* no dirent.h */ # elif defined(__WATCOMC__) /* Watcom C/C++ */ # define HAVE_DIRECT_H # elif defined(__apollo) /* Apollo */ @@ -169,7 +169,7 @@ #elif defined(MSDOS) || defined(WIN32) - /* figure out type of underlaying directory interface to be used */ +/* figure out type of underlaying directory interface to be used */ # if defined(WIN32) # define DIRENT_WIN32_INTERFACE # elif defined(MSDOS) @@ -178,7 +178,7 @@ # error "missing native dirent interface" # endif - /*** WIN32 specifics ***/ +/*** WIN32 specifics ***/ # if defined(DIRENT_WIN32_INTERFACE) # include <windows.h> # if !defined(DIRENT_MAXNAMLEN) @@ -186,11 +186,11 @@ # endif - /*** MS-DOS specifics ***/ +/*** MS-DOS specifics ***/ # elif defined(DIRENT_MSDOS_INTERFACE) # include <dos.h> - /* Borland defines file length macros in dir.h */ +/* Borland defines file length macros in dir.h */ # if defined(__BORLANDC__) # include <dir.h> # if !defined(DIRENT_MAXNAMLEN) @@ -200,7 +200,7 @@ # define _find_t find_t # endif - /* Turbo C defines ffblk structure in dir.h */ +/* Turbo C defines ffblk structure in dir.h */ # elif defined(__TURBOC__) # include <dir.h> # if !defined(DIRENT_MAXNAMLEN) @@ -208,13 +208,13 @@ # endif # define DIRENT_USE_FFBLK - /* MSVC */ +/* MSVC */ # elif defined(_MSC_VER) # if !defined(DIRENT_MAXNAMLEN) # define DIRENT_MAXNAMLEN (12) # endif - /* Watcom */ +/* Watcom */ # elif defined(__WATCOMC__) # if !defined(DIRENT_MAXNAMLEN) # if defined(__OS2__) || defined(__NT__) @@ -227,7 +227,7 @@ # endif # endif - /*** generic MS-DOS and MS-Windows stuff ***/ +/*** generic MS-DOS and MS-Windows stuff ***/ # if !defined(NAME_MAX) && defined(DIRENT_MAXNAMLEN) # define NAME_MAX DIRENT_MAXNAMLEN # endif @@ -236,67 +236,67 @@ # endif - /* - * Substitute for real dirent structure. Note that `d_name' field is a - * true character array although we have it copied in the implementation - * dependent data. We could save some memory if we had declared `d_name' - * as a pointer refering the name within implementation dependent data. - * We have not done that since some code may rely on sizeof(d_name) to be - * something other than four. Besides, directory entries are typically so - * small that it takes virtually no time to copy them from place to place. - */ - typedef struct dirent { - char d_name[NAME_MAX + 1]; +/* + * Substitute for real dirent structure. Note that `d_name' field is a + * true character array although we have it copied in the implementation + * dependent data. We could save some memory if we had declared `d_name' + * as a pointer refering the name within implementation dependent data. + * We have not done that since some code may rely on sizeof(d_name) to be + * something other than four. Besides, directory entries are typically so + * small that it takes virtually no time to copy them from place to place. + */ +typedef struct dirent { + char d_name[NAME_MAX + 1]; - /*** Operating system specific part ***/ + /*** Operating system specific part ***/ # if defined(DIRENT_WIN32_INTERFACE) /*WIN32*/ - WIN32_FIND_DATA data; + WIN32_FIND_DATA data; # elif defined(DIRENT_MSDOS_INTERFACE) /*MSDOS*/ # if defined(DIRENT_USE_FFBLK) - struct ffblk data; + struct ffblk data; # else - struct _find_t data; + struct _find_t data; # endif # endif - } dirent; +} dirent; - /* DIR substitute structure containing directory name. The name is - * essential for the operation of ``rewinndir'' function. */ - typedef struct DIR { - char *dirname; /* directory being scanned */ - dirent current; /* current entry */ - int dirent_filled; /* is current un-processed? */ +/* DIR substitute structure containing directory name. The name is + * essential for the operation of ``rewinndir'' function. */ +typedef struct DIR { + char *dirname; /* directory being scanned */ + dirent current; /* current entry */ + int dirent_filled; /* is current un-processed? */ - /*** Operating system specific part ***/ + /*** Operating system specific part ***/ # if defined(DIRENT_WIN32_INTERFACE) - HANDLE search_handle; + HANDLE search_handle; # elif defined(DIRENT_MSDOS_INTERFACE) # endif - } DIR; +} DIR; # ifdef __cplusplus extern "C" { # endif -/* supply prototypes for dirent functions */ -static DIR *opendir (const char *dirname); -static struct dirent *readdir (DIR *dirp); -static int closedir (DIR *dirp); -static void rewinddir (DIR *dirp); - -/* - * Implement dirent interface as static functions so that the user does not - * need to change his project in any way to use dirent function. With this - * it is sufficient to include this very header from source modules using - * dirent functions and the functions will be pulled in automatically. - */ + /* supply prototypes for dirent functions */ + static DIR *opendir (const char *dirname); + static struct dirent *readdir (DIR *dirp); + static int closedir (DIR *dirp); + static void rewinddir (DIR *dirp); + + /* + * Implement dirent interface as static functions so that the user does not + * need to change his project in any way to use dirent function. With this + * it is sufficient to include this very header from source modules using + * dirent functions and the functions will be pulled in automatically. + */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <errno.h> -/* use ffblk instead of _find_t if requested */ + /* use ffblk instead of _find_t if requested */ #if defined(DIRENT_USE_FFBLK) # define _A_ARCH (FA_ARCH) # define _A_HIDDEN (FA_HIDDEN) @@ -309,362 +309,354 @@ static void rewinddir (DIR *dirp); # define _dos_findfirst(name,flags,dest) findfirst(name,dest,flags) #endif -static int _initdir (DIR *p); -static const char *_getdirname (const struct dirent *dp); -static void _setdirname (struct DIR *dirp); - -/* - * <function name="opendir"> - * <intro>open directory stream for reading - * <syntax>DIR *opendir (const char *dirname); - * - * <desc>Open named directory stream for read and return pointer to the - * internal working area that is used for retrieving individual directory - * entries. The internal working area has no fields of your interest. - * - * <ret>Returns a pointer to the internal working area or NULL in case the - * directory stream could not be opened. Global `errno' variable will set - * in case of error as follows: - * - * <table> - * [EACESS |Permission denied. - * [EMFILE |Too many open files used by the process. - * [ENFILE |Too many open files in system. - * [ENOENT |Directory does not exist. - * [ENOMEM |Insufficient memory. - * [ENOTDIR |dirname does not refer to directory. This value is not - * reliable on MS-DOS and MS-Windows platforms. Many - * implementations return ENOENT even when the name refers to a - * file.] - * </table> - * </function> - */ -static DIR * -opendir( - const char *dirname) -{ - DIR *dirp; - assert (dirname != NULL); - - dirp = (DIR*)malloc (sizeof (struct DIR)); - if (dirp != NULL) { - char *p; - - /* allocate room for directory name */ - dirp->dirname = (char*) malloc (strlen (dirname) + 1 + strlen ("\\*.*")); - if (dirp->dirname == NULL) { - /* failed to duplicate directory name. errno set by malloc() */ - free (dirp); - return NULL; - } - /* Copy directory name while appending directory separator and "*.*". - * Directory separator is not appended if the name already ends with - * drive or directory separator. Directory separator is assumed to be - * '/' or '\' and drive separator is assumed to be ':'. */ - strcpy (dirp->dirname, dirname); - p = strchr (dirp->dirname, '\0'); - if (dirp->dirname < p && - *(p - 1) != '\\' && *(p - 1) != '/' && *(p - 1) != ':') - { - strcpy (p++, "/"); - } + static int _initdir (DIR *p); + static const char *_getdirname (const struct dirent *dp); + static void _setdirname (struct DIR *dirp); + + /* + * <function name="opendir"> + * <intro>open directory stream for reading + * <syntax>DIR *opendir (const char *dirname); + * + * <desc>Open named directory stream for read and return pointer to the + * internal working area that is used for retrieving individual directory + * entries. The internal working area has no fields of your interest. + * + * <ret>Returns a pointer to the internal working area or NULL in case the + * directory stream could not be opened. Global `errno' variable will set + * in case of error as follows: + * + * <table> + * [EACESS |Permission denied. + * [EMFILE |Too many open files used by the process. + * [ENFILE |Too many open files in system. + * [ENOENT |Directory does not exist. + * [ENOMEM |Insufficient memory. + * [ENOTDIR |dirname does not refer to directory. This value is not + * reliable on MS-DOS and MS-Windows platforms. Many + * implementations return ENOENT even when the name refers to a + * file.] + * </table> + * </function> + */ + static DIR * + opendir( + const char *dirname) { + DIR *dirp; + assert (dirname != NULL); + + dirp = (DIR*)malloc (sizeof (struct DIR)); + if (dirp != NULL) { + char *p; + + /* allocate room for directory name */ + dirp->dirname = (char*) malloc (strlen (dirname) + 1 + strlen ("\\*.*")); + if (dirp->dirname == NULL) { + /* failed to duplicate directory name. errno set by malloc() */ + free (dirp); + return NULL; + } + /* Copy directory name while appending directory separator and "*.*". + * Directory separator is not appended if the name already ends with + * drive or directory separator. Directory separator is assumed to be + * '/' or '\' and drive separator is assumed to be ':'. */ + strcpy (dirp->dirname, dirname); + p = strchr (dirp->dirname, '\0'); + if (dirp->dirname < p && + *(p - 1) != '\\' && *(p - 1) != '/' && *(p - 1) != ':') { + strcpy (p++, "/"); + } # ifdef DIRENT_WIN32_INTERFACE - strcpy (p, "*"); /*scan files with and without extension in win32*/ + strcpy (p, "*"); /*scan files with and without extension in win32*/ # else - strcpy (p, "*.*"); /*scan files with and without extension in DOS*/ + strcpy (p, "*.*"); /*scan files with and without extension in DOS*/ # endif - /* open stream */ - if (_initdir (dirp) == 0) { - /* initialization failed */ - free (dirp->dirname); - free (dirp); - return NULL; - } - } - return dirp; -} - - -/* - * <function name="readdir"> - * <intro>read a directory entry - * <syntax>struct dirent *readdir (DIR *dirp); - * - * <desc>Read individual directory entry and return pointer to a structure - * containing the name of the entry. Individual directory entries returned - * include normal files, sub-directories, pseudo-directories "." and ".." - * and also volume labels, hidden files and system files in MS-DOS and - * MS-Windows. You might want to use stat(2) function to determinate which - * one are you dealing with. Many dirent implementations already contain - * equivalent information in dirent structure but you cannot depend on - * this. - * - * The dirent structure contains several system dependent fields that - * generally have no interest to you. The only interesting one is char - * d_name[] that is also portable across different systems. The d_name - * field contains the name of the directory entry without leading path. - * While d_name is portable across different systems the actual storage - * capacity of d_name varies from system to system and there is no portable - * way to find out it at compile time as different systems define the - * capacity of d_name with different macros and some systems do not define - * capacity at all (besides actual declaration of the field). If you really - * need to find out storage capacity of d_name then you might want to try - * NAME_MAX macro. The NAME_MAX is defined in POSIX standard althought - * there are many MS-DOS and MS-Windows implementations those do not define - * it. There are also systems that declare d_name as "char d_name[1]" and - * then allocate suitable amount of memory at run-time. Thanks to Alain - * Decamps (Alain.Decamps@advalvas.be) for pointing it out to me. - * - * This all leads to the fact that it is difficult to allocate space - * for the directory names when the very same program is being compiled on - * number of operating systems. Therefore I suggest that you always - * allocate space for directory names dynamically. - * - * <ret> - * Returns a pointer to a structure containing name of the directory entry - * in `d_name' field or NULL if there was an error. In case of an error the - * global `errno' variable will set as follows: - * - * <table> - * [EBADF |dir parameter refers to an invalid directory stream. This value - * is not set reliably on all implementations.] - * </table> - * </function> - */ -static struct dirent * -readdir (DIR *dirp) -{ - assert (dirp != NULL); - if (dirp == NULL) { - errno = EBADF; - return NULL; - } + /* open stream */ + if (_initdir (dirp) == 0) { + /* initialization failed */ + free (dirp->dirname); + free (dirp); + return NULL; + } + } + return dirp; + } + + + /* + * <function name="readdir"> + * <intro>read a directory entry + * <syntax>struct dirent *readdir (DIR *dirp); + * + * <desc>Read individual directory entry and return pointer to a structure + * containing the name of the entry. Individual directory entries returned + * include normal files, sub-directories, pseudo-directories "." and ".." + * and also volume labels, hidden files and system files in MS-DOS and + * MS-Windows. You might want to use stat(2) function to determinate which + * one are you dealing with. Many dirent implementations already contain + * equivalent information in dirent structure but you cannot depend on + * this. + * + * The dirent structure contains several system dependent fields that + * generally have no interest to you. The only interesting one is char + * d_name[] that is also portable across different systems. The d_name + * field contains the name of the directory entry without leading path. + * While d_name is portable across different systems the actual storage + * capacity of d_name varies from system to system and there is no portable + * way to find out it at compile time as different systems define the + * capacity of d_name with different macros and some systems do not define + * capacity at all (besides actual declaration of the field). If you really + * need to find out storage capacity of d_name then you might want to try + * NAME_MAX macro. The NAME_MAX is defined in POSIX standard althought + * there are many MS-DOS and MS-Windows implementations those do not define + * it. There are also systems that declare d_name as "char d_name[1]" and + * then allocate suitable amount of memory at run-time. Thanks to Alain + * Decamps (Alain.Decamps@advalvas.be) for pointing it out to me. + * + * This all leads to the fact that it is difficult to allocate space + * for the directory names when the very same program is being compiled on + * number of operating systems. Therefore I suggest that you always + * allocate space for directory names dynamically. + * + * <ret> + * Returns a pointer to a structure containing name of the directory entry + * in `d_name' field or NULL if there was an error. In case of an error the + * global `errno' variable will set as follows: + * + * <table> + * [EBADF |dir parameter refers to an invalid directory stream. This value + * is not set reliably on all implementations.] + * </table> + * </function> + */ + static struct dirent * + readdir (DIR *dirp) { + assert (dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return NULL; + } #if defined(DIRENT_WIN32_INTERFACE) - if (dirp->search_handle == INVALID_HANDLE_VALUE) { - /* directory stream was opened/rewound incorrectly or it ended normally */ - errno = EBADF; - return NULL; - } + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* directory stream was opened/rewound incorrectly or it ended normally */ + errno = EBADF; + return NULL; + } #endif - if (dirp->dirent_filled != 0) { - /* - * Directory entry has already been retrieved and there is no need to - * retrieve a new one. Directory entry will be retrieved in advance - * when the user calls readdir function for the first time. This is so - * because real dirent has separate functions for opening and reading - * the stream whereas Win32 and DOS dirents open the stream - * automatically when we retrieve the first file. Therefore, we have to - * save the first file when opening the stream and later we have to - * return the saved entry when the user tries to read the first entry. - */ - dirp->dirent_filled = 0; - } else { - /* fill in entry and return that */ + if (dirp->dirent_filled != 0) { + /* + * Directory entry has already been retrieved and there is no need to + * retrieve a new one. Directory entry will be retrieved in advance + * when the user calls readdir function for the first time. This is so + * because real dirent has separate functions for opening and reading + * the stream whereas Win32 and DOS dirents open the stream + * automatically when we retrieve the first file. Therefore, we have to + * save the first file when opening the stream and later we have to + * return the saved entry when the user tries to read the first entry. + */ + dirp->dirent_filled = 0; + } else { + /* fill in entry and return that */ #if defined(DIRENT_WIN32_INTERFACE) - if (FindNextFile (dirp->search_handle, &dirp->current.data) == FALSE) { - /* Last file has been processed or an error occured */ - FindClose (dirp->search_handle); - dirp->search_handle = INVALID_HANDLE_VALUE; - errno = ENOENT; - return NULL; - } + if (FindNextFile (dirp->search_handle, &dirp->current.data) == FALSE) { + /* Last file has been processed or an error occured */ + FindClose (dirp->search_handle); + dirp->search_handle = INVALID_HANDLE_VALUE; + errno = ENOENT; + return NULL; + } # elif defined(DIRENT_MSDOS_INTERFACE) - if (_dos_findnext (&dirp->current.data) != 0) { - /* _dos_findnext and findnext will set errno to ENOENT when no - * more entries could be retrieved. */ - return NULL; - } + if (_dos_findnext (&dirp->current.data) != 0) { + /* _dos_findnext and findnext will set errno to ENOENT when no + * more entries could be retrieved. */ + return NULL; + } # endif - _setdirname (dirp); - assert (dirp->dirent_filled == 0); - } - return &dirp->current; -} - - -/* - * <function name="closedir"> - * <intro>close directory stream. - * <syntax>int closedir (DIR *dirp); - * - * <desc>Close directory stream opened by the `opendir' function. Close of - * directory stream invalidates the DIR structure as well as previously read - * dirent entry. - * - * <ret>The function typically returns 0 on success and -1 on failure but - * the function may be declared to return void on same systems. At least - * Borland C/C++ and some UNIX implementations use void as a return type. - * The dirent wrapper tries to define VOID_CLOSEDIR whenever closedir is - * known to return nothing. The very same definition is made by the GNU - * autoconf if you happen to use it. - * - * The global `errno' variable will set to EBADF in case of error. - * </function> - */ -static int -closedir (DIR *dirp) -{ - int retcode = 0; - - /* make sure that dirp points to legal structure */ - assert (dirp != NULL); - if (dirp == NULL) { - errno = EBADF; - return -1; - } - - /* free directory name and search handles */ - if (dirp->dirname != NULL) free (dirp->dirname); + _setdirname (dirp); + assert (dirp->dirent_filled == 0); + } + return &dirp->current; + } + + + /* + * <function name="closedir"> + * <intro>close directory stream. + * <syntax>int closedir (DIR *dirp); + * + * <desc>Close directory stream opened by the `opendir' function. Close of + * directory stream invalidates the DIR structure as well as previously read + * dirent entry. + * + * <ret>The function typically returns 0 on success and -1 on failure but + * the function may be declared to return void on same systems. At least + * Borland C/C++ and some UNIX implementations use void as a return type. + * The dirent wrapper tries to define VOID_CLOSEDIR whenever closedir is + * known to return nothing. The very same definition is made by the GNU + * autoconf if you happen to use it. + * + * The global `errno' variable will set to EBADF in case of error. + * </function> + */ + static int + closedir (DIR *dirp) { + int retcode = 0; + + /* make sure that dirp points to legal structure */ + assert (dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return -1; + } + + /* free directory name and search handles */ + if (dirp->dirname != NULL) free (dirp->dirname); #if defined(DIRENT_WIN32_INTERFACE) - if (dirp->search_handle != INVALID_HANDLE_VALUE) { - if (FindClose (dirp->search_handle) == FALSE) { - /* Unknown error */ - retcode = -1; - errno = EBADF; - } - } -#endif - - /* clear dirp structure to make sure that it cannot be used anymore*/ - memset (dirp, 0, sizeof (*dirp)); + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose (dirp->search_handle) == FALSE) { + /* Unknown error */ + retcode = -1; + errno = EBADF; + } + } +#endif + + /* clear dirp structure to make sure that it cannot be used anymore*/ + memset (dirp, 0, sizeof (*dirp)); # if defined(DIRENT_WIN32_INTERFACE) - dirp->search_handle = INVALID_HANDLE_VALUE; + dirp->search_handle = INVALID_HANDLE_VALUE; # endif - free (dirp); - return retcode; -} - - -/* - * <function name="rewinddir"> - * <intro>rewind directory stream to the beginning - * <syntax>void rewinddir (DIR *dirp); - * - * <desc>Rewind directory stream to the beginning so that the next call of - * readdir() returns the very first directory entry again. However, note - * that next call of readdir() may not return the same directory entry as it - * did in first time. The directory stream may have been affected by newly - * created files. - * - * Almost every dirent implementation ensure that rewinddir will update - * the directory stream to reflect any changes made to the directory entries - * since the previous ``opendir'' or ``rewinddir'' call. Keep an eye on - * this if your program depends on the feature. I know at least one dirent - * implementation where you are required to close and re-open the stream to - * see the changes. - * - * <ret>Returns nothing. If something went wrong while rewinding, you will - * notice it later when you try to retrieve the first directory entry. - */ -static void -rewinddir (DIR *dirp) -{ - /* make sure that dirp is legal */ - assert (dirp != NULL); - if (dirp == NULL) { - errno = EBADF; - return; - } - assert (dirp->dirname != NULL); - - /* close previous stream */ + free (dirp); + return retcode; + } + + + /* + * <function name="rewinddir"> + * <intro>rewind directory stream to the beginning + * <syntax>void rewinddir (DIR *dirp); + * + * <desc>Rewind directory stream to the beginning so that the next call of + * readdir() returns the very first directory entry again. However, note + * that next call of readdir() may not return the same directory entry as it + * did in first time. The directory stream may have been affected by newly + * created files. + * + * Almost every dirent implementation ensure that rewinddir will update + * the directory stream to reflect any changes made to the directory entries + * since the previous ``opendir'' or ``rewinddir'' call. Keep an eye on + * this if your program depends on the feature. I know at least one dirent + * implementation where you are required to close and re-open the stream to + * see the changes. + * + * <ret>Returns nothing. If something went wrong while rewinding, you will + * notice it later when you try to retrieve the first directory entry. + */ + static void + rewinddir (DIR *dirp) { + /* make sure that dirp is legal */ + assert (dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return; + } + assert (dirp->dirname != NULL); + + /* close previous stream */ #if defined(DIRENT_WIN32_INTERFACE) - if (dirp->search_handle != INVALID_HANDLE_VALUE) { - if (FindClose (dirp->search_handle) == FALSE) { - /* Unknown error */ - errno = EBADF; - } - } + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose (dirp->search_handle) == FALSE) { + /* Unknown error */ + errno = EBADF; + } + } #endif - /* re-open previous stream */ - if (_initdir (dirp) == 0) { - /* initialization failed but we cannot deal with error. User will notice - * error later when she tries to retrieve first directory enty. */ - /*EMPTY*/; - } -} - - -/* - * Open native directory stream object and retrieve first file. - * Be sure to close previous stream before opening new one. - */ -static int -_initdir (DIR *dirp) -{ - assert (dirp != NULL); - assert (dirp->dirname != NULL); - dirp->dirent_filled = 0; + /* re-open previous stream */ + if (_initdir (dirp) == 0) { + /* initialization failed but we cannot deal with error. User will notice + * error later when she tries to retrieve first directory enty. */ + /*EMPTY*/; + } + } + + + /* + * Open native directory stream object and retrieve first file. + * Be sure to close previous stream before opening new one. + */ + static int + _initdir (DIR *dirp) { + assert (dirp != NULL); + assert (dirp->dirname != NULL); + dirp->dirent_filled = 0; # if defined(DIRENT_WIN32_INTERFACE) - /* Open stream and retrieve first file */ - dirp->search_handle = FindFirstFile (dirp->dirname, &dirp->current.data); - if (dirp->search_handle == INVALID_HANDLE_VALUE) { - /* something went wrong but we don't know what. GetLastError() could - * give us more information about the error, but then we should map - * the error code into errno. */ - errno = ENOENT; - return 0; - } + /* Open stream and retrieve first file */ + dirp->search_handle = FindFirstFile (dirp->dirname, &dirp->current.data); + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* something went wrong but we don't know what. GetLastError() could + * give us more information about the error, but then we should map + * the error code into errno. */ + errno = ENOENT; + return 0; + } # elif defined(DIRENT_MSDOS_INTERFACE) - if (_dos_findfirst (dirp->dirname, - _A_SUBDIR | _A_RDONLY | _A_ARCH | _A_SYSTEM | _A_HIDDEN, - &dirp->current.data) != 0) - { - /* _dos_findfirst and findfirst will set errno to ENOENT when no - * more entries could be retrieved. */ - return 0; - } + if (_dos_findfirst (dirp->dirname, + _A_SUBDIR | _A_RDONLY | _A_ARCH | _A_SYSTEM | _A_HIDDEN, + &dirp->current.data) != 0) { + /* _dos_findfirst and findfirst will set errno to ENOENT when no + * more entries could be retrieved. */ + return 0; + } # endif - /* initialize DIR and it's first entry */ - _setdirname (dirp); - dirp->dirent_filled = 1; - return 1; -} + /* initialize DIR and it's first entry */ + _setdirname (dirp); + dirp->dirent_filled = 1; + return 1; + } -/* - * Return implementation dependent name of the current directory entry. - */ -static const char * -_getdirname (const struct dirent *dp) -{ + /* + * Return implementation dependent name of the current directory entry. + */ + static const char * + _getdirname (const struct dirent *dp) { #if defined(DIRENT_WIN32_INTERFACE) - return dp->data.cFileName; - + return dp->data.cFileName; + #elif defined(DIRENT_USE_FFBLK) - return dp->data.ff_name; - + return dp->data.ff_name; + #else - return dp->data.name; -#endif -} + return dp->data.name; +#endif + } -/* - * Copy name of implementation dependent directory entry to the d_name field. - */ -static void -_setdirname (struct DIR *dirp) { - /* make sure that d_name is long enough */ - assert (strlen (_getdirname (&dirp->current)) <= NAME_MAX); - - strncpy (dirp->current.d_name, - _getdirname (&dirp->current), - NAME_MAX); - dirp->current.d_name[NAME_MAX] = '\0'; /*char d_name[NAME_MAX+1]*/ -} - + /* + * Copy name of implementation dependent directory entry to the d_name field. + */ + static void + _setdirname (struct DIR *dirp) { + /* make sure that d_name is long enough */ + assert (strlen (_getdirname (&dirp->current)) <= NAME_MAX); + + strncpy (dirp->current.d_name, + _getdirname (&dirp->current), + NAME_MAX); + dirp->current.d_name[NAME_MAX] = '\0'; /*char d_name[NAME_MAX+1]*/ + } + # ifdef __cplusplus } # endif diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index e25ece4..6073e26 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -12,9 +12,9 @@ namespace uscxml { #ifdef BUILD_AS_PLUGINS PLUMA_CONNECTOR -bool connect(pluma::Host& host){ - host.add( new V8DataModelProvider() ); - return true; +bool connect(pluma::Host& host) { + host.add( new V8DataModelProvider() ); + return true; } #endif @@ -23,306 +23,310 @@ V8DataModel::V8DataModel() { } DataModel* V8DataModel::create(Interpreter* interpreter) { - V8DataModel* dm = new V8DataModel(); - dm->_interpreter = interpreter; - v8::Locker locker; - v8::HandleScope scope; + V8DataModel* dm = new V8DataModel(); + dm->_interpreter = interpreter; + v8::Locker locker; + v8::HandleScope scope; - // see http://stackoverflow.com/questions/3171418/v8-functiontemplate-class-instance + // see http://stackoverflow.com/questions/3171418/v8-functiontemplate-class-instance // dm->_globalTemplate = v8::Persistent<v8::ObjectTemplate>(v8::ObjectTemplate::New()); // dm->_globalTemplate->Set(v8::String::New("In"), v8::FunctionTemplate::New(jsIn, v8::External::New(reinterpret_cast<void*>(this)))); - v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); - global->Set(v8::String::New("In"), v8::FunctionTemplate::New(jsIn, v8::External::New(reinterpret_cast<void*>(dm)))); - global->Set(v8::String::New("print"), v8::FunctionTemplate::New(jsPrint, v8::External::New(reinterpret_cast<void*>(dm)))); - global->Set(v8::String::New("document"), V8SCXMLDOM::getDocument(interpreter->getDocument())); - - dm->_contexts.push_back(v8::Context::New(NULL, global)); - dm->setName(interpreter->getName()); - dm->setSessionId(interpreter->getSessionId()); - dm->eval("_ioprocessors = {};"); - - return dm; + v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); + global->Set(v8::String::New("In"), v8::FunctionTemplate::New(jsIn, v8::External::New(reinterpret_cast<void*>(dm)))); + global->Set(v8::String::New("print"), v8::FunctionTemplate::New(jsPrint, v8::External::New(reinterpret_cast<void*>(dm)))); + global->Set(v8::String::New("document"), V8SCXMLDOM::getDocument(interpreter->getDocument())); + + dm->_contexts.push_back(v8::Context::New(NULL, global)); + dm->setName(interpreter->getName()); + dm->setSessionId(interpreter->getSessionId()); + dm->eval("_ioprocessors = {};"); + + return dm; +} + +void V8DataModel::registerIOProcessor(const std::string& name, IOProcessor* ioprocessor) { + assign("_ioprocessors['" + name + "']", ioprocessor->getDataModelVariables()); } void V8DataModel::setSessionId(const std::string& sessionId) { - _sessionId = sessionId; - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - v8::Handle<v8::Object> global = _contexts.front()->Global(); + _sessionId = sessionId; + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.front()); + v8::Handle<v8::Object> global = _contexts.front()->Global(); - global->Set(v8::String::New("_sessionid"), v8::String::New(sessionId.c_str())); + global->Set(v8::String::New("_sessionid"), v8::String::New(sessionId.c_str())); } void V8DataModel::setName(const std::string& name) { - _name = name; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - v8::Handle<v8::Object> global = _contexts.front()->Global(); - - global->Set(v8::String::New("_name"), v8::String::New(name.c_str())); + _name = name; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.front()); + v8::Handle<v8::Object> global = _contexts.front()->Global(); + + global->Set(v8::String::New("_name"), v8::String::New(name.c_str())); } V8DataModel::~V8DataModel() { - while(_contexts.size() > 0) { - _contexts.back().Dispose(); - _contexts.pop_back(); - } + while(_contexts.size() > 0) { + _contexts.back().Dispose(); + _contexts.pop_back(); + } } void V8DataModel::pushContext() { - _contexts.push_back(_contexts.back().New(_contexts.back())); + _contexts.push_back(_contexts.back().New(_contexts.back())); } void V8DataModel::popContext() { - if (_contexts.size() > 1) { - _contexts.back().Dispose(); - _contexts.pop_back(); - } + if (_contexts.size() > 1) { + _contexts.back().Dispose(); + _contexts.pop_back(); + } } void V8DataModel::initialize() { } void V8DataModel::setEvent(const Event& event) { - _event = event; - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - v8::Handle<v8::Object> global = _contexts.front()->Global(); - - // this is unfortunate - can't we store the template in the object? - if (_eventTemplate.IsEmpty()) { - v8::Handle<v8::ObjectTemplate> localEventTemplate = v8::ObjectTemplate::New(); - localEventTemplate->SetInternalFieldCount(1); // we only have a single C++ object - localEventTemplate->SetAccessor(v8::String::New("name"), V8DataModel::jsGetEventName); - localEventTemplate->SetAccessor(v8::String::New("type"), V8DataModel::jsGetEventType); - localEventTemplate->SetAccessor(v8::String::New("sendid"), V8DataModel::jsGetEventSendId); - localEventTemplate->SetAccessor(v8::String::New("origin"), V8DataModel::jsGetEventOrigin); - localEventTemplate->SetAccessor(v8::String::New("origintype"), V8DataModel::jsGetEventOriginType); - localEventTemplate->SetAccessor(v8::String::New("invokeid"), V8DataModel::jsGetEventInvokeId); - _eventTemplate = v8::Persistent<v8::ObjectTemplate>::New(localEventTemplate); - } - - assert(_eventTemplate->InternalFieldCount() == 1); - v8::Handle<v8::Object> eventJS = _eventTemplate->NewInstance(); - eventJS->SetInternalField(0, v8::External::New(&_event)); - - eventJS->Set(v8::String::New("data"), getDataAsValue(event)); // set data part of _event - global->Set(v8::String::New("_event"), eventJS); + _event = event; + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.front()); + v8::Handle<v8::Object> global = _contexts.front()->Global(); + + // this is unfortunate - can't we store the template in the object? + if (_eventTemplate.IsEmpty()) { + v8::Handle<v8::ObjectTemplate> localEventTemplate = v8::ObjectTemplate::New(); + localEventTemplate->SetInternalFieldCount(1); // we only have a single C++ object + localEventTemplate->SetAccessor(v8::String::New("name"), V8DataModel::jsGetEventName); + localEventTemplate->SetAccessor(v8::String::New("type"), V8DataModel::jsGetEventType); + localEventTemplate->SetAccessor(v8::String::New("sendid"), V8DataModel::jsGetEventSendId); + localEventTemplate->SetAccessor(v8::String::New("origin"), V8DataModel::jsGetEventOrigin); + localEventTemplate->SetAccessor(v8::String::New("origintype"), V8DataModel::jsGetEventOriginType); + localEventTemplate->SetAccessor(v8::String::New("invokeid"), V8DataModel::jsGetEventInvokeId); + _eventTemplate = v8::Persistent<v8::ObjectTemplate>::New(localEventTemplate); + } + + assert(_eventTemplate->InternalFieldCount() == 1); + v8::Handle<v8::Object> eventJS = _eventTemplate->NewInstance(); + eventJS->SetInternalField(0, v8::External::New(&_event)); + + eventJS->Set(v8::String::New("data"), getDataAsValue(event)); // set data part of _event + global->Set(v8::String::New("_event"), eventJS); } Data V8DataModel::getStringAsData(const std::string& content) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - v8::Handle<v8::Value> result = evalAsValue(content); - Data data = getValueAsData(result); - return data; + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.front()); + v8::Handle<v8::Value> result = evalAsValue(content); + Data data = getValueAsData(result); + return data; } Data V8DataModel::getValueAsData(const v8::Handle<v8::Value>& value) { - Data data; - if (false) { - } else if (value->IsArray()) { - v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value); - for (int i = 0; i < array->Length(); i++) { - data.array.push_back(getValueAsData(array->Get(i))); - } - } else if (value->IsBoolean()) { - data.atom = (value->ToBoolean()->Value() ? "true" : "false"); - } else if (value->IsBooleanObject()) { - LOG(ERROR) << "IsBooleanObject is unimplemented" << std::endl; - } else if (value->IsDate()) { - LOG(ERROR) << "IsDate is unimplemented" << std::endl; - } else if (value->IsExternal()) { - LOG(ERROR) << "IsExternal is unimplemented" << std::endl; - } else if (value->IsFalse()) { - LOG(ERROR) << "IsFalse is unimplemented" << std::endl; - } else if (value->IsFunction()) { - LOG(ERROR) << "IsFunction is unimplemented" << std::endl; - } else if (value->IsInt32()) { - int32_t prop = value->Int32Value(); - data.atom = toStr(prop); - } else if (value->IsNativeError()) { - LOG(ERROR) << "IsNativeError is unimplemented" << std::endl; - } else if (value->IsNull()) { - LOG(ERROR) << "IsNull is unimplemented" << std::endl; - } else if (value->IsNumber()) { - v8::String::AsciiValue prop(v8::Handle<v8::String>::Cast(v8::Handle<v8::Number>::Cast(value))); - data.atom = *prop; - } else if (value->IsNumberObject()) { - LOG(ERROR) << "IsNumberObject is unimplemented" << std::endl; - } else if (value->IsObject()) { - v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); - v8::Local<v8::Array> properties = object->GetPropertyNames(); - for (int i = 0; i < properties->Length(); i++) { - assert(properties->Get(i)->IsString()); - v8::String::AsciiValue key(v8::Handle<v8::String>::Cast(properties->Get(i))); - v8::Local<v8::Value> property = object->Get(properties->Get(i)); - data.compound[*key] = getValueAsData(property); - } - } else if (value->IsRegExp()) { - LOG(ERROR) << "IsRegExp is unimplemented" << std::endl; - } else if(value->IsString()) { - v8::String::AsciiValue property(v8::Handle<v8::String>::Cast(value)); - data.atom = *property; - } else if(value->IsStringObject()) { - LOG(ERROR) << "IsStringObject is unimplemented" << std::endl; - } else if(value->IsTrue()) { - LOG(ERROR) << "IsTrue is unimplemented" << std::endl; - } else if(value->IsUint32()) { - LOG(ERROR) << "IsUint32 is unimplemented" << std::endl; - } else if(value->IsUndefined()) { - LOG(ERROR) << "IsUndefined is unimplemented" << std::endl; - } - return data; + Data data; + if (false) { + } else if (value->IsArray()) { + v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value); + for (int i = 0; i < array->Length(); i++) { + data.array.push_back(getValueAsData(array->Get(i))); + } + } else if (value->IsBoolean()) { + data.atom = (value->ToBoolean()->Value() ? "true" : "false"); + } else if (value->IsBooleanObject()) { + LOG(ERROR) << "IsBooleanObject is unimplemented" << std::endl; + } else if (value->IsDate()) { + LOG(ERROR) << "IsDate is unimplemented" << std::endl; + } else if (value->IsExternal()) { + LOG(ERROR) << "IsExternal is unimplemented" << std::endl; + } else if (value->IsFalse()) { + LOG(ERROR) << "IsFalse is unimplemented" << std::endl; + } else if (value->IsFunction()) { + LOG(ERROR) << "IsFunction is unimplemented" << std::endl; + } else if (value->IsInt32()) { + int32_t prop = value->Int32Value(); + data.atom = toStr(prop); + } else if (value->IsNativeError()) { + LOG(ERROR) << "IsNativeError is unimplemented" << std::endl; + } else if (value->IsNull()) { + LOG(ERROR) << "IsNull is unimplemented" << std::endl; + } else if (value->IsNumber()) { + v8::String::AsciiValue prop(v8::Handle<v8::String>::Cast(v8::Handle<v8::Number>::Cast(value))); + data.atom = *prop; + } else if (value->IsNumberObject()) { + LOG(ERROR) << "IsNumberObject is unimplemented" << std::endl; + } else if (value->IsObject()) { + v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); + v8::Local<v8::Array> properties = object->GetPropertyNames(); + for (int i = 0; i < properties->Length(); i++) { + assert(properties->Get(i)->IsString()); + v8::String::AsciiValue key(v8::Handle<v8::String>::Cast(properties->Get(i))); + v8::Local<v8::Value> property = object->Get(properties->Get(i)); + data.compound[*key] = getValueAsData(property); + } + } else if (value->IsRegExp()) { + LOG(ERROR) << "IsRegExp is unimplemented" << std::endl; + } else if(value->IsString()) { + v8::String::AsciiValue property(v8::Handle<v8::String>::Cast(value)); + data.atom = *property; + } else if(value->IsStringObject()) { + LOG(ERROR) << "IsStringObject is unimplemented" << std::endl; + } else if(value->IsTrue()) { + LOG(ERROR) << "IsTrue is unimplemented" << std::endl; + } else if(value->IsUint32()) { + LOG(ERROR) << "IsUint32 is unimplemented" << std::endl; + } else if(value->IsUndefined()) { + LOG(ERROR) << "IsUndefined is unimplemented" << std::endl; + } + return data; } - + v8::Handle<v8::Value> V8DataModel::getDataAsValue(const Data& data) { - if (data.compound.size() > 0) { - v8::Handle<v8::Object> value = v8::Object::New(); - std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin(); - while(compoundIter != data.compound.end()) { - value->Set(v8::String::New(compoundIter->first.c_str()), getDataAsValue(compoundIter->second)); - compoundIter++; - } - return value; - } - if (data.array.size() > 0) { - v8::Handle<v8::Object> value = v8::Array::New(); - std::list<Data>::const_iterator arrayIter = data.array.begin(); - uint32_t index = 0; - while(arrayIter != data.array.end()) { - value->Set(index++, getDataAsValue(*arrayIter)); - arrayIter++; - } - return value; - } - if (data.type == Data::VERBATIM) { - return v8::String::New(data.atom.c_str()); - } else { - return evalAsValue(data.atom); - } + if (data.compound.size() > 0) { + v8::Handle<v8::Object> value = v8::Object::New(); + std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin(); + while(compoundIter != data.compound.end()) { + value->Set(v8::String::New(compoundIter->first.c_str()), getDataAsValue(compoundIter->second)); + compoundIter++; + } + return value; + } + if (data.array.size() > 0) { + v8::Handle<v8::Object> value = v8::Array::New(); + std::list<Data>::const_iterator arrayIter = data.array.begin(); + uint32_t index = 0; + while(arrayIter != data.array.end()) { + value->Set(index++, getDataAsValue(*arrayIter)); + arrayIter++; + } + return value; + } + if (data.type == Data::VERBATIM) { + return v8::String::New(data.atom.c_str()); + } else { + return evalAsValue(data.atom); + } } v8::Handle<v8::Value> V8DataModel::jsPrint(const v8::Arguments& args) { - if (args.Length() > 0) { - v8::String::AsciiValue printMsg(args[0]->ToString()); - std::cout << *printMsg; - } - return v8::Undefined(); + if (args.Length() > 0) { + v8::String::AsciiValue printMsg(args[0]->ToString()); + std::cout << *printMsg; + } + return v8::Undefined(); } - + v8::Handle<v8::Value> V8DataModel::jsIn(const v8::Arguments& args) { - V8DataModel* INSTANCE = static_cast<V8DataModel*>(v8::External::Unwrap(args.Data())); - for (unsigned int i = 0; i < args.Length(); i++) { - if (args[i]->IsString()) { - std::string stateName(*v8::String::AsciiValue(args[i]->ToString())); - if (Interpreter::isMember(INSTANCE->_interpreter->getState(stateName), INSTANCE->_interpreter->getConfiguration())) { - continue; - } - } - return v8::Boolean::New(false); - } - return v8::Boolean::New(true); + V8DataModel* INSTANCE = static_cast<V8DataModel*>(v8::External::Unwrap(args.Data())); + for (unsigned int i = 0; i < args.Length(); i++) { + if (args[i]->IsString()) { + std::string stateName(*v8::String::AsciiValue(args[i]->ToString())); + if (Interpreter::isMember(INSTANCE->_interpreter->getState(stateName), INSTANCE->_interpreter->getConfiguration())) { + continue; + } + } + return v8::Boolean::New(false); + } + return v8::Boolean::New(true); } v8::Handle<v8::Value> V8DataModel::jsGetEventName(v8::Local<v8::String> property, - const v8::AccessorInfo &info) { - Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); - return v8::String::New(event->name.c_str()); + const v8::AccessorInfo &info) { + Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); + return v8::String::New(event->name.c_str()); } v8::Handle<v8::Value> V8DataModel::jsGetEventType(v8::Local<v8::String> property, - const v8::AccessorInfo &info) { - Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); - switch (event->type) { - case Event::PLATFORM: - return v8::String::New("platform"); - break; - case Event::INTERNAL: - return v8::String::New("internal"); - break; - case Event::EXTERNAL: - return v8::String::New("external"); - break; - default: - return v8::String::New(""); - break; - } + const v8::AccessorInfo &info) { + Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); + switch (event->type) { + case Event::PLATFORM: + return v8::String::New("platform"); + break; + case Event::INTERNAL: + return v8::String::New("internal"); + break; + case Event::EXTERNAL: + return v8::String::New("external"); + break; + default: + return v8::String::New(""); + break; + } } v8::Handle<v8::Value> V8DataModel::jsGetEventSendId(v8::Local<v8::String> property, - const v8::AccessorInfo &info) { - Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); - return v8::String::New(event->sendid.c_str()); - + const v8::AccessorInfo &info) { + Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); + return v8::String::New(event->sendid.c_str()); + } v8::Handle<v8::Value> V8DataModel::jsGetEventOrigin(v8::Local<v8::String> property, - const v8::AccessorInfo &info) { - Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); - return v8::String::New(event->origin.c_str()); + const v8::AccessorInfo &info) { + Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); + return v8::String::New(event->origin.c_str()); } v8::Handle<v8::Value> V8DataModel::jsGetEventOriginType(v8::Local<v8::String> property, - const v8::AccessorInfo &info) { - Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); - return v8::String::New(event->origintype.c_str()); + const v8::AccessorInfo &info) { + Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); + return v8::String::New(event->origintype.c_str()); } v8::Handle<v8::Value> V8DataModel::jsGetEventInvokeId(v8::Local<v8::String> property, - const v8::AccessorInfo &info) { - Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); - return v8::String::New(event->invokeid.c_str()); + const v8::AccessorInfo &info) { + Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); + return v8::String::New(event->invokeid.c_str()); } bool V8DataModel::validate(const std::string& location, const std::string& schema) { - return true; + return true; } uint32_t V8DataModel::getLength(const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - v8::Handle<v8::Array> result = evalAsValue(expr).As<v8::Array>(); - return result->Length(); + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.back()); + v8::Handle<v8::Array> result = evalAsValue(expr).As<v8::Array>(); + return result->Length(); } void V8DataModel::eval(const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - evalAsValue(expr); + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.back()); + evalAsValue(expr); } bool V8DataModel::evalAsBool(const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - v8::Handle<v8::Value> result = evalAsValue(expr); - return(result->ToBoolean()->BooleanValue()); + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.back()); + v8::Handle<v8::Value> result = evalAsValue(expr); + return(result->ToBoolean()->BooleanValue()); } std::string V8DataModel::evalAsString(const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - v8::Handle<v8::Value> result = evalAsValue(expr); - v8::String::AsciiValue data(result->ToString()); - return std::string(*data); + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.back()); + v8::Handle<v8::Value> result = evalAsValue(expr); + v8::String::AsciiValue data(result->ToString()); + return std::string(*data); } void V8DataModel::assign(const std::string& location, const Data& data) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - - std::stringstream ssJSON; - ssJSON << data; - assign(location, ssJSON.str()); + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.front()); + + std::stringstream ssJSON; + ssJSON << data; + assign(location, ssJSON.str()); // v8::Handle<v8::Object> variable = evalAsValue(location).As<v8::Object>(); // assert(!variable.IsEmpty()); // if (data.compound.size() > 0) { @@ -348,62 +352,62 @@ void V8DataModel::assign(const std::string& location, const Data& data) { } void V8DataModel::assign(const std::string& location, const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - evalAsValue((location + " = " + expr).c_str()); + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.back()); + evalAsValue((location + " = " + expr).c_str()); } v8::Handle<v8::Value> V8DataModel::evalAsValue(const std::string& expr) { - v8::TryCatch tryCatch; - v8::Handle<v8::String> source = v8::String::New(expr.c_str()); - v8::Handle<v8::Script> script = v8::Script::Compile(source); - - v8::Handle<v8::Value> result; - if (!script.IsEmpty()) - result = script->Run(); - - if (script.IsEmpty() || result.IsEmpty()) { - // throw an exception - assert(tryCatch.HasCaught()); - Event exceptionEvent; - exceptionEvent.name = "error.execution"; - - std::string exceptionString(*v8::String::AsciiValue(tryCatch.Exception())); - exceptionEvent.compound["exception"] = Data(exceptionString, Data::VERBATIM);; - - v8::Handle<v8::Message> message = tryCatch.Message(); - if (!message.IsEmpty()) { - std::string filename(*v8::String::AsciiValue(message->GetScriptResourceName())); - exceptionEvent.compound["filename"] = Data(filename, Data::VERBATIM); - - std::string sourceLine(*v8::String::AsciiValue(message->GetSourceLine())); - exceptionEvent.compound["sourceline"] = Data(sourceLine, Data::VERBATIM); - - std::stringstream ssLineNumber; - int lineNumber = message->GetLineNumber(); - ssLineNumber << lineNumber; - exceptionEvent.compound["linenumber"] = Data(ssLineNumber.str()); - - int startColumn = message->GetStartColumn(); - int endColumn = message->GetEndColumn(); - std::stringstream ssUnderline; - for (int i = 0; i < startColumn; i++) - ssUnderline << " "; - for (int i = startColumn; i < endColumn; i++) - ssUnderline << "^"; - exceptionEvent.compound["sourcemark"] = Data(ssUnderline.str(), Data::VERBATIM); - - std::string stackTrace(*v8::String::AsciiValue(tryCatch.StackTrace())); - exceptionEvent.compound["stacktrace"] = Data(stackTrace, Data::VERBATIM); - - } - - _interpreter->receiveInternal(exceptionEvent); - throw(exceptionEvent); - } - - return result; + v8::TryCatch tryCatch; + v8::Handle<v8::String> source = v8::String::New(expr.c_str()); + v8::Handle<v8::Script> script = v8::Script::Compile(source); + + v8::Handle<v8::Value> result; + if (!script.IsEmpty()) + result = script->Run(); + + if (script.IsEmpty() || result.IsEmpty()) { + // throw an exception + assert(tryCatch.HasCaught()); + Event exceptionEvent; + exceptionEvent.name = "error.execution"; + + std::string exceptionString(*v8::String::AsciiValue(tryCatch.Exception())); + exceptionEvent.compound["exception"] = Data(exceptionString, Data::VERBATIM);; + + v8::Handle<v8::Message> message = tryCatch.Message(); + if (!message.IsEmpty()) { + std::string filename(*v8::String::AsciiValue(message->GetScriptResourceName())); + exceptionEvent.compound["filename"] = Data(filename, Data::VERBATIM); + + std::string sourceLine(*v8::String::AsciiValue(message->GetSourceLine())); + exceptionEvent.compound["sourceline"] = Data(sourceLine, Data::VERBATIM); + + std::stringstream ssLineNumber; + int lineNumber = message->GetLineNumber(); + ssLineNumber << lineNumber; + exceptionEvent.compound["linenumber"] = Data(ssLineNumber.str()); + + int startColumn = message->GetStartColumn(); + int endColumn = message->GetEndColumn(); + std::stringstream ssUnderline; + for (int i = 0; i < startColumn; i++) + ssUnderline << " "; + for (int i = startColumn; i < endColumn; i++) + ssUnderline << "^"; + exceptionEvent.compound["sourcemark"] = Data(ssUnderline.str(), Data::VERBATIM); + + std::string stackTrace(*v8::String::AsciiValue(tryCatch.StackTrace())); + exceptionEvent.compound["stacktrace"] = Data(stackTrace, Data::VERBATIM); + + } + + _interpreter->receiveInternal(exceptionEvent); + throw(exceptionEvent); + } + + return result; } }
\ No newline at end of file diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h index 994ed18..deee58c 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h @@ -10,76 +10,78 @@ #endif namespace uscxml { - class Event; - class Data; - class V8SCXMLDOM; +class Event; +class Data; +class V8SCXMLDOM; } namespace uscxml { class V8DataModel : public DataModel { public: - V8DataModel(); - virtual ~V8DataModel(); - virtual DataModel* create(Interpreter* interpreter); - - virtual std::set<std::string> getNames() { + V8DataModel(); + virtual ~V8DataModel(); + virtual DataModel* create(Interpreter* interpreter); + + virtual std::set<std::string> getNames() { std::set<std::string> names; names.insert("ecmascript"); return names; } - virtual void initialize(); - virtual void setSessionId(const std::string& sessionId); - virtual void setName(const std::string& name); - virtual void setEvent(const Event& event); + virtual void initialize(); + virtual void setSessionId(const std::string& sessionId); + virtual void setName(const std::string& name); + virtual void setEvent(const Event& event); + + virtual void registerIOProcessor(const std::string& name, IOProcessor* ioprocessor); - virtual bool validate(const std::string& location, const std::string& schema); + virtual bool validate(const std::string& location, const std::string& schema); - virtual uint32_t getLength(const std::string& expr); - virtual void pushContext(); - virtual void popContext(); + virtual uint32_t getLength(const std::string& expr); + virtual void pushContext(); + virtual void popContext(); - virtual void eval(const std::string& expr); - virtual void assign(const std::string& location, const std::string& expr); - virtual void assign(const std::string& location, const Data& data); + virtual void eval(const std::string& expr); + virtual void assign(const std::string& location, const std::string& expr); + virtual void assign(const std::string& location, const Data& data); - virtual Data getStringAsData(const std::string& content); - virtual Data getValueAsData(const v8::Handle<v8::Value>& value); - - virtual std::string evalAsString(const std::string& expr); - virtual bool evalAsBool(const std::string& expr); + virtual Data getStringAsData(const std::string& content); + virtual Data getValueAsData(const v8::Handle<v8::Value>& value); - static v8::Handle<v8::Value> jsGetEventName(v8::Local<v8::String> property, - const v8::AccessorInfo &info); - static v8::Handle<v8::Value> jsGetEventType(v8::Local<v8::String> property, - const v8::AccessorInfo &info); - static v8::Handle<v8::Value> jsGetEventSendId(v8::Local<v8::String> property, - const v8::AccessorInfo &info); - static v8::Handle<v8::Value> jsGetEventOrigin(v8::Local<v8::String> property, - const v8::AccessorInfo &info); - static v8::Handle<v8::Value> jsGetEventOriginType(v8::Local<v8::String> property, - const v8::AccessorInfo &info); - static v8::Handle<v8::Value> jsGetEventInvokeId(v8::Local<v8::String> property, - const v8::AccessorInfo &info); + virtual std::string evalAsString(const std::string& expr); + virtual bool evalAsBool(const std::string& expr); - static v8::Handle<v8::Value> jsIn(const v8::Arguments& args); - static v8::Handle<v8::Value> jsPrint(const v8::Arguments& args); + static v8::Handle<v8::Value> jsGetEventName(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventType(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventSendId(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventOrigin(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventOriginType(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventInvokeId(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + + static v8::Handle<v8::Value> jsIn(const v8::Arguments& args); + static v8::Handle<v8::Value> jsPrint(const v8::Arguments& args); protected: - std::list<v8::Persistent<v8::Context> > _contexts; - Interpreter* _interpreter; + std::list<v8::Persistent<v8::Context> > _contexts; + Interpreter* _interpreter; std::string _sessionId; std::string _name; - - Event _event; - v8::Persistent<v8::ObjectTemplate> _globalTemplate; - v8::Persistent<v8::ObjectTemplate> _eventTemplate; - v8::Handle<v8::Value> evalAsValue(const std::string& expr); - virtual v8::Handle<v8::Value> getDataAsValue(const Data& data); + Event _event; + v8::Persistent<v8::ObjectTemplate> _globalTemplate; + v8::Persistent<v8::ObjectTemplate> _eventTemplate; + + v8::Handle<v8::Value> evalAsValue(const std::string& expr); + virtual v8::Handle<v8::Value> getDataAsValue(const Data& data); }; diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp index 6452330..585bdd7 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp @@ -14,206 +14,206 @@ assert(args[0]->type1()); \ assert(args[1]->type2()); namespace uscxml { - - using namespace Arabica::DOM; - using namespace Arabica::XPath; - - V8SCXMLDOM::V8SCXMLDOM() { + +using namespace Arabica::DOM; +using namespace Arabica::XPath; + +V8SCXMLDOM::V8SCXMLDOM() { +} + +v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getDocument(Arabica::DOM::Document<std::string>& document) { + v8::Handle<v8::ObjectTemplate> documentTmpl = v8::ObjectTemplate::New(); + documentTmpl->Set(v8::String::New("createElement"), v8::FunctionTemplate::New(jsDocumentCreateElement, v8::External::New(reinterpret_cast<void*>(&document)))); + documentTmpl->Set(v8::String::New("evaluate"), v8::FunctionTemplate::New(jsDocumentEvaluate, v8::External::New(reinterpret_cast<void*>(&document)))); + return documentTmpl; +} + +v8::Handle<v8::Value> V8SCXMLDOM::jsDocumentCreateElement(const v8::Arguments& args) { + assert(!args.Data().IsEmpty()); + assert(args.Data()->IsExternal()); + + ASSERT_ARGS1(args, IsString) + + Document<std::string>* document = static_cast<Document<std::string>*>(v8::External::Unwrap(args.Data())); + v8::Persistent<v8::Object> elementJS = v8::Persistent<v8::Object>::New(getElementTmpl()->NewInstance()); + + v8::String::AsciiValue tagName(args[0]); + Element<std::string>* element = new Element<std::string>(document->createElement(*tagName)); + + elementJS->SetInternalField(0, v8::External::New(element)); + elementJS.MakeWeak(NULL, jsElementDestructor); + return elementJS; +} + +v8::Handle<v8::Value> V8SCXMLDOM::jsDocumentEvaluate(const v8::Arguments& args) { + assert(!args.Data().IsEmpty()); + assert(args.Data()->IsExternal()); + + assert(args.Length() > 0); + assert(args[0]->IsString()); + + + Document<std::string>* document = static_cast<Document<std::string>*>(v8::External::Unwrap(args.Data())); + Node<std::string> context; + if (args.Length() > 1) { + assert(args[1]->ToObject()->InternalFieldCount() == 1); + context = *static_cast<Node<std::string>*>(v8::Local<v8::External>::Cast(args[1]->ToObject()->GetInternalField(0))->Value()); + } else { + context = *document; } + v8::String::AsciiValue xpathExpr(args[0]); + XPath<std::string> xpath; + XPathValue<std::string>* xpathValue = new XPathValue<std::string>(xpath.evaluate(*xpathExpr, context)); - v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getDocument(Arabica::DOM::Document<std::string>& document) { - v8::Handle<v8::ObjectTemplate> documentTmpl = v8::ObjectTemplate::New(); - documentTmpl->Set(v8::String::New("createElement"), v8::FunctionTemplate::New(jsDocumentCreateElement, v8::External::New(reinterpret_cast<void*>(&document)))); - documentTmpl->Set(v8::String::New("evaluate"), v8::FunctionTemplate::New(jsDocumentEvaluate, v8::External::New(reinterpret_cast<void*>(&document)))); - return documentTmpl; - } - - v8::Handle<v8::Value> V8SCXMLDOM::jsDocumentCreateElement(const v8::Arguments& args) { - assert(!args.Data().IsEmpty()); - assert(args.Data()->IsExternal()); - - ASSERT_ARGS1(args, IsString) - - Document<std::string>* document = static_cast<Document<std::string>*>(v8::External::Unwrap(args.Data())); - v8::Persistent<v8::Object> elementJS = v8::Persistent<v8::Object>::New(getElementTmpl()->NewInstance()); - - v8::String::AsciiValue tagName(args[0]); - Element<std::string>* element = new Element<std::string>(document->createElement(*tagName)); - - elementJS->SetInternalField(0, v8::External::New(element)); - elementJS.MakeWeak(NULL, jsElementDestructor); - return elementJS; - } - - v8::Handle<v8::Value> V8SCXMLDOM::jsDocumentEvaluate(const v8::Arguments& args) { - assert(!args.Data().IsEmpty()); - assert(args.Data()->IsExternal()); - - assert(args.Length() > 0); - assert(args[0]->IsString()); - - - Document<std::string>* document = static_cast<Document<std::string>*>(v8::External::Unwrap(args.Data())); - Node<std::string> context; - if (args.Length() > 1) { - assert(args[1]->ToObject()->InternalFieldCount() == 1); - context = *static_cast<Node<std::string>*>(v8::Local<v8::External>::Cast(args[1]->ToObject()->GetInternalField(0))->Value()); - } else { - context = *document; - } - v8::String::AsciiValue xpathExpr(args[0]); - XPath<std::string> xpath; - XPathValue<std::string>* xpathValue = new XPathValue<std::string>(xpath.evaluate(*xpathExpr, context)); - - v8::Persistent<v8::Object> xpathValueJS = v8::Persistent<v8::Object>::New(getXPathValueTmpl()->NewInstance()); - xpathValueJS->SetInternalField(0, v8::External::New(xpathValue)); - xpathValueJS.MakeWeak(NULL, jsXPathValueDestructor); - return xpathValueJS; - } - - v8::Handle<v8::Value> V8SCXMLDOM::jsElementTagName(v8::Local<v8::String> property, const v8::AccessorInfo &info) { - Element<std::string>* element = static_cast<Element<std::string>*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); - return v8::String::New(element->getTagName().c_str()); - } - - v8::Handle<v8::Value> V8SCXMLDOM::jsElementGetAttribute(const v8::Arguments& args) { - assert(!args.Data().IsEmpty()); - assert(args.Data()->IsExternal()); - - ASSERT_ARGS1(args, IsString); - - Element<std::string>* element = static_cast<Element<std::string>*>(v8::External::Unwrap(args.Data())); - - v8::String::AsciiValue attribute(args[0]); - if (element->hasAttribute(*attribute)) { - return v8::String::New(element->getAttribute(*attribute).c_str()); - } - return v8::String::New(""); - } - - v8::Handle<v8::Value> V8SCXMLDOM::jsElementSetAttribute(const v8::Arguments& args) { - v8::Local<v8::Object> self = args.Holder(); - assert(self->InternalFieldCount() == 1); - - ASSERT_ARGS2(args, IsString, IsString); - - v8::String::AsciiValue attribute(args[0]); - v8::String::AsciiValue value(args[1]); - - Element<std::string>* element = static_cast<Element<std::string>*>(v8::External::Unwrap(self->GetInternalField(0))); - element->setAttribute(*attribute, *value); - return v8::Undefined(); - } - - v8::Handle<v8::Value> V8SCXMLDOM::jsXPathValueAsNodeSet(const v8::Arguments& args) { - v8::Local<v8::Object> self = args.Holder(); - assert(self->InternalFieldCount() == 1); - XPathValue<std::string>* xPathValue = static_cast<XPathValue<std::string>*>(v8::External::Unwrap(self->GetInternalField(0))); - - v8::Persistent<v8::Object> nodeSetJS = v8::Persistent<v8::Object>::New(getNodeSetTmpl()->NewInstance()); - nodeSetJS->SetInternalField(0, v8::External::New(new NodeSet<std::string>(xPathValue->asNodeSet()))); - nodeSetJS.MakeWeak(NULL, jsNodeSetDestructor); - return nodeSetJS; - - } - - void V8SCXMLDOM::jsNodeSetDestructor(v8::Persistent<v8::Value> object, void* data) { - NodeSet<std::string>* nodeSet = static_cast<NodeSet<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value()); - delete nodeSet; - } - - void V8SCXMLDOM::jsNodeDestructor(v8::Persistent<v8::Value> object, void* data) { - Node<std::string>* node = static_cast<Node<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value()); - delete node; - } - - void V8SCXMLDOM::jsXPathValueDestructor(v8::Persistent<v8::Value> object, void* data) { - XPathValue<std::string>* xPathValue = static_cast<XPathValue<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value()); - delete xPathValue; - } - - void V8SCXMLDOM::jsElementDestructor(v8::Persistent<v8::Value> object, void* data) { - Element<std::string>* element = static_cast<Element<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value()); - delete element; - } - - v8::Handle<v8::Value> V8SCXMLDOM::jsNodeSetGetIndex(uint32_t index, const v8::AccessorInfo &info) { - v8::Local<v8::Object> self = info.Holder(); - assert(self->InternalFieldCount() == 1); - NodeSet<std::string>* nodeSet = static_cast<NodeSet<std::string>*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); - - if (nodeSet->size() >= index) { - Node<std::string>* node = new Node<std::string>((*nodeSet)[index]); - v8::Persistent<v8::Object> nodeJS = v8::Persistent<v8::Object>::New(getNodeTmpl()->NewInstance()); - nodeJS->SetInternalField(0, v8::External::New(node)); - nodeJS.MakeWeak(NULL, jsNodeDestructor); - return nodeJS; - } - return v8::Undefined(); - } - - v8::Handle<v8::Value> V8SCXMLDOM::jsNodeSetLength(const v8::Arguments& args) { - v8::Local<v8::Object> self = args.Holder(); - assert(self->InternalFieldCount() == 1); - NodeSet<std::string>* nodeSet = static_cast<NodeSet<std::string>*>(v8::External::Unwrap(self->GetInternalField(0))); - return v8::Integer::New(nodeSet->size()); - } - - v8::Handle<v8::Value> V8SCXMLDOM::jsNodeAppendChild(const v8::Arguments& args) { - v8::Local<v8::Object> self = args.Holder(); - assert(self->InternalFieldCount() == 1); - Node<std::string>* node = static_cast<Node<std::string>*>(v8::External::Unwrap(self->GetInternalField(0))); - - assert(args.Length() == 1); - assert(args[0]->IsObject()); - - Node<std::string>* childToAppend = static_cast<Node<std::string>*>(v8::External::Unwrap(args[0]->ToObject()->GetInternalField(0))); - node->appendChild(*childToAppend); - - return v8::Undefined(); - } - - v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::xPathValueTmpl; - v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getXPathValueTmpl() { - if (xPathValueTmpl.IsEmpty()) { - xPathValueTmpl = v8::ObjectTemplate::New(); - xPathValueTmpl->SetInternalFieldCount(1); - xPathValueTmpl->Set(v8::String::New("asNodeSet"), v8::FunctionTemplate::New(jsXPathValueAsNodeSet)); - } - return xPathValueTmpl; - } - - v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::nodeSetTmpl; - v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getNodeSetTmpl() { - if (nodeSetTmpl.IsEmpty()) { - nodeSetTmpl = v8::ObjectTemplate::New(); - nodeSetTmpl->SetInternalFieldCount(1); - nodeSetTmpl->SetIndexedPropertyHandler(jsNodeSetGetIndex); - nodeSetTmpl->Set(v8::String::New("length"), v8::FunctionTemplate::New(jsNodeSetLength)); - } - return nodeSetTmpl; - } - - v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::nodeTmpl; - v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getNodeTmpl() { - if (nodeTmpl.IsEmpty()) { - nodeTmpl = v8::ObjectTemplate::New(); - nodeTmpl->SetInternalFieldCount(1); - nodeTmpl->Set(v8::String::New("appendChild"), v8::FunctionTemplate::New(jsNodeAppendChild)); - } - return nodeTmpl; - } - - v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::elementTmpl; - v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getElementTmpl() { - if (elementTmpl.IsEmpty()) { - elementTmpl = v8::ObjectTemplate::New(); - elementTmpl->SetAccessor(v8::String::New("tagName"), V8SCXMLDOM::jsElementTagName); - elementTmpl->Set(v8::String::New("getAttribute"), v8::FunctionTemplate::New(jsElementGetAttribute)); - elementTmpl->Set(v8::String::New("setAttribute"), v8::FunctionTemplate::New(jsElementSetAttribute)); - elementTmpl->SetInternalFieldCount(1); - } - return elementTmpl; - } + v8::Persistent<v8::Object> xpathValueJS = v8::Persistent<v8::Object>::New(getXPathValueTmpl()->NewInstance()); + xpathValueJS->SetInternalField(0, v8::External::New(xpathValue)); + xpathValueJS.MakeWeak(NULL, jsXPathValueDestructor); + return xpathValueJS; +} + +v8::Handle<v8::Value> V8SCXMLDOM::jsElementTagName(v8::Local<v8::String> property, const v8::AccessorInfo &info) { + Element<std::string>* element = static_cast<Element<std::string>*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); + return v8::String::New(element->getTagName().c_str()); +} + +v8::Handle<v8::Value> V8SCXMLDOM::jsElementGetAttribute(const v8::Arguments& args) { + assert(!args.Data().IsEmpty()); + assert(args.Data()->IsExternal()); + + ASSERT_ARGS1(args, IsString); + + Element<std::string>* element = static_cast<Element<std::string>*>(v8::External::Unwrap(args.Data())); + + v8::String::AsciiValue attribute(args[0]); + if (element->hasAttribute(*attribute)) { + return v8::String::New(element->getAttribute(*attribute).c_str()); + } + return v8::String::New(""); +} + +v8::Handle<v8::Value> V8SCXMLDOM::jsElementSetAttribute(const v8::Arguments& args) { + v8::Local<v8::Object> self = args.Holder(); + assert(self->InternalFieldCount() == 1); + + ASSERT_ARGS2(args, IsString, IsString); + + v8::String::AsciiValue attribute(args[0]); + v8::String::AsciiValue value(args[1]); + + Element<std::string>* element = static_cast<Element<std::string>*>(v8::External::Unwrap(self->GetInternalField(0))); + element->setAttribute(*attribute, *value); + return v8::Undefined(); +} + +v8::Handle<v8::Value> V8SCXMLDOM::jsXPathValueAsNodeSet(const v8::Arguments& args) { + v8::Local<v8::Object> self = args.Holder(); + assert(self->InternalFieldCount() == 1); + XPathValue<std::string>* xPathValue = static_cast<XPathValue<std::string>*>(v8::External::Unwrap(self->GetInternalField(0))); + + v8::Persistent<v8::Object> nodeSetJS = v8::Persistent<v8::Object>::New(getNodeSetTmpl()->NewInstance()); + nodeSetJS->SetInternalField(0, v8::External::New(new NodeSet<std::string>(xPathValue->asNodeSet()))); + nodeSetJS.MakeWeak(NULL, jsNodeSetDestructor); + return nodeSetJS; + +} + +void V8SCXMLDOM::jsNodeSetDestructor(v8::Persistent<v8::Value> object, void* data) { + NodeSet<std::string>* nodeSet = static_cast<NodeSet<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value()); + delete nodeSet; +} + +void V8SCXMLDOM::jsNodeDestructor(v8::Persistent<v8::Value> object, void* data) { + Node<std::string>* node = static_cast<Node<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value()); + delete node; +} + +void V8SCXMLDOM::jsXPathValueDestructor(v8::Persistent<v8::Value> object, void* data) { + XPathValue<std::string>* xPathValue = static_cast<XPathValue<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value()); + delete xPathValue; +} + +void V8SCXMLDOM::jsElementDestructor(v8::Persistent<v8::Value> object, void* data) { + Element<std::string>* element = static_cast<Element<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value()); + delete element; +} + +v8::Handle<v8::Value> V8SCXMLDOM::jsNodeSetGetIndex(uint32_t index, const v8::AccessorInfo &info) { + v8::Local<v8::Object> self = info.Holder(); + assert(self->InternalFieldCount() == 1); + NodeSet<std::string>* nodeSet = static_cast<NodeSet<std::string>*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); + + if (nodeSet->size() >= index) { + Node<std::string>* node = new Node<std::string>((*nodeSet)[index]); + v8::Persistent<v8::Object> nodeJS = v8::Persistent<v8::Object>::New(getNodeTmpl()->NewInstance()); + nodeJS->SetInternalField(0, v8::External::New(node)); + nodeJS.MakeWeak(NULL, jsNodeDestructor); + return nodeJS; + } + return v8::Undefined(); +} + +v8::Handle<v8::Value> V8SCXMLDOM::jsNodeSetLength(const v8::Arguments& args) { + v8::Local<v8::Object> self = args.Holder(); + assert(self->InternalFieldCount() == 1); + NodeSet<std::string>* nodeSet = static_cast<NodeSet<std::string>*>(v8::External::Unwrap(self->GetInternalField(0))); + return v8::Integer::New(nodeSet->size()); +} + +v8::Handle<v8::Value> V8SCXMLDOM::jsNodeAppendChild(const v8::Arguments& args) { + v8::Local<v8::Object> self = args.Holder(); + assert(self->InternalFieldCount() == 1); + Node<std::string>* node = static_cast<Node<std::string>*>(v8::External::Unwrap(self->GetInternalField(0))); + + assert(args.Length() == 1); + assert(args[0]->IsObject()); + + Node<std::string>* childToAppend = static_cast<Node<std::string>*>(v8::External::Unwrap(args[0]->ToObject()->GetInternalField(0))); + node->appendChild(*childToAppend); + + return v8::Undefined(); +} + +v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::xPathValueTmpl; +v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getXPathValueTmpl() { + if (xPathValueTmpl.IsEmpty()) { + xPathValueTmpl = v8::ObjectTemplate::New(); + xPathValueTmpl->SetInternalFieldCount(1); + xPathValueTmpl->Set(v8::String::New("asNodeSet"), v8::FunctionTemplate::New(jsXPathValueAsNodeSet)); + } + return xPathValueTmpl; +} + +v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::nodeSetTmpl; +v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getNodeSetTmpl() { + if (nodeSetTmpl.IsEmpty()) { + nodeSetTmpl = v8::ObjectTemplate::New(); + nodeSetTmpl->SetInternalFieldCount(1); + nodeSetTmpl->SetIndexedPropertyHandler(jsNodeSetGetIndex); + nodeSetTmpl->Set(v8::String::New("length"), v8::FunctionTemplate::New(jsNodeSetLength)); + } + return nodeSetTmpl; +} + +v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::nodeTmpl; +v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getNodeTmpl() { + if (nodeTmpl.IsEmpty()) { + nodeTmpl = v8::ObjectTemplate::New(); + nodeTmpl->SetInternalFieldCount(1); + nodeTmpl->Set(v8::String::New("appendChild"), v8::FunctionTemplate::New(jsNodeAppendChild)); + } + return nodeTmpl; +} + +v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::elementTmpl; +v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getElementTmpl() { + if (elementTmpl.IsEmpty()) { + elementTmpl = v8::ObjectTemplate::New(); + elementTmpl->SetAccessor(v8::String::New("tagName"), V8SCXMLDOM::jsElementTagName); + elementTmpl->Set(v8::String::New("getAttribute"), v8::FunctionTemplate::New(jsElementGetAttribute)); + elementTmpl->Set(v8::String::New("setAttribute"), v8::FunctionTemplate::New(jsElementSetAttribute)); + elementTmpl->SetInternalFieldCount(1); + } + return elementTmpl; +} }
\ No newline at end of file diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h index c513e48..36c6b15 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h @@ -14,46 +14,46 @@ class V8SCXMLDOM { public: V8SCXMLDOM(); virtual ~V8SCXMLDOM() {}; - - static v8::Handle<v8::ObjectTemplate> getDocument(Arabica::DOM::Document<std::string>& document); - static v8::Handle<v8::Value> jsDocumentCreateElement(const v8::Arguments& args); - static v8::Handle<v8::Value> jsDocumentEvaluate(const v8::Arguments& args); - - static v8::Handle<v8::Value> jsElementTagName(v8::Local<v8::String> property, const v8::AccessorInfo &info); - static v8::Handle<v8::Value> jsElementGetAttribute(const v8::Arguments& args); - static v8::Handle<v8::Value> jsElementSetAttribute(const v8::Arguments& args); - static void jsElementDestructor(v8::Persistent<v8::Value> object, void* data); - - static v8::Handle<v8::Value> jsXPathValueAsNodeSet(const v8::Arguments& args); - static void jsXPathValueDestructor(v8::Persistent<v8::Value> object, void* data); - - static v8::Handle<v8::Value> jsNodeSetGetIndex(uint32_t index, const v8::AccessorInfo &info); - static v8::Handle<v8::Value> jsNodeSetLength(const v8::Arguments& args); - static void jsNodeSetDestructor(v8::Persistent<v8::Value> object, void* data); - - static v8::Handle<v8::Value> jsNodeAppendChild(const v8::Arguments& args); - static void jsNodeDestructor(v8::Persistent<v8::Value> object, void* data); - - static v8::Handle<v8::ObjectTemplate> getXPathValueTmpl(); - static v8::Handle<v8::ObjectTemplate> getNodeSetTmpl(); - static v8::Handle<v8::ObjectTemplate> getNodeTmpl(); - static v8::Handle<v8::ObjectTemplate> getElementTmpl(); - - static v8::Handle<v8::ObjectTemplate> xPathValueTmpl; - static v8::Handle<v8::ObjectTemplate> nodeSetTmpl; - static v8::Handle<v8::ObjectTemplate> nodeTmpl; - static v8::Handle<v8::ObjectTemplate> elementTmpl; + + static v8::Handle<v8::ObjectTemplate> getDocument(Arabica::DOM::Document<std::string>& document); + static v8::Handle<v8::Value> jsDocumentCreateElement(const v8::Arguments& args); + static v8::Handle<v8::Value> jsDocumentEvaluate(const v8::Arguments& args); + + static v8::Handle<v8::Value> jsElementTagName(v8::Local<v8::String> property, const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsElementGetAttribute(const v8::Arguments& args); + static v8::Handle<v8::Value> jsElementSetAttribute(const v8::Arguments& args); + static void jsElementDestructor(v8::Persistent<v8::Value> object, void* data); + + static v8::Handle<v8::Value> jsXPathValueAsNodeSet(const v8::Arguments& args); + static void jsXPathValueDestructor(v8::Persistent<v8::Value> object, void* data); + + static v8::Handle<v8::Value> jsNodeSetGetIndex(uint32_t index, const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsNodeSetLength(const v8::Arguments& args); + static void jsNodeSetDestructor(v8::Persistent<v8::Value> object, void* data); + + static v8::Handle<v8::Value> jsNodeAppendChild(const v8::Arguments& args); + static void jsNodeDestructor(v8::Persistent<v8::Value> object, void* data); + + static v8::Handle<v8::ObjectTemplate> getXPathValueTmpl(); + static v8::Handle<v8::ObjectTemplate> getNodeSetTmpl(); + static v8::Handle<v8::ObjectTemplate> getNodeTmpl(); + static v8::Handle<v8::ObjectTemplate> getElementTmpl(); + + static v8::Handle<v8::ObjectTemplate> xPathValueTmpl; + static v8::Handle<v8::ObjectTemplate> nodeSetTmpl; + static v8::Handle<v8::ObjectTemplate> nodeTmpl; + static v8::Handle<v8::ObjectTemplate> elementTmpl; }; class V8Node { }; - + class V8DOMDocument { - V8DOMDocument(); - virtual ~V8DOMDocument(); - - v8::Handle<v8::Array> jsChildNodes(); + V8DOMDocument(); + virtual ~V8DOMDocument(); + + v8::Handle<v8::Array> jsChildNodes(); }; } diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp new file mode 100644 index 0000000..77f0b66 --- /dev/null +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp @@ -0,0 +1,103 @@ +#include "uscxml/Common.h" +#include "SWIDataModel.h" +#include "uscxml/Message.h" +#include <glog/logging.h> + +#ifdef BUILD_AS_PLUGINS +#include <Pluma/Connector.hpp> +#endif + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host) { + host.add( new SWIDataModelProvider() ); + return true; +} +#endif + +SWIDataModel::SWIDataModel() { +} + +DataModel* SWIDataModel::create(Interpreter* interpreter) { + SWIDataModel* dm = new SWIDataModel(); + dm->_interpreter = interpreter; + const char* swiPath = SWI_LIBRARY_PATH; + dm->_plEngine = new PlEngine((char*)swiPath); + return dm; +} + +void SWIDataModel::registerIOProcessor(const std::string& name, IOProcessor* ioprocessor) { + std::cout << "SWIDataModel::registerIOProcessor" << std::endl; +} + +void SWIDataModel::setSessionId(const std::string& sessionId) { + std::cout << "SWIDataModel::setSessionId" << std::endl; + _sessionId = sessionId; +} + +void SWIDataModel::setName(const std::string& name) { + std::cout << "SWIDataModel::setName" << std::endl; + _name = name; +} + +SWIDataModel::~SWIDataModel() { +} + +void SWIDataModel::pushContext() { + std::cout << "SWIDataModel::pushContext" << std::endl; +} + +void SWIDataModel::popContext() { + std::cout << "SWIDataModel::popContext" << std::endl; +} + +void SWIDataModel::initialize() { + std::cout << "SWIDataModel::initialize" << std::endl; +} + +void SWIDataModel::setEvent(const Event& event) { + std::cout << "SWIDataModel::setEvent" << std::endl; + _event = event; +} + +Data SWIDataModel::getStringAsData(const std::string& content) { + std::cout << "SWIDataModel::getStringAsData" << std::endl; + Data data; + return data; +} + +bool SWIDataModel::validate(const std::string& location, const std::string& schema) { + std::cout << "SWIDataModel::validate" << std::endl; + return true; +} + +uint32_t SWIDataModel::getLength(const std::string& expr) { + std::cout << "SWIDataModel::getLength" << std::endl; + return 0; +} + +void SWIDataModel::eval(const std::string& expr) { + std::cout << "SWIDataModel::eval" << std::endl; +} + +bool SWIDataModel::evalAsBool(const std::string& expr) { + std::cout << "SWIDataModel::evalAsBool" << std::endl; + return true; +} + +std::string SWIDataModel::evalAsString(const std::string& expr) { + std::cout << "SWIDataModel::evalAsString" << std::endl; + return std::string(""); +} + +void SWIDataModel::assign(const std::string& location, const Data& data) { + std::cout << "SWIDataModel::assign" << std::endl; +} + +void SWIDataModel::assign(const std::string& location, const std::string& expr) { + std::cout << "SWIDataModel::assign" << std::endl; +} + +}
\ No newline at end of file diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h new file mode 100644 index 0000000..16dee3c --- /dev/null +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h @@ -0,0 +1,66 @@ +#ifndef SWIDATAMODEL_H_KN8TWG0V +#define SWIDATAMODEL_H_KN8TWG0V + +#include "uscxml/Interpreter.h" +#include <list> +#include <SWI-cpp.h> + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class SWIDataModel : public DataModel { +public: + SWIDataModel(); + virtual ~SWIDataModel(); + virtual DataModel* create(Interpreter* interpreter); + + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("prolog"); + return names; + } + + virtual void initialize(); + virtual void setSessionId(const std::string& sessionId); + virtual void setName(const std::string& name); + virtual void setEvent(const Event& event); + + virtual void registerIOProcessor(const std::string& name, IOProcessor* ioprocessor); + + virtual bool validate(const std::string& location, const std::string& schema); + + virtual uint32_t getLength(const std::string& expr); + virtual void pushContext(); + virtual void popContext(); + + virtual void eval(const std::string& expr); + virtual void assign(const std::string& location, const std::string& expr); + virtual void assign(const std::string& location, const Data& data); + + virtual Data getStringAsData(const std::string& content); + + virtual std::string evalAsString(const std::string& expr); + virtual bool evalAsBool(const std::string& expr); + + +protected: + Interpreter* _interpreter; + + std::string _sessionId; + std::string _name; + + Event _event; + PlEngine* _plEngine; + +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(SWIDataModel, DataModel); +#endif + +} + +#endif /* end of include guard: SWIDATAMODEL_H_KN8TWG0V */ diff --git a/src/uscxml/plugins/invoker/modality/MMIComponent.cpp b/src/uscxml/plugins/invoker/modality/MMIComponent.cpp index 0655806..170f4bc 100644 --- a/src/uscxml/plugins/invoker/modality/MMIComponent.cpp +++ b/src/uscxml/plugins/invoker/modality/MMIComponent.cpp @@ -2,41 +2,41 @@ #include "uscxml/Interpreter.h" namespace uscxml { - + MMIComponent::MMIComponent() { } - + MMIComponent::~MMIComponent() { }; - + Invoker* MMIComponent::create(Interpreter* interpreter) { - MMIComponent* invoker = new MMIComponent(); - invoker->_interpreter = interpreter; - return invoker; + MMIComponent* invoker = new MMIComponent(); + invoker->_interpreter = interpreter; + return invoker; } Data MMIComponent::getDataModelVariables() { - Data data; - return data; + Data data; + return data; } void MMIComponent::send(SendRequest& req) { - + } void MMIComponent::cancel(const std::string sendId) { - assert(false); + assert(false); } void MMIComponent::sendToParent(SendRequest& req) { - req.invokeid = _invokeId; - assert(false); + req.invokeid = _invokeId; + assert(false); } void MMIComponent::invoke(InvokeRequest& req) { - _invokeId = req.invokeid; - + _invokeId = req.invokeid; + } }
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/modality/MMIComponent.h b/src/uscxml/plugins/invoker/modality/MMIComponent.h index a83775f..96d796b 100644 --- a/src/uscxml/plugins/invoker/modality/MMIComponent.h +++ b/src/uscxml/plugins/invoker/modality/MMIComponent.h @@ -9,27 +9,27 @@ class Interpreter; class MMIComponent : public Invoker { public: - - enum State { - PAUSED, - RUNNING, - IDLE, - TERMINATED + + enum State { + PAUSED, + RUNNING, + IDLE, + TERMINATED }; MMIComponent(); - virtual ~MMIComponent(); - virtual Invoker* create(Interpreter* interpreter); - - virtual Data getDataModelVariables(); - virtual void send(SendRequest& req); - virtual void cancel(const std::string sendId); - virtual void invoke(InvokeRequest& req); - virtual void sendToParent(SendRequest& req); + virtual ~MMIComponent(); + virtual Invoker* create(Interpreter* interpreter); + + virtual Data getDataModelVariables(); + virtual void send(SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(InvokeRequest& req); + virtual void sendToParent(SendRequest& req); protected: - std::string _invokeId; - Interpreter* _interpreter; + std::string _invokeId; + Interpreter* _interpreter; State _state; }; @@ -39,31 +39,31 @@ protected: class MMICoreMessage { public: - std::string source; - std::string target; - std::string data; - std::string requestId; + std::string source; + std::string target; + std::string data; + std::string requestId; }; class MMICtxMessage : public MMICoreMessage { public: - std::string context; + std::string context; }; class MMIStartMessage : public MMICtxMessage { public: - std::string content; - std::string contentURL; + std::string content; + std::string contentURL; }; class MMISimpleStatusMessage : public MMICtxMessage { public: - std::string status; + std::string status; }; class MMIStatusMessage : public MMISimpleStatusMessage { public: - std::string statusInfo; + std::string statusInfo; }; /** Concrete MMI messages */ @@ -86,7 +86,7 @@ class MMIPrepareRequest : public MMIStartMessage {}; /***/ class MMIExtensionNotification : public MMICtxMessage { - std::string name; + std::string name; }; /***/ diff --git a/src/uscxml/plugins/invoker/modality/UmundoComponent.cpp b/src/uscxml/plugins/invoker/modality/UmundoComponent.cpp index 22dd279..10f23d4 100644 --- a/src/uscxml/plugins/invoker/modality/UmundoComponent.cpp +++ b/src/uscxml/plugins/invoker/modality/UmundoComponent.cpp @@ -2,48 +2,48 @@ #include "uscxml/Interpreter.h" namespace uscxml { - -UmundoComponent::UmundoComponent() { + +UmundoComponent::UmundoComponent() { } - + UmundoComponent::~UmundoComponent() { - delete _invokedInterpreter; + delete _invokedInterpreter; }; - + Invoker* UmundoComponent::create(Interpreter* interpreter) { - UmundoComponent* invoker = new UmundoComponent(); - invoker->_parentInterpreter = interpreter; - return invoker; + UmundoComponent* invoker = new UmundoComponent(); + invoker->_parentInterpreter = interpreter; + return invoker; } Data UmundoComponent::getDataModelVariables() { - Data data; - return data; + Data data; + return data; } void UmundoComponent::send(SendRequest& req) { - assert(false); + assert(false); } void UmundoComponent::cancel(const std::string sendId) { - assert(false); + assert(false); } void UmundoComponent::sendToParent(SendRequest& req) { - req.invokeid = _invokeId; - _parentInterpreter->receive(req); + req.invokeid = _invokeId; + _parentInterpreter->receive(req); } void UmundoComponent::invoke(InvokeRequest& req) { - _invokeId = req.invokeid; - _invokedInterpreter = Interpreter::fromURI(req.src); - DataModel* dataModel = _invokedInterpreter->getDataModel(); - if (dataModel != NULL) { - - } - _invokedInterpreter->setInvoker(this); - _invokedInterpreter->start(); + _invokeId = req.invokeid; + _invokedInterpreter = Interpreter::fromURI(req.src); + DataModel* dataModel = _invokedInterpreter->getDataModel(); + if (dataModel != NULL) { + + } + _invokedInterpreter->setInvoker(this); + _invokedInterpreter->start(); } }
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/modality/UmundoComponent.h b/src/uscxml/plugins/invoker/modality/UmundoComponent.h index f2c76c4..69b3961 100644 --- a/src/uscxml/plugins/invoker/modality/UmundoComponent.h +++ b/src/uscxml/plugins/invoker/modality/UmundoComponent.h @@ -6,25 +6,25 @@ namespace uscxml { class Interpreter; - + class UmundoComponent : public MMIComponent { public: UmundoComponent(); - virtual ~UmundoComponent(); - virtual Invoker* create(Interpreter* interpreter); - - virtual Data getDataModelVariables(); - virtual void send(SendRequest& req); - virtual void cancel(const std::string sendId); - virtual void invoke(InvokeRequest& req); - virtual void sendToParent(SendRequest& req); + virtual ~UmundoComponent(); + virtual Invoker* create(Interpreter* interpreter); + + virtual Data getDataModelVariables(); + virtual void send(SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(InvokeRequest& req); + virtual void sendToParent(SendRequest& req); protected: - std::string _invokeId; - Interpreter* _invokedInterpreter; - Interpreter* _parentInterpreter; + std::string _invokeId; + Interpreter* _invokedInterpreter; + Interpreter* _parentInterpreter; }; - + } #endif /* end of include guard: UMUNDOCOMPONENT_H_VMW54W1R */ diff --git a/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp index 13091ae..acc5c4b 100644 --- a/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp +++ b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp @@ -14,184 +14,184 @@ namespace uscxml { #ifdef BUILD_AS_PLUGINS PLUMA_CONNECTOR -bool connect(pluma::Host& host){ - host.add( new SpatialAudioProvider() ); - return true; +bool connect(pluma::Host& host) { + host.add( new SpatialAudioProvider() ); + return true; } #endif SpatialAudio::SpatialAudio() { - _audioDevOpen = false; - _audioDev = NULL; - _audioDevIndex = -1; - _pos = new float[3]; - _pos[0] = _pos[1] = _pos[2] = 0.0; - _listener = new float[3]; - _listener[0] = _listener[1] = _listener[2] = 0.0; + _audioDevOpen = false; + _audioDev = NULL; + _audioDevIndex = -1; + _pos = new float[3]; + _pos[0] = _pos[1] = _pos[2] = 0.0; + _listener = new float[3]; + _listener[0] = _listener[1] = _listener[2] = 0.0; } - + SpatialAudio::~SpatialAudio() { }; - + Invoker* SpatialAudio::create(Interpreter* interpreter) { - SpatialAudio* invoker = new SpatialAudio(); - invoker->_interpreter = interpreter; - return invoker; + SpatialAudio* invoker = new SpatialAudio(); + invoker->_interpreter = interpreter; + return invoker; } Data SpatialAudio::getDataModelVariables() { - Data data; + Data data; // data.compound["foo"] = Data("32"); - return data; + return data; } void SpatialAudio::send(SendRequest& req) { - if (!_audioDevOpen) { - _audioDev = miles_audio_device_open(_audioDevIndex, 0, 22050, 2, 1, 0); - if (_audioDev != NULL) { - _audioDevOpen = true; - float rolloffFactor = 0.2; - miles_audio_device_control(_audioDev, MILES_AUDIO_DEVICE_CTRL_SET_ROLLOFF_FACTOR, &rolloffFactor); - } - } - - if (boost::iequals(req.name, "play")) { - if (_audioDevOpen) { - getPosFromParams(req.params, _pos); + if (!_audioDevOpen) { + _audioDev = miles_audio_device_open(_audioDevIndex, 0, 22050, 2, 1, 0); + if (_audioDev != NULL) { + _audioDevOpen = true; + float rolloffFactor = 0.2; + miles_audio_device_control(_audioDev, MILES_AUDIO_DEVICE_CTRL_SET_ROLLOFF_FACTOR, &rolloffFactor); + } + } + + if (boost::iequals(req.name, "play")) { + if (_audioDevOpen) { + getPosFromParams(req.params, _pos); // std::cout << "Source: "; // for (int i = 0; i < 3; i++) { // std::cout << _pos[i] << " "; // } // std::cout << std::endl; - - miles_audio_device_control(_audioDev, MILES_AUDIO_DEVICE_CTRL_SET_POSITION, _pos); - - char* buffer = (char*)malloc(_audioDev->chunk_size); - // skip wav header - _dataStream.seekg(44); - - while(_dataStream.readsome(buffer, _audioDev->chunk_size) != 0) { - miles_audio_device_write(_audioDev, buffer, _audioDev->chunk_size); - } - free(buffer); - } - } else if (boost::iequals(req.name, "move.listener")) { - if (_audioDevOpen) { - getPosFromParams(req.params, _listener); - - std::cout << "Listener: "; - for (int i = 0; i < 3; i++) { - std::cout << _listener[i] << " "; - } - std::cout << std::endl; - - miles_audio_device_control(_audioDev, MILES_AUDIO_DEVICE_CTRL_SET_LISTENER_POS, _listener); - - } - } + + miles_audio_device_control(_audioDev, MILES_AUDIO_DEVICE_CTRL_SET_POSITION, _pos); + + char* buffer = (char*)malloc(_audioDev->chunk_size); + // skip wav header + _dataStream.seekg(44); + + while(_dataStream.readsome(buffer, _audioDev->chunk_size) != 0) { + miles_audio_device_write(_audioDev, buffer, _audioDev->chunk_size); + } + free(buffer); + } + } else if (boost::iequals(req.name, "move.listener")) { + if (_audioDevOpen) { + getPosFromParams(req.params, _listener); + + std::cout << "Listener: "; + for (int i = 0; i < 3; i++) { + std::cout << _listener[i] << " "; + } + std::cout << std::endl; + + miles_audio_device_control(_audioDev, MILES_AUDIO_DEVICE_CTRL_SET_LISTENER_POS, _listener); + + } + } } void SpatialAudio::cancel(const std::string sendId) { - assert(false); + assert(false); } void SpatialAudio::sendToParent(SendRequest& req) { - req.invokeid = _invokeId; - assert(false); + req.invokeid = _invokeId; + assert(false); } void SpatialAudio::invoke(InvokeRequest& req) { - _invokeId = req.invokeid; - - if (req.src.length() > 0) { - Arabica::io::URI url(req.src); - if (!_interpreter->makeAbsolute(url)) { - LOG(ERROR) << "Source attribute for audio invoker has relative URI " << req.src << " with no base URI set for interpreter"; - return; - } - - URL scriptUrl(url.as_string()); - _dataStream << scriptUrl; - } - - getPosFromParams(req.params, _pos); - - struct miles_audio_device_description *devices; - int ndevs; - + _invokeId = req.invokeid; + + if (req.src.length() > 0) { + Arabica::io::URI url(req.src); + if (!_interpreter->makeAbsolute(url)) { + LOG(ERROR) << "Source attribute for audio invoker has relative URI " << req.src << " with no base URI set for interpreter"; + return; + } + + URL scriptUrl(url.as_string()); + _dataStream << scriptUrl; + } + + getPosFromParams(req.params, _pos); + + struct miles_audio_device_description *devices; + int ndevs; + ndevs = miles_audio_device_get_supported_devices(&devices); - - for (int i = 0; i < ndevs; i++) { + + for (int i = 0; i < ndevs; i++) { if ((devices[i].capabilities & MILES_AUDIO_DEVICE_CAPABILITY_SPATIAL) && - (devices[i].capabilities & MILES_AUDIO_DEVICE_CAPABILITY_OUTPUT)) { - _audioDevIndex = i; - break; - } - } + (devices[i].capabilities & MILES_AUDIO_DEVICE_CAPABILITY_OUTPUT)) { + _audioDevIndex = i; + break; + } + } } - void SpatialAudio::getPosFromParams(std::map<std::string, std::list<std::string> >& params, float* position) { - // vector explicitly given - try { - if (params.find("x") != params.end()) - position[0] = boost::lexical_cast<float>(params["x"].front()); - if (params.find("y") != params.end()) - position[1] = boost::lexical_cast<float>(params["y"].front()); - if (params.find("z") != params.end()) - position[2] = boost::lexical_cast<float>(params["z"].front()); - } catch (boost::bad_lexical_cast& e) { - LOG(ERROR) << "Cannot interpret x, y or z as float value in params: " << e.what(); - } - - try { - // right is an alias for x - if (params.find("right") != params.end()) - position[0] = boost::lexical_cast<float>(params["right"].front()); - // height is an alias for y - if (params.find("height") != params.end()) - position[1] = boost::lexical_cast<float>(params["height"].front()); - // front is an alias for z - if (params.find("front") != params.end()) - position[2] = boost::lexical_cast<float>(params["front"].front()); - } catch (boost::bad_lexical_cast& e) { - LOG(ERROR) << "Cannot interpret right, height or front as float value in params: " << e.what(); - } - - // do we have a position on a circle? - try { - if (params.find("circle") != params.end()) { - float rad = posToRadian(params["circle"].front()); - position[0] = cosf(rad); - position[2] = -1 * sinf(rad); // z axis increases to front - } - } catch (boost::bad_lexical_cast& e) { - LOG(ERROR) << "Cannot interpret circle as float value in params: " << e.what(); - } +void SpatialAudio::getPosFromParams(std::map<std::string, std::list<std::string> >& params, float* position) { + // vector explicitly given + try { + if (params.find("x") != params.end()) + position[0] = boost::lexical_cast<float>(params["x"].front()); + if (params.find("y") != params.end()) + position[1] = boost::lexical_cast<float>(params["y"].front()); + if (params.find("z") != params.end()) + position[2] = boost::lexical_cast<float>(params["z"].front()); + } catch (boost::bad_lexical_cast& e) { + LOG(ERROR) << "Cannot interpret x, y or z as float value in params: " << e.what(); + } + + try { + // right is an alias for x + if (params.find("right") != params.end()) + position[0] = boost::lexical_cast<float>(params["right"].front()); + // height is an alias for y + if (params.find("height") != params.end()) + position[1] = boost::lexical_cast<float>(params["height"].front()); + // front is an alias for z + if (params.find("front") != params.end()) + position[2] = boost::lexical_cast<float>(params["front"].front()); + } catch (boost::bad_lexical_cast& e) { + LOG(ERROR) << "Cannot interpret right, height or front as float value in params: " << e.what(); + } + + // do we have a position on a circle? + try { + if (params.find("circle") != params.end()) { + float rad = posToRadian(params["circle"].front()); + position[0] = cosf(rad); + position[2] = -1 * sinf(rad); // z axis increases to front + } + } catch (boost::bad_lexical_cast& e) { + LOG(ERROR) << "Cannot interpret circle as float value in params: " << e.what(); + } // std::cout << _pos[0] << ":" << _pos[1] << ":" << _pos[2] << std::endl; } - + float SpatialAudio::posToRadian(std::string& position) { - boost::trim(position); - float rad = 0; - - if (position.size() > 3 && boost::iequals("deg", position.substr(position.length() - 3, 3))) { - rad = boost::lexical_cast<float>(position.substr(0, position.size() - 3)); - rad = fmodf(rad, 360); // into range [0-360] - rad /= 180; // into range [0-2] - rad *= M_PI; // into range [0-2PI] - rad -= M_PI_2; // 0 to top; - rad *= -1; // make clockwise - rad += 2 * M_PI; // make positive - } else if (position.size() > 3 && boost::iequals("rad", position.substr(position.length() - 3, 3))) { - rad = boost::lexical_cast<float>(position.substr(0, position.size() - 3)); - rad = fmodf(rad, M_PI * 2); // into range [0-2*PI] - } else { - LOG(ERROR) << "Cannot make sense of position value " << position << ": does not end in 'deg', 'rad'"; - } - return rad; + boost::trim(position); + float rad = 0; + + if (position.size() > 3 && boost::iequals("deg", position.substr(position.length() - 3, 3))) { + rad = boost::lexical_cast<float>(position.substr(0, position.size() - 3)); + rad = fmodf(rad, 360); // into range [0-360] + rad /= 180; // into range [0-2] + rad *= M_PI; // into range [0-2PI] + rad -= M_PI_2; // 0 to top; + rad *= -1; // make clockwise + rad += 2 * M_PI; // make positive + } else if (position.size() > 3 && boost::iequals("rad", position.substr(position.length() - 3, 3))) { + rad = boost::lexical_cast<float>(position.substr(0, position.size() - 3)); + rad = fmodf(rad, M_PI * 2); // into range [0-2*PI] + } else { + LOG(ERROR) << "Cannot make sense of position value " << position << ": does not end in 'deg', 'rad'"; + } + return rad; } - + }
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h index bbbf478..7632f52 100644 --- a/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h +++ b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h @@ -14,14 +14,14 @@ extern "C" { namespace uscxml { class Interpreter; - + class SpatialAudio : public MMIComponent { public: SpatialAudio(); - virtual ~SpatialAudio(); - virtual Invoker* create(Interpreter* interpreter); - - virtual std::set<std::string> getNames() { + virtual ~SpatialAudio(); + virtual Invoker* create(Interpreter* interpreter); + + virtual std::set<std::string> getNames() { std::set<std::string> names; names.insert("spatial-audio"); names.insert("audio"); @@ -30,29 +30,29 @@ public: return names; } - virtual Data getDataModelVariables(); - virtual void send(SendRequest& req); - virtual void cancel(const std::string sendId); - virtual void invoke(InvokeRequest& req); - virtual void sendToParent(SendRequest& req); + virtual Data getDataModelVariables(); + virtual void send(SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(InvokeRequest& req); + virtual void sendToParent(SendRequest& req); - void getPosFromParams(std::map<std::string, std::list<std::string> >& params, float* position); - static float posToRadian(std::string& position); + void getPosFromParams(std::map<std::string, std::list<std::string> >& params, float* position); + static float posToRadian(std::string& position); protected: - std::string _invokeId; - Interpreter* _invokedInterpreter; - - std::stringstream _dataStream; - - float* _pos; - float* _listener; - bool _audioDevOpen; - int _audioDevIndex; - struct miles_audio_device* _audioDev; + std::string _invokeId; + Interpreter* _invokedInterpreter; + + std::stringstream _dataStream; + + float* _pos; + float* _listener; + bool _audioDevOpen; + int _audioDevIndex; + struct miles_audio_device* _audioDev; }; - + } #endif /* end of include guard: SPATIALAUDIO_H_EH11SAQC */ diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp index 0e617b9..b4ee3eb 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp @@ -1,6 +1,5 @@ -#include "uscxml/Common.h" #include "USCXMLInvoker.h" -#include "uscxml/Interpreter.h" +#include <glog/logging.h> #ifdef BUILD_AS_PLUGINS #include <Pluma/Connector.hpp> @@ -10,53 +9,53 @@ namespace uscxml { #ifdef BUILD_AS_PLUGINS PLUMA_CONNECTOR -bool connect(pluma::Host& host){ - host.add( new USCXMLInvokerProvider() ); - return true; +bool connect(pluma::Host& host) { + host.add( new USCXMLInvokerProvider() ); + return true; } #endif -USCXMLInvoker::USCXMLInvoker() { +USCXMLInvoker::USCXMLInvoker() { } - + USCXMLInvoker::~USCXMLInvoker() { - delete _invokedInterpreter; + delete _invokedInterpreter; }; - + Invoker* USCXMLInvoker::create(Interpreter* interpreter) { - USCXMLInvoker* invoker = new USCXMLInvoker(); - invoker->_parentInterpreter = interpreter; - return invoker; + USCXMLInvoker* invoker = new USCXMLInvoker(); + invoker->_parentInterpreter = interpreter; + return invoker; } Data USCXMLInvoker::getDataModelVariables() { - Data data; - return data; + Data data; + return data; } void USCXMLInvoker::send(SendRequest& req) { - assert(false); + assert(false); } void USCXMLInvoker::cancel(const std::string sendId) { - assert(false); + assert(false); } void USCXMLInvoker::sendToParent(SendRequest& req) { - req.invokeid = _invokeId; - _parentInterpreter->receive(req); + req.invokeid = _invokeId; + _parentInterpreter->receive(req); } void USCXMLInvoker::invoke(InvokeRequest& req) { - _invokeId = req.invokeid; - _invokedInterpreter = Interpreter::fromURI(req.src); - DataModel* dataModel = _invokedInterpreter->getDataModel(); - if (dataModel != NULL) { - - } - _invokedInterpreter->setInvoker(this); - _invokedInterpreter->start(); + _invokeId = req.invokeid; + _invokedInterpreter = Interpreter::fromURI(req.src); + DataModel* dataModel = _invokedInterpreter->getDataModel(); + if (dataModel != NULL) { + + } + _invokedInterpreter->setInvoker(this); + _invokedInterpreter->start(); } }
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h index 9068a24..907df41 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h @@ -1,7 +1,7 @@ #ifndef USCXMLINVOKER_H_OQFA21IO #define USCXMLINVOKER_H_OQFA21IO -#include "uscxml/Factory.h" +#include <uscxml/Interpreter.h> #ifdef BUILD_AS_PLUGINS #include "uscxml/plugins/Plugins.h" @@ -10,13 +10,13 @@ namespace uscxml { class Interpreter; - + class USCXMLInvoker : public Invoker { public: USCXMLInvoker(); - virtual ~USCXMLInvoker(); - virtual Invoker* create(Interpreter* interpreter); - virtual std::set<std::string> getNames() { + virtual ~USCXMLInvoker(); + virtual Invoker* create(Interpreter* interpreter); + virtual std::set<std::string> getNames() { std::set<std::string> names; names.insert("uscxml"); names.insert("http://www.w3.org/TR/scxml"); @@ -24,16 +24,16 @@ public: return names; } - virtual Data getDataModelVariables(); - virtual void send(SendRequest& req); - virtual void cancel(const std::string sendId); - virtual void invoke(InvokeRequest& req); - virtual void sendToParent(SendRequest& req); + virtual Data getDataModelVariables(); + virtual void send(SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(InvokeRequest& req); + virtual void sendToParent(SendRequest& req); protected: - std::string _invokeId; - Interpreter* _invokedInterpreter; - Interpreter* _parentInterpreter; + std::string _invokeId; + Interpreter* _invokedInterpreter; + Interpreter* _parentInterpreter; }; #ifdef BUILD_AS_PLUGINS diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp index 68ffe5a..ee6c903 100644 --- a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp +++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp @@ -1,7 +1,4 @@ -#include "uscxml/config.h" -#include "uscxml/Common.h" #include "UmundoInvoker.h" -#include "uscxml/Interpreter.h" #include <glog/logging.h> #ifdef BUILD_AS_PLUGINS @@ -12,9 +9,9 @@ namespace uscxml { #ifdef BUILD_AS_PLUGINS PLUMA_CONNECTOR -bool connect(pluma::Host& host){ - host.add( new UmundoInvokerProvider() ); - return true; +bool connect(pluma::Host& host) { + host.add( new UmundoInvokerProvider() ); + return true; } #endif @@ -22,213 +19,215 @@ UmundoInvoker::UmundoInvoker() { } UmundoInvoker::~UmundoInvoker() { - _node.removeSubscriber(_sub); - _node.removePublisher(_pub); + _node.removeSubscriber(_sub); + _node.removePublisher(_pub); }; Invoker* UmundoInvoker::create(Interpreter* interpreter) { - UmundoInvoker* invoker = new UmundoInvoker(); - invoker->_interpreter = interpreter; - return invoker; + UmundoInvoker* invoker = new UmundoInvoker(); + invoker->_interpreter = interpreter; + return invoker; } Data UmundoInvoker::getDataModelVariables() { - Data data; - return data; + Data data; + return data; } void UmundoInvoker::send(SendRequest& req) { - umundo::Message* msg = new umundo::Message(); - - if (req.name.length() > 0) { - msg->putMeta("event", req.name); - } else { - msg->putMeta("event", "umundo"); - } - - if (req.params.find("type") != req.params.end()) { - // assume JSON in content to transform to protobuf object - if (req.content.length() > 0 && _interpreter->getDataModel() != NULL) { - std::string type = req.params["type"].front(); - const google::protobuf::Message* protoMsg = umundo::PBSerializer::getProto(type); - if (protoMsg == NULL) { - LOG(ERROR) << "No type " << type << " is known, pass a directory with proto .desc files via types param when invoking"; - return; - } - try { - Data data = _interpreter->getDataModel()->getStringAsData(req.content); - google::protobuf::Message* pbMsg = protoMsg->New(); - if (!dataToProtobuf(pbMsg, data)) { - LOG(ERROR) << "Cannot create message from JSON - not sending"; - } else { - // add all s11n properties - if (!_isService) { - _pub.prepareMsg(msg, type, pbMsg); - _pub.send(msg); - } else { - std::map<umundo::ServiceDescription, umundo::ServiceStub*>::iterator svcIter = _svcs.begin(); - while(svcIter != _svcs.end()) { - umundo::ServiceStub* stub = svcIter->second; - Event event; - void* rv = NULL; - stub->callStubMethod(req.name, pbMsg, type, rv, ""); - protobufToData(event, *(const google::protobuf::Message*)rv); - - event.name = _invokeId + ".reply." + req.name; - event.invokeid = _invokeId; - event.origin = msg->getMeta("um.channel"); - event.origintype = "umundo"; - event.type = Event::EXTERNAL; - - _interpreter->receive(event); - svcIter++; - } - } - } - } catch (Event e) { - LOG(ERROR) << "Syntax error when invoking umundo:" << std::endl << e << std::endl; - return; - } - } else { - LOG(ERROR) << "Required JSON object in content" << std::endl; - return; - } - } + umundo::Message* msg = new umundo::Message(); + + if (req.name.length() > 0) { + msg->putMeta("event", req.name); + } else { + msg->putMeta("event", "umundo"); + } + + if (req.params.find("type") != req.params.end()) { + // assume JSON in content to transform to protobuf object + if (req.content.length() > 0 && _interpreter->getDataModel() != NULL) { + std::string type; + std::multimap<std::string, std::string>::iterator typeIter = req.params.find("type"); + if (typeIter != req.params.end()) + type = typeIter->second; + const google::protobuf::Message* protoMsg = umundo::PBSerializer::getProto(type); + if (protoMsg == NULL) { + LOG(ERROR) << "No type " << type << " is known, pass a directory with proto .desc files via types param when invoking"; + return; + } + try { + Data data = _interpreter->getDataModel()->getStringAsData(req.content); + google::protobuf::Message* pbMsg = protoMsg->New(); + if (!dataToProtobuf(pbMsg, data)) { + LOG(ERROR) << "Cannot create message from JSON - not sending"; + } else { + // add all s11n properties + if (!_isService) { + _pub.prepareMsg(msg, type, pbMsg); + _pub.send(msg); + } else { + std::map<umundo::ServiceDescription, umundo::ServiceStub*>::iterator svcIter = _svcs.begin(); + while(svcIter != _svcs.end()) { + umundo::ServiceStub* stub = svcIter->second; + Event event; + void* rv = NULL; + stub->callStubMethod(req.name, pbMsg, type, rv, ""); + protobufToData(event, *(const google::protobuf::Message*)rv); + + event.name = _invokeId + ".reply." + req.name; + event.invokeid = _invokeId; + event.origin = msg->getMeta("um.channel"); + event.origintype = "umundo"; + event.type = Event::EXTERNAL; + + _interpreter->receive(event); + svcIter++; + } + } + } + } catch (Event e) { + LOG(ERROR) << "Syntax error when invoking umundo:" << std::endl << e << std::endl; + return; + } + } else { + LOG(ERROR) << "Required JSON object in content" << std::endl; + return; + } + } } void UmundoInvoker::cancel(const std::string sendId) { - assert(false); + assert(false); } void UmundoInvoker::sendToParent(SendRequest& req) { - assert(false); + assert(false); } void UmundoInvoker::invoke(InvokeRequest& req) { - _invokeId = req.invokeid; - - std::string channelName; - std::string serviceName; - - if (req.params.find("channel") != req.params.end()) { - channelName = req.params["channel"].front(); - _isService = false; - } else if (req.params.find("service") != req.params.end()) { - serviceName = req.params["service"].front(); - _isService = true; - } else { - LOG(ERROR) << "Invoking umundo needs a service or a channel param"; - return; - } - - _node = getNode(_interpreter); - - // add types from .proto or .desc files - if (req.params.find("types") != req.params.end()) { - std::list<std::string>::iterator typeIter = req.params["types"].begin(); - while(typeIter != req.params["types"].end()) { - Arabica::io::URI srcURI(*typeIter); - // if (!_interpreter->makeAbsolute(srcURI)) { - // LOG(ERROR) << "Relative URI for types in umundo invoker " << *typeIter << " with no base URI set for interpreter"; - // return; - // } - umundo::PBSerializer::addProto(srcURI.path()); - typeIter++; - } - } - - if (!_isService) { - // use umundo to publish objects on a channel - _pub = umundo::TypedPublisher(channelName); - _sub = umundo::TypedSubscriber(channelName, this); - - _node.addPublisher(_pub); - _node.addSubscriber(_sub); - - } else if (serviceName.length() > 0) { - // use umundo to access services - _svcFilter = umundo::ServiceFilter(serviceName); - _node.connect(&_svcMgr); - _svcMgr.startQuery(_svcFilter, this); - } + _invokeId = req.invokeid; + + std::string channelName; + std::string serviceName; + + if (req.params.find("channel") != req.params.end()) { + channelName = req.params.find("type")->second; + _isService = false; + } else if (req.params.find("service") != req.params.end()) { + serviceName = req.params.find("service")->second; + _isService = true; + } else { + LOG(ERROR) << "Invoking umundo needs a service or a channel param"; + return; + } + + _node = getNode(_interpreter); + + // add types from .proto or .desc files + if (req.params.find("types") != req.params.end()) { + std::pair<InvokeRequest::params_t::iterator, InvokeRequest::params_t::iterator> typeRange = req.params.equal_range("types"); + for (InvokeRequest::params_t::iterator it = typeRange.first; it != typeRange.second; it++) { + Arabica::io::URI srcURI(it->first); + // if (!_interpreter->makeAbsolute(srcURI)) { + // LOG(ERROR) << "Relative URI for types in umundo invoker " << *typeIter << " with no base URI set for interpreter"; + // return; + // } + umundo::PBSerializer::addProto(srcURI.path()); + } + } + + if (!_isService) { + // use umundo to publish objects on a channel + _pub = umundo::TypedPublisher(channelName); + _sub = umundo::TypedSubscriber(channelName, this); + + _node.addPublisher(_pub); + _node.addSubscriber(_sub); + + } else if (serviceName.length() > 0) { + // use umundo to access services + _svcFilter = umundo::ServiceFilter(serviceName); + _node.connect(&_svcMgr); + _svcMgr.startQuery(_svcFilter, this); + } } void UmundoInvoker::receive(void* object, umundo::Message* msg) { - uscxml::Event event; - if (msg->getMeta().find("event") != msg->getMeta().end()) { - event.name = msg->getMeta("event"); - } else { - event.name = "umundo.rcvd"; - } - - event.invokeid = _invokeId; - event.origin = msg->getMeta("um.channel"); - event.origintype = "umundo"; - event.type = Event::EXTERNAL; - + uscxml::Event event; + if (msg->getMeta().find("event") != msg->getMeta().end()) { + event.name = msg->getMeta("event"); + } else { + event.name = "umundo.rcvd"; + } + + event.invokeid = _invokeId; + event.origin = msg->getMeta("um.channel"); + event.origintype = "umundo"; + event.type = Event::EXTERNAL; + // if (msg->getMeta().find("um.s11n.type") != msg->getMeta().end()) // event.compound["class"] = msg->getMeta("um.s11n.type"); - - if (object != NULL) - protobufToData(event, *(const google::protobuf::Message*)object); - - // get meta fields into event - std::map<std::string, std::string>::const_iterator metaIter = msg->getMeta().begin(); - while(metaIter != msg->getMeta().end()) { - if (metaIter->first.substr(0,3).compare("um.") != 0) - event.compound[metaIter->first] = Data(metaIter->second, Data::VERBATIM); - metaIter++; - } - - _interpreter->receive(event); + + if (object != NULL) + protobufToData(event, *(const google::protobuf::Message*)object); + + // get meta fields into event + std::map<std::string, std::string>::const_iterator metaIter = msg->getMeta().begin(); + while(metaIter != msg->getMeta().end()) { + if (metaIter->first.substr(0,3).compare("um.") != 0) + event.compound[metaIter->first] = Data(metaIter->second, Data::VERBATIM); + metaIter++; + } + + _interpreter->receive(event); } void UmundoInvoker::added(umundo::ServiceDescription desc) { - LOG(ERROR) << "Service found!"; - - umundo::ServiceStub* stub = new umundo::ServiceStub(desc); - _svcs[desc] = stub; - - Event addedEvent; - addedEvent.invokeid = _invokeId; - addedEvent.origin = desc.getName(); - addedEvent.origintype = "umundo"; - addedEvent.type = Event::EXTERNAL; - addedEvent.name = _invokeId + ".added"; - - std::map<std::string, std::string>::const_iterator propIter = desc.getProperties().begin(); - while(propIter != desc.getProperties().end()) { - addedEvent.compound[propIter->first] = Data(propIter->second, Data::VERBATIM); - propIter++; - } - - _interpreter->receive(addedEvent); + LOG(ERROR) << "Service found!"; + + umundo::ServiceStub* stub = new umundo::ServiceStub(desc); + _svcs[desc] = stub; + + Event addedEvent; + addedEvent.invokeid = _invokeId; + addedEvent.origin = desc.getName(); + addedEvent.origintype = "umundo"; + addedEvent.type = Event::EXTERNAL; + addedEvent.name = _invokeId + ".added"; + + std::map<std::string, std::string>::const_iterator propIter = desc.getProperties().begin(); + while(propIter != desc.getProperties().end()) { + addedEvent.compound[propIter->first] = Data(propIter->second, Data::VERBATIM); + propIter++; + } + + _interpreter->receive(addedEvent); } void UmundoInvoker::removed(umundo::ServiceDescription desc) { - LOG(ERROR) << "Service lost!"; - - if (_svcs.find(desc) == _svcs.end()) { - return; - } - - delete _svcs[desc]; - _svcs.erase(desc); - - Event addedEvent; - addedEvent.invokeid = _invokeId; - addedEvent.origin = desc.getName(); - addedEvent.origintype = "umundo"; - addedEvent.type = Event::EXTERNAL; - addedEvent.name = _invokeId + ".removed"; - - std::map<std::string, std::string>::const_iterator propIter = desc.getProperties().begin(); - while(propIter != desc.getProperties().end()) { - addedEvent.compound[propIter->first] = Data(propIter->second, Data::VERBATIM); - propIter++; - } - - _interpreter->receive(addedEvent); + LOG(ERROR) << "Service lost!"; + + if (_svcs.find(desc) == _svcs.end()) { + return; + } + + delete _svcs[desc]; + _svcs.erase(desc); + + Event addedEvent; + addedEvent.invokeid = _invokeId; + addedEvent.origin = desc.getName(); + addedEvent.origintype = "umundo"; + addedEvent.type = Event::EXTERNAL; + addedEvent.name = _invokeId + ".removed"; + + std::map<std::string, std::string>::const_iterator propIter = desc.getProperties().begin(); + while(propIter != desc.getProperties().end()) { + addedEvent.compound[propIter->first] = Data(propIter->second, Data::VERBATIM); + propIter++; + } + + _interpreter->receive(addedEvent); } void UmundoInvoker::changed(umundo::ServiceDescription desc) { @@ -236,252 +235,252 @@ void UmundoInvoker::changed(umundo::ServiceDescription desc) { std::map<std::string, umundo::Node> UmundoInvoker::_nodes; umundo::Node UmundoInvoker::getNode(Interpreter* interpreter) { - if ((_nodes.find(interpreter->getName()) == _nodes.end())) { - _nodes[interpreter->getName()] = umundo::Node(); - } - return _nodes[interpreter->getName()]; + if ((_nodes.find(interpreter->getName()) == _nodes.end())) { + _nodes[interpreter->getName()] = umundo::Node(); + } + return _nodes[interpreter->getName()]; } bool UmundoInvoker::protobufToData(Data& data, const google::protobuf::Message& msg) { - const google::protobuf::Descriptor* desc = msg.GetDescriptor(); - const google::protobuf::Reflection* reflect = msg.GetReflection(); - - data.compound["type"] = Data(desc->name(), Data::VERBATIM); - - for (int i = 0; i < desc->field_count(); i++) { - const google::protobuf::FieldDescriptor* fieldDesc = desc->field(i); - std::string key = fieldDesc->name(); - - if (!fieldDesc->is_repeated() && !reflect->HasField(msg, fieldDesc)) - continue; - - switch(fieldDesc->type()) { - case google::protobuf::FieldDescriptor::TYPE_BOOL: - if (fieldDesc->is_repeated()) { - for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { - data.compound[key].array.push_back(Data(reflect->GetRepeatedBool(msg, fieldDesc, j) ? "true" : "false")); - } - } else { - data.compound[key].atom = (reflect->GetBool(msg, fieldDesc) ? "true" : "false"); - } - break; - case google::protobuf::FieldDescriptor::TYPE_BYTES: - case google::protobuf::FieldDescriptor::TYPE_STRING: - if (fieldDesc->is_repeated()) { - for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { - data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedString(msg, fieldDesc, j)), Data::VERBATIM)); - } - } else { - data.compound[key].atom = toStr(reflect->GetString(msg, fieldDesc)); - data.compound[key].type = Data::VERBATIM; - } - break; - case google::protobuf::FieldDescriptor::TYPE_DOUBLE: - if (fieldDesc->is_repeated()) { - for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { - data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedDouble(msg, fieldDesc, j)))); - } - } else { - data.compound[key].atom = toStr(reflect->GetDouble(msg, fieldDesc)); - } - break; - case google::protobuf::FieldDescriptor::TYPE_ENUM: - LOG(ERROR) << "TYPE_ENUM is unimplemented" << std::endl; - break; - case google::protobuf::FieldDescriptor::TYPE_FIXED32: - case google::protobuf::FieldDescriptor::TYPE_UINT32: - if (fieldDesc->is_repeated()) { - for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { - data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt32(msg, fieldDesc, j)))); - } - } else { - data.compound[key].atom = toStr(reflect->GetUInt32(msg, fieldDesc)); - } - break; - case google::protobuf::FieldDescriptor::TYPE_FIXED64: - case google::protobuf::FieldDescriptor::TYPE_UINT64: - if (fieldDesc->is_repeated()) { - for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { - data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt64(msg, fieldDesc, j)))); - } - } else { - data.compound[key].atom = toStr(reflect->GetUInt64(msg, fieldDesc)); - } - break; - case google::protobuf::FieldDescriptor::TYPE_FLOAT: - if (fieldDesc->is_repeated()) { - for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { - data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedFloat(msg, fieldDesc, j)))); - } - } else { - data.compound[key].atom = toStr(reflect->GetFloat(msg, fieldDesc)); - } - break; - case google::protobuf::FieldDescriptor::TYPE_GROUP: - LOG(ERROR) << "TYPE_GROUP is unimplemented" << std::endl; - break; - case google::protobuf::FieldDescriptor::TYPE_INT32: - case google::protobuf::FieldDescriptor::TYPE_SINT32: - case google::protobuf::FieldDescriptor::TYPE_SFIXED32: - if (fieldDesc->is_repeated()) { - for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { - data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt32(msg, fieldDesc, j)))); - } - } else { - data.compound[key].atom = toStr(reflect->GetInt32(msg, fieldDesc)); - } - break; - case google::protobuf::FieldDescriptor::TYPE_INT64: - case google::protobuf::FieldDescriptor::TYPE_SINT64: - case google::protobuf::FieldDescriptor::TYPE_SFIXED64: - if (fieldDesc->is_repeated()) { - for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { - data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt64(msg, fieldDesc, j)))); - } - } else { - data.compound[key].atom = toStr(reflect->GetInt64(msg, fieldDesc)); - } - break; - case google::protobuf::FieldDescriptor::TYPE_MESSAGE: - if (fieldDesc->is_repeated()) { - for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { - data.compound[key].array.push_back(Data()); - protobufToData(data.compound[key].array.back(), reflect->GetRepeatedMessage(msg, fieldDesc, j)); - } - } else { - protobufToData(data.compound[key], reflect->GetMessage(msg, fieldDesc)); - } - break; - } - } - return true; + const google::protobuf::Descriptor* desc = msg.GetDescriptor(); + const google::protobuf::Reflection* reflect = msg.GetReflection(); + + data.compound["type"] = Data(desc->name(), Data::VERBATIM); + + for (int i = 0; i < desc->field_count(); i++) { + const google::protobuf::FieldDescriptor* fieldDesc = desc->field(i); + std::string key = fieldDesc->name(); + + if (!fieldDesc->is_repeated() && !reflect->HasField(msg, fieldDesc)) + continue; + + switch(fieldDesc->type()) { + case google::protobuf::FieldDescriptor::TYPE_BOOL: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(reflect->GetRepeatedBool(msg, fieldDesc, j) ? "true" : "false")); + } + } else { + data.compound[key].atom = (reflect->GetBool(msg, fieldDesc) ? "true" : "false"); + } + break; + case google::protobuf::FieldDescriptor::TYPE_BYTES: + case google::protobuf::FieldDescriptor::TYPE_STRING: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedString(msg, fieldDesc, j)), Data::VERBATIM)); + } + } else { + data.compound[key].atom = toStr(reflect->GetString(msg, fieldDesc)); + data.compound[key].type = Data::VERBATIM; + } + break; + case google::protobuf::FieldDescriptor::TYPE_DOUBLE: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedDouble(msg, fieldDesc, j)))); + } + } else { + data.compound[key].atom = toStr(reflect->GetDouble(msg, fieldDesc)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_ENUM: + LOG(ERROR) << "TYPE_ENUM is unimplemented" << std::endl; + break; + case google::protobuf::FieldDescriptor::TYPE_FIXED32: + case google::protobuf::FieldDescriptor::TYPE_UINT32: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt32(msg, fieldDesc, j)))); + } + } else { + data.compound[key].atom = toStr(reflect->GetUInt32(msg, fieldDesc)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_FIXED64: + case google::protobuf::FieldDescriptor::TYPE_UINT64: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt64(msg, fieldDesc, j)))); + } + } else { + data.compound[key].atom = toStr(reflect->GetUInt64(msg, fieldDesc)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_FLOAT: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedFloat(msg, fieldDesc, j)))); + } + } else { + data.compound[key].atom = toStr(reflect->GetFloat(msg, fieldDesc)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_GROUP: + LOG(ERROR) << "TYPE_GROUP is unimplemented" << std::endl; + break; + case google::protobuf::FieldDescriptor::TYPE_INT32: + case google::protobuf::FieldDescriptor::TYPE_SINT32: + case google::protobuf::FieldDescriptor::TYPE_SFIXED32: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt32(msg, fieldDesc, j)))); + } + } else { + data.compound[key].atom = toStr(reflect->GetInt32(msg, fieldDesc)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_INT64: + case google::protobuf::FieldDescriptor::TYPE_SINT64: + case google::protobuf::FieldDescriptor::TYPE_SFIXED64: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt64(msg, fieldDesc, j)))); + } + } else { + data.compound[key].atom = toStr(reflect->GetInt64(msg, fieldDesc)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_MESSAGE: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data()); + protobufToData(data.compound[key].array.back(), reflect->GetRepeatedMessage(msg, fieldDesc, j)); + } + } else { + protobufToData(data.compound[key], reflect->GetMessage(msg, fieldDesc)); + } + break; + } + } + return true; } bool UmundoInvoker::dataToProtobuf(google::protobuf::Message* msg, Data& data) { - const google::protobuf::Descriptor* desc = msg->GetDescriptor(); - const google::protobuf::Reflection* reflect = msg->GetReflection(); - - for (int i = 0; i < desc->field_count(); i++) { - const google::protobuf::FieldDescriptor* fieldDesc = desc->field(i); - std::string key = fieldDesc->name(); - - if (data.compound.find(key) == data.compound.end()) { - if (fieldDesc->is_required()) { - LOG(ERROR) << "required field " << key << " not given in JSON"; - return false; - } - continue; - } - - std::list<Data>::iterator arrayIter = data.compound[key].array.begin(); - - switch(fieldDesc->type()) { - case google::protobuf::FieldDescriptor::TYPE_BOOL: - if (fieldDesc->is_repeated()) { - while(arrayIter != data.compound[key].array.end()) { - reflect->AddBool(msg, fieldDesc, arrayIter->atom.compare("false") == 0 ? false : true); - arrayIter++; - } - } else { - reflect->SetBool(msg, fieldDesc, (data.compound[key].atom.compare("false") == 0 ? false : true)); - } - break; - case google::protobuf::FieldDescriptor::TYPE_BYTES: - case google::protobuf::FieldDescriptor::TYPE_STRING: - if (fieldDesc->is_repeated()) { - while(arrayIter != data.compound[key].array.end()) { - reflect->AddString(msg, fieldDesc, arrayIter->atom); - arrayIter++; - } - } else { - reflect->SetString(msg, fieldDesc, data.compound[key].atom); - } - break; - case google::protobuf::FieldDescriptor::TYPE_DOUBLE: - if (fieldDesc->is_repeated()) { - while(arrayIter != data.compound[key].array.end()) { - reflect->AddDouble(msg, fieldDesc, strTo<double>(arrayIter->atom)); - arrayIter++; - } - } else { - reflect->SetDouble(msg, fieldDesc, strTo<double>(data.compound[key].atom)); - } - break; - case google::protobuf::FieldDescriptor::TYPE_ENUM: - LOG(ERROR) << "TYPE_ENUM is unimplemented" << std::endl; - break; - case google::protobuf::FieldDescriptor::TYPE_FIXED32: - case google::protobuf::FieldDescriptor::TYPE_UINT32: - if (fieldDesc->is_repeated()) { - while(arrayIter != data.compound[key].array.end()) { - reflect->AddUInt32(msg, fieldDesc, strTo<uint32_t>(arrayIter->atom)); - arrayIter++; - } - } else { - reflect->SetUInt32(msg, fieldDesc, strTo<uint32_t>(data.compound[key].atom)); - } - break; - case google::protobuf::FieldDescriptor::TYPE_FIXED64: - case google::protobuf::FieldDescriptor::TYPE_UINT64: - if (fieldDesc->is_repeated()) { - while(arrayIter != data.compound[key].array.end()) { - reflect->AddUInt64(msg, fieldDesc, strTo<uint64_t>(arrayIter->atom)); - arrayIter++; - } - } else { - reflect->SetUInt64(msg, fieldDesc, strTo<uint64_t>(data.compound[key].atom)); - } - break; - case google::protobuf::FieldDescriptor::TYPE_FLOAT: - if (fieldDesc->is_repeated()) { - while(arrayIter != data.compound[key].array.end()) { - reflect->AddFloat(msg, fieldDesc, strTo<float>(arrayIter->atom)); - arrayIter++; - } - } else { - reflect->SetFloat(msg, fieldDesc, strTo<float>(data.compound[key].atom)); - } - break; - case google::protobuf::FieldDescriptor::TYPE_GROUP: - LOG(ERROR) << "TYPE_GROUP is unimplemented" << std::endl; - break; - case google::protobuf::FieldDescriptor::TYPE_INT32: - case google::protobuf::FieldDescriptor::TYPE_SINT32: - case google::protobuf::FieldDescriptor::TYPE_SFIXED32: - if (fieldDesc->is_repeated()) { - while(arrayIter != data.compound[key].array.end()) { - reflect->AddInt32(msg, fieldDesc, strTo<int32_t>(arrayIter->atom)); - arrayIter++; - } - } else { - reflect->SetInt32(msg, fieldDesc, strTo<int32_t>(data.compound[key].atom)); - } - break; - case google::protobuf::FieldDescriptor::TYPE_INT64: - case google::protobuf::FieldDescriptor::TYPE_SINT64: - case google::protobuf::FieldDescriptor::TYPE_SFIXED64: - if (fieldDesc->is_repeated()) { - while(arrayIter != data.compound[key].array.end()) { - reflect->AddInt64(msg, fieldDesc, strTo<int64_t>(arrayIter->atom)); - arrayIter++; - } - } else { - reflect->SetInt64(msg, fieldDesc, strTo<int64_t>(data.compound[key].atom)); - } - break; - case google::protobuf::FieldDescriptor::TYPE_MESSAGE: - if (fieldDesc->is_repeated()) { - while(arrayIter != data.compound[key].array.end()) { - dataToProtobuf(reflect->AddMessage(msg, fieldDesc), *arrayIter); - arrayIter++; - } - } else { - dataToProtobuf(reflect->MutableMessage(msg, fieldDesc), data.compound[key]); - } - break; - } - } - return true; + const google::protobuf::Descriptor* desc = msg->GetDescriptor(); + const google::protobuf::Reflection* reflect = msg->GetReflection(); + + for (int i = 0; i < desc->field_count(); i++) { + const google::protobuf::FieldDescriptor* fieldDesc = desc->field(i); + std::string key = fieldDesc->name(); + + if (data.compound.find(key) == data.compound.end()) { + if (fieldDesc->is_required()) { + LOG(ERROR) << "required field " << key << " not given in JSON"; + return false; + } + continue; + } + + std::list<Data>::iterator arrayIter = data.compound[key].array.begin(); + + switch(fieldDesc->type()) { + case google::protobuf::FieldDescriptor::TYPE_BOOL: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddBool(msg, fieldDesc, arrayIter->atom.compare("false") == 0 ? false : true); + arrayIter++; + } + } else { + reflect->SetBool(msg, fieldDesc, (data.compound[key].atom.compare("false") == 0 ? false : true)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_BYTES: + case google::protobuf::FieldDescriptor::TYPE_STRING: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddString(msg, fieldDesc, arrayIter->atom); + arrayIter++; + } + } else { + reflect->SetString(msg, fieldDesc, data.compound[key].atom); + } + break; + case google::protobuf::FieldDescriptor::TYPE_DOUBLE: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddDouble(msg, fieldDesc, strTo<double>(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetDouble(msg, fieldDesc, strTo<double>(data.compound[key].atom)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_ENUM: + LOG(ERROR) << "TYPE_ENUM is unimplemented" << std::endl; + break; + case google::protobuf::FieldDescriptor::TYPE_FIXED32: + case google::protobuf::FieldDescriptor::TYPE_UINT32: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddUInt32(msg, fieldDesc, strTo<uint32_t>(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetUInt32(msg, fieldDesc, strTo<uint32_t>(data.compound[key].atom)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_FIXED64: + case google::protobuf::FieldDescriptor::TYPE_UINT64: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddUInt64(msg, fieldDesc, strTo<uint64_t>(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetUInt64(msg, fieldDesc, strTo<uint64_t>(data.compound[key].atom)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_FLOAT: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddFloat(msg, fieldDesc, strTo<float>(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetFloat(msg, fieldDesc, strTo<float>(data.compound[key].atom)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_GROUP: + LOG(ERROR) << "TYPE_GROUP is unimplemented" << std::endl; + break; + case google::protobuf::FieldDescriptor::TYPE_INT32: + case google::protobuf::FieldDescriptor::TYPE_SINT32: + case google::protobuf::FieldDescriptor::TYPE_SFIXED32: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddInt32(msg, fieldDesc, strTo<int32_t>(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetInt32(msg, fieldDesc, strTo<int32_t>(data.compound[key].atom)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_INT64: + case google::protobuf::FieldDescriptor::TYPE_SINT64: + case google::protobuf::FieldDescriptor::TYPE_SFIXED64: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddInt64(msg, fieldDesc, strTo<int64_t>(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetInt64(msg, fieldDesc, strTo<int64_t>(data.compound[key].atom)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_MESSAGE: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + dataToProtobuf(reflect->AddMessage(msg, fieldDesc), *arrayIter); + arrayIter++; + } + } else { + dataToProtobuf(reflect->MutableMessage(msg, fieldDesc), data.compound[key]); + } + break; + } + } + return true; } }
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h index 36a6217..72fcc9b 100644 --- a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h +++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h @@ -5,6 +5,7 @@ #include <umundo/s11n.h> #include <umundo/rpc.h> #include <umundo/s11n/protobuf/PBSerializer.h> +#include <uscxml/Interpreter.h> #include <google/protobuf/message.h> #ifdef BUILD_AS_PLUGINS @@ -18,46 +19,46 @@ class Interpreter; class UmundoInvoker : public Invoker, public umundo::TypedReceiver, public umundo::ResultSet<umundo::ServiceDescription> { public: UmundoInvoker(); - virtual ~UmundoInvoker(); - virtual Invoker* create(Interpreter* interpreter); + virtual ~UmundoInvoker(); + virtual Invoker* create(Interpreter* interpreter); - virtual std::set<std::string> getNames() { + virtual std::set<std::string> getNames() { std::set<std::string> names; names.insert("umundo"); names.insert("http://umundo.tk.informatik.tu-darmstadt.de/"); names.insert("http://umundo.tk.informatik.tu-darmstadt.de"); return names; } - - virtual Data getDataModelVariables(); - virtual void send(SendRequest& req); - virtual void cancel(const std::string sendId); - virtual void invoke(InvokeRequest& req); - virtual void sendToParent(SendRequest& req); - virtual void receive(void* object, umundo::Message* msg); + virtual Data getDataModelVariables(); + virtual void send(SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(InvokeRequest& req); + virtual void sendToParent(SendRequest& req); - virtual void added(umundo::ServiceDescription); + virtual void receive(void* object, umundo::Message* msg); + + virtual void added(umundo::ServiceDescription); virtual void removed(umundo::ServiceDescription); virtual void changed(umundo::ServiceDescription); - + protected: - std::string _invokeId; - bool _isService; - - bool dataToProtobuf(google::protobuf::Message* msg, Data& data); - bool protobufToData(Data& data, const google::protobuf::Message& msg); - - umundo::TypedPublisher _pub; - umundo::TypedSubscriber _sub; - umundo::Node _node; - - umundo::ServiceFilter _svcFilter; - umundo::ServiceManager _svcMgr; - std::map<umundo::ServiceDescription, umundo::ServiceStub*> _svcs; - - static std::map<std::string, umundo::Node> _nodes; - static umundo::Node getNode(Interpreter* interpreter); + std::string _invokeId; + bool _isService; + + bool dataToProtobuf(google::protobuf::Message* msg, Data& data); + bool protobufToData(Data& data, const google::protobuf::Message& msg); + + umundo::TypedPublisher _pub; + umundo::TypedSubscriber _sub; + umundo::Node _node; + + umundo::ServiceFilter _svcFilter; + umundo::ServiceManager _svcMgr; + std::map<umundo::ServiceDescription, umundo::ServiceStub*> _svcs; + + static std::map<std::string, umundo::Node> _nodes; + static umundo::Node getNode(Interpreter* interpreter); }; #ifdef BUILD_AS_PLUGINS diff --git a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp index 44c89ae..bed9f98 100644 --- a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp @@ -28,9 +28,9 @@ namespace uscxml { #ifdef BUILD_AS_PLUGINS PLUMA_CONNECTOR -bool connect(pluma::Host& host){ - host.add( new EventIOProcessorProvider() ); - return true; +bool connect(pluma::Host& host) { + host.add( new EventIOProcessorProvider() ); + return true; } #endif @@ -40,199 +40,227 @@ EventIOProcessor::EventIOProcessor() { } EventIOProcessor::~EventIOProcessor() { - _asyncQueue.stop(); - evdns_base_free(_dns, 1); - EventIOServer* httpServer = EventIOServer::getInstance(); - httpServer->unregisterProcessor(this); + _asyncQueue.stop(); + evdns_base_free(_dns, 1); + EventIOServer* httpServer = EventIOServer::getInstance(); + httpServer->unregisterProcessor(this); } IOProcessor* EventIOProcessor::create(Interpreter* interpreter) { - EventIOProcessor* io = new EventIOProcessor(); - io->_interpreter = interpreter; - - io->_dns = evdns_base_new(io->_asyncQueue._eventLoop, 1); - assert(io->_dns); - assert(evdns_base_count_nameservers(io->_dns) > 0); - - // register at http server - EventIOServer* httpServer = EventIOServer::getInstance(); - httpServer->registerProcessor(io); - - io->start(); - return io; + EventIOProcessor* io = new EventIOProcessor(); + io->_interpreter = interpreter; + + io->_dns = evdns_base_new(io->_asyncQueue._eventLoop, 1); + assert(io->_dns); + assert(evdns_base_count_nameservers(io->_dns) > 0); + + // register at http server + EventIOServer* httpServer = EventIOServer::getInstance(); + httpServer->registerProcessor(io); + + io->start(); + return io; } void EventIOProcessor::start() { - _asyncQueue.start(); + _asyncQueue.start(); } Data EventIOProcessor::getDataModelVariables() { Data data; - assert(_url.length() > 0); - data.compound["location"] = Data(_url, Data::VERBATIM); + assert(_url.length() > 0); + data.compound["location"] = Data(_url, Data::VERBATIM); return data; } void EventIOProcessor::send(SendRequest& req) { - // I cant figure out how to copy the reference into the struct :( - _sendData[req.sendid].req = req; - _sendData[req.sendid].ioProcessor = this; - - int err = 0; - char uriBuf[1024]; - - struct evhttp_uri* targetURI = evhttp_uri_parse(_sendData[req.sendid].req.target.c_str()); - if (evhttp_uri_get_port(targetURI) == 0) - evhttp_uri_set_port(targetURI, 80); - const char* hostName = evhttp_uri_get_host(targetURI); - - // use synchronous dns resolving for multicast dns - if(hostName && strlen(hostName) >= strlen(".local")) { - if(strcmp(hostName + strlen(hostName) - strlen(".local"), ".local") == 0) { - evhttp_uri_set_host(targetURI, EventIOServer::syncResolve(hostName).c_str()); - } - } - evhttp_uri_join(targetURI, uriBuf, 1024); - - LOG(INFO) << "URI for send request: " << uriBuf << std::endl; - - std::stringstream ssEndPoint; - ssEndPoint << evhttp_uri_get_host(targetURI) << ":" << evhttp_uri_get_port(targetURI); - std::string endPoint = ssEndPoint.str(); - - std::stringstream ssLocalURI; - ssLocalURI << evhttp_uri_get_path(targetURI) << evhttp_uri_get_fragment(targetURI); - std::string localURI = ssLocalURI.str(); - - if (_httpConnections.find(endPoint) == _httpConnections.end()) - _httpConnections[endPoint] = evhttp_connection_base_new(_asyncQueue._eventLoop, _dns, evhttp_uri_get_host(targetURI), evhttp_uri_get_port(targetURI)); - - struct evhttp_connection* httpConn = _httpConnections[endPoint]; - struct evhttp_request* httpReq = evhttp_request_new(EventIOProcessor::httpSendReqDone, this); - + // I cant figure out how to copy the reference into the struct :( + _sendData[req.sendid].req = req; + _sendData[req.sendid].ioProcessor = this; + + int err = 0; + char uriBuf[1024]; + + struct evhttp_uri* targetURI = evhttp_uri_parse(_sendData[req.sendid].req.target.c_str()); + if (evhttp_uri_get_port(targetURI) == 0) + evhttp_uri_set_port(targetURI, 80); + const char* hostName = evhttp_uri_get_host(targetURI); + + // use synchronous dns resolving for multicast dns + if(hostName && strlen(hostName) >= strlen(".local")) { + if(strcmp(hostName + strlen(hostName) - strlen(".local"), ".local") == 0) { + evhttp_uri_set_host(targetURI, EventIOServer::syncResolve(hostName).c_str()); + } + } + evhttp_uri_join(targetURI, uriBuf, 1024); + + LOG(INFO) << "URI for send request: " << uriBuf << std::endl; + + int port = evhttp_uri_get_port(targetURI); + if (port <= 0) + port = 80; + + std::stringstream ssEndPoint; + ssEndPoint << evhttp_uri_get_host(targetURI) << ":" << port; + std::string endPoint = ssEndPoint.str(); + + std::stringstream ssLocalURI; + ssLocalURI << evhttp_uri_get_path(targetURI) << evhttp_uri_get_fragment(targetURI); + std::string localURI = ssLocalURI.str(); + + if (_httpConnections.find(endPoint) == _httpConnections.end()) + _httpConnections[endPoint] = evhttp_connection_base_new(_asyncQueue._eventLoop, _dns, evhttp_uri_get_host(targetURI), evhttp_uri_get_port(targetURI)); + + struct evhttp_connection* httpConn = _httpConnections[endPoint]; + struct evhttp_request* httpReq = evhttp_request_new(EventIOProcessor::httpSendReqDone, this); + + // event name + if (req.name.size() > 0) { + evhttp_add_header(evhttp_request_get_output_headers(httpReq), "_scxmleventname", evhttp_encode_uri(req.name.c_str())); + } + + // event namelist + if (req.namelist.size() > 0) { + std::map<std::string, std::string>::iterator namelistIter = req.namelist.begin(); + while (namelistIter != req.namelist.end()) { + evhttp_add_header(evhttp_request_get_output_headers(httpReq), + namelistIter->first.c_str(), + evhttp_encode_uri(namelistIter->second.c_str())); + namelistIter++; + } + } + + // event params + if (req.params.size() > 0) { + std::multimap<std::string, std::string>::iterator paramIter = req.params.begin(); + while (paramIter != req.params.end()) { + evhttp_add_header(evhttp_request_get_output_headers(httpReq), + paramIter->first.c_str(), + evhttp_encode_uri(paramIter->second.c_str())); + paramIter++; + } + } + + // content + if (req.content.size() > 0) + evbuffer_add(evhttp_request_get_output_buffer(httpReq), req.content.c_str(), req.content.size()); + #if 0 - // event name - if (sendData->req.event.size() > 0) { - evhttp_add_header(evhttp_request_get_output_headers(httpReq), "_scxmleventname", evhttp_encode_uri(sendData->req.event.c_str())); - } - - // event namelist - if (sendData->req.namelist.size() > 0) { - std::map<std::string, std::string>::iterator namelistIter = sendData->req.namelist.begin(); - while (namelistIter != sendData->req.namelist.end()) { - evhttp_add_header(evhttp_request_get_output_headers(httpReq), - namelistIter->first.c_str(), - evhttp_encode_uri(namelistIter->second.c_str())); - namelistIter++; - } - } - - // event params - if (sendData->req.params.size() > 0) { - std::map<std::string, std::string>::iterator paramIter = sendData->req.params.begin(); - while (paramIter != sendData->req.params.end()) { - evhttp_add_header(evhttp_request_get_output_headers(httpReq), - paramIter->first.c_str(), - evhttp_encode_uri(paramIter->second.c_str())); - paramIter++; - } - } - - // content - if (sendData->req.content.size() > 0) - evbuffer_add(evhttp_request_get_output_buffer(httpReq), sendData->req.content.c_str(), sendData->req.content.size()); + evhttp_add_header(evhttp_request_get_output_headers(httpReq), "_scxmleventstruct", evhttp_encode_uri(req.toXMLString().c_str())); #endif - - evhttp_add_header(evhttp_request_get_output_headers(httpReq), "_scxmleventstruct", evhttp_encode_uri(req.toXMLString().c_str())); - - - _httpRequests[req.sendid] = httpReq; - err = evhttp_make_request(httpConn, - httpReq, - EVHTTP_REQ_POST, localURI.c_str()); - if (err) { - LOG(ERROR) << "Could not make http request to " << req.target; - } + // required as per http 1.1 RFC2616 section 14.23 + evhttp_add_header(evhttp_request_get_output_headers(httpReq), "Host", evhttp_uri_get_host(targetURI)); + + _httpRequests[req.sendid] = httpReq; + err = evhttp_make_request(httpConn, + httpReq, + EVHTTP_REQ_POST, localURI.c_str()); + if (err) { + LOG(ERROR) << "Could not make http request to " << req.target; + } } void EventIOProcessor::httpRecvReq(struct evhttp_request *req, void *arg) { - + const char *cmdtype; struct evkeyvalq *headers; struct evkeyval *header; struct evbuffer *buf; - switch (evhttp_request_get_command(req)) { - case EVHTTP_REQ_GET: cmdtype = "GET"; break; - case EVHTTP_REQ_POST: cmdtype = "POST"; break; - case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break; - case EVHTTP_REQ_PUT: cmdtype = "PUT"; break; - case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break; - case EVHTTP_REQ_OPTIONS: cmdtype = "OPTIONS"; break; - case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break; - case EVHTTP_REQ_CONNECT: cmdtype = "CONNECT"; break; - case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break; - default: cmdtype = "unknown"; break; + switch (evhttp_request_get_command(req)) { + case EVHTTP_REQ_GET: + cmdtype = "GET"; + break; + case EVHTTP_REQ_POST: + cmdtype = "POST"; + break; + case EVHTTP_REQ_HEAD: + cmdtype = "HEAD"; + break; + case EVHTTP_REQ_PUT: + cmdtype = "PUT"; + break; + case EVHTTP_REQ_DELETE: + cmdtype = "DELETE"; + break; + case EVHTTP_REQ_OPTIONS: + cmdtype = "OPTIONS"; + break; + case EVHTTP_REQ_TRACE: + cmdtype = "TRACE"; + break; + case EVHTTP_REQ_CONNECT: + cmdtype = "CONNECT"; + break; + case EVHTTP_REQ_PATCH: + cmdtype = "PATCH"; + break; + default: + cmdtype = "unknown"; + break; } - Event reqEvent; - reqEvent.type = Event::EXTERNAL; - bool scxmlStructFound = false; - - // map headers to event structure - headers = evhttp_request_get_input_headers(req); + Event reqEvent; + reqEvent.type = Event::EXTERNAL; + bool scxmlStructFound = false; + + // map headers to event structure + headers = evhttp_request_get_input_headers(req); for (header = headers->tqh_first; header; - header = header->next.tqe_next) { + header = header->next.tqe_next) { // std::cout << "Header: " << header->key << std::endl; // std::cout << "Value: " << evhttp_decode_uri(header->value) << std::endl; - if (boost::iequals("_scxmleventstruct", header->key)) { - reqEvent = Event::fromXML(evhttp_decode_uri(header->value)); - scxmlStructFound = true; - break; - } else if (boost::iequals("_scxmleventname", header->key)) { - reqEvent.name = evhttp_decode_uri(header->value); - } else { - reqEvent.compound[header->key] = Data(evhttp_decode_uri(header->value), Data::VERBATIM); - } + if (boost::iequals("_scxmleventstruct", header->key)) { + reqEvent = Event::fromXML(evhttp_decode_uri(header->value)); + scxmlStructFound = true; + break; + } else if (boost::iequals("_scxmleventname", header->key)) { + reqEvent.name = evhttp_decode_uri(header->value); + } else { + reqEvent.compound[header->key] = Data(evhttp_decode_uri(header->value), Data::VERBATIM); + } } - if (!scxmlStructFound) { - // get content into event - std::string content; - buf = evhttp_request_get_input_buffer(req); - while (evbuffer_get_length(buf)) { - int n; - char cbuf[128]; - n = evbuffer_remove(buf, cbuf, sizeof(buf)-1); - if (n > 0) { - content.append(cbuf, n); - } - } - reqEvent.compound["content"] = Data(content, Data::VERBATIM); - } - - EventIOProcessor* INSTANCE = (EventIOProcessor*)arg; - INSTANCE->_interpreter->receive(reqEvent); - + if (reqEvent.name.length() == 0) + reqEvent.name = cmdtype; + + if (!scxmlStructFound) { + // get content into event + std::string content; + buf = evhttp_request_get_input_buffer(req); + while (evbuffer_get_length(buf)) { + int n; + char cbuf[128]; + n = evbuffer_remove(buf, cbuf, sizeof(buf)-1); + if (n > 0) { + content.append(cbuf, n); + } + } + reqEvent.compound["content"] = Data(content, Data::VERBATIM); + } + + EventIOProcessor* INSTANCE = (EventIOProcessor*)arg; + INSTANCE->_interpreter->receive(reqEvent); + evhttp_send_reply(req, 200, "OK", NULL); } void EventIOProcessor::httpSendReqDone(struct evhttp_request *req, void *cb_arg) { - if (req) { - LOG(INFO) << "got return code " << evhttp_request_get_response_code(req) << std::endl; - } + if (req) { + LOG(INFO) << "got return code " << evhttp_request_get_response_code(req) << std::endl; + } } EventIOServer::EventIOServer(unsigned short port) { - _port = port; - _base = event_base_new(); - _http = evhttp_new(_base); - _handle = NULL; - while((_handle = evhttp_bind_socket_with_handle(_http, INADDR_ANY, _port)) == NULL) { - _port++; - } - determineAddress(); + _port = port; + _base = event_base_new(); + _http = evhttp_new(_base); + _handle = NULL; + while((_handle = evhttp_bind_socket_with_handle(_http, INADDR_ANY, _port)) == NULL) { + _port++; + } + determineAddress(); } EventIOServer::~EventIOServer() { @@ -242,128 +270,128 @@ EventIOServer* EventIOServer::_instance = NULL; tthread::recursive_mutex EventIOServer::_instanceMutex; EventIOServer* EventIOServer::getInstance() { - tthread::lock_guard<tthread::recursive_mutex> lock(_instanceMutex); - if (_instance == NULL) { - _instance = new EventIOServer(8080); - _instance->start(); - } - return _instance; + tthread::lock_guard<tthread::recursive_mutex> lock(_instanceMutex); + if (_instance == NULL) { + _instance = new EventIOServer(8080); + _instance->start(); + } + return _instance; } void EventIOServer::registerProcessor(EventIOProcessor* processor) { - EventIOServer* INSTANCE = getInstance(); - tthread::lock_guard<tthread::recursive_mutex> lock(INSTANCE->_mutex); - - /** - * Determine path for interpreter. - * - * If the interpreter has a name and it is not yet taken, choose it as the path - * for requests. If the interpreters name path is already taken, append digits - * until we have an available path. - * - * If the interpreter does not specify a name, take its sessionid. - */ - - std::string path = processor->_interpreter->getName(); - if (path.size() == 0) { - path = processor->_interpreter->getSessionId(); - } - assert(path.size() > 0); - - std::stringstream actualPath(path); - int i = 1; - while(INSTANCE->_processors.find(actualPath.str()) != INSTANCE->_processors.end()) { - actualPath.str(std::string()); - actualPath.clear(); - actualPath << path << ++i; - } - - std::stringstream processorURL; - processorURL << "http://" << INSTANCE->_address << ":" << INSTANCE->_port << "/" << actualPath.str(); - - INSTANCE->_processors[actualPath.str()] = processor; - processor->setURL(processorURL.str()); - - evhttp_set_cb(INSTANCE->_http, ("/" + actualPath.str()).c_str(), EventIOProcessor::httpRecvReq, processor); + EventIOServer* INSTANCE = getInstance(); + tthread::lock_guard<tthread::recursive_mutex> lock(INSTANCE->_mutex); + + /** + * Determine path for interpreter. + * + * If the interpreter has a name and it is not yet taken, choose it as the path + * for requests. If the interpreters name path is already taken, append digits + * until we have an available path. + * + * If the interpreter does not specify a name, take its sessionid. + */ + + std::string path = processor->_interpreter->getName(); + if (path.size() == 0) { + path = processor->_interpreter->getSessionId(); + } + assert(path.size() > 0); + + std::stringstream actualPath(path); + int i = 1; + while(INSTANCE->_processors.find(actualPath.str()) != INSTANCE->_processors.end()) { + actualPath.str(std::string()); + actualPath.clear(); + actualPath << path << ++i; + } + + std::stringstream processorURL; + processorURL << "http://" << INSTANCE->_address << ":" << INSTANCE->_port << "/" << actualPath.str(); + + INSTANCE->_processors[actualPath.str()] = processor; + processor->setURL(processorURL.str()); + + evhttp_set_cb(INSTANCE->_http, ("/" + actualPath.str()).c_str(), EventIOProcessor::httpRecvReq, processor); // evhttp_set_cb(THIS->_http, "/", EventIOProcessor::httpRecvReq, processor); // evhttp_set_gencb(THIS->_http, EventIOProcessor::httpRecvReq, NULL); } void EventIOServer::unregisterProcessor(EventIOProcessor* processor) { - EventIOServer* INSTANCE = getInstance(); - tthread::lock_guard<tthread::recursive_mutex> lock(INSTANCE->_mutex); - evhttp_del_cb(INSTANCE->_http, processor->_url.c_str()); + EventIOServer* INSTANCE = getInstance(); + tthread::lock_guard<tthread::recursive_mutex> lock(INSTANCE->_mutex); + evhttp_del_cb(INSTANCE->_http, processor->_url.c_str()); } - + void EventIOServer::start() { - _isRunning = true; - _thread = new tthread::thread(EventIOServer::run, this); + _isRunning = true; + _thread = new tthread::thread(EventIOServer::run, this); } void EventIOServer::run(void* instance) { - EventIOServer* INSTANCE = (EventIOServer*)instance; - while(INSTANCE->_isRunning) { - LOG(INFO) << "Dispatching HTTP Server" << std::endl; - event_base_dispatch(INSTANCE->_base); - } - LOG(INFO) << "HTTP Server stopped" << std::endl; + EventIOServer* INSTANCE = (EventIOServer*)instance; + while(INSTANCE->_isRunning) { + LOG(INFO) << "Dispatching HTTP Server" << std::endl; + event_base_dispatch(INSTANCE->_base); + } + LOG(INFO) << "HTTP Server stopped" << std::endl; } std::string EventIOServer::syncResolve(const std::string& hostname) { - struct hostent *he; - struct in_addr **addr_list; - int i; - - if ( (he = gethostbyname( hostname.c_str() ) ) != NULL) { - addr_list = (struct in_addr **) he->h_addr_list; - for(i = 0; addr_list[i] != NULL; i++) { - return std::string(inet_ntoa(*addr_list[i])); - } - } - return ""; + struct hostent *he; + struct in_addr **addr_list; + int i; + + if ( (he = gethostbyname( hostname.c_str() ) ) != NULL) { + addr_list = (struct in_addr **) he->h_addr_list; + for(i = 0; addr_list[i] != NULL; i++) { + return std::string(inet_ntoa(*addr_list[i])); + } + } + return ""; } - + void EventIOServer::determineAddress() { - char hostname[1024]; - gethostname(hostname, 1024); - _address = std::string(hostname); - + char hostname[1024]; + gethostname(hostname, 1024); + _address = std::string(hostname); + #if 0 - struct sockaddr_storage ss; - evutil_socket_t fd; - ev_socklen_t socklen = sizeof(ss); - char addrbuf[128]; - - void *inaddr; - const char *addr; - int got_port = -1; - fd = evhttp_bound_socket_get_fd(_handle); - memset(&ss, 0, sizeof(ss)); - if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) { - perror("getsockname() failed"); - return; - } - - if (ss.ss_family == AF_INET) { - got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port); - inaddr = &((struct sockaddr_in*)&ss)->sin_addr; - } else if (ss.ss_family == AF_INET6) { - got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port); - inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr; - } else { - fprintf(stderr, "Weird address family %d\n", - ss.ss_family); - return; - } - addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf, - sizeof(addrbuf)); - if (addr) { - _address = std::string(addr); - } else { - fprintf(stderr, "evutil_inet_ntop failed\n"); - return; - } + struct sockaddr_storage ss; + evutil_socket_t fd; + ev_socklen_t socklen = sizeof(ss); + char addrbuf[128]; + + void *inaddr; + const char *addr; + int got_port = -1; + fd = evhttp_bound_socket_get_fd(_handle); + memset(&ss, 0, sizeof(ss)); + if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) { + perror("getsockname() failed"); + return; + } + + if (ss.ss_family == AF_INET) { + got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port); + inaddr = &((struct sockaddr_in*)&ss)->sin_addr; + } else if (ss.ss_family == AF_INET6) { + got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port); + inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr; + } else { + fprintf(stderr, "Weird address family %d\n", + ss.ss_family); + return; + } + addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf, + sizeof(addrbuf)); + if (addr) { + _address = std::string(addr); + } else { + fprintf(stderr, "evutil_inet_ntop failed\n"); + return; + } #endif } diff --git a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h index af7aac7..f0228e9 100644 --- a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h +++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h @@ -18,84 +18,86 @@ namespace uscxml { class EventIOServer; - + class EventIOProcessor : public uscxml::IOProcessor { public: - struct SendData { - EventIOProcessor* ioProcessor; - uscxml::SendRequest req; - }; - - EventIOProcessor(); - virtual ~EventIOProcessor(); - virtual IOProcessor* create(uscxml::Interpreter* interpreter); - - virtual std::set<std::string> getNames() { + struct SendData { + EventIOProcessor* ioProcessor; + uscxml::SendRequest req; + }; + + EventIOProcessor(); + virtual ~EventIOProcessor(); + virtual IOProcessor* create(uscxml::Interpreter* interpreter); + + virtual std::set<std::string> getNames() { std::set<std::string> names; names.insert("basichttp"); names.insert("http://www.w3.org/TR/scxml/#SCXMLEventProcessor"); return names; } - virtual void send(uscxml::SendRequest& req); + virtual void send(uscxml::SendRequest& req); Data getDataModelVariables(); - void setURL(const std::string& url) { _url = url; } - - void start(); - static void run(void* instance); + void setURL(const std::string& url) { + _url = url; + } + + void start(); + static void run(void* instance); - static void httpMakeSendReq(void* userdata, std::string eventName); - static void httpSendReqDone(struct evhttp_request *req, void *cb_arg); - static void httpRecvReq(struct evhttp_request *req, void *arg); + static void httpMakeSendReq(void* userdata, std::string eventName); + static void httpSendReqDone(struct evhttp_request *req, void *cb_arg); + static void httpRecvReq(struct evhttp_request *req, void *arg); protected: - std::map<std::string, SendData> _sendData; - - std::string _url; - - uscxml::DelayedEventQueue _asyncQueue; - uscxml::Interpreter* _interpreter; - std::map<std::string, struct evhttp_connection*> _httpConnections; - std::map<std::string, struct evhttp_request*> _httpRequests; - struct evdns_base* _dns; - - friend class EventIOServer; + std::map<std::string, SendData> _sendData; + + std::string _url; + + uscxml::DelayedEventQueue _asyncQueue; + uscxml::Interpreter* _interpreter; + std::map<std::string, struct evhttp_connection*> _httpConnections; + std::map<std::string, struct evhttp_request*> _httpRequests; + struct evdns_base* _dns; + + friend class EventIOServer; }; class EventIOServer { private: - static EventIOServer* getInstance(); - EventIOServer(unsigned short port); - ~EventIOServer(); - - void start(); - void stop(); - static void run(void* instance); - - void determineAddress(); - static std::string syncResolve(const std::string& hostname); - - static void registerProcessor(EventIOProcessor* processor); - static void unregisterProcessor(EventIOProcessor* processor); - - - std::map<std::string, EventIOProcessor*> _processors; - - struct event_base* _base; - struct evhttp* _http; - struct evhttp_bound_socket* _handle; - - unsigned short _port; - std::string _address; - - static EventIOServer* _instance; - static tthread::recursive_mutex _instanceMutex; - tthread::thread* _thread; - tthread::recursive_mutex _mutex; - bool _isRunning; - - friend class EventIOProcessor; + static EventIOServer* getInstance(); + EventIOServer(unsigned short port); + ~EventIOServer(); + + void start(); + void stop(); + static void run(void* instance); + + void determineAddress(); + static std::string syncResolve(const std::string& hostname); + + static void registerProcessor(EventIOProcessor* processor); + static void unregisterProcessor(EventIOProcessor* processor); + + + std::map<std::string, EventIOProcessor*> _processors; + + struct event_base* _base; + struct evhttp* _http; + struct evhttp_bound_socket* _handle; + + unsigned short _port; + std::string _address; + + static EventIOServer* _instance; + static tthread::recursive_mutex _instanceMutex; + tthread::thread* _thread; + tthread::recursive_mutex _mutex; + bool _isRunning; + + friend class EventIOProcessor; }; #ifdef BUILD_AS_PLUGINS |