diff options
author | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-04-28 20:59:38 (GMT) |
---|---|---|
committer | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-04-28 20:59:38 (GMT) |
commit | 3d3f434c5be68a7e2b86ecccbaba40887852db99 (patch) | |
tree | e9378262ad68305f5add6f27a4338c21033bc5e1 | |
parent | 3b7be6b309e3a446e64f99511806c0ea7a440b8e (diff) | |
download | uscxml-3d3f434c5be68a7e2b86ecccbaba40887852db99.zip uscxml-3d3f434c5be68a7e2b86ecccbaba40887852db99.tar.gz uscxml-3d3f434c5be68a7e2b86ecccbaba40887852db99.tar.bz2 |
More work on prolog datamodel
-rw-r--r-- | CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/uscxml/Message.cpp | 24 | ||||
-rw-r--r-- | src/uscxml/Message.h | 4 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp | 96 | ||||
-rw-r--r-- | src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp | 18 | ||||
-rw-r--r-- | test/samples/uscxml/test-prolog.scxml | 33 | ||||
-rw-r--r-- | test/samples/uscxml/test-prolog2.scxml | 38 |
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> |