diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/uscxml/Factory.cpp | 3 | ||||
-rw-r--r-- | src/uscxml/Interpreter.cpp | 122 | ||||
-rw-r--r-- | src/uscxml/Interpreter.h | 1 | ||||
-rw-r--r-- | src/uscxml/Message.cpp | 62 | ||||
-rw-r--r-- | src/uscxml/Message.h | 7 | ||||
-rw-r--r-- | src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp | 2 | ||||
-rw-r--r-- | src/uscxml/invoker/scxml/USCXMLInvoker.cpp | 9 | ||||
-rw-r--r-- | src/uscxml/invoker/scxml/USCXMLInvoker.h | 1 | ||||
-rw-r--r-- | src/uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.cpp | 28 |
9 files changed, 189 insertions, 46 deletions
diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp index ee2a3bd..b2346c2 100644 --- a/src/uscxml/Factory.cpp +++ b/src/uscxml/Factory.cpp @@ -10,7 +10,8 @@ namespace uscxml { _dataModels["ecmascript"] = new V8DataModel(); // _ioProcessors["basichttp"] = new PionIOProcessor(); _ioProcessors["basichttp"] = new EventIOProcessor(); - _ioProcessors["http://www.w3.org/TR/scxml/#SCXMLEventProcessor"] = new EventIOProcessor(); + // use basichttp for transporting to/from scxml sessions as well + _ioProcessors["http://www.w3.org/TR/scxml/#SCXMLEventProcessor"] = _ioProcessors["basichttp"]; _invoker["scxml"] = new USCXMLInvoker(); _invoker["http://www.w3.org/TR/scxml/"] = _invoker["scxml"]; } diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 267d53f..b1c504c 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -278,6 +278,12 @@ void Interpreter::normalize(const Arabica::DOM::Node<std::string>& node) { if (!invokeElem.hasAttribute("id") && !invokeElem.hasAttribute("idlocation")) { invokeElem.setAttribute("id", getUUID()); } +// // make sure every finalize element contained has the invoke id as an attribute +// Arabica::XPath::NodeSet<std::string> finalizes = _xpath.evaluate("" + _nsPrefix + "finalize", invokeElem).asNodeSet(); +// for (int j = 0; j < finalizes.size(); j++) { +// Arabica::DOM::Element<std::string> finalizeElem = Arabica::DOM::Element<std::string>(finalizes[j]); +// finalizeElem.setAttribute("invokeid", invokeElem.getAttribute("id")); +// } } Arabica::XPath::NodeSet<std::string> finals = _xpath.evaluate("//" + _nsPrefix + "final", _doc).asNodeSet(); @@ -311,7 +317,7 @@ void Interpreter::mainEventLoop() { // Here we handle eventless transitions and transitions // triggered by internal events until machine is stable while(_running && !_stable) { -#if 0 +#if 1 std::cout << "Configuration: "; for (int i = 0; i < _configuration.size(); i++) { std::cout << ((Arabica::DOM::Element<std::string>)_configuration[i]).getAttribute("id") << ", "; @@ -325,6 +331,9 @@ void Interpreter::mainEventLoop() { } else { Event internalEvent = _internalQueue.front(); _internalQueue.pop_front(); +#if 1 + std::cout << "Received internal event " << internalEvent.name << std::endl; +#endif _dataModel->setEvent(internalEvent); enabledTransitions = selectTransitions(internalEvent.name); } @@ -357,16 +366,26 @@ void Interpreter::mainEventLoop() { break; if (_dataModel) - _dataModel->setEvent(externalEvent); + try { + _dataModel->setEvent(externalEvent); + } catch (Event e) { + LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl; + } for (unsigned int i = 0; i < _configuration.size(); i++) { NodeSet<std::string> invokes = _xpath.evaluate("" + _nsPrefix + "invoke", _configuration[i]).asNodeSet(); for (unsigned int j = 0; j < invokes.size(); j++) { - std::string invokeId = ((Arabica::DOM::Element<std::string>)invokes[i]).getAttribute("id"); - std::string autoForward = ((Arabica::DOM::Element<std::string>)invokes[i]).getAttribute("autoforward"); + Arabica::DOM::Element<std::string> invokeElem = (Arabica::DOM::Element<std::string>)invokes[j]; + std::string invokeId = invokeElem.getAttribute("id"); + std::string autoForward = invokeElem.getAttribute("autoforward"); if (boost::iequals(invokeId, externalEvent.invokeid)) { - // @TODO - // boost::shared_ptr<Invoke> invoke = boost::static_pointer_cast<Invoke>(interpreter::Factory::create("invoke", invokes[j])); - // invoke->applyFinalize(this); + + Arabica::XPath::NodeSet<std::string> finalizes = _xpath.evaluate("" + _nsPrefix + "finalize", invokeElem).asNodeSet(); + for (int k = 0; k < finalizes.size(); k++) { + Arabica::DOM::Element<std::string> finalizeElem = Arabica::DOM::Element<std::string>(finalizes[k]); + executeContent(finalizeElem); + } + + } if (autoForward.length() > 0) { // @TODO @@ -381,6 +400,61 @@ void Interpreter::mainEventLoop() { exitInterpreter(); } +void Interpreter::internalDoneSend(const Arabica::DOM::Node<std::string>& state) { + if (!isState(state)) + return; + + Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state; + Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)stateElem.getParentNode(); + Event event; + + Arabica::XPath::NodeSet<std::string> doneDatas = _xpath.evaluate("" + _nsPrefix + "donedata", stateElem).asNodeSet(); + if (doneDatas.size() > 0) { + // only process first donedata element + Arabica::DOM::Node<std::string> doneData = doneDatas[0]; + NodeList<std::string> doneChilds = doneData.getChildNodes(); + for (int i = 0; i < doneChilds.getLength(); i++) { + if (!doneChilds.item(i).getNodeType() == Node_base::ELEMENT_NODE) + continue; + if (boost::iequals(TAGNAME(doneChilds.item(i)), "param")) { + if (!HAS_ATTR(doneChilds.item(i), "name")) { + LOG(ERROR) << "param element is missing name attribut"; + continue; + } + std::string paramValue; + if (HAS_ATTR(doneChilds.item(i), "expr") && _dataModel) { + std::string location = _dataModel->evalAsString(ATTR(doneChilds.item(i), "expr")); + paramValue = _dataModel->evalAsString(location); + } else if(HAS_ATTR(doneChilds.item(i), "location") && _dataModel) { + paramValue = _dataModel->evalAsString(ATTR(doneChilds.item(i), "location")); + } else { + LOG(ERROR) << "param element is missing expr or location or no datamodel is specified"; + continue; + } + event.compound[ATTR(doneChilds.item(i), "name")] = paramValue; + } + if (boost::iequals(TAGNAME(doneChilds.item(i)), "content")) { + if (HAS_ATTR(doneChilds.item(i), "expr")) { + if (_dataModel) { + event.compound["content"] = Data(_dataModel->evalAsString(ATTR(doneChilds.item(i), "expr")), Data::VERBATIM); + } else { + LOG(ERROR) << "content element has expr attribute but no datamodel is specified."; + } + } else if (doneChilds.item(i).hasChildNodes()) { + event.compound["content"] = Data(doneChilds.item(i).getFirstChild().getNodeValue(), Data::VERBATIM); + } else { + LOG(ERROR) << "content element does not specify any content."; + } + + } + } + } + + event.name = "done.state." + parent.getAttribute("id"); + _internalQueue.push_back(event); + +} + void Interpreter::send(const Arabica::DOM::Node<std::string>& element) { SendRequest sendReq; try { @@ -627,9 +701,8 @@ void Interpreter::invoke(const Arabica::DOM::Node<std::string>& element) { } catch (Event e) { LOG(ERROR) << "Syntax error in invoke element:" << std::endl << e << std::endl; } - } - + void Interpreter::cancelInvoke(const Arabica::DOM::Node<std::string>& element) { std::string invokeId; if (HAS_ATTR(element, "idlocation") && _dataModel) { @@ -780,13 +853,13 @@ bool Interpreter::isPreemptingTransition(const Arabica::DOM::Node<std::string>& } void Interpreter::microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) { -#if 0 +#if 1 std::cout << "Transitions: "; for (int i = 0; i < enabledTransitions.size(); i++) { std::cout << ((Arabica::DOM::Element<std::string>)getSourceState(enabledTransitions[i])).getAttribute("id") << " -> " << std::endl; NodeSet<std::string> targetSet = getTargetStates(enabledTransitions[i]); for (int j = 0; j < targetSet.size(); j++) { - std::cout << " " << ((Arabica::DOM::Element<std::string>)targetSet[i]).getAttribute("id") << std::endl; + std::cout << " " << ((Arabica::DOM::Element<std::string>)targetSet[j]).getAttribute("id") << std::endl; } } std::cout << std::endl; @@ -1186,16 +1259,9 @@ void Interpreter::enterStates(const Arabica::XPath::NodeSet<std::string>& enable } if (isFinal(stateElem)) { + internalDoneSend(stateElem); Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)stateElem.getParentNode(); - Event event; - event.name = "done.state." + parent.getAttribute("id"); - Arabica::XPath::NodeSet<std::string> doneData = _xpath.evaluate("" + _nsPrefix + "donedata", stateElem).asNodeSet(); - if (doneData.size() > 0) { - event.dom = doneData[0]; - } - _internalQueue.push_back(event); - if (isParallel(parent.getParentNode())) { Arabica::DOM::Element<std::string> grandParent = (Arabica::DOM::Element<std::string>)parent.getParentNode(); @@ -1208,9 +1274,7 @@ void Interpreter::enterStates(const Arabica::XPath::NodeSet<std::string>& enable } } if (inFinalState) { - Event event; - event.name = "done.state." + grandParent.getAttribute("id"); - _internalQueue.push_back(event); + internalDoneSend(parent); } } } @@ -1231,6 +1295,7 @@ bool Interpreter::parentIsScxmlState(Arabica::DOM::Node<std::string> state) { } bool Interpreter::isInFinalState(const Arabica::DOM::Node<std::string>& state) { +// std::cout << ATTR(state, "id") << std::endl; if (isCompound(state)) { Arabica::XPath::NodeSet<std::string> childs = getChildStates(state); for (int i = 0; i < childs.size(); i++) { @@ -1283,10 +1348,15 @@ void Interpreter::addStatesToEnter(const Arabica::DOM::Node<std::string>& state, statesToEnter.push_back(state); if (isCompound(state)) { statesForDefaultEntry.push_back(state); +#if 0 NodeSet<std::string> tStates = getTargetStates(getInitialState(state)); for (int i = 0; i < tStates.size(); i++) { addStatesToEnter(tStates[i], statesToEnter, statesForDefaultEntry); } +#endif + addStatesToEnter(getInitialState(state), statesToEnter, statesForDefaultEntry); +// NodeSet<std::string> tStates = getTargetStates(getInitialState(state)); + } else if(isParallel(state)) { NodeSet<std::string> childStates = getChildStates(state); for (int i = 0; i < childStates.size(); i++) { @@ -1300,9 +1370,11 @@ Arabica::XPath::NodeSet<std::string> Interpreter::getChildStates(const Arabica:: Arabica::XPath::NodeSet<std::string> childs; Arabica::XPath::NodeSet<std::string> stateChilds = _xpath.evaluate("" + _nsPrefix + "state", state).asNodeSet(); Arabica::XPath::NodeSet<std::string> parallelChilds = _xpath.evaluate("" + _nsPrefix + "parallel", state).asNodeSet(); + Arabica::XPath::NodeSet<std::string> finalChilds = _xpath.evaluate("" + _nsPrefix + "final", state).asNodeSet(); childs.insert(childs.begin(), stateChilds.begin(), stateChilds.end()); childs.insert(childs.begin(), parallelChilds.begin(), parallelChilds.end()); + childs.insert(childs.begin(), finalChilds.begin(), finalChilds.end()); return childs; } @@ -1406,7 +1478,9 @@ NodeSet<std::string> Interpreter::getTargetStates(const Arabica::DOM::Node<std:: std::vector<std::string> targetIds = Interpreter::tokenizeIdRefs(ATTR(transition, "target")); for (int i = 0; i < targetIds.size(); i++) { - targetStates.push_back(getState(targetIds[i])); + Arabica::DOM::Node<std::string> state = getState(targetIds[i]); + assert(HAS_ATTR(state, "id")); + targetStates.push_back(state); } return targetStates; } @@ -1567,7 +1641,7 @@ void Interpreter::setupIOProcessors() { try { // _dataModel->setData("_ioprocessors", ioProcIter->first, _ioProcessors[ioProcIter->first]->getDataModelVariables()); _dataModel->assign("_ioprocessors['" + ioProcIter->first + "']", _ioProcessors[ioProcIter->first]->getDataModelVariables()); - std::cout << _dataModel->evalAsString("_ioprocessors['basichttp'].location") << std::endl; +// std::cout << _dataModel->evalAsString("_ioprocessors['basichttp'].location") << std::endl; } catch (Event e) { LOG(ERROR) << "Syntax error when setting _ioprocessors:" << std::endl << e << std::endl; } diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index a60f9f6..9447498 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -132,6 +132,7 @@ namespace uscxml { void invoke(const Arabica::DOM::Node<std::string>& element); void cancelInvoke(const Arabica::DOM::Node<std::string>& element); void returnDoneEvent(const Arabica::DOM::Node<std::string>& state); + void internalDoneSend(const Arabica::DOM::Node<std::string>& state); static void delayedSend(void* userdata, std::string eventName); static bool nameMatch(const std::string& transitionEvent, const std::string& event); diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp index f7e7a5a..9b713ca 100644 --- a/src/uscxml/Message.cpp +++ b/src/uscxml/Message.cpp @@ -101,6 +101,7 @@ Arabica::DOM::Document<std::string> Event::toDocument() { Arabica::DOM::Document<std::string> document = Data::toDocument(); Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement(); + scxmlMsg.setAttribute("source", origin); scxmlMsg.setAttribute("name", name); @@ -112,6 +113,40 @@ Arabica::DOM::Document<std::string> SendRequest::toDocument() { Arabica::DOM::Document<std::string> document = Event::toDocument(); Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement(); + // add params and namelist + if (params.size() > 0 || namelist.size() > 0) { + Arabica::DOM::NodeList<std::string> payload = scxmlMsg.getElementsByTagName("scxml:payload"); + if (payload.getLength() == 0) { + Arabica::DOM::Element<std::string> payloadElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "scxml:payload"); + scxmlMsg.appendChild(payloadElem); + } + Arabica::DOM::Node<std::string> payloadElem = scxmlMsg.getElementsByTagName("scxml:payload").item(0); + + // add parameters + std::map<std::string, std::string>::iterator paramIter = params.begin(); + while(paramIter != params.end()) { + Arabica::DOM::Element<std::string> propertyElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "scxml:property"); + propertyElem.setAttribute("name", paramIter->first); + Arabica::DOM::Text<std::string> textElem = document.createTextNode(paramIter->second); + propertyElem.appendChild(textElem); + payloadElem.appendChild(propertyElem); + paramIter++; + } + + // add namelist elements + std::map<std::string, std::string>::iterator namelistIter = namelist.begin(); + while(namelistIter != namelist.end()) { + Arabica::DOM::Element<std::string> propertyElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "scxml:property"); + propertyElem.setAttribute("name", namelistIter->first); + Arabica::DOM::Text<std::string> textElem = document.createTextNode(namelistIter->second); + propertyElem.appendChild(textElem); + payloadElem.appendChild(propertyElem); + namelistIter++; + } + + } + + scxmlMsg.setAttribute("sendid", sendid); return document; @@ -146,6 +181,31 @@ Event Event::fromXML(const std::string& xmlString) { event.name = ATTR(scxmlMsg, "name"); if (HAS_ATTR(scxmlMsg, "sendid")) event.sendid = ATTR(scxmlMsg, "sendid"); + + Arabica::DOM::NodeList<std::string> payloads = scxmlMsg.getElementsByTagName("scxml:payload"); + if (payloads.getLength() > 0) { + Arabica::DOM::Node<std::string> payload = payloads.item(0); + if (payload.getNodeType() == Arabica::DOM::Node_base::ELEMENT_NODE) { + Arabica::DOM::Element<std::string> payloadElem = (Arabica::DOM::Element<std::string>)payload; + Arabica::DOM::NodeList<std::string> properties = payloadElem.getElementsByTagName("scxml:property"); + if (properties.getLength() > 0) { + for (int i = 0; i < properties.getLength(); i++) { + if (HAS_ATTR(properties.item(i), "name")) { + std::string key = ATTR(properties.item(i), "name"); + std::string value; + Arabica::DOM::NodeList<std::string> childs = properties.item(i).getChildNodes(); + for (int j = 0; j < childs.getLength(); j++) { + if (childs.item(j).getNodeType() == Arabica::DOM::Node_base::TEXT_NODE) { + value = childs.item(j).getNodeValue(); + break; + } + } + event.compound[key] = Data(value, VERBATIM); + } + } + } + } + } } return event; } @@ -160,7 +220,7 @@ InvokeRequest InvokeRequest::fromXML(const std::string& xmlString) { #ifndef SWIGJAVA std::ostream& operator<< (std::ostream& os, const Event& event) { - os << (event.type == Event::EXTERNAL ? "External" : "Internal") << " Event " << (event.dom ? "with DOM attached" : "") << std::endl; + os << (event.type == Event::EXTERNAL ? "External" : "Internal") << " Event " /* << (event.dom ? "with DOM attached" : "")*/ << std::endl; if (event.name.size() > 0) os << " name: " << event.name << std::endl; diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index cd10c05..34b85e1 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -57,12 +57,13 @@ public: }; Event() : type(INTERNAL) {} - + Event(const Arabica::DOM::Node<std::string>& xmlString) : type(INTERNAL) {}; + std::string name; Type type; std::string origin; std::string origintype; - Arabica::DOM::Node<std::string> dom; +// Arabica::DOM::Node<std::string> dom; std::string sendid; std::string invokeid; @@ -85,7 +86,6 @@ public: std::string src; std::string namelist; bool autoForward; - Arabica::DOM::Node<std::string> finalize; std::map<std::string, std::string> params; std::string content; @@ -113,6 +113,7 @@ public: std::string toXMLString() { std::stringstream ss; ss << toDocument(); +// std::cout << ss.str() << std::endl; return ss.str(); } diff --git a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp b/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp index 647380e..c5e7c3b 100644 --- a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp +++ b/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp @@ -11,7 +11,7 @@ namespace uscxml { } DelayedEventQueue::~DelayedEventQueue() { - std::cout << "Deleting DelayedEventQueue" << std::endl; +// std::cout << "Deleting DelayedEventQueue" << std::endl; stop(); if (_thread) _thread->join(); diff --git a/src/uscxml/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/invoker/scxml/USCXMLInvoker.cpp index 2f5a0b6..1403d99 100644 --- a/src/uscxml/invoker/scxml/USCXMLInvoker.cpp +++ b/src/uscxml/invoker/scxml/USCXMLInvoker.cpp @@ -3,8 +3,7 @@ namespace uscxml { -USCXMLInvoker::USCXMLInvoker() { - +USCXMLInvoker::USCXMLInvoker() { } @@ -24,18 +23,20 @@ Data USCXMLInvoker::getDataModelVariables() { } void USCXMLInvoker::send(SendRequest& req) { - + assert(false); } void USCXMLInvoker::cancel(const std::string sendId) { - + assert(false); } void USCXMLInvoker::sendToParent(SendRequest& req) { + req.invokeid = _invokeId; _parentInterpreter->receive(req); } void USCXMLInvoker::invoke(InvokeRequest& req) { + _invokeId = req.invokeid; _invokedInterpreter = Interpreter::fromURI(req.src); DataModel* dataModel = _invokedInterpreter->getDataModel(); if (dataModel != NULL) { diff --git a/src/uscxml/invoker/scxml/USCXMLInvoker.h b/src/uscxml/invoker/scxml/USCXMLInvoker.h index 2fc9d25..76657d8 100644 --- a/src/uscxml/invoker/scxml/USCXMLInvoker.h +++ b/src/uscxml/invoker/scxml/USCXMLInvoker.h @@ -20,6 +20,7 @@ public: virtual void sendToParent(SendRequest& req); protected: + std::string _invokeId; Interpreter* _invokedInterpreter; Interpreter* _parentInterpreter; }; diff --git a/src/uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.cpp b/src/uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.cpp index 4daf179..d0adcb3 100644 --- a/src/uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.cpp +++ b/src/uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.cpp @@ -159,7 +159,8 @@ void EventIOProcessor::httpRecvReq(struct evhttp_request *req, void *arg) { Event reqEvent; reqEvent.type = Event::EXTERNAL; - + bool scxmlStructFound = false; + // map headers to event structure headers = evhttp_request_get_input_headers(req); for (header = headers->tqh_first; header; @@ -168,6 +169,7 @@ void EventIOProcessor::httpRecvReq(struct evhttp_request *req, void *arg) { // std::cout << "Value: " << evhttp_decode_uri(header->value) << std::endl; if (boost::iequals("_scxmleventstruct", header->key)) { reqEvent = Event::fromXML(evhttp_decode_uri(header->value)); + scxmlStructFound = true; break; } else if (boost::iequals("_scxmleventname", header->key)) { reqEvent.name = evhttp_decode_uri(header->value); @@ -176,18 +178,20 @@ void EventIOProcessor::httpRecvReq(struct evhttp_request *req, void *arg) { } } - // get content into event - std::string content; - buf = evhttp_request_get_input_buffer(req); - while (evbuffer_get_length(buf)) { - int n; - char cbuf[128]; - n = evbuffer_remove(buf, cbuf, sizeof(buf)-1); - if (n > 0) { - content.append(cbuf, n); + if (!scxmlStructFound) { + // get content into event + std::string content; + buf = evhttp_request_get_input_buffer(req); + while (evbuffer_get_length(buf)) { + int n; + char cbuf[128]; + n = evbuffer_remove(buf, cbuf, sizeof(buf)-1); + if (n > 0) { + content.append(cbuf, n); + } } - } - reqEvent.compound["content"] = Data(content, Data::VERBATIM); + reqEvent.compound["content"] = Data(content, Data::VERBATIM); + } EventIOProcessor* THIS = (EventIOProcessor*)arg; THIS->_interpreter->receive(reqEvent); |