summaryrefslogtreecommitdiffstats
path: root/src/uscxml/Interpreter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/uscxml/Interpreter.cpp')
-rw-r--r--src/uscxml/Interpreter.cpp3411
1 files changed, 1707 insertions, 1704 deletions
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index 17d499a..604921a 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -25,7 +25,7 @@ using namespace Arabica::DOM;
boost::uuids::random_generator Interpreter::uuidGen;
const std::string Interpreter::getUUID() {
- return boost::lexical_cast<std::string>(uuidGen());
+ return boost::lexical_cast<std::string>(uuidGen());
}
Interpreter::Interpreter() {
@@ -34,1166 +34,1171 @@ Interpreter::Interpreter() {
WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
}
-
+
Interpreter* Interpreter::fromDOM(const Arabica::DOM::Node<std::string>& node) {
- Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation();
- Interpreter* interpreter = new Interpreter();
- interpreter->_doc = domFactory.createDocument("http://www.w3.org/2005/07/scxml", "scxml", 0);
- interpreter->_doc.appendChild(node);
- interpreter->init();
+ Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation();
+ Interpreter* interpreter = new Interpreter();
+ interpreter->_doc = domFactory.createDocument("http://www.w3.org/2005/07/scxml", "scxml", 0);
+ interpreter->_doc.appendChild(node);
+ interpreter->init();
- return interpreter;
+ return interpreter;
}
Interpreter* Interpreter::fromXML(const std::string& xml) {
- std::istringstream is(xml);
- Arabica::SAX::InputSource<std::string> inputSource;
- return fromInputSource(inputSource);
+ std::istringstream is(xml);
+ Arabica::SAX::InputSource<std::string> inputSource;
+ return fromInputSource(inputSource);
}
Interpreter* Interpreter::fromURI(const std::string& uri) {
- Arabica::SAX::InputSource<std::string> inputSource(uri);
- Interpreter* interpreter = fromInputSource(inputSource);
+ Arabica::SAX::InputSource<std::string> inputSource(uri);
+ Interpreter* interpreter = fromInputSource(inputSource);
- // try to establish URI root for relative src attributes in document
- interpreter->_baseURI = toBaseURI(Arabica::io::URI(uri));
- return interpreter;
+ // try to establish URI root for relative src attributes in document
+ interpreter->_baseURI = toBaseURI(Arabica::io::URI(uri));
+ return interpreter;
}
Arabica::io::URI Interpreter::toBaseURI(const Arabica::io::URI& uri) {
- std::stringstream ssBaseURI;
- if (uri.scheme().size() > 0) {
- ssBaseURI << uri.scheme() << "://";
- } else {
- ssBaseURI << "file://";
- }
- if (uri.host().size() > 0) {
- ssBaseURI << uri.host();
- if (!boost::iequals(uri.port(), "0"))
- ssBaseURI << ":" << uri.port();
- }
- if (uri.path().size() > 0) {
- std::string uriPath = uri.path();
- uriPath = uriPath.substr(0, uriPath.find_last_of("/\\"));
- ssBaseURI << uriPath;
- }
- return Arabica::io::URI(ssBaseURI.str());
+ std::stringstream ssBaseURI;
+ if (uri.scheme().size() > 0) {
+ ssBaseURI << uri.scheme() << "://";
+ } else {
+ ssBaseURI << "file://";
+ }
+ if (uri.host().size() > 0) {
+ ssBaseURI << uri.host();
+ if (!boost::iequals(uri.port(), "0"))
+ ssBaseURI << ":" << uri.port();
+ }
+ if (uri.path().size() > 0) {
+ std::string uriPath = uri.path();
+ uriPath = uriPath.substr(0, uriPath.find_last_of("/\\"));
+ ssBaseURI << uriPath;
+ }
+ return Arabica::io::URI(ssBaseURI.str());
}
bool Interpreter::makeAbsolute(Arabica::io::URI& uri) {
- if (uri.is_absolute())
- return true;
-
- if (_baseURI.as_string().size() > 0) {
- std::stringstream ssAbsoluteURI;
- if (_baseURI.scheme().size() > 0)
- ssAbsoluteURI << _baseURI.scheme() << "://";
- if (_baseURI.host().size() > 0) {
- ssAbsoluteURI << _baseURI.host();
- if (!boost::iequals(_baseURI.port(), "0"))
- ssAbsoluteURI << ":" << _baseURI.port();
- }
- if (_baseURI.path().size() > 0) {
- ssAbsoluteURI << _baseURI.path() << "/" << uri.path();
- }
- uri = Arabica::io::URI(ssAbsoluteURI.str());
- return true;
- }
- return false;
+ if (uri.is_absolute())
+ return true;
+
+ if (_baseURI.as_string().size() > 0) {
+ std::stringstream ssAbsoluteURI;
+ if (_baseURI.scheme().size() > 0)
+ ssAbsoluteURI << _baseURI.scheme() << "://";
+ if (_baseURI.host().size() > 0) {
+ ssAbsoluteURI << _baseURI.host();
+ if (!boost::iequals(_baseURI.port(), "0"))
+ ssAbsoluteURI << ":" << _baseURI.port();
+ }
+ if (_baseURI.path().size() > 0) {
+ ssAbsoluteURI << _baseURI.path() << "/" << uri.path();
+ }
+ uri = Arabica::io::URI(ssAbsoluteURI.str());
+ return true;
+ }
+ return false;
}
Interpreter* Interpreter::fromInputSource(Arabica::SAX::InputSource<std::string>& source) {
- Interpreter* interpreter = new Interpreter();
-
- Arabica::SAX2DOM::Parser<std::string> domParser;
- Arabica::SAX::CatchErrorHandler<std::string> errorHandler;
- domParser.setErrorHandler(errorHandler);
- if(!domParser.parse(source) || !domParser.getDocument().hasChildNodes()) {
- LOG(INFO) << "could not parse input:";
- if(errorHandler.errorsReported()) {
- LOG(ERROR) << errorHandler.errors() << std::endl;
- } else {
- Arabica::SAX::InputSourceResolver resolver(source, Arabica::default_string_adaptor<std::string>());
- if (!resolver.resolve()) {
- LOG(ERROR) << "no such file";
- }
- }
- } else {
- interpreter->_doc = domParser.getDocument();
- }
- interpreter->init();
- return interpreter;
+ Interpreter* interpreter = new Interpreter();
+
+ Arabica::SAX2DOM::Parser<std::string> domParser;
+ Arabica::SAX::CatchErrorHandler<std::string> errorHandler;
+ domParser.setErrorHandler(errorHandler);
+ if(!domParser.parse(source) || !domParser.getDocument().hasChildNodes()) {
+ LOG(INFO) << "could not parse input:";
+ if(errorHandler.errorsReported()) {
+ LOG(ERROR) << errorHandler.errors() << std::endl;
+ } else {
+ Arabica::SAX::InputSourceResolver resolver(source, Arabica::default_string_adaptor<std::string>());
+ if (!resolver.resolve()) {
+ LOG(ERROR) << "no such file";
+ }
+ }
+ } else {
+ interpreter->_doc = domParser.getDocument();
+ }
+ interpreter->init();
+ return interpreter;
}
void Interpreter::init() {
_thread = NULL;
- _dataModel = NULL;
- _invoker = NULL;
- _running = false;
- _sendQueue = new DelayedEventQueue();
- _sendQueue->start();
- if (_doc) {
- // do we have a xmlns attribute?
- std::string ns = _doc.getDocumentElement().getNamespaceURI();
- if(ns.size() > 0) {
- _nsContext.addNamespaceDeclaration(ns, "sc");
- _xpath.setNamespaceContext(_nsContext);
- _nsPrefix = "sc:";
- }
- NodeList<std::string> scxmls = _doc.getElementsByTagName("scxml");
- if (scxmls.getLength() > 0) {
- _scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0);
- normalize(_doc);
- _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : getUUID());
- } else {
- LOG(ERROR) << "Cannot find SCXML element" << std::endl;
- }
- }
+ _dataModel = NULL;
+ _invoker = NULL;
+ _running = false;
+ _sendQueue = new DelayedEventQueue();
+ _sendQueue->start();
+ if (_doc) {
+ // do we have a xmlns attribute?
+ std::string ns = _doc.getDocumentElement().getNamespaceURI();
+ if(ns.size() > 0) {
+ _nsContext.addNamespaceDeclaration(ns, "sc");
+ _xpath.setNamespaceContext(_nsContext);
+ _nsPrefix = "sc:";
+ }
+ NodeList<std::string> scxmls = _doc.getElementsByTagName("scxml");
+ if (scxmls.getLength() > 0) {
+ _scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0);
+ normalize(_doc);
+ _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : getUUID());
+ } else {
+ LOG(ERROR) << "Cannot find SCXML element" << std::endl;
+ }
+ }
}
Interpreter::~Interpreter() {
- std::map<std::string, IOProcessor*>::iterator ioProcessorIter = _ioProcessors.begin();
- while(ioProcessorIter != _ioProcessors.end()) {
- delete ioProcessorIter->second;
- ioProcessorIter++;
- }
+ std::map<std::string, IOProcessor*>::iterator ioProcessorIter = _ioProcessors.begin();
+ while(ioProcessorIter != _ioProcessors.end()) {
+ delete ioProcessorIter->second;
+ ioProcessorIter++;
+ }
if (_thread) {
- _running = false;
- _externalQueue.push(Event());
- _thread->join();
+ _running = false;
+ _externalQueue.push(Event());
+ _thread->join();
delete(_thread);
}
- delete _dataModel;
- delete _sendQueue;
+ delete _dataModel;
+ delete _sendQueue;
}
void Interpreter::start() {
- _thread = new tthread::thread(Interpreter::run, this);
+ _thread = new tthread::thread(Interpreter::run, this);
}
-
+
void Interpreter::run(void* instance) {
((Interpreter*)instance)->interpret();
}
void Interpreter::waitForStabilization() {
- tthread::lock_guard<tthread::mutex> lock(_mutex);
- _stabilized.wait(_mutex);
+ tthread::lock_guard<tthread::mutex> lock(_mutex);
+ _stabilized.wait(_mutex);
}
-
+
// see: http://www.w3.org/TR/scxml/#AlgorithmforSCXMLInterpretation
void Interpreter::interpret() {
- if (!_scxml)
- return;
+ if (!_scxml)
+ return;
// dump();
- _sessionId = getUUID();
-
- if(HAS_ATTR(_scxml, "datamodel")) {
+ _sessionId = getUUID();
+
+ if(HAS_ATTR(_scxml, "datamodel")) {
_dataModel = Factory::getDataModel(ATTR(_scxml, "datamodel"), this);
if(_dataModel == NULL) {
- LOG(ERROR) << "No datamodel for " << ATTR(_scxml, "datamodel") << " registered";
- return;
- }
- }
+ LOG(ERROR) << "No datamodel for " << ATTR(_scxml, "datamodel") << " registered";
+ return;
+ }
+ }
- setupIOProcessors();
+ setupIOProcessors();
- // executeGlobalScriptElements
- NodeSet<std::string> globalScriptElems = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "script", _doc).asNodeSet();
- for (unsigned int i = 0; i < globalScriptElems.size(); i++) {
+ // executeGlobalScriptElements
+ NodeSet<std::string> globalScriptElems = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "script", _doc).asNodeSet();
+ for (unsigned int i = 0; i < globalScriptElems.size(); i++) {
// std::cout << globalScriptElems[i].getFirstChild().getNodeValue() << std::endl;
- if (_dataModel)
- executeContent(globalScriptElems[i]);
- }
-
- _running = true;
-
- std::string binding = _xpath.evaluate("/" + _nsPrefix + "scxml/@binding", _doc).asString();
- _binding = (boost::iequals(binding, "late") ? LATE : EARLY);
-
- // initialize all data elements
- if (_dataModel && _binding == EARLY) {
- NodeSet<std::string> dataElems = _xpath.evaluate("//" + _nsPrefix + "data", _doc).asNodeSet();
- for (unsigned int i = 0; i < dataElems.size(); i++) {
- initializeData(dataElems[i]);
- }
- } else if(_dataModel) {
- NodeSet<std::string> topDataElems = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "datamodel/" + _nsPrefix + "data", _doc).asNodeSet();
- for (unsigned int i = 0; i < topDataElems.size(); i++) {
- initializeData(topDataElems[i]);
- }
- }
-
- // we made sure during normalization that this element exists
- NodeSet<std::string> initialTransitions = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "initial/" + _nsPrefix + "transition", _doc).asNodeSet();
- assert(initialTransitions.size() > 0);
- initialTransitions.push_back(initialTransitions[0]);
- enterStates(initialTransitions);
-
- mainEventLoop();
+ if (_dataModel)
+ executeContent(globalScriptElems[i]);
+ }
+
+ _running = true;
+
+ std::string binding = _xpath.evaluate("/" + _nsPrefix + "scxml/@binding", _doc).asString();
+ _binding = (boost::iequals(binding, "late") ? LATE : EARLY);
+
+ // initialize all data elements
+ if (_dataModel && _binding == EARLY) {
+ NodeSet<std::string> dataElems = _xpath.evaluate("//" + _nsPrefix + "data", _doc).asNodeSet();
+ for (unsigned int i = 0; i < dataElems.size(); i++) {
+ initializeData(dataElems[i]);
+ }
+ } else if(_dataModel) {
+ NodeSet<std::string> topDataElems = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "datamodel/" + _nsPrefix + "data", _doc).asNodeSet();
+ for (unsigned int i = 0; i < topDataElems.size(); i++) {
+ initializeData(topDataElems[i]);
+ }
+ }
+
+ // we made sure during normalization that this element exists
+ NodeSet<std::string> initialTransitions = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "initial/" + _nsPrefix + "transition", _doc).asNodeSet();
+ assert(initialTransitions.size() > 0);
+ initialTransitions.push_back(initialTransitions[0]);
+ enterStates(initialTransitions);
+
+ mainEventLoop();
}
/**
* Called with a single data element from the topmost datamodel element.
*/
void Interpreter::initializeData(const Arabica::DOM::Node<std::string>& data) {
- if (!_dataModel) {
- LOG(ERROR) << "Cannot initialize data when no datamodel is given!";
- return;
- }
- try {
- if (!HAS_ATTR(data, "id"))
- return;
-
- if (HAS_ATTR(data, "expr")) {
- std::string value = ATTR(data, "expr");
- _dataModel->assign(ATTR(data, "id"), value);
- } else if (HAS_ATTR(data, "src")) {
- Arabica::SAX::InputSourceResolver resolver(Arabica::SAX::InputSource<std::string>(ATTR(data, "src")),
- Arabica::default_string_adaptor<std::string>());
- std::string value = std::string(std::istreambuf_iterator<char>(*resolver.resolve()), std::istreambuf_iterator<char>());
- _dataModel->assign(ATTR(data, "id"), value);
- } else if (data.hasChildNodes()) {
- // search for the text node with the actual script
- NodeList<std::string> dataChilds = data.getChildNodes();
- for (int i = 0; i < dataChilds.getLength(); i++) {
- if (dataChilds.item(i).getNodeType() == Node_base::TEXT_NODE) {
- Data value = Data(dataChilds.item(i).getNodeValue());
- _dataModel->assign(ATTR(data, "id"), value);
- break;
- }
- }
+ if (!_dataModel) {
+ LOG(ERROR) << "Cannot initialize data when no datamodel is given!";
+ return;
+ }
+ try {
+ if (!HAS_ATTR(data, "id"))
+ return;
+
+ if (HAS_ATTR(data, "expr")) {
+ std::string value = ATTR(data, "expr");
+ _dataModel->assign(ATTR(data, "id"), value);
+ } else if (HAS_ATTR(data, "src")) {
+ Arabica::SAX::InputSourceResolver resolver(Arabica::SAX::InputSource<std::string>(ATTR(data, "src")),
+ Arabica::default_string_adaptor<std::string>());
+ std::string value = std::string(std::istreambuf_iterator<char>(*resolver.resolve()), std::istreambuf_iterator<char>());
+ _dataModel->assign(ATTR(data, "id"), value);
+ } else if (data.hasChildNodes()) {
+ // search for the text node with the actual script
+ NodeList<std::string> dataChilds = data.getChildNodes();
+ for (int i = 0; i < dataChilds.getLength(); i++) {
+ if (dataChilds.item(i).getNodeType() == Node_base::TEXT_NODE) {
+ Data value = Data(dataChilds.item(i).getNodeValue());
+ _dataModel->assign(ATTR(data, "id"), value);
+ break;
+ }
+ }
// std::cout << value << std::endl;
- }
-
- } catch (Event e) {
- LOG(ERROR) << "Syntax error in send element:" << std::endl << e << std::endl;
- }
+ }
+
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in send element:" << std::endl << e << std::endl;
+ }
}
void Interpreter::normalize(const Arabica::DOM::Document<std::string>& node) {
- // make sure every state has an id and set isFirstEntry to true
- Arabica::XPath::NodeSet<std::string> states = _xpath.evaluate("//" + _nsPrefix + "state", _doc).asNodeSet();
- for (int i = 0; i < states.size(); i++) {
- Arabica::DOM::Element<std::string> stateElem = Arabica::DOM::Element<std::string>(states[i]);
- stateElem.setAttribute("isFirstEntry", "true");
- if (!stateElem.hasAttribute("id")) {
- stateElem.setAttribute("id", getUUID());
- }
- }
-
- // make sure every invoke has an idlocation or id
- Arabica::XPath::NodeSet<std::string> invokes = _xpath.evaluate("//" + _nsPrefix + "invoke", _doc).asNodeSet();
- for (int i = 0; i < invokes.size(); i++) {
- Arabica::DOM::Element<std::string> invokeElem = Arabica::DOM::Element<std::string>(invokes[i]);
- if (!invokeElem.hasAttribute("id") && !invokeElem.hasAttribute("idlocation")) {
- invokeElem.setAttribute("id", getUUID());
- }
+ // make sure every state has an id and set isFirstEntry to true
+ Arabica::XPath::NodeSet<std::string> states = _xpath.evaluate("//" + _nsPrefix + "state", _doc).asNodeSet();
+ for (int i = 0; i < states.size(); i++) {
+ Arabica::DOM::Element<std::string> stateElem = Arabica::DOM::Element<std::string>(states[i]);
+ stateElem.setAttribute("isFirstEntry", "true");
+ if (!stateElem.hasAttribute("id")) {
+ stateElem.setAttribute("id", getUUID());
+ }
+ }
+
+ // make sure every invoke has an idlocation or id
+ Arabica::XPath::NodeSet<std::string> invokes = _xpath.evaluate("//" + _nsPrefix + "invoke", _doc).asNodeSet();
+ for (int i = 0; i < invokes.size(); i++) {
+ Arabica::DOM::Element<std::string> invokeElem = Arabica::DOM::Element<std::string>(invokes[i]);
+ if (!invokeElem.hasAttribute("id") && !invokeElem.hasAttribute("idlocation")) {
+ invokeElem.setAttribute("id", getUUID());
+ }
// // make sure every finalize element contained has the invoke id as an attribute
// Arabica::XPath::NodeSet<std::string> finalizes = _xpath.evaluate("" + _nsPrefix + "finalize", invokeElem).asNodeSet();
// for (int j = 0; j < finalizes.size(); j++) {
// Arabica::DOM::Element<std::string> finalizeElem = Arabica::DOM::Element<std::string>(finalizes[j]);
// finalizeElem.setAttribute("invokeid", invokeElem.getAttribute("id"));
// }
- }
-
- Arabica::XPath::NodeSet<std::string> finals = _xpath.evaluate("//" + _nsPrefix + "final", _doc).asNodeSet();
- for (int i = 0; i < finals.size(); i++) {
- Arabica::DOM::Element<std::string> finalElem = Arabica::DOM::Element<std::string>(finals[i]);
- finalElem.setAttribute("isFirstEntry", "true");
- if (!finalElem.hasAttribute("id")) {
- finalElem.setAttribute("id", getUUID());
- }
- }
-
- Arabica::XPath::NodeSet<std::string> histories = _xpath.evaluate("//" + _nsPrefix + "history", _doc).asNodeSet();
- for (int i = 0; i < histories.size(); i++) {
- Arabica::DOM::Element<std::string> historyElem = Arabica::DOM::Element<std::string>(histories[i]);
- if (!historyElem.hasAttribute("id")) {
- historyElem.setAttribute("id", getUUID());
- }
- }
-
- Arabica::XPath::NodeSet<std::string> scxml = _xpath.evaluate("/" + _nsPrefix + "scxml", _doc).asNodeSet();
- if (!((Arabica::DOM::Element<std::string>)scxml[0]).hasAttribute("id")) {
- ((Arabica::DOM::Element<std::string>)scxml[0]).setAttribute("id", getUUID());
- }
-
- // create a pseudo initial and transition element
- Arabica::DOM::Element<std::string> initialState = (Arabica::DOM::Element<std::string>)getInitialState();
- Arabica::DOM::Element<std::string> initialElem = _doc.createElement("initial");
- Arabica::DOM::Element<std::string> transitionElem = _doc.createElement("transition");
- transitionElem.setAttribute("target", initialState.getAttribute("id"));
- initialElem.appendChild(transitionElem);
- _scxml.appendChild(initialElem);
-
-}
-
+ }
+
+ Arabica::XPath::NodeSet<std::string> finals = _xpath.evaluate("//" + _nsPrefix + "final", _doc).asNodeSet();
+ for (int i = 0; i < finals.size(); i++) {
+ Arabica::DOM::Element<std::string> finalElem = Arabica::DOM::Element<std::string>(finals[i]);
+ finalElem.setAttribute("isFirstEntry", "true");
+ if (!finalElem.hasAttribute("id")) {
+ finalElem.setAttribute("id", getUUID());
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> histories = _xpath.evaluate("//" + _nsPrefix + "history", _doc).asNodeSet();
+ for (int i = 0; i < histories.size(); i++) {
+ Arabica::DOM::Element<std::string> historyElem = Arabica::DOM::Element<std::string>(histories[i]);
+ if (!historyElem.hasAttribute("id")) {
+ historyElem.setAttribute("id", getUUID());
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> scxml = _xpath.evaluate("/" + _nsPrefix + "scxml", _doc).asNodeSet();
+ if (!((Arabica::DOM::Element<std::string>)scxml[0]).hasAttribute("id")) {
+ ((Arabica::DOM::Element<std::string>)scxml[0]).setAttribute("id", getUUID());
+ }
+
+ // create a pseudo initial and transition element
+ Arabica::DOM::Element<std::string> initialState = (Arabica::DOM::Element<std::string>)getInitialState();
+ Arabica::DOM::Element<std::string> initialElem = _doc.createElement("initial");
+ Arabica::DOM::Element<std::string> transitionElem = _doc.createElement("transition");
+ transitionElem.setAttribute("target", initialState.getAttribute("id"));
+ initialElem.appendChild(transitionElem);
+ _scxml.appendChild(initialElem);
+
+}
+
void Interpreter::mainEventLoop() {
- while(_running) {
- NodeSet<std::string> enabledTransitions;
- _stable = false;
+ while(_running) {
+ NodeSet<std::string> enabledTransitions;
+ _stable = false;
- // Here we handle eventless transitions and transitions
- // triggered by internal events until machine is stable
- while(_running && !_stable) {
+ // Here we handle eventless transitions and transitions
+ // triggered by internal events until machine is stable
+ while(_running && !_stable) {
#if 0
- std::cout << "Configuration: ";
- for (int i = 0; i < _configuration.size(); i++) {
- std::cout << ((Arabica::DOM::Element<std::string>)_configuration[i]).getAttribute("id") << ", ";
- }
- std::cout << std::endl;
+ std::cout << "Configuration: ";
+ for (int i = 0; i < _configuration.size(); i++) {
+ std::cout << ((Arabica::DOM::Element<std::string>)_configuration[i]).getAttribute("id") << ", ";
+ }
+ std::cout << std::endl;
#endif
- enabledTransitions = selectEventlessTransitions();
- if (enabledTransitions.size() == 0) {
- if (_internalQueue.size() == 0) {
- _stable = true;
- } else {
- Event internalEvent = _internalQueue.front();
- _internalQueue.pop_front();
+ enabledTransitions = selectEventlessTransitions();
+ if (enabledTransitions.size() == 0) {
+ if (_internalQueue.size() == 0) {
+ _stable = true;
+ } else {
+ Event internalEvent = _internalQueue.front();
+ _internalQueue.pop_front();
#if 0
- std::cout << "Received internal event " << internalEvent.name << std::endl;
+ std::cout << "Received internal event " << internalEvent.name << std::endl;
#endif
- if (_dataModel)
- _dataModel->setEvent(internalEvent);
- enabledTransitions = selectTransitions(internalEvent.name);
- }
- }
- if (!enabledTransitions.empty())
- microstep(enabledTransitions);
- }
-
- for (unsigned int i = 0; i < _statesToInvoke.size(); i++) {
- NodeSet<std::string> invokes = _xpath.evaluate("" + _nsPrefix + "invoke", _statesToInvoke[i]).asNodeSet();
- for (unsigned int j = 0; j < invokes.size(); j++) {
- invoke(invokes[j]);
- }
- }
-
- _statesToInvoke = NodeSet<std::string>();
- if (!_internalQueue.empty())
- continue;
-
- {
- tthread::lock_guard<tthread::mutex> lock(_mutex);
- _stabilized.notify_all();
- }
-
- Event externalEvent = _externalQueue.pop();
- if (!_running)
- exitInterpreter();
-
- if (_dataModel && boost::iequals(externalEvent.name, "cancel.invoke." + _sessionId))
- break;
-
- if (_dataModel)
- try {
- _dataModel->setEvent(externalEvent);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl;
- }
- for (unsigned int i = 0; i < _configuration.size(); i++) {
- NodeSet<std::string> invokes = _xpath.evaluate("" + _nsPrefix + "invoke", _configuration[i]).asNodeSet();
- for (unsigned int j = 0; j < invokes.size(); j++) {
- Arabica::DOM::Element<std::string> invokeElem = (Arabica::DOM::Element<std::string>)invokes[j];
- std::string invokeId = invokeElem.getAttribute("id");
- std::string autoForward = invokeElem.getAttribute("autoforward");
- if (boost::iequals(invokeId, externalEvent.invokeid)) {
-
- Arabica::XPath::NodeSet<std::string> finalizes = _xpath.evaluate("" + _nsPrefix + "finalize", invokeElem).asNodeSet();
- for (int k = 0; k < finalizes.size(); k++) {
- Arabica::DOM::Element<std::string> finalizeElem = Arabica::DOM::Element<std::string>(finalizes[k]);
- executeContent(finalizeElem);
- }
-
-
- }
- if (autoForward.length() > 0) {
- // @TODO
+ if (_dataModel)
+ _dataModel->setEvent(internalEvent);
+ enabledTransitions = selectTransitions(internalEvent.name);
+ }
+ }
+ if (!enabledTransitions.empty())
+ microstep(enabledTransitions);
+ }
+
+ for (unsigned int i = 0; i < _statesToInvoke.size(); i++) {
+ NodeSet<std::string> invokes = _xpath.evaluate("" + _nsPrefix + "invoke", _statesToInvoke[i]).asNodeSet();
+ for (unsigned int j = 0; j < invokes.size(); j++) {
+ invoke(invokes[j]);
+ }
+ }
+
+ _statesToInvoke = NodeSet<std::string>();
+ if (!_internalQueue.empty())
+ continue;
+
+ {
+ tthread::lock_guard<tthread::mutex> lock(_mutex);
+ _stabilized.notify_all();
+ }
+
+ Event externalEvent = _externalQueue.pop();
+ if (!_running)
+ exitInterpreter();
+
+ if (_dataModel && boost::iequals(externalEvent.name, "cancel.invoke." + _sessionId))
+ break;
+
+ if (_dataModel)
+ try {
+ _dataModel->setEvent(externalEvent);
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error while setting external event:" << std::endl << e << std::endl;
+ }
+ for (unsigned int i = 0; i < _configuration.size(); i++) {
+ NodeSet<std::string> invokes = _xpath.evaluate("" + _nsPrefix + "invoke", _configuration[i]).asNodeSet();
+ for (unsigned int j = 0; j < invokes.size(); j++) {
+ Arabica::DOM::Element<std::string> invokeElem = (Arabica::DOM::Element<std::string>)invokes[j];
+ std::string invokeId = invokeElem.getAttribute("id");
+ std::string autoForward = invokeElem.getAttribute("autoforward");
+ if (boost::iequals(invokeId, externalEvent.invokeid)) {
+
+ Arabica::XPath::NodeSet<std::string> finalizes = _xpath.evaluate("" + _nsPrefix + "finalize", invokeElem).asNodeSet();
+ for (int k = 0; k < finalizes.size(); k++) {
+ Arabica::DOM::Element<std::string> finalizeElem = Arabica::DOM::Element<std::string>(finalizes[k]);
+ executeContent(finalizeElem);
+ }
+
+
+ }
+ if (autoForward.length() > 0) {
+ // @TODO
// send(invokeId, externalEvent);
- }
- }
- }
- enabledTransitions = selectTransitions(externalEvent.name);
- if (!enabledTransitions.empty())
- microstep(enabledTransitions);
- }
- exitInterpreter();
+ }
+ }
+ }
+ enabledTransitions = selectTransitions(externalEvent.name);
+ if (!enabledTransitions.empty())
+ microstep(enabledTransitions);
+ }
+ exitInterpreter();
}
void Interpreter::internalDoneSend(const Arabica::DOM::Node<std::string>& state) {
- if (!isState(state))
- return;
-
- Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state;
- Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)stateElem.getParentNode();
- Event event;
-
- Arabica::XPath::NodeSet<std::string> doneDatas = _xpath.evaluate("" + _nsPrefix + "donedata", stateElem).asNodeSet();
- if (doneDatas.size() > 0) {
- // only process first donedata element
- Arabica::DOM::Node<std::string> doneData = doneDatas[0];
- NodeList<std::string> doneChilds = doneData.getChildNodes();
- for (int i = 0; i < doneChilds.getLength(); i++) {
- if (!doneChilds.item(i).getNodeType() == Node_base::ELEMENT_NODE)
- continue;
- if (boost::iequals(TAGNAME(doneChilds.item(i)), "param")) {
- if (!HAS_ATTR(doneChilds.item(i), "name")) {
- LOG(ERROR) << "param element is missing name attribut";
- continue;
- }
- std::string paramValue;
- if (HAS_ATTR(doneChilds.item(i), "expr") && _dataModel) {
- std::string location = _dataModel->evalAsString(ATTR(doneChilds.item(i), "expr"));
- paramValue = _dataModel->evalAsString(location);
- } else if(HAS_ATTR(doneChilds.item(i), "location") && _dataModel) {
- paramValue = _dataModel->evalAsString(ATTR(doneChilds.item(i), "location"));
- } else {
- LOG(ERROR) << "param element is missing expr or location or no datamodel is specified";
- continue;
- }
- event.compound[ATTR(doneChilds.item(i), "name")] = paramValue;
- }
- if (boost::iequals(TAGNAME(doneChilds.item(i)), "content")) {
- if (HAS_ATTR(doneChilds.item(i), "expr")) {
- if (_dataModel) {
- event.compound["content"] = Data(_dataModel->evalAsString(ATTR(doneChilds.item(i), "expr")), Data::VERBATIM);
- } else {
- LOG(ERROR) << "content element has expr attribute but no datamodel is specified.";
- }
- } else if (doneChilds.item(i).hasChildNodes()) {
- event.compound["content"] = Data(doneChilds.item(i).getFirstChild().getNodeValue(), Data::VERBATIM);
- } else {
- LOG(ERROR) << "content element does not specify any content.";
- }
-
- }
- }
- }
-
- event.name = "done.state." + parent.getAttribute("id");
- _internalQueue.push_back(event);
-
-}
-
+ if (!isState(state))
+ return;
+
+ Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state;
+ Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)stateElem.getParentNode();
+ Event event;
+
+ Arabica::XPath::NodeSet<std::string> doneDatas = _xpath.evaluate("" + _nsPrefix + "donedata", stateElem).asNodeSet();
+ if (doneDatas.size() > 0) {
+ // only process first donedata element
+ Arabica::DOM::Node<std::string> doneData = doneDatas[0];
+ NodeList<std::string> doneChilds = doneData.getChildNodes();
+ for (int i = 0; i < doneChilds.getLength(); i++) {
+ if (!doneChilds.item(i).getNodeType() == Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(doneChilds.item(i)), "param")) {
+ if (!HAS_ATTR(doneChilds.item(i), "name")) {
+ LOG(ERROR) << "param element is missing name attribut";
+ continue;
+ }
+ std::string paramValue;
+ if (HAS_ATTR(doneChilds.item(i), "expr") && _dataModel) {
+ std::string location = _dataModel->evalAsString(ATTR(doneChilds.item(i), "expr"));
+ paramValue = _dataModel->evalAsString(location);
+ } else if(HAS_ATTR(doneChilds.item(i), "location") && _dataModel) {
+ paramValue = _dataModel->evalAsString(ATTR(doneChilds.item(i), "location"));
+ } else {
+ LOG(ERROR) << "param element is missing expr or location or no datamodel is specified";
+ continue;
+ }
+ event.compound[ATTR(doneChilds.item(i), "name")] = paramValue;
+ }
+ if (boost::iequals(TAGNAME(doneChilds.item(i)), "content")) {
+ if (HAS_ATTR(doneChilds.item(i), "expr")) {
+ if (_dataModel) {
+ event.compound["content"] = Data(_dataModel->evalAsString(ATTR(doneChilds.item(i), "expr")), Data::VERBATIM);
+ } else {
+ LOG(ERROR) << "content element has expr attribute but no datamodel is specified.";
+ }
+ } else if (doneChilds.item(i).hasChildNodes()) {
+ event.compound["content"] = Data(doneChilds.item(i).getFirstChild().getNodeValue(), Data::VERBATIM);
+ } else {
+ LOG(ERROR) << "content element does not specify any content.";
+ }
+
+ }
+ }
+ }
+
+ event.name = "done.state." + parent.getAttribute("id");
+ _internalQueue.push_back(event);
+
+}
+
void Interpreter::send(const Arabica::DOM::Node<std::string>& element) {
- SendRequest sendReq;
- try {
- // event
- if (HAS_ATTR(element, "eventexpr") && _dataModel) {
- sendReq.name = _dataModel->evalAsString(ATTR(element, "eventexpr"));
- } else if (HAS_ATTR(element, "event")) {
- sendReq.name = ATTR(element, "event");
- }
- // target
- if (HAS_ATTR(element, "targetexpr") && _dataModel) {
- sendReq.target = _dataModel->evalAsString(ATTR(element, "targetexpr"));
- } else if (HAS_ATTR(element, "target")) {
- sendReq.target = ATTR(element, "target");
- }
- // type
- if (HAS_ATTR(element, "typeexpr") && _dataModel) {
- sendReq.type = _dataModel->evalAsString(ATTR(element, "typeexpr"));
- } else if (HAS_ATTR(element, "type")) {
- sendReq.type = ATTR(element, "type");
- } else {
- sendReq.type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor";
- }
- // id
- if (HAS_ATTR(element, "idlocation") && _dataModel) {
- sendReq.sendid = _dataModel->evalAsString(ATTR(element, "idlocation"));
- } else if (HAS_ATTR(element, "id")) {
- sendReq.sendid = ATTR(element, "id");
- } else {
- /*
- * The ids for <send> and <invoke> are subtly different. In a conformant
- * SCXML document, they must be unique within the session, but in the case
- * where the author does not provide them, the processor must generate a
- * new unique ID not at load time but each time the element is executed.
- * Furthermore the attribute 'idlocation' can be used to capture this
- * automatically generated id. Finally note that the automatically generated
- * id for <invoke> has a special format. See 6.4.1 Attribute Details for
- * details. The SCXML processor may generate all other ids in any format,
- * as long as they are unique.
- */
- sendReq.sendid = getUUID();
- }
- /** @TODO:
- *
- * If 'idlocation' is present, the SCXML Processor must generate an id when
- * the parent <send> element is evaluated and store it in this location.
- * See 3.14 IDs for details.
- *
- */
-
- // delay
- std::string delay;
- sendReq.delayMs = 0;
- if (HAS_ATTR(element, "delayexpr") && _dataModel) {
- delay = _dataModel->evalAsString(ATTR(element, "delayexpr"));
- } else if (HAS_ATTR(element, "delay")) {
- delay = ATTR(element, "delay");
- }
- if (delay.size() > 0) {
- boost::trim(delay);
- std::stringstream delayTime;
- if (delay.size() > 2 && boost::iequals("ms", delay.substr(delay.length() - 2, 2))) {
- delayTime << delay.substr(0, delay.size() - 2);
- delayTime >> sendReq.delayMs;
- } else if (delay.size() > 1 && boost::iequals("s", delay.substr(delay.length() - 1, 1))) {
- delayTime << delay.substr(0, delay.size() - 1);
- delayTime >> sendReq.delayMs;
- sendReq.delayMs *= 1000;
- } else {
- LOG(ERROR) << "Cannot make sense of delay value " << delay << ": does not end in 's' or 'ms'";
- }
- }
- // namelist
- if (HAS_ATTR(element, "namelist")) {
- std::vector<std::string> names = tokenizeIdRefs(ATTR(element, "namelist"));
- for (int i = 0; i < names.size(); i++) {
- sendReq.namelist[names[i]] = _dataModel->evalAsString(names[i]);
- }
- }
-
- // params
- NodeSet<std::string> params = _xpath.evaluate("" + _nsPrefix + "param", element).asNodeSet();
- for (int i = 0; i < params.size(); i++) {
- if (!HAS_ATTR(params[i], "name")) {
- LOG(ERROR) << "param element is missing name attribut";
- continue;
- }
- std::string paramValue;
- if (HAS_ATTR(params[i], "expr") && _dataModel) {
- paramValue = _dataModel->evalAsString(ATTR(params[i], "expr"));
- } else if(HAS_ATTR(params[i], "location") && _dataModel) {
- paramValue = _dataModel->evalAsString(ATTR(params[i], "location"));
- } else {
- LOG(ERROR) << "param element is missing expr or location or no datamodel is specified";
- continue;
- }
- sendReq.params[ATTR(params[i], "name")].push_back(paramValue);
- }
-
- // content
- NodeSet<std::string> contents = _xpath.evaluate("" + _nsPrefix + "content", element).asNodeSet();
- if (contents.size() > 1)
- LOG(ERROR) << "Only a single content element is allowed for send elements - using first one";
- if (contents.size() > 0) {
- if (HAS_ATTR(contents[0], "expr")) {
- if (_dataModel) {
- sendReq.content = _dataModel->evalAsString(ATTR(contents[0], "expr"));
- } else {
- LOG(ERROR) << "content element has expr attribute but no datamodel is specified.";
- }
- } else if (contents[0].hasChildNodes()) {
- sendReq.content = contents[0].getFirstChild().getNodeValue();
- } else {
- LOG(ERROR) << "content element does not specify any content.";
- }
- }
-
- assert(_sendIds.find(sendReq.sendid) == _sendIds.end());
- _sendIds[sendReq.sendid] = std::make_pair(this, sendReq);
- if (sendReq.delayMs > 0) {
- _sendQueue->addEvent(sendReq.sendid, Interpreter::delayedSend, sendReq.delayMs, &_sendIds[sendReq.sendid]);
- } else {
- delayedSend(&_sendIds[sendReq.sendid], sendReq.name);
- }
-
- } catch (Event e) {
- LOG(ERROR) << "Syntax error in send element:" << std::endl << e << std::endl;
- }
+ SendRequest sendReq;
+ try {
+ // event
+ if (HAS_ATTR(element, "eventexpr") && _dataModel) {
+ sendReq.name = _dataModel->evalAsString(ATTR(element, "eventexpr"));
+ } else if (HAS_ATTR(element, "event")) {
+ sendReq.name = ATTR(element, "event");
+ }
+ // target
+ if (HAS_ATTR(element, "targetexpr") && _dataModel) {
+ sendReq.target = _dataModel->evalAsString(ATTR(element, "targetexpr"));
+ } else if (HAS_ATTR(element, "target")) {
+ sendReq.target = ATTR(element, "target");
+ }
+ // type
+ if (HAS_ATTR(element, "typeexpr") && _dataModel) {
+ sendReq.type = _dataModel->evalAsString(ATTR(element, "typeexpr"));
+ } else if (HAS_ATTR(element, "type")) {
+ sendReq.type = ATTR(element, "type");
+ } else {
+ sendReq.type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor";
+ }
+ // id
+ if (HAS_ATTR(element, "idlocation") && _dataModel) {
+ sendReq.sendid = _dataModel->evalAsString(ATTR(element, "idlocation"));
+ } else if (HAS_ATTR(element, "id")) {
+ sendReq.sendid = ATTR(element, "id");
+ } else {
+ /*
+ * The ids for <send> and <invoke> are subtly different. In a conformant
+ * SCXML document, they must be unique within the session, but in the case
+ * where the author does not provide them, the processor must generate a
+ * new unique ID not at load time but each time the element is executed.
+ * Furthermore the attribute 'idlocation' can be used to capture this
+ * automatically generated id. Finally note that the automatically generated
+ * id for <invoke> has a special format. See 6.4.1 Attribute Details for
+ * details. The SCXML processor may generate all other ids in any format,
+ * as long as they are unique.
+ */
+ sendReq.sendid = getUUID();
+ }
+ /** @TODO:
+ *
+ * If 'idlocation' is present, the SCXML Processor must generate an id when
+ * the parent <send> element is evaluated and store it in this location.
+ * See 3.14 IDs for details.
+ *
+ */
+
+ // delay
+ std::string delay;
+ sendReq.delayMs = 0;
+ if (HAS_ATTR(element, "delayexpr") && _dataModel) {
+ delay = _dataModel->evalAsString(ATTR(element, "delayexpr"));
+ } else if (HAS_ATTR(element, "delay")) {
+ delay = ATTR(element, "delay");
+ }
+ if (delay.size() > 0) {
+ boost::trim(delay);
+ std::stringstream delayTime;
+ if (delay.size() > 2 && boost::iequals("ms", delay.substr(delay.length() - 2, 2))) {
+ delayTime << delay.substr(0, delay.size() - 2);
+ delayTime >> sendReq.delayMs;
+ } else if (delay.size() > 1 && boost::iequals("s", delay.substr(delay.length() - 1, 1))) {
+ delayTime << delay.substr(0, delay.size() - 1);
+ delayTime >> sendReq.delayMs;
+ sendReq.delayMs *= 1000;
+ } else {
+ LOG(ERROR) << "Cannot make sense of delay value " << delay << ": does not end in 's' or 'ms'";
+ }
+ }
+ // namelist
+ if (HAS_ATTR(element, "namelist")) {
+ std::vector<std::string> names = tokenizeIdRefs(ATTR(element, "namelist"));
+ for (int i = 0; i < names.size(); i++) {
+ sendReq.namelist[names[i]] = _dataModel->evalAsString(names[i]);
+ }
+ }
+
+ // params
+ NodeSet<std::string> params = _xpath.evaluate("" + _nsPrefix + "param", element).asNodeSet();
+ for (int i = 0; i < params.size(); i++) {
+ if (!HAS_ATTR(params[i], "name")) {
+ LOG(ERROR) << "param element is missing name attribut";
+ continue;
+ }
+ std::string paramValue;
+ if (HAS_ATTR(params[i], "expr") && _dataModel) {
+ paramValue = _dataModel->evalAsString(ATTR(params[i], "expr"));
+ } else if(HAS_ATTR(params[i], "location") && _dataModel) {
+ paramValue = _dataModel->evalAsString(ATTR(params[i], "location"));
+ } else {
+ LOG(ERROR) << "param element is missing expr or location or no datamodel is specified";
+ continue;
+ }
+ sendReq.params.insert(std::make_pair(ATTR(params[i], "name"), paramValue));
+ }
+
+ // content
+ NodeSet<std::string> contents = _xpath.evaluate("" + _nsPrefix + "content", element).asNodeSet();
+ if (contents.size() > 1)
+ LOG(ERROR) << "Only a single content element is allowed for send elements - using first one";
+ if (contents.size() > 0) {
+ if (HAS_ATTR(contents[0], "expr")) {
+ if (_dataModel) {
+ sendReq.content = _dataModel->evalAsString(ATTR(contents[0], "expr"));
+ } else {
+ LOG(ERROR) << "content element has expr attribute but no datamodel is specified.";
+ }
+ } else if (contents[0].hasChildNodes()) {
+ sendReq.content = contents[0].getFirstChild().getNodeValue();
+ } else {
+ LOG(ERROR) << "content element does not specify any content.";
+ }
+ }
+
+ assert(_sendIds.find(sendReq.sendid) == _sendIds.end());
+ _sendIds[sendReq.sendid] = std::make_pair(this, sendReq);
+ if (sendReq.delayMs > 0) {
+ _sendQueue->addEvent(sendReq.sendid, Interpreter::delayedSend, sendReq.delayMs, &_sendIds[sendReq.sendid]);
+ } else {
+ delayedSend(&_sendIds[sendReq.sendid], sendReq.name);
+ }
+
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in send element:" << std::endl << e << std::endl;
+ }
}
void Interpreter::delayedSend(void* userdata, std::string eventName) {
- std::pair<Interpreter*, SendRequest>* data = (std::pair<Interpreter*, SendRequest>*)(userdata);
-
- Interpreter* INSTANCE = data->first;
- SendRequest sendReq = data->second;
-
- if (boost::iequals(sendReq.target, "#_parent")) {
- // send to parent scxml session
- if (INSTANCE->_invoker != NULL) {
- INSTANCE->_invoker->sendToParent(sendReq);
- } else {
- LOG(ERROR) << "Can not send to parent, we were not invoked" << std::endl;
- }
- } else if (sendReq.target.find_first_of("#_") == 0) {
- // send to invoker
- std::string invokeId = sendReq.target.substr(2, sendReq.target.length() - 2);
- if (INSTANCE->_invokerIds.find(invokeId) != INSTANCE->_invokerIds.end()) {
- INSTANCE->_invokerIds[invokeId]->send(sendReq);
- } else {
- LOG(ERROR) << "Can not send to invoked component " << invokeId << ", no such invokeId" << std::endl;
- }
- } else if (sendReq.target.length() == 0) {
- INSTANCE->receive(sendReq);
- } else {
- IOProcessor* ioProc = INSTANCE->getIOProcessor(sendReq.type);
- if (ioProc != NULL) {
- ioProc->send(sendReq);
- }
- }
- assert(INSTANCE->_sendIds.find(sendReq.sendid) != INSTANCE->_sendIds.end());
- INSTANCE->_sendIds.erase(sendReq.sendid);
-}
-
+ std::pair<Interpreter*, SendRequest>* data = (std::pair<Interpreter*, SendRequest>*)(userdata);
+
+ Interpreter* INSTANCE = data->first;
+ SendRequest sendReq = data->second;
+
+ if (boost::iequals(sendReq.target, "#_parent")) {
+ // send to parent scxml session
+ if (INSTANCE->_invoker != NULL) {
+ INSTANCE->_invoker->sendToParent(sendReq);
+ } else {
+ LOG(ERROR) << "Can not send to parent, we were not invoked" << std::endl;
+ }
+ } else if (sendReq.target.find_first_of("#_") == 0) {
+ // send to invoker
+ std::string invokeId = sendReq.target.substr(2, sendReq.target.length() - 2);
+ if (INSTANCE->_invokerIds.find(invokeId) != INSTANCE->_invokerIds.end()) {
+ INSTANCE->_invokerIds[invokeId]->send(sendReq);
+ } else {
+ LOG(ERROR) << "Can not send to invoked component " << invokeId << ", no such invokeId" << std::endl;
+ }
+ } else if (sendReq.target.length() == 0) {
+ INSTANCE->receive(sendReq);
+ } else {
+ IOProcessor* ioProc = INSTANCE->getIOProcessor(sendReq.type);
+ if (ioProc != NULL) {
+ ioProc->send(sendReq);
+ }
+ }
+ assert(INSTANCE->_sendIds.find(sendReq.sendid) != INSTANCE->_sendIds.end());
+ INSTANCE->_sendIds.erase(sendReq.sendid);
+}
+
void Interpreter::invoke(const Arabica::DOM::Node<std::string>& element) {
- InvokeRequest invokeReq;
- try {
- // type
- if (HAS_ATTR(element, "typeexpr") && _dataModel) {
- invokeReq.type = _dataModel->evalAsString(ATTR(element, "typeexpr"));
- } else if (HAS_ATTR(element, "type")) {
- invokeReq.type = ATTR(element, "type");
- } else {
- LOG(ERROR) << "invoke element is missing expr or typeexpr or no datamodel is specified";
- }
-
- // src
- std::string source;
- if (HAS_ATTR(element, "srcexpr") && _dataModel) {
- source = _dataModel->evalAsString(ATTR(element, "srcexpr"));
- } else if (HAS_ATTR(element, "src")) {
- source = ATTR(element, "src");
- }
- if (source.length() > 0) {
- Arabica::io::URI srcURI(source);
- if (!makeAbsolute(srcURI)) {
- LOG(ERROR) << "invoke element has relative src URI with no baseURI set.";
- return;
- }
- invokeReq.src = srcURI.as_string();
- }
-
- // id
- if (HAS_ATTR(element, "idlocation") && _dataModel) {
- invokeReq.invokeid = _dataModel->evalAsString(ATTR(element, "idlocation"));
- } else if (HAS_ATTR(element, "id")) {
- invokeReq.invokeid = ATTR(element, "id");
- } else {
- assert(false);
- }
-
- // namelist
- if (HAS_ATTR(element, "namelist")) {
- invokeReq.namelist = ATTR(element, "namelist");
- }
-
- // autoforward
- if (HAS_ATTR(element, "autoforward")) {
- if (boost::iequals(ATTR(element, "autoforward"), "true")) {
- invokeReq.autoForward = true;
- }
- } else {
- invokeReq.autoForward = false;
- }
-
- // params
- NodeSet<std::string> params = _xpath.evaluate("" + _nsPrefix + "param", element).asNodeSet();
- for (int i = 0; i < params.size(); i++) {
- if (!HAS_ATTR(params[i], "name")) {
- LOG(ERROR) << "param element is missing name attribut";
- continue;
- }
- std::string paramValue;
- if (HAS_ATTR(params[i], "expr")) {
- if (_dataModel) {
- paramValue = _dataModel->evalAsString(ATTR(params[i], "expr"));
- } else {
- paramValue = ATTR(params[i], "expr");
- }
- } else if(HAS_ATTR(params[i], "location") && _dataModel) {
- paramValue = _dataModel->evalAsString(ATTR(params[i], "location"));
- } else {
- LOG(ERROR) << "param element is missing expr or location or no datamodel is specified";
- continue;
- }
- invokeReq.params[ATTR(params[i], "name")].push_back(paramValue);
- }
-
- // content
- NodeSet<std::string> contents = _xpath.evaluate("" + _nsPrefix + "content", element).asNodeSet();
- if (contents.size() > 1)
- LOG(ERROR) << "Only a single content element is allowed for send elements - using first one";
- if (contents.size() > 0) {
- invokeReq.content = contents[0].getNodeValue();
- }
-
- Invoker* invoker = Factory::getInvoker(invokeReq.type, this);
- if (invoker != NULL) {
- _invokerIds[invokeReq.invokeid] = invoker;
- LOG(INFO) << "Added " << invokeReq.type << " at " << invokeReq.invokeid;
- invoker->invoke(invokeReq);
- } else {
- LOG(ERROR) << "No invoker known for type " << invokeReq.type;
- }
-
- } catch (Event e) {
- LOG(ERROR) << "Syntax error in invoke element:" << std::endl << e << std::endl;
- }
-}
-
+ InvokeRequest invokeReq;
+ try {
+ // type
+ if (HAS_ATTR(element, "typeexpr") && _dataModel) {
+ invokeReq.type = _dataModel->evalAsString(ATTR(element, "typeexpr"));
+ } else if (HAS_ATTR(element, "type")) {
+ invokeReq.type = ATTR(element, "type");
+ } else {
+ LOG(ERROR) << "invoke element is missing expr or typeexpr or no datamodel is specified";
+ }
+
+ // src
+ std::string source;
+ if (HAS_ATTR(element, "srcexpr") && _dataModel) {
+ source = _dataModel->evalAsString(ATTR(element, "srcexpr"));
+ } else if (HAS_ATTR(element, "src")) {
+ source = ATTR(element, "src");
+ }
+ if (source.length() > 0) {
+ Arabica::io::URI srcURI(source);
+ if (!makeAbsolute(srcURI)) {
+ LOG(ERROR) << "invoke element has relative src URI with no baseURI set.";
+ return;
+ }
+ invokeReq.src = srcURI.as_string();
+ }
+
+ // id
+ if (HAS_ATTR(element, "idlocation") && _dataModel) {
+ invokeReq.invokeid = _dataModel->evalAsString(ATTR(element, "idlocation"));
+ } else if (HAS_ATTR(element, "id")) {
+ invokeReq.invokeid = ATTR(element, "id");
+ } else {
+ assert(false);
+ }
+
+ // namelist
+ if (HAS_ATTR(element, "namelist")) {
+ invokeReq.namelist = ATTR(element, "namelist");
+ }
+
+ // autoforward
+ if (HAS_ATTR(element, "autoforward")) {
+ if (boost::iequals(ATTR(element, "autoforward"), "true")) {
+ invokeReq.autoForward = true;
+ }
+ } else {
+ invokeReq.autoForward = false;
+ }
+
+ // params
+ NodeSet<std::string> params = _xpath.evaluate("" + _nsPrefix + "param", element).asNodeSet();
+ for (int i = 0; i < params.size(); i++) {
+ if (!HAS_ATTR(params[i], "name")) {
+ LOG(ERROR) << "param element is missing name attribut";
+ continue;
+ }
+ std::string paramValue;
+ if (HAS_ATTR(params[i], "expr")) {
+ if (_dataModel) {
+ paramValue = _dataModel->evalAsString(ATTR(params[i], "expr"));
+ } else {
+ paramValue = ATTR(params[i], "expr");
+ }
+ } else if(HAS_ATTR(params[i], "location") && _dataModel) {
+ paramValue = _dataModel->evalAsString(ATTR(params[i], "location"));
+ } else {
+ LOG(ERROR) << "param element is missing expr or location or no datamodel is specified";
+ continue;
+ }
+// invokeReq.params[ATTR(params[i], "name")].push_back(paramValue);
+ invokeReq.params.insert(std::make_pair(ATTR(params[i], "name"), paramValue));
+
+ }
+
+ // content
+ NodeSet<std::string> contents = _xpath.evaluate("" + _nsPrefix + "content", element).asNodeSet();
+ if (contents.size() > 1)
+ LOG(ERROR) << "Only a single content element is allowed for send elements - using first one";
+ if (contents.size() > 0) {
+ invokeReq.content = contents[0].getNodeValue();
+ }
+
+ Invoker* invoker = Factory::getInvoker(invokeReq.type, this);
+ if (invoker != NULL) {
+ _invokerIds[invokeReq.invokeid] = invoker;
+ LOG(INFO) << "Added " << invokeReq.type << " at " << invokeReq.invokeid;
+ invoker->invoke(invokeReq);
+ } else {
+ LOG(ERROR) << "No invoker known for type " << invokeReq.type;
+ }
+
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in invoke element:" << std::endl << e << std::endl;
+ }
+}
+
void Interpreter::cancelInvoke(const Arabica::DOM::Node<std::string>& element) {
- std::string invokeId;
- if (HAS_ATTR(element, "idlocation") && _dataModel) {
- invokeId = _dataModel->evalAsString(ATTR(element, "idlocation"));
- } else if (HAS_ATTR(element, "id")) {
- invokeId = ATTR(element, "id");
- } else {
- assert(false);
- }
- if (_invokerIds.find(invokeId) != _invokerIds.end()) {
- LOG(INFO) << "Removed invoker at " << invokeId;
- delete (_invokerIds[invokeId]);
- _invokerIds.erase(invokeId);
- } else {
- LOG(ERROR) << "Cannot cancel invoke for id " << invokeId << ": no soch invokation";
- }
+ std::string invokeId;
+ if (HAS_ATTR(element, "idlocation") && _dataModel) {
+ invokeId = _dataModel->evalAsString(ATTR(element, "idlocation"));
+ } else if (HAS_ATTR(element, "id")) {
+ invokeId = ATTR(element, "id");
+ } else {
+ assert(false);
+ }
+ if (_invokerIds.find(invokeId) != _invokerIds.end()) {
+ LOG(INFO) << "Removed invoker at " << invokeId;
+ delete (_invokerIds[invokeId]);
+ _invokerIds.erase(invokeId);
+ } else {
+ LOG(ERROR) << "Cannot cancel invoke for id " << invokeId << ": no soch invokation";
+ }
}
Arabica::XPath::NodeSet<std::string> Interpreter::selectTransitions(const std::string& event) {
- Arabica::XPath::NodeSet<std::string> enabledTransitions;
-
- NodeSet<std::string> atomicStates;
- for (unsigned int i = 0; i < _configuration.size(); i++) {
- if (isAtomic(_configuration[i]))
- atomicStates.push_back(_configuration[i]);
- }
- atomicStates.to_document_order();
-
- for (unsigned int i = 0; i < atomicStates.size(); i++) {
- NodeSet<std::string> ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node<std::string>());
- ancestors.push_back(atomicStates[i]);
- for (unsigned int j = 0; j < ancestors.size(); j++) {
- NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", ancestors[j]).asNodeSet();
- for (unsigned int k = 0; k < transitions.size(); k++) {
- if (((Arabica::DOM::Element<std::string>)transitions[k]).hasAttribute("event") &&
- nameMatch(((Arabica::DOM::Element<std::string>)transitions[k]).getAttribute("event"), event) &&
- hasConditionMatch(transitions[k])) {
- enabledTransitions.push_back(transitions[k]);
- goto LOOP;
- }
- }
- }
- LOOP:;
- }
- return enabledTransitions;
+ Arabica::XPath::NodeSet<std::string> enabledTransitions;
+
+ NodeSet<std::string> atomicStates;
+ for (unsigned int i = 0; i < _configuration.size(); i++) {
+ if (isAtomic(_configuration[i]))
+ atomicStates.push_back(_configuration[i]);
+ }
+ atomicStates.to_document_order();
+
+ for (unsigned int i = 0; i < atomicStates.size(); i++) {
+ NodeSet<std::string> ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node<std::string>());
+ ancestors.push_back(atomicStates[i]);
+ for (unsigned int j = 0; j < ancestors.size(); j++) {
+ NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", ancestors[j]).asNodeSet();
+ for (unsigned int k = 0; k < transitions.size(); k++) {
+ if (((Arabica::DOM::Element<std::string>)transitions[k]).hasAttribute("event") &&
+ nameMatch(((Arabica::DOM::Element<std::string>)transitions[k]).getAttribute("event"), event) &&
+ hasConditionMatch(transitions[k])) {
+ enabledTransitions.push_back(transitions[k]);
+ goto LOOP;
+ }
+ }
+ }
+LOOP:
+ ;
+ }
+ return enabledTransitions;
}
// see: http://www.w3.org/TR/scxml/#EventDescriptors
bool Interpreter::nameMatch(const std::string& transitionEvent, const std::string& event) {
- assert(transitionEvent.size() > 0);
- assert(event.size() > 0);
-
- // naive case of single descriptor and exact match
- if (boost::equals(transitionEvent, event))
- return true;
-
- boost::char_separator<char> sep(" ");
- boost::tokenizer<boost::char_separator<char> > tokens(transitionEvent, sep);
- boost::tokenizer<boost::char_separator<char> >::iterator tokenIter = tokens.begin();
-
- while(tokenIter != tokens.end()) {
- std::string eventDesc(*tokenIter++);
-
- // remove optional trailing .* for CCXML compatibility
- if (eventDesc.find("*", eventDesc.size() - 1) != std::string::npos)
- eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
- if (eventDesc.find(".", eventDesc.size() - 1) != std::string::npos)
- eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
-
- // was eventDesc the * wildcard
- if (eventDesc.size() == 0)
- return true;
-
- // are they already equal?
- if (boost::equals(eventDesc, event))
- return true;
-
- // eventDesc has to be a real prefix of event now and therefore shorter
- if (eventDesc.size() >= event.size())
- continue;
-
- // it is a prefix of the event name and event continues with .something
- if (eventDesc.compare(event.substr(0, eventDesc.size())) == 0)
- if (event.find(".", eventDesc.size()) == eventDesc.size())
- return true;
- }
- return false;
-}
-
+ assert(transitionEvent.size() > 0);
+ assert(event.size() > 0);
+
+ // naive case of single descriptor and exact match
+ if (boost::equals(transitionEvent, event))
+ return true;
+
+ boost::char_separator<char> sep(" ");
+ boost::tokenizer<boost::char_separator<char> > tokens(transitionEvent, sep);
+ boost::tokenizer<boost::char_separator<char> >::iterator tokenIter = tokens.begin();
+
+ while(tokenIter != tokens.end()) {
+ std::string eventDesc(*tokenIter++);
+
+ // remove optional trailing .* for CCXML compatibility
+ if (eventDesc.find("*", eventDesc.size() - 1) != std::string::npos)
+ eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
+ if (eventDesc.find(".", eventDesc.size() - 1) != std::string::npos)
+ eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
+
+ // was eventDesc the * wildcard
+ if (eventDesc.size() == 0)
+ return true;
+
+ // are they already equal?
+ if (boost::equals(eventDesc, event))
+ return true;
+
+ // eventDesc has to be a real prefix of event now and therefore shorter
+ if (eventDesc.size() >= event.size())
+ continue;
+
+ // it is a prefix of the event name and event continues with .something
+ if (eventDesc.compare(event.substr(0, eventDesc.size())) == 0)
+ if (event.find(".", eventDesc.size()) == eventDesc.size())
+ return true;
+ }
+ return false;
+}
+
Arabica::XPath::NodeSet<std::string> Interpreter::selectEventlessTransitions() {
- Arabica::XPath::NodeSet<std::string> enabledTransitions;
-
- NodeSet<std::string> atomicStates;
- for (unsigned int i = 0; i < _configuration.size(); i++) {
- if (isAtomic(_configuration[i]))
- atomicStates.push_back(_configuration[i]);
- }
- atomicStates.to_document_order();
-
- for (unsigned int i = 0; i < atomicStates.size(); i++) {
- NodeSet<std::string> ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node<std::string>());
- ancestors.push_back(atomicStates[i]);
- for (unsigned int j = 0; j < ancestors.size(); j++) {
- NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", ancestors[j]).asNodeSet();
- for (unsigned int k = 0; k < transitions.size(); k++) {
- if (!((Arabica::DOM::Element<std::string>)transitions[k]).hasAttribute("event") && hasConditionMatch(transitions[k])) {
- enabledTransitions.push_back(transitions[k]);
- goto LOOP;
- }
- }
- }
- LOOP:;
- }
-
- enabledTransitions = filterPreempted(enabledTransitions);
- return enabledTransitions;
+ Arabica::XPath::NodeSet<std::string> enabledTransitions;
+
+ NodeSet<std::string> atomicStates;
+ for (unsigned int i = 0; i < _configuration.size(); i++) {
+ if (isAtomic(_configuration[i]))
+ atomicStates.push_back(_configuration[i]);
+ }
+ atomicStates.to_document_order();
+
+ for (unsigned int i = 0; i < atomicStates.size(); i++) {
+ NodeSet<std::string> ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node<std::string>());
+ ancestors.push_back(atomicStates[i]);
+ for (unsigned int j = 0; j < ancestors.size(); j++) {
+ NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", ancestors[j]).asNodeSet();
+ for (unsigned int k = 0; k < transitions.size(); k++) {
+ if (!((Arabica::DOM::Element<std::string>)transitions[k]).hasAttribute("event") && hasConditionMatch(transitions[k])) {
+ enabledTransitions.push_back(transitions[k]);
+ goto LOOP;
+ }
+ }
+ }
+LOOP:
+ ;
+ }
+
+ enabledTransitions = filterPreempted(enabledTransitions);
+ return enabledTransitions;
}
bool Interpreter::hasConditionMatch(const Arabica::DOM::Node<std::string>& conditional) {
- try {
- if (_dataModel && HAS_ATTR(conditional, "cond"))
- return _dataModel->evalAsBool(ATTR(conditional, "cond"));
- } catch (Event e) {
- LOG(ERROR) << "Syntax error in cond attribute of " << TAGNAME(conditional) << " element:" << std::endl << e << std::endl;
- return false;
- }
- return true; // no condition is always true
+ try {
+ if (_dataModel && HAS_ATTR(conditional, "cond"))
+ return _dataModel->evalAsBool(ATTR(conditional, "cond"));
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in cond attribute of " << TAGNAME(conditional) << " element:" << std::endl << e << std::endl;
+ return false;
+ }
+ return true; // no condition is always true
}
Arabica::XPath::NodeSet<std::string> Interpreter::filterPreempted(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
- Arabica::XPath::NodeSet<std::string> filteredTransitions;
- for (unsigned int i = 0; i < enabledTransitions.size(); i++) {
- Arabica::DOM::Node<std::string> t = enabledTransitions[i];
- for (unsigned int j = i+1; j < enabledTransitions.size(); j++) {
- Arabica::DOM::Node<std::string> t2 = enabledTransitions[j];
- if (isPreemptingTransition(t2, t))
- goto LOOP;
- }
- filteredTransitions.push_back(t);
- LOOP:;
- }
- return filteredTransitions;
+ Arabica::XPath::NodeSet<std::string> filteredTransitions;
+ for (unsigned int i = 0; i < enabledTransitions.size(); i++) {
+ Arabica::DOM::Node<std::string> t = enabledTransitions[i];
+ for (unsigned int j = i+1; j < enabledTransitions.size(); j++) {
+ Arabica::DOM::Node<std::string> t2 = enabledTransitions[j];
+ if (isPreemptingTransition(t2, t))
+ goto LOOP;
+ }
+ filteredTransitions.push_back(t);
+LOOP:
+ ;
+ }
+ return filteredTransitions;
}
bool Interpreter::isPreemptingTransition(const Arabica::DOM::Node<std::string>& t1, const Arabica::DOM::Node<std::string>& t2) {
- if (t1 == t2)
- return false;
- if (isWithinSameChild(t1) && (!isTargetless(t2) && !isWithinSameChild(t2)))
- return true;
- if (!isTargetless(t1) && !isWithinSameChild(t1))
- return true;
- return false;
+ if (t1 == t2)
+ return false;
+ if (isWithinSameChild(t1) && (!isTargetless(t2) && !isWithinSameChild(t2)))
+ return true;
+ if (!isTargetless(t1) && !isWithinSameChild(t1))
+ return true;
+ return false;
}
void Interpreter::microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
#if 0
- std::cout << "Transitions: ";
- for (int i = 0; i < enabledTransitions.size(); i++) {
- std::cout << ((Arabica::DOM::Element<std::string>)getSourceState(enabledTransitions[i])).getAttribute("id") << " -> " << std::endl;
- NodeSet<std::string> targetSet = getTargetStates(enabledTransitions[i]);
- for (int j = 0; j < targetSet.size(); j++) {
- std::cout << " " << ((Arabica::DOM::Element<std::string>)targetSet[j]).getAttribute("id") << std::endl;
- }
- }
- std::cout << std::endl;
+ std::cout << "Transitions: ";
+ for (int i = 0; i < enabledTransitions.size(); i++) {
+ std::cout << ((Arabica::DOM::Element<std::string>)getSourceState(enabledTransitions[i])).getAttribute("id") << " -> " << std::endl;
+ NodeSet<std::string> targetSet = getTargetStates(enabledTransitions[i]);
+ for (int j = 0; j < targetSet.size(); j++) {
+ std::cout << " " << ((Arabica::DOM::Element<std::string>)targetSet[j]).getAttribute("id") << std::endl;
+ }
+ }
+ std::cout << std::endl;
#endif
- exitStates(enabledTransitions);
- executeTransitionContent(enabledTransitions);
- enterStates(enabledTransitions);
+ exitStates(enabledTransitions);
+ executeTransitionContent(enabledTransitions);
+ enterStates(enabledTransitions);
}
void Interpreter::exitInterpreter() {
- NodeSet<std::string> statesToExit = _configuration;
- statesToExit.to_document_order();
- statesToExit.reverse();
-
- for (int i = 0; i < statesToExit.size(); i++) {
- Arabica::XPath::NodeSet<std::string> onExitElems = _xpath.evaluate("" + _nsPrefix + "onexit", statesToExit[i]).asNodeSet();
- for (int j = 0; j < onExitElems.size(); j++) {
- executeContent(onExitElems[j]);
- }
- Arabica::XPath::NodeSet<std::string> invokeElems = _xpath.evaluate("" + _nsPrefix + "invoke", statesToExit[i]).asNodeSet();
- for (int j = 0; j < invokeElems.size(); j++) {
- cancelInvoke(invokeElems[j]);
- }
- if (isFinal(statesToExit[i]) && parentIsScxmlState(statesToExit[i])) {
- returnDoneEvent(statesToExit[i]);
- }
- }
- _configuration = NodeSet<std::string>();
+ NodeSet<std::string> statesToExit = _configuration;
+ statesToExit.to_document_order();
+ statesToExit.reverse();
+
+ for (int i = 0; i < statesToExit.size(); i++) {
+ Arabica::XPath::NodeSet<std::string> onExitElems = _xpath.evaluate("" + _nsPrefix + "onexit", statesToExit[i]).asNodeSet();
+ for (int j = 0; j < onExitElems.size(); j++) {
+ executeContent(onExitElems[j]);
+ }
+ Arabica::XPath::NodeSet<std::string> invokeElems = _xpath.evaluate("" + _nsPrefix + "invoke", statesToExit[i]).asNodeSet();
+ for (int j = 0; j < invokeElems.size(); j++) {
+ cancelInvoke(invokeElems[j]);
+ }
+ if (isFinal(statesToExit[i]) && parentIsScxmlState(statesToExit[i])) {
+ returnDoneEvent(statesToExit[i]);
+ }
+ }
+ _configuration = NodeSet<std::string>();
}
void Interpreter::executeTransitionContent(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
- for (int i = 0; i < enabledTransitions.size(); i++) {
- executeContent(enabledTransitions[i]);
- }
+ for (int i = 0; i < enabledTransitions.size(); i++) {
+ executeContent(enabledTransitions[i]);
+ }
}
void Interpreter::executeContent(const NodeList<std::string>& content) {
- for (unsigned int i = 0; i < content.getLength(); i++) {
- if (content.item(i).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- executeContent(content.item(i));
- }
+ for (unsigned int i = 0; i < content.getLength(); i++) {
+ if (content.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ executeContent(content.item(i));
+ }
}
-
+
void Interpreter::executeContent(const Arabica::DOM::Node<std::string>& content) {
- if (content.getNodeType() != Node_base::ELEMENT_NODE)
- return;
-
- if (false) {
- } else if (boost::iequals(TAGNAME(content), "raise")) {
- // --- RAISE --------------------------
- if (HAS_ATTR(content, "event")) {
- Event event;
- event.name = ATTR(content, "event");
- _internalQueue.push_back(event);
- }
- } else if (boost::iequals(TAGNAME(content), "if")) {
- // --- IF / ELSEIF / ELSE --------------
- Arabica::DOM::Element<std::string> ifElem = (Arabica::DOM::Element<std::string>)content;
- if(hasConditionMatch(ifElem)) {
- // condition is true, execute all content up to an elseif, else or end
- if (ifElem.hasChildNodes()) {
- NodeList<std::string> childs = ifElem.getChildNodes();
- for (unsigned int i = 0; i < childs.getLength(); i++) {
- if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- if (boost::iequals(TAGNAME(childs.item(i)), "elsif") ||
- boost::iequals(TAGNAME(childs.item(i)), "else"))
- break;
- executeContent(childs.item(i));
- }
- }
- } else {
- // condition does not match - do we have an elsif?
- if (ifElem.hasChildNodes()) {
- NodeList<std::string> elseifElem = ifElem.getElementsByTagName("elseif");
- for (unsigned int i = 0; i < elseifElem.getLength(); i++) {
- if (hasConditionMatch(elseifElem.item(i))) {
- executeContent(elseifElem.item(i).getChildNodes());
- goto ELSIF_ELEM_MATCH;
- }
- }
- NodeList<std::string> elseElem = ifElem.getElementsByTagName("else");
- if (elseElem.getLength() > 0)
- executeContent(elseElem.item(0).getChildNodes());
- }
- }
- ELSIF_ELEM_MATCH:;
- } else if (boost::iequals(TAGNAME(content), "elseif")) {
- std::cerr << "Found single elsif to evaluate!" << std::endl;
- } else if (boost::iequals(TAGNAME(content), "else")) {
- std::cerr << "Found single else to evaluate!" << std::endl;
- } else if (boost::iequals(TAGNAME(content), "foreach")) {
- // --- FOREACH --------------------------
- if (_dataModel) {
- if (HAS_ATTR(content, "array") && HAS_ATTR(content, "item")) {
- std::string array = ATTR(content, "array");
- std::string item = ATTR(content, "item");
- std::string index = (HAS_ATTR(content, "index") ? ATTR(content, "index") : "");
- uint32_t iterations = _dataModel->getLength(array);
- _dataModel->pushContext(); // copy old and enter new context
- for (uint32_t iteration = 0; iteration < iterations; iteration++) {
- {
- // assign array element to item
- std::stringstream ss;
- ss << array << "[" << iteration << "]";
- _dataModel->assign(item, ss.str());
- }
- if (index.length() > 0) {
- // assign iteration element to index
- std::stringstream ss;
- ss << iteration;
- _dataModel->assign(index,ss.str());
- }
- if (content.hasChildNodes())
- executeContent(content.getChildNodes());
- }
- _dataModel->popContext(); // leave stacked context
- } else {
- LOG(ERROR) << "Expected array and item attributes with foreach element!" << std::endl;
- }
- }
- } else if (boost::iequals(TAGNAME(content), "log")) {
- // --- LOG --------------------------
- Arabica::DOM::Element<std::string> logElem = (Arabica::DOM::Element<std::string>)content;
- if (logElem.hasAttribute("expr")) {
- if (_dataModel) {
- try {
- std::cout << _dataModel->evalAsString(logElem.getAttribute("expr")) << std::endl;
- } catch (Event e) {
- LOG(ERROR) << "Syntax error in expr attribute of log element:" << std::endl << e << std::endl;
- }
- } else {
- std::cout << logElem.getAttribute("expr") << std::endl;
- }
- }
- } else if (boost::iequals(TAGNAME(content), "assign")) {
- // --- ASSIGN --------------------------
- if (_dataModel && HAS_ATTR(content, "location") && HAS_ATTR(content, "expr")) {
- try {
- _dataModel->assign(ATTR(content, "location"), ATTR(content, "expr"));
- } catch (Event e) {
- LOG(ERROR) << "Syntax error in attributes of assign element:" << std::endl << e << std::endl;
- }
- }
- } else if (boost::iequals(TAGNAME(content), "validate")) {
- // --- VALIDATE --------------------------
- if (_dataModel) {
- std::string location = (HAS_ATTR(content, "location") ? ATTR(content, "location") : "");
- std::string schema = (HAS_ATTR(content, "schema") ? ATTR(content, "schema") : "");
- _dataModel->validate(location, schema);
- }
- } else if (boost::iequals(TAGNAME(content), "script")) {
- // --- SCRIPT --------------------------
- if (_dataModel) {
- if (HAS_ATTR(content, "src")) {
- Arabica::io::URI url(ATTR(content, "src"));
- if (!makeAbsolute(url)) {
- LOG(ERROR) << "script element has relative URI " << ATTR(content, "src") << " with no base URI set for interpreter";
- return;
- }
-
- std::stringstream srcContent;
- URL scriptUrl(url.as_string());
- srcContent << scriptUrl;
-
- try {
- _dataModel->eval(srcContent.str());
- } catch (Event e) {
- LOG(ERROR) << "Syntax error while executing script element from '" << ATTR(content, "src") << "':" << std::endl << e << std::endl;
- }
- } else {
- if (content.hasChildNodes()) {
- // search for the text node with the actual script
- if (content.getFirstChild().getNodeType() == Node_base::TEXT_NODE) {
- try {
- _dataModel->eval(content.getFirstChild().getNodeValue());
- } catch (Event e) {
- LOG(ERROR) << "Syntax error while executing script element" << std::endl << e << std::endl;
- }
- }
- }
- }
- }
- } else if (boost::iequals(TAGNAME(content), "send")) {
- // --- SEND --------------------------
- send(content);
- } else if (boost::iequals(TAGNAME(content), "cancel")) {
- // --- CANCEL --------------------------
- std::string sendId;
- try {
- if (HAS_ATTR(content, "sendidexpr")) {
- sendId = _dataModel->evalAsString(ATTR(content, "sendidexpr"));
- } else if(HAS_ATTR(content, "sendid")) {
- sendId = ATTR(content, "sendid");
- } else {
- LOG(ERROR) << "Expected sendidexpr or sendid attribute in cancel element";
- return;
- }
- _sendQueue->cancelEvent(sendId);
-
- } catch (Event e) {
- LOG(ERROR) << "Syntax error while executing cancel element" << std::endl << e << std::endl;
- }
-
- } else if (boost::iequals(TAGNAME(content), "invoke")) {
- // --- INVOKE --------------------------
- } else {
- NodeList<std::string> executable = content.getChildNodes();
- for (int i = 0; i < executable.getLength(); i++) {
- executeContent(executable.item(i));
- }
- }
+ if (content.getNodeType() != Node_base::ELEMENT_NODE)
+ return;
+
+ if (false) {
+ } else if (boost::iequals(TAGNAME(content), "raise")) {
+ // --- RAISE --------------------------
+ if (HAS_ATTR(content, "event")) {
+ Event event;
+ event.name = ATTR(content, "event");
+ _internalQueue.push_back(event);
+ }
+ } else if (boost::iequals(TAGNAME(content), "if")) {
+ // --- IF / ELSEIF / ELSE --------------
+ Arabica::DOM::Element<std::string> ifElem = (Arabica::DOM::Element<std::string>)content;
+ if(hasConditionMatch(ifElem)) {
+ // condition is true, execute all content up to an elseif, else or end
+ if (ifElem.hasChildNodes()) {
+ NodeList<std::string> childs = ifElem.getChildNodes();
+ for (unsigned int i = 0; i < childs.getLength(); i++) {
+ if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(childs.item(i)), "elsif") ||
+ boost::iequals(TAGNAME(childs.item(i)), "else"))
+ break;
+ executeContent(childs.item(i));
+ }
+ }
+ } else {
+ // condition does not match - do we have an elsif?
+ if (ifElem.hasChildNodes()) {
+ NodeList<std::string> elseifElem = ifElem.getElementsByTagName("elseif");
+ for (unsigned int i = 0; i < elseifElem.getLength(); i++) {
+ if (hasConditionMatch(elseifElem.item(i))) {
+ executeContent(elseifElem.item(i).getChildNodes());
+ goto ELSIF_ELEM_MATCH;
+ }
+ }
+ NodeList<std::string> elseElem = ifElem.getElementsByTagName("else");
+ if (elseElem.getLength() > 0)
+ executeContent(elseElem.item(0).getChildNodes());
+ }
+ }
+ELSIF_ELEM_MATCH:
+ ;
+ } else if (boost::iequals(TAGNAME(content), "elseif")) {
+ std::cerr << "Found single elsif to evaluate!" << std::endl;
+ } else if (boost::iequals(TAGNAME(content), "else")) {
+ std::cerr << "Found single else to evaluate!" << std::endl;
+ } else if (boost::iequals(TAGNAME(content), "foreach")) {
+ // --- FOREACH --------------------------
+ if (_dataModel) {
+ if (HAS_ATTR(content, "array") && HAS_ATTR(content, "item")) {
+ std::string array = ATTR(content, "array");
+ std::string item = ATTR(content, "item");
+ std::string index = (HAS_ATTR(content, "index") ? ATTR(content, "index") : "");
+ uint32_t iterations = _dataModel->getLength(array);
+ _dataModel->pushContext(); // copy old and enter new context
+ for (uint32_t iteration = 0; iteration < iterations; iteration++) {
+ {
+ // assign array element to item
+ std::stringstream ss;
+ ss << array << "[" << iteration << "]";
+ _dataModel->assign(item, ss.str());
+ }
+ if (index.length() > 0) {
+ // assign iteration element to index
+ std::stringstream ss;
+ ss << iteration;
+ _dataModel->assign(index,ss.str());
+ }
+ if (content.hasChildNodes())
+ executeContent(content.getChildNodes());
+ }
+ _dataModel->popContext(); // leave stacked context
+ } else {
+ LOG(ERROR) << "Expected array and item attributes with foreach element!" << std::endl;
+ }
+ }
+ } else if (boost::iequals(TAGNAME(content), "log")) {
+ // --- LOG --------------------------
+ Arabica::DOM::Element<std::string> logElem = (Arabica::DOM::Element<std::string>)content;
+ if (logElem.hasAttribute("expr")) {
+ if (_dataModel) {
+ try {
+ std::cout << _dataModel->evalAsString(logElem.getAttribute("expr")) << std::endl;
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in expr attribute of log element:" << std::endl << e << std::endl;
+ }
+ } else {
+ std::cout << logElem.getAttribute("expr") << std::endl;
+ }
+ }
+ } else if (boost::iequals(TAGNAME(content), "assign")) {
+ // --- ASSIGN --------------------------
+ if (_dataModel && HAS_ATTR(content, "location") && HAS_ATTR(content, "expr")) {
+ try {
+ _dataModel->assign(ATTR(content, "location"), ATTR(content, "expr"));
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in attributes of assign element:" << std::endl << e << std::endl;
+ }
+ }
+ } else if (boost::iequals(TAGNAME(content), "validate")) {
+ // --- VALIDATE --------------------------
+ if (_dataModel) {
+ std::string location = (HAS_ATTR(content, "location") ? ATTR(content, "location") : "");
+ std::string schema = (HAS_ATTR(content, "schema") ? ATTR(content, "schema") : "");
+ _dataModel->validate(location, schema);
+ }
+ } else if (boost::iequals(TAGNAME(content), "script")) {
+ // --- SCRIPT --------------------------
+ if (_dataModel) {
+ if (HAS_ATTR(content, "src")) {
+ Arabica::io::URI url(ATTR(content, "src"));
+ if (!makeAbsolute(url)) {
+ LOG(ERROR) << "script element has relative URI " << ATTR(content, "src") << " with no base URI set for interpreter";
+ return;
+ }
+
+ std::stringstream srcContent;
+ URL scriptUrl(url.as_string());
+ srcContent << scriptUrl;
+
+ try {
+ _dataModel->eval(srcContent.str());
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error while executing script element from '" << ATTR(content, "src") << "':" << std::endl << e << std::endl;
+ }
+ } else {
+ if (content.hasChildNodes()) {
+ // search for the text node with the actual script
+ if (content.getFirstChild().getNodeType() == Node_base::TEXT_NODE) {
+ try {
+ _dataModel->eval(content.getFirstChild().getNodeValue());
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error while executing script element" << std::endl << e << std::endl;
+ }
+ }
+ }
+ }
+ }
+ } else if (boost::iequals(TAGNAME(content), "send")) {
+ // --- SEND --------------------------
+ send(content);
+ } else if (boost::iequals(TAGNAME(content), "cancel")) {
+ // --- CANCEL --------------------------
+ std::string sendId;
+ try {
+ if (HAS_ATTR(content, "sendidexpr")) {
+ sendId = _dataModel->evalAsString(ATTR(content, "sendidexpr"));
+ } else if(HAS_ATTR(content, "sendid")) {
+ sendId = ATTR(content, "sendid");
+ } else {
+ LOG(ERROR) << "Expected sendidexpr or sendid attribute in cancel element";
+ return;
+ }
+ _sendQueue->cancelEvent(sendId);
+
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error while executing cancel element" << std::endl << e << std::endl;
+ }
+
+ } else if (boost::iequals(TAGNAME(content), "invoke")) {
+ // --- INVOKE --------------------------
+ } else {
+ NodeList<std::string> executable = content.getChildNodes();
+ for (int i = 0; i < executable.getLength(); i++) {
+ executeContent(executable.item(i));
+ }
+ }
}
void Interpreter::returnDoneEvent(const Arabica::DOM::Node<std::string>& state) {
}
void Interpreter::exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
- NodeSet<std::string> statesToExit;
- for (int i = 0; i < enabledTransitions.size(); i++) {
- Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]);
- if (!isTargetless(transition)) {
- std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external");
- NodeSet<std::string> tStates = getTargetStates(transition);
- Arabica::DOM::Node<std::string> ancestor;
- Arabica::DOM::Node<std::string> source = getSourceState(transition);
-
- bool allDescendants = true;
- for (int j = 0; j < tStates.size(); j++) {
- if (!isDescendant(tStates[j], source)) {
- allDescendants = false;
- break;
- }
- }
- if (boost::iequals(transitionType, "internal") &&
- isCompound(source) &&
- allDescendants)
- {
- ancestor = source;
- } else {
- NodeSet<std::string> tmpStates;
- tmpStates.push_back(source);
- tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end());
-
- ancestor = findLCCA(tmpStates);
- }
-
- for (int j = 0; j < _configuration.size(); j++) {
- if (isDescendant(_configuration[j], ancestor))
- statesToExit.push_back(_configuration[j]);
- }
- }
- }
- // remove statesToExit from _statesToInvoke
- std::list<Arabica::DOM::Node<std::string> > tmp;
- for (int i = 0; i < _statesToInvoke.size(); i++) {
- if (!isMember(_statesToInvoke[i], statesToExit)) {
- tmp.push_back(_statesToInvoke[i]);
- }
- }
- _statesToInvoke = NodeSet<std::string>();
- _statesToInvoke.insert(_statesToInvoke.end(), tmp.begin(), tmp.end());
-
- statesToExit.to_document_order();
- statesToExit.reverse();
-
- for (int i = 0; i < statesToExit.size(); i++) {
- NodeSet<std::string> historyElems = _xpath.evaluate("" + _nsPrefix + "history", statesToExit[i]).asNodeSet();
- for (int j = 0; j < historyElems.size(); j++) {
- Arabica::DOM::Element<std::string> historyElem = (Arabica::DOM::Element<std::string>)historyElems[j];
- std::string historyType = (historyElem.hasAttribute("type") ? historyElem.getAttribute("type") : "shallow");
- NodeSet<std::string> historyNodes;
- for (int k = 0; k < _configuration.size(); k++) {
- if (boost::iequals(historyType, "deep")) {
- if (isAtomic(_configuration[k]) && isDescendant(_configuration[k], statesToExit[i]))
- historyNodes.push_back(_configuration[k]);
- } else {
- if (_configuration[k].getParentNode() == statesToExit[i])
- historyNodes.push_back(_configuration[k]);
- }
- }
- _historyValue[historyElem.getAttribute("id")] = historyNodes;
- }
- }
-
- for (int i = 0; i < statesToExit.size(); i++) {
- Arabica::XPath::NodeSet<std::string> onExitElems = _xpath.evaluate("" + _nsPrefix + "onexit", statesToExit[i]).asNodeSet();
- for (int j = 0; j < onExitElems.size(); j++) {
- executeContent(onExitElems[j]);
- }
- Arabica::XPath::NodeSet<std::string> invokeElems = _xpath.evaluate("" + _nsPrefix + "invoke", statesToExit[i]).asNodeSet();
- for (int j = 0; j < invokeElems.size(); j++) {
- cancelInvoke(invokeElems[j]);
- }
- }
+ NodeSet<std::string> statesToExit;
+ for (int i = 0; i < enabledTransitions.size(); i++) {
+ Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]);
+ if (!isTargetless(transition)) {
+ std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external");
+ NodeSet<std::string> tStates = getTargetStates(transition);
+ Arabica::DOM::Node<std::string> ancestor;
+ Arabica::DOM::Node<std::string> source = getSourceState(transition);
+
+ bool allDescendants = true;
+ for (int j = 0; j < tStates.size(); j++) {
+ if (!isDescendant(tStates[j], source)) {
+ allDescendants = false;
+ break;
+ }
+ }
+ if (boost::iequals(transitionType, "internal") &&
+ isCompound(source) &&
+ allDescendants) {
+ ancestor = source;
+ } else {
+ NodeSet<std::string> tmpStates;
+ tmpStates.push_back(source);
+ tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end());
+
+ ancestor = findLCCA(tmpStates);
+ }
+
+ for (int j = 0; j < _configuration.size(); j++) {
+ if (isDescendant(_configuration[j], ancestor))
+ statesToExit.push_back(_configuration[j]);
+ }
+ }
+ }
+ // remove statesToExit from _statesToInvoke
+ std::list<Arabica::DOM::Node<std::string> > tmp;
+ for (int i = 0; i < _statesToInvoke.size(); i++) {
+ if (!isMember(_statesToInvoke[i], statesToExit)) {
+ tmp.push_back(_statesToInvoke[i]);
+ }
+ }
+ _statesToInvoke = NodeSet<std::string>();
+ _statesToInvoke.insert(_statesToInvoke.end(), tmp.begin(), tmp.end());
+
+ statesToExit.to_document_order();
+ statesToExit.reverse();
+
+ for (int i = 0; i < statesToExit.size(); i++) {
+ NodeSet<std::string> historyElems = _xpath.evaluate("" + _nsPrefix + "history", statesToExit[i]).asNodeSet();
+ for (int j = 0; j < historyElems.size(); j++) {
+ Arabica::DOM::Element<std::string> historyElem = (Arabica::DOM::Element<std::string>)historyElems[j];
+ std::string historyType = (historyElem.hasAttribute("type") ? historyElem.getAttribute("type") : "shallow");
+ NodeSet<std::string> historyNodes;
+ for (int k = 0; k < _configuration.size(); k++) {
+ if (boost::iequals(historyType, "deep")) {
+ if (isAtomic(_configuration[k]) && isDescendant(_configuration[k], statesToExit[i]))
+ historyNodes.push_back(_configuration[k]);
+ } else {
+ if (_configuration[k].getParentNode() == statesToExit[i])
+ historyNodes.push_back(_configuration[k]);
+ }
+ }
+ _historyValue[historyElem.getAttribute("id")] = historyNodes;
+ }
+ }
+
+ for (int i = 0; i < statesToExit.size(); i++) {
+ Arabica::XPath::NodeSet<std::string> onExitElems = _xpath.evaluate("" + _nsPrefix + "onexit", statesToExit[i]).asNodeSet();
+ for (int j = 0; j < onExitElems.size(); j++) {
+ executeContent(onExitElems[j]);
+ }
+ Arabica::XPath::NodeSet<std::string> invokeElems = _xpath.evaluate("" + _nsPrefix + "invoke", statesToExit[i]).asNodeSet();
+ for (int j = 0; j < invokeElems.size(); j++) {
+ cancelInvoke(invokeElems[j]);
+ }
+ }
// std::cout << "States to Exit: ";
// for (int i = 0; i < statesToExit.size(); i++) {
@@ -1201,533 +1206,531 @@ void Interpreter::exitStates(const Arabica::XPath::NodeSet<std::string>& enabled
// }
// std::cout << std::endl;
- // remove statesToExit from _configuration
- tmp.clear();
- for (int i = 0; i < _configuration.size(); i++) {
- if (!isMember(_configuration[i], statesToExit)) {
- tmp.push_back(_configuration[i]);
- }
- }
- _configuration = NodeSet<std::string>();
- _configuration.insert(_configuration.end(), tmp.begin(), tmp.end());
+ // remove statesToExit from _configuration
+ tmp.clear();
+ for (int i = 0; i < _configuration.size(); i++) {
+ if (!isMember(_configuration[i], statesToExit)) {
+ tmp.push_back(_configuration[i]);
+ }
+ }
+ _configuration = NodeSet<std::string>();
+ _configuration.insert(_configuration.end(), tmp.begin(), tmp.end());
+
-
}
void Interpreter::enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
- NodeSet<std::string> statesToEnter;
- NodeSet<std::string> statesForDefaultEntry;
-
- for (int i = 0; i < enabledTransitions.size(); i++) {
- Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]);
- if (!isTargetless(transition)) {
- std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external");
- NodeSet<std::string> tStates = getTargetStates(transition);
- Arabica::DOM::Node<std::string> ancestor;
- Arabica::DOM::Node<std::string> source = getSourceState(transition);
- assert(source);
-
- bool allDescendants = true;
- for (int j = 0; j < tStates.size(); j++) {
- if (!isDescendant(tStates[j], source)) {
- allDescendants = false;
- break;
- }
- }
- if (boost::iequals(transitionType, "internal") &&
- isCompound(source) &&
- allDescendants)
- {
- ancestor = source;
- } else {
- NodeSet<std::string> tmpStates;
- tmpStates.push_back(source);
- tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end());
-
- ancestor = findLCCA(tmpStates);
- }
-
- for (int j = 0; j < tStates.size(); j++) {
- addStatesToEnter(tStates[j], statesToEnter, statesForDefaultEntry);
- }
-
- for (int j = 0; j < tStates.size(); j++) {
- NodeSet<std::string> ancestors = getProperAncestors(tStates[j], ancestor);
- for (int k = 0; k < ancestors.size(); k++) {
- statesToEnter.push_back(ancestors[k]);
- if(isParallel(ancestors[k])) {
- NodeSet<std::string> childs = getChildStates(ancestors[k]);
- for (int l = 0; l < childs.size(); l++) {
- bool someIsDescendant = false;
- for (int m = 0; m < statesToEnter.size(); m++) {
- if (isDescendant(statesToEnter[m], childs[l])) {
- someIsDescendant = true;
- break;
- }
- }
- if (!someIsDescendant) {
- addStatesToEnter(childs[l], statesToEnter, statesForDefaultEntry);
- }
- }
- }
- }
- }
- }
- }
- statesToEnter.to_document_order();
- for (int i = 0; i < statesToEnter.size(); i++) {
- Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)statesToEnter[i];
- _configuration.push_back(stateElem);
- _statesToInvoke.push_back(stateElem);
- if (_binding == LATE && stateElem.getAttribute("isFirstEntry").size() > 0) {
- Arabica::XPath::NodeSet<std::string> dataModelElems = _xpath.evaluate("" + _nsPrefix + "datamodel", stateElem).asNodeSet();
- if(dataModelElems.size() > 0 && _dataModel) {
- Arabica::XPath::NodeSet<std::string> dataElems = _xpath.evaluate("" + _nsPrefix + "data", dataModelElems[0]).asNodeSet();
- for (int j = 0; j < dataElems.size(); j++) {
- initializeData(dataElems[j]);
- }
- }
- stateElem.setAttribute("isFirstEntry", "");
- }
- // execute onentry executable content
- Arabica::XPath::NodeSet<std::string> onEntryElems = _xpath.evaluate("" + _nsPrefix + "onentry", stateElem).asNodeSet();
- for (int j = 0; j < onEntryElems.size(); j++) {
- executeContent(onEntryElems[j]);
- }
- if (isMember(stateElem, statesForDefaultEntry)) {
- // execute initial transition content for compund states
- Arabica::XPath::NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "initial/" + _nsPrefix + "transition", stateElem).asNodeSet();
- for (int j = 0; j < transitions.size(); j++) {
- executeContent(transitions[j]);
- }
- }
-
- if (isFinal(stateElem)) {
- internalDoneSend(stateElem);
- Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)stateElem.getParentNode();
-
- if (isParallel(parent.getParentNode())) {
- Arabica::DOM::Element<std::string> grandParent = (Arabica::DOM::Element<std::string>)parent.getParentNode();
-
- Arabica::XPath::NodeSet<std::string> childs = getChildStates(grandParent);
- bool inFinalState = true;
- for (int j = 0; j < childs.size(); j++) {
- if (!isInFinalState(childs[j])) {
- inFinalState = false;
- break;
- }
- }
- if (inFinalState) {
- internalDoneSend(parent);
- }
- }
- }
- }
- for (int i = 0; i < _configuration.size(); i++) {
- Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)_configuration[i];
- if (isFinal(stateElem) && parentIsScxmlState(stateElem))
- _running = false;
- }
+ NodeSet<std::string> statesToEnter;
+ NodeSet<std::string> statesForDefaultEntry;
+
+ for (int i = 0; i < enabledTransitions.size(); i++) {
+ Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]);
+ if (!isTargetless(transition)) {
+ std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external");
+ NodeSet<std::string> tStates = getTargetStates(transition);
+ Arabica::DOM::Node<std::string> ancestor;
+ Arabica::DOM::Node<std::string> source = getSourceState(transition);
+ assert(source);
+
+ bool allDescendants = true;
+ for (int j = 0; j < tStates.size(); j++) {
+ if (!isDescendant(tStates[j], source)) {
+ allDescendants = false;
+ break;
+ }
+ }
+ if (boost::iequals(transitionType, "internal") &&
+ isCompound(source) &&
+ allDescendants) {
+ ancestor = source;
+ } else {
+ NodeSet<std::string> tmpStates;
+ tmpStates.push_back(source);
+ tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end());
+
+ ancestor = findLCCA(tmpStates);
+ }
+
+ for (int j = 0; j < tStates.size(); j++) {
+ addStatesToEnter(tStates[j], statesToEnter, statesForDefaultEntry);
+ }
+
+ for (int j = 0; j < tStates.size(); j++) {
+ NodeSet<std::string> ancestors = getProperAncestors(tStates[j], ancestor);
+ for (int k = 0; k < ancestors.size(); k++) {
+ statesToEnter.push_back(ancestors[k]);
+ if(isParallel(ancestors[k])) {
+ NodeSet<std::string> childs = getChildStates(ancestors[k]);
+ for (int l = 0; l < childs.size(); l++) {
+ bool someIsDescendant = false;
+ for (int m = 0; m < statesToEnter.size(); m++) {
+ if (isDescendant(statesToEnter[m], childs[l])) {
+ someIsDescendant = true;
+ break;
+ }
+ }
+ if (!someIsDescendant) {
+ addStatesToEnter(childs[l], statesToEnter, statesForDefaultEntry);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ statesToEnter.to_document_order();
+ for (int i = 0; i < statesToEnter.size(); i++) {
+ Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)statesToEnter[i];
+ _configuration.push_back(stateElem);
+ _statesToInvoke.push_back(stateElem);
+ if (_binding == LATE && stateElem.getAttribute("isFirstEntry").size() > 0) {
+ Arabica::XPath::NodeSet<std::string> dataModelElems = _xpath.evaluate("" + _nsPrefix + "datamodel", stateElem).asNodeSet();
+ if(dataModelElems.size() > 0 && _dataModel) {
+ Arabica::XPath::NodeSet<std::string> dataElems = _xpath.evaluate("" + _nsPrefix + "data", dataModelElems[0]).asNodeSet();
+ for (int j = 0; j < dataElems.size(); j++) {
+ initializeData(dataElems[j]);
+ }
+ }
+ stateElem.setAttribute("isFirstEntry", "");
+ }
+ // execute onentry executable content
+ Arabica::XPath::NodeSet<std::string> onEntryElems = _xpath.evaluate("" + _nsPrefix + "onentry", stateElem).asNodeSet();
+ for (int j = 0; j < onEntryElems.size(); j++) {
+ executeContent(onEntryElems[j]);
+ }
+ if (isMember(stateElem, statesForDefaultEntry)) {
+ // execute initial transition content for compund states
+ Arabica::XPath::NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "initial/" + _nsPrefix + "transition", stateElem).asNodeSet();
+ for (int j = 0; j < transitions.size(); j++) {
+ executeContent(transitions[j]);
+ }
+ }
+
+ if (isFinal(stateElem)) {
+ internalDoneSend(stateElem);
+ Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)stateElem.getParentNode();
+
+ if (isParallel(parent.getParentNode())) {
+ Arabica::DOM::Element<std::string> grandParent = (Arabica::DOM::Element<std::string>)parent.getParentNode();
+
+ Arabica::XPath::NodeSet<std::string> childs = getChildStates(grandParent);
+ bool inFinalState = true;
+ for (int j = 0; j < childs.size(); j++) {
+ if (!isInFinalState(childs[j])) {
+ inFinalState = false;
+ break;
+ }
+ }
+ if (inFinalState) {
+ internalDoneSend(parent);
+ }
+ }
+ }
+ }
+ for (int i = 0; i < _configuration.size(); i++) {
+ Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)_configuration[i];
+ if (isFinal(stateElem) && parentIsScxmlState(stateElem))
+ _running = false;
+ }
}
bool Interpreter::parentIsScxmlState(Arabica::DOM::Node<std::string> state) {
- Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state;
- Arabica::DOM::Element<std::string> parentElem = (Arabica::DOM::Element<std::string>)state.getParentNode();
- if (boost::iequals(parentElem.getTagName(), "scxml"))
- return true;
- return false;
+ Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state;
+ Arabica::DOM::Element<std::string> parentElem = (Arabica::DOM::Element<std::string>)state.getParentNode();
+ if (boost::iequals(parentElem.getTagName(), "scxml"))
+ return true;
+ return false;
}
-
+
bool Interpreter::isInFinalState(const Arabica::DOM::Node<std::string>& state) {
// std::cout << ATTR(state, "id") << std::endl;
- if (isCompound(state)) {
- Arabica::XPath::NodeSet<std::string> childs = getChildStates(state);
- for (int i = 0; i < childs.size(); i++) {
- if (isFinal(childs[i]) && isMember(childs[i], _configuration))
- return true;
- }
- } else if (isParallel(state)) {
- Arabica::XPath::NodeSet<std::string> childs = getChildStates(state);
- for (int i = 0; i < childs.size(); i++) {
- if (!isInFinalState(childs[i]))
- return false;
- }
- return true;
- }
- return false;
+ if (isCompound(state)) {
+ Arabica::XPath::NodeSet<std::string> childs = getChildStates(state);
+ for (int i = 0; i < childs.size(); i++) {
+ if (isFinal(childs[i]) && isMember(childs[i], _configuration))
+ return true;
+ }
+ } else if (isParallel(state)) {
+ Arabica::XPath::NodeSet<std::string> childs = getChildStates(state);
+ for (int i = 0; i < childs.size(); i++) {
+ if (!isInFinalState(childs[i]))
+ return false;
+ }
+ return true;
+ }
+ return false;
}
bool Interpreter::isMember(const Arabica::DOM::Node<std::string>& node, const Arabica::XPath::NodeSet<std::string>& set) {
- for (int i = 0; i < set.size(); i++) {
- if (set[i] == node)
- return true;
- }
- return false;
+ for (int i = 0; i < set.size(); i++) {
+ if (set[i] == node)
+ return true;
+ }
+ return false;
}
-
+
void Interpreter::addStatesToEnter(const Arabica::DOM::Node<std::string>& state,
- Arabica::XPath::NodeSet<std::string>& statesToEnter,
- Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
- std::string stateId = ((Arabica::DOM::Element<std::string>)state).getAttribute("id");
- if (isHistory(state)) {
- if (_historyValue.find(stateId) != _historyValue.end()) {
- Arabica::XPath::NodeSet<std::string> historyValue = _historyValue[stateId];
- for (int i = 0; i < historyValue.size(); i++) {
- addStatesToEnter(historyValue[i], statesToEnter, statesForDefaultEntry);
- NodeSet<std::string> ancestors = getProperAncestors(historyValue[i], state);
- for (int j = 0; j < ancestors.size(); j++) {
- statesToEnter.push_back(ancestors[j]);
- }
- }
- } else {
- NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", state).asNodeSet();
- for (int i = 0; i < transitions.size(); i++) {
- NodeSet<std::string> targets = getTargetStates(transitions[i]);
- for (int j = 0; j < targets.size(); j++) {
- addStatesToEnter(targets[j], statesToEnter, statesForDefaultEntry);
- }
- }
- }
- } else {
- statesToEnter.push_back(state);
- if (isCompound(state)) {
- statesForDefaultEntry.push_back(state);
+ Arabica::XPath::NodeSet<std::string>& statesToEnter,
+ Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
+ std::string stateId = ((Arabica::DOM::Element<std::string>)state).getAttribute("id");
+ if (isHistory(state)) {
+ if (_historyValue.find(stateId) != _historyValue.end()) {
+ Arabica::XPath::NodeSet<std::string> historyValue = _historyValue[stateId];
+ for (int i = 0; i < historyValue.size(); i++) {
+ addStatesToEnter(historyValue[i], statesToEnter, statesForDefaultEntry);
+ NodeSet<std::string> ancestors = getProperAncestors(historyValue[i], state);
+ for (int j = 0; j < ancestors.size(); j++) {
+ statesToEnter.push_back(ancestors[j]);
+ }
+ }
+ } else {
+ NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", state).asNodeSet();
+ for (int i = 0; i < transitions.size(); i++) {
+ NodeSet<std::string> targets = getTargetStates(transitions[i]);
+ for (int j = 0; j < targets.size(); j++) {
+ addStatesToEnter(targets[j], statesToEnter, statesForDefaultEntry);
+ }
+ }
+ }
+ } else {
+ statesToEnter.push_back(state);
+ if (isCompound(state)) {
+ statesForDefaultEntry.push_back(state);
#if 0
- NodeSet<std::string> tStates = getTargetStates(getInitialState(state));
- for (int i = 0; i < tStates.size(); i++) {
- addStatesToEnter(tStates[i], statesToEnter, statesForDefaultEntry);
- }
+ NodeSet<std::string> tStates = getTargetStates(getInitialState(state));
+ for (int i = 0; i < tStates.size(); i++) {
+ addStatesToEnter(tStates[i], statesToEnter, statesForDefaultEntry);
+ }
#endif
- addStatesToEnter(getInitialState(state), statesToEnter, statesForDefaultEntry);
+ addStatesToEnter(getInitialState(state), statesToEnter, statesForDefaultEntry);
// NodeSet<std::string> tStates = getTargetStates(getInitialState(state));
- } else if(isParallel(state)) {
- NodeSet<std::string> childStates = getChildStates(state);
- for (int i = 0; i < childStates.size(); i++) {
- addStatesToEnter(childStates[i], statesToEnter, statesForDefaultEntry);
- }
- }
- }
+ } else if(isParallel(state)) {
+ NodeSet<std::string> childStates = getChildStates(state);
+ for (int i = 0; i < childStates.size(); i++) {
+ addStatesToEnter(childStates[i], statesToEnter, statesForDefaultEntry);
+ }
+ }
+ }
}
Arabica::XPath::NodeSet<std::string> Interpreter::getChildStates(const Arabica::DOM::Node<std::string>& state) {
- Arabica::XPath::NodeSet<std::string> childs;
-
- Arabica::DOM::NodeList<std::string> childElems = state.getChildNodes();
- for (int i = 0; i < childElems.getLength(); i++) {
- if (isState(childElems.item(i))) {
- childs.push_back(childElems.item(i));
- }
- }
- return childs;
-}
-
+ Arabica::XPath::NodeSet<std::string> childs;
+
+ Arabica::DOM::NodeList<std::string> childElems = state.getChildNodes();
+ for (int i = 0; i < childElems.getLength(); i++) {
+ if (isState(childElems.item(i))) {
+ childs.push_back(childElems.item(i));
+ }
+ }
+ return childs;
+}
+
Arabica::DOM::Node<std::string> Interpreter::findLCCA(const Arabica::XPath::NodeSet<std::string>& states) {
// std::cout << "findLCCA: ";
// for (int i = 0; i < states.size(); i++) {
// std::cout << ((Arabica::DOM::Element<std::string>)states[i]).getAttribute("id") << " - " << states[i].getLocalName() << ", ";
// }
// std::cout << std::flush;
-
- Arabica::XPath::NodeSet<std::string> ancestors = getProperAncestors(states[0], Arabica::DOM::Node<std::string>());
- ancestors.push_back(states[0]); // state[0] may already be the ancestor - bug in W3C spec?
- Arabica::DOM::Node<std::string> ancestor;
- for (int i = 0; i < ancestors.size(); i++) {
- for (int j = 0; j < states.size(); j++) {
+
+ Arabica::XPath::NodeSet<std::string> ancestors = getProperAncestors(states[0], Arabica::DOM::Node<std::string>());
+ ancestors.push_back(states[0]); // state[0] may already be the ancestor - bug in W3C spec?
+ Arabica::DOM::Node<std::string> ancestor;
+ for (int i = 0; i < ancestors.size(); i++) {
+ for (int j = 0; j < states.size(); j++) {
// std::cout << "Checking " << TAGNAME(state) << " and " << TAGNAME(ancestors[i]) << std::endl;
- if (!isDescendant(states[j], ancestors[i]) && (states[j] != ancestors[i]))
- goto NEXT_ANCESTOR;
- }
- ancestor = ancestors[i];
- break;
- NEXT_ANCESTOR:;
- }
- assert(ancestor);
+ if (!isDescendant(states[j], ancestors[i]) && (states[j] != ancestors[i]))
+ goto NEXT_ANCESTOR;
+ }
+ ancestor = ancestors[i];
+ break;
+NEXT_ANCESTOR:
+ ;
+ }
+ assert(ancestor);
// std::cout << " -> " << ((Arabica::DOM::Element<std::string>)ancestor).getAttribute("id") << " " << ancestor.getLocalName() << std::endl;
- return ancestor;
+ return ancestor;
}
Arabica::DOM::Node<std::string> Interpreter::getState(const std::string& stateId) {
- // first try atomic and compund states
+ // first try atomic and compund states
// std::cout << _nsPrefix << stateId << std::endl;
- NodeSet<std::string> target = _xpath.evaluate("//" + _nsPrefix + "state[@id='" + stateId + "']", _doc).asNodeSet();
- if (target.size() > 0)
- goto FOUND;
+ NodeSet<std::string> target = _xpath.evaluate("//" + _nsPrefix + "state[@id='" + stateId + "']", _doc).asNodeSet();
+ if (target.size() > 0)
+ goto FOUND;
- // now parallel states
- target = _xpath.evaluate("//" + _nsPrefix + "parallel[@id='" + stateId + "']", _doc).asNodeSet();
- if (target.size() > 0)
- goto FOUND;
+ // now parallel states
+ target = _xpath.evaluate("//" + _nsPrefix + "parallel[@id='" + stateId + "']", _doc).asNodeSet();
+ if (target.size() > 0)
+ goto FOUND;
- // now final states
- target = _xpath.evaluate("//" + _nsPrefix + "final[@id='" + stateId + "']", _doc).asNodeSet();
- if (target.size() > 0)
- goto FOUND;
+ // now final states
+ target = _xpath.evaluate("//" + _nsPrefix + "final[@id='" + stateId + "']", _doc).asNodeSet();
+ if (target.size() > 0)
+ goto FOUND;
FOUND:
- if (target.size() > 0) {
- assert(target.size() == 1);
- return target[0];
- }
- // return the empty node
- return Arabica::DOM::Node<std::string>();
+ if (target.size() > 0) {
+ assert(target.size() == 1);
+ return target[0];
+ }
+ // return the empty node
+ return Arabica::DOM::Node<std::string>();
}
Arabica::DOM::Node<std::string> Interpreter::getSourceState(const Arabica::DOM::Node<std::string>& transition) {
- if (boost::iequals(TAGNAME(transition.getParentNode()), "initial"))
- return transition.getParentNode().getParentNode();
- return transition.getParentNode();
-}
-
- /**
- * In a conformant SCXML document, a compound state may specify either an "initial"
- * attribute or an <initial> element, but not both. See 3.6 <initial> for a
- * discussion of the difference between the two notations. If neither the "initial"
- * attribute nor an <initial> element is specified, the SCXML Processor must use
- * the first child state in document order as the default initial state.
- */
+ if (boost::iequals(TAGNAME(transition.getParentNode()), "initial"))
+ return transition.getParentNode().getParentNode();
+ return transition.getParentNode();
+}
+
+/**
+ * In a conformant SCXML document, a compound state may specify either an "initial"
+ * attribute or an <initial> element, but not both. See 3.6 <initial> for a
+ * discussion of the difference between the two notations. If neither the "initial"
+ * attribute nor an <initial> element is specified, the SCXML Processor must use
+ * the first child state in document order as the default initial state.
+ */
Arabica::DOM::Node<std::string> Interpreter::getInitialState(Arabica::DOM::Node<std::string> state) {
- if (!state) {
- state = _doc.getFirstChild();
- while(!isState(state))
- state = state.getNextSibling();
- }
-
- assert(isCompound(state) || isParallel(state));
-
- // initial attribute at element
- Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state;
- if (stateElem.hasAttribute("initial")) {
- return getState(stateElem.getAttribute("initial"));
- }
-
- // initial element as child
- NodeSet<std::string> initialStates = _xpath.evaluate("" + _nsPrefix + "initial", state).asNodeSet();
- if(initialStates.size() == 1)
- return initialStates[0];
-
- // first child state
- NodeList<std::string> childs = state.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- if (isState(childs.item(i)))
- return childs.item(i);
- }
- // nothing found
- return Arabica::DOM::Node<std::string>();
+ if (!state) {
+ state = _doc.getFirstChild();
+ while(!isState(state))
+ state = state.getNextSibling();
+ }
+
+ assert(isCompound(state) || isParallel(state));
+
+ // initial attribute at element
+ Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state;
+ if (stateElem.hasAttribute("initial")) {
+ return getState(stateElem.getAttribute("initial"));
+ }
+
+ // initial element as child
+ NodeSet<std::string> initialStates = _xpath.evaluate("" + _nsPrefix + "initial", state).asNodeSet();
+ if(initialStates.size() == 1)
+ return initialStates[0];
+
+ // first child state
+ NodeList<std::string> childs = state.getChildNodes();
+ for (int i = 0; i < childs.getLength(); i++) {
+ if (isState(childs.item(i)))
+ return childs.item(i);
+ }
+ // nothing found
+ return Arabica::DOM::Node<std::string>();
}
NodeSet<std::string> Interpreter::getTargetStates(const Arabica::DOM::Node<std::string>& transition) {
- NodeSet<std::string> targetStates;
-
- // if we are called with a state, process all its transitions
- if (isState(transition)) {
- NodeList<std::string> childs = transition.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- if (childs.item(i).getNodeType() == Node_base::ELEMENT_NODE && boost::iequals(TAGNAME(childs.item(i)), "transition")) {
- targetStates.push_back(getTargetStates(childs.item(i)));
- }
- }
- return targetStates;
- }
-
- std::string targetId = ((Arabica::DOM::Element<std::string>)transition).getAttribute("target");
-
- std::vector<std::string> targetIds = Interpreter::tokenizeIdRefs(ATTR(transition, "target"));
- for (int i = 0; i < targetIds.size(); i++) {
- Arabica::DOM::Node<std::string> state = getState(targetIds[i]);
- assert(HAS_ATTR(state, "id"));
- targetStates.push_back(state);
- }
- return targetStates;
+ NodeSet<std::string> targetStates;
+
+ // if we are called with a state, process all its transitions
+ if (isState(transition)) {
+ NodeList<std::string> childs = transition.getChildNodes();
+ for (int i = 0; i < childs.getLength(); i++) {
+ if (childs.item(i).getNodeType() == Node_base::ELEMENT_NODE && boost::iequals(TAGNAME(childs.item(i)), "transition")) {
+ targetStates.push_back(getTargetStates(childs.item(i)));
+ }
+ }
+ return targetStates;
+ }
+
+ std::string targetId = ((Arabica::DOM::Element<std::string>)transition).getAttribute("target");
+
+ std::vector<std::string> targetIds = Interpreter::tokenizeIdRefs(ATTR(transition, "target"));
+ for (int i = 0; i < targetIds.size(); i++) {
+ Arabica::DOM::Node<std::string> state = getState(targetIds[i]);
+ assert(HAS_ATTR(state, "id"));
+ targetStates.push_back(state);
+ }
+ return targetStates;
}
std::vector<std::string> Interpreter::tokenizeIdRefs(const std::string& idRefs) {
- std::vector<std::string> ids;
-
- if (idRefs.length() > 0) {
- std::istringstream iss(idRefs);
-
- std::copy(std::istream_iterator<std::string>(iss),
- std::istream_iterator<std::string>(),
- std::back_inserter<std::vector<std::string> >(ids));
- }
-
- return ids;
-}
-
+ std::vector<std::string> ids;
+
+ if (idRefs.length() > 0) {
+ std::istringstream iss(idRefs);
+
+ std::copy(std::istream_iterator<std::string>(iss),
+ std::istream_iterator<std::string>(),
+ std::back_inserter<std::vector<std::string> >(ids));
+ }
+
+ return ids;
+}
+
NodeSet<std::string> Interpreter::getProperAncestors(const Arabica::DOM::Node<std::string>& s1,
- const Arabica::DOM::Node<std::string>& s2) {
- NodeSet<std::string> ancestors;
- if (isState(s1)) {
- Arabica::DOM::Node<std::string> node = s1;
- while((node = node.getParentNode())) {
- if (!isState(node))
- break;
- if (!boost::iequals(TAGNAME(node), "parallel") && !boost::iequals(TAGNAME(node), "state") && !boost::iequals(TAGNAME(node), "scxml"))
- break;
- if (node == s2)
- break;
- ancestors.push_back(node);
- }
- }
- return ancestors;
+ const Arabica::DOM::Node<std::string>& s2) {
+ NodeSet<std::string> ancestors;
+ if (isState(s1)) {
+ Arabica::DOM::Node<std::string> node = s1;
+ while((node = node.getParentNode())) {
+ if (!isState(node))
+ break;
+ if (!boost::iequals(TAGNAME(node), "parallel") && !boost::iequals(TAGNAME(node), "state") && !boost::iequals(TAGNAME(node), "scxml"))
+ break;
+ if (node == s2)
+ break;
+ ancestors.push_back(node);
+ }
+ }
+ return ancestors;
}
bool Interpreter::isDescendant(const Arabica::DOM::Node<std::string>& s1,
- const Arabica::DOM::Node<std::string>& s2) {
- Arabica::DOM::Node<std::string> parent = s1.getParentNode();
- while(parent) {
- if (s2 == parent)
- return true;
- parent = parent.getParentNode();
- }
- return false;
-}
-
+ const Arabica::DOM::Node<std::string>& s2) {
+ Arabica::DOM::Node<std::string> parent = s1.getParentNode();
+ while(parent) {
+ if (s2 == parent)
+ return true;
+ parent = parent.getParentNode();
+ }
+ return false;
+}
+
bool Interpreter::isTargetless(const Arabica::DOM::Node<std::string>& transition) {
- if (transition.hasAttributes()) {
- if (((Arabica::DOM::Element<std::string>)transition).hasAttribute("target"))
- return false;
- }
- return true;
+ if (transition.hasAttributes()) {
+ if (((Arabica::DOM::Element<std::string>)transition).hasAttribute("target"))
+ return false;
+ }
+ return true;
}
bool Interpreter::isWithinSameChild(const Arabica::DOM::Node<std::string>& transition) {
- if (!isTargetless(transition)) {
- std::string target = ((Arabica::DOM::Element<std::string>)transition).getAttribute("target");
- Arabica::XPath::XPath<std::string> xpath;
- // @todo: do we need to look at parallel as well?
- if (xpath.evaluate("" + _nsPrefix + "state[id=\"" + target + "\"]", transition.getParentNode()).asNodeSet().size() > 0)
- return true;
- }
- return false;
+ if (!isTargetless(transition)) {
+ std::string target = ((Arabica::DOM::Element<std::string>)transition).getAttribute("target");
+ Arabica::XPath::XPath<std::string> xpath;
+ // @todo: do we need to look at parallel as well?
+ if (xpath.evaluate("" + _nsPrefix + "state[id=\"" + target + "\"]", transition.getParentNode()).asNodeSet().size() > 0)
+ return true;
+ }
+ return false;
}
bool Interpreter::isState(const Arabica::DOM::Node<std::string>& state) {
- if (!state)
- return false;
- if (state.getNodeType() != Arabica::DOM::Node_base::ELEMENT_NODE)
- return false;
-
- std::string tagName = TAGNAME(state);
- if (boost::iequals("state", tagName))
- return true;
- if (boost::iequals("scxml", tagName))
- return true;
- if (boost::iequals("parallel", tagName))
- return true;
- if (boost::iequals("final", tagName))
- return true;
- return false;
+ if (!state)
+ return false;
+ if (state.getNodeType() != Arabica::DOM::Node_base::ELEMENT_NODE)
+ return false;
+
+ std::string tagName = TAGNAME(state);
+ if (boost::iequals("state", tagName))
+ return true;
+ if (boost::iequals("scxml", tagName))
+ return true;
+ if (boost::iequals("parallel", tagName))
+ return true;
+ if (boost::iequals("final", tagName))
+ return true;
+ return false;
}
bool Interpreter::isFinal(const Arabica::DOM::Node<std::string>& state) {
- std::string tagName = TAGNAME(state);
- if (boost::iequals("final", tagName))
- return true;
- if (HAS_ATTR(state, "final") && boost::iequals("true", ATTR(state, "final")))
- return true;
- return false;
+ std::string tagName = TAGNAME(state);
+ if (boost::iequals("final", tagName))
+ return true;
+ if (HAS_ATTR(state, "final") && boost::iequals("true", ATTR(state, "final")))
+ return true;
+ return false;
}
bool Interpreter::isInitial(const Arabica::DOM::Node<std::string>& state) {
- if (!isState(state))
- return false;
-
- Arabica::DOM::Node<std::string> parent = state.getParentNode();
- if (!isState(parent))
- return true; // scxml element
-
- if (getInitialState(parent) == state)
- return true; // every nested node
-
- return false;
+ if (!isState(state))
+ return false;
+
+ Arabica::DOM::Node<std::string> parent = state.getParentNode();
+ if (!isState(parent))
+ return true; // scxml element
+
+ if (getInitialState(parent) == state)
+ return true; // every nested node
+
+ return false;
}
bool Interpreter::isPseudoState(const Arabica::DOM::Node<std::string>& state) {
- std::string tagName = TAGNAME(state);
- if (boost::iequals("initial", tagName))
- return true;
- if (boost::iequals("history", tagName))
- return true;
- return false;
+ std::string tagName = TAGNAME(state);
+ if (boost::iequals("initial", tagName))
+ return true;
+ if (boost::iequals("history", tagName))
+ return true;
+ return false;
}
bool Interpreter::isTransitionTarget(const Arabica::DOM::Node<std::string>& elem) {
- return (isState(elem) || boost::iequals(TAGNAME(elem), "history"));
+ return (isState(elem) || boost::iequals(TAGNAME(elem), "history"));
}
bool Interpreter::isAtomic(const Arabica::DOM::Node<std::string>& state) {
- if (boost::iequals("final", TAGNAME(state)))
- return true;
-
- // I will assume that parallel states are not meant to be atomic.
- if (boost::iequals("parallel", TAGNAME(state)))
- return false;
+ if (boost::iequals("final", TAGNAME(state)))
+ return true;
- Arabica::DOM::NodeList<std::string> childs = state.getChildNodes();
- for (unsigned int i = 0; i < childs.getLength(); i++) {
- if (isState(childs.item(i)))
- return false;
- }
- return true;
+ // I will assume that parallel states are not meant to be atomic.
+ if (boost::iequals("parallel", TAGNAME(state)))
+ return false;
+
+ Arabica::DOM::NodeList<std::string> childs = state.getChildNodes();
+ for (unsigned int i = 0; i < childs.getLength(); i++) {
+ if (isState(childs.item(i)))
+ return false;
+ }
+ return true;
}
bool Interpreter::isHistory(const Arabica::DOM::Node<std::string>& state) {
- if (boost::iequals("history", TAGNAME(state)))
- return true;
- return false;
+ if (boost::iequals("history", TAGNAME(state)))
+ return true;
+ return false;
}
bool Interpreter::isParallel(const Arabica::DOM::Node<std::string>& state) {
- if (!isState(state))
- return false;
- if (boost::iequals("parallel", TAGNAME(state)))
- return true;
- return false;
+ if (!isState(state))
+ return false;
+ if (boost::iequals("parallel", TAGNAME(state)))
+ return true;
+ return false;
}
-
+
bool Interpreter::isCompound(const Arabica::DOM::Node<std::string>& state) {
- if (!isState(state))
- return false;
+ if (!isState(state))
+ return false;
+
+ if (boost::iequals(TAGNAME(state), "parallel"))
+ return false;
- if (boost::iequals(TAGNAME(state), "parallel"))
- return false;
-
- Arabica::DOM::NodeList<std::string> childs = state.getChildNodes();
- for (unsigned int i = 0; i < childs.getLength(); i++) {
- if (isState(childs.item(i)))
- return true;
- }
- return false;
+ Arabica::DOM::NodeList<std::string> childs = state.getChildNodes();
+ for (unsigned int i = 0; i < childs.getLength(); i++) {
+ if (isState(childs.item(i)))
+ return true;
+ }
+ return false;
}
void Interpreter::setupIOProcessors() {
- std::map<std::string, IOProcessor*>::iterator ioProcIter = Factory::getInstance()->_ioProcessors.begin();
- while(ioProcIter != Factory::getInstance()->_ioProcessors.end()) {
- _ioProcessors[ioProcIter->first] = Factory::getIOProcessor(ioProcIter->first, this);
- if (_dataModel) {
- try {
-// _dataModel->setData("_ioprocessors", ioProcIter->first, _ioProcessors[ioProcIter->first]->getDataModelVariables());
- _dataModel->assign("_ioprocessors['" + ioProcIter->first + "']", _ioProcessors[ioProcIter->first]->getDataModelVariables());
-// std::cout << _dataModel->evalAsString("_ioprocessors['basichttp'].location") << std::endl;
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when setting _ioprocessors:" << std::endl << e << std::endl;
- }
- } else {
- LOG(INFO) << "Not registering " << ioProcIter->first << " at _ioprocessors in datamodel, no datamodel specified";
- }
- ioProcIter++;
- }
+ std::map<std::string, IOProcessor*>::iterator ioProcIter = Factory::getInstance()->_ioProcessors.begin();
+ while(ioProcIter != Factory::getInstance()->_ioProcessors.end()) {
+ _ioProcessors[ioProcIter->first] = Factory::getIOProcessor(ioProcIter->first, this);
+ if (_dataModel) {
+ try {
+ _dataModel->registerIOProcessor(ioProcIter->first, _ioProcessors[ioProcIter->first]);
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error when setting _ioprocessors:" << std::endl << e << std::endl;
+ }
+ } else {
+ LOG(INFO) << "Not registering " << ioProcIter->first << " at _ioprocessors in datamodel, no datamodel specified";
+ }
+ ioProcIter++;
+ }
}
IOProcessor* Interpreter::getIOProcessor(const std::string& type) {
- if (_ioProcessors.find(type) == _ioProcessors.end()) {
- LOG(ERROR) << "No ioProcessor known for type " << type;
- return NULL;
- }
- return _ioProcessors[type];
+ if (_ioProcessors.find(type) == _ioProcessors.end()) {
+ LOG(ERROR) << "No ioProcessor known for type " << type;
+ return NULL;
+ }
+ return _ioProcessors[type];
}
//IOProcessor* Interpreter::getIOProcessorForId(const std::string& sendId) {
@@ -1737,237 +1740,237 @@ IOProcessor* Interpreter::getIOProcessor(const std::string& type) {
// }
// return _ioProcessorsIds[sendId];
//}
-
+
bool Interpreter::validate() {
- bool validationErrors = false;
-
- if (!_doc) {
- LOG(ERROR) << "Document " << _baseURI.as_string() << " was not parsed successfully" << std::endl;
- return false;
- }
-
- // semantic issues ------------
- if ((_xpath.evaluate("/" + _nsPrefix + "scxml/@datamodel", _doc).asNodeSet().size() == 0) &&
- _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "script", _doc).asNodeSet().size() > 0) {
- LOG(ERROR) << "Script elements used, but no datamodel specified" << std::endl;
- }
-
- // element issues ------------
- Arabica::XPath::NodeSet<std::string> scxmlElems = _xpath.evaluate(_nsPrefix + "scxml", _doc).asNodeSet();
- if (scxmlElems.size() > 0)
- LOG(ERROR) << "More than one scxml element found" << std::endl;
- for (unsigned int i = 0; i < scxmlElems.size(); i++) {
- if (!HAS_ATTR(scxmlElems[i], "xmlns"))
- LOG(ERROR) << "scxml element has no xmlns attribute" << std::endl;
- if (!HAS_ATTR(scxmlElems[i], "version"))
- LOG(ERROR) << "scxml element has no version attribute" << std::endl;
- NodeList<std::string> childs = scxmlElems[i].getChildNodes();
- for (unsigned int j = 0; j < childs.getLength(); j++) {
- if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- if (boost::iequals(TAGNAME(childs.item(j)), "state") ||
- boost::iequals(TAGNAME(childs.item(j)), "parallel") ||
- boost::iequals(TAGNAME(childs.item(j)), "final") ||
- boost::iequals(TAGNAME(childs.item(j)), "datamodel") ||
- boost::iequals(TAGNAME(childs.item(j)), "script")) {
- LOG(ERROR) << "scxml element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
- }
- }
- }
-
- Arabica::XPath::NodeSet<std::string> stateElems = _xpath.evaluate(_nsPrefix + "state", _doc).asNodeSet();
- for (unsigned int i = 0; i < stateElems.size(); i++) {
- NodeList<std::string> childs = stateElems[i].getChildNodes();
- for (unsigned int j = 0; j < childs.getLength(); j++) {
- if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- if (boost::iequals(TAGNAME(childs.item(j)), "onentry") ||
- boost::iequals(TAGNAME(childs.item(j)), "onexit") ||
- boost::iequals(TAGNAME(childs.item(j)), "transition") ||
- boost::iequals(TAGNAME(childs.item(j)), "initial") ||
- boost::iequals(TAGNAME(childs.item(j)), "state") ||
- boost::iequals(TAGNAME(childs.item(j)), "parallel") ||
- boost::iequals(TAGNAME(childs.item(j)), "final") ||
- boost::iequals(TAGNAME(childs.item(j)), "history") ||
- boost::iequals(TAGNAME(childs.item(j)), "datamodel") ||
- boost::iequals(TAGNAME(childs.item(j)), "invoke")) {
- LOG(ERROR) << "state element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
- }
- }
- }
-
- Arabica::XPath::NodeSet<std::string> parallelElems = _xpath.evaluate(_nsPrefix + "parallel", _doc).asNodeSet();
- for (unsigned int i = 0; i < parallelElems.size(); i++) {
- NodeList<std::string> childs = parallelElems[i].getChildNodes();
- for (unsigned int j = 0; j < childs.getLength(); j++) {
- if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- if (boost::iequals(TAGNAME(childs.item(j)), "onentry") ||
- boost::iequals(TAGNAME(childs.item(j)), "onexit") ||
- boost::iequals(TAGNAME(childs.item(j)), "transition") ||
- boost::iequals(TAGNAME(childs.item(j)), "state") ||
- boost::iequals(TAGNAME(childs.item(j)), "parallel") ||
- boost::iequals(TAGNAME(childs.item(j)), "history") ||
- boost::iequals(TAGNAME(childs.item(j)), "datamodel") ||
- boost::iequals(TAGNAME(childs.item(j)), "invoke")) {
- LOG(ERROR) << "parallel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
- }
- }
- }
-
- Arabica::XPath::NodeSet<std::string> transitionElems = _xpath.evaluate(_nsPrefix + "transition", _doc).asNodeSet();
- for (unsigned int i = 0; i < transitionElems.size(); i++) {
- if (HAS_ATTR(transitionElems[i], "cond") &&
- !HAS_ATTR(transitionElems[i], "event")) {
- LOG(ERROR) << "transition element with cond attribute but without event attribute not allowed" << std::endl;
- }
- NodeList<std::string> childs = scxmlElems[i].getChildNodes();
- for (unsigned int j = 0; j < childs.getLength(); j++) {
- if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- }
- }
-
- Arabica::XPath::NodeSet<std::string> initialElems = _xpath.evaluate(_nsPrefix + "initial", _doc).asNodeSet();
- for (unsigned int i = 0; i < initialElems.size(); i++) {
- NodeList<std::string> childs = initialElems[i].getChildNodes();
- for (unsigned int j = 0; j < childs.getLength(); j++) {
- if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- if (boost::iequals(TAGNAME(childs.item(j)), "transition")) {
- LOG(ERROR) << "initial element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
- }
- }
- }
-
- Arabica::XPath::NodeSet<std::string> finalElems = _xpath.evaluate(_nsPrefix + "final", _doc).asNodeSet();
- for (unsigned int i = 0; i < finalElems.size(); i++) {
- NodeList<std::string> childs = finalElems[i].getChildNodes();
- for (unsigned int j = 0; j < childs.getLength(); j++) {
- if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- if (!boost::iequals(TAGNAME(childs.item(j)), "onentry") ||
- !boost::iequals(TAGNAME(childs.item(j)), "onexit") ||
- !boost::iequals(TAGNAME(childs.item(j)), "donedata")) {
- LOG(ERROR) << "parallel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
- }
- }
- }
-
- Arabica::XPath::NodeSet<std::string> historyElems = _xpath.evaluate(_nsPrefix + "history", _doc).asNodeSet();
- for (unsigned int i = 0; i < historyElems.size(); i++) {
- NodeList<std::string> childs = historyElems[i].getChildNodes();
- for (unsigned int j = 0; j < childs.getLength(); j++) {
- if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- if (boost::iequals(TAGNAME(childs.item(j)), "transition")) {
- LOG(ERROR) << "history element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
- }
- }
- }
-
- Arabica::XPath::NodeSet<std::string> datamodelElems = _xpath.evaluate(_nsPrefix + "datamodel", _doc).asNodeSet();
- for (unsigned int i = 0; i < datamodelElems.size(); i++) {
- NodeList<std::string> childs = datamodelElems[i].getChildNodes();
- for (unsigned int j = 0; j < childs.getLength(); j++) {
- if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
- continue;
- if (!boost::iequals(TAGNAME(childs.item(j)), "data")) {
- LOG(ERROR) << "datamodel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
- }
- }
- }
-
- Arabica::XPath::NodeSet<std::string> dataElems = _xpath.evaluate(_nsPrefix + "data", _doc).asNodeSet();
- for (unsigned int i = 0; i < dataElems.size(); i++) {
- if (!HAS_ATTR(dataElems[i], "id"))
- LOG(ERROR) << "data element has no id attribute" << std::endl;
- }
-
- return validationErrors;
-}
-
+ bool validationErrors = false;
+
+ if (!_doc) {
+ LOG(ERROR) << "Document " << _baseURI.as_string() << " was not parsed successfully" << std::endl;
+ return false;
+ }
+
+ // semantic issues ------------
+ if ((_xpath.evaluate("/" + _nsPrefix + "scxml/@datamodel", _doc).asNodeSet().size() == 0) &&
+ _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "script", _doc).asNodeSet().size() > 0) {
+ LOG(ERROR) << "Script elements used, but no datamodel specified" << std::endl;
+ }
+
+ // element issues ------------
+ Arabica::XPath::NodeSet<std::string> scxmlElems = _xpath.evaluate(_nsPrefix + "scxml", _doc).asNodeSet();
+ if (scxmlElems.size() > 0)
+ LOG(ERROR) << "More than one scxml element found" << std::endl;
+ for (unsigned int i = 0; i < scxmlElems.size(); i++) {
+ if (!HAS_ATTR(scxmlElems[i], "xmlns"))
+ LOG(ERROR) << "scxml element has no xmlns attribute" << std::endl;
+ if (!HAS_ATTR(scxmlElems[i], "version"))
+ LOG(ERROR) << "scxml element has no version attribute" << std::endl;
+ NodeList<std::string> childs = scxmlElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(childs.item(j)), "state") ||
+ boost::iequals(TAGNAME(childs.item(j)), "parallel") ||
+ boost::iequals(TAGNAME(childs.item(j)), "final") ||
+ boost::iequals(TAGNAME(childs.item(j)), "datamodel") ||
+ boost::iequals(TAGNAME(childs.item(j)), "script")) {
+ LOG(ERROR) << "scxml element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> stateElems = _xpath.evaluate(_nsPrefix + "state", _doc).asNodeSet();
+ for (unsigned int i = 0; i < stateElems.size(); i++) {
+ NodeList<std::string> childs = stateElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(childs.item(j)), "onentry") ||
+ boost::iequals(TAGNAME(childs.item(j)), "onexit") ||
+ boost::iequals(TAGNAME(childs.item(j)), "transition") ||
+ boost::iequals(TAGNAME(childs.item(j)), "initial") ||
+ boost::iequals(TAGNAME(childs.item(j)), "state") ||
+ boost::iequals(TAGNAME(childs.item(j)), "parallel") ||
+ boost::iequals(TAGNAME(childs.item(j)), "final") ||
+ boost::iequals(TAGNAME(childs.item(j)), "history") ||
+ boost::iequals(TAGNAME(childs.item(j)), "datamodel") ||
+ boost::iequals(TAGNAME(childs.item(j)), "invoke")) {
+ LOG(ERROR) << "state element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> parallelElems = _xpath.evaluate(_nsPrefix + "parallel", _doc).asNodeSet();
+ for (unsigned int i = 0; i < parallelElems.size(); i++) {
+ NodeList<std::string> childs = parallelElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(childs.item(j)), "onentry") ||
+ boost::iequals(TAGNAME(childs.item(j)), "onexit") ||
+ boost::iequals(TAGNAME(childs.item(j)), "transition") ||
+ boost::iequals(TAGNAME(childs.item(j)), "state") ||
+ boost::iequals(TAGNAME(childs.item(j)), "parallel") ||
+ boost::iequals(TAGNAME(childs.item(j)), "history") ||
+ boost::iequals(TAGNAME(childs.item(j)), "datamodel") ||
+ boost::iequals(TAGNAME(childs.item(j)), "invoke")) {
+ LOG(ERROR) << "parallel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> transitionElems = _xpath.evaluate(_nsPrefix + "transition", _doc).asNodeSet();
+ for (unsigned int i = 0; i < transitionElems.size(); i++) {
+ if (HAS_ATTR(transitionElems[i], "cond") &&
+ !HAS_ATTR(transitionElems[i], "event")) {
+ LOG(ERROR) << "transition element with cond attribute but without event attribute not allowed" << std::endl;
+ }
+ NodeList<std::string> childs = scxmlElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> initialElems = _xpath.evaluate(_nsPrefix + "initial", _doc).asNodeSet();
+ for (unsigned int i = 0; i < initialElems.size(); i++) {
+ NodeList<std::string> childs = initialElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(childs.item(j)), "transition")) {
+ LOG(ERROR) << "initial element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> finalElems = _xpath.evaluate(_nsPrefix + "final", _doc).asNodeSet();
+ for (unsigned int i = 0; i < finalElems.size(); i++) {
+ NodeList<std::string> childs = finalElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (!boost::iequals(TAGNAME(childs.item(j)), "onentry") ||
+ !boost::iequals(TAGNAME(childs.item(j)), "onexit") ||
+ !boost::iequals(TAGNAME(childs.item(j)), "donedata")) {
+ LOG(ERROR) << "parallel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> historyElems = _xpath.evaluate(_nsPrefix + "history", _doc).asNodeSet();
+ for (unsigned int i = 0; i < historyElems.size(); i++) {
+ NodeList<std::string> childs = historyElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(childs.item(j)), "transition")) {
+ LOG(ERROR) << "history element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> datamodelElems = _xpath.evaluate(_nsPrefix + "datamodel", _doc).asNodeSet();
+ for (unsigned int i = 0; i < datamodelElems.size(); i++) {
+ NodeList<std::string> childs = datamodelElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (!boost::iequals(TAGNAME(childs.item(j)), "data")) {
+ LOG(ERROR) << "datamodel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> dataElems = _xpath.evaluate(_nsPrefix + "data", _doc).asNodeSet();
+ for (unsigned int i = 0; i < dataElems.size(); i++) {
+ if (!HAS_ATTR(dataElems[i], "id"))
+ LOG(ERROR) << "data element has no id attribute" << std::endl;
+ }
+
+ return validationErrors;
+}
+
void Interpreter::dump() {
- if (!_doc)
- return;
- dump(_doc);
+ if (!_doc)
+ return;
+ dump(_doc);
}
void Interpreter::dump(const Arabica::DOM::Node<std::string>& node, int lvl) {
- if (!node)
- return;
-
- std::string indent = "";
- for (unsigned int i = 0; i < lvl; i++)
- indent += " ";
-
- std::cout << indent;
- switch(node.getNodeType()) {
- case Arabica::DOM::Node_base::ELEMENT_NODE: {
- std::cout << "ELEMENT_NODE: ";
- Arabica::DOM::Element<std::string> elem = (Arabica::DOM::Element<std::string>)node;
- break;
- }
- case Arabica::DOM::Node_base::ATTRIBUTE_NODE:
- std::cout << "ATTRIBUTE_NODE: ";
- break;
- case Arabica::DOM::Node_base::TEXT_NODE:
- std::cout << "TEXT_NODE: ";
- break;
- case Arabica::DOM::Node_base::CDATA_SECTION_NODE:
- std::cout << "CDATA_SECTION_NODE: ";
- break;
- case Arabica::DOM::Node_base::ENTITY_REFERENCE_NODE:
- std::cout << "ENTITY_REFERENCE_NODE: ";
- break;
- case Arabica::DOM::Node_base::ENTITY_NODE:
- std::cout << "ENTITY_NODE: ";
- break;
- case Arabica::DOM::Node_base::PROCESSING_INSTRUCTION_NODE:
- std::cout << "PROCESSING_INSTRUCTION_NODE: ";
- break;
- case Arabica::DOM::Node_base::COMMENT_NODE:
- std::cout << "COMMENT_NODE: ";
- break;
- case Arabica::DOM::Node_base::DOCUMENT_NODE:
- std::cout << "DOCUMENT_NODE: ";
- break;
- case Arabica::DOM::Node_base::DOCUMENT_TYPE_NODE:
- std::cout << "DOCUMENT_TYPE_NODE: ";
- break;
- case Arabica::DOM::Node_base::DOCUMENT_FRAGMENT_NODE:
- std::cout << "DOCUMENT_FRAGMENT_NODE: ";
- break;
- case Arabica::DOM::Node_base::NOTATION_NODE:
- std::cout << "NOTATION_NODE: ";
- break;
- case Arabica::DOM::Node_base::MAX_TYPE:
- std::cout << "MAX_TYPE: ";
- break;
- }
- std::cout << node.getNamespaceURI() << " " << node.getNodeName() << std::endl;
-
- if (node.getNodeValue().length() > 0 && node.getNodeValue().find_first_not_of(" \t\n") != std::string::npos)
- std::cout << indent << "Value: '" << node.getNodeValue() << "'" << std::endl;
-
-
- if (node.hasAttributes()) {
- Arabica::DOM::NamedNodeMap<std::string> attrs = node.getAttributes();
- for (unsigned int i = 0; i < attrs.getLength(); i++) {
- std::cout << indent << " " << attrs.item(i).getLocalName() << " = " << attrs.item(i).getNodeValue() << " (" << std::endl;
- std::cout << indent << " namespace: " << attrs.item(i).getNamespaceURI() << std::endl;
- std::cout << indent << " nodeName: " << attrs.item(i).getNodeName() << std::endl;
- std::cout << indent << " prefix: " << attrs.item(i).getPrefix() << std::endl;
- std::cout << indent << " )" << std::endl;
- }
- }
-
- if (node.hasChildNodes()) {
- Arabica::DOM::NodeList<std::string> childs = node.getChildNodes();
- for (unsigned int i = 0; i < childs.getLength(); i++) {
- dump(childs.item(i), lvl+1);
- }
- }
+ if (!node)
+ return;
+
+ std::string indent = "";
+ for (unsigned int i = 0; i < lvl; i++)
+ indent += " ";
+
+ std::cout << indent;
+ switch(node.getNodeType()) {
+ case Arabica::DOM::Node_base::ELEMENT_NODE: {
+ std::cout << "ELEMENT_NODE: ";
+ Arabica::DOM::Element<std::string> elem = (Arabica::DOM::Element<std::string>)node;
+ break;
+ }
+ case Arabica::DOM::Node_base::ATTRIBUTE_NODE:
+ std::cout << "ATTRIBUTE_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::TEXT_NODE:
+ std::cout << "TEXT_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::CDATA_SECTION_NODE:
+ std::cout << "CDATA_SECTION_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::ENTITY_REFERENCE_NODE:
+ std::cout << "ENTITY_REFERENCE_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::ENTITY_NODE:
+ std::cout << "ENTITY_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::PROCESSING_INSTRUCTION_NODE:
+ std::cout << "PROCESSING_INSTRUCTION_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::COMMENT_NODE:
+ std::cout << "COMMENT_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::DOCUMENT_NODE:
+ std::cout << "DOCUMENT_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::DOCUMENT_TYPE_NODE:
+ std::cout << "DOCUMENT_TYPE_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::DOCUMENT_FRAGMENT_NODE:
+ std::cout << "DOCUMENT_FRAGMENT_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::NOTATION_NODE:
+ std::cout << "NOTATION_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::MAX_TYPE:
+ std::cout << "MAX_TYPE: ";
+ break;
+ }
+ std::cout << node.getNamespaceURI() << " " << node.getNodeName() << std::endl;
+
+ if (node.getNodeValue().length() > 0 && node.getNodeValue().find_first_not_of(" \t\n") != std::string::npos)
+ std::cout << indent << "Value: '" << node.getNodeValue() << "'" << std::endl;
+
+
+ if (node.hasAttributes()) {
+ Arabica::DOM::NamedNodeMap<std::string> attrs = node.getAttributes();
+ for (unsigned int i = 0; i < attrs.getLength(); i++) {
+ std::cout << indent << " " << attrs.item(i).getLocalName() << " = " << attrs.item(i).getNodeValue() << " (" << std::endl;
+ std::cout << indent << " namespace: " << attrs.item(i).getNamespaceURI() << std::endl;
+ std::cout << indent << " nodeName: " << attrs.item(i).getNodeName() << std::endl;
+ std::cout << indent << " prefix: " << attrs.item(i).getPrefix() << std::endl;
+ std::cout << indent << " )" << std::endl;
+ }
+ }
+
+ if (node.hasChildNodes()) {
+ Arabica::DOM::NodeList<std::string> childs = node.getChildNodes();
+ for (unsigned int i = 0; i < childs.getLength(); i++) {
+ dump(childs.item(i), lvl+1);
+ }
+ }
}
} \ No newline at end of file