summaryrefslogtreecommitdiffstats
path: root/src/uscxml
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-03-07 13:03:04 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-03-07 13:03:04 (GMT)
commitca46aa711fb5d08a8fd1cc6b91593c281189e8e3 (patch)
treec46ed5fcbf44ea1a32517f8ba3d6d9a066b6fed8 /src/uscxml
parentfce16e70dff8503bfab2e734bca5a52d9057a3ee (diff)
downloaduscxml-ca46aa711fb5d08a8fd1cc6b91593c281189e8e3.zip
uscxml-ca46aa711fb5d08a8fd1cc6b91593c281189e8e3.tar.gz
uscxml-ca46aa711fb5d08a8fd1cc6b91593c281189e8e3.tar.bz2
Modified InterpreterMonitor for uscxml-debugger
Diffstat (limited to 'src/uscxml')
-rw-r--r--src/uscxml/Interpreter.cpp58
-rw-r--r--src/uscxml/Interpreter.h53
-rw-r--r--src/uscxml/Message.cpp23
-rw-r--r--src/uscxml/Message.h22
-rw-r--r--src/uscxml/URL.cpp2
-rw-r--r--src/uscxml/concurrency/BlockingQueue.h5
-rw-r--r--src/uscxml/debug/Breakpoint.cpp231
-rw-r--r--src/uscxml/debug/Breakpoint.h77
-rw-r--r--src/uscxml/debug/Debugger.cpp247
-rw-r--r--src/uscxml/debug/Debugger.h115
-rw-r--r--src/uscxml/debug/DebuggerServlet.cpp321
-rw-r--r--src/uscxml/debug/DebuggerServlet.h83
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.cpp16
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.h8
-rw-r--r--src/uscxml/interpreter/InterpreterDraft6.cpp443
-rw-r--r--src/uscxml/plugins/invoker/imap/IMAPInvoker.cpp81
-rw-r--r--src/uscxml/plugins/invoker/imap/IMAPInvoker.h40
-rw-r--r--src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp2
-rw-r--r--src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp2
19 files changed, 1486 insertions, 343 deletions
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index 6334065..2e867ba 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -258,6 +258,7 @@ InterpreterImpl::InterpreterImpl() {
_sendQueue = NULL;
_parentQueue = NULL;
_running = false;
+ _destroyed = false;
_done = true;
_isInitialized = false;
_httpServlet = NULL;
@@ -403,12 +404,18 @@ InterpreterImpl::~InterpreterImpl() {
_running = false;
// tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
if (_thread) {
- // unblock event queue
- Event event;
- event.name = "unblock.and.die";
- receive(event);
- _thread->join();
- delete(_thread);
+ if (_thread->get_id() != tthread::this_thread::get_id()) {
+ // unblock event queue
+ Event event;
+ event.name = "unblock.and.die";
+ receive(event);
+
+ _thread->join();
+ delete(_thread);
+ } else {
+ // this can happen with a shared_from_this at an interpretermonitor
+ _destroyed = true;
+ }
}
if (_sendQueue)
delete _sendQueue;
@@ -422,6 +429,11 @@ void InterpreterImpl::start() {
_thread = new tthread::thread(InterpreterImpl::run, this);
}
+void InterpreterImpl::stop() {
+ _running = false;
+}
+
+
void InterpreterImpl::run(void* instance) {
try {
((InterpreterImpl*)instance)->interpret();
@@ -1116,9 +1128,24 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node<std::string>& element) {
invoker.setType(invokeReq.type);
invoker.setInterpreter(this);
_invokers[invokeReq.invokeid] = invoker;
- LOG(INFO) << "Added invoker " << invokeReq.type << " at " << invokeReq.invokeid;
try {
+
+ // --- MONITOR: beforeInvoking ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->beforeInvoking(shared_from_this(), Element<std::string>(element), invokeReq.invokeid);
+ } USCXML_MONITOR_CATCH_BLOCK(beforeInvoking)
+ }
+
invoker.invoke(invokeReq);
+ LOG(INFO) << "Added invoker " << invokeReq.type << " at " << invokeReq.invokeid;
+
+ // --- MONITOR: afterInvoking ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->afterInvoking(shared_from_this(), Element<std::string>(element), invokeReq.invokeid);
+ } USCXML_MONITOR_CATCH_BLOCK(afterInvoking)
+ }
// this is out of draft but so useful to know when an invoker started
// Event invSuccess;
@@ -1166,9 +1193,24 @@ void InterpreterImpl::cancelInvoke(const Arabica::DOM::Node<std::string>& elemen
} catch (Event e) {
LOG(ERROR) << "Syntax when removing invoker:" << std::endl << e << std::endl;
}
-
}
+
+ // --- MONITOR: beforeUninvoking ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->beforeUninvoking(shared_from_this(), Element<std::string>(element), invokeId);
+ } USCXML_MONITOR_CATCH_BLOCK(beforeUninvoking)
+ }
+
_invokers.erase(invokeId);
+
+ // --- MONITOR: afterUninvoking ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->afterUninvoking(shared_from_this(), Element<std::string>(element), invokeId);
+ } USCXML_MONITOR_CATCH_BLOCK(beforeUninvoking)
+ }
+
} else {
LOG(ERROR) << "Cannot cancel invoke for id " << invokeId << ": no such invokation";
}
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
index d2e63e9..94c5d74 100644
--- a/src/uscxml/Interpreter.h
+++ b/src/uscxml/Interpreter.h
@@ -48,6 +48,18 @@
#include "uscxml/server/InterpreterServlet.h"
+#define USCXML_MONITOR_CATCH_BLOCK(callback)\
+catch (Event e) {\
+ LOG(ERROR) << "Syntax error when calling " #callback " on monitors: " << std::endl << e << std::endl;\
+} catch (boost::bad_weak_ptr e) {\
+ LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;\
+} catch (...) {\
+ LOG(ERROR) << "An exception occured when calling " #callback " on monitors";\
+}\
+if (_destroyed) {\
+ throw boost::bad_weak_ptr();\
+}
+
namespace uscxml {
class HTTPServletInvoker;
@@ -139,6 +151,7 @@ public:
virtual ~InterpreterImpl();
void start();
+ void stop();
static void run(void*);
void join() {
if (_thread != NULL) _thread->join();
@@ -288,6 +301,7 @@ public:
static std::list<std::string> tokenizeIdRefs(const std::string& idRefs);
static std::string spaceNormalize(const std::string& text);
+ static bool nameMatch(const std::string& transitionEvent, const std::string& event);
bool isInEmbeddedDocument(const Arabica::DOM::Node<std::string>& node);
bool isInitial(const Arabica::DOM::Node<std::string>& state);
@@ -337,6 +351,7 @@ protected:
bool _running;
bool _done;
+ bool _destroyed; // see comment in destructor
bool _isInitialized;
InterpreterImpl::Binding _binding;
Arabica::XPath::NodeSet<std::string> _configuration;
@@ -381,7 +396,6 @@ protected:
void internalDoneSend(const Arabica::DOM::Node<std::string>& state);
static void delayedSend(void* userdata, std::string eventName);
- static bool nameMatch(const std::string& transitionEvent, const std::string& event);
bool hasConditionMatch(const Arabica::DOM::Node<std::string>& conditional);
bool isInFinalState(const Arabica::DOM::Node<std::string>& state);
bool parentIsScxmlState(const Arabica::DOM::Node<std::string>& state);
@@ -417,7 +431,7 @@ public:
static Interpreter fromURI(const std::string& uri);
static Interpreter fromInputSource(Arabica::SAX::InputSource<std::string>& source);
- Interpreter() : _impl() {}
+ Interpreter() : _impl() {} // the empty, invalid interpreter
Interpreter(boost::shared_ptr<InterpreterImpl> const impl) : _impl(impl) { }
Interpreter(const Interpreter& other) : _impl(other._impl) { }
virtual ~Interpreter() {};
@@ -442,6 +456,9 @@ public:
void start() {
return _impl->start();
}
+ void stop() {
+ return _impl->stop();
+ }
void join() {
return _impl->join();
};
@@ -685,15 +702,35 @@ protected:
class USCXML_API InterpreterMonitor {
public:
virtual ~InterpreterMonitor() {}
+
+ virtual void beforeProcessingEvent(Interpreter interpreter, const Event& event) {}
+ virtual void beforeMicroStep(Interpreter interpreter) {}
+
+ virtual void beforeExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state) {}
+ virtual void afterExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state) {}
+
+ virtual void beforeUninvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) {}
+ virtual void afterUninvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) {}
+
+ virtual void beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition) {}
+ virtual void afterTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition) {}
+
+ virtual void beforeEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state) {}
+ virtual void afterEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state) {}
+
+ virtual void beforeInvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) {}
+ virtual void afterInvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) {}
+
+ virtual void afterMicroStep(Interpreter interpreter) {}
+
+ virtual void beforeExecutingContent(Interpreter interpreter, const Arabica::DOM::Element<std::string>& element) {}
+ virtual void afterExecutingContent(Interpreter interpreter, const Arabica::DOM::Element<std::string>& element) {}
+
virtual void onStableConfiguration(Interpreter interpreter) {}
+
virtual void beforeCompletion(Interpreter interpreter) {}
virtual void afterCompletion(Interpreter interpreter) {}
- virtual void beforeMicroStep(Interpreter interpreter) {}
- virtual void beforeTakingTransitions(Interpreter interpreter, const Arabica::XPath::NodeSet<std::string>& transitions) {}
- virtual void beforeEnteringStates(Interpreter interpreter, const Arabica::XPath::NodeSet<std::string>& statesToEnter) {}
- virtual void afterEnteringStates(Interpreter interpreter) {}
- virtual void beforeExitingStates(Interpreter interpreter, const Arabica::XPath::NodeSet<std::string>& statesToExit) {}
- virtual void afterExitingStates(Interpreter interpreter) {}
+
};
}
diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp
index e8ae98c..aeb0027 100644
--- a/src/uscxml/Message.cpp
+++ b/src/uscxml/Message.cpp
@@ -721,27 +721,38 @@ std::string Data::toJSON(const Data& data) {
}
os << "]";
} else if (data.atom.size() > 0) {
+ // empty string is handled below
if (data.type == Data::VERBATIM) {
os << "\"";
for (int i = 0; i < data.atom.size(); i++) {
// escape string
- if (data.atom[i] == '"') {
+ if (false) {
+ } else if (data.atom[i] == '"') {
os << '\\';
+ os << data.atom[i];
+ } else if (data.atom[i] == '\n') {
+ os << "\\n";
+ } else {
+ os << data.atom[i];
}
- os << data.atom[i];
}
os << "\"";
} else {
os << data.atom;
}
} else if (data.node) {
+ std::ostringstream xmlSerSS;
+ xmlSerSS << data.node;
+ std::string xmlSer = xmlSerSS.str();
+ boost::replace_all(xmlSer, "\"", "\\\"");
+ boost::replace_all(xmlSer, "\n", "\\n");
+ os << "\"" << xmlSer << "\"";
+ } else {
if (data.type == Data::VERBATIM) {
- os << "";
+ os << "\"\""; // empty string
} else {
- os << data.atom;
+ os << "null";
}
- } else {
- os << "undefined";
}
return os.str();
}
diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h
index bdb9498..f61cd1d 100644
--- a/src/uscxml/Message.h
+++ b/src/uscxml/Message.h
@@ -71,8 +71,19 @@ public:
};
Data() : type(INTERPRETED) {}
+
+ // TODO: default INTERPRETED is unfortunate
Data(const std::string& atom_, Type type_ = INTERPRETED) : atom(atom_), type(type_) {}
Data(const char* data, size_t size, const std::string& mimeType, bool adopt = false);
+
+ // convenience constructors
+ Data(short atom_) : atom(toStr(atom_)), type(INTERPRETED) {}
+ Data(int atom_) : atom(toStr(atom_)), type(INTERPRETED) {}
+ Data(unsigned int atom_) : atom(toStr(atom_)), type(INTERPRETED) {}
+ Data(long atom_) : atom(toStr(atom_)), type(INTERPRETED) {}
+ Data(unsigned long atom_) : atom(toStr(atom_)), type(INTERPRETED) {}
+ Data(float atom_) : atom(toStr(atom_)), type(INTERPRETED) {}
+ Data(double atom_) : atom(toStr(atom_)), type(INTERPRETED) {}
Data(bool atom_) : type(INTERPRETED) {
if (atom_) {
atom = "true";
@@ -80,9 +91,18 @@ public:
atom = "false";
}
}
- template <typename T> Data(T value) : atom(toStr(value)), type(INTERPRETED) {}
+
template <typename T> Data(T value, Type type_) : atom(toStr(value)), type(type_) {}
+#if 0
+ // constructor for arbitrary types, skip if type is subclass though (C++11)
+ // we will have to drop this constructor as it interferes with operator Data() and entails C++11
+ template <typename T>
+ Data(T value, typename std::enable_if<! std::is_base_of<Data, T>::value>::type* = nullptr)
+ : atom(toStr(value)), type(INTERPRETED) {}
+#endif
+
+
explicit Data(const Arabica::DOM::Node<std::string>& dom);
virtual ~Data() {}
diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp
index 1ed99c3..1ba8404 100644
--- a/src/uscxml/URL.cpp
+++ b/src/uscxml/URL.cpp
@@ -176,7 +176,7 @@ URLImpl::operator Data() const {
data.compound["scheme"] = Data(_uri.scheme(), Data::VERBATIM);
data.compound["path"] = Data(_uri.path(), Data::VERBATIM);
data.compound["port"] = Data(_uri.port());
- data.compound["isAbsolute"] = Data(_uri.is_absolute() ? "true" : "false");
+ data.compound["isAbsolute"] = Data(_uri.is_absolute());
if (_statusCode.length() > 0)
data.compound["statusCode"] = Data(_statusCode, Data::VERBATIM);
if (_statusMsg.length() > 0)
diff --git a/src/uscxml/concurrency/BlockingQueue.h b/src/uscxml/concurrency/BlockingQueue.h
index a77bfb7..fc62fce 100644
--- a/src/uscxml/concurrency/BlockingQueue.h
+++ b/src/uscxml/concurrency/BlockingQueue.h
@@ -57,6 +57,11 @@ public:
return ret;
}
+ virtual void clear() {
+ tthread::lock_guard<tthread::mutex> lock(_mutex);
+ _queue.clear();
+ }
+
virtual bool isEmpty() {
tthread::lock_guard<tthread::mutex> lock(_mutex);
return _queue.empty();
diff --git a/src/uscxml/debug/Breakpoint.cpp b/src/uscxml/debug/Breakpoint.cpp
new file mode 100644
index 0000000..f64efad
--- /dev/null
+++ b/src/uscxml/debug/Breakpoint.cpp
@@ -0,0 +1,231 @@
+/**
+ * @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"
+
+namespace uscxml {
+
+Breakpoint::Breakpoint(const Data& data) {
+ subject = UNDEF_SUBJECT;
+ when = UNDEF_WHEN;
+ action = UNDEF_ACTION;
+
+ if (data.hasKey("when")) {
+ if (false) {
+ } else if (data["when"].atom == "before") {
+ when = BEFORE;
+ } else if (data["when"].atom == "after") {
+ when = AFTER;
+ } else if (data["when"].atom == "on") {
+ when = ON;
+ }
+ }
+
+ if (data.hasKey("action")) {
+ if (false) {
+ } else if (data["action"].atom == "enter") {
+ action = ENTER;
+ } else if (data["action"].atom == "exit") {
+ action = EXIT;
+ } else if (data["action"].atom == "invoke") {
+ action = INVOKE;
+ } else if (data["action"].atom == "cancel") {
+ action = UNINVOKE;
+ }
+ }
+
+ if (data.hasKey("subject")) {
+ if (false) {
+ } else if (data["subject"].atom == "state") {
+ subject = STATE;
+ } else if (data["subject"].atom == "transition") {
+ subject = TRANSITION;
+ } else if (data["subject"].atom == "stable") {
+ subject = STABLE;
+ } else if (data["subject"].atom == "microstep") {
+ subject = MICROSTEP;
+ } else if (data["subject"].atom == "event") {
+ subject = EVENT;
+ } else if (data["subject"].atom == "invoker") {
+ subject = INVOKER;
+ } else if (data["subject"].atom == "exec") {
+ subject = EXECUTABLE;
+ }
+ }
+
+ if (data.hasKey("condition"))
+ condition = data["condition"].atom;
+
+ if (data.hasKey("invokeId"))
+ invokeId = data["invokeId"].atom;
+
+ if (data.hasKey("invokeType"))
+ invokeType = data["invokeType"].atom;
+
+ if (data.hasKey("eventName"))
+ eventName = data["eventName"].atom;
+
+ if (data.hasKey("stateId"))
+ stateId = data["stateId"].atom;
+
+ if (data.hasKey("transSource"))
+ transSource = data["transSource"].atom;
+
+ if (data.hasKey("transTarget"))
+ transTarget = data["transTarget"].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("exec", 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 (stateId.length() > 0)
+ data.compound["stateId"] = Data(stateId, Data::VERBATIM);
+
+ if (transSource.length() > 0)
+ data.compound["transSource"] = Data(transSource, Data::VERBATIM);
+
+ if (transTarget.length() > 0)
+ data.compound["transTarget"] = Data(transTarget, Data::VERBATIM);
+
+ if (condition.length() > 0)
+ data.compound["condition"] = Data(condition, Data::VERBATIM);
+
+ return data;
+}
+
+bool Breakpoint::matches(const Breakpoint& other) const {
+ // would we match the given breakpoint?
+
+ if (subject != UNDEF_SUBJECT &&
+ other.subject != UNDEF_SUBJECT &&
+ other.subject != subject)
+ return false; // subject does not match
+
+ if (when != UNDEF_WHEN &&
+ other.when != UNDEF_WHEN &&
+ other.when != when)
+ return false; // time does not match
+
+ if (action != UNDEF_ACTION &&
+ other.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 && !InterpreterImpl::nameMatch(invokeId, other.invokeId)) {
+ return false;
+ }
+
+ if(invokeType.length() > 0 && !InterpreterImpl::nameMatch(invokeType, other.invokeType)) {
+ return false;
+ }
+
+ if(stateId.length() > 0 && !InterpreterImpl::nameMatch(stateId, other.stateId)) {
+ return false;
+ }
+
+ if(eventName.length() > 0 && !InterpreterImpl::nameMatch(eventName, other.eventName)) {
+ return false;
+ }
+
+ if(transSource.length() > 0 && !InterpreterImpl::nameMatch(transSource, other.transSource)) {
+ return false;
+ }
+
+ if(transTarget.length() > 0 && !InterpreterImpl::nameMatch(transTarget, other.transTarget)) {
+ return false;
+ }
+
+ return true;
+}
+
+
+bool Breakpoint::isValid() {
+ 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..b2861d8
--- /dev/null
+++ b/src/uscxml/debug/Breakpoint.h
@@ -0,0 +1,77 @@
+/**
+ * @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 "uscxml/Message.h"
+
+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() {}
+ Breakpoint(const Data& data);
+
+ // would we match the given breakpoint as well?
+ bool matches(const Breakpoint& other) const;
+
+ bool isValid();
+
+ Data toData() const;
+
+ bool operator<(const Breakpoint& other) const {
+ return (origData < other.origData);
+ }
+
+ When when;
+ Subject subject;
+ Action action;
+
+ std::string invokeId;
+ std::string invokeType;
+
+ std::string eventName;
+
+ std::string stateId;
+ std::string transSource;
+ std::string transTarget;
+
+ std::string condition;
+ Data origData;
+};
+
+}
+
+
+
+#endif /* end of include guard: BREAKPOINT_H_VR7K7T1X */
diff --git a/src/uscxml/debug/Debugger.cpp b/src/uscxml/debug/Debugger.cpp
new file mode 100644
index 0000000..aa97a22
--- /dev/null
+++ b/src/uscxml/debug/Debugger.cpp
@@ -0,0 +1,247 @@
+/**
+* @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/DOMUtils.h"
+
+namespace uscxml {
+
+void Debugger::afterCompletion(Interpreter interpreter) {
+ Data msg;
+ msg.compound["replyType"] = Data("finished", Data::VERBATIM);
+ pushData(msg);
+}
+
+std::list<Breakpoint> getQualifiedStateBreakpoints(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, Breakpoint breakpointTemplate) {
+ std::list<Breakpoint> breakpoints;
+
+ Breakpoint bp = breakpointTemplate; // copy base as template
+ bp.stateId = ATTR(state, "id");
+ bp.subject = Breakpoint::STATE;
+ breakpoints.push_back(bp);
+
+ return breakpoints;
+}
+
+std::list<Breakpoint> getQualifiedInvokeBreakpoints(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string invokeId, Breakpoint breakpointTemplate) {
+ std::list<Breakpoint> breakpoints;
+
+ Breakpoint bp = breakpointTemplate; // copy base as template
+ bp.subject = Breakpoint::INVOKER;
+ bp.invokeId = invokeId;
+
+ if (HAS_ATTR(invokeElem, "type")) {
+ bp.invokeType = ATTR(invokeElem, "type");
+ } else if (HAS_ATTR(invokeElem, "typeexpr")) {
+ bp.invokeType = interpreter.getDataModel().evalAsString(ATTR(invokeElem, "typeexpr"));
+ }
+
+ breakpoints.push_back(bp);
+
+ return breakpoints;
+}
+
+std::list<Breakpoint> getQualifiedTransBreakpoints(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, Breakpoint breakpointTemplate) {
+ std::list<Breakpoint> breakpoints;
+
+ Arabica::DOM::Element<std::string> source(interpreter.getSourceState(transition));
+ Arabica::XPath::NodeSet<std::string> targets = interpreter.getTargetStates(transition);
+
+ for (int j = 0; j < targets.size(); j++) {
+ Arabica::DOM::Element<std::string> target(targets[j]);
+
+ Breakpoint bp = breakpointTemplate; // copy base as template
+ bp.transSource = ATTR(source, "id");
+ bp.transTarget = ATTR(target, "id");
+ bp.subject = Breakpoint::TRANSITION;
+
+ breakpoints.push_back(bp);
+ }
+
+ return breakpoints;
+}
+
+void Debugger::beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition) {
+ handleTransition(interpreter, transition, Breakpoint::BEFORE);
+}
+void Debugger::afterTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition) {
+ handleTransition(interpreter, transition, Breakpoint::AFTER);
+}
+void Debugger::beforeExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state) {
+ handleState(interpreter, state, Breakpoint::BEFORE, Breakpoint::EXIT);
+}
+void Debugger::afterExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state) {
+ handleState(interpreter, state, Breakpoint::AFTER, Breakpoint::EXIT);
+}
+void Debugger::beforeEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state) {
+ handleState(interpreter, state, Breakpoint::BEFORE, Breakpoint::ENTER);
+}
+void Debugger::afterEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state) {
+ handleState(interpreter, state, Breakpoint::AFTER, Breakpoint::ENTER);
+}
+void Debugger::beforeUninvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) {
+ handleInvoke(interpreter, invokeElem, invokeid, Breakpoint::BEFORE, Breakpoint::UNINVOKE);
+}
+void Debugger::afterUninvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) {
+ handleInvoke(interpreter, invokeElem, invokeid, Breakpoint::AFTER, Breakpoint::UNINVOKE);
+}
+void Debugger::beforeInvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) {
+ handleInvoke(interpreter, invokeElem, invokeid, Breakpoint::BEFORE, Breakpoint::INVOKE);
+}
+void Debugger::afterInvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid) {
+ handleInvoke(interpreter, invokeElem, invokeid, Breakpoint::AFTER, Breakpoint::INVOKE);
+}
+void Debugger::onStableConfiguration(Interpreter interpreter) {
+ handleStable(interpreter, Breakpoint::ON);
+}
+void Debugger::beforeMicroStep(Interpreter interpreter) {
+ handleMicrostep(interpreter, Breakpoint::BEFORE);
+}
+void Debugger::afterMicroStep(Interpreter interpreter) {
+ handleMicrostep(interpreter, Breakpoint::AFTER);
+}
+void Debugger::beforeProcessingEvent(Interpreter interpreter, const Event& event) {
+ handleEvent(interpreter, event, Breakpoint::BEFORE);
+}
+
+void Debugger::handleEvent(Interpreter interpreter, const Event& event, Breakpoint::When when) {
+ if (!interpreter.isRunning())
+ return;
+
+ std::list<Breakpoint> breakpoints;
+
+ Breakpoint breakpoint;
+ breakpoint.when = when;
+ breakpoint.eventName = event.name;
+ breakpoint.subject = Breakpoint::EVENT;
+ breakpoints.push_back(breakpoint);
+
+ checkBreakpoints(interpreter, breakpoints);
+
+}
+
+void Debugger::handleStable(Interpreter interpreter, Breakpoint::When when) {
+ if (!interpreter.isRunning())
+ return;
+
+ std::list<Breakpoint> breakpoints;
+
+ Breakpoint breakpoint;
+ breakpoint.when = when;
+ breakpoint.subject = Breakpoint::STABLE;
+ breakpoints.push_back(breakpoint);
+
+ checkBreakpoints(interpreter, breakpoints);
+}
+
+void Debugger::handleMicrostep(Interpreter interpreter, Breakpoint::When when) {
+ if (!interpreter.isRunning())
+ return;
+
+ std::list<Breakpoint> breakpoints;
+
+ Breakpoint breakpoint;
+ breakpoint.when = when;
+ breakpoint.subject = Breakpoint::MICROSTEP;
+ breakpoints.push_back(breakpoint);
+
+ checkBreakpoints(interpreter, breakpoints);
+}
+
+void Debugger::handleTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, Breakpoint::When when) {
+ if (!interpreter.isRunning())
+ return;
+
+ Breakpoint breakpointTemplate;
+ breakpointTemplate.when = when;
+ std::list<Breakpoint> qualifiedBreakpoints = getQualifiedTransBreakpoints(interpreter, transition, breakpointTemplate);
+ checkBreakpoints(interpreter, qualifiedBreakpoints);
+}
+
+void Debugger::handleState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, Breakpoint::When when, Breakpoint::Action action) {
+ if (!interpreter.isRunning())
+ return;
+
+ Breakpoint breakpointTemplate;
+ breakpointTemplate.when = when;
+ breakpointTemplate.action = action;
+ std::list<Breakpoint> qualifiedBreakpoints = getQualifiedStateBreakpoints(interpreter, state, breakpointTemplate);
+ checkBreakpoints(interpreter, qualifiedBreakpoints);
+
+}
+
+void Debugger::handleInvoke(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeId, Breakpoint::When when, Breakpoint::Action action) {
+ if (!interpreter.isRunning())
+ return;
+
+ Breakpoint breakpointTemplate;
+ breakpointTemplate.when = when;
+ breakpointTemplate.action = action;
+ std::list<Breakpoint> qualifiedBreakpoints = getQualifiedInvokeBreakpoints(interpreter, invokeElem, invokeId, breakpointTemplate);
+ checkBreakpoints(interpreter, qualifiedBreakpoints);
+
+}
+
+void Debugger::checkBreakpoints(Interpreter interpreter, const std::list<Breakpoint> qualifiedBreakpoints) {
+ std::list<Breakpoint>::const_iterator qualifiedBreakpointIter = qualifiedBreakpoints.begin();
+ while(qualifiedBreakpointIter != qualifiedBreakpoints.end()) {
+ const Breakpoint& qualifiedBreakpoint = *qualifiedBreakpointIter++;
+
+ // check if one of the user-supplied breakpoints match
+ bool userBreakpointMatched = false;
+ std::set<Breakpoint>::const_iterator breakpointIter = _breakPoints.begin();
+ while(breakpointIter != _breakPoints.end()) {
+ const Breakpoint& breakpoint = *breakpointIter++;
+ if (breakpoint.matches(qualifiedBreakpoint)) {
+ Data replyData;
+ replyData.compound["breakpoint"] = breakpoint.toData();
+ replyData.compound["qualified"] = qualifiedBreakpoint.toData();
+
+ userBreakpointMatched = true;
+ hitBreakpoint(interpreter, replyData);
+ }
+ }
+ if (_isStepping && !userBreakpointMatched) {
+ Data replyData;
+ replyData.compound["qualified"] = qualifiedBreakpoint.toData();
+ hitBreakpoint(interpreter, replyData);
+ }
+ }
+}
+
+void Debugger::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(msg);
+}
+
+
+} \ 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..dfc197d
--- /dev/null
+++ b/src/uscxml/debug/Debugger.h
@@ -0,0 +1,115 @@
+/**
+ * @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/Message.h"
+#include "uscxml/Interpreter.h"
+#include "uscxml/debug/Breakpoint.h"
+
+#include <glog/logging.h>
+
+namespace uscxml {
+
+class USCXML_API Debugger : public InterpreterMonitor, public google::LogSink {
+public:
+ Debugger() {
+ _isStepping = false;
+ }
+ virtual ~Debugger() {}
+
+ class LogMessage : public Data {
+ public:
+ 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);
+ }
+ };
+
+ virtual void pushData(Data pushData) = 0;
+ virtual void hitBreakpoint(const Interpreter& interpreter, Data data) = 0;
+
+ void stepping(bool enable) {
+ _isStepping = enable;
+ }
+
+ // InterpreterMonitor
+ virtual void beforeProcessingEvent(Interpreter interpreter, const Event& event);
+ virtual void beforeMicroStep(Interpreter interpreter);
+ virtual void beforeExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state);
+ virtual void afterExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state);
+ virtual void beforeUninvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid);
+ virtual void afterUninvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid);
+ virtual void beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition);
+ virtual void afterTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition);
+ virtual void beforeEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state);
+ virtual void afterEnteringState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state);
+ virtual void beforeInvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid);
+ virtual void afterInvoking(Interpreter interpreter, const Arabica::DOM::Element<std::string>& invokeElem, const std::string& invokeid);
+ virtual void afterMicroStep(Interpreter interpreter);
+ virtual void beforeExecutingContent(Interpreter interpreter, const Arabica::DOM::Element<std::string>& element) {}
+ virtual void afterExecutingContent(Interpreter interpreter, const Arabica::DOM::Element<std::string>& element) {}
+ virtual void onStableConfiguration(Interpreter interpreter);
+ virtual void beforeCompletion(Interpreter interpreter) {}
+ virtual void afterCompletion(Interpreter interpreter);
+
+ // 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 handleTransition(Interpreter interpreter,
+ const Arabica::DOM::Element<std::string>& transition,
+ Breakpoint::When when);
+ void handleState(Interpreter interpreter,
+ const Arabica::DOM::Element<std::string>& state,
+ Breakpoint::When when,
+ Breakpoint::Action action);
+ void handleInvoke(Interpreter interpreter,
+ const Arabica::DOM::Element<std::string>& invokeElem,
+ const std::string& invokeId,
+ Breakpoint::When when,
+ Breakpoint::Action action);
+ void handleStable(Interpreter interpreter, Breakpoint::When when);
+ void handleMicrostep(Interpreter interpreter, Breakpoint::When when);
+ void handleEvent(Interpreter interpreter, const Event& event, Breakpoint::When when);
+ void checkBreakpoints(Interpreter interpreter, const std::list<Breakpoint> qualifiedBreakpoints);
+
+ bool _isStepping;
+ std::set<Breakpoint> _breakPoints;
+
+};
+
+}
+
+
+#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..e179b8c
--- /dev/null
+++ b/src/uscxml/debug/DebuggerServlet.cpp
@@ -0,0 +1,321 @@
+/**
+ * @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/UUID.h"
+#include <boost/algorithm/string.hpp>
+
+namespace uscxml {
+
+void DebuggerServlet::pushData(Data pushData) {
+ std::cout << "trying to push " << pushData["replyType"].atom << std::endl;
+ _sendQueue.push(pushData);
+ serverPushData();
+}
+
+void DebuggerServlet::serverPushData() {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+
+ if (_sendQueue.isEmpty())
+ return;
+
+ if (!_clientConn)
+ return;
+
+ Data reply = _sendQueue.pop();
+ std::cout << "pushing " << reply["replyType"].atom << std::endl;
+ returnData(_clientConn, reply);
+ _clientConn = 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);
+ }
+
+ reply.content = Data::toJSON(replyData);
+ reply.headers["Access-Control-Allow-Origin"] = "*";
+ reply.headers["Content-Type"] = "application/json";
+ HTTPServer::reply(reply);
+}
+
+void DebuggerServlet::hitBreakpoint(const Interpreter& interpreter,
+ Data data) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+
+ data.compound["replyType"] = Data("breakpoint", Data::VERBATIM);
+ pushData(data);
+
+ _resumeCond.wait(_mutex);
+ tthread::this_thread::sleep_for(tthread::chrono::milliseconds(200));
+}
+
+bool DebuggerServlet::isCORS(const HTTPServer::Request& request) {
+ return (request.data["type"].atom == "options" &&
+ request.data["header"].hasKey("Origin") &&
+ request.data["header"].hasKey("Access-Control-Request-Method"));
+}
+
+void DebuggerServlet::handleCORS(const HTTPServer::Request& request) {
+ HTTPServer::Reply corsReply(request);
+ if (request.data["header"].hasKey("Origin")) {
+ corsReply.headers["Access-Control-Allow-Origin"] = request.data["header"]["Origin"].atom;
+ } else {
+ corsReply.headers["Access-Control-Allow-Origin"] = "*";
+ }
+ if (request.data["header"].hasKey("Access-Control-Request-Method"))
+ corsReply.headers["Access-Control-Allow-Methods"] = request.data["header"]["Access-Control-Request-Method"].atom;
+ if (request.data["header"].hasKey("Access-Control-Request-Headers"))
+ corsReply.headers["Access-Control-Allow-Headers"] = request.data["header"]["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;
+
+ if (false) {
+ } else if (boost::starts_with(request.data["path"].atom, "/poll")) {
+ processPoll(request);
+ } else if (boost::starts_with(request.data["path"].atom, "/connect")) {
+ processConnect(request);
+ } else if (boost::starts_with(request.data["path"].atom, "/disconnect")) {
+ processDisconnect(request);
+ } else if (boost::starts_with(request.data["path"].atom, "/sessions")) {
+ processListSessions(request);
+ } else if (boost::starts_with(request.data["path"].atom, "/breakpoint/add")) {
+ processAddBreakPoint(request);
+ } else if (boost::starts_with(request.data["path"].atom, "/breakpoint/remove")) {
+ processRemoveBreakPoint(request);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/prepare")) {
+ processDebugPrepare(request);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/start")) {
+ processDebugStart(request);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/stop")) {
+ processDebugStop(request);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/step")) {
+ processDebugStep(request);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/pause")) {
+ processDebugPause(request);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/resume")) {
+ processDebugResume(request);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/eval")) {
+ processDebugEval(request);
+ }
+
+ return true;
+}
+
+void DebuggerServlet::processPoll(const HTTPServer::Request& request) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+ _clientConn = request;
+ serverPushData();
+}
+
+void DebuggerServlet::processDebugPrepare(const HTTPServer::Request& request) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+
+// std::cout << "clearing all pushes" << std::endl;
+// _sendQueue.clear();
+
+ // this will call the destructor if _interpreter already is set
+ _resumeCond.notify_all();
+ _interpreter = Interpreter::fromXML(request.data["content"].atom);
+
+ Data replyData;
+ if (_interpreter) {
+ // register ourself as a monitor
+ _interpreter.addMonitor(this);
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ } else {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ }
+ returnData(request, replyData);
+}
+
+void DebuggerServlet::processDebugStart(const HTTPServer::Request& request) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+
+ Data replyData;
+ if (_interpreter) {
+ // register ourself as a monitor
+ _interpreter.start();
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ } else {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ }
+ returnData(request, replyData);
+}
+
+void DebuggerServlet::processDebugStop(const HTTPServer::Request& request) {
+// tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+
+ stepping(false);
+
+ Data replyData;
+ if (_interpreter) {
+ _interpreter.stop();
+ _resumeCond.notify_all(); // unblock breakpoints
+ _interpreter.join();
+ _interpreter = Interpreter(); // empty interpreter, calls destructor
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ } else {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("Interpreter already stopped", Data::VERBATIM);
+ }
+ returnData(request, replyData);
+}
+
+void DebuggerServlet::processDebugEval(const HTTPServer::Request& request) {
+ Data replyData;
+ if (!_interpreter) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No interpreter running", Data::VERBATIM);
+ } else if (!_interpreter.getDataModel()) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No datamodel available", Data::VERBATIM);
+ } else if (!request.data["content"].hasKey("expression")) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No expression given", Data::VERBATIM);
+ } else {
+ std::string expr = request.data["content"]["expression"].atom;
+ try {
+ replyData.compound["eval"] = _interpreter.getDataModel().getStringAsData(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);
+ }
+ returnData(request, replyData);
+}
+
+void DebuggerServlet::processDebugStep(const HTTPServer::Request& request) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+
+ stepping(true);
+ _resumeCond.notify_one();
+
+ Data replyData;
+ if (_interpreter && !_interpreter.isRunning()) {
+ // register ourself as a monitor
+ _interpreter.start();
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ } else {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ }
+ returnData(request, replyData);
+
+}
+
+void DebuggerServlet::processDebugResume(const HTTPServer::Request& request) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+
+ stepping(false);
+
+ Data replyData;
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ returnData(request, replyData);
+
+ _resumeCond.notify_one();
+}
+
+void DebuggerServlet::processDebugPause(const HTTPServer::Request& request) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+
+ Data replyData;
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ returnData(request, replyData);
+}
+
+void DebuggerServlet::processConnect(const HTTPServer::Request& request) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+ _sessionId = UUID::getUUID();
+ _breakPoints.clear();
+// _sendQueue.clear();
+
+ Data replyData;
+ replyData.compound["session"] = Data(_sessionId, Data::VERBATIM);
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ returnData(request, replyData);
+}
+
+void DebuggerServlet::processListSessions(const HTTPServer::Request& request) {
+ Data replyData;
+
+ // TODO: return actual data
+ Data sessionData;
+ sessionData.compound["name"] = Data("Not actually a Session", Data::VERBATIM);
+ sessionData.compound["id"] = Data("23452523-wg23g2g2-234t2g-23g2g", Data::VERBATIM);
+ replyData.compound["sessions"].array.push_back(sessionData);
+
+ sessionData.compound["name"] = Data("But returned from the server!", Data::VERBATIM);
+ sessionData.compound["id"] = Data("swfgsgfw-g232vqvq-234t2g-23g2g", Data::VERBATIM);
+ replyData.compound["sessions"].array.push_back(sessionData);
+
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ returnData(request, replyData);
+}
+
+void DebuggerServlet::processDisconnect(const HTTPServer::Request& request) {
+ Data replyData;
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ returnData(request, replyData);
+}
+
+void DebuggerServlet::processAddBreakPoint(const HTTPServer::Request& request) {
+ Breakpoint breakPoint(request.data["content"]);
+ Data replyData;
+ if (breakPoint.isValid()) {
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+
+ if (_breakPoints.find(breakPoint) == _breakPoints.end()) {
+ _breakPoints.insert(breakPoint);
+ }
+ } else {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ }
+ returnData(request, replyData);
+}
+
+void DebuggerServlet::processRemoveBreakPoint(const HTTPServer::Request& request) {
+ Breakpoint breakPoint(request.data["content"]);
+ Data replyData;
+ if (_breakPoints.erase(breakPoint) > 0) {
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ } else {
+ replyData.compound["message"] = Data("No such breakpoint", Data::VERBATIM);
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ }
+ returnData(request, replyData);
+}
+
+
+} \ 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..5cd0be9
--- /dev/null
+++ b/src/uscxml/debug/DebuggerServlet.h
@@ -0,0 +1,83 @@
+/**
+ * @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 "getopt.h"
+
+#include "uscxml/server/HTTPServer.h"
+#include "uscxml/Interpreter.h"
+
+#include "uscxml/debug/Debugger.h"
+#include "uscxml/concurrency/tinythread.h"
+
+namespace uscxml {
+
+class USCXML_API DebuggerServlet : public Debugger, public HTTPServlet {
+public:
+ 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(Data pushData);
+ void returnData(const HTTPServer::Request& request, Data replyData);
+
+ void hitBreakpoint(const Interpreter& interpreter,
+ Data data);
+
+ void processDebugEval(const HTTPServer::Request& request);
+ void processDebugPrepare(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 processConnect(const HTTPServer::Request& request);
+ void processListSessions(const HTTPServer::Request& request);
+ void processDisconnect(const HTTPServer::Request& request);
+ void processAddBreakPoint(const HTTPServer::Request& request);
+ void processRemoveBreakPoint(const HTTPServer::Request& request);
+ void processPoll(const HTTPServer::Request& request);
+
+protected:
+ void serverPushData();
+
+ Interpreter _interpreter;
+ std::string _sessionId;
+ std::string _url;
+ HTTPServer::Request _clientConn;
+ tthread::condition_variable _resumeCond;
+ tthread::recursive_mutex _mutex;
+ concurrency::BlockingQueue<Data> _sendQueue;
+};
+
+}
+
+#endif /* end of include guard: DEBUGGERSERVLET_H_ATUMDA3G */
diff --git a/src/uscxml/debug/SCXMLDotWriter.cpp b/src/uscxml/debug/SCXMLDotWriter.cpp
index 07e7b9a..2058d72 100644
--- a/src/uscxml/debug/SCXMLDotWriter.cpp
+++ b/src/uscxml/debug/SCXMLDotWriter.cpp
@@ -32,9 +32,9 @@ SCXMLDotWriter::SCXMLDotWriter() {
_indentation = 0;
}
-SCXMLDotWriter::SCXMLDotWriter(Interpreter interpreter, const Arabica::XPath::NodeSet<std::string>& transitions) {
+SCXMLDotWriter::SCXMLDotWriter(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition) {
_interpreter = interpreter;
- _transitions = transitions;
+ _transition = transition;
_iteration = 0;
_indentation = 0;
}
@@ -61,10 +61,10 @@ void SCXMLDotWriter::beforeMicroStep(Interpreter interpreter) {
// toDot(fileSS.str(), interpreter);
}
-void SCXMLDotWriter::beforeTakingTransitions(Interpreter interpreter, const Arabica::XPath::NodeSet<std::string>& transitions) {
+void SCXMLDotWriter::beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition) {
std::ostringstream fileSS;
fileSS << interpreter.getName() << "." << std::setw(6) << std::setfill('0') << _iteration++ << ".dot";
- toDot(fileSS.str(), interpreter, transitions);
+ toDot(fileSS.str(), interpreter, transition);
}
std::string SCXMLDotWriter::getPrefix() {
@@ -74,10 +74,10 @@ std::string SCXMLDotWriter::getPrefix() {
return prefix;
}
-void SCXMLDotWriter::toDot(const std::string& filename, Interpreter interpreter, const Arabica::XPath::NodeSet<std::string>& transitions) {
+void SCXMLDotWriter::toDot(const std::string& filename, Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition) {
std::ofstream outfile(filename.c_str());
NodeList<std::string > scxmlElems = interpreter.getDocument().getElementsByTagName("scxml");
- SCXMLDotWriter writer(interpreter, transitions);
+ SCXMLDotWriter writer(interpreter, transition);
if (scxmlElems.getLength() > 0) {
writer._indentation++;
outfile << "digraph {" << std::endl;
@@ -168,7 +168,7 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Arabica::DOM::Ele
for (int i = 0; i < childElems.getLength(); i++) {
if (childElems.item(i).getNodeType() == Node_base::ELEMENT_NODE && iequals(TAGNAME(childElems.item(i)), "transition")) {
writeTransitionElement(os, (Arabica::DOM::Element<std::string>)childElems.item(i));
- bool active = Interpreter::isMember(childElems.item(i), _transitions);
+ bool active = (childElems.item(i) == _transition);
os << getPrefix() << "\"" << elemId << "\" -> \"" << idForNode(childElems.item(i)) << "\" [arrowhead=none" << std::endl;
if (active) {
os << ", penwidth=3, color=red]" << std::endl;
@@ -202,7 +202,7 @@ void SCXMLDotWriter::writeTransitionElement(std::ostream& os, const Arabica::DOM
Arabica::XPath::NodeSet<std::string> targetStates = _interpreter.getTargetStates(elem);
- bool active = Interpreter::isMember(elem, _transitions);
+ bool active = (elem == _transition);
std::string label;
os << getPrefix() << "\"" << elemId << "\"[";
diff --git a/src/uscxml/debug/SCXMLDotWriter.h b/src/uscxml/debug/SCXMLDotWriter.h
index 2d3625c..4e2d7a8 100644
--- a/src/uscxml/debug/SCXMLDotWriter.h
+++ b/src/uscxml/debug/SCXMLDotWriter.h
@@ -65,12 +65,12 @@ public:
virtual void onStableConfiguration(Interpreter interpreter);
virtual void afterCompletion(Interpreter interpreter);
- virtual void beforeTakingTransitions(Interpreter interpreter, const Arabica::XPath::NodeSet<std::string>& transitions);
+ virtual void beforeTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition);
virtual void beforeMicroStep(Interpreter interpreter);
static void toDot(const std::string& filename,
Interpreter interpreter,
- const Arabica::XPath::NodeSet<std::string>& transitions = Arabica::XPath::NodeSet<std::string>());
+ const Arabica::DOM::Element<std::string>& transition = Arabica::DOM::Element<std::string>());
std::string getDetailedLabel(const Arabica::DOM::Element<std::string>& elem, int indentation = 0);
std::string colorForIndent(int indent);
@@ -84,7 +84,7 @@ public:
protected:
SCXMLDotWriter(Interpreter interpreter,
- const Arabica::XPath::NodeSet<std::string>& transitions);
+ const Arabica::DOM::Element<std::string>& transition);
void writeSCXMLElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem);
void writeStateElement(std::ostream& os, const Arabica::DOM::Element<std::string>& elem);
@@ -95,7 +95,7 @@ protected:
int _indentation;
// these are only set in ephemeral instances per monitor call
- Arabica::XPath::NodeSet<std::string> _transitions;
+ Arabica::DOM::Element<std::string> _transition;
Interpreter _interpreter;
};
diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp
index 772ad96..9e9204a 100644
--- a/src/uscxml/interpreter/InterpreterDraft6.cpp
+++ b/src/uscxml/interpreter/InterpreterDraft6.cpp
@@ -30,144 +30,130 @@ using namespace Arabica::DOM;
// see: http://www.w3.org/TR/scxml/#AlgorithmforSCXMLInterpretation
void InterpreterDraft6::interpret() {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
- if (!_isInitialized)
- init();
+ try {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+ if (!_isInitialized)
+ init();
-// std::cout << _scxml << std::endl;
-
- if (!_scxml) {
-// _mutex.unlock();
- return;
- }
-// dump();
-
- // just make sure we have a session id
- assert(_sessionId.length() > 0);
-
- setupIOProcessors();
-
- std::string datamodelName;
- if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "datamodel"))
- datamodelName = ATTR(_scxml, "datamodel");
- if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "profile")) // SCION SCXML uses profile to specify datamodel
- datamodelName = ATTR(_scxml, "profile");
- if(datamodelName.length() > 0) {
- _dataModel = _factory->createDataModel(datamodelName, this);
- if (!_dataModel) {
- Event e;
- e.data.compound["cause"] = Data("Cannot instantiate datamodel");
- throw e;
+ if (!_scxml) {
+ return;
}
- } else {
- _dataModel = _factory->createDataModel("null", this);
- }
- if(datamodelName.length() > 0 && !_dataModel) {
- LOG(ERROR) << "No datamodel for " << datamodelName << " registered";
- }
-
- if (_dataModel) {
- _dataModel.assign("_x.args", _cmdLineOptions);
- }
-
- _running = true;
- _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY);
-
- // @TODO: Reread http://www.w3.org/TR/scxml/#DataBinding
-
- if (_dataModel && _binding == EARLY) {
- // initialize all data elements
- NodeSet<std::string> dataElems = _xpath.evaluate("//" + _xpathPrefix + "data", _scxml).asNodeSet();
- for (unsigned int i = 0; i < dataElems.size(); i++) {
- // do not process data elements of nested documents from invokers
- if (!getAncestorElement(dataElems[i], _xmlNSPrefix + "invoke"))
- if (dataElems[i].getNodeType() == Node_base::ELEMENT_NODE) {
- initializeData(Element<std::string>(dataElems[i]));
- }
+ // dump();
+
+ // just make sure we have a session id
+ assert(_sessionId.length() > 0);
+
+ setupIOProcessors();
+
+ std::string datamodelName;
+ if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "datamodel"))
+ datamodelName = ATTR(_scxml, "datamodel");
+ if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "profile")) // SCION SCXML uses profile to specify datamodel
+ datamodelName = ATTR(_scxml, "profile");
+ if(datamodelName.length() > 0) {
+ _dataModel = _factory->createDataModel(datamodelName, this);
+ if (!_dataModel) {
+ Event e;
+ e.data.compound["cause"] = Data("Cannot instantiate datamodel");
+ throw e;
+ }
+ } else {
+ _dataModel = _factory->createDataModel("null", this);
}
- } else if(_dataModel) {
- // initialize current data elements
- NodeSet<std::string> topDataElems = filterChildElements(_xmlNSPrefix + "data", filterChildElements(_xmlNSPrefix + "datamodel", _scxml));
- for (unsigned int i = 0; i < topDataElems.size(); i++) {
- if (topDataElems[i].getNodeType() == Node_base::ELEMENT_NODE)
- initializeData(Element<std::string>(topDataElems[i]));
+ if(datamodelName.length() > 0 && !_dataModel) {
+ LOG(ERROR) << "No datamodel for " << datamodelName << " registered";
}
- }
- // executeGlobalScriptElements
- NodeSet<std::string> globalScriptElems = filterChildElements(_xmlNSPrefix + "script", _scxml);
- for (unsigned int i = 0; i < globalScriptElems.size(); i++) {
if (_dataModel) {
- executeContent(globalScriptElems[i]);
+ _dataModel.assign("_x.args", _cmdLineOptions);
}
- }
- NodeSet<std::string> initialTransitions;
+ _running = true;
+ _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY);
- if (_userDefinedStartConfiguration.size() > 0) {
- // we emulate entering a given configuration by creating a pseudo deep history
- Element<std::string> initHistory = _document.createElementNS(_nsURL, "history");
- initHistory.setAttribute("id", UUID::getUUID());
- initHistory.setAttribute("type", "deep");
- _scxml.insertBefore(initHistory, _scxml.getFirstChild());
+ // @TODO: Reread http://www.w3.org/TR/scxml/#DataBinding
- std::string histId = ATTR(initHistory, "id");
- NodeSet<std::string> histStates;
- for (int i = 0; i < _userDefinedStartConfiguration.size(); i++) {
- histStates.push_back(getState(_userDefinedStartConfiguration[i]));
+ if (_dataModel && _binding == EARLY) {
+ // initialize all data elements
+ NodeSet<std::string> dataElems = _xpath.evaluate("//" + _xpathPrefix + "data", _scxml).asNodeSet();
+ for (unsigned int i = 0; i < dataElems.size(); i++) {
+ // do not process data elements of nested documents from invokers
+ if (!getAncestorElement(dataElems[i], _xmlNSPrefix + "invoke"))
+ if (dataElems[i].getNodeType() == Node_base::ELEMENT_NODE) {
+ initializeData(Element<std::string>(dataElems[i]));
+ }
+ }
+ } else if(_dataModel) {
+ // initialize current data elements
+ NodeSet<std::string> topDataElems = filterChildElements(_xmlNSPrefix + "data", filterChildElements(_xmlNSPrefix + "datamodel", _scxml));
+ for (unsigned int i = 0; i < topDataElems.size(); i++) {
+ if (topDataElems[i].getNodeType() == Node_base::ELEMENT_NODE)
+ initializeData(Element<std::string>(topDataElems[i]));
+ }
}
- _historyValue[histId] = histStates;
-
- Element<std::string> initialElem = _document.createElementNS(_nsURL, "initial");
- initialElem.setAttribute("generated", "true");
- Element<std::string> transitionElem = _document.createElementNS(_nsURL, "transition");
- transitionElem.setAttribute("target", histId);
- initialElem.appendChild(transitionElem);
- _scxml.appendChild(initialElem);
- initialTransitions.push_back(transitionElem);
- } else {
- // try to get initial transition form initial element
- initialTransitions = _xpath.evaluate("/" + _xpathPrefix + "initial/" + _xpathPrefix + "transition", _scxml).asNodeSet();
- if (initialTransitions.size() == 0) {
- Arabica::XPath::NodeSet<std::string> initialStates;
- // fetch per draft
- initialStates = getInitialStates();
- assert(initialStates.size() > 0);
- for (int i = 0; i < initialStates.size(); i++) {
- Element<std::string> initialElem = _document.createElementNS(_nsURL, "initial");
- initialElem.setAttribute("generated", "true");
- Element<std::string> transitionElem = _document.createElementNS(_nsURL, "transition");
- transitionElem.setAttribute("target", ATTR(initialStates[i], "id"));
- initialElem.appendChild(transitionElem);
- _scxml.appendChild(initialElem);
- initialTransitions.push_back(transitionElem);
+ // executeGlobalScriptElements
+ NodeSet<std::string> globalScriptElems = filterChildElements(_xmlNSPrefix + "script", _scxml);
+ for (unsigned int i = 0; i < globalScriptElems.size(); i++) {
+ if (_dataModel) {
+ executeContent(globalScriptElems[i]);
}
}
- }
- assert(initialTransitions.size() > 0);
+ NodeSet<std::string> initialTransitions;
- monIter_t monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->beforeTakingTransitions(shared_from_this(), initialTransitions);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling beforeTakingTransitions on monitors: " << std::endl << e << std::endl;
- } catch (boost::bad_weak_ptr e) {
- LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling beforeTakingTransitions on monitors";
+ if (_userDefinedStartConfiguration.size() > 0) {
+ // we emulate entering a given configuration by creating a pseudo deep history
+ Element<std::string> initHistory = _document.createElementNS(_nsURL, "history");
+ initHistory.setAttribute("id", UUID::getUUID());
+ initHistory.setAttribute("type", "deep");
+ _scxml.insertBefore(initHistory, _scxml.getFirstChild());
+
+ std::string histId = ATTR(initHistory, "id");
+ NodeSet<std::string> histStates;
+ for (int i = 0; i < _userDefinedStartConfiguration.size(); i++) {
+ histStates.push_back(getState(_userDefinedStartConfiguration[i]));
+ }
+ _historyValue[histId] = histStates;
+
+ Element<std::string> initialElem = _document.createElementNS(_nsURL, "initial");
+ initialElem.setAttribute("generated", "true");
+ Element<std::string> transitionElem = _document.createElementNS(_nsURL, "transition");
+ transitionElem.setAttribute("target", histId);
+ initialElem.appendChild(transitionElem);
+ _scxml.appendChild(initialElem);
+ initialTransitions.push_back(transitionElem);
+
+ } else {
+ // try to get initial transition form initial element
+ initialTransitions = _xpath.evaluate("/" + _xpathPrefix + "initial/" + _xpathPrefix + "transition", _scxml).asNodeSet();
+ if (initialTransitions.size() == 0) {
+ Arabica::XPath::NodeSet<std::string> initialStates;
+ // fetch per draft
+ initialStates = getInitialStates();
+ assert(initialStates.size() > 0);
+ for (int i = 0; i < initialStates.size(); i++) {
+ Element<std::string> initialElem = _document.createElementNS(_nsURL, "initial");
+ initialElem.setAttribute("generated", "true");
+ Element<std::string> transitionElem = _document.createElementNS(_nsURL, "transition");
+ transitionElem.setAttribute("target", ATTR(initialStates[i], "id"));
+ initialElem.appendChild(transitionElem);
+ _scxml.appendChild(initialElem);
+ initialTransitions.push_back(transitionElem);
+ }
+ }
}
- monIter++;
- }
- enterStates(initialTransitions);
-// _mutex.unlock();
+ assert(initialTransitions.size() > 0);
-// assert(hasLegalConfiguration());
- mainEventLoop();
+ enterStates(initialTransitions);
+ // _mutex.unlock();
+ // assert(hasLegalConfiguration());
+ mainEventLoop();
+ } catch (boost::bad_weak_ptr e) {
+ LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
+ }
// set datamodel to null from this thread
if(_dataModel)
_dataModel = DataModel();
@@ -192,22 +178,7 @@ void InterpreterDraft6::mainEventLoop() {
}
std::cout << std::endl;
#endif
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->beforeMicroStep(shared_from_this());
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling beforeMicroStep on monitors: " << std::endl << e << std::endl;
- } catch (boost::bad_weak_ptr e) {
- LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
- _mutex.unlock();
- goto EXIT_INTERPRETER;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling beforeMicroStep on monitors";
- }
- monIter++;
- }
-
+
enabledTransitions = selectEventlessTransitions();
if (enabledTransitions.size() == 0) {
if (_internalQueue.size() == 0) {
@@ -218,27 +189,20 @@ void InterpreterDraft6::mainEventLoop() {
#if VERBOSE
std::cout << "Received internal event " << _currEvent.name << std::endl;
#endif
+
+ // --- MONITOR: beforeProcessingEvent ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
+ } USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
+ }
+
if (_dataModel)
_dataModel.setEvent(_currEvent);
enabledTransitions = selectTransitions(_currEvent.name);
}
}
if (!enabledTransitions.empty()) {
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->beforeTakingTransitions(shared_from_this(), enabledTransitions);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling beforeTakingTransitions on monitors: " << std::endl << e << std::endl;
- } catch (boost::bad_weak_ptr e) {
- LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
- _mutex.unlock();
- goto EXIT_INTERPRETER;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling beforeTakingTransitions on monitors";
- }
- monIter++;
- }
// test 403b
enabledTransitions.to_document_order();
microstep(enabledTransitions);
@@ -269,20 +233,14 @@ void InterpreterDraft6::mainEventLoop() {
monIter = _monitors.begin();
// if (!_sendQueue || _sendQueue->isEmpty()) {
- while(monIter != _monitors.end()) {
+
+ // --- MONITOR: onStableConfiguration ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
try {
(*monIter)->onStableConfiguration(shared_from_this());
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling onStableConfiguration on monitors: " << std::endl << e << std::endl;
- } catch (boost::bad_weak_ptr e) {
- LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
- _mutex.unlock();
- goto EXIT_INTERPRETER;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling onStableConfiguration on monitors";
- }
- monIter++;
+ } USCXML_MONITOR_CATCH_BLOCK(onStableConfiguration)
}
+
// }
_mutex.unlock();
@@ -303,6 +261,13 @@ void InterpreterDraft6::mainEventLoop() {
if (!_running)
goto EXIT_INTERPRETER;
+ // --- MONITOR: beforeProcessingEvent ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->beforeProcessingEvent(shared_from_this(), _currEvent);
+ } USCXML_MONITOR_CATCH_BLOCK(beforeProcessingEvent)
+ }
+
if (_dataModel && iequals(_currEvent.name, "cancel.invoke." + _sessionId))
break;
@@ -360,19 +325,11 @@ void InterpreterDraft6::mainEventLoop() {
}
EXIT_INTERPRETER:
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
+ // --- MONITOR: beforeCompletion ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
try {
(*monIter)->beforeCompletion(shared_from_this());
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling beforeCompletion on monitors: " << std::endl << e << std::endl;
- } catch (boost::bad_weak_ptr e) {
- LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
- exitInterpreter();
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling beforeCompletion on monitors";
- }
- monIter++;
+ } USCXML_MONITOR_CATCH_BLOCK(beforeCompletion)
}
exitInterpreter();
@@ -384,19 +341,11 @@ EXIT_INTERPRETER:
}
}
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
+ // --- MONITOR: afterCompletion ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
try {
(*monIter)->afterCompletion(shared_from_this());
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling afterCompletion on monitors: " << std::endl << e << std::endl;
- } catch (boost::bad_weak_ptr e) {
- LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
- exitInterpreter();
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling afterCompletion on monitors";
- }
- monIter++;
+ } USCXML_MONITOR_CATCH_BLOCK(afterCompletion)
}
}
@@ -635,9 +584,45 @@ void InterpreterDraft6::microstep(const Arabica::XPath::NodeSet<std::string>& en
std::cout << std::endl;
#endif
+ // --- MONITOR: beforeMicroStep ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->beforeMicroStep(shared_from_this());
+ } USCXML_MONITOR_CATCH_BLOCK(beforeMicroStep)
+ }
+
exitStates(enabledTransitions);
- executeContent(enabledTransitions);
+
+ monIter_t monIter;
+ for (int i = 0; i < enabledTransitions.size(); i++) {
+ Element<std::string> transition(enabledTransitions[i]);
+
+ // --- MONITOR: beforeTakingTransitions ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->beforeTakingTransition(shared_from_this(), transition);
+ } USCXML_MONITOR_CATCH_BLOCK(beforeTakingTransitions)
+ }
+
+ executeContent(transition);
+
+ // --- MONITOR: afterTakingTransitions ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->afterTakingTransition(shared_from_this(), transition);
+ } USCXML_MONITOR_CATCH_BLOCK(afterTakingTransitions)
+ }
+ }
+
enterStates(enabledTransitions);
+
+ // --- MONITOR: afterMicroStep ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->afterMicroStep(shared_from_this());
+ } USCXML_MONITOR_CATCH_BLOCK(afterMicroStep)
+ }
+
}
void InterpreterDraft6::exitInterpreter() {
@@ -734,21 +719,6 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
std::cout << std::endl;
#endif
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->beforeExitingStates(shared_from_this(), statesToExit);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling beforeExitingStates on monitors: " << std::endl << e << std::endl;
- } catch (boost::bad_weak_ptr e) {
- LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
- exitInterpreter();
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling beforeExitingStates on monitors";
- }
- monIter++;
- }
-
for (int i = 0; i < statesToExit.size(); i++) {
NodeSet<std::string> histories = filterChildElements(_xmlNSPrefix + "history", statesToExit[i]);
for (int j = 0; j < histories.size(); j++) {
@@ -777,11 +747,26 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
}
for (int i = 0; i < statesToExit.size(); i++) {
+ // --- MONITOR: beforeExitingState ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->beforeExitingState(shared_from_this(), Element<std::string>(statesToExit[i]));
+ } USCXML_MONITOR_CATCH_BLOCK(beforeExitingState)
+ }
+
NodeSet<std::string> onExits = filterChildElements(_xmlNSPrefix + "onExit", statesToExit[i]);
for (int j = 0; j < onExits.size(); j++) {
Element<std::string> onExitElem = (Element<std::string>)onExits[j];
executeContent(onExitElem);
}
+
+ // --- MONITOR: afterExitingState ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->afterExitingState(shared_from_this(), Element<std::string>(statesToExit[i]));
+ } USCXML_MONITOR_CATCH_BLOCK(afterExitingState)
+ }
+
NodeSet<std::string> invokes = filterChildElements(_xmlNSPrefix + "invoke", statesToExit[i]);
for (int j = 0; j < invokes.size(); j++) {
Element<std::string> invokeElem = (Element<std::string>)invokes[j];
@@ -797,22 +782,6 @@ void InterpreterDraft6::exitStates(const Arabica::XPath::NodeSet<std::string>& e
_configuration = NodeSet<std::string>();
_configuration.insert(_configuration.end(), tmp.begin(), tmp.end());
}
-
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->afterExitingStates(shared_from_this());
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling afterExitingStates on monitors: " << std::endl << e << std::endl;
- } catch (boost::bad_weak_ptr e) {
- LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
- exitInterpreter();
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling afterExitingStates on monitors";
- }
- monIter++;
- }
-
}
void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
@@ -926,23 +895,16 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
std::cout << std::endl;
#endif
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->beforeEnteringStates(shared_from_this(), statesToEnter);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling beforeEnteringStates on monitors: " << std::endl << e << std::endl;
- } catch (boost::bad_weak_ptr e) {
- LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
- exitInterpreter();
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling beforeEnteringStates on monitors";
- }
- monIter++;
- }
-
for (int i = 0; i < statesToEnter.size(); i++) {
Element<std::string> stateElem = (Element<std::string>)statesToEnter[i];
+
+ // --- MONITOR: beforeEnteringState ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->beforeEnteringState(shared_from_this(), stateElem);
+ } USCXML_MONITOR_CATCH_BLOCK(beforeEnteringState)
+ }
+
_configuration.push_back(stateElem);
_statesToInvoke.push_back(stateElem);
if (_binding == LATE && stateElem.getAttribute("isFirstEntry").size() > 0) {
@@ -960,6 +922,13 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
NodeSet<std::string> onEntryElems = filterChildElements(_xmlNSPrefix + "onEntry", stateElem);
executeContent(onEntryElems, false);
+ // --- MONITOR: afterEnteringState ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->afterEnteringState(shared_from_this(), stateElem);
+ } USCXML_MONITOR_CATCH_BLOCK(afterEnteringState)
+ }
+
if (isMember(stateElem, statesForDefaultEntry)) {
// execute initial transition content for compound states
Arabica::XPath::NodeSet<std::string> transitions = _xpath.evaluate("" + _xpathPrefix + "initial/" + _xpathPrefix + "transition", stateElem).asNodeSet();
@@ -996,22 +965,6 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
_done = true;
}
}
-
- monIter = _monitors.begin();
- while(monIter != _monitors.end()) {
- try {
- (*monIter)->afterEnteringStates(shared_from_this());
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when calling afterEnteringStates on monitors: " << std::endl << e << std::endl;
- } catch (boost::bad_weak_ptr e) {
- LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
- return;
- } catch (...) {
- LOG(ERROR) << "An exception occured when calling afterEnteringStates on monitors";
- }
- monIter++;
- }
-
}
void InterpreterDraft6::addStatesToEnter(const Node<std::string>& state,
diff --git a/src/uscxml/plugins/invoker/imap/IMAPInvoker.cpp b/src/uscxml/plugins/invoker/imap/IMAPInvoker.cpp
index 19c5907..5237977 100644
--- a/src/uscxml/plugins/invoker/imap/IMAPInvoker.cpp
+++ b/src/uscxml/plugins/invoker/imap/IMAPInvoker.cpp
@@ -17,6 +17,7 @@
* @endcond
*/
+#define NOMINMAX // and have MSVC die in a fire for defining min macro
#include "IMAPInvoker.h"
#include <glog/logging.h>
@@ -71,7 +72,7 @@ size_t IMAPInvoker::writeCurlData(void *ptr, size_t size, size_t nmemb, void *us
IMAPContext* ctx = (IMAPContext*)userdata;
- size_t toWrite = std::min(ctx->outContent.length() - ctx->readPtr, size * nmemb);
+ size_t toWrite = (std::min)(ctx->outContent.length() - ctx->readPtr, size * nmemb);
if (toWrite > 0) {
memcpy (ptr, ctx->outContent.c_str() + ctx->readPtr, toWrite);
ctx->readPtr += toWrite;
@@ -100,7 +101,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "mailbox", args->mailbox);
ctx = new IMAPContext();
- ctx->command = IMAPContext::SELECT;
+ ctx->command = IMAPContext::IMAP_SELECT;
ctx->arguments = args;
} else if (iequals(req.name, "examine")) {
@@ -108,7 +109,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "mailbox", args->mailbox);
ctx = new IMAPContext();
- ctx->command = IMAPContext::EXAMINE;
+ ctx->command = IMAPContext::IMAP_EXAMINE;
ctx->arguments = args;
} else if (iequals(req.name, "delete")) {
@@ -116,7 +117,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "mailbox", args->mailbox);
ctx = new IMAPContext();
- ctx->command = IMAPContext::DELETE;
+ ctx->command = IMAPContext::IMAP_DELETE;
ctx->arguments = args;
} else if (iequals(req.name, "rename")) {
@@ -125,7 +126,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "name", args->newName);
ctx = new IMAPContext();
- ctx->command = IMAPContext::RENAME;
+ ctx->command = IMAPContext::IMAP_RENAME;
ctx->arguments = args;
} else if (iequals(req.name, "subscribe")) {
@@ -133,7 +134,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "mailbox", args->mailbox);
ctx = new IMAPContext();
- ctx->command = IMAPContext::SUBSCRIBE;
+ ctx->command = IMAPContext::IMAP_SUBSCRIBE;
ctx->arguments = args;
} else if (iequals(req.name, "unsubscribe")) {
@@ -141,7 +142,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "mailbox", args->mailbox);
ctx = new IMAPContext();
- ctx->command = IMAPContext::UNSUBSCRIBE;
+ ctx->command = IMAPContext::IMAP_UNSUBSCRIBE;
ctx->arguments = args;
} else if (iequals(req.name, "list")) {
@@ -150,7 +151,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "reference", args->refName);
ctx = new IMAPContext();
- ctx->command = IMAPContext::LIST;
+ ctx->command = IMAPContext::IMAP_LIST;
ctx->arguments = args;
} else if (iequals(req.name, "lsub")) {
@@ -159,7 +160,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "reference", args->refName);
ctx = new IMAPContext();
- ctx->command = IMAPContext::LSUB;
+ ctx->command = IMAPContext::IMAP_LSUB;
ctx->arguments = args;
} else if (iequals(req.name, "status")) {
@@ -168,7 +169,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "dataitems", args->dataItems);
ctx = new IMAPContext();
- ctx->command = IMAPContext::STATUS;
+ ctx->command = IMAPContext::IMAP_STATUS;
ctx->arguments = args;
} else if (iequals(req.name, "append")) {
@@ -182,28 +183,28 @@ void IMAPInvoker::send(const SendRequest& req) {
}
ctx = new IMAPContext();
- ctx->command = IMAPContext::APPEND;
+ ctx->command = IMAPContext::IMAP_APPEND;
ctx->arguments = args;
} else if (iequals(req.name, "check")) {
IMAPContext::Check* args = new IMAPContext::Check();
ctx = new IMAPContext();
- ctx->command = IMAPContext::CHECK;
+ ctx->command = IMAPContext::IMAP_CHECK;
ctx->arguments = args;
} else if (iequals(req.name, "close")) {
IMAPContext::Close* args = new IMAPContext::Close();
ctx = new IMAPContext();
- ctx->command = IMAPContext::CLOSE;
+ ctx->command = IMAPContext::IMAP_CLOSE;
ctx->arguments = args;
} else if (iequals(req.name, "expunge")) {
IMAPContext::Expunge* args = new IMAPContext::Expunge();
ctx = new IMAPContext();
- ctx->command = IMAPContext::EXPUNGE;
+ ctx->command = IMAPContext::IMAP_EXPUNGE;
ctx->arguments = args;
} else if (iequals(req.name, "search")) {
@@ -212,7 +213,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "criteria", args->criteria);
ctx = new IMAPContext();
- ctx->command = IMAPContext::SEARCH;
+ ctx->command = IMAPContext::IMAP_SEARCH;
ctx->arguments = args;
} else if (iequals(req.name, "fetch")) {
@@ -221,7 +222,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "itemnames", args->itemNames);
ctx = new IMAPContext();
- ctx->command = IMAPContext::FETCH;
+ ctx->command = IMAPContext::IMAP_FETCH;
ctx->arguments = args;
} else if (iequals(req.name, "store")) {
@@ -231,7 +232,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "values", args->values);
ctx = new IMAPContext();
- ctx->command = IMAPContext::STORE;
+ ctx->command = IMAPContext::IMAP_STORE;
ctx->arguments = args;
} else if (iequals(req.name, "copy")) {
@@ -240,7 +241,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "sequence", args->sequence);
ctx = new IMAPContext();
- ctx->command = IMAPContext::COPY;
+ ctx->command = IMAPContext::IMAP_COPY;
ctx->arguments = args;
} else if (iequals(req.name, "uid")) {
@@ -249,7 +250,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "arguments", args->arguments);
ctx = new IMAPContext();
- ctx->command = IMAPContext::UID;
+ ctx->command = IMAPContext::IMAP_UID;
ctx->arguments = args;
} else if (boost::istarts_with(req.name, "x")) {
@@ -258,7 +259,7 @@ void IMAPInvoker::send(const SendRequest& req) {
Event::getParam(req.params, "arguments", args->arguments);
ctx = new IMAPContext();
- ctx->command = IMAPContext::XEXTENSION;
+ ctx->command = IMAPContext::IMAP_XEXTENSION;
ctx->arguments = args;
}
@@ -322,74 +323,74 @@ void IMAPInvoker::process(IMAPContext* ctx) {
std::stringstream cmdSS;
switch (ctx->command) {
- case IMAPContext::SELECT: {
+ case IMAPContext::IMAP_SELECT: {
IMAPContext::Select* cmd = (IMAPContext::Select*)ctx->arguments;
cmdSS << "SELECT " << "\"" << cmd->mailbox << "\"";
break;
}
- case IMAPContext::EXAMINE: {
+ case IMAPContext::IMAP_EXAMINE: {
IMAPContext::Examine* cmd = (IMAPContext::Examine*)ctx->arguments;
cmdSS << "EXAMINE " << "\"" << cmd->mailbox << "\"";
break;
}
- case IMAPContext::CREATE: {
+ case IMAPContext::IMAP_CREATE: {
IMAPContext::Create* cmd = (IMAPContext::Create*)ctx->arguments;
cmdSS << "CREATE " << "\"" << cmd->mailbox << "\"";
break;
}
- case IMAPContext::DELETE: {
+ case IMAPContext::IMAP_DELETE: {
IMAPContext::Delete* cmd = (IMAPContext::Delete*)ctx->arguments;
cmdSS << "DELETE " << "\"" << cmd->mailbox << "\"";
break;
}
- case IMAPContext::RENAME: {
+ case IMAPContext::IMAP_RENAME: {
IMAPContext::Rename* cmd = (IMAPContext::Rename*)ctx->arguments;
cmdSS << "RENAME " << "\"" << cmd->mailbox << "\" \"" << cmd->newName << "\"";
break;
}
- case IMAPContext::SUBSCRIBE: {
+ case IMAPContext::IMAP_SUBSCRIBE: {
IMAPContext::Subscribe* cmd = (IMAPContext::Subscribe*)ctx->arguments;
cmdSS << "SUBSCRIBE " << "\"" << cmd->mailbox << "\"";
break;
}
- case IMAPContext::UNSUBSCRIBE: {
+ case IMAPContext::IMAP_UNSUBSCRIBE: {
IMAPContext::Unsubscribe* cmd = (IMAPContext::Unsubscribe*)ctx->arguments;
cmdSS << "UNSUBSCRIBE " << "\"" << cmd->mailbox << "\"";
break;
}
- case IMAPContext::LIST: {
+ case IMAPContext::IMAP_LIST: {
IMAPContext::List* cmd = (IMAPContext::List*)ctx->arguments;
cmdSS << "LIST " << "\"" << cmd->mailbox << "\" \"" << cmd->refName << "\"";
break;
}
- case IMAPContext::LSUB: {
+ case IMAPContext::IMAP_LSUB: {
IMAPContext::LSub* cmd = (IMAPContext::LSub*)ctx->arguments;
cmdSS << "LSUB " << "\"" << cmd->mailbox << "\" \"" << cmd->refName << "\"";
break;
}
- case IMAPContext::STATUS: {
+ case IMAPContext::IMAP_STATUS: {
IMAPContext::Status* cmd = (IMAPContext::Status*)ctx->arguments;
cmdSS << "STATUS " << "\"" << cmd->mailbox << "\" (" << cmd->dataItems << ")";
break;
}
- case IMAPContext::APPEND: {
+ case IMAPContext::IMAP_APPEND: {
IMAPContext::Append* cmd = (IMAPContext::Append*)ctx->arguments;
cmdSS << "APPEND " << "\"" << cmd->mailbox << "\" (" << cmd->flags << ") {" << cmd->dateTime << "}";
break;
}
- case IMAPContext::CHECK: {
+ case IMAPContext::IMAP_CHECK: {
cmdSS << "CHECK";
break;
}
- case IMAPContext::CLOSE: {
+ case IMAPContext::IMAP_CLOSE: {
cmdSS << "CLOSE";
break;
}
- case IMAPContext::EXPUNGE: {
+ case IMAPContext::IMAP_EXPUNGE: {
cmdSS << "EXPUNGE";
break;
}
- case IMAPContext::SEARCH: {
+ case IMAPContext::IMAP_SEARCH: {
IMAPContext::Search* cmd = (IMAPContext::Search*)ctx->arguments;
cmdSS << "SEARCH ";
if (cmd->charSet.size() > 0) {
@@ -398,27 +399,27 @@ void IMAPInvoker::process(IMAPContext* ctx) {
cmdSS << cmd->criteria;
break;
}
- case IMAPContext::FETCH: {
+ case IMAPContext::IMAP_FETCH: {
IMAPContext::Fetch* cmd = (IMAPContext::Fetch*)ctx->arguments;
cmdSS << "FETCH " << cmd->sequence << " " << cmd->itemNames;
break;
}
- case IMAPContext::STORE: {
+ case IMAPContext::IMAP_STORE: {
IMAPContext::Store* cmd = (IMAPContext::Store*)ctx->arguments;
cmdSS << "STORE " << cmd->sequence << " " << cmd->itemNames << " " << cmd->values;
break;
}
- case IMAPContext::COPY: {
+ case IMAPContext::IMAP_COPY: {
IMAPContext::Copy* cmd = (IMAPContext::Copy*)ctx->arguments;
cmdSS << "COPY " << "\"" << cmd->mailbox << "\" " << cmd->sequence;
break;
}
- case IMAPContext::UID: {
+ case IMAPContext::IMAP_UID: {
IMAPContext::UId* cmd = (IMAPContext::UId*)ctx->arguments;
cmdSS << "UID " << cmd->command << " " << cmd->arguments;
break;
}
- case IMAPContext::XEXTENSION: {
+ case IMAPContext::IMAP_XEXTENSION: {
IMAPContext::XExtension* cmd = (IMAPContext::XExtension*)ctx->arguments;
cmdSS << cmd->command << " " << cmd->arguments;
break;
diff --git a/src/uscxml/plugins/invoker/imap/IMAPInvoker.h b/src/uscxml/plugins/invoker/imap/IMAPInvoker.h
index 3c367da..94d199b 100644
--- a/src/uscxml/plugins/invoker/imap/IMAPInvoker.h
+++ b/src/uscxml/plugins/invoker/imap/IMAPInvoker.h
@@ -56,27 +56,27 @@ protected:
public:
enum Cmd {
// valid in authenticated state
- SELECT,
- EXAMINE,
- CREATE,
- DELETE,
- RENAME,
- SUBSCRIBE,
- UNSUBSCRIBE,
- LIST,
- LSUB,
- STATUS,
- APPEND,
+ IMAP_SELECT,
+ IMAP_EXAMINE,
+ IMAP_CREATE,
+ IMAP_DELETE,
+ IMAP_RENAME,
+ IMAP_SUBSCRIBE,
+ IMAP_UNSUBSCRIBE,
+ IMAP_LIST,
+ IMAP_LSUB,
+ IMAP_STATUS,
+ IMAP_APPEND,
// valid in selected state
- CHECK,
- CLOSE,
- EXPUNGE,
- SEARCH,
- FETCH,
- STORE,
- COPY,
- UID,
- XEXTENSION,
+ IMAP_CHECK,
+ IMAP_CLOSE,
+ IMAP_EXPUNGE,
+ IMAP_SEARCH,
+ IMAP_FETCH,
+ IMAP_STORE,
+ IMAP_COPY,
+ IMAP_UID,
+ IMAP_XEXTENSION,
};
struct MailboxOp {
diff --git a/src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp b/src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp
index 3e130a0..1248733 100644
--- a/src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp
+++ b/src/uscxml/plugins/invoker/smtp/SMTPInvoker.cpp
@@ -59,7 +59,7 @@ size_t SMTPInvoker::writeCurlData(void *ptr, size_t size, size_t nmemb, void *us
SMTPContext* ctx = (SMTPContext*)userdata;
- size_t toWrite = std::min(ctx->content.length() - ctx->readPtr, size * nmemb);
+ size_t toWrite = (std::min)(ctx->content.length() - ctx->readPtr, size * nmemb);
if (toWrite > 0) {
memcpy (ptr, ctx->content.c_str() + ctx->readPtr, toWrite);
ctx->readPtr += toWrite;
diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp
index a6a2df3..4129413 100644
--- a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp
+++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp
@@ -369,7 +369,7 @@ bool UmundoInvoker::protobufToData(Data& data, const google::protobuf::Message&
const google::protobuf::Descriptor* desc = msg.GetDescriptor();
const google::protobuf::Reflection* reflect = msg.GetReflection();
- data.compound["type"] = Data(desc->name(), Data::VERBATIM);
+ data.compound["protobufType"] = Data(desc->name(), Data::VERBATIM);
for (int i = 0; i < desc->field_count(); i++) {
const google::protobuf::FieldDescriptor* fieldDesc = desc->field(i);