summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--src/uscxml/Message.cpp24
-rw-r--r--src/uscxml/Message.h4
-rw-r--r--src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp96
-rw-r--r--src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp18
-rw-r--r--test/samples/uscxml/test-prolog.scxml33
-rw-r--r--test/samples/uscxml/test-prolog2.scxml38
7 files changed, 183 insertions, 34 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3475c4d..bdd2f45 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -327,7 +327,9 @@ if (NOT WIN32)
set(XML_LIBRARIES ${LIBXML2_LIBRARIES})
list (APPEND USCXML_CORE_LIBS "dl")
list (APPEND USCXML_CORE_LIBS "pthread")
- list (APPEND USCXML_CORE_LIBS "rt")
+ if (NOT APPLE)
+ list (APPEND USCXML_CORE_LIBS "rt")
+ endif()
elseif(WIN32)
list (APPEND XML_LIBRARIES "Ws2_32")
list (APPEND XML_LIBRARIES "Winmm")
diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp
index 27e01e2..67198ea 100644
--- a/src/uscxml/Message.cpp
+++ b/src/uscxml/Message.cpp
@@ -308,6 +308,30 @@ Data Data::fromJSON(const std::string& jsonString) {
return data;
}
+void Event::initContent(const std::string& content) {
+ // try to parse as JSON
+ Data json = Data::fromJSON(content);
+ if (json) {
+ data = json;
+ return;
+ }
+
+ // try to parse as XML
+ Arabica::SAX2DOM::Parser<std::string> parser;
+ Arabica::SAX::CatchErrorHandler<std::string> errorHandler;
+ parser.setErrorHandler(errorHandler);
+
+ std::istringstream is(content);
+ Arabica::SAX::InputSource<std::string> inputSource;
+ inputSource.setByteStream(is);
+ if (parser.parse(inputSource)) {
+ dom = parser.getDocument();
+ return;
+ }
+
+ this->content = content;
+}
+
Event Event::fromXML(const std::string& xmlString) {
Arabica::SAX2DOM::Parser<std::string> eventParser;
Arabica::SAX::CatchErrorHandler<std::string> errorHandler;
diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h
index ea1e8ab..3bb30fc 100644
--- a/src/uscxml/Message.h
+++ b/src/uscxml/Message.h
@@ -173,10 +173,12 @@ public:
Data getData() {
return data;
}
- void setData(const Data& invokeId) {
+ void setData(const Data& data) {
this->data = data;
}
+ void initContent(const std::string& content);
+
static Event fromXML(const std::string& xmlString);
Arabica::DOM::Document<std::string> toDocument();
std::string toXMLString() {
diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp
index 0c65fa9..7e63174 100644
--- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp
+++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp
@@ -124,10 +124,10 @@ void SWIDataModel::setEvent(const Event& event) {
PlCall("retractall(event(_))");
// simple values
- PlCall("assert", PlCompound("event", PlCompound("name", PlString(event.name.c_str()))));
+ PlCall("assert", PlCompound("event", PlCompound("name", PlTerm(event.name.c_str()))));
PlCall("assert", PlCompound("event", PlCompound("origin", PlString(event.origin.c_str()))));
PlCall("assert", PlCompound("event", PlCompound("origintype", PlString(event.invokeid.c_str()))));
- PlCall("assert", PlCompound("event", PlCompound("invokeid", PlString(event.origintype.c_str()))));
+ PlCall("assert", PlCompound("event", PlCompound("invokeid", PlTerm(event.origintype.c_str()))));
PlCall("assert", PlCompound("event", PlCompound("raw", PlString(event.raw.c_str()))));
// event.type
@@ -143,11 +143,11 @@ void SWIDataModel::setEvent(const Event& event) {
type = "external";
break;
}
- PlCall("assert", PlCompound("event", PlCompound("type", PlString(type.c_str()))));
+ PlCall("assert", PlCompound("event", PlCompound("type", PlTerm(type.c_str()))));
// event.sendid
if (!event.hideSendId)
- PlCall("assert", PlCompound("event", PlCompound("sendid", PlString(event.sendid.c_str()))));
+ PlCall("assert", PlCompound("event", PlCompound("sendid", PlTerm(event.sendid.c_str()))));
// event.data
URL domUrl;
@@ -170,9 +170,9 @@ void SWIDataModel::setEvent(const Event& event) {
paramIter = event.params.upper_bound(paramIter->first);
}
if (uniqueKeys > 0) {
- std::stringstream paramArray;
paramIter = event.params.begin();
for(int i = 0; paramIter != event.params.end(); i++) {
+ std::stringstream paramArray;
Event::params_t::const_iterator lastValueIter = event.params.upper_bound(paramIter->first);
paramArray << paramIter->first << "([";
@@ -185,7 +185,8 @@ void SWIDataModel::setEvent(const Event& event) {
}
paramArray << "])";
std::stringstream paramExpr;
- paramExpr << "assert(event(param(" << paramArray << ")))";
+ paramExpr << "assert(event(param(" << paramArray.str() << ")))";
+ //std::cout << paramExpr.str() << std::endl;
PlCall(paramExpr.str().c_str());
paramIter = lastValueIter;
@@ -208,15 +209,46 @@ bool SWIDataModel::validate(const std::string& location, const std::string& sche
}
uint32_t SWIDataModel::getLength(const std::string& expr) {
-// std::cout << "SWIDataModel::getLength" << std::endl;
- return 0;
+ PlCompound compound(expr.c_str());
+ PlTermv termv(compound.arity());
+ for (int i = 0; i < compound.arity(); i++) {
+ termv[i] = compound[i + 1];
+ }
+ PlQuery query(compound.name(), termv);
+ uint32_t length = 0;
+ while(query.next_solution() > 0)
+ length++;
+ return length;
}
void SWIDataModel::setForeach(const std::string& item,
const std::string& array,
const std::string& index,
uint32_t iteration) {
- // std::cout << "SWIDataModel::setForeach" << std::endl;
+ PlCompound compound(array.c_str());
+ PlCompound orig(array.c_str());
+ PlTermv termv(compound.arity());
+ for (int i = 0; i < compound.arity(); i++) {
+ termv[i] = compound[i + 1];
+ }
+ {
+ int tmp = iteration + 1;
+ PlQuery query(compound.name(), termv);
+ while (tmp) {
+ query.next_solution();
+ tmp--;
+ }
+ }
+ PlCall("retractall", PlCompound(index.c_str(), 1));
+ PlCall("retractall", PlCompound(item.c_str(), 1));
+ PlCall("assert", PlCompound(index.c_str(), PlTerm((long)iteration)));
+
+ std::map<std::string, PlTerm> vars = resolveAtoms(compound, orig);
+ std::map<std::string, PlTerm>::iterator varIter = vars.begin();
+ while(varIter != vars.end()) {
+ PlCall("assert", PlCompound(item.c_str(), varIter->second));
+ varIter++;
+ }
}
void SWIDataModel::eval(const std::string& expr) {
@@ -294,11 +326,45 @@ void SWIDataModel::assign(const Arabica::DOM::Element<std::string>& assignElem,
const Arabica::DOM::Document<std::string>& doc,
const std::string& content) {
std::string expr = content;
+ std::string predicate;
if (HAS_ATTR(assignElem, "expr")) {
expr = ATTR(assignElem, "expr");
}
- if (expr.length() > 0)
+ if (HAS_ATTR(assignElem, "id"))
+ predicate = ATTR(assignElem, "id");
+ if (HAS_ATTR(assignElem, "location"))
+ predicate = ATTR(assignElem, "location");
+
+ if (predicate.size() > 0) {
+ size_t aritySep = predicate.find_first_of("/");
+ if (aritySep != std::string::npos) {
+ std::string functor = predicate.substr(0, aritySep);
+ std::string arity = predicate.substr(aritySep + 1);
+ std::string callAssert = "assert";
+ if (HAS_ATTR(assignElem, "type")) {
+ std::string type = ATTR(assignElem, "type");
+ if (boost::iequals(type, "retract")) {
+ PlCall("retractall", PlCompound(functor.c_str(), strTo<long>(arity)));
+ } else if(boost::iequals(type, "append")) {
+ callAssert = "assertz";
+ } else if(boost::iequals(type, "prepend")) {
+ callAssert = "asserta";
+ }
+ }
+ // treat content as . seperated facts
+ std::stringstream factStream(content);
+ std::string item;
+ while(std::getline(factStream, item, '.')) {
+ std::string fact = boost::trim_copy(item);
+ if (fact.length() == 0)
+ continue;
+ PlCall((callAssert + "(" + functor + "(" + fact + "))").c_str());
+ }
+
+ }
+ } else if (expr.length() > 0) {
eval(expr);
+ }
}
void SWIDataModel::assign(const std::string& location, const Data& data) {
@@ -308,15 +374,11 @@ void SWIDataModel::assign(const std::string& location, const Data& data) {
void SWIDataModel::init(const Arabica::DOM::Element<std::string>& dataElem,
const Arabica::DOM::Document<std::string>& doc,
const std::string& content) {
- std::string key;
- if (HAS_ATTR(dataElem, "id")) {
- key = ATTR(dataElem, "id");
- } else if (HAS_ATTR(dataElem, "location")) {
- key = ATTR(dataElem, "location");
- }
assign(dataElem, doc, content);
}
-void SWIDataModel::init(const std::string& location, const Data& data) {}
+void SWIDataModel::init(const std::string& location, const Data& data) {
+ assign(location, data);
+}
bool SWIDataModel::isDeclared(const std::string& expr) {
return true;
diff --git a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp
index c8d86fa..6ddb83c 100644
--- a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp
+++ b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp
@@ -84,6 +84,8 @@ void BasicHTTPIOProcessor::httpRecvRequest(const HTTPServer::Request& req) {
std::string value = evhttp_decode_uri(term.substr(split + 1).c_str());
if (boost::iequals(key, "_scxmleventname")) {
reqEvent.name = value;
+ } else if (boost::iequals(key, "content")) {
+ reqEvent.initContent(value);
} else {
reqEvent.data.compound[key] = value;
reqEvent.params.insert(std::make_pair(key, value));
@@ -187,11 +189,19 @@ void BasicHTTPIOProcessor::send(const SendRequest& req) {
}
// content
- if (kvps.str().size() > 0) {
- targetURL.setOutContent(kvps.str());
- } else if (req.content.size() > 0) {
- targetURL.setOutContent(req.content);
+
+ if (req.content.size() > 0) {
+ kvps << kvpSeperator << evhttp_encode_uri("content") << "=" << evhttp_encode_uri(req.content.c_str());
+ kvpSeperator = "&";
+ }
+ if (req.dom) {
+ std::stringstream xmlStream;
+ xmlStream << req.dom;
+ kvps << kvpSeperator << evhttp_encode_uri("content") << "=" << evhttp_encode_uri(xmlStream.str().c_str());
+ kvpSeperator = "&";
}
+ targetURL.setOutContent(kvps.str());
+
targetURL.setRequestType("post");
targetURL.addMonitor(this);
diff --git a/test/samples/uscxml/test-prolog.scxml b/test/samples/uscxml/test-prolog.scxml
index 8d171e6..e802c8e 100644
--- a/test/samples/uscxml/test-prolog.scxml
+++ b/test/samples/uscxml/test-prolog.scxml
@@ -11,6 +11,8 @@
<!-- if no id is given, we assume assertion mode -->
<data>
+ :- multifile father/2.
+ :- multifile mother/2.
father(bob, jim).
father(bob, john).
father(bob, jack).
@@ -19,13 +21,13 @@
mother(martha, jack).
</data>
<!-- if id is given, we treat it the name of a predicate -->
- <data id="sibling/2">
+ <!-- data id="sibling/2">
jim, john.
jim, jack.
john, jack.
- </data>
+ </data -->
<!-- if an id is given, json data is transformed into a prolog compound term -->
- <data id="john">
+ <!-- data id="john">
{
"name": "John",
"age": 25,
@@ -44,9 +46,9 @@
}
]
}
- </data>
+ </data -->
<!-- If an id is given, parse XML as nested compund terms -->
- <data id="jack">
+ <!--data id="jack">
<person name="jack" age="27">
<address>
<street>23 3rd Street</street>
@@ -56,12 +58,13 @@
384 234-5534
</phone>
</person>
- </data>
+ </data -->
</datamodel>
<!--
scripts are executed in assertion mode
-->
<script>
+ :- multifile older/2.
older(bob, martha).
older(bob, john).
older(bob, jack).
@@ -78,7 +81,7 @@
<send event="foo">This is a foo event.</send>
</onentry>
<!-- boolean expressions are true if there is a solution-->
- <transition event="foo" cond="not(father(X, jim)), mother(X, john), older(bob, X)." target="sending"/>
+ <transition event="foo" cond="older(bob, martha)." target="sending"/>
</state>
<state id="sending">
<onentry>
@@ -99,18 +102,26 @@
</content>
</send>
</onentry>
- <transition event="bar" cond="in('sending')" target="assigning"/>
+ <transition event="bar" cond="event(name(X)), X='bar'." target="assigning"/>
</state>
<state id="assigning">
<onentry>
+ <log label="Index" expr="listing." />
+ <foreach array="father(bob, X)"
+ item="child"
+ index="index">
+ <log label="child" expr="child(X)" />
+ <log label="index" expr="index(X)" />
+ </foreach>
+ <raise event="baz" />
<!-- assigning with retract attribute -->
- <assign id="older/2" retract="">
+ <!--assign id="older/2" retract="older/2">
older(jim, john).
older(jim, jack).
older(john, jack).
- </assign>
+ </assign-->
</onentry>
- <transition event="bar" cond="in('assigning')" target="end"/>
+ <transition event="baz" cond="in('assigning')" target="end"/>
</state>
<state id="end" final="true">
<onentry>
diff --git a/test/samples/uscxml/test-prolog2.scxml b/test/samples/uscxml/test-prolog2.scxml
new file mode 100644
index 0000000..f697b89
--- /dev/null
+++ b/test/samples/uscxml/test-prolog2.scxml
@@ -0,0 +1,38 @@
+<scxml datamodel="prolog">
+ <data id="father/2">
+ bob, jim.
+ bob, john.
+ </data>
+ <data>
+ mother(martha, jim).
+ mother(martha, john).
+ </data>
+ <state id="s1">
+ <onentry>
+ <foreach array="father(bob, X)"
+ item="child"
+ index="index">
+ <log label="index" expr="index(X)" />
+ <log label="child" expr="child(X)" />
+ </foreach>
+ </onentry>
+ <transition target="s2"
+ cond="mother(martha, X), father(bob, X)"/>
+ </state>
+ <state id="s2">
+ <onentry>
+ <send type="basichttp"
+ targetexpr="ioprocessors(basichttp(location(X)))"
+ event="foo">
+ <content>
+ <p>Snippet of XML</p>
+ </content>
+ </send>
+ </onentry>
+ <transition
+ target="end"
+ event="foo"
+ cond="member(element('p',_,_), X), event(data(X))" />
+ </state>
+ <state id="end" final="true" />
+</scxml>