summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-07-21 11:34:44 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-07-21 11:34:44 (GMT)
commitdc5f5ddfa10bf91524e6f7555c263eaea069dcb0 (patch)
tree576b15e7fe75476e8ece954b52aa88871941beb5
parent641117e7400e9e5ef0fa451f732eb9009f0914cb (diff)
downloaduscxml-dc5f5ddfa10bf91524e6f7555c263eaea069dcb0.zip
uscxml-dc5f5ddfa10bf91524e6f7555c263eaea069dcb0.tar.gz
uscxml-dc5f5ddfa10bf91524e6f7555c263eaea069dcb0.tar.bz2
try / catch blocks for applications and work on dot output
-rw-r--r--apps/uscxml-browser.cpp80
-rw-r--r--apps/uscxml-dot.cpp92
-rw-r--r--apps/uscxml-transform.cpp63
-rw-r--r--embedding/java/src/org/uscxml/tests/monitor/TestCustomMonitor.java51
-rw-r--r--src/uscxml/Interpreter.cpp3
-rw-r--r--src/uscxml/UUID.cpp36
-rw-r--r--src/uscxml/UUID.h1
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.cpp531
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.h67
-rw-r--r--src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp9
-rw-r--r--test/CMakeLists.txt5
-rw-r--r--test/src/test-vxml-mmi-socket.cpp72
12 files changed, 671 insertions, 339 deletions
diff --git a/apps/uscxml-browser.cpp b/apps/uscxml-browser.cpp
index e431fdf..f9a06bb 100644
--- a/apps/uscxml-browser.cpp
+++ b/apps/uscxml-browser.cpp
@@ -173,52 +173,60 @@ int main(int argc, char** argv) {
std::string documentURL = options.interpreters[0].first;
LOG(INFO) << "Processing " << documentURL;
- Interpreter interpreter = Interpreter::fromURI(documentURL);
- if (interpreter) {
- interpreter.setCmdLineOptions(currOptions->additionalParameters);
- interpreter.setCapabilities(options.getCapabilities());
-
- if (options.verbose) {
- VerboseMonitor* vm = new VerboseMonitor();
- interpreter.addMonitor(vm);
- }
- if (options.withDebugger) {
- interpreter.addMonitor(debugger);
- }
- interpreters.push_back(interpreter);
+ try {
+ Interpreter interpreter = Interpreter::fromURI(documentURL);
+ if (interpreter) {
+ interpreter.setCmdLineOptions(currOptions->additionalParameters);
+ interpreter.setCapabilities(options.getCapabilities());
- } else {
- LOG(ERROR) << "Cannot create interpreter from " << documentURL;
+ if (options.verbose) {
+ VerboseMonitor* vm = new VerboseMonitor();
+ interpreter.addMonitor(vm);
+ }
+ if (options.withDebugger) {
+ interpreter.addMonitor(debugger);
+ }
+
+ interpreters.push_back(interpreter);
+
+ } else {
+ LOG(ERROR) << "Cannot create interpreter from " << documentURL;
+ }
+ } catch (Event e) {
+ std::cout << e << std::endl;
}
}
// start interpreters
- std::list<Interpreter>::iterator interpreterIter = interpreters.begin();
- while(interpreterIter != interpreters.end()) {
- interpreterIter->start();
- interpreterIter++;
- }
-
- bool stillRunning = true;
- // call from main thread for UI events
- while(interpreters.size() > 0) {
- interpreterIter = interpreters.begin();
+ try {
+ std::list<Interpreter>::iterator interpreterIter = interpreters.begin();
while(interpreterIter != interpreters.end()) {
- stillRunning = interpreterIter->runOnMainThread(25);
- if (!stillRunning) {
- interpreters.erase(interpreterIter++);
- } else {
- interpreterIter++;
+ interpreterIter->start();
+ interpreterIter++;
+ }
+
+ bool stillRunning = true;
+ // call from main thread for UI events
+ while(interpreters.size() > 0) {
+ interpreterIter = interpreters.begin();
+ while(interpreterIter != interpreters.end()) {
+ stillRunning = interpreterIter->runOnMainThread(25);
+ if (!stillRunning) {
+ interpreters.erase(interpreterIter++);
+ } else {
+ interpreterIter++;
+ }
}
}
- }
- if (options.withDebugger) {
- // idle and wait for CTRL+C or debugging events
- while(true)
- tthread::this_thread::sleep_for(tthread::chrono::seconds(1));
+ if (options.withDebugger) {
+ // idle and wait for CTRL+C or debugging events
+ while(true)
+ tthread::this_thread::sleep_for(tthread::chrono::seconds(1));
+ }
+ } catch (Event e) {
+ std::cout << e << std::endl;
}
-
return EXIT_SUCCESS;
} \ No newline at end of file
diff --git a/apps/uscxml-dot.cpp b/apps/uscxml-dot.cpp
index 3324e54..56f5c57 100644
--- a/apps/uscxml-dot.cpp
+++ b/apps/uscxml-dot.cpp
@@ -7,6 +7,7 @@
#include "uscxml/Factory.h"
#include <boost/algorithm/string.hpp>
+
using namespace uscxml;
void printUsageAndExit(const char* progName) {
@@ -19,12 +20,17 @@ void printUsageAndExit(const char* progName) {
printf("%s version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n", progStr.c_str());
printf("Usage\n");
printf("\t%s", progStr.c_str());
- printf(" [-dN_0] URL");
- printf(" [[-dN_1] state_id1] .. [[-dN_M] state_idM]");
+ printf(" [-eTYPE] [-dN] [-tN] URL");
+ printf(" [[-dN] [-tN] [-eTYPE] state_id1] .. [[-dN] [-tN] [-eTYPE] state_idM]");
printf("\n");
printf("Options\n");
printf("\tURL : URL of SCXML document\n");
+ printf("\t-e TYPE : type of edges to use:\n");
+ printf("\t 'target' - aggregate per target node (default)\n");
+ printf("\t 'event' - aggregate per event name\n");
+ printf("\t 'transition' no aggregation, display each transition\n");
printf("\t-d : depth below anchor node (INF per default)\n");
+ printf("\t-t : transition depth below anchor (INF per default)\n");
printf("\tstate_id : anchor node state id (topmost scxml element per default)\n");
printf("\n");
exit(1);
@@ -32,9 +38,9 @@ void printUsageAndExit(const char* progName) {
int currOpt = 1;
-int consumeDepthOption(int argc, char** argv) {
+int32_t consumeNumericOption(int argc, char** argv, const std::string& name, int32_t defaultVal) {
std::string test = argv[currOpt];
- if (boost::starts_with(test, "-")) {
+ if (boost::starts_with(test, std::string("-") + name)) {
int value = 0;
if (test.size() > 2) {
// no space before value
@@ -52,7 +58,7 @@ int consumeDepthOption(int argc, char** argv) {
return value;
}
- return -1;
+ return defaultVal;
}
int main(int argc, char** argv) {
@@ -61,43 +67,69 @@ int main(int argc, char** argv) {
google::LogToStderr();
google::InitGoogleLogging(argv[0]);
- std::list<SCXMLDotWriter::StateAnchor> stateAnchors;
-
+
if (argc < 2)
printUsageAndExit(argv[0]);
- try {
- // see if there is an initial depth given for root
- int depth = consumeDepthOption(argc, argv);
- if (depth >= 0) {
- SCXMLDotWriter::StateAnchor anchor;
- anchor.depth = depth;
- stateAnchors.push_back(anchor);
+ std::list<SCXMLDotWriter::StateAnchor> stateAnchors;
+ SCXMLDotWriter::StateAnchor currAnchor;
+
+ int option;
+ while ((option = getopt(argc, argv, "d:t:")) != -1) {
+ switch(option) {
+ case 'd': currAnchor.childDepth = strTo<int32_t>(optarg); break;
+ case 't': currAnchor.transDepth = strTo<int32_t>(optarg); break;
+ case 'e': {
+ std::string edgeType(optarg);
+ if (edgeType == "target") {
+ currAnchor.type = SCXMLDotWriter::PORT_TARGET;
+ } else if (edgeType == "event") {
+ currAnchor.type = SCXMLDotWriter::PORT_EVENT;
+ } else if (edgeType == "transition") {
+ currAnchor.type = SCXMLDotWriter::PORT_TRANSITION;
+ } else {
+ printUsageAndExit(argv[0]);
+ }
+ break;
+ }
+ default: break;
}
+ }
+
+ if (currAnchor)
+ stateAnchors.push_back(currAnchor);
+ try {
// current option has to be the interpreter's name
- URL inputFile(argv[currOpt++]);
+ URL inputFile(argv[optind]);
Interpreter interpreter = Interpreter::fromURI(inputFile);
-
- for (; currOpt < argc; currOpt++) {
- SCXMLDotWriter::StateAnchor anchor;
- depth = consumeDepthOption(argc, argv);
-
- if (depth >= 0) {
- anchor.depth = depth;
+ optind++;
+
+ while(optind < argc) {
+ // are
+ while ((option = getopt(argc, argv, "d:t:")) != -1) {
+ switch(option) {
+ case 'd': currAnchor.childDepth = strTo<int32_t>(optarg); break;
+ case 't': currAnchor.transDepth = strTo<int32_t>(optarg); break;
+ default: break;
+ }
}
-
- if (argc > currOpt) {
- std::string expr(argv[currOpt++]);
- anchor.element = interpreter.getImpl()->getState(expr);
+ if (argc > optind) {
+ std::string expr(argv[optind++]);
+ currAnchor.element = interpreter.getImpl()->getState(expr);
} else {
printUsageAndExit(argv[0]);
}
-
- stateAnchors.push_back(anchor);
+
+ if (currAnchor) {
+ stateAnchors.push_back(currAnchor);
+ }
+
+ currAnchor = SCXMLDotWriter::StateAnchor();
}
-
- SCXMLDotWriter::toDot("machine.dot", interpreter, stateAnchors);
+
+ std::string outName = inputFile.file() + ".dot";
+ SCXMLDotWriter::toDot(outName, interpreter, stateAnchors);
} catch(Event e) {
std::cerr << e << std::cout;
diff --git a/apps/uscxml-transform.cpp b/apps/uscxml-transform.cpp
index d0c3524..245a89c 100644
--- a/apps/uscxml-transform.cpp
+++ b/apps/uscxml-transform.cpp
@@ -161,41 +161,44 @@ int main(int argc, char** argv) {
HTTPServer::getInstance(30444, 30445, NULL);
Interpreter interpreter;
- if (inputFile.size() == 0 || inputFile == "-") {
- LOG(INFO) << "Reading SCXML from STDIN";
- std::stringstream ss;
- std::string line;
- while (std::getline(std::cin, line)) {
- ss << line;
+ try {
+ if (inputFile.size() == 0 || inputFile == "-") {
+ LOG(INFO) << "Reading SCXML from STDIN";
+ std::stringstream ss;
+ std::string line;
+ while (std::getline(std::cin, line)) {
+ ss << line;
+ }
+ interpreter = Interpreter::fromXML(ss.str());
+ } else {
+ interpreter = Interpreter::fromURI(inputFile);
+ }
+ if (!interpreter) {
+ LOG(ERROR) << "Cannot create interpreter from " << inputFile;
+ exit(EXIT_FAILURE);
}
- interpreter = Interpreter::fromXML(ss.str());
- } else {
- interpreter = Interpreter::fromURI(inputFile);
- }
- if (!interpreter) {
- LOG(ERROR) << "Cannot create interpreter from " << inputFile;
- exit(EXIT_FAILURE);
- }
-
- if (toPromela) {
- Interpreter flatInterpreter = ChartToFSM::flatten(interpreter);
- if (outputFile.size() == 0 || outputFile == "-") {
- FSMToPromela::writeProgram(std::cout, flatInterpreter);
- } else {
- std::ofstream outStream;
- outStream.open(outputFile.c_str());
- FSMToPromela::writeProgram(outStream, flatInterpreter);
- outStream.close();
+ if (toPromela) {
+ Interpreter flatInterpreter = ChartToFSM::flatten(interpreter);
+
+ if (outputFile.size() == 0 || outputFile == "-") {
+ FSMToPromela::writeProgram(std::cout, flatInterpreter);
+ } else {
+ std::ofstream outStream;
+ outStream.open(outputFile.c_str());
+ FSMToPromela::writeProgram(outStream, flatInterpreter);
+ outStream.close();
+ }
+ exit(EXIT_SUCCESS);
}
- exit(EXIT_SUCCESS);
- }
- if (toFlat) {
- std::cout << ChartToFSM::flatten(interpreter).getDocument();
- exit(EXIT_SUCCESS);
+ if (toFlat) {
+ std::cout << ChartToFSM::flatten(interpreter).getDocument();
+ exit(EXIT_SUCCESS);
+ }
+ } catch (Event e) {
+ std::cout << e << std::endl;
}
-
return EXIT_SUCCESS;
} \ No newline at end of file
diff --git a/embedding/java/src/org/uscxml/tests/monitor/TestCustomMonitor.java b/embedding/java/src/org/uscxml/tests/monitor/TestCustomMonitor.java
new file mode 100644
index 0000000..c748f50
--- /dev/null
+++ b/embedding/java/src/org/uscxml/tests/monitor/TestCustomMonitor.java
@@ -0,0 +1,51 @@
+package org.uscxml.tests.monitor;
+
+import org.uscxml.Data;
+import org.uscxml.Interpreter;
+import org.uscxml.InterpreterException;
+import org.uscxml.InterpreterMonitor;
+
+public class TestCustomMonitor extends InterpreterMonitor {
+
+ @Override
+ public void afterEnteringState(Interpreter interpreter, String stateId,
+ String xpath, String state, boolean moreComing) {
+ System.out.println("Entered state " + stateId);
+ if ("s2".equals(stateId)) {
+ Data data = interpreter.getDataModel().getStringAsData("foo");
+ System.out.println(data);
+ }
+ }
+
+ public static void main(String[] args) throws InterpreterException {
+ System.load("/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava64.jnilib");
+
+ String xml =
+ "<scxml datamodel=\"ecmascript\">" +
+ " <datamodel>" +
+ " <data id=\"foo\">" +
+ " { foo: 'bar', baz: 'foo' }" +
+ " </data>" +
+ " </datamodel>" +
+ " <state id=\"s1\">" +
+ " <transition target=\"s2\" />" +
+ " </state>" +
+ " <state id=\"s2\">" +
+ " <transition target=\"s3\" />" +
+ " </state>" +
+ " <state id=\"s3\">" +
+ " <transition target=\"done\" />" +
+ " </state>" +
+ " <final id=\"done\" />" +
+ "</scxml>";
+
+ // parse and interpret
+ Interpreter interpreter = Interpreter.fromXML(xml);
+
+ TestCustomMonitor monitor = new TestCustomMonitor();
+ interpreter.addMonitor(monitor);
+
+ interpreter.interpret();
+ }
+
+}
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index 90f00c4..5a1df44 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -2345,6 +2345,9 @@ bool InterpreterImpl::isInitial(const Arabica::DOM::Element<std::string>& state)
if (isMember(state, getInitialStates(parent)))
return true; // every nested node
+ if (isParallel(parent))
+ return true;
+
return false;
}
diff --git a/src/uscxml/UUID.cpp b/src/uscxml/UUID.cpp
index 8647739..b56b727 100644
--- a/src/uscxml/UUID.cpp
+++ b/src/uscxml/UUID.cpp
@@ -31,4 +31,40 @@ std::string UUID::getUUID() {
return os.str();
}
+bool UUID::isUUID(const std::string& uuid) {
+ if (uuid.size() != 36)
+ return false;
+
+ if (uuid[8] != '-' || uuid[13] != '-' || uuid[18] != '-' || uuid[23] != '-')
+ return false;
+
+ for (int i = 0; i < 36; i++) {
+ if (i == 8 || i == 13 || i == 18 || i ==23)
+ continue;
+
+ char c = uuid[i];
+ if (c == 'a' ||
+ c == 'b' ||
+ c == 'c' ||
+ c == 'd' ||
+ c == 'e' ||
+ c == 'f' ||
+ c == '0' ||
+ c == '1' ||
+ c == '2' ||
+ c == '3' ||
+ c == '4' ||
+ c == '5' ||
+ c == '6' ||
+ c == '7' ||
+ c == '8' ||
+ c == '9') {
+ continue;
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
} \ No newline at end of file
diff --git a/src/uscxml/UUID.h b/src/uscxml/UUID.h
index af129e7..873d963 100644
--- a/src/uscxml/UUID.h
+++ b/src/uscxml/UUID.h
@@ -29,6 +29,7 @@ namespace uscxml {
class USCXML_API UUID {
public:
static std::string getUUID();
+ static bool isUUID(const std::string& uuid);
static boost::uuids::random_generator uuidGen;
};
diff --git a/src/uscxml/debug/SCXMLDotWriter.cpp b/src/uscxml/debug/SCXMLDotWriter.cpp
index 4061f41..88db575 100644
--- a/src/uscxml/debug/SCXMLDotWriter.cpp
+++ b/src/uscxml/debug/SCXMLDotWriter.cpp
@@ -18,6 +18,7 @@
*/
#include "uscxml/Common.h"
+#include "uscxml/UUID.h"
#include "SCXMLDotWriter.h"
#include "uscxml/DOMUtils.h"
#include <boost/algorithm/string.hpp> // replace_all
@@ -26,7 +27,8 @@
namespace uscxml {
using namespace Arabica::DOM;
-
+using namespace Arabica::XPath;
+
SCXMLDotWriter::SCXMLDotWriter() {
_iteration = 0;
_indentation = 0;
@@ -34,26 +36,29 @@ SCXMLDotWriter::SCXMLDotWriter() {
SCXMLDotWriter::SCXMLDotWriter(Interpreter interpreter,
const std::list<SCXMLDotWriter::StateAnchor>& stateAnchors,
- const Arabica::DOM::Element<std::string>& transition) {
+ const Element<std::string>& transition) {
_interpreter = interpreter;
_xmlNSPrefix = _interpreter.getNameSpaceInfo().xmlNSPrefix;
_transition = transition;
_anchors = stateAnchors;
- if (_anchors.size() == 0) {
- NodeList<std::string > scxmlElems = interpreter.getDocument().getElementsByTagName("scxml");
+ NodeList<std::string > scxmlElems = interpreter.getDocument().getElementsByTagName("scxml");
+ _scxml = (Element<std::string>)scxmlElems.item(0);
+ if (_anchors.size() == 0) {
StateAnchor anchor;
- anchor.element = (Arabica::DOM::Element<std::string>)scxmlElems.item(0);
+ anchor.element = _scxml;
_anchors.push_back(anchor);
}
for (std::list<StateAnchor>::iterator anchIter = _anchors.begin(); anchIter != _anchors.end(); anchIter++) {
- if (!anchIter->element) {
- NodeList<std::string > scxmlElems = interpreter.getDocument().getElementsByTagName("scxml");
- anchIter->element = (Arabica::DOM::Element<std::string>)scxmlElems.item(0);
- }
- assembleGraph(anchIter->element, anchIter->depth);
+ if (!anchIter->element)
+ anchIter->element = _scxml;
+ if (anchIter->childDepth >= 0 && anchIter->transDepth == -1)
+ anchIter->transDepth = anchIter->childDepth;
+
+ _portType = anchIter->type;
+ assembleGraph(anchIter->element, anchIter->childDepth, anchIter->transDepth + 1);
}
_iteration = 0;
@@ -83,7 +88,7 @@ void SCXMLDotWriter::beforeMicroStep(Interpreter interpreter) {
}
void SCXMLDotWriter::beforeTakingTransition(Interpreter interpreter,
- const Arabica::DOM::Element<std::string>& transition,
+ const Element<std::string>& transition,
bool moreComing) {
std::ostringstream fileSS;
fileSS << interpreter.getName() << "." << std::setw(6) << std::setfill('0') << _iteration++ << ".dot";
@@ -99,20 +104,60 @@ std::string SCXMLDotWriter::getPrefix() {
void SCXMLDotWriter::writeTo(std::ostream& os) {
os << "digraph {" << std::endl;
- os << " rankdir=TB;" << std::endl;
+ os << " rankdir=LR;" << std::endl;
os << " fontsize=10;" << std::endl;
// outfile << " splines=ortho;" << std::endl;
// outfile << " splines=false;" << std::endl;
// outfile << " nodesep=1.0;" << std::endl;
_indentation++;
- for (std::list<SCXMLDotWriter::StateAnchor>::iterator anchIter = _anchors.begin();
- anchIter != _anchors.end(); anchIter++) {
- writeStateElement(os, _graph[idForNode(anchIter->element)]);
- }
- _indentation--;
+ writeStateElement(os, _scxml);
+
+ // write edges at end of file
+ for(std::set<DotEdge>::iterator edgeIter = _edges.begin(); edgeIter != _edges.end(); edgeIter++) {
+ if (edgeIter->from == edgeIter->to)
+ continue;
+ if (_histories.find(edgeIter->to) != _histories.end()) {
+ if (_histories.find(edgeIter->to)->second.from == _histories.find(edgeIter->to)->second.to)
+ continue;
+ }
+
+ os << getPrefix() << "\"" << edgeIter->from << "\"";
+ if (edgeIter->fromPort.size() > 0) {
+ os << std::string(":\"") + edgeIter->fromPort + "\":e";
+ } else {
+ os << ":__name";
+ }
+ os << " -> ";
+
+ if (_histories.find(edgeIter->to) != _histories.end()) {
+ os << getPrefix() << "\"" << _histories.find(edgeIter->to)->second.to << "\"";
+ if (_histories.find(edgeIter->to)->second.toPort.size() > 0) {
+ os << std::string(":\"") + _histories.find(edgeIter->to)->second.toPort + "\"";
+ } else {
+ os << ":__name";
+ }
+ } else {
+ os << getPrefix() << "\"" << edgeIter->to << "\"";
+ if (edgeIter->toPort.size() > 0) {
+ os << std::string(":\"") + edgeIter->toPort + "\"";
+ } else {
+ os << ":__name";
+ }
+ }
+ if (edgeIter->type == EDGE_INITAL) {
+ os << ":nw [style=\"dashed\", color=\"black\"]";
+ } else {
+ os << " [color=\"black\"]";
+ }
+ os << std::endl;
+
+ }
+
+ _indentation--;
+
os << "}" << std::endl;
}
@@ -120,7 +165,7 @@ void SCXMLDotWriter::writeTo(std::ostream& os) {
void SCXMLDotWriter::toDot(const std::string& filename,
Interpreter interpreter,
const std::list<SCXMLDotWriter::StateAnchor>& stateAnchors,
- const Arabica::DOM::Element<std::string>& transition) {
+ const Element<std::string>& transition) {
std::ofstream outfile(filename.c_str());
SCXMLDotWriter writer(interpreter, stateAnchors, transition);
@@ -128,42 +173,50 @@ void SCXMLDotWriter::toDot(const std::string& filename,
}
-void SCXMLDotWriter::assembleGraph(const Arabica::DOM::Element<std::string>& state, uint32_t depth) {
+/**
+ * Walk the subset of the graph that is reachable and remember the nodes
+ */
+void SCXMLDotWriter::assembleGraph(const Element<std::string>& state, int32_t childDepth, int32_t transDepth) {
std::string nodeId = idForNode(state);
+ // this node is neither included per child, nor per transition
+ if (childDepth <= 0 && transDepth <= 0) {
+ return;
+ }
+
// been here
if (_graph.find(nodeId) != _graph.end())
return;
- if (depth == 0) {
- _graph[nodeId].isBorder = true;
- }
+ _graph[nodeId].node = state;
+ _graph[nodeId].portType = _portType;
- if (ATTR(state, "id") == "WiFiOff") {
- assert(true);
+
+ if (childDepth == 0 && transDepth == 0) {
+ _graph[nodeId].isBorder = true;
}
- _graph[nodeId].node = state;
-
- if (depth == 0)
- return;
- Arabica::XPath::NodeSet<std::string> childElems = InterpreterImpl::filterChildType(Arabica::DOM::Node_base::ELEMENT_NODE, state);
+ NodeSet<std::string> childElems = InterpreterImpl::filterChildType(Node_base::ELEMENT_NODE, state);
for (int i = 0; i < childElems.size(); i++) {
- Arabica::DOM::Element<std::string> childElem(childElems[i]);
+ Element<std::string> childElem(childElems[i]);
+ // remember histories we passed
if (iequals(TAGNAME(childElem), "history")) {
- _histories[ATTR(childElem, "id")] = ATTR(state, "id") + ":" + ATTR(childElem, "id");
+ _histories[ATTR(childElem, "id")].to = ATTR(state, "id");
+ _histories[ATTR(childElem, "id")].toPort = ATTR(childElem, "id");
}
+ // follow transitions
if (iequals(TAGNAME(childElem), "transition")) {
- Arabica::XPath::NodeSet<std::string> targetStates = _interpreter.getImpl()->getTargetStates(childElem);
+ _graph[nodeId].transitions.push_back(childElem);
+ NodeSet<std::string> targetStates = _interpreter.getImpl()->getTargetStates(childElem);
for (int j = 0; j < targetStates.size(); j++) {
std::string remoteNodeId = idForNode(targetStates[j]);
_graph[nodeId].targets.insert(std::make_pair(remoteNodeId, childElem));
- // recurse along the transition targets
- assembleGraph((Arabica::DOM::Element<std::string>)targetStates[j], depth - 1);
+ // recurse along the transition targets, no weight from child depth
+ assembleGraph((Element<std::string>)targetStates[j], 0, transDepth - 1);
}
if (targetStates.size() == 0)
_graph[nodeId].targets.insert(std::make_pair(nodeId, childElem));
@@ -178,147 +231,247 @@ void SCXMLDotWriter::assembleGraph(const Arabica::DOM::Element<std::string>& sta
}
}
+ // follow childs
if (InterpreterImpl::isState(Element<std::string>(childElem))) {
- // add to initial states if it is initial
if (_interpreter.getImpl()->isInitial(Element<std::string>(childElem))) {
+ // add to initial states if it is initial
_graph[nodeId].initialchilds.insert(idForNode(childElem));
} else if (_interpreter.getImpl()->isParallel(Element<std::string>(state))) {
+ // add to initial states if we are parallel
_graph[nodeId].initialchilds.insert(idForNode(childElem));
}
// in any case, it is a child state
_graph[nodeId].childs.insert(idForNode(childElem));
- // recurse
- assembleGraph(childElem, depth - 1);
+ // recurse (do we really need to?)
+ assembleGraph(childElem, childDepth - 1, transDepth);
}
-
}
}
-void SCXMLDotWriter::writeStateElement(std::ostream& os, const DotState& state) {
- const Arabica::DOM::Element<std::string>& stateElem = state.node;
+
+/**
+ * Walk the complete graph and draw reachable subset
+ */
+void SCXMLDotWriter::writeStateElement(std::ostream& os, const Element<std::string>& stateElem) {
std::string stateId = idForNode(stateElem);
if (_knownIds.find(stateId) != _knownIds.end())
return;
_knownIds.insert(stateId);
+ std::list<Node<std::string> > invisParents;
+ bool isVisible = (_graph.find(stateId) != _graph.end());
+
bool subgraph = InterpreterImpl::isCompound(stateElem) || InterpreterImpl::isParallel(stateElem);
+ bool fatherIsParallel = (stateElem.getParentNode() &&
+ stateElem.getParentNode().getNodeType() == Node_base::ELEMENT_NODE &&
+ InterpreterImpl::isParallel(Element<std::string>(stateElem.getParentNode())));
+
if (subgraph) {
_indentation++;
os << std::endl;
os << getPrefix() << "subgraph \"cluster_" << stateId << "\" {" << std::endl;
_indentation++;
os << getPrefix() << "fontsize=14" << std::endl;
- os << getPrefix() << "label=<<b>";
- if (InterpreterImpl::isCompound(stateElem)) {
- os << "Compound: ";
- } else {
- os << "Parallel: ";
- }
- os << nameForNode(stateElem) << "</b>>" << std::endl;
-// os << getPrefix() << "rank=\"same\"" << std::endl;
+ os << getPrefix() << "label=<<b>" << nameForNode(stateElem) << "</b>>" << std::endl;
+ // os << getPrefix() << "rank=\"same\"" << std::endl;
os << getPrefix() << "labeljust=l" << std::endl;
-// os << getPrefix() << "ranksep=\"equally\"" << std::endl;
+ os << getPrefix() << (fatherIsParallel ? "style=dashed" : "style=solid") << std::endl;
+
+ // os << getPrefix() << "ranksep=\"equally\"" << std::endl;
+
}
- os << std::endl;
- os << getPrefix() << "\"" << stateId << "\" [" << std::endl;
- _indentation++;
+ if (isVisible) {
+ // this state is visible!
+ const DotState& dotState = _graph.find(stateId)->second;
+
+ // is this a subgraph?
+
+ os << std::endl;
+ os << getPrefix() << "\"" << stateId << "\" [" << std::endl;
+ _indentation++;
+
+ os << getPrefix() << "fontsize=10," << std::endl;
+ os << getPrefix() << "shape=plaintext," << std::endl;
+ os << getPrefix() << (fatherIsParallel ? "style=dashed," : "style=solid,") << std::endl;
+
+ // is the current state in the basic configuration?
+ if (InterpreterImpl::isMember(stateElem, _interpreter.getBasicConfiguration()))
+ os << getPrefix() << "color=red, penwidth=3," << std::endl;
+
+ // is the current state in the basic configuration?
+ if (dotState.isBorder)
+ os << getPrefix() << "color=blue," << std::endl;
+
+ // is this state final?
+ if (_interpreter.getImpl()->isFinal(stateElem)) {
+ os << getPrefix() << "shape=doublecircle," << std::endl;
+ os << getPrefix() << "color=black," << std::endl;
+ os << getPrefix() << "penwidth=2," << std::endl;
+ os << getPrefix() << "label=<" << nameForNode(stateElem) << ">" << std::endl;
+ _indentation--;
+ os << getPrefix() << "];" << std::endl;
+
+ return;
+ }
- os << getPrefix() << "fontsize=10," << std::endl;
- os << getPrefix() << "shape=plaintext," << std::endl;
+ // is the state initial?
+ bool isInitial = _interpreter.getImpl()->isInitial(stateElem);
+ // if (isInitial)
+ // os << getPrefix() << "style=filled, fillcolor=lightgrey, " << std::endl;
- // is the current state in the basic configuration?
- if (InterpreterImpl::isMember(stateElem, _interpreter.getBasicConfiguration()))
- os << getPrefix() << "color=red, penwidth=3," << std::endl;
+ DotState::mmap_s_e_t::const_iterator destIterF, destIterB;
+ std::list<std::string> outPorts; // count unique keys
- // is the current state in the basic configuration?
- if (state.isBorder)
- os << getPrefix() << "color=blue," << std::endl;
+ switch (dotState.portType) {
+ case PORT_TARGET: // outports are per target
+ for(DotState::mmap_s_e_t::const_iterator it = dotState.targets.begin(), end = dotState.targets.end();
+ it != end;
+ it = dotState.targets.upper_bound(it->first)) {
+ outPorts.push_back(it->first);
+ }
+ break;
+ case PORT_EVENT: // outports are per event
+ for(DotState::mmap_s_e_t::const_iterator it = dotState.events.begin(), end = dotState.events.end();
+ it != end;
+ it = dotState.events.upper_bound(it->first)) {
+ outPorts.push_back(it->first);
+ }
+ break;
+ case PORT_TRANSITION:
+ for (int i = 0; i < dotState.transitions.size(); i++) {
+ outPorts.push_back(idForNode(dotState.transitions[i]));
+ }
+ break;
+ }
+
+ os << getPrefix() << "label = < " << std::endl;
+
+ /*
+ <table cellborder="1" border="0" cellspacing="0" cellpadding="2" style="rounded">
+ <tr><td port="name" rowspan="4"><b>step</b></td></tr>
+ <tr><td port="foo.error.port" align="right">foo.error.port</td></tr>
+ <tr><td port="bar" align="right">bar</td></tr>
+ <tr><td port="baz" align="right">baz</td></tr>
+ </table>
+ */
+
+ std::string details = getDetailedLabel(stateElem);
+
+ os << "<table " << (isInitial ? "bgcolor=\"orange\" " : "") << "cellborder=\"1\" border=\"0\" cellspacing=\"0\" cellpadding=\"2\" >" << std::endl;
+ os << " <tr><td port=\"__name\" rowspan=\"" << outPorts.size() + 1 << "\"><b>" << nameForNode(stateElem) << "</b></td></tr>" << std::endl;
+
+ switch (dotState.portType) {
+ case PORT_TARGET: // outports are per target
+ writePerTargetPorts(os, outPorts, dotState);
+ break;
+ case PORT_EVENT: // outports are per event
+ writePerEventPorts(os, outPorts, dotState);
+ break;
+ case PORT_TRANSITION:
+ writePerTransitionPorts(os, outPorts, dotState);
+ break;
+ }
+
+
+ // write details of the state
+ if (details.size() > 0) {
+ os << " <tr><td colspan=\"" << (outPorts.size() == 0 ? 1 : 2) << "\">" << std::endl;
+ os << details << std::endl;
+ os << " </td></tr>" << std::endl;
+ }
+
+ // write history states
+ NodeSet<std::string> histories = InterpreterImpl::filterChildElements(_xmlNSPrefix + "history", stateElem);
+ for (int i = 0; i < histories.size(); i++) {
+ os << " <tr><td port=\"" << ATTR(histories[i], "id") << "\" colspan=\"" << (outPorts.size() == 0 ? 1 : 2) << "\"><b>history: </b>" << ATTR(histories[i], "id") << "</td></tr>" << std::endl;
+
+ }
+
+ os << "</table>" << std::endl << getPrefix() << ">" << std::endl;
- // is this state final?
- if (_interpreter.getImpl()->isFinal(stateElem)) {
- os << getPrefix() << "shape=doublecircle," << std::endl;
- os << getPrefix() << "color=black," << std::endl;
- os << getPrefix() << "penwidth=2," << std::endl;
- os << getPrefix() << "label=<" << nameForNode(stateElem) << ">" << std::endl;
_indentation--;
os << getPrefix() << "];" << std::endl;
- return;
- }
- // is the state initial?
- bool isInitial = _interpreter.getImpl()->isInitial(stateElem);
-// if (isInitial)
-// os << getPrefix() << "style=filled, fillcolor=lightgrey, " << std::endl;
+ for (std::set<std::string>::iterator initIter = dotState.initialchilds.begin(); initIter != dotState.initialchilds.end(); initIter++) {
+ std::string destId = *initIter;
+ DotEdge edge(stateId, destId);
+ edge.type = EDGE_INITAL;
+ if (_graph.find(destId) != _graph.end())
+ _edges.insert(edge);
+ }
- DotState::mmap_s_e_t::const_iterator destIterF, destIterB;
- std::list<std::string> outPorts; // count unique keys
-#if PER_EVENT_TRANS
- // count unique event names
- for(DotState::mmap_s_e_t::const_iterator it = state.events.begin(), end = state.events.end();
- it != end;
- it = state.events.upper_bound(it->first)) {
- outPorts.push_back(it->first);
}
-#else
- // count unique adjecent nodes
- for(DotState::mmap_s_e_t::const_iterator it = state.targets.begin(), end = state.targets.end();
- it != end;
- it = state.targets.upper_bound(it->first)) {
- outPorts.push_back(it->first);
+
+ // recurse into children and search others to draw
+ NodeSet<std::string> childElems = InterpreterImpl::filterChildType(Node_base::ELEMENT_NODE, stateElem);
+ for (int i = 0; i < childElems.size(); i++) {
+ Element<std::string> childElem(childElems[i]);
+ if (InterpreterImpl::isState(Element<std::string>(childElem))) {
+ writeStateElement(os, childElem);
+ }
}
-#endif
- os << getPrefix() << "label = < " << std::endl;
+ if (subgraph) {
+ _indentation--;
+ os << getPrefix() << "} #" << stateId << std::endl;
+ _indentation--;
+ }
+}
- /*
- <table cellborder="1" border="0" cellspacing="0" cellpadding="2" style="rounded">
- <tr><td port="name" rowspan="4"><b>step</b></td></tr>
- <tr><td port="foo.error.port" align="right">foo.error.port</td></tr>
- <tr><td port="bar" align="right">bar</td></tr>
- <tr><td port="baz" align="right">baz</td></tr>
- </table>
- */
-
- std::string details = getDetailedLabel(stateElem);
-
- os << "<table " << (isInitial ? "bgcolor=\"orange\" " : "") << "cellborder=\"1\" border=\"0\" cellspacing=\"0\" cellpadding=\"2\" >" << std::endl;
- os << " <tr><td port=\"__name\" rowspan=\"" << outPorts.size() + 1 << "\"><b>" << nameForNode(stateElem) << "</b></td></tr>" << std::endl;
- for(std::list<std::string>::iterator nameIter = outPorts.begin(); nameIter != outPorts.end(); nameIter++) {
-#ifdef PER_EVENT_TRANS
- os << " <tr><td port=\"" << portEscape(*nameIter) << "\" align=\"right\">" << *nameIter << "</td></tr>" << std::endl;
-#else
- // gather all events that activate the transition
- std::string portName = *nameIter;
+void SCXMLDotWriter::writePerTransitionPorts(std::ostream& os, const std::list<std::string>& outPorts, const DotState& dotState) {
+ // TODO: Not implemented
+}
-// std::cout << ATTR(stateElem, "id") << std::endl;
+void SCXMLDotWriter::writePerEventPorts(std::ostream& os, const std::list<std::string>& outPorts, const DotState& dotState) {
+ // TODO: Not implemented
- if (ATTR(stateElem, "id") == "ConfirmQuit") {
- assert(true);
- }
+ // outports contain event names
+ std::string stateId = idForNode(dotState.node);
+ DotState::mmap_s_e_t::const_iterator destIterF, destIterB;
+
+ for(std::list<std::string>::const_iterator nameIter = outPorts.begin(); nameIter != outPorts.end(); nameIter++) {
+ os << " <tr><td port=\"" << portEscape(*nameIter) << "\" align=\"right\">" << *nameIter << "</td></tr>" << std::endl;
+ }
+}
+void SCXMLDotWriter::writePerTargetPorts(std::ostream& os, const std::list<std::string>& outPorts, const DotState& dotState) {
+ // outports contain remote node ids
+ std::string stateId = idForNode(dotState.node);
+ DotState::mmap_s_e_t::const_iterator destIterF, destIterB;
+
+ for(std::list<std::string>::const_iterator nameIter = outPorts.begin(); nameIter != outPorts.end(); nameIter++) {
+
+ // gather all events that activate the transition
+ std::string portName = *nameIter;
+ DotEdge edge(stateId, portName);
+ edge.fromPort = portName;
+
std::multimap<std::string, std::string> eventConds; // event to condition
- std::pair <DotState::mmap_s_e_t::const_iterator, DotState::mmap_s_e_t::const_iterator> targetKeyRange = state.targets.equal_range(portName);
+ std::pair <DotState::mmap_s_e_t::const_iterator, DotState::mmap_s_e_t::const_iterator> targetKeyRange = dotState.targets.equal_range(portName);
for (destIterB = targetKeyRange.first; destIterB != targetKeyRange.second; ++destIterB) {
- const Arabica::DOM::Element<std::string>& transElem = destIterB->second;
+ const Element<std::string>& transElem = destIterB->second;
std::list<std::string> eventNames = InterpreterImpl::tokenizeIdRefs(ATTR(transElem, "event"));
for (std::list<std::string>::iterator eventIter = eventNames.begin(); eventIter != eventNames.end(); eventIter++) {
eventConds.insert(std::make_pair(*eventIter, ATTR(transElem, "cond")));
}
if (eventNames.size() == 0) {
// spontaneous transition
- eventConds.insert(std::make_pair("&#8709;", ATTR(transElem, "cond")));
+ eventConds.insert(std::make_pair("&#35;", ATTR(transElem, "cond")));
+ edge.type = EDGE_SPONTANEOUS;
}
}
-
+ if (_graph.find(portName) != _graph.end())
+ _edges.insert(edge);
+
typedef std::multimap<std::string, std::string>::iterator condIter_t;
std::stringstream outPortSS;
outPortSS << "<b>" << portName << "</b><br align=\"right\" />";
-
+
std::string opener = "{";
std::string closer;
std::string seperator;
@@ -326,125 +479,25 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const DotState& state)
for(iterA = eventConds.begin(); iterA != eventConds.end(); iterA = iterB) {
std::string eventName = iterA->first;
bool hasCondition = false;
-
+
std::pair <condIter_t, condIter_t> condRange = eventConds.equal_range(eventName);
for (iterB = condRange.first; iterB != condRange.second; ++iterB) {
hasCondition = true;
}
-
+
outPortSS << opener << seperator << eventName << (hasCondition ? "" : "");
seperator = ", ";
opener = "";
closer = "}";
}
outPortSS << closer;
-
+
os << " <tr><td port=\"" << portEscape(portName) << "\" align=\"right\">" << outPortSS.str() << "</td></tr>" << std::endl;
-#endif
- }
-
- if (details.size() > 0) {
- os << " <tr><td colspan=\"" << (outPorts.size() == 0 ? 1 : 2) << "\">" << std::endl;
- os << details << std::endl;
- os << " </td></tr>" << std::endl;
- }
-
- Arabica::XPath::NodeSet<std::string> histories = InterpreterImpl::filterChildElements(_xmlNSPrefix + "history", stateElem);
- for (int i = 0; i < histories.size(); i++) {
- os << " <tr><td port=\"" << ATTR(histories[i], "id") << "\" colspan=\"" << (outPorts.size() == 0 ? 1 : 2) << "\"><b>history: </b>" << ATTR(histories[i], "id") << "</td></tr>" << std::endl;
-
- }
-
- os << "</table>" << std::endl << getPrefix() << ">" << std::endl;
-
- _indentation--;
- os << getPrefix() << "];" << std::endl;
-
- // always display childs up to the desired depth
- for (std::set<std::string>::iterator childIter = state.childs.begin(); childIter != state.childs.end(); childIter++) {
- if (_graph.find(*childIter) != _graph.end())
- writeStateElement(os, _graph[*childIter]);
- }
-
- if (subgraph) {
- _indentation--;
- os << getPrefix() << "} " << std::endl;
- _indentation--;
- }
-
-#if 1
- std::string initialEdgeStyle = "style=\"dashed\", color=\"black\"";
- std::string transitionEdgeStyle = "color=black";
-
- for (std::set<std::string>::iterator initIter = state.initialchilds.begin(); initIter != state.initialchilds.end(); initIter++) {
- std::string destId = *initIter;
- if (_histories.find(destId) != _histories.end()) {
- os << getPrefix() << stateId << ":__name -> " << _histories[destId] << " [" << initialEdgeStyle << "]" << std::endl;
- } else if(InterpreterImpl::isFinal(_graph[destId].node)) {
- os << getPrefix() << stateId << ":__name -> " << destId << ":__name:nw [" << initialEdgeStyle << "]" << std::endl;
- } else {
- os << getPrefix() << stateId << ":__name -> " << destId << ":__name:nw [" << initialEdgeStyle << "]" << std::endl;
- }
- }
-
-#if PER_EVENT_TRANS
- // iterate all events and make connections
- DotState::mmap_s_e_t::const_iterator destIterF, destIterB;
- for(destIterF = state.events.begin(); destIterF != state.events.end(); destIterF = destIterB) {
- std::string eventName = destIterF->first;
-
- // all these react to the same event
- std::pair <DotState::mmap_s_e_t::const_iterator,DotState::mmap_s_e_t::const_iterator> keyRange = state.events.equal_range(eventName);
- for (destIterB = keyRange.first; destIterB != keyRange.second; ++destIterB) {
- const Arabica::DOM::Element<std::string>& transElem = destIterB->second;
- Arabica::XPath::NodeSet<std::string> targetStates = _interpreter.getImpl()->getTargetStates(transElem);
- for (int i = 0; i < targetStates.size(); i++) {
- std::string destId = idForNode(targetStates[i]);
- if (_histories.find(destId) != _histories.end()) {
- os << getPrefix() << "" << stateId << ":\"" << portEscape(eventName) << "\" -> " << _histories[destId] << " [" << transitionEdgeStyle << "]" << std::endl;
- } else if(InterpreterImpl::isFinal(_graph[destId].node)) {
- os << getPrefix() << stateId << ":\"" << portEscape(eventName) << "\" -> " << destId << " [" << transitionEdgeStyle << "]" << std::endl;
- } else {
- os << getPrefix() << "" << stateId << ":\"" << portEscape(eventName) << "\" -> " << destId << ":__name [" << transitionEdgeStyle << "]" << std::endl;
- }
- }
- }
- }
-#else
- // iterate all *targets* and make connections
- for(destIterF = state.targets.begin(); destIterF != state.targets.end(); destIterF = destIterB) {
- std::string eventName = destIterF->first;
-
- // all these react to the same event
- std::pair <DotState::mmap_s_e_t::const_iterator,DotState::mmap_s_e_t::const_iterator> keyRange = state.targets.equal_range(eventName);
- std::set<Arabica::DOM::Element<std::string> > targetSet;
- for (destIterB = keyRange.first; destIterB != keyRange.second; ++destIterB) {
- const Arabica::DOM::Element<std::string>& transElem = destIterB->second;
- Arabica::XPath::NodeSet<std::string> targetStates = _interpreter.getImpl()->getTargetStates(transElem);
- for (int i = 0; i < targetStates.size(); i++) {
- targetSet.insert(Arabica::DOM::Element<std::string>(targetStates[i]));
- }
- }
- for (std::set<Arabica::DOM::Element<std::string> >::iterator stateIter = targetSet.begin(); stateIter != targetSet.end(); stateIter++) {
- std::string destId = idForNode(*stateIter);
- if (_histories.find(destId) != _histories.end()) {
- os << getPrefix() << "" << stateId << ":\"" << portEscape(eventName) << "\" -> " << _histories[destId] << " [" << transitionEdgeStyle << "]" << std::endl;
- } else if(InterpreterImpl::isFinal(_graph[destId].node)) {
- os << getPrefix() << stateId << ":\"" << portEscape(eventName) << "\" -> " << destId << " [" << transitionEdgeStyle << "]" << std::endl;
- } else {
- os << getPrefix() << "" << stateId << ":\"" << portEscape(eventName) << "\" -> " << destId << ":__name [" << transitionEdgeStyle << "]" << std::endl;
- }
- writeStateElement(os, _graph[destId]);
- }
}
-#endif
-
-#endif
-
}
-std::string SCXMLDotWriter::getDetailedLabel(const Arabica::DOM::Element<std::string>& elem, int indentation) {
+std::string SCXMLDotWriter::getDetailedLabel(const Element<std::string>& elem, int indentation) {
/*
<table>
@@ -525,6 +578,12 @@ std::string SCXMLDotWriter::getDetailedLabel(const Arabica::DOM::Element<std::st
}
// send ---------
+ if (iequals(TAGNAME(childElems.item(i)), "raise")) {
+ if (HAS_ATTR(childElems.item(i), "event "))
+ details.name += "<br />event = " + ATTR(childElems.item(i), "event");
+ }
+
+ // send ---------
if (iequals(TAGNAME(childElems.item(i)), "send")) {
if (HAS_ATTR(childElems.item(i), "id"))
details.name += "<br />id = " + ATTR(childElems.item(i), "id");
@@ -597,7 +656,7 @@ std::string SCXMLDotWriter::getDetailedLabel(const Arabica::DOM::Element<std::st
}
// recurse
- details.content = getDetailedLabel((Arabica::DOM::Element<std::string>)childElems.item(i), indentation + 1);
+ details.content = getDetailedLabel((Element<std::string>)childElems.item(i), indentation + 1);
content.push_back(details);
}
@@ -631,7 +690,7 @@ std::string SCXMLDotWriter::portEscape(const std::string& text) {
std::string escaped(text);
boost::replace_all(escaped, ".", "-");
- return escaped;
+ return text;
}
std::string SCXMLDotWriter::dotEscape(const std::string& text) {
@@ -655,14 +714,22 @@ std::string SCXMLDotWriter::colorForIndent(int indent) {
return ss.str();
}
-std::string SCXMLDotWriter::nameForNode(const Arabica::DOM::Node<std::string>& node) {
+std::string SCXMLDotWriter::nameForNode(const Node<std::string>& node) {
std::string elemName;
if (node.getNodeType() == Node_base::ELEMENT_NODE) {
- Arabica::DOM::Element<std::string> elem = (Arabica::DOM::Element<std::string>)node;
- if (InterpreterImpl::isParallel(elem))
- elemName += "<i>Parallel</i><br />";
- if (elem.hasAttribute("name")) {
- elemName += elem.getAttribute("name");
+ Element<std::string> elem = (Element<std::string>)node;
+
+ if (false) {
+ } else if (elem.getTagName() == "scxml") {
+ if (elem.hasAttribute("name") && !UUID::isUUID(elem.getAttribute("name"))) {
+ elemName += elem.getAttribute("name");
+ } else if (elem.hasAttribute("id") && !UUID::isUUID(elem.getAttribute("id"))) {
+ elemName += elem.getAttribute("id");
+ }
+ } else if (InterpreterImpl::isCompound(elem)) {
+ elemName = "<i>Compound: </i>" + elem.getAttribute("id");
+ } else if (InterpreterImpl::isParallel(elem)) {
+ elemName = "<i>Parallel: </i>" + elem.getAttribute("id");
} else if (elem.hasAttribute("id")) {
elemName += elem.getAttribute("id");
}
@@ -674,12 +741,12 @@ std::string SCXMLDotWriter::nameForNode(const Arabica::DOM::Node<std::string>& n
}
-std::string SCXMLDotWriter::idForNode(const Arabica::DOM::Node<std::string>& node) {
+std::string SCXMLDotWriter::idForNode(const Node<std::string>& node) {
std::string elemId;
// try to get the id as the name or id attribute
if (node.getNodeType() == Node_base::ELEMENT_NODE) {
- Arabica::DOM::Element<std::string> elem = (Arabica::DOM::Element<std::string>)node;
+ Element<std::string> elem = (Element<std::string>)node;
if (elem.hasAttribute("name")) {
elemId = elem.getAttribute("name");
} else if (elem.hasAttribute("id")) {
@@ -689,8 +756,8 @@ std::string SCXMLDotWriter::idForNode(const Arabica::DOM::Node<std::string>& nod
// no luck, create id from position in tree
if (elemId.size() == 0) {
- Arabica::DOM::Node<std::string> tmpParent = node;
- Arabica::DOM::Node<std::string> tmpIndex;
+ Node<std::string> tmpParent = node;
+ Node<std::string> tmpIndex;
do {
if (tmpParent.getNodeType() != Node_base::ELEMENT_NODE)
continue;
diff --git a/src/uscxml/debug/SCXMLDotWriter.h b/src/uscxml/debug/SCXMLDotWriter.h
index 30d5fcf..79ea6c1 100644
--- a/src/uscxml/debug/SCXMLDotWriter.h
+++ b/src/uscxml/debug/SCXMLDotWriter.h
@@ -57,10 +57,23 @@ class Interpreter;
class USCXML_API SCXMLDotWriter : public InterpreterMonitor {
public:
+ enum PortType {
+ PORT_TARGET,
+ PORT_EVENT,
+ PORT_TRANSITION
+ };
+
struct StateAnchor {
- StateAnchor() : depth(std::numeric_limits<int32_t>::max()) {}
+ StateAnchor() : childDepth(-1), transDepth(-1), type(PORT_TARGET) {}
Arabica::DOM::Element<std::string> element;
- uint32_t depth;
+ int32_t childDepth;
+ int32_t transDepth;
+
+ PortType type;
+
+ operator bool() const {
+ return childDepth != -1 || transDepth != -1 || element;
+ }
};
struct ElemDetails {
@@ -70,17 +83,45 @@ public:
};
struct DotState {
- DotState() : isBorder(false) {}
+ DotState() : isBorder(false), portType(PORT_TARGET) {}
Arabica::DOM::Element<std::string> node;
+ Arabica::XPath::NodeSet<std::string> transitions;
std::multimap<std::string, Arabica::DOM::Element<std::string> > targets; // key is remote node, transition is element
std::multimap<std::string, Arabica::DOM::Element<std::string> > events; // key is event name, value is transitions that react
bool isBorder;
+ PortType portType;
+
std::set<std::string> childs;
std::set<std::string> initialchilds;
+
typedef std::multimap<std::string, Arabica::DOM::Element<std::string> > mmap_s_e_t;
};
+ enum EdgeType {
+ EDGE_INITAL,
+ EDGE_TRANSIION,
+ EDGE_SPONTANEOUS
+ };
+
+ struct DotEdge {
+ DotEdge() : type(EDGE_TRANSIION) {}
+ DotEdge(const std::string& from, const std::string& to) : type(EDGE_TRANSIION), from(from), to(to) {
+ }
+
+ bool operator< (const DotEdge& other) const {
+ return from + fromPort + to + toPort > other.from + other.fromPort + other.to + other.toPort;
+ }
+
+ EdgeType type;
+ std::string from;
+ std::string fromCompass;
+ std::string fromPort;
+ std::string to;
+ std::string toPort;
+ std::string toCompass;
+ };
+
SCXMLDotWriter();
~SCXMLDotWriter();
@@ -120,8 +161,15 @@ protected:
const std::list<SCXMLDotWriter::StateAnchor>& stateAnchors,
const Arabica::DOM::Element<std::string>& transition);
- void assembleGraph(const Arabica::DOM::Element<std::string>& start, uint32_t depth = std::numeric_limits<int32_t>::max());
- void writeStateElement(std::ostream& os, const DotState& elem);
+ void assembleGraph(const Arabica::DOM::Element<std::string>& start,
+ int32_t childDepth = std::numeric_limits<int32_t>::max(),
+ int32_t transDepth = std::numeric_limits<int32_t>::max());
+ void writeStateElement(std::ostream& os, const Arabica::DOM::Element<std::string>& state);
+
+ void writePerTransitionPorts(std::ostream& os, const std::list<std::string>& outPorts, const DotState& dotState);
+ void writePerEventPorts(std::ostream& os, const std::list<std::string>& outPorts, const DotState& dotState);
+ void writePerTargetPorts(std::ostream& os, const std::list<std::string>& outPorts, const DotState& dotState);
+
void writeUnknownNode(std::ostream& os, const std::string& targetId);
int _iteration;
@@ -130,13 +178,18 @@ protected:
int _indentation;
std::map<std::string, DotState> _graph;
-
+ std::set<DotEdge> _edges;
+
// these are only set in ephemeral instances per monitor call
Arabica::DOM::Element<std::string> _transition;
+ Arabica::DOM::Element<std::string> _scxml;
Interpreter _interpreter;
std::string _xmlNSPrefix;
std::list<StateAnchor> _anchors;
- std::map<std::string, std::string> _histories;
+ std::map<std::string, DotEdge> _histories;
+
+ PortType _portType;
+
};
}
diff --git a/src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp b/src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp
index 8ab95ea..6db5ac4 100644
--- a/src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp
+++ b/src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp
@@ -24,7 +24,7 @@
#include <DOM/SAX2DOM/SAX2DOM.hpp>
#include <SAX/helpers/InputSourceResolver.hpp>
-#include <uscxml/NameSpacingParser.h>
+#include <uscxml/DOMUtils.h>
#include <boost/algorithm/string.hpp>
@@ -109,7 +109,7 @@ Arabica::DOM::Node<std::string> MMIEvent::getEventNode(Arabica::DOM::Node<std::s
Arabica::DOM::Document<std::string> MMIEvent::toXML() const {
Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation();
Document<std::string> doc = domFactory.createDocument(nameSpace, "", 0);
- Element<std::string> mmiElem = doc.createElementNS(nameSpace, "mmi");
+// Element<std::string> mmiElem = doc.createElementNS(nameSpace, "mmi");
Element<std::string> msgElem = doc.createElementNS(nameSpace, tagName);
msgElem.setAttributeNS(nameSpace, "Source", source);
msgElem.setAttributeNS(nameSpace, "Target", target);
@@ -136,8 +136,9 @@ Arabica::DOM::Document<std::string> MMIEvent::toXML() const {
msgElem.appendChild(dataElem);
}
- mmiElem.appendChild(msgElem);
- doc.appendChild(mmiElem);
+// mmiElem.appendChild(msgElem);
+// doc.appendChild(mmiElem);
+ doc.appendChild(msgElem);
return doc;
}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 62b8749..436f52e 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -134,6 +134,11 @@ target_link_libraries(test-sockets uscxml)
# add_test(test-datamodel ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-sockets)
set_target_properties(test-sockets PROPERTIES FOLDER "Tests")
+add_executable(test-vxml-mmi-socket src/test-vxml-mmi-socket.cpp)
+target_link_libraries(test-vxml-mmi-socket uscxml)
+# add_test(test-datamodel ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-sockets)
+set_target_properties(test-vxml-mmi-socket PROPERTIES FOLDER "Tests")
+
# if (NOT WIN32)
# add_executable(test-mmi src/test-mmi.cpp)
# target_link_libraries(test-mmi uscxml)
diff --git a/test/src/test-vxml-mmi-socket.cpp b/test/src/test-vxml-mmi-socket.cpp
new file mode 100644
index 0000000..b57b7f6
--- /dev/null
+++ b/test/src/test-vxml-mmi-socket.cpp
@@ -0,0 +1,72 @@
+#include "uscxml/config.h"
+#include "uscxml/server/Socket.h"
+#include <iostream>
+#include <stdexcept>
+
+#include <event2/event.h>
+#include "event2/thread.h"
+
+#ifdef HAS_SIGNAL_H
+#include <signal.h>
+#endif
+
+#include "uscxml/concurrency/tinythread.h"
+#include "uscxml/plugins/ioprocessor/modality/MMIMessages.h"
+#include <DOM/io/Stream.hpp>
+
+#include "uscxml/plugins/ioprocessor/modality/MMIMessages.cpp"
+
+
+using namespace uscxml;
+
+class TestServer : public ServerSocket {
+public:
+ TestServer(int domain, int type, int protocol) : ServerSocket(domain, type, protocol) {}
+ virtual void readCallback(const char* data, size_t size, Connection& conn) {
+ std::string content(data, size);
+// std::cout << "Server got: " << content << std::endl;
+ std::string urghs("hi!");
+ conn.reply(urghs.data(), urghs.size());
+ };
+};
+
+class TestClient : public ClientSocket {
+public:
+ TestClient(int domain, int type, int protocol) : ClientSocket(domain, type, protocol) {}
+ virtual void readCallback(const char* data, size_t size) {
+ std::string content(data, size);
+ };
+};
+
+int main(int argc, char** argv) {
+
+#if defined(HAS_SIGNAL_H) && !defined(WIN32)
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+#ifndef _WIN32
+ evthread_use_pthreads();
+#else
+ evthread_use_windows_threads();
+#endif
+
+// TestClient client(PF_INET, SOCK_STREAM, 0);
+// client.connect("epikur.local", 4343);
+
+ StartRequest startReq;
+ startReq.source = "undefined.source";
+ startReq.target = "epikur.local:4343";
+ startReq.requestId = "131234141234";
+ startReq.data =
+ "<vxml xmlns=\"http://www.w3.org/2001/vxml\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"2.1\" xml:lang=\"en\""
+ "xsi:schematicLocation=\"http://www.w3.org/2001/vxml http://www.w3.org/TR/voicexml20/vxml.xsd\">"
+ " <prompt>Goodbye!</prompt>"
+ "</vxml>";
+
+ Arabica::DOM::Document<std::string> reqXML = startReq.toXML();
+ std::stringstream xmlSS;
+ xmlSS << reqXML;
+ std::cout << reqXML;
+
+// client.write(xmlSS.str().data(), xmlSS.str().size());
+} \ No newline at end of file