diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/uscxml/Interpreter.cpp | 200 | ||||
-rw-r--r-- | src/uscxml/Interpreter.h | 1 | ||||
-rw-r--r-- | src/uscxml/Message.h | 153 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp | 32 |
4 files changed, 144 insertions, 242 deletions
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 4700056..e17b760 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -23,6 +23,18 @@ #define VERBOSE 0 +#define CATCH_AND_DISTRIBUTE(msg) \ +catch (Event e) {\ + LOG(ERROR) << msg << std::endl << e << std::endl;\ + if (rethrow) {\ + throw(e);\ + } else {\ + e.name = "error.execution";\ + e.type = Event::PLATFORM;\ + _internalQueue.push_back(e);\ + }\ +} + namespace uscxml { using namespace Arabica::XPath; @@ -356,54 +368,12 @@ void Interpreter::internalDoneSend(const Arabica::DOM::Node<std::string>& state) if (doneDatas.size() > 0) { // only process first donedata element Arabica::DOM::Node<std::string> doneData = doneDatas[0]; - NodeList<std::string> doneChilds = doneData.getChildNodes(); - for (int i = 0; i < doneChilds.getLength(); i++) { - if (doneChilds.item(i).getNodeType() != Node_base::ELEMENT_NODE) - continue; - if (boost::iequals(TAGNAME(doneChilds.item(i)), _xmlNSPrefix + "param")) { - try { - if (!HAS_ATTR(doneChilds.item(i), "name")) { - LOG(ERROR) << "param element is missing name attribut"; - continue; - } - std::string paramValue; - if (HAS_ATTR(doneChilds.item(i), "expr") && _dataModel) { - std::string expr = _dataModel.evalAsString(ATTR(doneChilds.item(i), "expr")); - paramValue = _dataModel.evalAsString(expr); - } else if(HAS_ATTR(doneChilds.item(i), "location") && _dataModel) { - paramValue = _dataModel.evalAsString(ATTR(doneChilds.item(i), "location")); - } else { - LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; - continue; - } - /// test 294 - event.data.compound[ATTR(doneChilds.item(i), "name")] = paramValue; - } catch (Event e) { - e.name = "error.execution"; - _internalQueue.push_back(e); - } - } - if (boost::iequals(TAGNAME(doneChilds.item(i)), _xmlNSPrefix + "content")) { - if (HAS_ATTR(doneChilds.item(i), "expr")) { - try { - if (_dataModel) { - /// test 294 - event.data = Data(_dataModel.evalAsString(ATTR(doneChilds.item(i), "expr")), Data::VERBATIM); - } else { - LOG(ERROR) << "content element has expr attribute but no datamodel is specified."; - } - } catch (Event e) { - e.name = "error.execution"; - _internalQueue.push_back(e); - } - } else if (doneChilds.item(i).hasChildNodes()) { - event.data = Data(doneChilds.item(i).getFirstChild().getNodeValue(), Data::VERBATIM); - } else { - LOG(ERROR) << "content element does not specify any content."; - } - - } - } + processParamChilds(doneData, event.params); + Arabica::XPath::NodeSet<std::string> contents = filterChildElements(_xmlNSPrefix + "content", doneDatas[0]); + if (contents.size() > 1) + LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; + if (contents.size() > 0) + processContentElement(contents[0], event.dom, event.content); } event.name = "done.state." + ATTR(stateElem.getParentNode(), "id"); // parent?! @@ -465,6 +435,38 @@ void Interpreter::processContentElement(const Arabica::DOM::Node<std::string>& c } } +void Interpreter::processParamChilds(const Arabica::DOM::Node<std::string>& element, std::multimap<std::string, std::string>& params) { + NodeSet<std::string> paramElems = filterChildElements(_xmlNSPrefix + "param", element); + try { + for (int i = 0; i < paramElems.size(); i++) { + if (!HAS_ATTR(paramElems[i], "name")) { + LOG(ERROR) << "param element is missing name attribute"; + continue; + } + std::string paramValue; + if (HAS_ATTR(paramElems[i], "expr") && _dataModel) { + paramValue = _dataModel.evalAsString(ATTR(paramElems[i], "expr")); + } else if(HAS_ATTR(paramElems[i], "location") && _dataModel) { + paramValue = _dataModel.evalAsString(ATTR(paramElems[i], "location")); + } else { + LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; + continue; + } + std::string paramKey = ATTR(paramElems[i], "name"); + params.insert(std::make_pair(paramKey, paramValue)); + } + } catch(Event e) { + LOG(ERROR) << "Syntax error while processing params:" << std::endl << e << std::endl; + // test 343 + std::multimap<std::string, std::string>::iterator paramIter = params.begin(); + while(paramIter != params.end()) { + params.erase(paramIter++); + } + e.name = "error.execution"; + _internalQueue.push_back(e); + } +} + void Interpreter::send(const Arabica::DOM::Node<std::string>& element) { SendRequest sendReq; // test 331 @@ -585,28 +587,7 @@ void Interpreter::send(const Arabica::DOM::Node<std::string>& element) { try { // params - NodeSet<std::string> params = filterChildElements(_xmlNSPrefix + "param", element); - for (int i = 0; i < params.size(); i++) { - if (!HAS_ATTR(params[i], "name")) { - LOG(ERROR) << "param element is missing name attribute"; - continue; - } - std::string paramValue; - if (HAS_ATTR(params[i], "expr") && _dataModel) { - paramValue = _dataModel.evalAsString(ATTR(params[i], "expr")); - } else if(HAS_ATTR(params[i], "location") && _dataModel) { - paramValue = _dataModel.evalAsString(ATTR(params[i], "location")); - } else { - LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; - continue; - } - std::string paramKey = ATTR(params[i], "name"); - // use lower case parameter name in params - this is at least something to think about again - std::string lcParamKey = paramKey; - boost::algorithm::to_lower(lcParamKey); - sendReq.params.insert(std::make_pair(lcParamKey, paramValue)); - sendReq.data.compound[paramKey] = Data(paramValue, Data::VERBATIM); - } + processParamChilds(element, sendReq.params); } catch (Event e) { LOG(ERROR) << "Syntax error in send element param expr:" << std::endl << e << std::endl; return; @@ -760,30 +741,7 @@ void Interpreter::invoke(const Arabica::DOM::Node<std::string>& element) { } // params - NodeSet<std::string> params = filterChildElements(_xmlNSPrefix + "param", element); - for (int i = 0; i < params.size(); i++) { - if (!HAS_ATTR(params[i], "name")) { - LOG(ERROR) << "param element is missing name attribut"; - continue; - } - std::string paramValue; - if (HAS_ATTR(params[i], "expr")) { - if (_dataModel) { - paramValue = _dataModel.evalAsString(ATTR(params[i], "expr")); - } else { - LOG(ERROR) << "Cannot use param expr without a datamodel!"; - } - } else if(HAS_ATTR(params[i], "location") && _dataModel) { - paramValue = _dataModel.evalAsString(ATTR(params[i], "location")); - } else { - LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; - continue; - } - std::string paramKey = ATTR(params[i], "name"); - //boost::algorithm::to_lower(paramKey); - invokeReq.params.insert(std::make_pair(paramKey, paramValue)); - - } + processParamChilds(element, invokeReq.params); // content try { @@ -911,6 +869,8 @@ bool Interpreter::hasConditionMatch(const Arabica::DOM::Node<std::string>& condi return _dataModel.evalAsBool(ATTR(conditional, "cond")); } catch (Event e) { LOG(ERROR) << "Syntax error in cond attribute of " << TAGNAME(conditional) << " element:" << std::endl << e << std::endl; + e.name = "error.execution"; + _internalQueue.push_back(e); return false; } } @@ -1000,12 +960,8 @@ void Interpreter::executeContent(const Arabica::DOM::Node<std::string>& content, uint32_t iterations = 0; try { iterations = _dataModel.getLength(array); - } catch (Event e) { - LOG(ERROR) << "Syntax error in array attribute of foreach element:" << std::endl << e << std::endl; - if (rethrow) - throw e; - return; } + CATCH_AND_DISTRIBUTE("Syntax error in array attribute of foreach element:") try { _dataModel.pushContext(); // copy old and enter new context for (uint32_t iteration = 0; iteration < iterations; iteration++) { @@ -1026,12 +982,8 @@ void Interpreter::executeContent(const Arabica::DOM::Node<std::string>& content, executeContent(content.getChildNodes(), true); } _dataModel.popContext(); // leave stacked context - } catch (Event e) { - _dataModel.popContext(); // leave stacked context even when exception was thrown - LOG(ERROR) << "Syntax error in foreach element:" << std::endl << e << std::endl; - if (rethrow) - throw e; } + CATCH_AND_DISTRIBUTE("Syntax error in foreach element:") } else { LOG(ERROR) << "Expected array and item attributes with foreach element!" << std::endl; } @@ -1045,11 +997,8 @@ void Interpreter::executeContent(const Arabica::DOM::Node<std::string>& content, if (_dataModel) { try { std::cout << _dataModel.evalAsString(logElem.getAttribute("expr")) << std::endl; - } catch (Event e) { - LOG(ERROR) << "Syntax error in expr attribute of log element:" << std::endl << e << std::endl; - if (rethrow) - throw e; } + CATCH_AND_DISTRIBUTE("Syntax error in expr attribute of log element:") } else { if (logElem.hasAttribute("label")) std::cout << std::endl; @@ -1062,18 +1011,12 @@ void Interpreter::executeContent(const Arabica::DOM::Node<std::string>& content, if (!_dataModel.isDeclared(ATTR(content, "location"))) { // test 286, 331 LOG(ERROR) << "Assigning to undeclared location '" << ATTR(content, "location") << "' not allowed." << std::endl; - Event e("error.execution", Event::PLATFORM); - _internalQueue.push_back(e); - throw e; - return; + throw Event("error.execution", Event::PLATFORM); } 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) - throw e; } + CATCH_AND_DISTRIBUTE("Syntax error in attributes of assign element:") } } else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "validate")) { // --- VALIDATE -------------------------- @@ -1106,22 +1049,16 @@ void Interpreter::executeContent(const Arabica::DOM::Node<std::string>& content, try { _dataModel.eval(srcContent.str()); - } catch (Event e) { - LOG(ERROR) << "Syntax error while executing script element from '" << ATTR(content, "src") << "':" << std::endl << e << std::endl; - if (rethrow) - throw e; } + CATCH_AND_DISTRIBUTE("Syntax error while executing script element from '" << ATTR(content, "src") << "':") } else { if (content.hasChildNodes()) { // search for the text node with the actual script if (content.getFirstChild().getNodeType() == Node_base::TEXT_NODE) { try { _dataModel.eval(content.getFirstChild().getNodeValue()); - } catch (Event e) { - LOG(ERROR) << "Syntax error while executing script element" << std::endl << e << std::endl; - if (rethrow) - throw e; } + CATCH_AND_DISTRIBUTE("Syntax error while executing script element") } } } @@ -1143,12 +1080,8 @@ void Interpreter::executeContent(const Arabica::DOM::Node<std::string>& content, } _sendQueue->cancelEvent(sendId); - } catch (Event e) { - LOG(ERROR) << "Syntax error while executing cancel element" << std::endl << e << std::endl; - if (rethrow) - throw e; } - + CATCH_AND_DISTRIBUTE("Syntax error while executing cancel element") } else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "invoke")) { // --- INVOKE -------------------------- } else { @@ -1368,24 +1301,21 @@ Arabica::XPath::NodeSet<std::string> Interpreter::getInitialStates(Arabica::DOM: assert(isCompound(state) || isParallel(state)); - Arabica::XPath::NodeSet<std::string> initialStates; - // initial attribute at element Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state; if (stateElem.hasAttribute("initial")) { return getStates(tokenizeIdRefs(stateElem.getAttribute("initial"))); } - Arabica::XPath::NodeSet<std::string> initStates; - // initial element as child - but not the implicit generated one NodeSet<std::string> initElems = filterChildElements(_xmlNSPrefix + "initial", state); if(initElems.size() == 1 && !boost::iequals(ATTR(initElems[0], "generated"), "true")) { - initStates.push_back(initialStates[0]); - return initStates; + NodeSet<std::string> initTrans = filterChildElements(_xmlNSPrefix + "transition", initElems[0]); + return getTargetStates(initTrans[0]); } // first child state + Arabica::XPath::NodeSet<std::string> initStates; NodeList<std::string> childs = state.getChildNodes(); for (int i = 0; i < childs.getLength(); i++) { if (isState(childs.item(i))) { diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 0eac6fb..4bac414 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -287,6 +287,7 @@ 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, std::string& text); + void processParamChilds(const Arabica::DOM::Node<std::string>& element, std::multimap<std::string, std::string>& params); void send(const Arabica::DOM::Node<std::string>& element); void invoke(const Arabica::DOM::Node<std::string>& element); diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index cb7196a..19adf99 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -172,51 +172,6 @@ public: return ss.str(); } -#ifdef SWIGIMPORTED -protected: -#endif - - std::string name; - Type type; - std::string origin; - std::string origintype; - Arabica::DOM::Document<std::string> dom; - std::string sendid; - std::string invokeid; - Data data; - std::string content; - -#ifndef SWIG - friend std::ostream& operator<< (std::ostream& os, const Event& event); -#endif -}; - -class InvokeRequest : public Event { -public: - InvokeRequest(Event event) : Event(event) {} - InvokeRequest() {} - - std::string getType() { - return type; - } - void setType(const std::string& type) { - this->type = type; - } - - std::string getSource() { - return src; - } - void setSource(const std::string& src) { - this->src = src; - } - - bool isAutoForwarded() { - return autoForward; - } - void setAutoForwarded(bool autoForward) { - this->autoForward = autoForward; - } - #ifdef SWIG /// TODO: Do we want to set namelist and params as well? std::map<std::string, std::string> getNameList() { @@ -263,6 +218,57 @@ public: } #endif + +#ifdef SWIGIMPORTED +protected: +#endif + + std::string name; + Type type; + std::string origin; + std::string origintype; + Arabica::DOM::Document<std::string> dom; + std::string sendid; + std::string invokeid; + Data data; + std::string content; + std::map<std::string, std::string> namelist; + std::multimap<std::string, std::string> params; + + typedef std::multimap<std::string, std::string> params_t; + typedef std::map<std::string, std::string> namelist_t; + +#ifndef SWIG + friend std::ostream& operator<< (std::ostream& os, const Event& event); +#endif +}; + +class InvokeRequest : public Event { +public: + InvokeRequest(Event event) : Event(event) {} + InvokeRequest() {} + + std::string getType() { + return type; + } + void setType(const std::string& type) { + this->type = type; + } + + std::string getSource() { + return src; + } + void setSource(const std::string& src) { + this->src = src; + } + + bool isAutoForwarded() { + return autoForward; + } + void setAutoForwarded(bool autoForward) { + this->autoForward = autoForward; + } + static InvokeRequest fromXML(const std::string& xmlString); Arabica::DOM::Document<std::string> toDocument(); std::string toXMLString() { @@ -277,11 +283,6 @@ protected: std::string type; std::string src; bool autoForward; - std::map<std::string, std::string> namelist; - std::multimap<std::string, std::string> params; - - typedef std::multimap<std::string, std::string> params_t; - typedef std::map<std::string, std::string> namelist_t; #ifndef SWIG friend std::ostream& operator<< (std::ostream& os, const InvokeRequest& sendReq); @@ -315,52 +316,6 @@ public: this->delayMs = delayMs; } -#ifdef SWIG - /// TODO: Do we want to set namelist and params as well? - std::map<std::string, std::string> getNameList() { - return namelist; - } - - const std::vector<std::string> getNameListKeys() { - std::set<std::string> keys; - namelist_t::const_iterator nameListIter = namelist.begin(); - while (nameListIter != namelist.end()) { - keys.insert(nameListIter->first); - nameListIter++; - } - return std::vector<std::string>(keys.begin(), keys.end()); - } - - // substitute multimap by map with vectors for language bindings - std::map<std::string, std::vector<std::string> > getParams() { - std::map<std::string, std::vector<std::string> > paramsMap; - params_t::iterator paramIter = params.begin(); - while(paramIter != params.end()) { - paramsMap[paramIter->first].push_back(paramIter->second); - paramIter++; - } - return paramsMap; - } - - const std::vector<std::string> getParamKeys() { - std::set<std::string> keys; - params_t::iterator paramIter = params.begin(); - while(paramIter != params.end()) { - keys.insert(paramIter->first); - paramIter++; - } - return std::vector<std::string>(keys.begin(), keys.end()); - } - -#else - std::map<std::string, std::string>& getNameList() { - return namelist; - } - std::multimap<std::string, std::string>& getParams() { - return params; - } -#endif - static SendRequest fromXML(const std::string& xmlString); Arabica::DOM::Document<std::string> toDocument(); std::string toXMLString() { @@ -377,12 +332,6 @@ protected: std::string type; uint32_t delayMs; - std::map<std::string, std::string> namelist; - std::multimap<std::string, std::string> params; - - typedef std::map<std::string, std::string> namelist_t; - typedef std::multimap<std::string, std::string> params_t; - #ifndef SWIG friend std::ostream& operator<< (std::ostream& os, const SendRequest& sendReq); #endif diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index c24e3ec..e86472b 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -143,6 +143,7 @@ void V8DataModel::setEvent(const Event& event) { eventObj->SetInternalField(0, Arabica::DOM::V8DOM::toExternal(privData)); eventObj.MakeWeak(0, Arabica::DOM::V8SCXMLEvent::jsDestructor); if (event.dom) { + // _event.data is a DOM document v8::Handle<v8::Function> retCtor = Arabica::DOM::V8Document::getTmpl()->GetFunction(); v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance()); @@ -153,11 +154,33 @@ void V8DataModel::setEvent(const Event& event) { retObj->SetInternalField(0, Arabica::DOM::V8DOM::toExternal(retPrivData)); retObj.MakeWeak(0, Arabica::DOM::V8Document::jsDestructor); - eventObj->Set(v8::String::New("data"), retObj); // set data part of _event + eventObj->Set(v8::String::New("data"), retObj); } else if (event.content.length() > 0) { - eventObj->Set(v8::String::New("data"), v8::String::New(event.content.c_str())); // set data part of _event + // _event.data is a string + eventObj->Set(v8::String::New("data"), v8::String::New(event.content.c_str())); } else { - eventObj->Set(v8::String::New("data"), getDataAsValue(event.data)); // set data part of _event + // _event.data is KVP + Event eventCopy(event); + if (!eventCopy.params.empty()) { + Event::params_t::iterator paramIter = eventCopy.params.begin(); + while(paramIter != eventCopy.params.end()) { + eventCopy.data.compound[paramIter->first] = Data(paramIter->second, Data::VERBATIM); + paramIter++; + } + } + if (!eventCopy.namelist.empty()) { + Event::namelist_t::iterator nameListIter = eventCopy.namelist.begin(); + while(nameListIter != eventCopy.namelist.end()) { + eventCopy.data.compound[nameListIter->first] = Data(nameListIter->second, Data::VERBATIM); + nameListIter++; + } + } + if (eventCopy.data.compound.size() > 0) { + eventObj->Set(v8::String::New("data"), getDataAsValue(eventCopy.data)); // set data part of _event + } else { + // test 343 + eventObj->Set(v8::String::New("data"), v8::Undefined()); // set data part of _event + } } global->Set(v8::String::New("_event"), eventObj); } @@ -296,7 +319,6 @@ uint32_t V8DataModel::getLength(const std::string& expr) { exceptionEvent.name = "error.execution"; exceptionEvent.data.compound["exception"] = Data("'" + expr + "' does not evaluate to an array.", Data::VERBATIM);; - _interpreter->receiveInternal(exceptionEvent); throw(exceptionEvent); } @@ -438,7 +460,7 @@ void V8DataModel::throwExceptionEvent(const v8::TryCatch& tryCatch) { } - _interpreter->receiveInternal(exceptionEvent); +// _interpreter->receiveInternal(exceptionEvent); throw(exceptionEvent); } |