summaryrefslogtreecommitdiffstats
path: root/src/uscxml
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-03-11 14:45:38 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-03-11 14:45:38 (GMT)
commitc34e0ce034586a05308e552cbbdff48beec7dd96 (patch)
tree39c73ba64b0d228b3c53913ea4e7ab6dda6ad5c1 /src/uscxml
parentca46aa711fb5d08a8fd1cc6b91593c281189e8e3 (diff)
downloaduscxml-c34e0ce034586a05308e552cbbdff48beec7dd96.zip
uscxml-c34e0ce034586a05308e552cbbdff48beec7dd96.tar.gz
uscxml-c34e0ce034586a05308e552cbbdff48beec7dd96.tar.bz2
Integrated debugger into browser (use -d command line parameter)
Diffstat (limited to 'src/uscxml')
-rw-r--r--src/uscxml/DOMUtils.cpp23
-rw-r--r--src/uscxml/DOMUtils.h2
-rw-r--r--src/uscxml/Interpreter.cpp45
-rw-r--r--src/uscxml/Interpreter.h36
-rw-r--r--src/uscxml/Message.cpp7
-rw-r--r--src/uscxml/debug/Breakpoint.cpp65
-rw-r--r--src/uscxml/debug/Breakpoint.h29
-rw-r--r--src/uscxml/debug/DebugSession.cpp378
-rw-r--r--src/uscxml/debug/DebugSession.h99
-rw-r--r--src/uscxml/debug/Debugger.cpp114
-rw-r--r--src/uscxml/debug/Debugger.h60
-rw-r--r--src/uscxml/debug/DebuggerServlet.cpp330
-rw-r--r--src/uscxml/debug/DebuggerServlet.h69
-rw-r--r--src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp2
-rw-r--r--src/uscxml/server/HTTPServer.cpp2
15 files changed, 902 insertions, 359 deletions
diff --git a/src/uscxml/DOMUtils.cpp b/src/uscxml/DOMUtils.cpp
index c38b087..3cf986b 100644
--- a/src/uscxml/DOMUtils.cpp
+++ b/src/uscxml/DOMUtils.cpp
@@ -25,9 +25,14 @@
namespace uscxml {
-std::string DOMUtils::xPathForNode(const Arabica::DOM::Node<std::string>& node) {
+std::string DOMUtils::xPathForNode(const Arabica::DOM::Node<std::string>& node, const std::string& ns) {
std::string xPath;
-
+ std::string nsPrefix;
+
+ if (ns.size() > 0) {
+ nsPrefix = ns + ":";
+ }
+
if (!node || node.getNodeType() != Arabica::DOM::Node_base::ELEMENT_NODE)
return xPath;
@@ -37,12 +42,16 @@ std::string DOMUtils::xPathForNode(const Arabica::DOM::Node<std::string>& node)
case Arabica::DOM::Node_base::ELEMENT_NODE: {
if (HAS_ATTR(curr, "id")) {
// we assume ids to be unique and return immediately
- xPath.insert(0, "//" + TAGNAME(curr) + "[@id=\"" + ATTR(curr, "id") + "\"]");
+ if (ns == "*") {
+ xPath.insert(0, "//*[local-name() = \"" + TAGNAME(curr) + "\"][@id=\"" + ATTR(curr, "id") + "\"]");
+ } else {
+ xPath.insert(0, "//" + nsPrefix + TAGNAME(curr) + "[@id=\"" + ATTR(curr, "id") + "\"]");
+ }
return xPath;
} else {
// check previous siblings to count our index
Arabica::DOM::Node<std::string> sibling = curr.getPreviousSibling();
- int index = 1;
+ int index = 1; // xpath indices start at 1
while(sibling) {
if (sibling.getNodeType() == Arabica::DOM::Node_base::ELEMENT_NODE) {
if (iequals(TAGNAME(sibling), TAGNAME(curr))) {
@@ -51,7 +60,11 @@ std::string DOMUtils::xPathForNode(const Arabica::DOM::Node<std::string>& node)
}
sibling = sibling.getPreviousSibling();
}
- xPath.insert(0, "/" + TAGNAME(curr) + "[" + toStr(index) + "]");
+ if (ns == "*") {
+ xPath.insert(0, "/*[local-name() = \"" + TAGNAME(curr) + "\"][" + toStr(index) + "]");
+ } else {
+ xPath.insert(0, "/" + nsPrefix + TAGNAME(curr) + "[" + toStr(index) + "]");
+ }
}
break;
}
diff --git a/src/uscxml/DOMUtils.h b/src/uscxml/DOMUtils.h
index 731b332..596bb36 100644
--- a/src/uscxml/DOMUtils.h
+++ b/src/uscxml/DOMUtils.h
@@ -35,7 +35,7 @@ namespace uscxml {
class USCXML_API DOMUtils {
public:
- static std::string xPathForNode(const Arabica::DOM::Node<std::string>& node);
+ static std::string xPathForNode(const Arabica::DOM::Node<std::string>& node, const std::string& ns = "");
static std::list<Arabica::DOM::Node<std::string> > getElementsByType(const Arabica::DOM::Node<std::string>& root, Arabica::DOM::Node_base::Type type);
};
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index 2e867ba..bfee23a 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -98,7 +98,7 @@ void InterpreterOptions::printUsageAndExit(const char* progName) {
printf("\n");
printf("Options\n");
printf("\t-v : be verbose\n");
- printf("\t-d : write each configuration as a dot file\n");
+ printf("\t-d : enable debugging via HTTP\n");
printf("\t-lN : Set loglevel to N\n");
printf("\t-tN : port for HTTP server\n");
printf("\t-sN : port for HTTPS server\n");
@@ -120,7 +120,7 @@ InterpreterOptions InterpreterOptions::fromCmdLine(int argc, char** argv) {
optind = 0;
struct option longOptions[] = {
{"verbose", no_argument, 0, 'v'},
- {"dot", no_argument, 0, 'd'},
+ {"debug", no_argument, 0, 'd'},
{"port", required_argument, 0, 't'},
{"ssl-port", required_argument, 0, 's'},
{"ws-port", required_argument, 0, 'w'},
@@ -134,11 +134,6 @@ InterpreterOptions InterpreterOptions::fromCmdLine(int argc, char** argv) {
};
opterr = 0;
- if (argc < 2) {
- options.error = "No SCXML document to evaluate";
- return options;
- }
-
InterpreterOptions* currOptions = &options;
// parse global options
@@ -183,7 +178,7 @@ InterpreterOptions InterpreterOptions::fromCmdLine(int argc, char** argv) {
currOptions->pluginPath = optarg;
break;
case 'd':
- currOptions->useDot = true;
+ currOptions->withDebugger = true;
break;
case 'c':
currOptions->certificate = optarg;
@@ -228,7 +223,7 @@ InterpreterOptions InterpreterOptions::fromCmdLine(int argc, char** argv) {
DONE_PARSING_CMD:
- if (options.interpreters.size() == 0)
+ if (options.interpreters.size() == 0 && !options.withDebugger)
options.error = "No SCXML document to evaluate";
return options;
@@ -328,6 +323,7 @@ Interpreter Interpreter::fromURI(const std::string& uri) {
// try to establish URI root for relative src attributes in document
if (interpreter) {
interpreter._impl->_baseURI = URL::asBaseURL(absUrl);
+ interpreter._impl->_sourceURI = absUrl;
} else {
LOG(ERROR) << "Cannot create interpreter from URI '" << absUrl.asString() << "'";
}
@@ -1310,16 +1306,26 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node<std::string>& cont
if (content.getNodeType() != Node_base::ELEMENT_NODE)
return;
- if (false) {
- } else if (iequals(TAGNAME(content), _xmlNSPrefix + "onentry") ||
- iequals(TAGNAME(content), _xmlNSPrefix + "onexit") ||
- iequals(TAGNAME(content), _xmlNSPrefix + "finalize") ||
- iequals(TAGNAME(content), _xmlNSPrefix + "transition")) {
+ if (iequals(TAGNAME(content), _xmlNSPrefix + "onentry") ||
+ iequals(TAGNAME(content), _xmlNSPrefix + "onexit") ||
+ iequals(TAGNAME(content), _xmlNSPrefix + "finalize") ||
+ iequals(TAGNAME(content), _xmlNSPrefix + "transition")) {
// --- CONVENIENCE LOOP --------------------------
NodeList<std::string> executable = content.getChildNodes();
for (int i = 0; i < executable.getLength(); i++) {
executeContent(executable.item(i), rethrow);
}
+ return;
+ }
+
+ // --- MONITOR: beforeExecutingContent ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->beforeExecutingContent(shared_from_this(), content);
+ } USCXML_MONITOR_CATCH_BLOCK(beforeExecutingContent)
+ }
+
+ if (false) {
} else if (iequals(TAGNAME(content), _xmlNSPrefix + "raise")) {
// --- RAISE --------------------------
if (HAS_ATTR(content, "event")) {
@@ -1453,6 +1459,9 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node<std::string>& cont
}
} catch (Event exception) {
// script failed to download
+ if (exception.name == "error.communication") {
+ throw exception; // terminate test329
+ }
receive(exception);
return;
}
@@ -1526,6 +1535,14 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node<std::string>& cont
}
execContent.exitElement(content);
}
+
+ // --- MONITOR: afterExecutingContent ------------------------------
+ for(monIter_t monIter = _monitors.begin(); monIter != _monitors.end(); monIter++) {
+ try {
+ (*monIter)->afterExecutingContent(shared_from_this(), content);
+ } USCXML_MONITOR_CATCH_BLOCK(afterExecutingContent)
+ }
+
}
void InterpreterImpl::returnDoneEvent(const Arabica::DOM::Node<std::string>& state) {
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
index 94c5d74..f6b1783 100644
--- a/src/uscxml/Interpreter.h
+++ b/src/uscxml/Interpreter.h
@@ -98,7 +98,7 @@ enum Capabilities {
class USCXML_API InterpreterOptions {
public:
- bool useDot;
+ bool withDebugger;
bool verbose;
bool withHTTP;
bool withHTTPS;
@@ -126,7 +126,7 @@ public:
protected:
InterpreterOptions() :
- useDot(false),
+ withDebugger(false),
verbose(false),
withHTTP(true),
withHTTPS(true),
@@ -171,12 +171,19 @@ public:
_monitors.erase(monitor);
}
- void setBaseURI(std::string baseURI) {
- _baseURI = URL(baseURI);
+ void setSourceURI(std::string sourceURI) {
+ _sourceURI = URL(sourceURI);
+
+ URL baseURI(sourceURI);
+ URL::toBaseURL(baseURI);
+ _baseURI = baseURI;
}
URL getBaseURI() {
return _baseURI;
}
+ URL getSourceURI() {
+ return _sourceURI;
+ }
void setCmdLineOptions(std::map<std::string, std::string> params);
Data getCmdLineOptions() {
@@ -213,6 +220,11 @@ public:
return _nameSpaceInfo[ns] + ":";
return "";
}
+
+ Arabica::XPath::NodeSet<std::string> getNodeSetForXPath(const std::string& xpathExpr) {
+ return _xpath.evaluate(xpathExpr, _scxml).asNodeSet();
+ }
+
void setNameSpaceInfo(const std::map<std::string, std::string> nameSpaceInfo);
std::map<std::string, std::string> getNameSpaceInfo() {
return _nameSpaceInfo;
@@ -339,6 +351,7 @@ protected:
tthread::recursive_mutex _pluginMutex;
URL _baseURI;
+ URL _sourceURI;
Arabica::DOM::Document<std::string> _document;
Arabica::DOM::Element<std::string> _scxml;
Arabica::XPath::XPath<std::string> _xpath;
@@ -478,8 +491,11 @@ public:
return _impl->removeMonitor(monitor);
}
- void setBaseURI(std::string baseURI) {
- return _impl->setBaseURI(baseURI);
+ void setSourceURI(std::string sourceURI) {
+ return _impl->setSourceURI(sourceURI);
+ }
+ URL getSourceURI() {
+ return _impl->getSourceURI();
}
URL getBaseURI() {
return _impl->getBaseURI();
@@ -527,7 +543,10 @@ public:
std::string getXMLPrefixForNS(const std::string& ns) {
return _impl->getXMLPrefixForNS(ns);
}
-
+ Arabica::XPath::NodeSet<std::string> getNodeSetForXPath(const std::string& xpathExpr) {
+ return _impl->getNodeSetForXPath(xpathExpr);
+ }
+
void inline receiveInternal(const Event& event) {
return _impl->receiveInternal(event);
}
@@ -709,6 +728,9 @@ public:
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 beforeExecutingContent(Interpreter interpreter, const Arabica::DOM::Node<std::string>& content) {}
+ virtual void afterExecutingContent(Interpreter interpreter, const Arabica::DOM::Node<std::string>& content) {}
+
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) {}
diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp
index aeb0027..33dca84 100644
--- a/src/uscxml/Message.cpp
+++ b/src/uscxml/Message.cpp
@@ -430,6 +430,7 @@ Data Data::fromJSON(const std::string& jsonString) {
std::string value = trimmed.substr(t[currTok].start, t[currTok].end - t[currTok].start);
if (dataStack.back()->type == Data::VERBATIM) {
boost::replace_all(value, "\\\"", "\"");
+ boost::replace_all(value, "\\n", "\n");
}
dataStack.back()->atom = value;
dataStack.pop_back();
@@ -728,10 +729,11 @@ std::string Data::toJSON(const Data& data) {
// escape string
if (false) {
} else if (data.atom[i] == '"') {
- os << '\\';
- os << data.atom[i];
+ os << "\\\"";
} else if (data.atom[i] == '\n') {
os << "\\n";
+ } else if (data.atom[i] == '\t') {
+ os << "\\t";
} else {
os << data.atom[i];
}
@@ -746,6 +748,7 @@ std::string Data::toJSON(const Data& data) {
std::string xmlSer = xmlSerSS.str();
boost::replace_all(xmlSer, "\"", "\\\"");
boost::replace_all(xmlSer, "\n", "\\n");
+ boost::replace_all(xmlSer, "\t", "\\t");
os << "\"" << xmlSer << "\"";
} else {
if (data.type == Data::VERBATIM) {
diff --git a/src/uscxml/debug/Breakpoint.cpp b/src/uscxml/debug/Breakpoint.cpp
index f64efad..58cf295 100644
--- a/src/uscxml/debug/Breakpoint.cpp
+++ b/src/uscxml/debug/Breakpoint.cpp
@@ -19,10 +19,12 @@
#include "uscxml/debug/Breakpoint.h"
#include "uscxml/Interpreter.h"
+#include "uscxml/DOMUtils.h"
namespace uscxml {
Breakpoint::Breakpoint(const Data& data) {
+ enabled = true;
subject = UNDEF_SUBJECT;
when = UNDEF_WHEN;
action = UNDEF_ACTION;
@@ -65,7 +67,7 @@ Breakpoint::Breakpoint(const Data& data) {
subject = EVENT;
} else if (data["subject"].atom == "invoker") {
subject = INVOKER;
- } else if (data["subject"].atom == "exec") {
+ } else if (data["subject"].atom == "executable") {
subject = EXECUTABLE;
}
}
@@ -82,6 +84,12 @@ Breakpoint::Breakpoint(const Data& data) {
if (data.hasKey("eventName"))
eventName = data["eventName"].atom;
+ if (data.hasKey("executableName"))
+ executableName = data["executableName"].atom;
+
+ if (data.hasKey("executableXPath"))
+ executableXPath = data["executableXPath"].atom;
+
if (data.hasKey("stateId"))
stateId = data["stateId"].atom;
@@ -116,7 +124,7 @@ Data Breakpoint::toData() const {
data.compound["subject"] = Data("invoker", Data::VERBATIM);
break;
case EXECUTABLE:
- data.compound["subject"] = Data("exec", Data::VERBATIM);
+ data.compound["subject"] = Data("executable", Data::VERBATIM);
break;
default:
break;
@@ -162,6 +170,16 @@ Data Breakpoint::toData() const {
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);
@@ -177,34 +195,31 @@ Data Breakpoint::toData() const {
return data;
}
-bool Breakpoint::matches(const Breakpoint& other) const {
+bool Breakpoint::matches(Interpreter interpreter, 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)) {
+ if(invokeId.length() > 0 && invokeId != other.invokeId) {
return false;
}
- if(invokeType.length() > 0 && !InterpreterImpl::nameMatch(invokeType, other.invokeType)) {
+ if(invokeType.length() > 0 && invokeType != other.invokeType) {
return false;
}
- if(stateId.length() > 0 && !InterpreterImpl::nameMatch(stateId, other.stateId)) {
+ if(stateId.length() > 0 && stateId != other.stateId) {
return false;
}
@@ -212,19 +227,39 @@ bool Breakpoint::matches(const Breakpoint& other) const {
return false;
}
- if(transSource.length() > 0 && !InterpreterImpl::nameMatch(transSource, other.transSource)) {
+ if(executableName.length() > 0 && executableName != other.executableName) {
return false;
}
- if(transTarget.length() > 0 && !InterpreterImpl::nameMatch(transTarget, other.transTarget)) {
+ if(executableXPath.length()) {
+ Arabica::XPath::NodeSet<std::string> nodes;
+ try {
+ nodes = interpreter.getNodeSetForXPath(executableXPath);
+ } catch (...) {
+ return false;
+ }
+ return Interpreter::isMember(other.element, nodes);
+ }
+
+ if(transSource.length() > 0 && transSource != other.transSource) {
return false;
}
-
- return true;
-}
+ if(transTarget.length() > 0 && transTarget != other.transTarget) {
+ return false;
+ }
-bool Breakpoint::isValid() {
+ if (condition.length() > 0) {
+ try {
+ DataModel dm = interpreter.getDataModel();
+ if (!dm || !dm.evalAsBool(condition)) {
+ return false;
+ }
+ } catch (...) {
+ return false;
+ }
+ }
+
return true;
}
diff --git a/src/uscxml/debug/Breakpoint.h b/src/uscxml/debug/Breakpoint.h
index b2861d8..cd6fea5 100644
--- a/src/uscxml/debug/Breakpoint.h
+++ b/src/uscxml/debug/Breakpoint.h
@@ -21,6 +21,7 @@
#define BREAKPOINT_H_VR7K7T1X
#include "uscxml/Message.h"
+#include "uscxml/Interpreter.h"
namespace uscxml {
@@ -39,35 +40,49 @@ public:
UNDEF_ACTION, ENTER, EXIT, INVOKE, UNINVOKE
};
- Breakpoint() {}
+ Breakpoint() {
+ subject = UNDEF_SUBJECT;
+ when = UNDEF_WHEN;
+ action = UNDEF_ACTION;
+ }
Breakpoint(const Data& data);
// would we match the given breakpoint as well?
- bool matches(const Breakpoint& other) const;
-
- bool isValid();
-
+ bool matches(Interpreter interpreter, const Breakpoint& other) const;
+
Data toData() const;
bool operator<(const Breakpoint& other) const {
- return (origData < other.origData);
+ 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;
+ Arabica::DOM::Element<std::string> element;
+
std::string invokeId;
std::string invokeType;
std::string eventName;
+ std::string executableName;
+ std::string executableXPath;
+
std::string stateId;
std::string transSource;
std::string transTarget;
std::string condition;
- Data origData;
};
}
diff --git a/src/uscxml/debug/DebugSession.cpp b/src/uscxml/debug/DebugSession.cpp
new file mode 100644
index 0000000..46b414f
--- /dev/null
+++ b/src/uscxml/debug/DebugSession.cpp
@@ -0,0 +1,378 @@
+/**
+ * @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"
+
+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) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+
+ Arabica::XPath::NodeSet<std::string> basicConf = _interpreter.getBasicConfiguration();
+ for (int i = 0; i < basicConf.size(); i++) {
+ Arabica::DOM::Element<std::string> element = Arabica::DOM::Element<std::string>(basicConf[i]);
+ if (element.hasAttribute("id")) {
+ replyData.compound["basicStates"].array.push_back(Data(element.getAttribute("id"), Data::VERBATIM));
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> activeConf = _interpreter.getConfiguration();
+ for (int i = 0; i < activeConf.size(); i++) {
+ Arabica::DOM::Element<std::string> element = Arabica::DOM::Element<std::string>(activeConf[i]);
+ if (element.hasAttribute("id")) {
+ replyData.compound["activeStates"].array.push_back(Data(element.getAttribute("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["xml"].atom);
+ } else if (data.hasKey("url")) {
+ _interpreter = Interpreter::fromURI(data["url"].atom);
+ } else {
+ _interpreter = Interpreter();
+ }
+
+ if (_interpreter) {
+ // register ourself as a monitor
+ _interpreter.addMonitor(_debugger);
+ _debugger->attachSession(_interpreter, shared_from_this());
+ if (data.hasKey("url")) {
+ // this allows to resolve relative external reources
+ _interpreter.setSourceURI(data["url"].atom);
+ }
+ 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["attach"].atom;
+ bool interpreterFound = false;
+
+ // find interpreter for sessionid
+ std::map<std::string, boost::weak_ptr<InterpreterImpl> > instances = Interpreter::getInstances();
+ for (std::map<std::string, boost::weak_ptr<InterpreterImpl> >::iterator instIter = instances.begin();
+ instIter != instances.end();
+ instIter++) {
+
+ boost::shared_ptr<InterpreterImpl> instance = instIter->second.lock();
+ if (instance && instance->getSessionId() == interpreterId) {
+ _interpreter = instance;
+ _debugger->attachSession(_interpreter, 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.getDocument();
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ }
+
+ return replyData;
+}
+
+Data DebugSession::debugDetach(const Data& data) {
+ Data replyData;
+ _isAttached = false;
+
+ _debugger->detachSession(_interpreter);
+ 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();
+ 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);
+ }
+
+ if (_interpreter && !_isAttached)
+ _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) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+
+ stepping(true);
+ _resumeCond.notify_one();
+
+ Data replyData;
+ if (_interpreter) {
+ // register ourself as a monitor
+ if (!_interpreter.isRunning())
+ _interpreter.start();
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
+ } else {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ }
+ return replyData;
+}
+
+Data DebugSession::debugResume(const Data& data) {
+ tthread::lock_guard<tthread::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) {
+ tthread::lock_guard<tthread::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) {
+ tthread::lock_guard<tthread::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["expression"].atom;
+
+ 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 {
+ 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);
+ }
+ 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..12f1d93
--- /dev/null
+++ b/src/uscxml/debug/DebugSession.h
@@ -0,0 +1,99 @@
+/**
+ * @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>
+
+namespace uscxml {
+
+class Debugger;
+
+class USCXML_API DebugSession : public boost::enable_shared_from_this<DebugSession> {
+public:
+ DebugSession() {
+ _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;
+
+ tthread::condition_variable _resumeCond;
+ tthread::recursive_mutex _runMutex;
+ tthread::recursive_mutex _mutex;
+
+ bool _markedForDeletion;
+ Debugger* _debugger;
+ Interpreter _interpreter;
+ std::set<Breakpoint> _breakPoints;
+ Breakpoint _skipTo;
+
+};
+
+
+}
+
+
+#endif /* end of include guard: DEBUGSESSION_H_M8YHEGV6 */
diff --git a/src/uscxml/debug/Debugger.cpp b/src/uscxml/debug/Debugger.cpp
index aa97a22..3a19228 100644
--- a/src/uscxml/debug/Debugger.cpp
+++ b/src/uscxml/debug/Debugger.cpp
@@ -23,9 +23,13 @@
namespace uscxml {
void Debugger::afterCompletion(Interpreter interpreter) {
+ boost::shared_ptr<DebugSession> session = getSession(interpreter);
+ if (!session)
+ return;
+
Data msg;
msg.compound["replyType"] = Data("finished", Data::VERBATIM);
- pushData(msg);
+ pushData(session, msg);
}
std::list<Breakpoint> getQualifiedStateBreakpoints(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, Breakpoint breakpointTemplate) {
@@ -33,6 +37,7 @@ std::list<Breakpoint> getQualifiedStateBreakpoints(Interpreter interpreter, cons
Breakpoint bp = breakpointTemplate; // copy base as template
bp.stateId = ATTR(state, "id");
+ bp.element = state;
bp.subject = Breakpoint::STATE;
breakpoints.push_back(bp);
@@ -44,6 +49,7 @@ std::list<Breakpoint> getQualifiedInvokeBreakpoints(Interpreter interpreter, con
Breakpoint bp = breakpointTemplate; // copy base as template
bp.subject = Breakpoint::INVOKER;
+ bp.element = invokeElem;
bp.invokeId = invokeId;
if (HAS_ATTR(invokeElem, "type")) {
@@ -67,6 +73,7 @@ std::list<Breakpoint> getQualifiedTransBreakpoints(Interpreter interpreter, cons
Arabica::DOM::Element<std::string> target(targets[j]);
Breakpoint bp = breakpointTemplate; // copy base as template
+ bp.element = transition;
bp.transSource = ATTR(source, "id");
bp.transTarget = ATTR(target, "id");
bp.subject = Breakpoint::TRANSITION;
@@ -83,6 +90,12 @@ void Debugger::beforeTakingTransition(Interpreter interpreter, const Arabica::DO
void Debugger::afterTakingTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition) {
handleTransition(interpreter, transition, Breakpoint::AFTER);
}
+void Debugger::beforeExecutingContent(Interpreter interpreter, const Arabica::DOM::Node<std::string>& content) {
+ handleExecutable(interpreter, Arabica::DOM::Element<std::string>(content), Breakpoint::BEFORE);
+}
+void Debugger::afterExecutingContent(Interpreter interpreter, const Arabica::DOM::Node<std::string>& content) {
+ handleExecutable(interpreter, Arabica::DOM::Element<std::string>(content), Breakpoint::AFTER);
+}
void Debugger::beforeExitingState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state) {
handleState(interpreter, state, Breakpoint::BEFORE, Breakpoint::EXIT);
}
@@ -120,9 +133,34 @@ void Debugger::beforeProcessingEvent(Interpreter interpreter, const Event& event
handleEvent(interpreter, event, Breakpoint::BEFORE);
}
+void Debugger::handleExecutable(Interpreter interpreter,
+ const Arabica::DOM::Element<std::string>& execContentElem,
+ Breakpoint::When when) {
+ if (!interpreter.isRunning())
+ return;
+ boost::shared_ptr<DebugSession> session = getSession(interpreter);
+ if (!session)
+ return;
+
+ std::list<Breakpoint> breakpoints;
+
+ Breakpoint breakpoint;
+ breakpoint.when = when;
+ breakpoint.element = execContentElem;
+ breakpoint.executableName = execContentElem.getLocalName();
+ breakpoint.subject = Breakpoint::EXECUTABLE;
+ breakpoints.push_back(breakpoint);
+
+ session->checkBreakpoints(breakpoints);
+
+}
+
void Debugger::handleEvent(Interpreter interpreter, const Event& event, Breakpoint::When when) {
if (!interpreter.isRunning())
return;
+ boost::shared_ptr<DebugSession> session = getSession(interpreter);
+ if (!session)
+ return;
std::list<Breakpoint> breakpoints;
@@ -132,13 +170,16 @@ void Debugger::handleEvent(Interpreter interpreter, const Event& event, Breakpoi
breakpoint.subject = Breakpoint::EVENT;
breakpoints.push_back(breakpoint);
- checkBreakpoints(interpreter, breakpoints);
+ session->checkBreakpoints(breakpoints);
}
void Debugger::handleStable(Interpreter interpreter, Breakpoint::When when) {
if (!interpreter.isRunning())
return;
+ boost::shared_ptr<DebugSession> session = getSession(interpreter);
+ if (!session)
+ return;
std::list<Breakpoint> breakpoints;
@@ -147,13 +188,16 @@ void Debugger::handleStable(Interpreter interpreter, Breakpoint::When when) {
breakpoint.subject = Breakpoint::STABLE;
breakpoints.push_back(breakpoint);
- checkBreakpoints(interpreter, breakpoints);
+ session->checkBreakpoints(breakpoints);
}
void Debugger::handleMicrostep(Interpreter interpreter, Breakpoint::When when) {
if (!interpreter.isRunning())
return;
-
+ boost::shared_ptr<DebugSession> session = getSession(interpreter);
+ if (!session)
+ return;
+
std::list<Breakpoint> breakpoints;
Breakpoint breakpoint;
@@ -161,86 +205,50 @@ void Debugger::handleMicrostep(Interpreter interpreter, Breakpoint::When when) {
breakpoint.subject = Breakpoint::MICROSTEP;
breakpoints.push_back(breakpoint);
- checkBreakpoints(interpreter, breakpoints);
+ session->checkBreakpoints(breakpoints);
}
void Debugger::handleTransition(Interpreter interpreter, const Arabica::DOM::Element<std::string>& transition, Breakpoint::When when) {
if (!interpreter.isRunning())
return;
+ boost::shared_ptr<DebugSession> session = getSession(interpreter);
+ if (!session)
+ return;
Breakpoint breakpointTemplate;
breakpointTemplate.when = when;
std::list<Breakpoint> qualifiedBreakpoints = getQualifiedTransBreakpoints(interpreter, transition, breakpointTemplate);
- checkBreakpoints(interpreter, qualifiedBreakpoints);
+ session->checkBreakpoints(qualifiedBreakpoints);
}
void Debugger::handleState(Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, Breakpoint::When when, Breakpoint::Action action) {
if (!interpreter.isRunning())
return;
+ boost::shared_ptr<DebugSession> session = getSession(interpreter);
+ if (!session)
+ return;
Breakpoint breakpointTemplate;
breakpointTemplate.when = when;
breakpointTemplate.action = action;
std::list<Breakpoint> qualifiedBreakpoints = getQualifiedStateBreakpoints(interpreter, state, breakpointTemplate);
- checkBreakpoints(interpreter, qualifiedBreakpoints);
+ session->checkBreakpoints(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;
+ boost::shared_ptr<DebugSession> session = getSession(interpreter);
+ if (!session)
+ 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);
- }
- }
-}
+ session->checkBreakpoints(qualifiedBreakpoints);
-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);
}
diff --git a/src/uscxml/debug/Debugger.h b/src/uscxml/debug/Debugger.h
index dfc197d..c49e90f 100644
--- a/src/uscxml/debug/Debugger.h
+++ b/src/uscxml/debug/Debugger.h
@@ -23,45 +23,40 @@
#include "uscxml/Message.h"
#include "uscxml/Interpreter.h"
#include "uscxml/debug/Breakpoint.h"
-
-#include <glog/logging.h>
+#include "uscxml/debug/DebugSession.h"
namespace uscxml {
-class USCXML_API Debugger : public InterpreterMonitor, public google::LogSink {
+class USCXML_API Debugger : public InterpreterMonitor {
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;
+ virtual void attachSession(Interpreter interpreter, boost::shared_ptr<DebugSession> session) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_sessionMutex);
+ _sessionForInterpreter[interpreter] = session;
+ }
+
+ virtual void detachSession(Interpreter interpreter) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_sessionMutex);
+ _sessionForInterpreter.erase(interpreter);
+ }
- void stepping(bool enable) {
- _isStepping = enable;
+ virtual boost::shared_ptr<DebugSession> getSession(Interpreter interpreter) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_sessionMutex);
+ if (_sessionForInterpreter.find(interpreter) != _sessionForInterpreter.end())
+ return _sessionForInterpreter[interpreter];
+ return boost::shared_ptr<DebugSession>();
}
+ virtual void pushData(boost::shared_ptr<DebugSession> session, Data pushData) = 0;
+
// InterpreterMonitor
virtual void beforeProcessingEvent(Interpreter interpreter, const Event& event);
virtual void beforeMicroStep(Interpreter interpreter);
+ virtual void beforeExecutingContent(Interpreter interpreter, const Arabica::DOM::Node<std::string>& content);
+ virtual void afterExecutingContent(Interpreter interpreter, const Arabica::DOM::Node<std::string>& content);
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);
@@ -79,12 +74,6 @@ public:
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,
@@ -99,14 +88,15 @@ protected:
const std::string& invokeId,
Breakpoint::When when,
Breakpoint::Action action);
+ void handleExecutable(Interpreter interpreter,
+ const Arabica::DOM::Element<std::string>& execContentElem,
+ Breakpoint::When when);
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;
-
+ tthread::recursive_mutex _sessionMutex;
+ std::map<Interpreter, boost::shared_ptr<DebugSession> > _sessionForInterpreter;
};
}
diff --git a/src/uscxml/debug/DebuggerServlet.cpp b/src/uscxml/debug/DebuggerServlet.cpp
index e179b8c..55ced75 100644
--- a/src/uscxml/debug/DebuggerServlet.cpp
+++ b/src/uscxml/debug/DebuggerServlet.cpp
@@ -23,25 +23,30 @@
namespace uscxml {
-void DebuggerServlet::pushData(Data pushData) {
+void DebuggerServlet::pushData(boost::shared_ptr<DebugSession> session, Data pushData) {
std::cout << "trying to push " << pushData["replyType"].atom << std::endl;
- _sendQueue.push(pushData);
- serverPushData();
+
+ 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() {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
- if (_sendQueue.isEmpty())
+void DebuggerServlet::serverPushData(boost::shared_ptr<DebugSession> session) {
+ if (_sendQueues[session].isEmpty())
return;
- if (!_clientConn)
+ if (!_clientConns[session])
return;
- Data reply = _sendQueue.pop();
+ Data reply = _sendQueues[session].pop();
std::cout << "pushing " << reply["replyType"].atom << std::endl;
- returnData(_clientConn, reply);
- _clientConn = HTTPServer::Request();
+ returnData(_clientConns[session], reply);
+ _clientConns[session] = HTTPServer::Request();
}
void DebuggerServlet::returnData(const HTTPServer::Request& request, Data replyData) {
@@ -56,17 +61,6 @@ void DebuggerServlet::returnData(const HTTPServer::Request& request, Data replyD
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" &&
@@ -101,220 +95,164 @@ bool DebuggerServlet::httpRecvRequest(const HTTPServer::Request& request) {
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::starts_with(request.data["path"].atom, "/poll")) {
- processPoll(request);
- } else if (boost::starts_with(request.data["path"].atom, "/connect")) {
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/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")) {
+ return true;
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/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);
+ return true;
+ }
+
+ // get session or return error
+ if (false) {
+ } else if (!request.data["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["content"]["session"].atom) == _sessionForId.end()) {
+ replyData.compound["status"] = Data("failure", Data::VERBATIM);
+ replyData.compound["reason"] = Data("No such session", Data::VERBATIM);
+ }
+ if (replyData) {
+ returnData(request, replyData);
+ return true;
+ }
+
+ boost::shared_ptr<DebugSession> session = _sessionForId[request.data["content"]["session"].atom];
+
+ if (false) {
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/poll")) {
+ // save long-standing client poll
+ _clientConns[session] = request;
+ serverPushData(session);
+
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/disconnect")) {
+ processDisconnect(request);
+
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/enable/all")) {
+ replyData = session->enableAllBreakPoints();
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/disable/all")) {
+ replyData = session->disableAllBreakPoints();
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/skipto")) {
+ replyData = session->skipToBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/add")) {
+ replyData = session->addBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/remove")) {
+ replyData = session->removeBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/enable")) {
+ replyData = session->enableBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/breakpoint/disable")) {
+ replyData = session->disableBreakPoint(request.data["content"]);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/stop")) {
+ replyData = session->debugStop(request.data["content"]);
} else if (boost::starts_with(request.data["path"].atom, "/debug/prepare")) {
- processDebugPrepare(request);
+ replyData = session->debugPrepare(request.data["content"]);
+ } else if (boost::starts_with(request.data["path"].atom, "/debug/attach")) {
+ replyData = session->debugAttach(request.data["content"]);
} 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);
+ replyData = session->debugStart(request.data["content"]);
} else if (boost::starts_with(request.data["path"].atom, "/debug/step")) {
- processDebugStep(request);
+ replyData = session->debugStep(request.data["content"]);
} else if (boost::starts_with(request.data["path"].atom, "/debug/pause")) {
- processDebugPause(request);
+ replyData = session->debugPause(request.data["content"]);
} else if (boost::starts_with(request.data["path"].atom, "/debug/resume")) {
- processDebugResume(request);
+ replyData = session->debugResume(request.data["content"]);
} else if (boost::starts_with(request.data["path"].atom, "/debug/eval")) {
- processDebugEval(request);
+ replyData = session->debugEval(request.data["content"]);
}
- 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);
+ if (replyData) {
+ returnData(request, replyData);
+ return true;
}
- returnData(request, replyData);
+
+ return true;
}
-void DebuggerServlet::processDebugStart(const HTTPServer::Request& request) {
+// someone connected, create a new session
+void DebuggerServlet::processConnect(const HTTPServer::Request& request) {
tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+ std::string sessionId = UUID::getUUID();
+
+ _sessionForId[sessionId] = boost::shared_ptr<DebugSession>(new DebugSession());
+ _sessionForId[sessionId]->setDebugger(this);
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);
- }
+ replyData.compound["session"] = Data(sessionId, Data::VERBATIM);
+ replyData.compound["status"] = Data("success", Data::VERBATIM);
returnData(request, replyData);
}
-void DebuggerServlet::processDebugStop(const HTTPServer::Request& request) {
-// tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
- stepping(false);
+void DebuggerServlet::processDisconnect(const HTTPServer::Request& request) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
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()) {
+ if (!request.data["content"].hasKey("session")) {
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);
+ replyData.compound["reason"] = Data("No session given", Data::VERBATIM);
+ returnData(request, replyData);
}
- returnData(request, replyData);
-}
-void DebuggerServlet::processDebugStep(const HTTPServer::Request& request) {
- tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+ std::string sessionId = request.data["content"]["session"].atom;
- 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 {
+ 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());
+ _sessionForId[sessionId]->debugStop(request.data["content"]);
+ _clientConns.erase(_sessionForId[sessionId]);
+ _sendQueues.erase(_sessionForId[sessionId]);
+ _sessionForId.erase(sessionId);
}
- 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);
+
+ std::map<std::string, boost::weak_ptr<InterpreterImpl> > instances = Interpreter::getInstances();
+ for (std::map<std::string, boost::weak_ptr<InterpreterImpl> >::iterator instIter = instances.begin();
+ instIter != instances.end();
+ instIter++) {
+
+ boost::shared_ptr<InterpreterImpl> instance = instIter->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->getSourceURI().asString(), Data::VERBATIM);
+ sessionData.compound["xml"].node = instance->getDocument();
+
+ replyData.compound["sessions"].array.push_back(sessionData);
}
- } else {
- replyData.compound["status"] = Data("failure", Data::VERBATIM);
}
+
+ replyData.compound["status"] = Data("success", 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);
+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(boost::shared_ptr<DebugSession>(), msg);
}
diff --git a/src/uscxml/debug/DebuggerServlet.h b/src/uscxml/debug/DebuggerServlet.h
index 5cd0be9..ae5178f 100644
--- a/src/uscxml/debug/DebuggerServlet.h
+++ b/src/uscxml/debug/DebuggerServlet.h
@@ -22,6 +22,7 @@
#include "uscxml/Common.h"
#include "getopt.h"
+#include <glog/logging.h>
#include "uscxml/server/HTTPServer.h"
#include "uscxml/Interpreter.h"
@@ -31,8 +32,25 @@
namespace uscxml {
-class USCXML_API DebuggerServlet : public Debugger, public HTTPServlet {
+class USCXML_API DebuggerServlet : public Debugger, public HTTPServlet, public google::LogSink {
public:
+ 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 ~DebuggerServlet() {}
// from Debugger
@@ -46,36 +64,43 @@ public:
_url = url;
}
- void pushData(Data pushData);
+ void pushData(boost::shared_ptr<DebugSession> session, 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 processDisconnect(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);
+
+// 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();
+ void serverPushData(boost::shared_ptr<DebugSession>);
- Interpreter _interpreter;
- std::string _sessionId;
std::string _url;
- HTTPServer::Request _clientConn;
- tthread::condition_variable _resumeCond;
+ std::map<boost::shared_ptr<DebugSession>, HTTPServer::Request> _clientConns;
+ std::map<boost::shared_ptr<DebugSession>, concurrency::BlockingQueue<Data> > _sendQueues;
+ std::map<std::string, boost::shared_ptr<DebugSession> > _sessionForId;
+
tthread::recursive_mutex _mutex;
- concurrency::BlockingQueue<Data> _sendQueue;
};
}
diff --git a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp
index 51e1e28..085d919 100644
--- a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp
+++ b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp
@@ -263,7 +263,7 @@ void BasicHTTPIOProcessor::downloadCompleted(const URL& url) {
std::map<std::string, std::pair<URL, SendRequest> >::iterator reqIter = _sendRequests.begin();
while(reqIter != _sendRequests.end()) {
if (reqIter->second.first == url) {
- // test 513
+ // test513
std::string statusCode = url.getStatusCode();
if (statusCode.length() > 0) {
std::string statusPrefix = statusCode.substr(0,1);
diff --git a/src/uscxml/server/HTTPServer.cpp b/src/uscxml/server/HTTPServer.cpp
index 6c26811..69096fc 100644
--- a/src/uscxml/server/HTTPServer.cpp
+++ b/src/uscxml/server/HTTPServer.cpp
@@ -105,7 +105,7 @@ HTTPServer::HTTPServer(unsigned short port, unsigned short wsPort, SSLConfig* ss
LOG(ERROR) << "HTTP server cannot bind to tcp/" << _port;
}
}
-
+
_wsPort = wsPort;
if (_wsPort > 0) {
_wsHandle = evws_bind_socket(_evws, _wsPort);