diff options
64 files changed, 965 insertions, 230 deletions
@@ -1,16 +1,12 @@ # uSCXML ReadMe -uSCXML is a SCXML interpreter written in C/C++. It is mostly feature-complete and -[standards compliant](https://github.com/tklab-tud/uscxml#test-reports) to a large extend. -It runs on <b>Linux</b>, <b>Windows</b> and <b>MacOSX</b>, each 32- as well as 64Bits. -There are still a few rough edges, especially with the plugins and custom extensions. - -The latest release will also compile for <b>iOS</b> using the toolchain files in <tt>contrib/cmake/</tt> -it features the (still experimental) JavaScriptCore ecmascript datamodel and no prolog datamodel. I will -work on the Android version as soon as I have some time at my hands. +uSCXML is a SCXML interpreter written in C/C++. It is mostly feature-complete and to a large extend +[standards compliant](https://github.com/tklab-tud/uscxml#test-reports). +It runs on <b>Linux</b>, <b>Windows</b> and <b>MacOSX</b>, each 32- as well as 64Bits as well as <b>iOS</b>. +There are still a few rough edges though, especially with the plugins and custom extensions. * <b>Datamodels</b> - * Full [ECMAScript datamodel](https://github.com/tklab-tud/uscxml/tree/master/src/uscxml/plugins/datamodel/ecmascript) using Google's v8 and JavaScriptCore (JSC is somewhat experimental) + * Full [ECMAScript datamodel](https://github.com/tklab-tud/uscxml/tree/master/src/uscxml/plugins/datamodel/ecmascript) using Google's v8 (and JavaScriptCore on MacOSX and iOS) * Full [NULL datamodel](https://github.com/tklab-tud/uscxml/tree/master/src/uscxml/plugins/datamodel/null) with required <tt>In</tt> predicate * Early [Prolog datamodel](https://github.com/tklab-tud/uscxml/tree/master/src/uscxml/plugins/datamodel/prolog/swi) using SWI prolog * Rudimentary support for [XPath datamodel](https://github.com/tklab-tud/uscxml/tree/master/src/uscxml/plugins/datamodel/xpath) @@ -35,13 +31,19 @@ work on the Android version as soon as I have some time at my hands. * We continuously run the [W3C IRP tests](http://www.w3.org/Voice/2013/scxml-irp/) for SCXML. * Have a look at the [result](http://uscxml.tk.informatik.tu-darmstadt.de/cdash/index.php?project=uscxml) for the various platforms. - * The manual tests are [excluded](https://github.com/tklab-tud/uscxml/blob/master/contrib/ctest/CTestCustom.ctest.in). + * The manual and XPath specific tests are [excluded](https://github.com/tklab-tud/uscxml/blob/master/contrib/ctest/CTestCustom.ctest.in). uSCXML still fails the following ecmascript tests: <table> <tr><th>Test#</th><th>Status</th><th>Description</th><th>Comment</th></tr> <tr> + <td><tt><a href="https://github.com/tklab-tud/uscxml/blob/master/test/samples/w3c/ecma/test159.scxml">159</a></tt></td> + <td><tt>Failed</tt></td> + <td>"If the processing of an element of executable content causes an error to be raised, the processor MUST NOT process the remaining elements of the block."</td> + <td>uSCXML continues processing the rest of the block as if there was no error.</td> + </tr> + <tr> <td><tt><a href="https://github.com/tklab-tud/uscxml/blob/master/test/samples/w3c/ecma/test301.scxml">301</a></tt></td> <td><tt>Failed</tt></td> <td>"the processor should reject this document because it can't download the script"</td> @@ -60,6 +62,18 @@ uSCXML still fails the following ecmascript tests: <td>"test that any attempt to change the value of a system variable causes error.execution to be raised"</td> <td>Same issue as above: we allow writing to <tt>_event</tt>.</td> </tr> + <tr> + <td> + <tt> + <a href="https://github.com/tklab-tud/uscxml/blob/master/test/samples/w3c/ecma/test519.scxml">519</a> + <a href="https://github.com/tklab-tud/uscxml/blob/master/test/samples/w3c/ecma/test520.scxml">520</a> + <a href="https://github.com/tklab-tud/uscxml/blob/master/test/samples/w3c/ecma/test531.scxml">531</a> + <a href="https://github.com/tklab-tud/uscxml/blob/master/test/samples/w3c/ecma/test534.scxml">534</a> + </tt></td> + <td><tt>Failed</tt></td> + <td></td> + <td>Tests contain non-standard ECMAScript.</td> + </tr> </table> ## License @@ -72,3 +86,68 @@ upon](https://github.com/tklab-tud/uscxml/blob/master/docs/BUILDING.md#build-dep We do not yet feature installers. Please download the source and have a look at the [build instructions](https://github.com/tklab-tud/uscxml/blob/master/docs/BUILDING.md). + +## Usage + +In order to use the interpreter, you need to <tt>#include "uscxml/Interpreter.h"</tt> and instantiate +objects of <tt>uscxml::Interpreter</tt>. + +### Blocking Interpretation with SCXML from URL + Interpreter scxml = Interpreter::fromURL("http://www.example.com/fancy.scxml"); + scxml.start(); // non-blocking + +There are some cases, i.e. with graphical invokers, where the main thread is <emph>required</emph> in order +to react to UI events. You will have to deligate control flow from the main thread into the interpreter +every now and then: + + interpreter.runOnMainThread(25); + +This will perform a single iteration on the invoked components with a maximum of 25 frames per seconds +or return immediately. You will have to call this method every now and then if you are using e.g. the +<tt>scenegraph</tt> invoker. + +### Non-Blocking Interpretation with inline SCXML + Interpreter scxml = Interpreter::fromXML("<scxml><final id="exit"/></scxml>"); + scxml.interpret(); // blocking + +### Callbacks for an Interpreter + +You can register an <tt>InterpreterMonitor</tt> prior to start in order to receive +control-flow upon various events in the Interpreter. + + class StatusMonitor : public uscxml::InterpreterMonitor { + void onStableConfiguration(Interpreter) {} + void beforeCompletion(Interpreter) {} + void afterCompletion(Interpreter) {} + void beforeMicroStep(Interpreter) {} + void beforeTakingTransitions(Interpreter, const Arabica::XPath::NodeSet<std::string>&) {} + void beforeEnteringStates(Interpreter, const Arabica::XPath::NodeSet<std::string>&) {} + void afterEnteringStates(Interpreter) {} + void beforeExitingStates(Interpreter, const Arabica::XPath::NodeSet<std::string>&) {} + void afterExitingStates(Interpreter) {} + }; + + StatusMonitor statMon; + Interpreter scxml = Interpreter::fromXML("<scxml><final id="exit"/></scxml>"); + scxml.addMonitor(&statMon); + scxml.start(); + +This will cause the interpreter to invoke the callbacks from the monitor whenever the corresponding +internal phase is reached. + +## Extending uSCXML + +The uSCXML interpreter can be extended by introducing new + + 1. DataModels as embedded scripting languages (e.g. ECMAScript, Prolog and XPath) + 2. Invokers to represent external components that deliver and accept events (e.g. iCal, SceneGraph, DirectoryMonitor) + 3. I/O-Processors to provide communication with external systems (e.g. BasicHTTP, SCXML). + 4. Elements for Executable Content (e.g. <respond>, <fetch>, <postpone>). + +The basic approach to extend the interpreter is the same in all cases: + + 1. Write a class inheriting the abstract base class (e.g. <tt>DataModelImpl</tt>, <tt>InvokerImpl</tt>, <tt>IOProcessorImpl</tt>, <tt>ExecutableContentImpl</tt>). + 2. Instantiate your class and register it as a prototype at the <tt>Factory</tt> via one of its static <tt>register*</tt> methods. + 1. You can register at the global Factory Singleton via <tt>Factory::register*(prototypeInstance)</tt> + 2. Or provide a new Factory instance to selected interpreters as an in-between. + 3. Write an interpreter using your new functionality. diff --git a/contrib/ctest/CTestCustom.ctest.in b/contrib/ctest/CTestCustom.ctest.in index 098e4e2..e263147 100644 --- a/contrib/ctest/CTestCustom.ctest.in +++ b/contrib/ctest/CTestCustom.ctest.in @@ -7,6 +7,7 @@ # grep -ori 'datamodel="null' . # skip xpath datamodel tests +# these are manual or xpath tests generated by the ecma generator set(CTEST_CUSTOM_TESTS_IGNORE "ecma/test178.scxml" "ecma/test230.scxml" @@ -14,6 +15,37 @@ set(CTEST_CUSTOM_TESTS_IGNORE "ecma/test307.scxml" "ecma/test313.scxml" "ecma/test314.scxml" + "ecma/test415.scxml" + "ecma/test463.scxml" + "ecma/test464.scxml" + "ecma/test465.scxml" + "ecma/test466.scxml" + "ecma/test467.scxml" + "ecma/test468.scxml" + "ecma/test469.scxml" + "ecma/test470.scxml" + "ecma/test473.scxml" + "ecma/test474.scxml" + "ecma/test475.scxml" + "ecma/test476.scxml" + "ecma/test477.scxml" + "ecma/test478.scxml" + "ecma/test479.scxml" + "ecma/test480.scxml" + "ecma/test481.scxml" + "ecma/test482.scxml" + "ecma/test483.scxml" + "ecma/test537.scxml" + "ecma/test539.scxml" + "ecma/test540.scxml" + "ecma/test542.scxml" + "ecma/test543.scxml" + "ecma/test544.scxml" + "ecma/test546.scxml" + "ecma/test547.scxml" + "ecma/test555.scxml" + "ecma/test568.scxml" + ) diff --git a/contrib/dom/idl/SCXMLEvent.idl b/contrib/dom/idl/SCXMLEvent.idl index fbb7661..67f5070 100644 --- a/contrib/dom/idl/SCXMLEvent.idl +++ b/contrib/dom/idl/SCXMLEvent.idl @@ -7,7 +7,7 @@ const unsigned short EXTERNAL = 2; const unsigned short PLATFORM = 3; - [CustomGetter, EmptyAsNull] readonly attribute DOMString eventType; + [CustomGetter, EmptyAsNull] readonly attribute DOMString type; readonly attribute DOMString name; [EmptyAsNull] readonly attribute DOMString origin; [EmptyAsNull] readonly attribute DOMString origintype; diff --git a/src/bindings/swig/java/JavaDataModel.h b/src/bindings/swig/java/JavaDataModel.h index 5d76480..ca503d1 100644 --- a/src/bindings/swig/java/JavaDataModel.h +++ b/src/bindings/swig/java/JavaDataModel.h @@ -62,7 +62,7 @@ public: } virtual void assign(const Arabica::DOM::Element<std::string>& assignElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content) { // convert XML back into strings std::string location; @@ -72,9 +72,9 @@ public: std::ostringstream ssAssign; ssAssign << assignElem; std::string tmp; - if (doc) { + if (node) { std::ostringstream ssContent; - ssContent << doc; + ssContent << node; tmp = ssContent.str(); } else { tmp = content; @@ -89,7 +89,7 @@ public: // this is assign the function exposed to java virtual void init(const Arabica::DOM::Element<std::string>& dataElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content) { // convert XML back into strings std::string location; @@ -100,9 +100,9 @@ public: if (dataElem) ssData << dataElem; std::string tmp; - if (doc) { + if (node) { std::ostringstream ssContent; - ssContent << doc; + ssContent << node; tmp = ssContent.str(); } else { tmp = content; diff --git a/src/bindings/swig/php/uscxmlNativePHP.php b/src/bindings/swig/php/uscxmlNativePHP.php index 6e4823a..358975a 100644 --- a/src/bindings/swig/php/uscxmlNativePHP.php +++ b/src/bindings/swig/php/uscxmlNativePHP.php @@ -2,7 +2,7 @@ /* ---------------------------------------------------------------------------- * This file was automatically generated by SWIG (http://www.swig.org). - * Version 2.0.7 + * Version 2.0.9 * * This file is not intended to be easily readable and contains a number of * coding conventions designed to improve portability and efficiency. Do not make @@ -423,14 +423,6 @@ class Event { Event_setDOM($this->_cPtr,$dom); } - static function getFirstDOMElement($self_or_dom) { - return Event_getFirstDOMElement($self_or_dom); - } - - static function getStrippedDOM($self_or_dom) { - return Event_getStrippedDOM($self_or_dom); - } - function getRaw() { return Event_getRaw($this->_cPtr); } diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp index bc23e53..1494dff 100644 --- a/src/uscxml/Factory.cpp +++ b/src/uscxml/Factory.cpp @@ -352,7 +352,9 @@ boost::shared_ptr<InvokerImpl> Factory::createInvoker(const std::string& type, I if (_invokerAliases.find(type) != _invokerAliases.end()) { std::string canonicalName = _invokerAliases[type]; if (_invokers.find(canonicalName) != _invokers.end()) { - return _invokers[canonicalName]->create(interpreter); + boost::shared_ptr<InvokerImpl> invoker = _invokers[canonicalName]->create(interpreter); + invoker->setInterpreter(interpreter); + return invoker; } } @@ -372,7 +374,9 @@ boost::shared_ptr<DataModelImpl> Factory::createDataModel(const std::string& typ if (_dataModelAliases.find(type) != _dataModelAliases.end()) { std::string canonicalName = _dataModelAliases[type]; if (_dataModels.find(canonicalName) != _dataModels.end()) { - return _dataModels[canonicalName]->create(interpreter); + boost::shared_ptr<DataModelImpl> dataModel = _dataModels[canonicalName]->create(interpreter); + dataModel->setInterpreter(interpreter); + return dataModel; } } @@ -391,7 +395,9 @@ boost::shared_ptr<IOProcessorImpl> Factory::createIOProcessor(const std::string& if (_ioProcessorAliases.find(type) != _ioProcessorAliases.end()) { std::string canonicalName = _ioProcessorAliases[type]; if (_ioProcessors.find(canonicalName) != _ioProcessors.end()) { - return _ioProcessors[canonicalName]->create(interpreter); + boost::shared_ptr<IOProcessorImpl> ioProc = _ioProcessors[canonicalName]->create(interpreter); + ioProc->setInterpreter(interpreter); + return ioProc; } } @@ -399,7 +405,7 @@ boost::shared_ptr<IOProcessorImpl> Factory::createIOProcessor(const std::string& if (_parentFactory) { return _parentFactory->createIOProcessor(type, interpreter); } else { - LOG(ERROR) << "No " << type << " Datamodel known"; + LOG(ERROR) << "No " << type << " IOProcessor known"; } return boost::shared_ptr<IOProcessorImpl>(); @@ -409,7 +415,8 @@ boost::shared_ptr<ExecutableContentImpl> Factory::createExecutableContent(const // do we have this type in this factory? std::string actualNameSpace = (nameSpace.length() == 0 ? "http://www.w3.org/2005/07/scxml" : nameSpace); if (_executableContent.find(std::make_pair(localName, actualNameSpace)) != _executableContent.end()) { - return _executableContent[std::make_pair(localName, actualNameSpace)]->create(interpreter); + boost::shared_ptr<ExecutableContentImpl> execContent = _executableContent[std::make_pair(localName, actualNameSpace)]->create(interpreter); + execContent->setInterpreter(interpreter); } // lookup in parent factory diff --git a/src/uscxml/Factory.h b/src/uscxml/Factory.h index 0432f34..b815712 100644 --- a/src/uscxml/Factory.h +++ b/src/uscxml/Factory.h @@ -52,7 +52,9 @@ public: } virtual std::string getLocalName() = 0; ///< The name of the element. - virtual std::string getNamespace() = 0; ///< The namespace of the element. + virtual std::string getNamespace() { + return "http://www.w3.org/2005/07/scxml"; ///< The namespace of the element. + } virtual void enterElement(const Arabica::DOM::Node<std::string>& node) = 0; ///< Invoked when entering the element as part of evaluating executable content. virtual void exitElement(const Arabica::DOM::Node<std::string>& node) = 0; ///< Invoked when exiting the element as part of evaluating executable content. virtual bool processChildren() = 0; ///< Whether or not the interpreter should process this elements children. @@ -283,15 +285,19 @@ public: virtual bool isDeclared(const std::string& expr) = 0; virtual void assign(const Arabica::DOM::Element<std::string>& assignElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content) = 0; virtual void assign(const std::string& location, const Data& data) = 0; virtual void init(const Arabica::DOM::Element<std::string>& dataElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content) = 0; virtual void init(const std::string& location, const Data& data) = 0; + virtual void setInterpreter(InterpreterImpl* interpreter) { + _interpreter = interpreter; + } + // we need it public for various static functions InterpreterImpl* _interpreter; }; @@ -358,18 +364,18 @@ public: } virtual void assign(const Arabica::DOM::Element<std::string>& assignElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content) { - return _impl->assign(assignElem, doc, content); + return _impl->assign(assignElem, node, content); } virtual void assign(const std::string& location, const Data& data) { return _impl->assign(location, data); } virtual void init(const Arabica::DOM::Element<std::string>& dataElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content) { - return _impl->init(dataElem, doc, content); + return _impl->init(dataElem, node, content); } virtual void init(const std::string& location, const Data& data) { return _impl->init(location, data); @@ -383,6 +389,10 @@ public: return _impl->replaceExpressions(content); } + virtual void setInterpreter(InterpreterImpl* interpreter) { + _impl->setInterpreter(interpreter); + } + protected: boost::shared_ptr<DataModelImpl> _impl; }; diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 6b17d94..4015026 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -174,7 +174,7 @@ void InterpreterImpl::setNameSpaceInfo(const std::map<std::string, std::string> if (boost::iequals(uri, "http://www.w3.org/2005/07/scxml")) { _nsURL = uri; if (prefix.size() == 0) { - LOG(INFO) << "Mapped default namespace to 'scxml:'"; +// LOG(INFO) << "Mapped default namespace to 'scxml:'"; _xpathPrefix = "scxml:"; _nsContext.addNamespaceDeclaration(uri, "scxml"); _nsToPrefix[uri] = "scxml"; @@ -203,11 +203,12 @@ void InterpreterImpl::setName(const std::string& name) { InterpreterImpl::~InterpreterImpl() { _running = false; - tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); +// tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); if (_thread) { // unblock event queue Event event; - _externalQueue.push(event); + event.name = "unblock.and.die"; + receive(event); _thread->join(); delete(_thread); } @@ -327,7 +328,7 @@ void InterpreterImpl::initializeData(const Element<std::string>& data) { } try { - Arabica::DOM::Document<std::string> dom; + Arabica::DOM::Node<std::string> dom; std::string text; processDOMorText(data, dom, text); _dataModel.init(data, dom, text); @@ -401,6 +402,7 @@ void InterpreterImpl::normalize(Arabica::DOM::Element<std::string>& scxml) { void InterpreterImpl::receiveInternal(const Event& event) { std::cout << _name << " receiveInternal: " << event.name << std::endl; _internalQueue.push_back(event); +// _condVar.notify_all(); } void InterpreterImpl::receive(const Event& event, bool toFront) { @@ -410,6 +412,7 @@ void InterpreterImpl::receive(const Event& event, bool toFront) { } else { _externalQueue.push(event); } + _condVar.notify_all(); } void InterpreterImpl::internalDoneSend(const Arabica::DOM::Node<std::string>& state) { @@ -448,7 +451,7 @@ void InterpreterImpl::internalDoneSend(const Arabica::DOM::Node<std::string>& st } void InterpreterImpl::processContentElement(const Arabica::DOM::Node<std::string>& content, - Arabica::DOM::Document<std::string>& dom, + Arabica::DOM::Node<std::string>& dom, std::string& text, std::string& expr) { if (HAS_ATTR(content, "expr")) { @@ -460,16 +463,16 @@ void InterpreterImpl::processContentElement(const Arabica::DOM::Node<std::string } } -void InterpreterImpl::processDOMorText(const Arabica::DOM::Node<std::string>& node, - Arabica::DOM::Document<std::string>& dom, +void InterpreterImpl::processDOMorText(const Arabica::DOM::Node<std::string>& element, + Arabica::DOM::Node<std::string>& dom, std::string& text) { // do we need to download? - if (HAS_ATTR(node, "src") || - (HAS_ATTR(node, "srcexpr") && _dataModel)) { + if (HAS_ATTR(element, "src") || + (HAS_ATTR(element, "srcexpr") && _dataModel)) { std::stringstream srcContent; - URL sourceURL(HAS_ATTR(node, "srcexpr") ? _dataModel.evalAsString(ATTR(node, "srcexpr")) : ATTR(node, "src")); + URL sourceURL(HAS_ATTR(element, "srcexpr") ? _dataModel.evalAsString(ATTR(element, "srcexpr")) : ATTR(element, "src")); if (!sourceURL.toAbsolute(_baseURI)) { - LOG(ERROR) << LOCALNAME(node) << " element has relative src or srcexpr URI with no baseURI set."; + LOG(ERROR) << LOCALNAME(element) << " element has relative src or srcexpr URI with no baseURI set."; return; } if (_cachedURLs.find(sourceURL.asString()) != _cachedURLs.end() && false) { @@ -477,14 +480,14 @@ void InterpreterImpl::processDOMorText(const Arabica::DOM::Node<std::string>& no } else { srcContent << sourceURL; if (sourceURL.downloadFailed()) { - LOG(ERROR) << LOCALNAME(node) << " source cannot be downloaded"; + LOG(ERROR) << LOCALNAME(element) << " source cannot be downloaded"; return; } _cachedURLs[sourceURL.asString()] = sourceURL; } if (srcContent.str().length() > 0) { // try to parse as XML - Arabica::SAX2DOM::Parser<std::string> parser; + NameSpacingParser parser; std::stringstream* ss = new std::stringstream(); (*ss) << srcContent.str(); std::auto_ptr<std::istream> ssPtr(ss); @@ -494,45 +497,68 @@ void InterpreterImpl::processDOMorText(const Arabica::DOM::Node<std::string>& no // parser.setFeature(Arabica::SAX::FeatureNames<std::string>().external_general, true); if (parser.parse(inputSource) && parser.getDocument()) { - dom = parser.getDocument(); - //std::cout << dom; - Node<std::string> content = dom.getDocumentElement(); + Document<std::string> doc = parser.getDocument(); + dom = doc.getDocumentElement(); +#if 0 + Node<std::string> content = doc.getDocumentElement(); assert(content.getNodeType() == Node_base::ELEMENT_NODE); - Node<std::string> container = dom.createElement("container"); + Node<std::string> container = doc.createElement("container"); dom.replaceChild(container, content); container.appendChild(content); // std::cout << dom << std::endl; +#endif return; } else { + if (parser.errorsReported()) { + LOG(ERROR) << parser.errors(); + } text = srcContent.str(); return; } } } - if (!node.hasChildNodes()) + if (!element.hasChildNodes()) return; - Node<std::string> child = node.getFirstChild(); - while(child) { - if (child.getNodeType() == Node_base::TEXT_NODE || child.getNodeType() == Node_base::CDATA_SECTION_NODE) { + /** + * Figure out whether the given element contains text, has one child or many childs + */ + bool hasTextContent = false; + bool hasOneChild = false; + Node<std::string> theOneChild; + bool hasManyChilds = false; + + Node<std::string> child = element.getFirstChild(); + while (child) { +// std::cout << child.getNodeType() << std::endl; + if (child.getNodeType() == Node_base::TEXT_NODE || + child.getNodeType() == Node_base::CDATA_SECTION_NODE) { std::string trimmed = child.getNodeValue(); boost::trim(trimmed); - if (trimmed.length() > 0) + if (trimmed.length() > 0) { + hasTextContent = true; + } + } else { + if (hasOneChild) { + hasManyChilds = true; + hasOneChild = false; break; - } - if (child.getNodeType() == Node_base::ELEMENT_NODE) { - break; + } + hasOneChild = true; + theOneChild = child; } child = child.getNextSibling(); } - if (child && child.getNodeType() == Node_base::ELEMENT_NODE) { - DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); - dom = domFactory.createDocument(child.getNamespaceURI(), "", 0); - // we need to import the parent - to support xpath test150 - Node<std::string> newNode = dom.importNode(child.getParentNode(), true); - dom.appendChild(newNode); - } else if(child && (child.getNodeType() == Node_base::TEXT_NODE || child.getNodeType() == Node_base::CDATA_SECTION_NODE)) { + + if (hasOneChild) { + // if we have a single child, it will be the content of the dom + dom = theOneChild; + } else if (hasManyChilds) { + // if we have multiple childs + dom = element; + } else if(hasTextContent) { + child = element.getFirstChild(); while(child) { if ((child.getNodeType() == Node_base::TEXT_NODE || child.getNodeType() == Node_base::CDATA_SECTION_NODE)) { text += child.getNodeValue(); @@ -540,7 +566,7 @@ void InterpreterImpl::processDOMorText(const Arabica::DOM::Node<std::string>& no child = child.getNextSibling(); } } else { - LOG(ERROR) << LOCALNAME(node) << " has neither text nor element children."; + LOG(ERROR) << LOCALNAME(element) << " has neither text nor element children."; } } @@ -1123,7 +1149,7 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node<std::string>& cont LOG(ERROR) << "Assigning to undeclared location '" << ATTR(content, "location") << "' not allowed." << std::endl; throw Event("error.execution", Event::PLATFORM); } else { - Document<std::string> dom; + Node<std::string> dom; std::string text; processDOMorText(content, dom, text); _dataModel.assign(Element<std::string>(content), dom, text); @@ -1188,7 +1214,10 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node<std::string>& cont } } else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "send")) { // --- SEND -------------------------- - send(content); + try { + send(content); + } + CATCH_AND_DISTRIBUTE("Error while sending content") } else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "cancel")) { // --- CANCEL -------------------------- std::string sendId; diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index f8cf823..d2c9025 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -251,6 +251,7 @@ protected: bool _stable; tthread::thread* _thread; tthread::recursive_mutex _mutex; + tthread::condition_variable _condVar; tthread::recursive_mutex _pluginMutex; URL _baseURI; @@ -291,13 +292,13 @@ protected: void executeContent(const Arabica::XPath::NodeSet<std::string>& content, bool rethrow = false); void processContentElement(const Arabica::DOM::Node<std::string>& element, - Arabica::DOM::Document<std::string>& dom, + Arabica::DOM::Node<std::string>& dom, std::string& text, std::string& expr); void processParamChilds(const Arabica::DOM::Node<std::string>& element, std::multimap<std::string, std::string>& params); - void processDOMorText(const Arabica::DOM::Node<std::string>& node, - Arabica::DOM::Document<std::string>& dom, + void processDOMorText(const Arabica::DOM::Node<std::string>& element, + Arabica::DOM::Node<std::string>& dom, std::string& text); void send(const Arabica::DOM::Node<std::string>& element); diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp index ddb8996..f3f8c27 100644 --- a/src/uscxml/Message.cpp +++ b/src/uscxml/Message.cpp @@ -110,37 +110,37 @@ Arabica::DOM::Document<std::string> Data::toDocument() { return document; } -Arabica::DOM::Node<std::string> Event::getFirstDOMElement() const { - return getFirstDOMElement(dom); -} - -Arabica::DOM::Document<std::string> Event::getStrippedDOM() const { - return getStrippedDOM(dom); -} - -Arabica::DOM::Node<std::string> Event::getFirstDOMElement(const Arabica::DOM::Document<std::string> dom) { - Arabica::DOM::Node<std::string> data = dom.getDocumentElement().getFirstChild(); - while (data) { - if (data.getNodeType() == Arabica::DOM::Node_base::TEXT_NODE) { - std::string trimmed = boost::trim_copy(data.getNodeValue()); - if (trimmed.length() == 0) { - data = data.getNextSibling(); - continue; - } - } - break; - } - return data; -} - -Arabica::DOM::Document<std::string> Event::getStrippedDOM(const Arabica::DOM::Document<std::string> dom) { - Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); - Arabica::DOM::Document<std::string> document = domFactory.createDocument("", "", 0); - if (dom) { - document.getDocumentElement().appendChild(document.importNode(getFirstDOMElement(dom), true)); - } - return document; -} +//Arabica::DOM::Node<std::string> Event::getFirstDOMElement() const { +// return getFirstDOMElement(dom); +//} +// +//Arabica::DOM::Document<std::string> Event::getStrippedDOM() const { +// return getStrippedDOM(dom); +//} + +//Arabica::DOM::Node<std::string> Event::getFirstDOMElement(const Arabica::DOM::Document<std::string> dom) { +// Arabica::DOM::Node<std::string> data = dom.getDocumentElement().getFirstChild(); +// while (data) { +// if (data.getNodeType() == Arabica::DOM::Node_base::TEXT_NODE) { +// std::string trimmed = boost::trim_copy(data.getNodeValue()); +// if (trimmed.length() == 0) { +// data = data.getNextSibling(); +// continue; +// } +// } +// break; +// } +// return data; +//} +// +//Arabica::DOM::Document<std::string> Event::getStrippedDOM(const Arabica::DOM::Document<std::string> dom) { +// Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); +// Arabica::DOM::Document<std::string> document = domFactory.createDocument("", "", 0); +// if (dom) { +// document.getDocumentElement().appendChild(document.importNode(getFirstDOMElement(dom), true)); +// } +// return document; +//} Arabica::DOM::Document<std::string> Event::toDocument() { Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index 1e7a7ca..afc536f 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -158,17 +158,18 @@ public: this->origintype = originType; } - Arabica::DOM::Document<std::string> getDOM() { + Arabica::DOM::Node<std::string> getDOM() { return dom; } - void setDOM(const Arabica::DOM::Document<std::string>& dom) { + void setDOM(const Arabica::DOM::Node<std::string>& dom) { this->dom = dom; } - Arabica::DOM::Node<std::string> getFirstDOMElement() const; - Arabica::DOM::Document<std::string> getStrippedDOM() const; - static Arabica::DOM::Node<std::string> getFirstDOMElement(const Arabica::DOM::Document<std::string> dom); - static Arabica::DOM::Document<std::string> getStrippedDOM(const Arabica::DOM::Document<std::string> dom); +// Arabica::DOM::Node<std::string> getFirstDOMElement() const; +// Arabica::DOM::Document<std::string> getStrippedDOM() const; +// +// static Arabica::DOM::Node<std::string> getFirstDOMElement(const Arabica::DOM::Document<std::string> dom); +// static Arabica::DOM::Document<std::string> getStrippedDOM(const Arabica::DOM::Document<std::string> dom); std::string getRaw() { return raw; @@ -239,7 +240,7 @@ protected: Type eventType; std::string origin; std::string origintype; - Arabica::DOM::Document<std::string> dom; + Arabica::DOM::Node<std::string> dom; std::string sendid; bool hideSendId; std::string invokeid; diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp index 4d60999..cefe935d 100644 --- a/src/uscxml/URL.cpp +++ b/src/uscxml/URL.cpp @@ -103,7 +103,7 @@ URLImpl::~URLImpl() { curl_easy_cleanup(_handle); } -URLImpl::operator Data() { +URLImpl::operator Data() const { Data data; data.compound["url"] = Data(asString(), Data::VERBATIM); data.compound["host"] = Data(_uri.host(), Data::VERBATIM); @@ -117,7 +117,7 @@ URLImpl::operator Data() { data.compound["statusMsg"] = Data(_statusMsg, Data::VERBATIM); - std::vector<std::string>::iterator pathIter = _pathComponents.begin(); + std::vector<std::string>::const_iterator pathIter = _pathComponents.begin(); while(pathIter != _pathComponents.end()) { data.compound["pathComponent"].array.push_back(Data(*pathIter, Data::VERBATIM)); pathIter++; diff --git a/src/uscxml/URL.h b/src/uscxml/URL.h index 3acd462..16c29c7 100644 --- a/src/uscxml/URL.h +++ b/src/uscxml/URL.h @@ -95,7 +95,7 @@ public: bool downloadFailed() { return _hasFailed; } - operator Data(); + operator Data() const; friend class URLFetcher; @@ -249,7 +249,7 @@ public: friend class URLFetcher; friend std::ostream & operator<<(std::ostream &stream, const URL& p); - operator Data() { + operator Data() const { return _impl->operator Data(); } diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index 881fa8b..e044fcf 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -9,7 +9,6 @@ using namespace Arabica::DOM; // see: http://www.w3.org/TR/scxml/#AlgorithmforSCXMLInterpretation void InterpreterDraft6::interpret() { -// _mutex.lock(); tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); if (!_isInitialized) init(); @@ -264,7 +263,11 @@ void InterpreterDraft6::mainEventLoop() { while(_externalQueue.isEmpty() && _thread == NULL) { runOnMainThread(200); } + _mutex.lock(); + while(_externalQueue.isEmpty()) { + _condVar.wait(_mutex); + } _currEvent = _externalQueue.pop(); #if VERBOSE std::cout << "Received externalEvent event " << _currEvent.name << std::endl; @@ -273,8 +276,6 @@ void InterpreterDraft6::mainEventLoop() { if (!_running) goto EXIT_INTERPRETER; - _mutex.lock(); - if (_dataModel && boost::iequals(_currEvent.name, "cancel.invoke." + _sessionId)) break; diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp index 712799c..c714735 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp @@ -3,6 +3,9 @@ #include "JSCDataModel.h" #include "JSCDOM.h" #include "dom/JSCDocument.h" +#include "dom/JSCElement.h" +#include "dom/JSCText.h" +#include "dom/JSCCDATASection.h" #include "dom/JSCSCXMLEvent.h" #include "uscxml/Message.h" @@ -12,6 +15,13 @@ #include <Pluma/Connector.hpp> #endif +#define TO_JSC_DOMVALUE(type) \ +struct JSC##type::JSC##type##Private* privData = new JSC##type::JSC##type##Private(); \ +privData->dom = _dom; \ +privData->nativeObj = new type<std::string>(node); \ +JSObjectRef retObj = JSObjectMake(_ctx, JSC##type::getTmpl(), privData);\ +return retObj; + namespace uscxml { using namespace Arabica::XPath; @@ -96,24 +106,24 @@ boost::shared_ptr<DataModelImpl> JSCDataModel::create(InterpreterImpl* interpret JSClassRef jsInvokerClassRef = JSClassCreate(&jsInvokersClassDef); JSObjectRef jsInvoker = JSObjectMake(dm->_ctx, jsInvokerClassRef, dm.get()); JSStringRef invokerName = JSStringCreateWithUTF8CString("_invokers"); - JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), invokerName, jsInvoker, kJSPropertyAttributeNone, NULL); + JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), invokerName, jsInvoker, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, NULL); JSStringRelease(invokerName); JSClassRef jsIOProcClassRef = JSClassCreate(&jsIOProcessorsClassDef); JSObjectRef jsIOProc = JSObjectMake(dm->_ctx, jsIOProcClassRef, dm.get()); JSStringRef ioProcName = JSStringCreateWithUTF8CString("_ioprocessors"); - JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), ioProcName, jsIOProc, kJSPropertyAttributeNone, NULL); + JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), ioProcName, jsIOProc, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, NULL); JSStringRelease(ioProcName); JSStringRef nameName = JSStringCreateWithUTF8CString("_name"); JSStringRef name = JSStringCreateWithUTF8CString(dm->_interpreter->getName().c_str()); - JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), nameName, JSValueMakeString(dm->_ctx, name), kJSPropertyAttributeNone, NULL); + JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), nameName, JSValueMakeString(dm->_ctx, name), kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, NULL); JSStringRelease(nameName); JSStringRelease(name); JSStringRef sessionIdName = JSStringCreateWithUTF8CString("_sessionid"); JSStringRef sessionId = JSStringCreateWithUTF8CString(dm->_interpreter->getSessionId().c_str()); - JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), sessionIdName, JSValueMakeString(dm->_ctx, sessionId), kJSPropertyAttributeNone, NULL); + JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), sessionIdName, JSValueMakeString(dm->_ctx, sessionId), kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, NULL); JSStringRelease(sessionIdName); JSStringRelease(sessionId); @@ -153,7 +163,7 @@ void JSCDataModel::setEvent(const Event& event) { if (event.dom) { JSStringRef propName = JSStringCreateWithUTF8CString("data"); - JSObjectSetProperty(_ctx, eventObj, propName, getDocumentAsValue(event.dom), 0, &exception); + JSObjectSetProperty(_ctx, eventObj, propName, getNodeAsValue(event.dom), 0, &exception); JSStringRelease(propName); if (exception) handleException(exception); @@ -342,8 +352,19 @@ bool JSCDataModel::validate(const std::string& location, const std::string& sche } uint32_t JSCDataModel::getLength(const std::string& expr) { -// LOG(ERROR) << "I am not sure whether getLength() works :("; - JSValueRef result = evalAsValue("(" + expr + ").length"); + JSValueRef result; + + result = evalAsValue("(" + expr + ").length"); + JSType type = JSValueGetType(_ctx, result); + if (type == kJSTypeNull || type == kJSTypeUndefined) { + Event exceptionEvent; + exceptionEvent.data.compound["exception"] = Data("'" + expr + "' does not evaluate to an array.", Data::VERBATIM); + exceptionEvent.name = "error.execution"; + exceptionEvent.eventType = Event::PLATFORM; + + throw(exceptionEvent); + } + JSValueRef exception = NULL; double length = JSValueToNumber(_ctx, result, &exception); if (exception) @@ -424,7 +445,7 @@ JSValueRef JSCDataModel::evalAsValue(const std::string& expr, bool dontThrow) { } void JSCDataModel::assign(const Element<std::string>& assignElem, - const Document<std::string>& doc, + const Node<std::string>& node, const std::string& content) { std::string key; JSValueRef exception = NULL; @@ -436,10 +457,20 @@ void JSCDataModel::assign(const Element<std::string>& assignElem, if (key.length() == 0) throw Event("error.execution", Event::PLATFORM); + // flags on attribute are ignored? + if (key.compare("_sessionid") == 0) + throw Event("error.execution", Event::PLATFORM); + if (key.compare("_name") == 0) + throw Event("error.execution", Event::PLATFORM); + if (key.compare("_ioprocessors") == 0) + throw Event("error.execution", Event::PLATFORM); + if (key.compare("_invokers") == 0) + throw Event("error.execution", Event::PLATFORM); + if (HAS_ATTR(assignElem, "expr")) { evalAsValue(key + " = " + ATTR(assignElem, "expr")); - } else if (doc) { - JSObjectSetProperty(_ctx, JSContextGetGlobalObject(_ctx), JSStringCreateWithUTF8CString(key.c_str()), getDocumentAsValue(doc), 0, &exception); + } else if (node) { + JSObjectSetProperty(_ctx, JSContextGetGlobalObject(_ctx), JSStringCreateWithUTF8CString(key.c_str()), getNodeAsValue(node), 0, &exception); if (exception) handleException(exception); } else if (content.size() > 0) { @@ -455,15 +486,24 @@ void JSCDataModel::assign(const Element<std::string>& assignElem, } } -JSValueRef JSCDataModel::getDocumentAsValue(const Document<std::string>& doc) { - - struct JSCDocument::JSCDocumentPrivate* retPrivData = new JSCDocument::JSCDocumentPrivate(); - retPrivData->dom = _dom; - retPrivData->nativeObj = new Document<std::string>(doc); - - JSObjectRef retObj = JSObjectMake(_ctx, JSCDocument::getTmpl(), retPrivData); - - return retObj; +JSValueRef JSCDataModel::getNodeAsValue(const Node<std::string>& node) { + switch (node.getNodeType()) { + case Node_base::ELEMENT_NODE: { + TO_JSC_DOMVALUE(Element); + } + case Node_base::TEXT_NODE: { + TO_JSC_DOMVALUE(Text); + } + case Node_base::CDATA_SECTION_NODE: { + TO_JSC_DOMVALUE(CDATASection); + } + case Node_base::DOCUMENT_NODE: { + TO_JSC_DOMVALUE(Document); + } + default: { + TO_JSC_DOMVALUE(Node); + } + } } void JSCDataModel::assign(const std::string& location, const Data& data) { @@ -473,10 +513,10 @@ void JSCDataModel::assign(const std::string& location, const Data& data) { } void JSCDataModel::init(const Element<std::string>& dataElem, - const Document<std::string>& doc, + const Node<std::string>& node, const std::string& content) { try { - assign(dataElem, doc, content); + assign(dataElem, node, content); } catch (Event e) { // test 277 std::string key; diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h index f7360d4..9bb3034 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h @@ -50,12 +50,12 @@ public: virtual bool isDeclared(const std::string& expr); virtual void assign(const Arabica::DOM::Element<std::string>& assignElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content); virtual void assign(const std::string& location, const Data& data); virtual void init(const Arabica::DOM::Element<std::string>& dataElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content); virtual void init(const std::string& location, const Data& data); @@ -77,7 +77,7 @@ protected: static JSValueRef jsInvokerGetProp(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception); static void jsInvokerListProps(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames); - JSValueRef getDocumentAsValue(const Arabica::DOM::Document<std::string>& doc); + JSValueRef getNodeAsValue(const Arabica::DOM::Node<std::string>& node); JSValueRef getDataAsValue(const Data& data); Data getValueAsData(const JSValueRef value); JSValueRef evalAsValue(const std::string& expr, bool dontThrow = false); diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCSCXMLEvent.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCSCXMLEvent.cpp index 579012b..de3a93f 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCSCXMLEvent.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCSCXMLEvent.cpp @@ -7,7 +7,7 @@ namespace DOM { JSClassRef JSCSCXMLEvent::Tmpl; JSStaticValue JSCSCXMLEvent::staticValues[] = { - { "eventType", eventTypeCustomAttrGetter, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly }, + { "type", typeCustomAttrGetter, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly }, { "name", nameAttrGetter, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly }, { "origin", originAttrGetter, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly }, { "origintype", origintypeAttrGetter, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly }, diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCSCXMLEvent.h b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCSCXMLEvent.h index d3a25d5..5ac8ccb 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCSCXMLEvent.h +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCSCXMLEvent.h @@ -39,7 +39,7 @@ public: JSC_DESTRUCTOR(JSCSCXMLEventPrivate); - static JSValueRef eventTypeCustomAttrGetter(JSContextRef ctx, JSObjectRef thisObj, JSStringRef propertyName, JSValueRef* exception); + static JSValueRef typeCustomAttrGetter(JSContextRef ctx, JSObjectRef thisObj, JSStringRef propertyName, JSValueRef* exception); static JSValueRef nameAttrGetter(JSContextRef ctx, JSObjectRef thisObj, JSStringRef propertyName, JSValueRef* exception); static JSValueRef originAttrGetter(JSContextRef ctx, JSObjectRef thisObj, JSStringRef propertyName, JSValueRef* exception); static JSValueRef origintypeAttrGetter(JSContextRef ctx, JSObjectRef thisObj, JSStringRef propertyName, JSValueRef* exception); diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCSCXMLEventCustom.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCSCXMLEventCustom.cpp index 0209467..e197796 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCSCXMLEventCustom.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/dom/JSCSCXMLEventCustom.cpp @@ -3,7 +3,7 @@ namespace Arabica { namespace DOM { -JSValueRef JSCSCXMLEvent::eventTypeCustomAttrGetter(JSContextRef ctx, JSObjectRef thisObj, JSStringRef propertyName, JSValueRef* exception) { +JSValueRef JSCSCXMLEvent::typeCustomAttrGetter(JSContextRef ctx, JSObjectRef thisObj, JSStringRef propertyName, JSValueRef* exception) { struct JSCSCXMLEventPrivate* privData = (struct JSCSCXMLEventPrivate*)JSObjectGetPrivate(thisObj); JSStringRef stringRef; diff --git a/src/uscxml/plugins/datamodel/ecmascript/Storage.cpp b/src/uscxml/plugins/datamodel/ecmascript/Storage.cpp index 9131784..b5bb474 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/Storage.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/Storage.cpp @@ -5,7 +5,7 @@ namespace uscxml { Storage::Storage(const std::string& filename) { _filename = filename; - std::cout << _filename << std::endl; +// std::cout << _filename << std::endl; std::fstream file; file.open(_filename.c_str(), std::ios_base::in); // read content into data diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index 017b2eb..ea112f1 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -4,6 +4,9 @@ #include "V8DOM.h" #include "dom/V8Document.h" #include "dom/V8Node.h" +#include "dom/V8Element.h" +#include "dom/V8Text.h" +#include "dom/V8CDATASection.h" #include "dom/V8SCXMLEvent.h" #include "uscxml/Message.h" @@ -13,6 +16,17 @@ #include <Pluma/Connector.hpp> #endif +#define TO_V8_DOMVALUE(type) \ +v8::Handle<v8::Function> retCtor = V8##type::getTmpl()->GetFunction();\ +v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance());\ +struct V8##type::V8##type##Private* retPrivData = new V8##type::V8##type##Private();\ +retPrivData->dom = _dom;\ +retPrivData->nativeObj = new type<std::string>(node);\ +retObj->SetInternalField(0, V8DOM::toExternal(retPrivData));\ +retObj.MakeWeak(0, V8##type::jsDestructor);\ +return retObj; + + namespace uscxml { using namespace Arabica::XPath; @@ -152,7 +166,7 @@ void V8DataModel::setEvent(const Event& event) { eventObj.MakeWeak(0, V8SCXMLEvent::jsDestructor); if (event.dom) { - eventObj->Set(v8::String::New("data"), getDocumentAsValue(event.dom)); + eventObj->Set(v8::String::New("data"), getNodeAsValue(event.dom)); } else if (event.content.length() > 0) { // _event.data is a string or JSON Data json = Data::fromJSON(event.content); @@ -268,18 +282,26 @@ Data V8DataModel::getValueAsData(const v8::Handle<v8::Value>& value, std::set<v8 return data; } -v8::Handle<v8::Value> V8DataModel::getDocumentAsValue(const Document<std::string>& doc) { - v8::Handle<v8::Function> retCtor = V8Document::getTmpl()->GetFunction(); - v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance()); - - struct V8Document::V8DocumentPrivate* retPrivData = new V8Document::V8DocumentPrivate(); - retPrivData->dom = _dom; - retPrivData->nativeObj = new Document<std::string>(doc); +v8::Handle<v8::Value> V8DataModel::getNodeAsValue(const Node<std::string>& node) { - retObj->SetInternalField(0, V8DOM::toExternal(retPrivData)); - retObj.MakeWeak(0, V8Document::jsDestructor); + switch (node.getNodeType()) { + case Node_base::ELEMENT_NODE: { + TO_V8_DOMVALUE(Element); + } + case Node_base::TEXT_NODE: { + TO_V8_DOMVALUE(Text); + } + case Node_base::CDATA_SECTION_NODE: { + TO_V8_DOMVALUE(CDATASection); + } + case Node_base::DOCUMENT_NODE: { + TO_V8_DOMVALUE(Document); + } + default: { + TO_V8_DOMVALUE(Node); + } + } - return retObj; } v8::Handle<v8::Value> V8DataModel::getDataAsValue(const Data& data) { @@ -459,7 +481,7 @@ double V8DataModel::evalAsNumber(const std::string& expr) { } void V8DataModel::assign(const Element<std::string>& assignElem, - const Document<std::string>& doc, + const Node<std::string>& node, const std::string& content) { v8::Locker locker; v8::HandleScope handleScope; @@ -477,8 +499,8 @@ void V8DataModel::assign(const Element<std::string>& assignElem, if (HAS_ATTR(assignElem, "expr")) { evalAsValue(key + " = " + ATTR(assignElem, "expr")); - } else if (doc) { - global->Set(v8::String::New(key.c_str()), getDocumentAsValue(doc)); + } else if (node) { + global->Set(v8::String::New(key.c_str()), getNodeAsValue(node)); } else if (content.size() > 0) { try { evalAsValue(key + " = " + content); @@ -502,7 +524,7 @@ void V8DataModel::assign(const std::string& location, } void V8DataModel::init(const Element<std::string>& dataElem, - const Document<std::string>& doc, + const Node<std::string>& doc, const std::string& content) { try { assign(dataElem, doc, content); @@ -536,7 +558,6 @@ void V8DataModel::init(const std::string& location, evalAsValue(location + " = undefined", true); throw e; } - } diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h index 9d17093..0dffa27 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h @@ -50,13 +50,13 @@ public: virtual void eval(const Arabica::DOM::Element<std::string>& scriptElem, const std::string& expr); virtual void assign(const Arabica::DOM::Element<std::string>& assignElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content); virtual void assign(const std::string& location, const Data& data); virtual void init(const Arabica::DOM::Element<std::string>& dataElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content); virtual void init(const std::string& location, const Data& data); @@ -87,7 +87,7 @@ protected: v8::Handle<v8::Value> evalAsValue(const std::string& expr, bool dontThrow = false); v8::Handle<v8::Value> getDataAsValue(const Data& data); - v8::Handle<v8::Value> getDocumentAsValue(const Arabica::DOM::Document<std::string>& doc); + v8::Handle<v8::Value> getNodeAsValue(const Arabica::DOM::Node<std::string>& node); void throwExceptionEvent(const v8::TryCatch& tryCatch); }; diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.h b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.h index 3c5e6ee..9cc4ad4 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.h +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEvent.h @@ -41,7 +41,7 @@ public: static bool hasInstance(v8::Handle<v8::Value>); - static v8::Handle<v8::Value> eventTypeCustomAttrGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info); + static v8::Handle<v8::Value> typeCustomAttrGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info); static v8::Handle<v8::Value> nameAttrGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info); static v8::Handle<v8::Value> originAttrGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info); static v8::Handle<v8::Value> origintypeAttrGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info); @@ -63,7 +63,7 @@ public: instance->SetInternalFieldCount(1); - instance->SetAccessor(v8::String::NewSymbol("eventType"), V8SCXMLEvent::eventTypeCustomAttrGetter, 0, + instance->SetAccessor(v8::String::NewSymbol("type"), V8SCXMLEvent::typeCustomAttrGetter, 0, v8::External::New(0), static_cast<v8::AccessControl>(v8::DEFAULT), static_cast<v8::PropertyAttribute>(v8::None)); instance->SetAccessor(v8::String::NewSymbol("name"), V8SCXMLEvent::nameAttrGetter, 0, v8::External::New(0), static_cast<v8::AccessControl>(v8::DEFAULT), static_cast<v8::PropertyAttribute>(v8::None)); diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEventCustom.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEventCustom.cpp index d02a4cb..a8870cc 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEventCustom.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLEventCustom.cpp @@ -3,7 +3,7 @@ namespace Arabica { namespace DOM { -v8::Handle<v8::Value> V8SCXMLEvent::eventTypeCustomAttrGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info) { +v8::Handle<v8::Value> V8SCXMLEvent::typeCustomAttrGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info) { v8::Local<v8::Object> self = info.Holder(); V8SCXMLEventPrivate* privData = V8DOM::toClassPtr<V8SCXMLEventPrivate >(self->GetInternalField(0)); diff --git a/src/uscxml/plugins/datamodel/null/NULLDataModel.h b/src/uscxml/plugins/datamodel/null/NULLDataModel.h index b86c01c..74d170f 100644 --- a/src/uscxml/plugins/datamodel/null/NULLDataModel.h +++ b/src/uscxml/plugins/datamodel/null/NULLDataModel.h @@ -42,12 +42,12 @@ public: virtual void popContext(); virtual void assign(const Arabica::DOM::Element<std::string>& assignElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content) {} virtual void assign(const std::string& location, const Data& data) {} virtual void init(const Arabica::DOM::Element<std::string>& dataElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content) {} virtual void init(const std::string& location, const Data& data) {} diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp index a72fc6c..07cba96 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp @@ -223,7 +223,8 @@ void SWIDataModel::setEvent(const Event& event) { if (event.dom) { std::stringstream dataInitStr; std::stringstream xmlDoc; - xmlDoc << event.getFirstDOMElement(); +// xmlDoc << event.getFirstDOMElement(); + xmlDoc << event.dom; domUrl = URL::toLocalFile(xmlDoc.str(), ".pl"); dataInitStr << "load_xml_file('" << domUrl.asLocalFile(".pl") << "', XML), copy_term(XML,DATA), assert(event(data(DATA)))"; PlCall(dataInitStr.str().c_str()); @@ -408,7 +409,7 @@ std::map<std::string, PlTerm> SWIDataModel::resolveAtoms(PlTerm& term, PlTerm& o } void SWIDataModel::assign(const Element<std::string>& assignElem, - const Document<std::string>& doc, + const Node<std::string>& node, const std::string& content) { SET_PL_CONTEXT std::string expr = content; @@ -435,15 +436,15 @@ void SWIDataModel::assign(const Element<std::string>& assignElem, URL domUrl; Data json; - if (!doc) + if (!node) json = Data::fromJSON(expr); - if (doc) { + if (node) { std::stringstream dataInitStr; std::stringstream xmlDoc; - Node<std::string> node = Event::getFirstDOMElement(doc); + Node<std::string> child = node; while(node) { - xmlDoc << node; - node = node.getNextSibling(); + xmlDoc << child; + child = node.getNextSibling(); } domUrl = URL::toLocalFile(xmlDoc.str(), ".pl"); if (boost::iequals(type, "retract")) @@ -488,9 +489,9 @@ void SWIDataModel::assign(const std::string& location, const Data& data) { } void SWIDataModel::init(const Element<std::string>& dataElem, - const Document<std::string>& doc, + const Node<std::string>& node, const std::string& content) { - assign(dataElem, doc, content); + assign(dataElem, node, content); } void SWIDataModel::init(const std::string& location, const Data& data) { assign(location, data); diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h index 123e938..0a26643 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h @@ -42,12 +42,12 @@ public: virtual void popContext(); virtual void assign(const Arabica::DOM::Element<std::string>& assignElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content); virtual void assign(const std::string& location, const Data& data); virtual void init(const Arabica::DOM::Element<std::string>& dataElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content); virtual void init(const std::string& location, const Data& data); diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp index 842c560..cb40890 100644 --- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp @@ -174,7 +174,8 @@ void XPathDataModel::setEvent(const Event& event) { eventDataElem.appendChild(textNode); } if (event.dom) { - Node<std::string> importedNode = _doc.importNode(event.getFirstDOMElement(), true); +// Node<std::string> importedNode = _doc.importNode(event.getFirstDOMElement(), true); + Node<std::string> importedNode = _doc.importNode(event.dom, true); eventDataElem.appendChild(importedNode); } @@ -370,7 +371,7 @@ double XPathDataModel::evalAsNumber(const std::string& expr) { } void XPathDataModel::assign(const Element<std::string>& assignElem, - const Document<std::string>& doc, + const Node<std::string>& node, const std::string& content) { std::string location; if (HAS_ATTR(assignElem, "id")) { @@ -399,9 +400,9 @@ void XPathDataModel::assign(const Element<std::string>& assignElem, } #endif NodeSet<std::string> nodeSet; - if (doc) { - if (doc.getDocumentElement()) { - Node<std::string> data = doc.getDocumentElement().getFirstChild(); + if (node) { + if (node) { + Node<std::string> data = node; while (data) { // do not add empty text as a node if (data.getNodeType() == Node_base::TEXT_NODE) { @@ -447,7 +448,7 @@ NodeSet<std::string> XPathDataModel::dataToNodeSet(const Data& data) { } void XPathDataModel::init(const Element<std::string>& dataElem, - const Document<std::string>& doc, + const Node<std::string>& node, const std::string& content) { std::string location; if (HAS_ATTR(dataElem, "id")) { @@ -458,9 +459,9 @@ void XPathDataModel::init(const Element<std::string>& dataElem, Element<std::string> container = _doc.createElement("data"); container.setAttribute("id", location); - if (doc) { - if (doc.getDocumentElement()) { - Node<std::string> data = doc.getDocumentElement().getFirstChild(); + if (node) { + if (node) { + Node<std::string> data = node; while (data) { Node<std::string> dataClone = _doc.importNode(data, true); container.appendChild(dataClone); @@ -504,10 +505,10 @@ void XPathDataModel::init(const Element<std::string>& dataElem, #if 0 nodeSet.push_back(container); #else - Node<std::string> node = container.getFirstChild(); - while(node) { - nodeSet.push_back(node); - node = node.getNextSibling(); + Node<std::string> child = container.getFirstChild(); + while(child) { + nodeSet.push_back(child); + child = child.getNextSibling(); } #endif _varResolver.setVariable(location, nodeSet); diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h index 240c62c..62ee439 100644 --- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h @@ -89,12 +89,12 @@ public: virtual void eval(const Arabica::DOM::Element<std::string>& scriptElem, const std::string& expr); virtual void assign(const Arabica::DOM::Element<std::string>& assignElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content); virtual void assign(const std::string& location, const Data& data); virtual void init(const Arabica::DOM::Element<std::string>& dataElem, - const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Node<std::string>& node, const std::string& content); virtual void init(const std::string& location, const Data& data); diff --git a/src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp b/src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp index 6403a80..477a788 100644 --- a/src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp +++ b/src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp @@ -258,8 +258,8 @@ void OpenALInvoker::invoke(const InvokeRequest& req) { throw std::string("openal error create context"); } - std::cout << boost::lexical_cast<std::string>(_alContext); - std::cout << boost::lexical_cast<std::string>(_alDevice); +// std::cout << boost::lexical_cast<std::string>(_alContext); +// std::cout << boost::lexical_cast<std::string>(_alDevice); // alcMakeContextCurrent(_alContext); // float listener[3] = {0,0,0}; diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp index 06141c3..090f1b3 100644 --- a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp +++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGInvoker.cpp @@ -49,11 +49,9 @@ void OSGInvoker::invoke(const InvokeRequest& req) { evTarget.addEventListener("DOMNodeRemoved", *this, false); evTarget.addEventListener("DOMAttrModified", *this, false); - Arabica::XPath::NodeSet<std::string> content = Interpreter::filterChildElements("content", req.dom); - std::set<std::string> validChilds; validChilds.insert("display"); - processChildren(validChilds, content[0]); + processChildren(validChilds, req.dom); } void OSGInvoker::runOnMainThread() { diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp index c697993..85c4b9c 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp @@ -35,7 +35,7 @@ Data USCXMLInvoker::getDataModelVariables() { } void USCXMLInvoker::send(const SendRequest& req) { - _invokedInterpreter.getImpl()->_externalQueue.push(req); + _invokedInterpreter.receive(req); } void USCXMLInvoker::cancel(const std::string sendId) { @@ -46,7 +46,12 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) { if (req.src.length() > 0) { _invokedInterpreter = Interpreter::fromURI(req.src); } else if (req.dom) { - _invokedInterpreter = Interpreter::fromDOM(req.dom); + Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); + Arabica::DOM::Document<std::string> dom = domFactory.createDocument(req.dom.getNamespaceURI(), "", 0); + // we need to import the parent - to support xpath test150 + Arabica::DOM::Node<std::string> newNode = dom.importNode(req.dom, true); + dom.appendChild(newNode); + _invokedInterpreter = Interpreter::fromDOM(dom); } else if (req.content.size() > 0) { _invokedInterpreter = Interpreter::fromXML(req.content); } else { @@ -73,7 +78,8 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) { /// test240 assumes that invoke request params will carry over to the datamodel _invokedInterpreter.getImpl()->setInvokeRequest(req); - _invokedInterpreter.getImpl()->start(); + _invokedInterpreter.start(); +// tthread::this_thread::sleep_for(tthread::chrono::seconds(1)); } else { /// test 530 _parentInterpreter->receive(Event("done.invoke." + _invokeId, Event::PLATFORM)); diff --git a/src/uscxml/plugins/invoker/vxml/VoiceXMLInvoker.cpp b/src/uscxml/plugins/invoker/vxml/VoiceXMLInvoker.cpp index ddca2eb..c0d3329 100644 --- a/src/uscxml/plugins/invoker/vxml/VoiceXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/vxml/VoiceXMLInvoker.cpp @@ -58,7 +58,8 @@ void VoiceXMLInvoker::send(const SendRequest& req) { // } // } // } - domSS << req.getFirstDOMElement(); +// domSS << req.getFirstDOMElement(); + domSS << req.dom; start.content = domSS.str(); _interpreter->getDataModel().replaceExpressions(start.content); diff --git a/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp index 059e7f5..acbf085 100644 --- a/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp @@ -88,7 +88,8 @@ bool XHTMLInvoker::httpRecvRequest(const HTTPServer::Request& req) { std::string content; std::stringstream ss; if (_invokeReq.dom) { - ss << _invokeReq.getFirstDOMElement(); +// ss << _invokeReq.getFirstDOMElement(); + ss << _invokeReq.dom; content = ss.str(); } else if(_invokeReq.data) { ss << _invokeReq.data; @@ -160,14 +161,16 @@ void XHTMLInvoker::reply(const SendRequest& req, const HTTPServer::Request& long if (req.dom) { std::stringstream ss; - Arabica::DOM::Node<std::string> content = req.dom.getDocumentElement(); +// Arabica::DOM::Node<std::string> content = req.dom.getDocumentElement(); + Arabica::DOM::Node<std::string> content = req.dom; if (content && boost::iequals(content.getLocalName(), "content")) { reply.headers["X-SCXML-Type"] = (HAS_ATTR(content, "type") ? ATTR(content, "type") : "replacechildren"); reply.headers["X-SCXML-XPath"] = (HAS_ATTR(content, "xpath") ? ATTR(content, "xpath") : "/html/body"); if (HAS_ATTR(content, "attr")) reply.headers["X-SCXML-Attr"] = ATTR(content, "attr"); } - ss << req.getFirstDOMElement(); +// ss << req.getFirstDOMElement(); + ss << req.dom; reply.content = ss.str(); reply.headers["Content-Type"] = "application/xml"; } else if (req.data) { diff --git a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp index 56e2523..90cebc3 100644 --- a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp @@ -255,6 +255,16 @@ void BasicHTTPIOProcessor::downloadCompleted(const URL& url) { std::map<std::string, std::pair<URL, SendRequest> >::iterator reqIter = _sendRequests.begin(); while(reqIter != _sendRequests.end()) { if (reqIter->second.first == url) { + // test 513 + std::string statusCode = url.getStatusCode(); + if (statusCode.length() > 0) { + std::string statusPrefix = statusCode.substr(0,1); + std::string statusRest = statusCode.substr(1); + Event event; + event.data = url; + event.name = "HTTP." + statusPrefix + "." + statusRest; + returnEvent(event); + } _sendRequests.erase(reqIter); return; } diff --git a/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp index 98d98e1..ac570c4 100644 --- a/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.cpp @@ -158,6 +158,7 @@ void SCXMLIOProcessor::send(const SendRequest& req) { LOG(ERROR) << "Not sure what to make of the target '" << reqCopy.target << "' - raising error" << std::endl; Event error("error.execution", Event::PLATFORM); error.sendid = reqCopy.sendid; + // test 159 still fails _interpreter->receiveInternal(error); } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a78c079..53ec38f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -109,9 +109,11 @@ foreach( W3C_TEST ${W3C_TESTS} ) if (NOT TEST_NAME MATCHES ".*sub.*") if (RUN_W3C_ECMA_TESTS AND TEST_NAME MATCHES "^ecma\\/.*") add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST}) + set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED") endif() if (RUN_W3C_XPATH_TESTS AND TEST_NAME MATCHES "^xpath\\/.*") add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST}) + set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED") endif() endif() endforeach() diff --git a/test/samples/uscxml/test-markup-passing.scxml b/test/samples/uscxml/test-markup-passing.scxml new file mode 100644 index 0000000..32866b1 --- /dev/null +++ b/test/samples/uscxml/test-markup-passing.scxml @@ -0,0 +1,54 @@ +<scxml binding="late" datamodel="ecmascript" + xmlns="http://www.w3.org/2005/07/scxml" + xmlns:foo="http://uscxml.tk.informatik.tu-darmstadt.de/foo.xsd"> + <!-- + embedded markup contains a single child + --> + <state id="markup-embedded-single"> + <datamodel> + <data id="markup"> + <root> + <child>1</child> + <foo:child>2</foo:child> + </root> + </data> + </datamodel> + <onentry> + <log label="markup-embedded-single" expr="markup.nodeName" /> + </onentry> + <transition cond="markup.nodeName === 'root'" target="markup-embedded-many" /> + </state> + + <!-- + embedded markup contains multiple childs + --> + <state id="markup-embedded-many"> + <datamodel> + <data id="markup"> + <root> + <child>1</child> + <foo:child>2</foo:child> + </root> + <root> + <child>1</child> + <foo:child>2</foo:child> + </root> + </data> + </datamodel> + <onentry> + <log label="markup-embedded-many" expr="markup.nodeName" /> + </onentry> + <transition cond="markup.nodeName === 'data'" target="markup-file" /> + </state> + + <state id="markup-file"> + <datamodel> + <data id="markup" src="test-markup.xml" /> + </datamodel> + <onentry> + <log label="markup-file" expr="markup.nodeName" /> + </onentry> + <transition cond="markup.nodeName === 'root'" target="exit" /> + </state> + <final id="exit" /> +</scxml>
\ No newline at end of file diff --git a/test/samples/uscxml/test-markup.xml b/test/samples/uscxml/test-markup.xml new file mode 100644 index 0000000..81da3d2 --- /dev/null +++ b/test/samples/uscxml/test-markup.xml @@ -0,0 +1,6 @@ +<root + xmlns="http://www.w3.org/2005/07/scxml" + xmlns:foo="http://uscxml.tk.informatik.tu-darmstadt.de/scenegraph.xsd"> + <child>1</child> + <foo:child>2</foo:child> +</root>
\ No newline at end of file diff --git a/test/samples/uscxml/test-scenegraph.scxml b/test/samples/uscxml/test-scenegraph.scxml index f0d1173..0efcd6d 100644 --- a/test/samples/uscxml/test-scenegraph.scxml +++ b/test/samples/uscxml/test-scenegraph.scxml @@ -23,17 +23,17 @@ </scenegraph:viewport> <scenegraph:viewport x="0" y="50%" width="50%" height="50%" id="scene3"> <scenegraph:rotation id="treeRotation" pitch="100deg" roll="3.15149rad" yaw="10deg"> - <scenegraph:node src="http://people.sc.fsu.edu/~jburkardt/data/obj/airboat.obj" /> + <scenegraph:node src="http://cs.iupui.edu/~aharris/webDesign/vrml/tree.wrl" /> </scenegraph:rotation> </scenegraph:viewport> <scenegraph:viewport x="50%" y="50%" width="50%" height="50%" id="scene4"> <scenegraph:translation x="0" y="0" z="0"> - <scenegraph:node src="http://people.sc.fsu.edu/~jburkardt/data/obj/airboat.obj" /> + <scenegraph:node src="scenegraph/HARD_MP_VAL_000.wrl" /> </scenegraph:translation> </scenegraph:viewport> <scenegraph:viewport x="50%" y="0" width="50%" height="50%" id="scene2"> <scenegraph:translation x="0" y="0" z="0"> - <scenegraph:node src="http://people.sc.fsu.edu/~jburkardt/data/obj/airboat.obj" /> + <scenegraph:node src="http://cs.iupui.edu/~aharris/mm/vrml4/house.wrl" /> </scenegraph:translation> </scenegraph:viewport> </scenegraph:display> diff --git a/test/samples/w3c/ecma/test159.scxml b/test/samples/w3c/ecma/test159.scxml index d144855..d7b7821 100644 --- a/test/samples/w3c/ecma/test159.scxml +++ b/test/samples/w3c/ecma/test159.scxml @@ -6,8 +6,8 @@ The send tag will raise an error so var1 should not be incremented. If it is fa <state id="s0"> <onentry> - <send event="thisWillFail" conf:illegaltarget=""/> - <conf:incrementId id="1"/> + <send event="thisWillFail" target="baz"/> + <assign location="Var1" expr="Var1 + 1"/> </onentry> <transition cond="Var1==1" target="fail"/> <transition target="pass"/> diff --git a/test/samples/w3c/ecma/test191.scxml b/test/samples/w3c/ecma/test191.scxml index a44856b..6e82274 100644 --- a/test/samples/w3c/ecma/test191.scxml +++ b/test/samples/w3c/ecma/test191.scxml @@ -22,7 +22,7 @@ pass, otherwise we fail. The timer insures that some event is generated and tha </content> </invoke> <transition event="childToParent" target="pass"/> - <transition event="*" target="pass"/> + <transition event="*" target="fail"/> </state> <final id="pass"><onentry><log label="Outcome" expr="'pass'"/></onentry></final> diff --git a/test/samples/w3c/ecma/test354.scxml b/test/samples/w3c/ecma/test354.scxml new file mode 100644 index 0000000..3a3c33b --- /dev/null +++ b/test/samples/w3c/ecma/test354.scxml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- test that event.data can be populated using both namelist, param and <content> +and that correct values are used --><scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance" initial="s0" version="1.0" datamodel="ecmascript"> +<datamodel> + <data id="Var1" expr="1"/> + <data id="Var2"/> + <data id="Var3"/> + </datamodel> + +<state id="s0"> + <onentry> + <send delay="5s" event="timeout"/> + <send event="event1" type="http://www.w3.org/TR/scxml/#SCXMLEventProcessor" namelist="Var1"> + <param name="param1" expr="2"/> + </send> + </onentry> + <transition event="event1" target="s1"> + <assign location="Var2" expr="_event.data.Var1"/> + <assign location="Var3" expr="_event.data.param1"/> + </transition> + <transition event="*" target="fail"> + </transition> + +</state> + +<state id="s1"> + + <transition cond="Var2==1" target="s2"/> + <transition target="fail"/> + </state> + +<state id="s2"> + <transition cond="Var3==2" target="s3"/> + <transition target="fail"/> + </state> + +<state id="s3"> + <onentry> + <send delay="5s" event="timeout"/> + <send event="event2"> + <content>foo</content> + </send> + </onentry> + <transition event="event2" cond="_event.data === 'foo'" target="pass"/> + <transition event="*" target="fail"/> + +</state> + + + <final id="pass"><onentry><log label="Outcome" expr="'pass'"/></onentry></final> + <final id="fail"><onentry><log label="Outcome" expr="'fail'"/></onentry></final> + +</scxml>
\ No newline at end of file diff --git a/test/samples/w3c/ecma/test415.scxml b/test/samples/w3c/ecma/test415.scxml new file mode 100644 index 0000000..159218b --- /dev/null +++ b/test/samples/w3c/ecma/test415.scxml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- Test that the state machine halts when it enters a top-level final state. Since + the initial state is a final state, this machine should halt immediately without + processing "event1" which is raised in the final state's on-entry handler. This + is a manual test since there is no platform-independent way to test that event1 + is not processed --><scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance" initial="final" version="1.0" datamodel="ecmascript"> + <final id="final"> + <onentry> + <raise event="event1"/> + </onentry> + </final> + +</scxml>
\ No newline at end of file diff --git a/test/samples/w3c/ecma/test483.scxml b/test/samples/w3c/ecma/test483.scxml new file mode 100644 index 0000000..0a1b236 --- /dev/null +++ b/test/samples/w3c/ecma/test483.scxml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- test that foreach works correctly, iterating over node set in document order. + This tests assertions 483-485 --><scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance" name="scxmltest" initial="s0" version="1.0" datamodel="xpath"> + <datamodel> + <data id="var1"> + <nodes xmlns=""> + <node/> + <node/> + <node/> + </nodes> + </data> + </datamodel> + +<state id="s0"> + <onentry> + <foreach array="$var1/nodes/node" item="item" index="pos"> + <assign location="$item" type="addattribute" attr="position" expr="$pos"/> + </foreach> + </onentry> + + <transition cond="$var1/nodes/node[1]/@position = 1 and $var1/nodes/node[2]/@position = 2 and $var1/nodes/node[3]/@position = 3" target="pass"/> + <transition target="fail"/> + </state> + +<final id="pass"><onentry><log label="Outcome" expr="'pass'"/></onentry></final> +<final id="fail"><onentry><log label="Outcome" expr="'fail'"/></onentry></final> + +</scxml>
\ No newline at end of file diff --git a/test/samples/w3c/ecma/test513.scxml b/test/samples/w3c/ecma/test513.scxml new file mode 100644 index 0000000..c26d498 --- /dev/null +++ b/test/samples/w3c/ecma/test513.scxml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- test that we get an HTTP success code back on successful delivery. To run this test, implementations +must support an extension to send: if the parameter httpResponse is present with value 'true', then when +the processor gets an http response code back, it must raise an event 'http.n1.nrest' where 'ni' is +the first digit of the response code and 'nrest' are the remaining digits--><scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance" initial="s0" datamodel="ecmascript" version="1.0"> + +<state id="s0" initial="s01"> + <datamodel> + <data id="Var1"/> + </datamodel> + + <onentry> + <send event="timeout" delay="30s"/> + </onentry> + <invoke type="http://www.w3.org/TR/scxml/"> + <content> + <!-- child script. Once we're running send childRunning to parent and include basicHTTPAccess URI --> + <scxml initial="child0" datamodel="ecmascript" version="1.0"> + <state id="child0"> + <onentry> + <send target="#_parent" event="childRunning"> + <param name="uri" expr="_ioprocessors['basichttp']['location']"/> + </send> + </onentry> + </state> + </scxml> + </content> + </invoke> + + <transition event="*" target="fail"/> + + <state id="s01"> + <!-- when we get the event from the child, extract the access uri and use + the basicHTTP event i/o processor to send it an event --> + <transition event="childRunning" target="s02"> + <assign location="Var1" expr="_event.data.uri"/> + <send event="test" targetexpr="Var1" httpResponse="true" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor"/> + </transition> + </state> + + <state id="s02"> + <!-- the child should send this back automatically. It does not need to take + any transition on the event --> + <transition event="HTTP.2" target="pass"/> + </state> + </state> + + <final id="pass"><onentry><log label="Outcome" expr="'pass'"/></onentry></final> + <final id="fail"><onentry><log label="Outcome" expr="'fail'"/></onentry></final> + +</scxml>
\ No newline at end of file diff --git a/test/samples/w3c/ecma/test528.scxml b/test/samples/w3c/ecma/test528.scxml index edeb367..f0e8911 100644 --- a/test/samples/w3c/ecma/test528.scxml +++ b/test/samples/w3c/ecma/test528.scxml @@ -6,8 +6,7 @@ <transition event="error.execution" target="s1"/> <transition event="done.state.s0" target="fail"/> - <transition event="done.state.s0" target="fail"> - </transition> + <transition event="done.state.s0" target="fail"/> <state id="s01"> <transition target="s02"/> diff --git a/test/samples/w3c/txml/test159.txml b/test/samples/w3c/txml/test159.txml index abf1925..b7245c0 100644 --- a/test/samples/w3c/txml/test159.txml +++ b/test/samples/w3c/txml/test159.txml @@ -11,7 +11,7 @@ The send tag will raise an error so var1 should not be incremented. If it is fa <state id="s0"> <onentry> <send event="thisWillFail" conf:illegaltarget=""/> - <conf:incrementId id="1"/> + <conf:incrementID id="1"/> </onentry> <transition conf:idVal="1=1" conf:targetfail=""/> <transition conf:targetpass=""/> diff --git a/test/samples/w3c/txml/test191.txml b/test/samples/w3c/txml/test191.txml index 60b44a9..6f42159 100644 --- a/test/samples/w3c/txml/test191.txml +++ b/test/samples/w3c/txml/test191.txml @@ -25,7 +25,7 @@ pass, otherwise we fail. The timer insures that some event is generated and tha </content> </invoke> <transition event="childToParent" conf:targetpass=""/> - <transition event="*" conf:targetpass=""/> + <transition event="*" conf:targetfail=""/> </state> <conf:pass/> diff --git a/test/samples/w3c/txml/test354.txml b/test/samples/w3c/txml/test354.txml new file mode 100644 index 0000000..d9e643a --- /dev/null +++ b/test/samples/w3c/txml/test354.txml @@ -0,0 +1,56 @@ +<?xml version="1.0"?> + +<!-- test that event.data can be populated using both namelist, param and <content> +and that correct values are used --> + +<scxml initial="s0" version="1.0" conf:datamodel="" xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance"> +<datamodel> + <data conf:id="1" expr="1"/> + <data conf:id="2"/> + <data conf:id="3"/> + </datamodel> + +<state id="s0"> + <onentry> + <send delay="5s" event="timeout"/> + <send event="event1" type="http://www.w3.org/TR/scxml/#SCXMLEventProcessor" namelist="Var1"> + <param name="param1" conf:expr="2"/> + </send> + </onentry> + <transition event="event1" target="s1"> + <assign conf:location="2" conf:eventDataNamelistValue="Var1"/> + <assign conf:location="3" conf:eventDataParamValue="param1"/> + </transition> + <transition event="*" conf:targetfail=""> + </transition> + +</state> + +<state id="s1"> + + <transition conf:idVal="2=1" target="s2"/> + <transition conf:targetfail=""/> + </state> + +<state id="s2"> + <transition conf:idVal="3=2" target="s3"/> + <transition conf:targetfail=""/> + </state> + +<state id="s3"> + <onentry> + <send delay="5s" event="timeout"/> + <send event="event2"> + <content>foo</content> + </send> + </onentry> + <transition event="event2" conf:eventdataVal="foo" conf:targetpass=""/> + <transition event="*" conf:targetfail=""/> + +</state> + + + <conf:pass/> + <conf:fail/> + +</scxml>
\ No newline at end of file diff --git a/test/samples/w3c/txml/test415.txml b/test/samples/w3c/txml/test415.txml new file mode 100644 index 0000000..5bb3343 --- /dev/null +++ b/test/samples/w3c/txml/test415.txml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<!-- Test that the state machine halts when it enters a top-level final state. Since + the initial state is a final state, this machine should halt immediately without + processing "event1" which is raised in the final state's on-entry handler. This + is a manual test since there is no platform-independent way to test that event1 + is not processed --> + +<scxml initial="final" version="1.0" conf:datamodel="" xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance"> + <final id="final"> + <onentry> + <raise event="event1"/> + </onentry> + </final> + +</scxml>
\ No newline at end of file diff --git a/test/samples/w3c/txml/test483.txml b/test/samples/w3c/txml/test483.txml new file mode 100644 index 0000000..7eab75b --- /dev/null +++ b/test/samples/w3c/txml/test483.txml @@ -0,0 +1,31 @@ +<?xml version="1.0"?> + <!-- test that foreach works correctly, iterating over node set in document order. + This tests assertions 483-485 --> + + <scxml xmlns="http://www.w3.org/2005/07/scxml" name="scxmltest" + xmlns:conf="http://www.w3.org/2005/scxml-conformance" initial="s0" version="1.0" datamodel="xpath"> + <datamodel> + <data id="var1"> + <nodes xmlns=""> + <node/> + <node/> + <node/> + </nodes> + </data> + </datamodel> + +<state id="s0"> + <onentry> + <foreach array="$var1/nodes/node" item="item" index="pos"> + <assign location="$item" type="addattribute" attr="position" expr="$pos"/> + </foreach> + </onentry> + + <transition cond="$var1/nodes/node[1]/@position = 1 and $var1/nodes/node[2]/@position = 2 and $var1/nodes/node[3]/@position = 3" conf:targetpass=""/> + <transition conf:targetfail=""/> + </state> + +<conf:pass/> +<conf:fail/> + +</scxml>
\ No newline at end of file diff --git a/test/samples/w3c/txml/test513.txml b/test/samples/w3c/txml/test513.txml new file mode 100644 index 0000000..65dda29 --- /dev/null +++ b/test/samples/w3c/txml/test513.txml @@ -0,0 +1,54 @@ +<?xml version="1.0"?> + +<!-- test that we get an HTTP success code back on successful delivery. To run this test, implementations +must support an extension to send: if the parameter httpResponse is present with value 'true', then when +the processor gets an http response code back, it must raise an event 'http.n1.nrest' where 'ni' is +the first digit of the response code and 'nrest' are the remaining digits--> + +<scxml initial="s0" conf:datamodel="" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance"> + +<state id="s0" initial="s01"> + <datamodel> + <data conf:id="1"/> + </datamodel> + + <onentry> + <send event="timeout" delay="30s"/> + </onentry> + <invoke type="http://www.w3.org/TR/scxml/"> + <content> + <!-- child script. Once we're running send childRunning to parent and include basicHTTPAccess URI --> + <scxml initial="child0" conf:datamodel="" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance"> + <state id="child0"> + <onentry> + <send target="#_parent" event="childRunning"> + <param name="uri" conf:basicHTTPAccessURI=""/> + </send> + </onentry> + </state> + </scxml> + </content> + </invoke> + + <transition event="*" conf:targetfail=""/> + + <state id="s01"> + <!-- when we get the event from the child, extract the access uri and use + the basicHTTP event i/o processor to send it an event --> + <transition event="childRunning" target="s02"> + <assign conf:location="1" conf:eventDataFieldValue="uri"/> + <send event="test" conf:targetExpr="1" httpResponse="true" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor"/> + </transition> + </state> + + <state id="s02"> + <!-- the child should send this back automatically. It does not need to take + any transition on the event --> + <transition event="HTTP.2" conf:targetpass=""/> + </state> + </state> + + <conf:pass/> + <conf:fail/> + +</scxml>
\ No newline at end of file diff --git a/test/samples/w3c/txml/test528.txml b/test/samples/w3c/txml/test528.txml index 69b7bb2..271bb1c 100644 --- a/test/samples/w3c/txml/test528.txml +++ b/test/samples/w3c/txml/test528.txml @@ -9,8 +9,7 @@ <transition event="error.execution" target="s1"/> <transition event="done.state.s0" conf:targetfail=""/> - <transition event="done.state.s0" conf:targetfail=""> - </transition> + <transition event="done.state.s0" conf:targetfail=""/> <state id="s01"> <transition target="s02"/> diff --git a/test/samples/w3c/xpath/test159.scxml b/test/samples/w3c/xpath/test159.scxml index 70a325d..1f2af35 100644 --- a/test/samples/w3c/xpath/test159.scxml +++ b/test/samples/w3c/xpath/test159.scxml @@ -7,7 +7,7 @@ The send tag will raise an error so var1 should not be incremented. If it is fa <state id="s0"> <onentry> <send event="thisWillFail" conf:illegaltarget=""/> - <conf:incrementId id="1"/> + <assign location="$Var1" expr="$Var1 + 1"/> </onentry> <transition cond="$Var1/text() =1" target="fail"/> <transition target="pass"/> diff --git a/test/samples/w3c/xpath/test191.scxml b/test/samples/w3c/xpath/test191.scxml index 25862ac..1910eaf 100644 --- a/test/samples/w3c/xpath/test191.scxml +++ b/test/samples/w3c/xpath/test191.scxml @@ -22,7 +22,7 @@ pass, otherwise we fail. The timer insures that some event is generated and tha </content> </invoke> <transition event="childToParent" target="pass"/> - <transition event="*" target="pass"/> + <transition event="*" target="fail"/> </state> <final id="pass"><onentry><log label="Outcome" expr="'pass'"/></onentry></final> diff --git a/test/samples/w3c/xpath/test354.scxml b/test/samples/w3c/xpath/test354.scxml new file mode 100644 index 0000000..93d768d --- /dev/null +++ b/test/samples/w3c/xpath/test354.scxml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- test that event.data can be populated using both namelist, param and <content> +and that correct values are used --><scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance" initial="s0" version="1.0" datamodel="xpath"> +<datamodel> + <data id="Var1" expr="1"/> + <data id="Var2"/> + <data id="Var3"/> + </datamodel> + +<state id="s0"> + <onentry> + <send delay="5s" event="timeout"/> + <send event="event1" type="http://www.w3.org/TR/scxml/#SCXMLEventProcessor" namelist="Var1"> + <param name="param1" expr="2"/> + </send> + </onentry> + <transition event="event1" target="s1"> + <assign location="$Var2" expr="$_event/data/data[@id='Var1']/data/text()"/> + <assign location="$Var3" expr="$_event/data/data[@id='param1']/text()"/> + </transition> + <transition event="*" target="fail"> + </transition> + +</state> + +<state id="s1"> + + <transition cond="$Var2/text() =1" target="s2"/> + <transition target="fail"/> + </state> + +<state id="s2"> + <transition cond="$Var3/text() =2" target="s3"/> + <transition target="fail"/> + </state> + +<state id="s3"> + <onentry> + <send delay="5s" event="timeout"/> + <send event="event2"> + <content>foo</content> + </send> + </onentry> + <transition event="event2" cond="$_event/data = 'foo'" target="pass"/> + <transition event="*" target="fail"/> + +</state> + + + <final id="pass"><onentry><log label="Outcome" expr="'pass'"/></onentry></final> + <final id="fail"><onentry><log label="Outcome" expr="'fail'"/></onentry></final> + +</scxml>
\ No newline at end of file diff --git a/test/samples/w3c/xpath/test415.scxml b/test/samples/w3c/xpath/test415.scxml new file mode 100644 index 0000000..2da0bef --- /dev/null +++ b/test/samples/w3c/xpath/test415.scxml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- Test that the state machine halts when it enters a top-level final state. Since + the initial state is a final state, this machine should halt immediately without + processing "event1" which is raised in the final state's on-entry handler. This + is a manual test since there is no platform-independent way to test that event1 + is not processed --><scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance" initial="final" version="1.0" datamodel="xpath"> + <final id="final"> + <onentry> + <raise event="event1"/> + </onentry> + </final> + +</scxml>
\ No newline at end of file diff --git a/test/samples/w3c/xpath/test483.scxml b/test/samples/w3c/xpath/test483.scxml new file mode 100644 index 0000000..0a1b236 --- /dev/null +++ b/test/samples/w3c/xpath/test483.scxml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- test that foreach works correctly, iterating over node set in document order. + This tests assertions 483-485 --><scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance" name="scxmltest" initial="s0" version="1.0" datamodel="xpath"> + <datamodel> + <data id="var1"> + <nodes xmlns=""> + <node/> + <node/> + <node/> + </nodes> + </data> + </datamodel> + +<state id="s0"> + <onentry> + <foreach array="$var1/nodes/node" item="item" index="pos"> + <assign location="$item" type="addattribute" attr="position" expr="$pos"/> + </foreach> + </onentry> + + <transition cond="$var1/nodes/node[1]/@position = 1 and $var1/nodes/node[2]/@position = 2 and $var1/nodes/node[3]/@position = 3" target="pass"/> + <transition target="fail"/> + </state> + +<final id="pass"><onentry><log label="Outcome" expr="'pass'"/></onentry></final> +<final id="fail"><onentry><log label="Outcome" expr="'fail'"/></onentry></final> + +</scxml>
\ No newline at end of file diff --git a/test/samples/w3c/xpath/test513.scxml b/test/samples/w3c/xpath/test513.scxml new file mode 100644 index 0000000..bc29bb4 --- /dev/null +++ b/test/samples/w3c/xpath/test513.scxml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?><!-- test that we get an HTTP success code back on successful delivery. To run this test, implementations +must support an extension to send: if the parameter httpResponse is present with value 'true', then when +the processor gets an http response code back, it must raise an event 'http.n1.nrest' where 'ni' is +the first digit of the response code and 'nrest' are the remaining digits--><scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance" initial="s0" datamodel="xpath" version="1.0"> + +<state id="s0" initial="s01"> + <datamodel> + <data id="Var1"/> + </datamodel> + + <onentry> + <send event="timeout" delay="30s"/> + </onentry> + <invoke type="http://www.w3.org/TR/scxml/"> + <content> + <!-- child script. Once we're running send childRunning to parent and include basicHTTPAccess URI --> + <scxml initial="child0" datamodel="xpath" version="1.0"> + <state id="child0"> + <onentry> + <send target="#_parent" event="childRunning"> + <param name="uri" expr="_ioprocessors/processor[@name="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor"]/location/text()"/> + </send> + </onentry> + </state> + </scxml> + </content> + </invoke> + + <transition event="*" target="fail"/> + + <state id="s01"> + <!-- when we get the event from the child, extract the access uri and use + the basicHTTP event i/o processor to send it an event --> + <transition event="childRunning" target="s02"> + <assign location="$Var1" expr="$_event/data/data[@id='uri']/text()"/> + <send event="test" targetexpr="$Var1" httpResponse="true" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor"/> + </transition> + </state> + + <state id="s02"> + <!-- the child should send this back automatically. It does not need to take + any transition on the event --> + <transition event="HTTP.2" target="pass"/> + </state> + </state> + + <final id="pass"><onentry><log label="Outcome" expr="'pass'"/></onentry></final> + <final id="fail"><onentry><log label="Outcome" expr="'fail'"/></onentry></final> + +</scxml>
\ No newline at end of file diff --git a/test/samples/w3c/xpath/test528.scxml b/test/samples/w3c/xpath/test528.scxml index 7cc88f7..f8f8416 100644 --- a/test/samples/w3c/xpath/test528.scxml +++ b/test/samples/w3c/xpath/test528.scxml @@ -6,8 +6,7 @@ <transition event="error.execution" target="s1"/> <transition event="done.state.s0" target="fail"/> - <transition event="done.state.s0" target="fail"> - </transition> + <transition event="done.state.s0" target="fail"/> <state id="s01"> <transition target="s02"/> diff --git a/test/src/test-arabica-xpath.cpp b/test/src/test-arabica-xpath.cpp index ced1de3..408cc2b 100644 --- a/test/src/test-arabica-xpath.cpp +++ b/test/src/test-arabica-xpath.cpp @@ -52,7 +52,7 @@ public: virtual Arabica::XPath::XPathValue<string_type, string_adaptor> resolveVariable(const string_type& /* namespace_uri */, const string_type& name) const { using namespace Arabica::XPath; - typename VarMap::const_iterator n = map_.find(name); + VarMap::const_iterator n = map_.find(name); if(n == map_.end()) throw UnboundVariableException(string_adaptor::asStdString(name)); return XPathValue<string_type, string_adaptor>(new StringValue<string_type, string_adaptor>((*n).second)); diff --git a/test/src/test-datamodel.cpp b/test/src/test-datamodel.cpp index b0ed107..773fe7f 100644 --- a/test/src/test-datamodel.cpp +++ b/test/src/test-datamodel.cpp @@ -19,7 +19,8 @@ int main(int argc, char** argv) { WSAStartup(MAKEWORD(2, 2), &wsaData); #endif - DataModel dm(Factory::getInstance()->createDataModel("ecmascript", NULL)); + Interpreter interpreter = Interpreter::fromXML("<scxml></scxml>"); + DataModel dm(Factory::getInstance()->createDataModel("ecmascript", interpreter.getImpl().get())); dm.evalAsString("var foo = 12"); { diff --git a/test/src/test-w3c.cpp b/test/src/test-w3c.cpp index f18b339..1600c27 100644 --- a/test/src/test-w3c.cpp +++ b/test/src/test-w3c.cpp @@ -98,8 +98,11 @@ void printUsageAndExit() { class W3CStatusMonitor : public uscxml::InterpreterMonitor { void beforeCompletion(uscxml::Interpreter interpreter) { Arabica::XPath::NodeSet<std::string> config = interpreter.getConfiguration(); - if (config.size() == 1 && boost::iequals(ATTR(config[0], "id"), "pass")) + if (config.size() == 1 && boost::iequals(ATTR(config[0], "id"), "pass")) { + std::cout << "TEST SUCCEEDED" << std::endl; exit(EXIT_SUCCESS); + } + std::cout << "TEST FAILED" << std::endl; exit(EXIT_FAILURE); } }; |