summaryrefslogtreecommitdiffstats
path: root/src/uscxml
diff options
context:
space:
mode:
authorStefan Radomski <github@mintwerk.de>2016-06-18 11:55:39 (GMT)
committerStefan Radomski <github@mintwerk.de>2016-06-18 11:55:39 (GMT)
commit0e0be07906a720ae54e4572d6ac0cb657424550d (patch)
tree7d48c87a9142a5dad06570ca4daf0212475d83f1 /src/uscxml
parent84bbbd42c3480c40c0355c64899f99f8d588d5c0 (diff)
downloaduscxml-0e0be07906a720ae54e4572d6ac0cb657424550d.zip
uscxml-0e0be07906a720ae54e4572d6ac0cb657424550d.tar.gz
uscxml-0e0be07906a720ae54e4572d6ac0cb657424550d.tar.bz2
Started to port Debugger and issue 87
Diffstat (limited to 'src/uscxml')
-rw-r--r--src/uscxml/Interpreter.cpp22
-rw-r--r--src/uscxml/Interpreter.h7
-rw-r--r--src/uscxml/debug/Breakpoint.cpp267
-rw-r--r--src/uscxml/debug/Breakpoint.h100
-rw-r--r--src/uscxml/debug/DebugSession.cpp373
-rw-r--r--src/uscxml/debug/DebugSession.h107
-rw-r--r--src/uscxml/debug/Debugger.cpp258
-rw-r--r--src/uscxml/debug/Debugger.h116
-rw-r--r--src/uscxml/debug/DebuggerServlet.cpp261
-rw-r--r--src/uscxml/debug/DebuggerServlet.h108
-rw-r--r--src/uscxml/interpreter/BasicContentExecutor.cpp14
-rw-r--r--src/uscxml/interpreter/BasicEventQueue.cpp20
-rw-r--r--src/uscxml/interpreter/ContentExecutorImpl.h2
-rw-r--r--src/uscxml/interpreter/FastMicroStep.cpp87
-rw-r--r--src/uscxml/interpreter/FastMicroStep.h2
-rw-r--r--src/uscxml/interpreter/InterpreterImpl.cpp2
-rw-r--r--src/uscxml/interpreter/InterpreterImpl.h18
-rw-r--r--src/uscxml/interpreter/InterpreterMonitor.h64
-rw-r--r--src/uscxml/interpreter/MicroStepImpl.h5
-rw-r--r--src/uscxml/util/BlockingQueue.h77
-rw-r--r--src/uscxml/util/DOM.h40
21 files changed, 1827 insertions, 123 deletions
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index a050401..d21ec6a 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -220,8 +220,12 @@ void Interpreter::setActionLanguage(ActionLanguage actionLanguage) {
return _impl->setActionLanguage(actionLanguage);
}
-void Interpreter::setMonitor(InterpreterMonitor* monitor) {
- return _impl->setMonitor(monitor);
+void Interpreter::addMonitor(InterpreterMonitor* monitor) {
+ return _impl->addMonitor(monitor);
+}
+
+void Interpreter::removeMonitor(InterpreterMonitor* monitor) {
+ return _impl->removeMonitor(monitor);
}
std::list<InterpreterIssue> Interpreter::validate() {
@@ -240,19 +244,19 @@ static void printNodeSet(const std::list<XERCESC_NS::DOMElement*> nodes) {
}
#endif
-void StateTransitionMonitor::beforeTakingTransition(const XERCESC_NS::DOMElement* transition) {
+void StateTransitionMonitor::beforeTakingTransition(InterpreterImpl* impl, const XERCESC_NS::DOMElement* transition) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
std::cerr << "Transition: " << uscxml::DOMUtils::xPathForNode(transition) << std::endl;
}
-void StateTransitionMonitor::onStableConfiguration() {
+void StateTransitionMonitor::onStableConfiguration(InterpreterImpl* impl) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
std::cerr << "Stable Config: { ";
// printNodeSet(_interpreter.getConfiguration());
std::cerr << " }" << std::endl;
}
-void StateTransitionMonitor::beforeProcessingEvent(const uscxml::Event& event) {
+void StateTransitionMonitor::beforeProcessingEvent(InterpreterImpl* impl, const uscxml::Event& event) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
switch (event.eventType) {
case uscxml::Event::INTERNAL:
@@ -267,23 +271,23 @@ void StateTransitionMonitor::beforeProcessingEvent(const uscxml::Event& event)
}
}
-void StateTransitionMonitor::beforeExecutingContent(const XERCESC_NS::DOMElement* element) {
+void StateTransitionMonitor::beforeExecutingContent(InterpreterImpl* impl, const XERCESC_NS::DOMElement* element) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
std::cerr << "Executable Content: " << DOMUtils::xPathForNode(element) << std::endl;
}
-void StateTransitionMonitor::beforeExitingState(const XERCESC_NS::DOMElement* state) {
+void StateTransitionMonitor::beforeExitingState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
std::cerr << "Exiting: " << (HAS_ATTR(state, "id") ? ATTR(state, "id") : DOMUtils::xPathForNode(state)) << std::endl;
}
-void StateTransitionMonitor::beforeEnteringState(const XERCESC_NS::DOMElement* state) {
+void StateTransitionMonitor::beforeEnteringState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
std::cerr << "Entering: " << (HAS_ATTR(state, "id") ? ATTR(state, "id") : DOMUtils::xPathForNode(state)) << std::endl;
}
-void StateTransitionMonitor::beforeMicroStep() {
+void StateTransitionMonitor::beforeMicroStep(InterpreterImpl* impl) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
std::cerr << "Config: {";
// printNodeSet(_interpreter.getConfiguration());
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
index 4dbefd8..0d7573c 100644
--- a/src/uscxml/Interpreter.h
+++ b/src/uscxml/Interpreter.h
@@ -221,7 +221,12 @@ public:
/**
* Attach a monitor to make more details of the interpreter observable.
*/
- void setMonitor(InterpreterMonitor* monitor);
+ void addMonitor(InterpreterMonitor* monitor);
+
+ /**
+ * Remove a monitor that was attached previously.
+ */
+ void removeMonitor(InterpreterMonitor* monitor);
/**
* Return the actual implementation of the Interperter.
diff --git a/src/uscxml/debug/Breakpoint.cpp b/src/uscxml/debug/Breakpoint.cpp
new file mode 100644
index 0000000..1e40ee3
--- /dev/null
+++ b/src/uscxml/debug/Breakpoint.cpp
@@ -0,0 +1,267 @@
+/**
+ * @file
+ * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#include "uscxml/debug/Breakpoint.h"
+#include "uscxml/Interpreter.h"
+#include "uscxml/interpreter/InterpreterImpl.h"
+#include "uscxml/util/DOM.h"
+#include "uscxml/util/String.h"
+
+namespace uscxml {
+
+Breakpoint::Breakpoint(const Data& data) {
+ enabled = true;
+ subject = UNDEF_SUBJECT;
+ when = UNDEF_WHEN;
+ action = UNDEF_ACTION;
+
+ if (data.hasKey("when")) {
+ if (false) {
+ } else if (data.at("when").atom == "before") {
+ when = BEFORE;
+ } else if (data.at("when").atom == "after") {
+ when = AFTER;
+ } else if (data.at("when").atom == "on") {
+ when = ON;
+ }
+ }
+
+ if (data.hasKey("action")) {
+ if (false) {
+ } else if (data.at("action").atom == "enter") {
+ action = ENTER;
+ } else if (data.at("action").atom == "exit") {
+ action = EXIT;
+ } else if (data.at("action").atom == "invoke") {
+ action = INVOKE;
+ } else if (data.at("action").atom == "cancel") {
+ action = UNINVOKE;
+ }
+ }
+
+ if (data.hasKey("subject")) {
+ if (false) {
+ } else if (data.at("subject").atom == "state") {
+ subject = STATE;
+ } else if (data.at("subject").atom == "transition") {
+ subject = TRANSITION;
+ } else if (data.at("subject").atom == "stable") {
+ subject = STABLE;
+ } else if (data.at("subject").atom == "microstep") {
+ subject = MICROSTEP;
+ } else if (data.at("subject").atom == "event") {
+ subject = EVENT;
+ } else if (data.at("subject").atom == "invoker") {
+ subject = INVOKER;
+ } else if (data.at("subject").atom == "executable") {
+ subject = EXECUTABLE;
+ }
+ }
+
+ if (data.hasKey("condition"))
+ condition = data.at("condition").atom;
+
+ if (data.hasKey("invokeId"))
+ invokeId = data.at("invokeId").atom;
+
+ if (data.hasKey("invokeType"))
+ invokeType = data.at("invokeType").atom;
+
+ if (data.hasKey("eventName"))
+ eventName = data.at("eventName").atom;
+
+ if (data.hasKey("executableName"))
+ executableName = data.at("executableName").atom;
+
+ if (data.hasKey("executableXPath"))
+ executableXPath = data.at("executableXPath").atom;
+
+ if (data.hasKey("stateId"))
+ stateId = data.at("stateId").atom;
+
+ if (data.hasKey("transSourceId"))
+ transSourceId = data.at("transSourceId").atom;
+
+ if (data.hasKey("transTargetId"))
+ transTargetId = data.at("transTargetId").atom;
+
+}
+
+Data Breakpoint::toData() const {
+ Data data;
+
+ switch (subject) {
+ case STATE:
+ data.compound["subject"] = Data("state", Data::VERBATIM);
+ break;
+ case TRANSITION:
+ data.compound["subject"] = Data("transition", Data::VERBATIM);
+ break;
+ case STABLE:
+ data.compound["subject"] = Data("stable", Data::VERBATIM);
+ break;
+ case MICROSTEP:
+ data.compound["subject"] = Data("microstep", Data::VERBATIM);
+ break;
+ case EVENT:
+ data.compound["subject"] = Data("event", Data::VERBATIM);
+ break;
+ case INVOKER:
+ data.compound["subject"] = Data("invoker", Data::VERBATIM);
+ break;
+ case EXECUTABLE:
+ data.compound["subject"] = Data("executable", Data::VERBATIM);
+ break;
+ default:
+ break;
+ }
+
+ switch (when) {
+ case AFTER:
+ data.compound["when"] = Data("after", Data::VERBATIM);
+ break;
+ case BEFORE:
+ data.compound["when"] = Data("before", Data::VERBATIM);
+ break;
+ case ON:
+ data.compound["when"] = Data("on", Data::VERBATIM);
+ break;
+ default:
+ break;
+ }
+
+ switch (action) {
+ case ENTER:
+ data.compound["action"] = Data("enter", Data::VERBATIM);
+ break;
+ case EXIT:
+ data.compound["action"] = Data("exit", Data::VERBATIM);
+ break;
+ case INVOKE:
+ data.compound["action"] = Data("invoke", Data::VERBATIM);
+ break;
+ case UNINVOKE:
+ data.compound["action"] = Data("cancel", Data::VERBATIM);
+ break;
+ default:
+ break;
+ }
+
+ if (invokeId.length() > 0)
+ data.compound["invokeId"] = Data(invokeId, Data::VERBATIM);
+
+ if (invokeType.length() > 0)
+ data.compound["invokeType"] = Data(invokeType, Data::VERBATIM);
+
+ if (eventName.length() > 0)
+ data.compound["eventName"] = Data(eventName, Data::VERBATIM);
+
+ if (executableName.length() > 0)
+ data.compound["executableName"] = Data(executableName, Data::VERBATIM);
+
+ if (executableXPath.length() > 0) {
+ data.compound["executableXPath"] = Data(executableXPath, Data::VERBATIM);
+ }
+
+ if (element)
+ data.compound["xpath"] = Data(DOMUtils::xPathForNode(element, "*"), Data::VERBATIM);
+
+ if (stateId.length() > 0)
+ data.compound["stateId"] = Data(stateId, Data::VERBATIM);
+
+ if (transSourceId.length() > 0)
+ data.compound["transSourceId"] = Data(transSourceId, Data::VERBATIM);
+
+ if (transTargetId.length() > 0)
+ data.compound["transTargetId"] = Data(transTargetId, Data::VERBATIM);
+
+ if (condition.length() > 0)
+ data.compound["condition"] = Data(condition, Data::VERBATIM);
+
+ return data;
+}
+
+bool Breakpoint::matches(Interpreter interpreter, const Breakpoint& other) const {
+ // would we match the given breakpoint?
+
+ if (subject != UNDEF_SUBJECT &&
+ other.subject != subject)
+ return false; // subject does not match
+
+ if (when != UNDEF_WHEN &&
+ other.when != when)
+ return false; // time does not match
+
+ if (action != UNDEF_ACTION &&
+ other.action != action)
+ return false; // action does not match
+
+ // when we have a qualifier it has to match
+ if(invokeId.length() > 0 && invokeId != other.invokeId) {
+ return false;
+ }
+
+ if(invokeType.length() > 0 && invokeType != other.invokeType) {
+ return false;
+ }
+
+ if(stateId.length() > 0 && stateId != other.stateId) {
+ return false;
+ }
+
+ if(eventName.length() > 0 && !nameMatch(eventName, other.eventName)) {
+ return false;
+ }
+
+ if(executableName.length() > 0 && executableName != other.executableName) {
+ return false;
+ }
+
+#if 0
+ if(executableXPath.length()) {
+ Arabica::XPath::NodeSet<std::string> nodes;
+ try {
+ nodes = interpreter.getNodeSetForXPath(executableXPath);
+ } catch (...) {
+ return false;
+ }
+ return InterpreterImpl::isMember(other.element, nodes);
+ }
+#endif
+
+ if(transSourceId.length() > 0 && transSourceId != other.transSourceId) {
+ return false;
+ }
+
+ if(transTargetId.length() > 0 && transTargetId != other.transTargetId) {
+ return false;
+ }
+
+ if (condition.length() > 0) {
+ try {
+ interpreter.getImpl()->isTrue(condition);
+ } catch (...) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/debug/Breakpoint.h b/src/uscxml/debug/Breakpoint.h
new file mode 100644
index 0000000..3809663
--- /dev/null
+++ b/src/uscxml/debug/Breakpoint.h
@@ -0,0 +1,100 @@
+/**
+ * @file
+ * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#ifndef BREAKPOINT_H_VR7K7T1X
+#define BREAKPOINT_H_VR7K7T1X
+
+#include <string> // for string
+#include "uscxml/Common.h" // for USCXML_API
+#include "uscxml/Interpreter.h"
+//#include "DOM/Element.hpp" // for Element
+#include "uscxml/messages/Data.h" // for Data
+
+// forward declare
+namespace XERCESC_NS {
+ class DOMElement;
+}
+
+namespace uscxml {
+
+class USCXML_API Breakpoint {
+public:
+
+ enum When {
+ UNDEF_WHEN, AFTER, BEFORE, ON
+ };
+
+ enum Subject {
+ UNDEF_SUBJECT, STATE, TRANSITION, STABLE, MICROSTEP, EVENT, INVOKER, EXECUTABLE
+ };
+
+ enum Action {
+ UNDEF_ACTION, ENTER, EXIT, INVOKE, UNINVOKE
+ };
+
+ Breakpoint() {
+ subject = UNDEF_SUBJECT;
+ when = UNDEF_WHEN;
+ action = UNDEF_ACTION;
+ }
+ Breakpoint(const Data& data);
+
+ // would we match the given breakpoint as well?
+ bool matches(Interpreter interpreter, const Breakpoint& other) const;
+
+ Data toData() const;
+
+ bool operator<(const Breakpoint& other) const {
+ return (toData() < other.toData());
+ }
+
+ operator bool() {
+ return (subject != UNDEF_SUBJECT ||
+ when != UNDEF_WHEN ||
+ action != UNDEF_ACTION);
+ }
+
+ mutable bool enabled;
+
+ When when;
+ Subject subject;
+ Action action;
+
+ const XERCESC_NS::DOMElement* element = NULL;
+
+ std::string invokeId;
+ std::string invokeType;
+
+ std::string eventName;
+
+ std::string executableName;
+ std::string executableXPath;
+
+ std::string stateId;
+ std::string transSourceId;
+ std::string transTargetId;
+
+ std::string condition;
+};
+
+}
+
+
+
+#endif /* end of include guard: BREAKPOINT_H_VR7K7T1X */
diff --git a/src/uscxml/debug/DebugSession.cpp b/src/uscxml/debug/DebugSession.cpp
new file mode 100644
index 0000000..ef4d469
--- /dev/null
+++ b/src/uscxml/debug/DebugSession.cpp
@@ -0,0 +1,373 @@
+/**
+ * @file
+ * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#include "uscxml/debug/DebugSession.h"
+#include "uscxml/debug/Debugger.h"
+#include "uscxml/util/Predicates.h"
+
+namespace uscxml {
+
+void DebugSession::checkBreakpoints(const std::list<Breakpoint> qualifiedBreakpoints) {
+ std::list<Breakpoint>::const_iterator qualifiedBreakpointIter = qualifiedBreakpoints.begin();
+
+ if (!_breakpointsEnabled)
+ return;
+
+ while(qualifiedBreakpointIter != qualifiedBreakpoints.end()) {
+ const Breakpoint& qualifiedBreakpoint = *qualifiedBreakpointIter++;
+
+ // check if one of the user-supplied breakpoints match
+ bool userBreakpointMatched = false;
+ Data replyData;
+
+ if (_skipTo) {
+ if (_skipTo.matches(_interpreter, qualifiedBreakpoint)) {
+ replyData.compound["breakpoint"] = _skipTo.toData();
+ replyData.compound["qualified"] = qualifiedBreakpoint.toData();
+ breakExecution(replyData);
+ _skipTo = Breakpoint();
+ }
+ continue;
+ }
+
+ std::set<Breakpoint>::const_iterator breakpointIter = _breakPoints.begin();
+ while(breakpointIter != _breakPoints.end()) {
+ const Breakpoint& breakpoint = *breakpointIter++;
+ if (!breakpoint.enabled)
+ continue;
+ if (breakpoint.matches(_interpreter, qualifiedBreakpoint)) {
+ // do we have a condition?
+
+ replyData.compound["breakpoint"] = breakpoint.toData();
+ replyData.compound["qualified"] = qualifiedBreakpoint.toData();
+
+ userBreakpointMatched = true;
+ breakExecution(replyData);
+ }
+ }
+ if (_isStepping && !userBreakpointMatched) {
+ replyData.compound["qualified"] = qualifiedBreakpoint.toData();
+ breakExecution(replyData);
+
+ }
+ }
+}
+
+void DebugSession::breakExecution(Data replyData) {
+ std::lock_guard<std::recursive_mutex> lock(_mutex);
+
+ std::list<XERCESC_NS::DOMElement*> configuration = _interpreter.getConfiguration();
+ for (auto state : configuration) {
+ if (HAS_ATTR(state, "id")) {
+ replyData.compound["activeStates"].array.push_back(Data(ATTR(state, "id"), Data::VERBATIM));
+ if (isAtomic(state)) {
+ replyData.compound["basicStates"].array.push_back(Data(ATTR(state, "id"), Data::VERBATIM));
+ }
+ }
+ }
+
+ replyData.compound["replyType"] = Data("breakpoint", Data::VERBATIM);
+ _debugger->pushData(shared_from_this(), replyData);
+ _resumeCond.wait(_mutex);
+}
+
+Data DebugSession::debugPrepare(const Data& data) {
+ Data replyData;
+
+ if (!data.hasKey("xml") && !data.hasKey("url")) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No XML or URL given", Data::VERBATIM);
+ return replyData;
+ }
+
+ debugStop(data);
+
+ _isAttached = false;
+
+ if (data.hasKey("xml")) {
+ _interpreter = Interpreter::fromXML(data.at("xml").atom, (data.hasKey("url") ? data.at("url").atom : ""));
+ } else if (data.hasKey("url")) {
+ _interpreter = Interpreter::fromURL(data.at("url").atom);
+ } else {
+ _interpreter = Interpreter();
+ }
+
+ if (_interpreter) {
+ // register ourself as a monitor
+ _interpreter.addMonitor(_debugger);
+ _debugger->attachSession(_interpreter.getImpl().get(), shared_from_this());
+
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ } else {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ }
+
+ return replyData;
+}
+
+Data DebugSession::debugAttach(const Data& data) {
+ Data replyData;
+ _isAttached = true;
+
+ if (!data.hasKey("attach")) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No id to attach to given", Data::VERBATIM);
+ return replyData;
+ }
+
+ std::string interpreterId = data.at("attach").atom;
+ bool interpreterFound = false;
+
+ // find interpreter for sessionid
+ std::map<std::string, std::weak_ptr<InterpreterImpl> > instances = InterpreterImpl::getInstances();
+ for (auto weakInstance : instances) {
+
+ std::shared_ptr<InterpreterImpl> instance = weakInstance.second.lock();
+ if (instance && instance->getSessionId() == interpreterId) {
+ _interpreter = instance;
+ _debugger->attachSession(_interpreter.getImpl().get(), shared_from_this());
+ interpreterFound = true;
+ break;
+ }
+ }
+
+ if (!interpreterFound) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No interpreter with given id found", Data::VERBATIM);
+ } else {
+ replyData.compound["xml"].node = _interpreter.getImpl()->getDocument();
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ }
+
+ return replyData;
+}
+
+Data DebugSession::debugDetach(const Data& data) {
+ Data replyData;
+ _isAttached = false;
+
+ _debugger->detachSession(_interpreter.getImpl().get());
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ return replyData;
+}
+
+Data DebugSession::debugStart(const Data& data) {
+ Data replyData;
+
+ if (_isAttached) {
+ replyData.compound["reason"] = Data("Already started when attached", Data::VERBATIM);
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ } else if (!_interpreter) {
+ replyData.compound["reason"] = Data("No interpreter attached or loaded", Data::VERBATIM);
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ } else {
+ //_interpreter.start();
+ assert(false);
+
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ }
+
+ return replyData;
+}
+
+Data DebugSession::debugStop(const Data& data) {
+ Data replyData;
+
+ if (_interpreter) {
+ // detach from old intepreter
+ _debugger->detachSession(_interpreter.getImpl().get());
+ }
+
+ if (_interpreter && !_isAttached)
+ assert(false);
+ //_interpreter.stop();
+ // unblock
+ _resumeCond.notify_all();
+
+ _skipTo = Breakpoint();
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+
+ // calls destructor
+ _interpreter = Interpreter();
+
+ return replyData;
+}
+
+Data DebugSession::debugStep(const Data& data) {
+ std::lock_guard<std::recursive_mutex> lock(_mutex);
+
+ stepping(true);
+ _resumeCond.notify_one();
+
+ Data replyData;
+ if (_interpreter) {
+ // register ourself as a monitor
+ if (!_isRunning)
+ //_interpreter.start();
+ assert(false);
+
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ } else {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ }
+ return replyData;
+}
+
+Data DebugSession::debugResume(const Data& data) {
+ std::lock_guard<std::recursive_mutex> lock(_mutex);
+
+ stepping(false);
+
+ Data replyData;
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+
+ _resumeCond.notify_one();
+ return replyData;
+}
+
+
+Data DebugSession::debugPause(const Data& data) {
+ std::lock_guard<std::recursive_mutex> lock(_mutex);
+
+ _skipTo = Breakpoint();
+ stepping(true);
+
+ Data replyData;
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+
+ return replyData;
+}
+
+Data DebugSession::skipToBreakPoint(const Data& data) {
+ std::lock_guard<std::recursive_mutex> lock(_mutex);
+
+ _skipTo = Breakpoint(data);
+
+ Data replyData;
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+
+ _resumeCond.notify_one();
+ return replyData;
+}
+
+Data DebugSession::addBreakPoint(const Data& data) {
+ Breakpoint breakpoint(data);
+
+ Data replyData;
+ if (_breakPoints.find(breakpoint) == _breakPoints.end()) {
+ _breakPoints.insert(breakpoint);
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+
+ } else {
+ replyData.compound["reason"] = Data("Breakpoint already exists", Data::VERBATIM);
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ }
+ return replyData;
+}
+
+Data DebugSession::removeBreakPoint(const Data& data) {
+ Breakpoint breakpoint(data);
+
+ Data replyData;
+ if (_breakPoints.find(breakpoint) != _breakPoints.end()) {
+ _breakPoints.erase(breakpoint);
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ } else {
+ replyData.compound["reason"] = Data("No such breakpoint", Data::VERBATIM);
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ }
+ return replyData;
+}
+
+Data DebugSession::enableBreakPoint(const Data& data) {
+ Breakpoint breakpoint(data);
+
+ Data replyData;
+ if (_breakPoints.find(breakpoint) != _breakPoints.end()) {
+ _breakPoints.find(breakpoint)->enabled = true;
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ } else {
+ replyData.compound["reason"] = Data("No such breakpoint", Data::VERBATIM);
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ }
+
+ return replyData;
+}
+Data DebugSession::disableBreakPoint(const Data& data) {
+ Breakpoint breakpoint(data);
+
+ Data replyData;
+ if (_breakPoints.find(breakpoint) != _breakPoints.end()) {
+ _breakPoints.find(breakpoint)->enabled = false;
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ } else {
+ replyData.compound["reason"] = Data("No such breakpoint", Data::VERBATIM);
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ }
+
+ return replyData;
+}
+Data DebugSession::enableAllBreakPoints() {
+ Data replyData;
+
+ _breakpointsEnabled = true;
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+
+ return replyData;
+}
+Data DebugSession::disableAllBreakPoints() {
+ Data replyData;
+
+ _breakpointsEnabled = false;
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+
+ return replyData;
+}
+
+Data DebugSession::debugEval(const Data& data) {
+ Data replyData;
+
+ if (!data.hasKey("expression")) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No expression given", Data::VERBATIM);
+ return replyData;
+ }
+
+ std::string expr = data.at("expression").atom;
+
+ if (!_interpreter) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No interpreter running", Data::VERBATIM);
+ } else if (!_interpreter.getImpl()->_dataModel) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No datamodel available", Data::VERBATIM);
+ } else {
+ try {
+ replyData.compound["eval"] = _interpreter.getImpl()->getAsData(expr);
+ } catch (Event e) {
+ replyData.compound["eval"] = e.data;
+ replyData.compound["eval"].compound["error"] = Data(e.name, Data::VERBATIM);
+ }
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ }
+ return replyData;
+}
+
+
+} \ No newline at end of file
diff --git a/src/uscxml/debug/DebugSession.h b/src/uscxml/debug/DebugSession.h
new file mode 100644
index 0000000..a1ecaa0
--- /dev/null
+++ b/src/uscxml/debug/DebugSession.h
@@ -0,0 +1,107 @@
+/**
+ * @file
+ * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#ifndef DEBUGSESSION_H_M8YHEGV6
+#define DEBUGSESSION_H_M8YHEGV6
+
+#include "uscxml/debug/Breakpoint.h"
+#include "uscxml/Interpreter.h"
+#include <time.h>
+#include <set>
+#include <thread>
+#include <condition_variable>
+
+namespace uscxml {
+
+class Debugger;
+
+class USCXML_API DebugSession : public std::enable_shared_from_this<DebugSession> {
+public:
+ DebugSession() {
+ _isRunning = false;
+ _isStepping = false;
+ _isAttached = false;
+ _breakpointsEnabled = true;
+ _markedForDeletion = false;
+ _debugger = NULL;
+ }
+
+ void stepping(bool enable) {
+ _isStepping = enable;
+ }
+
+ void checkBreakpoints(const std::list<Breakpoint> qualifiedBreakpoints);
+
+ Data debugPrepare(const Data& data);
+ Data debugAttach(const Data& data);
+ Data debugDetach(const Data& data);
+ Data debugStart(const Data& data);
+ Data debugStop(const Data& data);
+ Data debugStep(const Data& data);
+ Data debugResume(const Data& data);
+ Data debugPause(const Data& data);
+ Data skipToBreakPoint(const Data& data);
+ Data addBreakPoint(const Data& data);
+ Data removeBreakPoint(const Data& data);
+ Data enableBreakPoint(const Data& data);
+ Data disableBreakPoint(const Data& data);
+ Data enableAllBreakPoints();
+ Data disableAllBreakPoints();
+ Data debugEval(const Data& data);
+
+ void setDebugger(Debugger* debugger) {
+ _debugger = debugger;
+ }
+
+ Interpreter getInterpreter() {
+ return _interpreter;
+ }
+
+ void markForDeletion(bool mark) {
+ _markedForDeletion = mark;
+ }
+
+protected:
+ void breakExecution(Data replyData);
+
+ bool _isStepping;
+ bool _isAttached;
+ bool _breakpointsEnabled;
+
+ std::condition_variable_any _resumeCond;
+ std::recursive_mutex _runMutex;
+ std::recursive_mutex _mutex;
+
+ std::thread* _interpreterThread = NULL;
+ bool _isRunning;
+
+ bool _markedForDeletion;
+ Debugger* _debugger;
+ Interpreter _interpreter;
+ std::set<Breakpoint> _breakPoints;
+ Breakpoint _skipTo;
+
+ friend class Debugger;
+};
+
+
+}
+
+
+#endif /* end of include guard: DEBUGSESSION_H_M8YHEGV6 */
diff --git a/src/uscxml/debug/Debugger.cpp b/src/uscxml/debug/Debugger.cpp
new file mode 100644
index 0000000..09c21e7
--- /dev/null
+++ b/src/uscxml/debug/Debugger.cpp
@@ -0,0 +1,258 @@
+/**
+* @file
+* @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+* @copyright Simplified BSD
+*
+* @cond
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the FreeBSD license as published by the FreeBSD
+* project.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*
+* You should have received a copy of the FreeBSD license along with this
+* program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+* @endcond
+*/
+
+#include "uscxml/debug/Debugger.h"
+#include "uscxml/util/DOM.h"
+#include "uscxml/util/Predicates.h"
+#include "uscxml/debug/DebugSession.h"
+
+namespace uscxml {
+
+void Debugger::afterCompletion(InterpreterImpl* impl) {
+ std::shared_ptr<DebugSession> session = getSession(impl);
+ if (!session)
+ return;
+
+ Data msg;
+ msg.compound["replyType"] = Data("finished", Data::VERBATIM);
+ pushData(session, msg);
+}
+
+void Debugger::beforeCompletion(InterpreterImpl* impl) {}
+
+std::list<Breakpoint> Debugger::getQualifiedStateBreakpoints(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state, Breakpoint breakpointTemplate) {
+ std::list<Breakpoint> breakpoints;
+
+ Breakpoint bp = breakpointTemplate; // copy base as template
+ bp.stateId = ATTR(state, "id");
+ bp.element = state;
+ bp.subject = Breakpoint::STATE;
+ breakpoints.push_back(bp);
+
+ return breakpoints;
+}
+
+std::list<Breakpoint> Debugger::getQualifiedInvokeBreakpoints(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string invokeId, Breakpoint breakpointTemplate) {
+ std::list<Breakpoint> breakpoints;
+
+ Breakpoint bp = breakpointTemplate; // copy base as template
+ bp.subject = Breakpoint::INVOKER;
+ bp.element = invokeElem;
+ bp.invokeId = invokeId;
+
+ if (HAS_ATTR(invokeElem, "type")) {
+ bp.invokeType = ATTR(invokeElem, "type");
+ } else if (HAS_ATTR(invokeElem, "typeexpr")) {
+ bp.invokeType = impl->evalAsData(ATTR(invokeElem, "typeexpr")).atom;
+ }
+
+ breakpoints.push_back(bp);
+
+ return breakpoints;
+}
+
+std::list<Breakpoint> Debugger::getQualifiedTransBreakpoints(InterpreterImpl* impl, const XERCESC_NS::DOMElement* transition, Breakpoint breakpointTemplate) {
+ std::list<Breakpoint> breakpoints;
+
+ XERCESC_NS::DOMElement* source = getSourceState(transition);
+ std::list<XERCESC_NS::DOMElement*> targets = getTargetStates(transition, impl->_scxml);
+
+ for (auto target : targets) {
+
+ Breakpoint bp = breakpointTemplate; // copy base as template
+ bp.element = transition;
+ bp.transSourceId = ATTR(source, "id");
+ bp.transTargetId = ATTR(target, "id");
+ bp.subject = Breakpoint::TRANSITION;
+
+ breakpoints.push_back(bp);
+ }
+
+ return breakpoints;
+}
+
+void Debugger::beforeTakingTransition(InterpreterImpl* impl, const XERCESC_NS::DOMElement* transition) {
+ handleTransition(impl, transition, Breakpoint::BEFORE);
+}
+void Debugger::afterTakingTransition(InterpreterImpl* impl, const XERCESC_NS::DOMElement* transition) {
+ handleTransition(impl, transition, Breakpoint::AFTER);
+}
+void Debugger::beforeExecutingContent(InterpreterImpl* impl, const XERCESC_NS::DOMElement* execContent) {
+ handleExecutable(impl, execContent, Breakpoint::BEFORE);
+}
+void Debugger::afterExecutingContent(InterpreterImpl* impl, const XERCESC_NS::DOMElement* execContent) {
+ handleExecutable(impl, execContent, Breakpoint::AFTER);
+}
+void Debugger::beforeExitingState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state) {
+ handleState(impl, state, Breakpoint::BEFORE, Breakpoint::EXIT);
+}
+void Debugger::afterExitingState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state) {
+ handleState(impl, state, Breakpoint::AFTER, Breakpoint::EXIT);
+}
+void Debugger::beforeEnteringState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state) {
+ handleState(impl, state, Breakpoint::BEFORE, Breakpoint::ENTER);
+}
+void Debugger::afterEnteringState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state) {
+ handleState(impl, state, Breakpoint::AFTER, Breakpoint::ENTER);
+}
+void Debugger::beforeUninvoking(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {
+ handleInvoke(impl, invokeElem, invokeid, Breakpoint::BEFORE, Breakpoint::UNINVOKE);
+}
+void Debugger::afterUninvoking(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {
+ handleInvoke(impl, invokeElem, invokeid, Breakpoint::AFTER, Breakpoint::UNINVOKE);
+}
+void Debugger::beforeInvoking(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {
+ handleInvoke(impl, invokeElem, invokeid, Breakpoint::BEFORE, Breakpoint::INVOKE);
+}
+void Debugger::afterInvoking(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {
+ handleInvoke(impl, invokeElem, invokeid, Breakpoint::AFTER, Breakpoint::INVOKE);
+}
+void Debugger::onStableConfiguration(InterpreterImpl* impl) {
+ handleStable(impl, Breakpoint::ON);
+}
+void Debugger::beforeMicroStep(InterpreterImpl* impl) {
+ handleMicrostep(impl, Breakpoint::BEFORE);
+}
+void Debugger::afterMicroStep(InterpreterImpl* impl) {
+ handleMicrostep(impl, Breakpoint::AFTER);
+}
+void Debugger::beforeProcessingEvent(InterpreterImpl* impl, const Event& event) {
+ handleEvent(impl, event, Breakpoint::BEFORE);
+}
+
+void Debugger::handleExecutable(InterpreterImpl* impl,
+ const XERCESC_NS::DOMElement* execContentElem,
+ Breakpoint::When when) {
+ std::shared_ptr<DebugSession> session = getSession(impl);
+ if (!session)
+ return;
+ if (!session->_isRunning)
+ return;
+
+ std::list<Breakpoint> breakpoints;
+
+ Breakpoint breakpoint;
+ breakpoint.when = when;
+ breakpoint.element = execContentElem;
+ breakpoint.executableName = X(execContentElem->getLocalName()).str();
+ breakpoint.subject = Breakpoint::EXECUTABLE;
+ breakpoints.push_back(breakpoint);
+
+ session->checkBreakpoints(breakpoints);
+
+}
+
+void Debugger::handleEvent(InterpreterImpl* impl, const Event& event, Breakpoint::When when) {
+ std::shared_ptr<DebugSession> session = getSession(impl);
+ if (!session)
+ return;
+ if (!session->_isRunning)
+ return;
+
+ std::list<Breakpoint> breakpoints;
+
+ Breakpoint breakpoint;
+ breakpoint.when = when;
+ breakpoint.eventName = event.name;
+ breakpoint.subject = Breakpoint::EVENT;
+ breakpoints.push_back(breakpoint);
+
+ session->checkBreakpoints(breakpoints);
+
+}
+
+void Debugger::handleStable(InterpreterImpl* impl, Breakpoint::When when) {
+ std::shared_ptr<DebugSession> session = getSession(impl);
+ if (!session)
+ return;
+ if (!session->_isRunning)
+ return;
+
+ std::list<Breakpoint> breakpoints;
+
+ Breakpoint breakpoint;
+ breakpoint.when = when;
+ breakpoint.subject = Breakpoint::STABLE;
+ breakpoints.push_back(breakpoint);
+
+ session->checkBreakpoints(breakpoints);
+}
+
+void Debugger::handleMicrostep(InterpreterImpl* impl, Breakpoint::When when) {
+ std::shared_ptr<DebugSession> session = getSession(impl);
+ if (!session)
+ return;
+ if (!session->_isRunning)
+ return;
+
+ std::list<Breakpoint> breakpoints;
+
+ Breakpoint breakpoint;
+ breakpoint.when = when;
+ breakpoint.subject = Breakpoint::MICROSTEP;
+ breakpoints.push_back(breakpoint);
+
+ session->checkBreakpoints(breakpoints);
+}
+
+void Debugger::handleTransition(InterpreterImpl* impl, const XERCESC_NS::DOMElement* transition, Breakpoint::When when) {
+ std::shared_ptr<DebugSession> session = getSession(impl);
+ if (!session)
+ return;
+ if (!session->_isRunning)
+ return;
+
+ Breakpoint breakpointTemplate;
+ breakpointTemplate.when = when;
+ std::list<Breakpoint> qualifiedBreakpoints = getQualifiedTransBreakpoints(impl, transition, breakpointTemplate);
+ session->checkBreakpoints(qualifiedBreakpoints);
+}
+
+void Debugger::handleState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state, Breakpoint::When when, Breakpoint::Action action) {
+ std::shared_ptr<DebugSession> session = getSession(impl);
+ if (!session)
+ return;
+ if (!session->_isRunning)
+ return;
+
+ Breakpoint breakpointTemplate;
+ breakpointTemplate.when = when;
+ breakpointTemplate.action = action;
+ std::list<Breakpoint> qualifiedBreakpoints = getQualifiedStateBreakpoints(impl, state, breakpointTemplate);
+ session->checkBreakpoints(qualifiedBreakpoints);
+
+}
+
+void Debugger::handleInvoke(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeId, Breakpoint::When when, Breakpoint::Action action) {
+ std::shared_ptr<DebugSession> session = getSession(impl);
+ if (!session)
+ return;
+ if (!session->_isRunning)
+ return;
+
+ Breakpoint breakpointTemplate;
+ breakpointTemplate.when = when;
+ breakpointTemplate.action = action;
+ std::list<Breakpoint> qualifiedBreakpoints = getQualifiedInvokeBreakpoints(impl, invokeElem, invokeId, breakpointTemplate);
+ session->checkBreakpoints(qualifiedBreakpoints);
+
+}
+
+
+} \ No newline at end of file
diff --git a/src/uscxml/debug/Debugger.h b/src/uscxml/debug/Debugger.h
new file mode 100644
index 0000000..08136d6
--- /dev/null
+++ b/src/uscxml/debug/Debugger.h
@@ -0,0 +1,116 @@
+/**
+ * @file
+ * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#ifndef DEBUGGERMONITOR_H_Z050WPFH
+#define DEBUGGERMONITOR_H_Z050WPFH
+
+#include "uscxml/messages/Data.h" // for Data
+#include "uscxml/messages/Event.h" // for Event
+#include "uscxml/interpreter/InterpreterImpl.h"
+#include "uscxml/debug/Breakpoint.h"
+
+namespace uscxml {
+
+class DebugSession;
+
+class USCXML_API Debugger : public InterpreterMonitor {
+public:
+ Debugger() {
+ }
+ virtual ~Debugger() {}
+
+ virtual void attachSession(InterpreterImpl* impl, std::shared_ptr<DebugSession> session) {
+ std::lock_guard<std::recursive_mutex> lock(_sessionMutex);
+ _sessionForInterpreter[impl] = session;
+ }
+
+ virtual void detachSession(InterpreterImpl* impl) {
+ std::lock_guard<std::recursive_mutex> lock(_sessionMutex);
+ _sessionForInterpreter.erase(impl);
+ }
+
+ virtual std::shared_ptr<DebugSession> getSession(InterpreterImpl* impl) {
+ std::lock_guard<std::recursive_mutex> lock(_sessionMutex);
+ if (_sessionForInterpreter.find(impl) != _sessionForInterpreter.end())
+ return _sessionForInterpreter[impl];
+ return std::shared_ptr<DebugSession>();
+ }
+
+ virtual void pushData(std::shared_ptr<DebugSession> session, Data pushData) = 0;
+
+ // InterpreterMonitor
+ virtual void beforeProcessingEvent(InterpreterImpl* impl, const Event& event);
+ virtual void beforeMicroStep(InterpreterImpl* impl);
+ virtual void beforeExitingState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state);
+ virtual void afterExitingState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state);
+ virtual void beforeExecutingContent(InterpreterImpl* impl, const XERCESC_NS::DOMElement* execContent);
+ virtual void afterExecutingContent(InterpreterImpl* impl, const XERCESC_NS::DOMElement* execContent);
+ virtual void beforeUninvoking(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid);
+ virtual void afterUninvoking(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid);
+ virtual void beforeTakingTransition(InterpreterImpl* impl, const XERCESC_NS::DOMElement* transition);
+ virtual void afterTakingTransition(InterpreterImpl* impl, const XERCESC_NS::DOMElement* transition);
+ virtual void beforeEnteringState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state);
+ virtual void afterEnteringState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state);
+ virtual void beforeInvoking(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid);
+ virtual void afterInvoking(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid);
+ virtual void afterMicroStep(InterpreterImpl* impl);
+ virtual void onStableConfiguration(InterpreterImpl* impl);
+ virtual void beforeCompletion(InterpreterImpl* impl);
+ virtual void afterCompletion(InterpreterImpl* impl);
+
+protected:
+
+ void handleTransition(InterpreterImpl* impl,
+ const XERCESC_NS::DOMElement* transition,
+ Breakpoint::When when);
+ void handleState(InterpreterImpl* impl,
+ const XERCESC_NS::DOMElement* state,
+ Breakpoint::When when,
+ Breakpoint::Action action);
+ void handleInvoke(InterpreterImpl* impl,
+ const XERCESC_NS::DOMElement* invokeElem,
+ const std::string& invokeId,
+ Breakpoint::When when,
+ Breakpoint::Action action);
+ void handleExecutable(InterpreterImpl* impl,
+ const XERCESC_NS::DOMElement* execContentElem,
+ Breakpoint::When when);
+ void handleStable(InterpreterImpl* impl, Breakpoint::When when);
+ void handleMicrostep(InterpreterImpl* impl, Breakpoint::When when);
+ void handleEvent(InterpreterImpl* impl, const Event& event, Breakpoint::When when);
+
+ std::list<Breakpoint> getQualifiedTransBreakpoints(InterpreterImpl* impl,
+ const XERCESC_NS::DOMElement* transition,
+ Breakpoint breakpointTemplate);
+ std::list<Breakpoint> getQualifiedStateBreakpoints(InterpreterImpl* impl,
+ const XERCESC_NS::DOMElement* state,
+ Breakpoint breakpointTemplate);
+ std::list<Breakpoint> getQualifiedInvokeBreakpoints(InterpreterImpl* impl,
+ const XERCESC_NS::DOMElement* invokeElem,
+ const std::string invokeId,
+ Breakpoint breakpointTemplate);
+
+ std::recursive_mutex _sessionMutex;
+ std::map<InterpreterImpl*, std::shared_ptr<DebugSession> > _sessionForInterpreter;
+};
+
+}
+
+
+#endif /* end of include guard: DEBUGGERMONITOR_H_Z050WPFH */
diff --git a/src/uscxml/debug/DebuggerServlet.cpp b/src/uscxml/debug/DebuggerServlet.cpp
new file mode 100644
index 0000000..2b035a6
--- /dev/null
+++ b/src/uscxml/debug/DebuggerServlet.cpp
@@ -0,0 +1,261 @@
+/**
+ * @file
+ * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#include "uscxml/debug/DebuggerServlet.h"
+#include "uscxml/debug/DebugSession.h"
+#include "uscxml/util/UUID.h"
+#include <boost/algorithm/string.hpp>
+
+namespace uscxml {
+
+void DebuggerServlet::pushData(std::shared_ptr<DebugSession> session, Data pushData) {
+ std::cout << "trying to push " << pushData.at("replyType").atom << std::endl;
+
+ if (!session) {
+ if (_sendQueues.size() > 0) // logging is not aware of its interpreter
+ _sendQueues.begin()->second.push(pushData);
+ } else {
+ _sendQueues[session].push(pushData);
+ }
+
+ serverPushData(session);
+}
+
+void DebuggerServlet::serverPushData(std::shared_ptr<DebugSession> session) {
+ if (_sendQueues[session].isEmpty())
+ return;
+
+ if (!_clientConns[session])
+ return;
+
+ Data reply = _sendQueues[session].pop();
+ std::cout << "pushing " << reply.at("replyType").atom << std::endl;
+ returnData(_clientConns[session], reply);
+ _clientConns[session] = HTTPServer::Request();
+}
+
+void DebuggerServlet::returnData(const HTTPServer::Request& request, Data replyData) {
+ HTTPServer::Reply reply(request);
+
+ if (!replyData.hasKey("status")) {
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ }
+
+ std::cout << "<- " << replyData << std::endl;
+
+ reply.content = Data::toJSON(replyData);
+ reply.headers["Access-Control-Allow-Origin"] = "*";
+ reply.headers["Content-Type"] = "application/json";
+ HTTPServer::reply(reply);
+}
+
+bool DebuggerServlet::isCORS(const HTTPServer::Request& request) {
+ return (request.data.at("type").atom == "options" &&
+ request.data.at("header").hasKey("Origin") &&
+ request.data.at("header").hasKey("Access-Control-Request-Method"));
+}
+
+void DebuggerServlet::handleCORS(const HTTPServer::Request& request) {
+ HTTPServer::Reply corsReply(request);
+ if (request.data.at("header").hasKey("Origin")) {
+ corsReply.headers["Access-Control-Allow-Origin"] = request.data.at("header").at("Origin").atom;
+ } else {
+ corsReply.headers["Access-Control-Allow-Origin"] = "*";
+ }
+ if (request.data.at("header").hasKey("Access-Control-Request-Method"))
+ corsReply.headers["Access-Control-Allow-Methods"] = request.data.at("header").at("Access-Control-Request-Method").atom;
+ if (request.data.at("header").hasKey("Access-Control-Request-Headers"))
+ corsReply.headers["Access-Control-Allow-Headers"] = request.data.at("header").at("Access-Control-Request-Headers").atom;
+
+ // std::cout << "CORS!" << std::endl << request << std::endl;
+ HTTPServer::reply(corsReply);
+}
+
+bool DebuggerServlet::httpRecvRequest(const HTTPServer::Request& request) {
+ if (!request.data.hasKey("path"))
+ return false; // returnError(request);
+
+ if (isCORS(request)) {
+ handleCORS(request);
+ return true;
+ }
+
+ std::cout << request.data["path"] << ": " << request.data["content"] << std::endl;
+
+ Data replyData;
+ // process request that don't need a session
+ if (false) {
+ } else if (boost::istarts_with(request.data.at("path").atom, "/debug/connect")) {
+ processConnect(request);
+ return true;
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/sessions")) {
+ processListSessions(request);
+ return true;
+ }
+
+ // get session or return error
+ if (false) {
+ } else if (!request.data.at("content").hasKey("session")) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No session given", Data::VERBATIM);
+ } else if (_sessionForId.find(request.data.at("content").at("session").atom) == _sessionForId.end()) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No such session", Data::VERBATIM);
+ }
+ if (!replyData.empty()) {
+ returnData(request, replyData);
+ return true;
+ }
+
+ std::shared_ptr<DebugSession> session = _sessionForId[request.data.at("content").at("session").atom];
+
+ if (false) {
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/poll")) {
+ // save long-standing client poll
+ _clientConns[session] = request;
+ serverPushData(session);
+
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/disconnect")) {
+ processDisconnect(request);
+
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/enable/all")) {
+ replyData = session->enableAllBreakPoints();
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/disable/all")) {
+ replyData = session->disableAllBreakPoints();
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/skipto")) {
+ replyData = session->skipToBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/add")) {
+ replyData = session->addBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/remove")) {
+ replyData = session->removeBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/enable")) {
+ replyData = session->enableBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/breakpoint/disable")) {
+ replyData = session->disableBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/stop")) {
+ replyData = session->debugStop(request.data["content"]);
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/prepare")) {
+ replyData = session->debugPrepare(request.data["content"]);
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/attach")) {
+ replyData = session->debugAttach(request.data["content"]);
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/start")) {
+ replyData = session->debugStart(request.data["content"]);
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/step")) {
+ replyData = session->debugStep(request.data["content"]);
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/pause")) {
+ replyData = session->debugPause(request.data["content"]);
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/resume")) {
+ replyData = session->debugResume(request.data["content"]);
+ } else if (boost::starts_with(request.data.at("path").atom, "/debug/eval")) {
+ replyData = session->debugEval(request.data["content"]);
+ }
+
+ if (!replyData.empty()) {
+ returnData(request, replyData);
+ return true;
+ }
+
+ return true;
+}
+
+// someone connected, create a new session
+void DebuggerServlet::processConnect(const HTTPServer::Request& request) {
+ std::lock_guard<std::recursive_mutex> lock(_mutex);
+ std::string sessionId = UUID::getUUID();
+
+ _sessionForId[sessionId] = std::shared_ptr<DebugSession>(new DebugSession());
+ _sessionForId[sessionId]->setDebugger(this);
+
+ Data replyData;
+ replyData.compound["session"] = Data(sessionId, Data::VERBATIM);
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ returnData(request, replyData);
+}
+
+void DebuggerServlet::processDisconnect(const HTTPServer::Request& request) {
+ std::lock_guard<std::recursive_mutex> lock(_mutex);
+
+ Data replyData;
+
+ if (!request.data.at("content").hasKey("session")) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No session given", Data::VERBATIM);
+ returnData(request, replyData);
+ }
+
+ std::string sessionId = request.data.at("content").at("session").atom;
+
+ if (_sessionForId.find(sessionId) == _sessionForId.end()) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No such session", Data::VERBATIM);
+ } else {
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ detachSession(_sessionForId[sessionId]->getInterpreter().getImpl().get());
+ _sessionForId[sessionId]->debugStop(request.data["content"]);
+ _clientConns.erase(_sessionForId[sessionId]);
+ _sendQueues.erase(_sessionForId[sessionId]);
+ _sessionForId.erase(sessionId);
+ }
+
+ returnData(request, replyData);
+}
+
+void DebuggerServlet::processListSessions(const HTTPServer::Request& request) {
+ Data replyData;
+
+ std::map<std::string, std::weak_ptr<InterpreterImpl> > instances = InterpreterImpl::getInstances();
+ for (auto weakInstance : instances) {
+
+ std::shared_ptr<InterpreterImpl> instance = weakInstance.second.lock();
+ if (instance) {
+ Data sessionData;
+ sessionData.compound["name"] = Data(instance->getName(), Data::VERBATIM);
+ sessionData.compound["id"] = Data(instance->getSessionId(), Data::VERBATIM);
+ sessionData.compound["source"] = Data(instance->getBaseURL(), Data::VERBATIM);
+ sessionData.compound["xml"].node = instance->getDocument();
+
+ replyData.compound["sessions"].array.push_back(sessionData);
+ }
+ }
+
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ returnData(request, replyData);
+}
+
+/*
+void DebuggerServlet::send(google::LogSeverity severity, const char* full_filename,
+ const char* base_filename, int line,
+ const struct ::tm* tm_time,
+ const char* message, size_t message_len) {
+
+ // _sendQueue is thread-safe, not sure about ToString though
+
+ LogMessage msg(severity,
+ full_filename,
+ base_filename,
+ line,
+ tm_time,
+ std::string(message, message_len),
+ ToString(severity, base_filename, line, tm_time, message, message_len));
+ msg.compound["replyType"] = Data("log", Data::VERBATIM);
+ pushData(std::shared_ptr<DebugSession>(), msg);
+}
+*/
+
+} \ No newline at end of file
diff --git a/src/uscxml/debug/DebuggerServlet.h b/src/uscxml/debug/DebuggerServlet.h
new file mode 100644
index 0000000..dc6b0ee
--- /dev/null
+++ b/src/uscxml/debug/DebuggerServlet.h
@@ -0,0 +1,108 @@
+/**
+ * @file
+ * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#ifndef DEBUGGERSERVLET_H_ATUMDA3G
+#define DEBUGGERSERVLET_H_ATUMDA3G
+
+#include "uscxml/Common.h"
+#include <easylogging++.h>
+#include "uscxml/util/BlockingQueue.h"
+#include "uscxml/server/HTTPServer.h"
+
+#include "uscxml/debug/Debugger.h"
+
+namespace uscxml {
+
+class USCXML_API DebuggerServlet : public Debugger, public HTTPServlet {
+public:
+ class LogMessage : public Data {
+ public:
+#if 0
+ LogMessage(google::LogSeverity severity, const char* full_filename,
+ const char* base_filename, int line,
+ const struct ::tm* tm_time,
+ std::string message, std::string formatted) {
+
+ compound["severity"] = severity;
+ compound["fullFilename"] = Data(full_filename, Data::VERBATIM);
+ compound["baseFilename"] = Data(base_filename, Data::VERBATIM);
+ compound["line"] = line;
+ compound["message"] = Data(message, Data::VERBATIM);
+ compound["time"] = Data(mktime((struct ::tm*)tm_time), Data::INTERPRETED);
+ compound["formatted"] = Data(formatted, Data::VERBATIM);
+ }
+#endif
+ };
+
+ virtual ~DebuggerServlet() {}
+
+ // from Debugger
+ virtual void addBreakpoint(const Breakpoint& breakpoint) {};
+
+ bool isCORS(const HTTPServer::Request& request);
+ void handleCORS(const HTTPServer::Request& request);
+
+ bool httpRecvRequest(const HTTPServer::Request& request);
+ void setURL(const std::string& url) {
+ _url = url;
+ }
+
+ void pushData(std::shared_ptr<DebugSession> session, Data pushData);
+ void returnData(const HTTPServer::Request& request, Data replyData);
+
+ void processDisconnect(const HTTPServer::Request& request);
+ void processConnect(const HTTPServer::Request& request);
+ void processListSessions(const HTTPServer::Request& request);
+
+// void processDebugPrepare(const HTTPServer::Request& request);
+// void processDebugAttach(const HTTPServer::Request& request);
+// void processDebugStart(const HTTPServer::Request& request);
+// void processDebugStop(const HTTPServer::Request& request);
+
+// void processDebugEval(const HTTPServer::Request& request);
+// void processDebugStart(const HTTPServer::Request& request);
+// void processDebugStop(const HTTPServer::Request& request);
+// void processDebugStep(const HTTPServer::Request& request);
+// void processDebugResume(const HTTPServer::Request& request);
+// void processDebugPause(const HTTPServer::Request& request);
+// void processAddBreakPoint(const HTTPServer::Request& request);
+// void processRemoveBreakPoint(const HTTPServer::Request& request);
+// void processPoll(const HTTPServer::Request& request);
+
+ // Logsink
+ /**
+ virtual void send(google::LogSeverity severity, const char* full_filename,
+ const char* base_filename, int line,
+ const struct ::tm* tm_time,
+ const char* message, size_t message_len);
+*/
+protected:
+ void serverPushData(std::shared_ptr<DebugSession>);
+
+ std::string _url;
+ std::map<std::shared_ptr<DebugSession>, HTTPServer::Request> _clientConns;
+ std::map<std::shared_ptr<DebugSession>, BlockingQueue<Data> > _sendQueues;
+ std::map<std::string, std::shared_ptr<DebugSession> > _sessionForId;
+
+ std::recursive_mutex _mutex;
+};
+
+}
+
+#endif /* end of include guard: DEBUGGERSERVLET_H_ATUMDA3G */
diff --git a/src/uscxml/interpreter/BasicContentExecutor.cpp b/src/uscxml/interpreter/BasicContentExecutor.cpp
index 58d3eae..0f5a67f 100644
--- a/src/uscxml/interpreter/BasicContentExecutor.cpp
+++ b/src/uscxml/interpreter/BasicContentExecutor.cpp
@@ -330,7 +330,7 @@ void BasicContentExecutor::process(XERCESC_NS::DOMElement* block, const X& xmlPr
}
try {
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(), beforeExecutingContent, block);
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(), beforeExecutingContent, block);
if (false) {
} else if (iequals(tagName, xmlPrefix.str() + "raise")) {
@@ -358,12 +358,12 @@ void BasicContentExecutor::process(XERCESC_NS::DOMElement* block, const X& xmlPr
Event e(exc);
_callbacks->enqueueInternal(e);
LOG(ERROR) << exc << std::endl;
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(), afterExecutingContent, block);
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(), afterExecutingContent, block);
throw e; // will be catched in microstepper
}
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(), afterExecutingContent, block);
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(), afterExecutingContent, block);
}
@@ -463,18 +463,18 @@ void BasicContentExecutor::invoke(XERCESC_NS::DOMElement* element) {
finalize = finalizes.front();
}
- USCXML_MONITOR_CALLBACK2(_callbacks->getMonitor(), beforeUninvoking, element, invokeEvent.invokeid);
+ USCXML_MONITOR_CALLBACK2(_callbacks->getMonitors(), beforeUninvoking, element, invokeEvent.invokeid);
_callbacks->invoke(type, source, autoForward, finalize, invokeEvent);
- USCXML_MONITOR_CALLBACK2(_callbacks->getMonitor(), afterUninvoking, element, invokeEvent.invokeid);
+ USCXML_MONITOR_CALLBACK2(_callbacks->getMonitors(), afterUninvoking, element, invokeEvent.invokeid);
}
void BasicContentExecutor::uninvoke(XERCESC_NS::DOMElement* invoke) {
char* invokeId = (char*)invoke->getUserData(X("invokeid"));
assert(invokeId != NULL);
- USCXML_MONITOR_CALLBACK2(_callbacks->getMonitor(), beforeUninvoking, invoke, invokeId);
+ USCXML_MONITOR_CALLBACK2(_callbacks->getMonitors(), beforeUninvoking, invoke, invokeId);
_callbacks->uninvoke(invokeId);
- USCXML_MONITOR_CALLBACK2(_callbacks->getMonitor(), afterUninvoking, invoke, invokeId);
+ USCXML_MONITOR_CALLBACK2(_callbacks->getMonitors(), afterUninvoking, invoke, invokeId);
invoke->setUserData(X("invokeid"), NULL, NULL);
free(invokeId);
diff --git a/src/uscxml/interpreter/BasicEventQueue.cpp b/src/uscxml/interpreter/BasicEventQueue.cpp
index 7505f46..3cf4daf 100644
--- a/src/uscxml/interpreter/BasicEventQueue.cpp
+++ b/src/uscxml/interpreter/BasicEventQueue.cpp
@@ -37,24 +37,10 @@ Event BasicEventQueue::dequeue(size_t blockMs) {
if (blockMs > 0) {
// block for given milliseconds or until queue is filled
- std::chrono::time_point<std::chrono::system_clock> updated, now;
- std::chrono::milliseconds remain;
+ auto endTime = std::chrono::system_clock::now() + std::chrono::milliseconds(blockMs);
- if (blockMs > (std::chrono::system_clock::duration::max)().count()) {
- blockMs = (std::chrono::system_clock::duration::max)().count();
- }
-
- updated = now = std::chrono::system_clock::now();
- remain = std::chrono::milliseconds(blockMs);
-
- while (remain.count() > 0 && _queue.empty()) {
- _cond.wait_for(_mutex, remain);
-
- now = std::chrono::system_clock::now();
-
- auto elapsed = now - updated;
- remain -= std::chrono::duration_cast<std::chrono::milliseconds>(elapsed);
- updated = now;
+ while (_queue.empty()) {
+ _cond.wait_until(_mutex, endTime);
}
}
diff --git a/src/uscxml/interpreter/ContentExecutorImpl.h b/src/uscxml/interpreter/ContentExecutorImpl.h
index e1a7e8c..0e12aff 100644
--- a/src/uscxml/interpreter/ContentExecutorImpl.h
+++ b/src/uscxml/interpreter/ContentExecutorImpl.h
@@ -65,7 +65,7 @@ public:
virtual const Event& getCurrentEvent() = 0;
/** Monitoring */
- virtual InterpreterMonitor* getMonitor() = 0;
+ virtual std::set<InterpreterMonitor*> getMonitors() = 0;
};
diff --git a/src/uscxml/interpreter/FastMicroStep.cpp b/src/uscxml/interpreter/FastMicroStep.cpp
index ea43c5d..826df93 100644
--- a/src/uscxml/interpreter/FastMicroStep.cpp
+++ b/src/uscxml/interpreter/FastMicroStep.cpp
@@ -89,68 +89,66 @@ FastMicroStep::~FastMicroStep() {
}
}
-void FastMicroStep::resortStates(DOMNode* node, const X& xmlPrefix) {
- if (node->getNodeType() != DOMNode::ELEMENT_NODE)
- return;
+void FastMicroStep::resortStates(DOMElement* element, const X& xmlPrefix) {
- /**
+ /**
initials
deep histories
shallow histories
everything else
*/
- DOMElement* element = dynamic_cast<DOMElement*>(node);
+ DOMElement* child = element->getFirstElementChild();
+ while(child) {
+ resortStates(child, xmlPrefix);
+ child = child->getNextElementSibling();
+ }
// shallow history states to top
- DOMNode* child = element->getFirstChild();
+ child = element->getFirstElementChild();
while(child) {
- resortStates(child, xmlPrefix);
- if (child->getNodeType() == DOMNode::ELEMENT_NODE &&
- TAGNAME_CAST(child) == xmlPrefix.str() + "history" &&
- (!HAS_ATTR(element, "type") || iequals(ATTR(element, "type"), "shallow"))) {
+ if (TAGNAME_CAST(child) == xmlPrefix.str() + "history" &&
+ (!HAS_ATTR(element, "type") || iequals(ATTR(element, "type"), "shallow"))) {
- DOMNode* tmp = child->getNextSibling();
+ DOMElement* tmp = child->getNextElementSibling();
if (child != element->getFirstChild()) {
element->insertBefore(child, element->getFirstChild());
}
child = tmp;
} else {
- child = child->getNextSibling();
+ child = child->getNextElementSibling();
}
}
// deep history states to top
- child = element->getFirstChild();
+ child = element->getFirstElementChild();
while(child) {
- resortStates(child, xmlPrefix);
if (child->getNodeType() == DOMNode::ELEMENT_NODE &&
TAGNAME_CAST(child) == xmlPrefix.str() + "history" &&
HAS_ATTR(element, "type") &&
iequals(ATTR(element, "type"), "deep")) {
- DOMNode* tmp = child->getNextSibling();
+ DOMElement* tmp = child->getNextElementSibling();
if (child != element->getFirstChild()) {
element->insertBefore(child, element->getFirstChild());
}
child = tmp;
} else {
- child = child->getNextSibling();
+ child = child->getNextElementSibling();
}
}
// initial states on top of histories even
- child = element->getFirstChild();
+ child = element->getFirstElementChild();
while(child) {
- resortStates(child, xmlPrefix);
if (child->getNodeType() == DOMNode::ELEMENT_NODE && LOCALNAME_CAST(child) == "initial") {
- DOMNode* tmp = child->getNextSibling();
+ DOMElement* tmp = child->getNextElementSibling();
if (child != element->getFirstChild()) {
element->insertBefore(child, element->getFirstChild());
}
child = tmp;
} else {
- child = child->getNextSibling();
+ child = child->getNextElementSibling();
}
}
}
@@ -193,10 +191,9 @@ void FastMicroStep::init(XERCESC_NS::DOMElement* scxml) {
}
resortStates(_scxml, _xmlPrefix);
-
- // TODO: https://github.com/tklab-tud/uscxml/blob/master/src/uscxml/transform/ChartToC.cpp#L244
-
-
+// assert(false);
+// throw NULL;
+
/** -- All things states -- */
std::list<XERCESC_NS::DOMElement*> tmp;
@@ -467,7 +464,7 @@ InterpreterState FastMicroStep::step(size_t blockMs) {
return USCXML_FINISHED;
if (_flags & USCXML_CTX_TOP_LEVEL_FINAL) {
- USCXML_MONITOR_CALLBACK(_callbacks->getMonitor(), beforeCompletion);
+ USCXML_MONITOR_CALLBACK(_callbacks->getMonitors(), beforeCompletion);
/* exit all remaining states */
i = USCXML_NUMBER_STATES;
@@ -498,7 +495,7 @@ InterpreterState FastMicroStep::step(size_t blockMs) {
_flags |= USCXML_CTX_FINISHED;
- USCXML_MONITOR_CALLBACK(_callbacks->getMonitor(), afterCompletion);
+ USCXML_MONITOR_CALLBACK(_callbacks->getMonitors(), afterCompletion);
return USCXML_FINISHED;
}
@@ -508,7 +505,7 @@ InterpreterState FastMicroStep::step(size_t blockMs) {
targetSet |= USCXML_GET_STATE(0).completion;
_flags |= USCXML_CTX_SPONTANEOUS | USCXML_CTX_INITIALIZED;
- USCXML_MONITOR_CALLBACK(_callbacks->getMonitor(), beforeMicroStep);
+ USCXML_MONITOR_CALLBACK(_callbacks->getMonitors(), beforeMicroStep);
goto ESTABLISH_ENTRYSET;
}
@@ -520,7 +517,7 @@ InterpreterState FastMicroStep::step(size_t blockMs) {
if ((_event = _callbacks->dequeueInternal())) {
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(), beforeProcessingEvent, _event);
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(), beforeProcessingEvent, _event);
goto SELECT_TRANSITIONS;
}
@@ -551,13 +548,13 @@ InterpreterState FastMicroStep::step(size_t blockMs) {
// we dequeued all internal events and ought to signal stable configuration
if (!(_flags & USCXML_CTX_STABLE)) {
- USCXML_MONITOR_CALLBACK(_callbacks->getMonitor(), onStableConfiguration);
+ USCXML_MONITOR_CALLBACK(_callbacks->getMonitors(), onStableConfiguration);
_microstepConfigurations.clear();
_flags |= USCXML_CTX_STABLE;
}
if ((_event = _callbacks->dequeueExternal(blockMs))) {
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(), beforeProcessingEvent, _event);
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(), beforeProcessingEvent, _event);
goto SELECT_TRANSITIONS;
}
@@ -629,7 +626,7 @@ SELECT_TRANSITIONS:
return USCXML_MACROSTEPPED;
}
- USCXML_MONITOR_CALLBACK(_callbacks->getMonitor(), beforeMicroStep);
+ USCXML_MONITOR_CALLBACK(_callbacks->getMonitors(), beforeMicroStep);
#ifdef USCXML_VERBOSE
std::cerr << "Targets: ";
@@ -793,7 +790,7 @@ ESTABLISH_ENTRYSET:
while(i-- > 0) {
if (BIT_HAS(i, exitSet) && BIT_HAS(i, _configuration)) {
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(), beforeExitingState, USCXML_GET_STATE(i).element);
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(), beforeExitingState, USCXML_GET_STATE(i).element);
/* call all on exit handlers */
for (auto exitIter = USCXML_GET_STATE(i).onExit.begin(); exitIter != USCXML_GET_STATE(i).onExit.end(); exitIter++) {
@@ -805,7 +802,7 @@ ESTABLISH_ENTRYSET:
}
BIT_CLEAR(i, _configuration);
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(), afterExitingState, USCXML_GET_STATE(i).element);
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(), afterExitingState, USCXML_GET_STATE(i).element);
}
}
@@ -814,7 +811,7 @@ ESTABLISH_ENTRYSET:
i = transSet.find_first();
while(i != boost::dynamic_bitset<>::npos) {
if ((USCXML_GET_TRANS(i).type & (USCXML_TRANS_HISTORY | USCXML_TRANS_INITIAL)) == 0) {
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(), beforeTakingTransition, USCXML_GET_TRANS(i).element);
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(), beforeTakingTransition, USCXML_GET_TRANS(i).element);
if (USCXML_GET_TRANS(i).onTrans != NULL) {
@@ -826,7 +823,7 @@ ESTABLISH_ENTRYSET:
}
}
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(), afterTakingTransition, USCXML_GET_TRANS(i).element);
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(), afterTakingTransition, USCXML_GET_TRANS(i).element);
}
i = transSet.find_next(i);
@@ -856,7 +853,7 @@ ESTABLISH_ENTRYSET:
continue;
}
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(), beforeEnteringState, USCXML_GET_STATE(i).element);
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(), beforeEnteringState, USCXML_GET_STATE(i).element);
BIT_SET_AT(i, _configuration);
@@ -877,7 +874,7 @@ ESTABLISH_ENTRYSET:
}
}
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(), afterEnteringState, USCXML_GET_STATE(i).element);
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(), afterEnteringState, USCXML_GET_STATE(i).element);
/* take history and initial transitions */
for (j = 0; j < USCXML_NUMBER_TRANS; j++) {
@@ -885,7 +882,7 @@ ESTABLISH_ENTRYSET:
(USCXML_GET_TRANS(j).type & (USCXML_TRANS_HISTORY | USCXML_TRANS_INITIAL)) &&
USCXML_GET_STATE(USCXML_GET_TRANS(j).source).parent == i) {
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(), beforeTakingTransition, USCXML_GET_TRANS(j).element);
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(), beforeTakingTransition, USCXML_GET_TRANS(j).element);
/* call executable content in transition */
if (USCXML_GET_TRANS(j).onTrans != NULL) {
@@ -896,7 +893,7 @@ ESTABLISH_ENTRYSET:
}
}
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(), afterTakingTransition, USCXML_GET_TRANS(j).element);
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(), afterTakingTransition, USCXML_GET_TRANS(j).element);
}
}
@@ -941,15 +938,17 @@ ESTABLISH_ENTRYSET:
}
}
}
- USCXML_MONITOR_CALLBACK(_callbacks->getMonitor(), afterMicroStep);
+ USCXML_MONITOR_CALLBACK(_callbacks->getMonitors(), afterMicroStep);
// are we running in circles?
if (_microstepConfigurations.find(_configuration) != _microstepConfigurations.end()) {
- USCXML_MONITOR_CALLBACK1(_callbacks->getMonitor(),
+ InterpreterIssue issue("Reentering same configuration during microstep - possible endless loop",
+ NULL,
+ InterpreterIssue::USCXML_ISSUE_WARNING);
+
+ USCXML_MONITOR_CALLBACK1(_callbacks->getMonitors(),
reportIssue,
- InterpreterIssue("Reentering same configuration during microstep - possible endless loop",
- NULL,
- InterpreterIssue::USCXML_ISSUE_WARNING));
+ issue);
}
_microstepConfigurations.insert(_configuration);
diff --git a/src/uscxml/interpreter/FastMicroStep.h b/src/uscxml/interpreter/FastMicroStep.h
index a3cdf9c..dd58480 100644
--- a/src/uscxml/interpreter/FastMicroStep.h
+++ b/src/uscxml/interpreter/FastMicroStep.h
@@ -125,7 +125,7 @@ protected:
private:
std::list<XERCESC_NS::DOMElement*> getHistoryCompletion(const XERCESC_NS::DOMElement* state);
- void resortStates(XERCESC_NS::DOMNode* node, const X& xmlPrefix);
+ void resortStates(XERCESC_NS::DOMElement* node, const X& xmlPrefix);
bool conflictsCached(const XERCESC_NS::DOMElement* t1, const XERCESC_NS::DOMElement* t2, const XERCESC_NS::DOMElement* root); ///< overrides implementation Predicates::conflicts for speed
diff --git a/src/uscxml/interpreter/InterpreterImpl.cpp b/src/uscxml/interpreter/InterpreterImpl.cpp
index 0547f12..5cbae3c 100644
--- a/src/uscxml/interpreter/InterpreterImpl.cpp
+++ b/src/uscxml/interpreter/InterpreterImpl.cpp
@@ -69,7 +69,7 @@ void InterpreterImpl::addInstance(std::shared_ptr<InterpreterImpl> interpreterIm
_instances[interpreterImpl->getSessionId()] = interpreterImpl;
}
-InterpreterImpl::InterpreterImpl() : _isInitialized(false), _document(NULL), _scxml(NULL), _state(USCXML_INSTANTIATED), _monitor(NULL) {
+InterpreterImpl::InterpreterImpl() : _isInitialized(false), _document(NULL), _scxml(NULL), _state(USCXML_INSTANTIATED) {
try {
::xercesc_3_1::XMLPlatformUtils::Initialize();
} catch (const XERCESC_NS::XMLException& toCatch) {
diff --git a/src/uscxml/interpreter/InterpreterImpl.h b/src/uscxml/interpreter/InterpreterImpl.h
index be33306..6d047ec 100644
--- a/src/uscxml/interpreter/InterpreterImpl.h
+++ b/src/uscxml/interpreter/InterpreterImpl.h
@@ -97,10 +97,14 @@ public:
return _microStepper.getConfiguration();
}
- void setMonitor(InterpreterMonitor* monitor) {
- _monitor = monitor;
+ void addMonitor(InterpreterMonitor* monitor) {
+ _monitors.insert(monitor);
}
+ void removeMonitor(InterpreterMonitor* monitor) {
+ _monitors.erase(monitor);
+ }
+
/**
MicrostepCallbacks
*/
@@ -132,8 +136,8 @@ public:
_execContent.uninvoke(invoke);
}
- virtual InterpreterMonitor* getMonitor() {
- return _monitor;
+ virtual std::set<InterpreterMonitor*> getMonitors() {
+ return _monitors;
}
/**
@@ -255,7 +259,9 @@ protected:
friend class InterpreterIssue;
friend class TransformerImpl;
friend class USCXMLInvoker;
- friend class SCXMLIOProcessor;
+ friend class SCXMLIOProcessor;
+ friend class DebugSession;
+ friend class Debugger;
X _xmlPrefix;
X _xmlNS;
@@ -280,7 +286,7 @@ protected:
std::map<std::string, IOProcessor> _ioProcs;
std::map<std::string, Invoker> _invokers;
std::set<std::string> _autoForwarders;
- InterpreterMonitor* _monitor;
+ std::set<InterpreterMonitor*> _monitors;
private:
void setupDOM();
diff --git a/src/uscxml/interpreter/InterpreterMonitor.h b/src/uscxml/interpreter/InterpreterMonitor.h
index 8dac445..ff2e7cb 100644
--- a/src/uscxml/interpreter/InterpreterMonitor.h
+++ b/src/uscxml/interpreter/InterpreterMonitor.h
@@ -33,14 +33,14 @@ catch (std::bad_weak_ptr e) { LOG(ERROR) << "Unclean shutdown " << std::endl; }
catch (...) { LOG(ERROR) << "An exception occurred when calling " #callback " on monitors"; } \
if (_state == USCXML_DESTROYED) { throw std::bad_weak_ptr(); }
-#define USCXML_MONITOR_CALLBACK(callback, function) \
-if (callback) { callback->function(); }
+#define USCXML_MONITOR_CALLBACK(callbacks, function) \
+for (auto callback : callbacks) { callback->function(NULL); }
-#define USCXML_MONITOR_CALLBACK1(callback, function, arg1) \
-if (callback) { callback->function(arg1); }
+#define USCXML_MONITOR_CALLBACK1(callbacks, function, arg1) \
+for (auto callback : callbacks) { callback->function(NULL, arg1); }
-#define USCXML_MONITOR_CALLBACK2(callback, function, arg1, arg2) \
-if (callback) { callback->function(arg1, arg2); }
+#define USCXML_MONITOR_CALLBACK2(callbacks, function, arg1, arg2) \
+for (auto callback : callbacks) { callback->function(NULL, arg1, arg2); }
// forward declare
namespace XERCESC_NS {
@@ -54,34 +54,34 @@ public:
InterpreterMonitor() : _copyToInvokers(false) {}
virtual ~InterpreterMonitor() {}
- virtual void beforeProcessingEvent(const Event& event) {}
- virtual void beforeMicroStep() {}
+ virtual void beforeProcessingEvent(InterpreterImpl* impl, const Event& event) {}
+ virtual void beforeMicroStep(InterpreterImpl* impl) {}
- virtual void beforeExitingState(const XERCESC_NS::DOMElement* state) {}
- virtual void afterExitingState(const XERCESC_NS::DOMElement* state) {}
+ virtual void beforeExitingState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state) {}
+ virtual void afterExitingState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state) {}
- virtual void beforeExecutingContent(const XERCESC_NS::DOMElement* execContent) {}
- virtual void afterExecutingContent(const XERCESC_NS::DOMElement* execContent) {}
+ virtual void beforeExecutingContent(InterpreterImpl* impl, const XERCESC_NS::DOMElement* execContent) {}
+ virtual void afterExecutingContent(InterpreterImpl* impl, const XERCESC_NS::DOMElement* execContent) {}
- virtual void beforeUninvoking(const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {}
- virtual void afterUninvoking(const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {}
+ virtual void beforeUninvoking(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {}
+ virtual void afterUninvoking(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {}
- virtual void beforeTakingTransition(const XERCESC_NS::DOMElement* transition) {}
- virtual void afterTakingTransition(const XERCESC_NS::DOMElement* transition) {}
+ virtual void beforeTakingTransition(InterpreterImpl* impl, const XERCESC_NS::DOMElement* transition) {}
+ virtual void afterTakingTransition(InterpreterImpl* impl, const XERCESC_NS::DOMElement* transition) {}
- virtual void beforeEnteringState(const XERCESC_NS::DOMElement* state) {}
- virtual void afterEnteringState(const XERCESC_NS::DOMElement* state) {}
+ virtual void beforeEnteringState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state) {}
+ virtual void afterEnteringState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state) {}
- virtual void beforeInvoking(const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {}
- virtual void afterInvoking(const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {}
+ virtual void beforeInvoking(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {}
+ virtual void afterInvoking(InterpreterImpl* impl, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {}
- virtual void afterMicroStep() {}
- virtual void onStableConfiguration() {}
+ virtual void afterMicroStep(InterpreterImpl* impl) {}
+ virtual void onStableConfiguration(InterpreterImpl* impl) {}
- virtual void beforeCompletion() {}
- virtual void afterCompletion() {}
+ virtual void beforeCompletion(InterpreterImpl* impl) {}
+ virtual void afterCompletion(InterpreterImpl* impl) {}
- virtual void reportIssue(const InterpreterIssue& issue) {}
+ virtual void reportIssue(InterpreterImpl* impl, const InterpreterIssue& issue) {}
void copyToInvokers(bool copy) {
_copyToInvokers = copy;
@@ -101,13 +101,13 @@ public:
StateTransitionMonitor() {}
virtual ~StateTransitionMonitor() {}
- virtual void beforeTakingTransition(const XERCESC_NS::DOMElement* transition);
- virtual void beforeExecutingContent(const XERCESC_NS::DOMElement* element);
- virtual void onStableConfiguration();
- virtual void beforeProcessingEvent(const uscxml::Event& event);
- virtual void beforeExitingState(const XERCESC_NS::DOMElement* state);
- virtual void beforeEnteringState(const XERCESC_NS::DOMElement* state);
- virtual void beforeMicroStep();
+ virtual void beforeTakingTransition(InterpreterImpl* impl, const XERCESC_NS::DOMElement* transition);
+ virtual void beforeExecutingContent(InterpreterImpl* impl, const XERCESC_NS::DOMElement* element);
+ virtual void onStableConfiguration(InterpreterImpl* impl);
+ virtual void beforeProcessingEvent(InterpreterImpl* impl, const uscxml::Event& event);
+ virtual void beforeExitingState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state);
+ virtual void beforeEnteringState(InterpreterImpl* impl, const XERCESC_NS::DOMElement* state);
+ virtual void beforeMicroStep(InterpreterImpl* impl);
protected:
static std::recursive_mutex _mutex;
diff --git a/src/uscxml/interpreter/MicroStepImpl.h b/src/uscxml/interpreter/MicroStepImpl.h
index be9d974..cb4aec6 100644
--- a/src/uscxml/interpreter/MicroStepImpl.h
+++ b/src/uscxml/interpreter/MicroStepImpl.h
@@ -23,6 +23,7 @@
#include "uscxml/config.h"
#include <list>
+#include <set>
#include <string>
#include <xercesc/dom/DOM.hpp>
@@ -33,6 +34,8 @@
namespace uscxml {
+class InterpreterMonitor;
+
/**
* @ingroup microstep
* @ingroup callback
@@ -57,7 +60,7 @@ public:
virtual void uninvoke(XERCESC_NS::DOMElement* invoke) = 0;
/** Monitoring */
- virtual InterpreterMonitor* getMonitor() = 0;
+ virtual std::set<InterpreterMonitor*> getMonitors() = 0;
};
/**
diff --git a/src/uscxml/util/BlockingQueue.h b/src/uscxml/util/BlockingQueue.h
new file mode 100644
index 0000000..2f0ab2e
--- /dev/null
+++ b/src/uscxml/util/BlockingQueue.h
@@ -0,0 +1,77 @@
+/**
+ * @file
+ * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#ifndef BLOCKINGQUEUE_H_4LEVMY0N
+#define BLOCKINGQUEUE_H_4LEVMY0N
+
+#include "uscxml/Common.h"
+#include <list>
+#include <condition_variable>
+
+namespace uscxml {
+
+template <class T>
+class BlockingQueue {
+public:
+ BlockingQueue() {}
+ virtual ~BlockingQueue() {
+ }
+
+ virtual void push(const T& elem) {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _queue.push_back(elem);
+ _cond.notify_all();
+ }
+
+ virtual void push_front(const T& elem) {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _queue.push_front(elem);
+ _cond.notify_all();
+ }
+
+ virtual T pop() {
+ std::lock_guard<std::mutex> lock(_mutex);
+// std::cout << "Popping from " << this << std::endl;
+ while (_queue.empty()) {
+ _cond.wait(_mutex);
+ }
+ T ret = _queue.front();
+ _queue.pop_front();
+ return ret;
+ }
+
+ virtual void clear() {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _queue.clear();
+ }
+
+ virtual bool isEmpty() {
+ std::lock_guard<std::mutex> lock(_mutex);
+ return _queue.empty();
+ }
+
+protected:
+ std::mutex _mutex;
+ std::condition_variable_any _cond;
+ std::list<T> _queue;
+};
+
+}
+
+#endif /* end of include guard: BLOCKINGQUEUE_H_4LEVMY0N */
diff --git a/src/uscxml/util/DOM.h b/src/uscxml/util/DOM.h
index 0b35f40..86fa813 100644
--- a/src/uscxml/util/DOM.h
+++ b/src/uscxml/util/DOM.h
@@ -127,17 +127,20 @@ class USCXML_API X {
public :
X(X const &other) {
+
_localForm = other._localForm;
_unicodeForm = XERCESC_NS::XMLString::replicate(other._unicodeForm);
_deallocOther = true;
}
void operator=(X const &other) { // did we maybe leak before?
+
_localForm = other._localForm;
_unicodeForm = XERCESC_NS::XMLString::replicate(other._unicodeForm);
_deallocOther = true;
}
X(const XMLCh* const toTranscode) {
+
if (toTranscode != NULL) {
// Call the private transcoding method
char* tmp = XERCESC_NS::XMLString::transcode(toTranscode);
@@ -149,6 +152,7 @@ public :
}
X(const std::string& fromTranscode) {
+
// Call the private transcoding method
_localForm = fromTranscode;
_unicodeForm = XERCESC_NS::XMLString::transcode(fromTranscode.c_str());
@@ -156,6 +160,7 @@ public :
}
X(const char* const fromTranscode) {
+
// Call the private transcoding method
_localForm = fromTranscode;
_unicodeForm = XERCESC_NS::XMLString::transcode(fromTranscode);
@@ -163,22 +168,25 @@ public :
}
X(char* fromTranscode) {
- // Call the private transcoding method
+
+ // Call the private transcoding method
_localForm = fromTranscode;
_unicodeForm = XERCESC_NS::XMLString::transcode(fromTranscode);
_deallocOther = true;
}
X() {
+
_unicodeForm = NULL;
_deallocOther = false;
}
~X() {
+
if (_deallocOther)
XERCESC_NS::XMLString::release(&_unicodeForm);
}
-
+
const std::string& str() const {
return _localForm;
}
@@ -195,7 +203,7 @@ public :
operator std::string () {
return _localForm;
}
-
+
protected:
friend USCXML_API std::ostream& operator<< (std::ostream& os, const X& data);
@@ -277,6 +285,32 @@ private:
};
#endif
+
+#if 0
+static const X kElementScxmlName = X("scxml");
+static const X kElementStateName = X("state");
+static const X kElementParallelName = X("parallel");
+static const X kElementTransitionName = X("transition");
+static const X kElementInitialName = X("initial");
+static const X kElementFinalName = X("final");
+static const X kElementOnEntryName = X("onentry");
+static const X kElementOnExitName = X("onexit");
+static const X kElementHistoryName = X("history");
+
+static const X kElementRaiseName = X("raise");
+static const X kElementIfName = X("if");
+static const X kElementElseIfName = X("elseif");
+static const X kElementElseName = X("else");
+static const X kElementForEachName = X("foreach");
+static const X kElementLogName = X("log");
+
+static const X kElementDataModelName = X("datamodel");
+static const X kElementDataName = X("data");
+static const X kElementAssignName = X("assign");
+static const X kElementContentName = X("content");
+static const X kElementParamName = X("param");
+static const X kElementScriptName = X("script");
+#endif
USCXML_API std::ostream& operator<< (std::ostream& os, const X& xmlString);
USCXML_API std::ostream& operator<< (std::ostream& os, const XERCESC_NS::DOMNode& node);