From c912952fb5e8072770262c64932c1d8cf2027cf0 Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Mon, 1 Apr 2013 01:58:37 +0200 Subject: Various bug-fixes for W3C test conformance and stack traces with exceptions and segfaults --- .gitignore | 1 + apps/mmi-browser.cpp | 75 ++++++++++++++++ config.h.in | 2 + contrib/cmake/HeaderExists.cmake | 3 + src/uscxml/Factory.h | 9 ++ src/uscxml/Interpreter.cpp | 100 ++++++++++++++++----- src/uscxml/Interpreter.h | 10 ++- src/uscxml/Message.h | 1 + src/uscxml/interpreter/InterpreterDraft6.cpp | 54 ++++++++--- .../datamodel/ecmascript/v8/V8DataModel.cpp | 8 ++ .../plugins/datamodel/ecmascript/v8/V8DataModel.h | 5 +- .../plugins/datamodel/prolog/swi/SWIDataModel.cpp | 4 + .../plugins/datamodel/prolog/swi/SWIDataModel.h | 1 + src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp | 21 +++-- src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h | 1 + .../basichttp/libevent/EventIOProcessor.cpp | 16 +++- .../basichttp/libevent/EventIOProcessor.h | 2 +- 17 files changed, 264 insertions(+), 49 deletions(-) diff --git a/.gitignore b/.gitignore index 402fed2..c1665be 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ build/* build/ build*/ +nbproject contrib/prebuilt/darwin* contrib/prebuilt/linux* contrib/prebuilt/windows* diff --git a/apps/mmi-browser.cpp b/apps/mmi-browser.cpp index 56d7f02..6f997e7 100644 --- a/apps/mmi-browser.cpp +++ b/apps/mmi-browser.cpp @@ -6,6 +6,14 @@ #include #endif +#ifdef HAS_EXECINFO_H +#include +#endif + +#ifdef HAS_DLFCN_H +#include +#endif + #ifdef _WIN32 #include "XGetopt.h" #endif @@ -30,6 +38,71 @@ class VerboseMonitor : public uscxml::InterpreterMonitor { } }; + +#ifdef HAS_EXECINFO_H +void printBacktrace(void** array, int size) { + char** messages = backtrace_symbols(array, size); + for (int i = 0; i < size && messages != NULL; ++i) { + std::cerr << "\t" << messages[i] << std::endl; + } + std::cerr << std::endl; + free(messages); +} + +#ifdef HAS_DLFCN_H +// see https://gist.github.com/nkuln/2020860 +typedef void (*cxa_throw_type)(void *, void *, void (*) (void *)); +cxa_throw_type orig_cxa_throw = 0; + +void load_orig_throw_code() { + orig_cxa_throw = (cxa_throw_type) dlsym(RTLD_NEXT, "__cxa_throw"); +} + +extern "C" +void __cxa_throw (void *thrown_exception, void *pvtinfo, void (*dest)(void *)) { + std::cerr << __FUNCTION__ << " will throw exception from " << std::endl; + if (orig_cxa_throw == 0) + load_orig_throw_code(); + + void *array[50]; + size_t size = backtrace(array, 50); + printBacktrace(array, size); + orig_cxa_throw(thrown_exception, pvtinfo, dest); +} +#endif +#endif + + +// see http://stackoverflow.com/questions/2443135/how-do-i-find-where-an-exception-was-thrown-in-c +void customTerminate() { + static bool tried_throw = false; + try { + // try once to re-throw currently active exception + if (!tried_throw) { + throw; + tried_throw = true; + } else { + tried_throw = false; + }; + } + catch (const std::exception &e) { + std::cerr << __FUNCTION__ << " caught unhandled exception. what(): " + << e.what() << std::endl; + } + catch (...) { + std::cerr << __FUNCTION__ << " caught unknown/unhandled exception." + << std::endl; + } + +#ifdef HAS_EXECINFO_H + void * array[50]; + int size = backtrace(array, 50); + + printBacktrace(array, size); +#endif + abort(); +} + void printUsageAndExit() { printf("mmi-browser version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n"); printf("Usage\n"); @@ -48,6 +121,8 @@ void printUsageAndExit() { int main(int argc, char** argv) { using namespace uscxml; + std::set_terminate(customTerminate); + #ifdef HAS_SIGNAL_H signal(SIGPIPE, SIG_IGN); #endif diff --git a/config.h.in b/config.h.in index 5637057..f7ef7a2 100644 --- a/config.h.in +++ b/config.h.in @@ -63,5 +63,7 @@ #cmakedefine HAS_UNISTD_H #cmakedefine HAS_STRING_H #cmakedefine HAS_SIGNAL_H +#cmakedefine HAS_EXECINFO_H +#cmakedefine HAS_DLFCN_H #endif \ No newline at end of file diff --git a/contrib/cmake/HeaderExists.cmake b/contrib/cmake/HeaderExists.cmake index 29f801d..9d0570e 100644 --- a/contrib/cmake/HeaderExists.cmake +++ b/contrib/cmake/HeaderExists.cmake @@ -2,3 +2,6 @@ include(CheckIncludeFile) CHECK_INCLUDE_FILE(unistd.h HAS_UNISTD_H) CHECK_INCLUDE_FILE(string.h HAS_STRING_H) CHECK_INCLUDE_FILE(signal.h HAS_SIGNAL_H) +CHECK_INCLUDE_FILE(execinfo.h HAS_EXECINFO_H) +CHECK_INCLUDE_FILE(dlfcn.h HAS_DLFCN_H) + diff --git a/src/uscxml/Factory.h b/src/uscxml/Factory.h index 9cfc202..b86c5d1 100644 --- a/src/uscxml/Factory.h +++ b/src/uscxml/Factory.h @@ -157,6 +157,10 @@ public: return *this; } + virtual std::set getNames() { + return _impl->getNames(); + } + virtual Data getDataModelVariables() const { return _impl->getDataModelVariables(); }; @@ -242,6 +246,7 @@ public: virtual bool evalAsBool(const std::string& expr) = 0; virtual void assign(const std::string& location, const std::string& expr) = 0; virtual void assign(const std::string& location, const Data& data) = 0; + virtual bool isDefined(const std::string& expr) = 0; protected: Interpreter* _interpreter; @@ -315,6 +320,10 @@ public: return _impl->assign(location, data); } + virtual bool isDefined(const std::string& expr) { + return _impl->isDefined(expr); + } + protected: boost::shared_ptr _impl; }; diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 482a42c..7289b82 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -198,8 +198,10 @@ bool Interpreter::toAbsoluteURI(URL& uri) { } Interpreter::~Interpreter() { + tthread::lock_guard lock(_mutex); if (_thread) { _running = false; + // unblock event queue Event event; _externalQueue.push(event); _thread->join(); @@ -237,7 +239,7 @@ bool Interpreter::runOnMainThread(int fps, bool blocking) { _lastRunOnMainThread = tthread::timeStamp(); - tthread::lock_guard lock(_mutex); + tthread::lock_guard lock(_mutex); std::map::iterator ioProcessorIter = _ioProcessors.begin(); while(ioProcessorIter != _ioProcessors.end()) { ioProcessorIter->second.runOnMainThread(); @@ -356,7 +358,7 @@ void Interpreter::internalDoneSend(const Arabica::DOM::Node& state) Arabica::DOM::Node doneData = doneDatas[0]; NodeList doneChilds = doneData.getChildNodes(); for (int i = 0; i < doneChilds.getLength(); i++) { - if (!doneChilds.item(i).getNodeType() == Node_base::ELEMENT_NODE) + if (doneChilds.item(i).getNodeType() != Node_base::ELEMENT_NODE) continue; if (boost::iequals(TAGNAME(doneChilds.item(i)), _xmlNSPrefix + "param")) { if (!HAS_ATTR(doneChilds.item(i), "name")) { @@ -427,8 +429,6 @@ void Interpreter::send(const Arabica::DOM::Node& element) { sendReq.type = _dataModel.evalAsString(ATTR(element, "typeexpr")); } else if (HAS_ATTR(element, "type")) { sendReq.type = ATTR(element, "type"); - } else { - sendReq.type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; } } catch (Event e) { LOG(ERROR) << "Syntax error in send element typeexpr:" << std::endl << e << std::endl; @@ -458,7 +458,7 @@ void Interpreter::send(const Arabica::DOM::Node& element) { * See 3.14 IDs for details. * */ - sendReq.sendid = getUUID(); + sendReq.sendid = ATTR(getParentState(element), "id") + "." + getUUID(); if (HAS_ATTR(element, "idlocation") && _dataModel) { _dataModel.assign(ATTR(element, "idlocation"), "'" + sendReq.sendid + "'"); } @@ -622,6 +622,10 @@ void Interpreter::delayedSend(void* userdata, std::string eventName) { Interpreter* INSTANCE = data->first; SendRequest sendReq = data->second; + // test 253 + if (sendReq.origintype.length() == 0) + sendReq.origintype = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; + // see http://www.w3.org/TR/scxml/#SendTargets if (boost::iequals(sendReq.target, "#_parent")) { // send to parent scxml session @@ -637,7 +641,7 @@ void Interpreter::delayedSend(void* userdata, std::string eventName) { // send to invoker std::string invokeId = sendReq.target.substr(2, sendReq.target.length() - 2); if (INSTANCE->_invokers.find(invokeId) != INSTANCE->_invokers.end()) { - tthread::lock_guard lock(INSTANCE->_mutex); + tthread::lock_guard lock(INSTANCE->_mutex); try { INSTANCE->_invokers[invokeId].send(sendReq); } catch(...) { @@ -646,7 +650,9 @@ void Interpreter::delayedSend(void* userdata, std::string eventName) { } else { LOG(ERROR) << "Can not send to invoked component '" << invokeId << "', no such invokeId" << std::endl; } - } else if (sendReq.target.length() == 0) { + } else if (sendReq.target.length() == 0 && + (sendReq.type.length() == 0 || + boost::equals(sendReq.type, "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"))) { /** * If neither the 'target' nor the 'targetexpr' attribute is specified, the * SCXML Processor must add the event will be added to the external event @@ -661,6 +667,8 @@ void Interpreter::delayedSend(void* userdata, std::string eventName) { } catch(...) { LOG(ERROR) << "Exception caught while sending event to ioprocessor " << sendReq.type; } + } else { + INSTANCE->_internalQueue.push_back(Event("error.execution")); } } assert(INSTANCE->_sendIds.find(sendReq.sendid) != INSTANCE->_sendIds.end()); @@ -697,12 +705,18 @@ void Interpreter::invoke(const Arabica::DOM::Node& element) { } // id - if (HAS_ATTR(element, "idlocation") && _dataModel) { - invokeReq.invokeid = _dataModel.evalAsString(ATTR(element, "idlocation")); - } else if (HAS_ATTR(element, "id")) { - invokeReq.invokeid = ATTR(element, "id"); - } else { - assert(false); + try { + if (HAS_ATTR(element, "id")) { + invokeReq.invokeid = ATTR(element, "id"); + } else { + invokeReq.invokeid = ATTR(getParentState(element), "id") + "." + getUUID(); + if (HAS_ATTR(element, "idlocation") && _dataModel) { + _dataModel.assign(ATTR(element, "idlocation"), "'" + invokeReq.invokeid + "'"); + } + } + } catch (Event e) { + LOG(ERROR) << "Syntax error in invoke element idlocation:" << std::endl << e << std::endl; + return; } // namelist @@ -743,7 +757,7 @@ void Interpreter::invoke(const Arabica::DOM::Node& element) { continue; } std::string paramKey = ATTR(params[i], "name"); - boost::algorithm::to_lower(paramKey); + //boost::algorithm::to_lower(paramKey); invokeReq.params.insert(std::make_pair(paramKey, paramValue)); } @@ -815,7 +829,7 @@ void Interpreter::invoke(const Arabica::DOM::Node& element) { Invoker invoker(Factory::createInvoker(invokeReq.type, this)); if (invoker) { - tthread::lock_guard lock(_mutex); + tthread::lock_guard lock(_mutex); try { invoker.setInvokeId(invokeReq.invokeid); invoker.setType(invokeReq.type); @@ -966,9 +980,7 @@ void Interpreter::executeContent(const Arabica::DOM::Node& content, } else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "raise")) { // --- RAISE -------------------------- if (HAS_ATTR(content, "event")) { - Event event; - event.name = ATTR(content, "event"); - _internalQueue.push_back(event); + _internalQueue.push_back(Event(ATTR(content, "event"))); } } else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "if")) { // --- IF / ELSEIF / ELSE -------------- @@ -1057,6 +1069,8 @@ void Interpreter::executeContent(const Arabica::DOM::Node& content, // --- LOG -------------------------- Arabica::DOM::Element logElem = (Arabica::DOM::Element)content; if (logElem.hasAttribute("expr")) { + if (logElem.hasAttribute("label")) + std::cout << logElem.getAttribute("label") << ": "; if (_dataModel) { try { std::cout << _dataModel.evalAsString(logElem.getAttribute("expr")) << std::endl; @@ -1066,14 +1080,22 @@ void Interpreter::executeContent(const Arabica::DOM::Node& content, throw e; } } else { - std::cout << logElem.getAttribute("expr") << std::endl; + if (logElem.hasAttribute("label")) + std::cout << std::endl; } } } else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "assign")) { // --- ASSIGN -------------------------- if (_dataModel && HAS_ATTR(content, "location") && HAS_ATTR(content, "expr")) { try { - _dataModel.assign(ATTR(content, "location"), ATTR(content, "expr")); + if (!_dataModel.isDefined(ATTR(content, "location"))) { + // test 286 + LOG(ERROR) << "Assigning to undeclared location '" << ATTR(content, "location") << "' not allowed." << std::endl; + _internalQueue.push_back(Event("error.execution")); + return; + } else { + _dataModel.assign(ATTR(content, "location"), ATTR(content, "expr")); + } } catch (Event e) { LOG(ERROR) << "Syntax error in attributes of assign element:" << std::endl << e << std::endl; if (rethrow) @@ -1179,6 +1201,11 @@ void Interpreter::executeContent(const Arabica::DOM::Node& content, } void Interpreter::returnDoneEvent(const Arabica::DOM::Node& state) { + if (_parentQueue != NULL) { + Event done; + done.name = "done.invoke." + _sessionId; + _parentQueue->push(done); + } } bool Interpreter::parentIsScxmlState(Arabica::DOM::Node state) { @@ -1227,6 +1254,26 @@ Arabica::XPath::NodeSet Interpreter::getChildStates(const Arabica:: return childs; } +Arabica::DOM::Node Interpreter::getParentState(const Arabica::DOM::Node& element) { + Arabica::DOM::Node parent = element.getParentNode(); + while(parent && !isState(parent)) { + parent = parent.getParentNode(); + } + return parent; +} + +bool Interpreter::hasAncestorElement(const Arabica::DOM::Node& node, const std::string tagName) { + Arabica::DOM::Node parent = node.getParentNode(); + while(parent) { + if (parent.getNodeType() == Node_base::ELEMENT_NODE && + boost::iequals(TAGNAME(parent), tagName)) { + return true; + } + parent = parent.getParentNode(); + } + return false; +} + /** See: http://www.w3.org/TR/scxml/#LCCA The Least Common Compound Ancestor is the or element s such that s is a proper ancestor @@ -1591,7 +1638,7 @@ bool Interpreter::isCompound(const Arabica::DOM::Node& state) { } void Interpreter::setupIOProcessors() { - tthread::lock_guard lock(_mutex); + tthread::lock_guard lock(_mutex); std::map::iterator ioProcIter = Factory::getInstance()->_ioProcessors.begin(); while(ioProcIter != Factory::getInstance()->_ioProcessors.end()) { if (boost::iequals(ioProcIter->first, "basichttp") && !(_capabilities & CAN_BASIC_HTTP)) { @@ -1603,6 +1650,15 @@ void Interpreter::setupIOProcessors() { _ioProcessors[ioProcIter->first].setType(ioProcIter->first); _ioProcessors[ioProcIter->first].setInterpreter(this); + // register aliases + std::set names = _ioProcessors[ioProcIter->first].getNames(); + std::set::iterator nameIter = names.begin(); + while(nameIter != names.end()) { + if (!boost::equal(*nameIter, ioProcIter->first)) + _ioProcessors[*nameIter] = _ioProcessors[ioProcIter->first]; + nameIter++; + } + if (_dataModel) { try { _dataModel.registerIOProcessor(ioProcIter->first, _ioProcessors[ioProcIter->first]); @@ -1617,7 +1673,7 @@ void Interpreter::setupIOProcessors() { } IOProcessor Interpreter::getIOProcessor(const std::string& type) { - tthread::lock_guard lock(_mutex); + tthread::lock_guard lock(_mutex); if (_ioProcessors.find(type) == _ioProcessors.end()) { LOG(ERROR) << "No ioProcessor known for type " << type; return IOProcessor(); diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 9443a05..9d21ab4 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -177,6 +177,9 @@ public: void setConfiguration(const std::vector& states) { _userDefinedStartConfiguration = states; } + void setInvokeRequest(const InvokeRequest& req) { + _invokeReq = req; + } Arabica::DOM::Node getState(const std::string& stateId); Arabica::XPath::NodeSet getStates(const std::vector& stateIds); @@ -220,6 +223,8 @@ public: bool isInitial(const Arabica::DOM::Node& state); Arabica::XPath::NodeSet getInitialStates(Arabica::DOM::Node state = Arabica::DOM::Node()); static Arabica::XPath::NodeSet getChildStates(const Arabica::DOM::Node& state); + static Arabica::DOM::Node getParentState(const Arabica::DOM::Node& element); + static bool hasAncestorElement(const Arabica::DOM::Node& node, const std::string tagName); Arabica::XPath::NodeSet getTargetStates(const Arabica::DOM::Node& transition); Arabica::DOM::Node getSourceState(const Arabica::DOM::Node& transition); @@ -238,7 +243,7 @@ protected: bool _stable; tthread::thread* _thread; - tthread::mutex _mutex; + tthread::recursive_mutex _mutex; URL _baseURI; Arabica::DOM::Document _document; @@ -257,7 +262,8 @@ protected: Arabica::XPath::NodeSet _configuration; Arabica::XPath::NodeSet _statesToInvoke; std::vector _userDefinedStartConfiguration; - + InvokeRequest _invokeReq; + DataModel _dataModel; std::map > _historyValue; diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index 176ae86..eed9836 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -95,6 +95,7 @@ public: }; Event() : type(INTERNAL) {} + Event(const std::string& name) : name(name), type(INTERNAL) {} Event(const Arabica::DOM::Node& xmlString) : type(INTERNAL) {}; bool operator< (const Event& other) const { return this < &other; diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index 7e32ef8..8682b8d 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -9,6 +9,7 @@ using namespace Arabica::DOM; // see: http://www.w3.org/TR/scxml/#AlgorithmforSCXMLInterpretation void InterpreterDraft6::interpret() { + _mutex.lock(); if (!_isInitialized) init(); @@ -16,7 +17,8 @@ void InterpreterDraft6::interpret() { return; // dump(); - _sessionId = getUUID(); + if (_sessionId.length() == 0) + _sessionId = getUUID(); std::string datamodelName; if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "datamodel")) @@ -49,7 +51,9 @@ void InterpreterDraft6::interpret() { // initialize all data elements NodeSet dataElems = _xpath.evaluate("//" + _xpathPrefix + "data", _scxml).asNodeSet(); for (unsigned int i = 0; i < dataElems.size(); i++) { - initializeData(dataElems[i]); + // do not process data elements of nested documents from invokers + if (!hasAncestorElement(dataElems[i], _xmlNSPrefix + "invoke")) + initializeData(dataElems[i]); } } else if(_dataModel) { // initialize current data elements @@ -97,16 +101,17 @@ void InterpreterDraft6::interpret() { assert(initialTransitions.size() > 0); enterStates(initialTransitions); + _mutex.unlock(); // assert(hasLegalConfiguration()); mainEventLoop(); - if (_parentQueue) { - // send one final event to unblock eventual listeners - Event quit; - quit.name = "done.state.scxml"; - _parentQueue->push(quit); - } +// if (_parentQueue) { +// // send one final event to unblock eventual listeners +// Event quit; +// quit.name = "done.state.scxml"; +// _parentQueue->push(quit); +// } // set datamodel to null from this thread if(_dataModel) @@ -122,12 +127,31 @@ void InterpreterDraft6::initializeData(const Arabica::DOM::Node& da LOG(ERROR) << "Cannot initialize data when no datamodel is given!"; return; } - try { - if (!HAS_ATTR(data, "id")) { - LOG(ERROR) << "Data element has no id!"; - return; + + if (!HAS_ATTR(data, "id")) { + LOG(ERROR) << "Data element has no id!"; + return; + } + + /// test 240 + if (_invokeReq.params.find(ATTR(data, "id")) != _invokeReq.params.end()) { + try { + _dataModel.assign(ATTR(data, "id"), _invokeReq.params.find(ATTR(data, "id"))->second); + } catch (Event e) { + LOG(ERROR) << "Syntax error when initializing data from parameters:" << std::endl << e << std::endl; + } + return; + } + if (_invokeReq.namelist.find(ATTR(data, "id")) != _invokeReq.namelist.end()) { + try { + _dataModel.assign(ATTR(data, "id"), _invokeReq.namelist.find(ATTR(data, "id"))->second); + } catch (Event e) { + LOG(ERROR) << "Syntax error when initializing data from namelist:" << std::endl << e << std::endl; } + return; + } + try { if (HAS_ATTR(data, "expr")) { std::string value = ATTR(data, "expr"); _dataModel.assign(ATTR(data, "id"), value); @@ -161,7 +185,7 @@ void InterpreterDraft6::initializeData(const Arabica::DOM::Node& da } catch (Event e) { LOG(ERROR) << "Syntax error in data element:" << std::endl << e << std::endl; - } + } } void InterpreterDraft6::mainEventLoop() { @@ -263,7 +287,7 @@ void InterpreterDraft6::mainEventLoop() { #endif _currEvent.type = Event::EXTERNAL; // make sure it is set to external if (!_running) - exitInterpreter(); + goto EXIT_INTERPRETER; if (_dataModel && boost::iequals(_currEvent.name, "cancel.invoke." + _sessionId)) break; @@ -307,6 +331,8 @@ void InterpreterDraft6::mainEventLoop() { if (!enabledTransitions.empty()) microstep(enabledTransitions); } + +EXIT_INTERPRETER: monIter = _monitors.begin(); while(monIter != _monitors.end()) { try { diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index 4072862..0663db4 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -285,6 +285,14 @@ void V8DataModel::eval(const std::string& expr) { evalAsValue(expr); } +bool V8DataModel::isDefined(const std::string& expr) { + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.back()); + v8::Handle result = evalAsValue(expr); + return !result->IsUndefined(); +} + bool V8DataModel::evalAsBool(const std::string& expr) { v8::Locker locker; v8::HandleScope handleScope; diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h index 6d4ca63..a9db5ca 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h @@ -38,7 +38,7 @@ public: virtual void registerIOProcessor(const std::string& name, const IOProcessor& ioprocessor); virtual bool validate(const std::string& location, const std::string& schema); - + virtual uint32_t getLength(const std::string& expr); virtual void pushContext(); virtual void popContext(); @@ -49,7 +49,8 @@ public: virtual Data getStringAsData(const std::string& content); virtual Data getValueAsData(const v8::Handle& value); - + virtual bool isDefined(const std::string& expr); + virtual std::string evalAsString(const std::string& expr); virtual bool evalAsBool(const std::string& expr); virtual double evalAsNumber(const std::string& expr); diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp index fe881dc..c9d2237 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp @@ -142,4 +142,8 @@ void SWIDataModel::assign(const std::string& location, const std::string& expr) eval(expr); } +bool SWIDataModel::isDefined(const std::string& expr) { + return true; +} + } \ No newline at end of file diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h index 63300dd..52d1e34 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h @@ -39,6 +39,7 @@ public: virtual void eval(const std::string& expr); virtual void assign(const std::string& location, const std::string& expr); virtual void assign(const std::string& location, const Data& data); + virtual bool isDefined(const std::string& expr); virtual Data getStringAsData(const std::string& content); diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp index c0e87d7..292b79e 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp @@ -15,11 +15,12 @@ bool connect(pluma::Host& host) { } #endif -USCXMLInvoker::USCXMLInvoker() { + USCXMLInvoker::USCXMLInvoker() : _cancelled(false) { } USCXMLInvoker::~USCXMLInvoker() { + _cancelled = true; delete _invokedInterpreter; }; @@ -35,7 +36,7 @@ Data USCXMLInvoker::getDataModelVariables() { } void USCXMLInvoker::send(const SendRequest& req) { - assert(false); + _invokedInterpreter->_externalQueue.push(req); } void USCXMLInvoker::cancel(const std::string sendId) { @@ -50,11 +51,11 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) { } else { LOG(ERROR) << "Cannot invoke nested SCXML interpreter, neither src attribute nor DOM is given"; } - DataModel dataModel(_invokedInterpreter->getDataModel()); - if (dataModel) { - - } if (_invokedInterpreter) { + DataModel dataModel(_invokedInterpreter->getDataModel()); + if (dataModel) { + + } _invokedInterpreter->setParentQueue(this); // transfer namespace prefixes _invokedInterpreter->_nsURL = _parentInterpreter->_nsURL; @@ -66,11 +67,19 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) { nsIter++; } _invokedInterpreter->_xmlNSPrefix = _parentInterpreter->_xmlNSPrefix; + _invokedInterpreter->_sessionId = req.invokeid; + + /// test240 assumes that invoke request params will carry over to the datamodel + _invokedInterpreter->setInvokeRequest(req); + _invokedInterpreter->start(); } } void USCXMLInvoker::push(const SendRequest& event) { + // test 252 + if (_cancelled) + return; SendRequest copyEvent(event); copyEvent.invokeid = _invokeId; _parentInterpreter->receive(copyEvent); diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h index 857ffe2..b1386b1 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h @@ -38,6 +38,7 @@ public: virtual void push(const SendRequest& event); protected: + bool _cancelled; Interpreter* _invokedInterpreter; Interpreter* _parentInterpreter; }; diff --git a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp index ad47896..a1f803d 100644 --- a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp @@ -118,7 +118,14 @@ void EventIOProcessor::httpRecvRequest(const HTTPServer::Request& req) { void EventIOProcessor::send(const SendRequest& req) { - std::string target = req.target; + bool isLocal = false; + std::string target; + if (req.target.length() > 0) { + target = req.target; + } else { + isLocal = true; + target = _url; + } URL targetURL(target); // event name @@ -152,7 +159,12 @@ void EventIOProcessor::send(const SendRequest& req) { targetURL.addMonitor(this); _sendRequests[req.sendid] = std::make_pair(targetURL, req); - URLFetcher::fetchURL(targetURL); + if (isLocal) { + // test201 use a blocking request with local communication + targetURL.download(true); + } else { + URLFetcher::fetchURL(targetURL); + } } void EventIOProcessor::downloadStarted(const URL& url) {} diff --git a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h index 5446624..c549b2b 100644 --- a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h +++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h @@ -29,7 +29,7 @@ public: virtual std::set getNames() { std::set names; names.insert("basichttp"); - names.insert("http://www.w3.org/TR/scxml/#SCXMLEventProcessor"); + names.insert("http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor"); return names; } -- cgit v0.12