summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt7
-rw-r--r--README.md2
-rwxr-xr-xcontrib/build-scripts/build-libevent-linux.sh2
-rw-r--r--contrib/cmake/FindLua.cmake171
-rw-r--r--contrib/cmake/FindSWI.cmake2
-rw-r--r--src/uscxml/URL.cpp11
-rw-r--r--src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp135
-rw-r--r--src/uscxml/plugins/ioprocessor/modality/MMIMessages.h15
-rw-r--r--src/uscxml/server/Socket.cpp109
-rw-r--r--src/uscxml/server/Socket.h22
-rw-r--r--src/uscxml/transform/ChartToFSM.cpp136
-rw-r--r--src/uscxml/transform/ChartToFSM.h9
-rw-r--r--test/CMakeLists.txt5
-rw-r--r--test/src/test-sockets.cpp67
-rw-r--r--test/src/test-vxml-mmi-http.cpp165
-rw-r--r--test/src/test-vxml-mmi-socket.cpp133
16 files changed, 804 insertions, 187 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4905554..ccc4a11 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,7 +14,7 @@ endif()
# specify USCXML version
SET(USCXML_VERSION_MAJOR "0")
SET(USCXML_VERSION_MINOR "3")
-SET(USCXML_VERSION_PATCH "0")
+SET(USCXML_VERSION_PATCH "1")
SET(USCXML_VERSION ${USCXML_VERSION_MAJOR}.${USCXML_VERSION_MINOR}.${USCXML_VERSION_PATCH})
# build type has to be set before the project definition4
@@ -164,7 +164,7 @@ else ()
endif()
endif()
-SET(USCXML_LIBRARY_HOST_URL_PREFIX "http://uscxml.mintwerk.de/prebuilt" CACHE STRING "The root path of an URL where to look for prebuilt libraries.")
+SET(USCXML_LIBRARY_HOST_URL_PREFIX "http://uscxml.tk.informatik.tu-darmstadt.de/prebuilt" CACHE STRING "The root path of an URL where to look for prebuilt libraries.")
if (CMAKE_CROSSCOMPILING)
if (IOS)
@@ -238,7 +238,8 @@ if (NOT EXISTS ${USCXML_PREBUILT_LIBRARY_PATH})
)
file(WRITE ${PROJECT_SOURCE_DIR}/contrib/prebuilt/${USCXML_PLATFORM_ID}/VERSION.txt "${USCXML_VERSION}")
else()
- message("Downloading prebuilt libraries failed with ${STATUS_STRING} - maybe this platform is not supported?")
+ message("Downloading prebuilt libraries failed with ${STATUS_STRING}")
+ message("Provide prebuilts in ${PROJECT_SOURCE_DIR}/contrib/prebuilt/${USCXML_PLATFORM_ID}/")
endif()
endif()
diff --git a/README.md b/README.md
index 14bd901..76a4eff 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@
## General
uSCXML is a SCXML interpreter written in C/C++. It is [standards compliant](#test-reports) and [easily extended](#extending-uscxml)
-even in C# and Java. It runs on <b>Linux</b>, <b>Windows</b> and <b>Mac OSX</b>, each 32- as well as 64Bits as well as <b>iOS</b>.
+even in C# and Java. It runs on <b>Linux</b>, <b>Windows</b>, <b>Raspberry Pi</b> and <b>Mac OSX</b>, each 32- as well as 64Bits as well as <b>iOS</b>.
* <b>Datamodels</b>
* Full [ECMAScript datamodel](https://github.com/tklab-tud/uscxml/tree/master/src/uscxml/plugins/datamodel/ecmascript) using Google's v8 (and JavaScriptCore on MacOSX and iOS)
diff --git a/contrib/build-scripts/build-libevent-linux.sh b/contrib/build-scripts/build-libevent-linux.sh
index cdb6115..c57ad52 100755
--- a/contrib/build-scripts/build-libevent-linux.sh
+++ b/contrib/build-scripts/build-libevent-linux.sh
@@ -20,7 +20,7 @@ if [ ! -f event.c ]; then
exit
fi
-rm lib*.a
+#rm lib*.a
if [ -f Makefile ]; then
make clean
diff --git a/contrib/cmake/FindLua.cmake b/contrib/cmake/FindLua.cmake
new file mode 100644
index 0000000..f8b68b2
--- /dev/null
+++ b/contrib/cmake/FindLua.cmake
@@ -0,0 +1,171 @@
+#.rst:
+# FindLua
+# -------
+#
+#
+#
+# Locate Lua library This module defines
+#
+# ::
+#
+# LUA_FOUND - if false, do not try to link to Lua
+# LUA_LIBRARIES - both lua and lualib
+# LUA_INCLUDE_DIR - where to find lua.h
+# LUA_VERSION_STRING - the version of Lua found
+# LUA_VERSION_MAJOR - the major version of Lua
+# LUA_VERSION_MINOR - the minor version of Lua
+# LUA_VERSION_PATCH - the patch version of Lua
+#
+#
+#
+# Note that the expected include convention is
+#
+# ::
+#
+# #include "lua.h"
+#
+# and not
+#
+# ::
+#
+# #include <lua/lua.h>
+#
+# This is because, the lua location is not standardized and may exist in
+# locations other than lua/
+
+#=============================================================================
+# Copyright 2007-2009 Kitware, Inc.
+# Copyright 2013 Rolf Eike Beer <eike@sf-mail.de>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+unset(_lua_include_subdirs)
+unset(_lua_library_names)
+
+# this is a function only to have all the variables inside go away automatically
+function(set_lua_version_vars)
+ set(LUA_VERSIONS5 5.3 5.2 5.1 5.0)
+
+ if (Lua_FIND_VERSION_EXACT)
+ if (Lua_FIND_VERSION_COUNT GREATER 1)
+ set(lua_append_versions ${Lua_FIND_VERSION_MAJOR} ${Lua_FIND_VERSION_MINOR})
+ endif ()
+ elseif (Lua_FIND_VERSION)
+ # once there is a different major version supported this should become a loop
+ if (NOT Lua_FIND_VERSION_MAJOR GREATER 5)
+ if (Lua_FIND_VERSION_COUNT EQUAL 1)
+ set(lua_append_versions ${LUA_VERSIONS5})
+ else ()
+ foreach (subver IN LISTS LUA_VERSIONS5)
+ if (NOT subver VERSION_LESS ${Lua_FIND_VERSION})
+ list(APPEND lua_append_versions ${subver})
+ endif ()
+ endforeach ()
+ endif ()
+ endif ()
+ else ()
+ # once there is a different major version supported this should become a loop
+ set(lua_append_versions ${LUA_VERSIONS5})
+ endif ()
+
+ foreach (ver IN LISTS lua_append_versions)
+ string(REGEX MATCH "^([0-9]+)\\.([0-9]+)$" _ver "${ver}")
+ list(APPEND _lua_include_subdirs
+ include/lua${CMAKE_MATCH_1}${CMAKE_MATCH_2}
+ include/lua${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
+ include/lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
+ )
+ list(APPEND _lua_library_names
+ lua${CMAKE_MATCH_1}${CMAKE_MATCH_2}
+ lua${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
+ lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
+ )
+ endforeach ()
+
+ set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE)
+ set(_lua_library_names "${_lua_library_names}" PARENT_SCOPE)
+endfunction(set_lua_version_vars)
+
+set_lua_version_vars()
+
+find_path(LUA_INCLUDE_DIR lua.h
+ HINTS
+ ENV LUA_DIR
+ PATH_SUFFIXES ${_lua_include_subdirs} include/lua include
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt
+)
+unset(_lua_include_subdirs)
+
+find_library(LUA_LIBRARY
+ NAMES ${_lua_library_names} lua
+ HINTS
+ ENV LUA_DIR
+ PATH_SUFFIXES lib
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+)
+unset(_lua_library_names)
+
+if (LUA_LIBRARY)
+ # include the math library for Unix
+ if (UNIX AND NOT APPLE AND NOT BEOS)
+ find_library(LUA_MATH_LIBRARY m)
+ set(LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}")
+ # For Windows and Mac, don't need to explicitly include the math library
+ else ()
+ set(LUA_LIBRARIES "${LUA_LIBRARY}")
+ endif ()
+endif ()
+
+if (LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h")
+ # At least 5.[012] have different ways to express the version
+ # so all of them need to be tested. Lua 5.2 defines LUA_VERSION
+ # and LUA_RELEASE as joined by the C preprocessor, so avoid those.
+ file(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_strings
+ REGEX "^#define[ \t]+LUA_(RELEASE[ \t]+\"Lua [0-9]|VERSION([ \t]+\"Lua [0-9]|_[MR])).*")
+
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MAJOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MAJOR ";${lua_version_strings};")
+ if (LUA_VERSION_MAJOR MATCHES "^[0-9]+$")
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MINOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MINOR ";${lua_version_strings};")
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_RELEASE[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_PATCH ";${lua_version_strings};")
+ set(LUA_VERSION_STRING "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_PATCH}")
+ else ()
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
+ if (NOT LUA_VERSION_STRING MATCHES "^[0-9.]+$")
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
+ endif ()
+ string(REGEX REPLACE "^([0-9]+)\\.[0-9.]*$" "\\1" LUA_VERSION_MAJOR "${LUA_VERSION_STRING}")
+ string(REGEX REPLACE "^[0-9]+\\.([0-9]+)[0-9.]*$" "\\1" LUA_VERSION_MINOR "${LUA_VERSION_STRING}")
+ string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]).*" "\\1" LUA_VERSION_PATCH "${LUA_VERSION_STRING}")
+ endif ()
+
+ unset(lua_version_strings)
+endif()
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if
+# all listed variables are TRUE
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua
+ REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR
+ VERSION_VAR LUA_VERSION_STRING)
+
+mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARY LUA_MATH_LIBRARY)
diff --git a/contrib/cmake/FindSWI.cmake b/contrib/cmake/FindSWI.cmake
index 7aa5f32..f89f705 100644
--- a/contrib/cmake/FindSWI.cmake
+++ b/contrib/cmake/FindSWI.cmake
@@ -186,7 +186,7 @@ endif()
#message(FATAL_ERROR "SWI_BINARY: ${SWI_BINARY} / SWI_LIBRARY_RELEASE: ${SWI_LIBRARY_RELEASE} / SWI_LIBRARY_DEBUG: ${SWI_LIBRARY_DEBUG} / SWI_INCLUDE_DIR: ${SWI_INCLUDE_DIR} / SWI_CPP_INCLUDE_DIR: ${SWI_CPP_INCLUDE_DIR}")
INCLUDE(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(SWI DEFAULT_MSG SWI_LIBRARY SWI_BINARY SWI_INCLUDE_DIR SWI_CPP_INCLUDE_DIR)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SWI DEFAULT_MSG SWI_LIBRARY SWI_BINARY SWI_INCLUDE_DIR)
if (SWI_FOUND)
diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp
index 4e97faa..f5ba85c 100644
--- a/src/uscxml/URL.cpp
+++ b/src/uscxml/URL.cpp
@@ -341,6 +341,7 @@ void URLImpl::setRequestType(const std::string& requestType) {
void URLImpl::setOutContent(const std::string& content) {
_outContent = content;
+ _requestType = "POST";
}
const std::string URLImpl::getInContent(bool forceReload) {
@@ -602,15 +603,17 @@ void URLFetcher::fetchURL(URL& url) {
struct curl_slist* headers = NULL;
std::map<std::string, std::string>::iterator paramIter = url._impl->_outHeader.begin();
while(paramIter != url._impl->_outHeader.end()) {
- char* key = curl_easy_escape(handle, paramIter->first.c_str(), paramIter->first.length());
- char* value = curl_easy_escape(handle, paramIter->second.c_str(), paramIter->second.length());
+// char* key = curl_easy_escape(handle, paramIter->first.c_str(), paramIter->first.length());
+// char* value = curl_easy_escape(handle, paramIter->second.c_str(), paramIter->second.length());
+
+ const char* value = paramIter->second.c_str();
char* header = (char*)malloc(paramIter->first.size() + strlen(value) + 3);
sprintf(header,"%s: %s", paramIter->first.c_str(), value);
headers = curl_slist_append(headers, header);
- curl_free(key);
- curl_free(value);
+// curl_free(key);
+// curl_free(value);
paramIter++;
}
diff --git a/src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp b/src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp
index 6db5ac4..67a2371 100644
--- a/src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp
+++ b/src/uscxml/plugins/ioprocessor/modality/MMIMessages.cpp
@@ -34,6 +34,19 @@
(element.hasAttributeNS(nameSpace, #name) ? element.getAttributeNS(nameSpace, #name) : "") \
)
+#define FIND_EVENT_NODE(node)\
+while (node) {\
+ if (node.getNodeType() == Node_base::ELEMENT_NODE) {\
+ if (boost::iequals(node.getLocalName(), "MMI")) {\
+ node = node.getFirstChild();\
+ continue;\
+ } else {\
+ break;\
+ }\
+ }\
+ node = node.getNextSibling();\
+}\
+
namespace uscxml {
@@ -42,9 +55,21 @@ using namespace Arabica::DOM;
std::string MMIEvent::nameSpace = "http://www.w3.org/2008/04/mmi-arch";
MMIEvent::Type MMIEvent::getType(Arabica::DOM::Node<std::string> node) {
- if (!node)
+ if (!node || node.getNodeType() != Arabica::DOM::Node_base::ELEMENT_NODE)
return INVALID;
+ // MMI container?
+ if (boost::iequals(node.getLocalName(), "MMI")) {
+ node = node.getFirstChild();
+ if (!node)
+ return INVALID;
+ while(node.getNodeType() != Arabica::DOM::Node_base::ELEMENT_NODE) {
+ node = node.getNextSibling();
+ if (!node)
+ return INVALID;
+ }
+ }
+
if (boost::iequals(node.getLocalName(), "NEWCONTEXTREQUEST"))
return NEWCONTEXTREQUEST;
if (boost::iequals(node.getLocalName(), "NEWCONTEXTRESPONSE"))
@@ -84,32 +109,9 @@ MMIEvent::Type MMIEvent::getType(Arabica::DOM::Node<std::string> node) {
return INVALID;
}
-Arabica::DOM::Node<std::string> MMIEvent::getEventNode(Arabica::DOM::Node<std::string> node) {
- if (!node)
- return node;
-
- if (node.getNodeType() == Node_base::DOCUMENT_NODE)
- node = Arabica::DOM::Document<std::string>(node).getDocumentElement();
-
- // get the first element
- while (node && node.getNodeType() != Node_base::ELEMENT_NODE) {
- node = node.getNextSibling();
- }
- // get the contained message
- if (node && getType(node) == INVALID) {
- node = node.getFirstChild();
- while (node && node.getNodeType() != Node_base::ELEMENT_NODE && getType(node) == INVALID) {
- node = node.getNextSibling();
- }
- }
- return node;
-}
-
-
-Arabica::DOM::Document<std::string> MMIEvent::toXML() const {
+Arabica::DOM::Document<std::string> MMIEvent::toXML(bool encapsulateInMMI) 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> msgElem = doc.createElementNS(nameSpace, tagName);
msgElem.setAttributeNS(nameSpace, "Source", source);
msgElem.setAttributeNS(nameSpace, "Target", target);
@@ -136,21 +138,25 @@ Arabica::DOM::Document<std::string> MMIEvent::toXML() const {
msgElem.appendChild(dataElem);
}
-// mmiElem.appendChild(msgElem);
-// doc.appendChild(mmiElem);
- doc.appendChild(msgElem);
+ if (encapsulateInMMI) {
+ Element<std::string> mmiElem = doc.createElementNS(nameSpace, "mmi");
+ mmiElem.appendChild(msgElem);
+ doc.appendChild(mmiElem);
+ } else {
+ doc.appendChild(msgElem);
+ }
return doc;
}
-Arabica::DOM::Document<std::string> ContextualizedRequest::toXML() const {
- Document<std::string> doc = MMIEvent::toXML();
+Arabica::DOM::Document<std::string> ContextualizedRequest::toXML(bool encapsulateInMMI) const {
+ Document<std::string> doc = MMIEvent::toXML(encapsulateInMMI);
Element<std::string> msgElem = Element<std::string>(doc.getDocumentElement().getFirstChild());
msgElem.setAttributeNS(nameSpace, "Context", context);
return doc;
}
-Arabica::DOM::Document<std::string> ContentRequest::toXML() const {
- Document<std::string> doc = ContextualizedRequest::toXML();
+Arabica::DOM::Document<std::string> ContentRequest::toXML(bool encapsulateInMMI) const {
+ Document<std::string> doc = ContextualizedRequest::toXML(encapsulateInMMI);
Element<std::string> msgElem = Element<std::string>(doc.getDocumentElement().getFirstChild());
if (contentURL.href.size() > 0) {
@@ -185,15 +191,15 @@ Arabica::DOM::Document<std::string> ContentRequest::toXML() const {
return doc;
}
-Arabica::DOM::Document<std::string> ExtensionNotification::toXML() const {
- Document<std::string> doc = ContextualizedRequest::toXML();
+Arabica::DOM::Document<std::string> ExtensionNotification::toXML(bool encapsulateInMMI) const {
+ Document<std::string> doc = ContextualizedRequest::toXML(encapsulateInMMI);
Element<std::string> msgElem = Element<std::string>(doc.getDocumentElement().getFirstChild());
msgElem.setAttributeNS(nameSpace, "Name", name);
return doc;
}
-Arabica::DOM::Document<std::string> StatusResponse::toXML() const {
- Document<std::string> doc = ContextualizedRequest::toXML();
+Arabica::DOM::Document<std::string> StatusResponse::toXML(bool encapsulateInMMI) const {
+ Document<std::string> doc = ContextualizedRequest::toXML(encapsulateInMMI);
Element<std::string> msgElem = Element<std::string>(doc.getDocumentElement().getFirstChild());
if (status == ALIVE) {
msgElem.setAttributeNS(nameSpace, "Status", "alive");
@@ -207,8 +213,8 @@ Arabica::DOM::Document<std::string> StatusResponse::toXML() const {
return doc;
}
-Arabica::DOM::Document<std::string> StatusInfoResponse::toXML() const {
- Document<std::string> doc = StatusResponse::toXML();
+Arabica::DOM::Document<std::string> StatusInfoResponse::toXML(bool encapsulateInMMI) const {
+ Document<std::string> doc = StatusResponse::toXML(encapsulateInMMI);
Element<std::string> msgElem = Element<std::string>(doc.getDocumentElement().getFirstChild());
Element<std::string> statusInfoElem = doc.createElementNS(nameSpace, "StatusInfo");
@@ -219,8 +225,8 @@ Arabica::DOM::Document<std::string> StatusInfoResponse::toXML() const {
return doc;
}
-Arabica::DOM::Document<std::string> StatusRequest::toXML() const {
- Document<std::string> doc = ContextualizedRequest::toXML();
+Arabica::DOM::Document<std::string> StatusRequest::toXML(bool encapsulateInMMI) const {
+ Document<std::string> doc = ContextualizedRequest::toXML(encapsulateInMMI);
Element<std::string> msgElem = Element<std::string>(doc.getDocumentElement().getFirstChild());
if (automaticUpdate) {
@@ -234,11 +240,8 @@ Arabica::DOM::Document<std::string> StatusRequest::toXML() const {
MMIEvent MMIEvent::fromXML(Arabica::DOM::Node<std::string> node, InterpreterImpl* interpreter) {
MMIEvent msg;
- while (node) {
- if (node.getNodeType() == Node_base::ELEMENT_NODE)
- break;
- node = node.getNextSibling();
- }
+ FIND_EVENT_NODE(node);
+
Element<std::string> msgElem(node);
msg.source = STRING_ATTR_OR_EXPR(msgElem, Source);
msg.target = STRING_ATTR_OR_EXPR(msgElem, Target);
@@ -281,11 +284,8 @@ MMIEvent::operator Event() const {
ContextualizedRequest ContextualizedRequest::fromXML(Arabica::DOM::Node<std::string> node, InterpreterImpl* interpreter) {
ContextualizedRequest msg(MMIEvent::fromXML(node, interpreter));
- while (node) {
- if (node.getNodeType() == Node_base::ELEMENT_NODE)
- break;
- node = node.getNextSibling();
- }
+ FIND_EVENT_NODE(node);
+
Element<std::string> msgElem(node);
msg.context = STRING_ATTR_OR_EXPR(msgElem, Context);
return msg;
@@ -300,11 +300,8 @@ ContextualizedRequest::operator Event() const {
ContentRequest ContentRequest::fromXML(Arabica::DOM::Node<std::string> node, InterpreterImpl* interpreter) {
ContentRequest msg(ContextualizedRequest::fromXML(node, interpreter));
- while (node) {
- if (node.getNodeType() == Node_base::ELEMENT_NODE)
- break;
- node = node.getNextSibling();
- }
+ FIND_EVENT_NODE(node);
+
Element<std::string> msgElem(node);
Element<std::string> contentElem;
@@ -344,11 +341,8 @@ ContentRequest ContentRequest::fromXML(Arabica::DOM::Node<std::string> node, Int
ExtensionNotification ExtensionNotification::fromXML(Arabica::DOM::Node<std::string> node, InterpreterImpl* interpreter) {
ExtensionNotification msg(ContextualizedRequest::fromXML(node, interpreter));
- while (node) {
- if (node.getNodeType() == Node_base::ELEMENT_NODE)
- break;
- node = node.getNextSibling();
- }
+ FIND_EVENT_NODE(node);
+
Element<std::string> msgElem(node);
msg.name = STRING_ATTR_OR_EXPR(msgElem, Name);
msg.type = EXTENSIONNOTIFICATION;
@@ -367,11 +361,8 @@ ExtensionNotification::operator Event() const {
StatusResponse StatusResponse::fromXML(Arabica::DOM::Node<std::string> node, InterpreterImpl* interpreter) {
StatusResponse msg(ContextualizedRequest::fromXML(node, interpreter));
- while (node) {
- if (node.getNodeType() == Node_base::ELEMENT_NODE)
- break;
- node = node.getNextSibling();
- }
+ FIND_EVENT_NODE(node);
+
Element<std::string> msgElem(node);
std::string status = STRING_ATTR_OR_EXPR(msgElem, Status);
@@ -390,11 +381,8 @@ StatusResponse StatusResponse::fromXML(Arabica::DOM::Node<std::string> node, Int
StatusInfoResponse StatusInfoResponse::fromXML(Arabica::DOM::Node<std::string> node, InterpreterImpl* interpreter) {
StatusInfoResponse msg(StatusResponse::fromXML(node, interpreter));
- while (node) {
- if (node.getNodeType() == Node_base::ELEMENT_NODE)
- break;
- node = node.getNextSibling();
- }
+ FIND_EVENT_NODE(node);
+
Element<std::string> msgElem(node);
Element<std::string> statusInfoElem;
@@ -424,11 +412,8 @@ StatusInfoResponse StatusInfoResponse::fromXML(Arabica::DOM::Node<std::string> n
StatusRequest StatusRequest::fromXML(Arabica::DOM::Node<std::string> node, InterpreterImpl* interpreter) {
StatusRequest msg(ContextualizedRequest::fromXML(node, interpreter));
- while (node) {
- if (node.getNodeType() == Node_base::ELEMENT_NODE)
- break;
- node = node.getNextSibling();
- }
+ FIND_EVENT_NODE(node);
+
Element<std::string> msgElem(node);
std::string autoUpdate = STRING_ATTR_OR_EXPR(msgElem, RequestAutomaticUpdate);
diff --git a/src/uscxml/plugins/ioprocessor/modality/MMIMessages.h b/src/uscxml/plugins/ioprocessor/modality/MMIMessages.h
index fc9142e..e4456f8 100644
--- a/src/uscxml/plugins/ioprocessor/modality/MMIMessages.h
+++ b/src/uscxml/plugins/ioprocessor/modality/MMIMessages.h
@@ -51,9 +51,8 @@ public:
};
static Type getType(Arabica::DOM::Node<std::string> node);
- static Arabica::DOM::Node<std::string> getEventNode(Arabica::DOM::Node<std::string> node);
- virtual Arabica::DOM::Document<std::string> toXML() const;
+ virtual Arabica::DOM::Document<std::string> toXML(bool encapsulateInMMI = false) const;
static MMIEvent fromXML(Arabica::DOM::Node<std::string> node,
InterpreterImpl* interpreter = NULL);
@@ -107,7 +106,7 @@ public:
class ContextualizedRequest : public MMIEvent {
public:
- virtual Arabica::DOM::Document<std::string> toXML() const;
+ virtual Arabica::DOM::Document<std::string> toXML(bool encapsulateInMMI = false) const;
static ContextualizedRequest fromXML(Arabica::DOM::Node<std::string> node,
InterpreterImpl* interpreter = NULL);
operator Event() const;
@@ -207,7 +206,7 @@ public:
tagName = "StatusRequest";
type = STARTREQUEST;
}
- virtual Arabica::DOM::Document<std::string> toXML() const;
+ virtual Arabica::DOM::Document<std::string> toXML(bool encapsulateInMMI = false) const;
static StatusRequest fromXML(Arabica::DOM::Node<std::string> node,
InterpreterImpl* interpreter = NULL);
operator Event() const;
@@ -224,7 +223,7 @@ public:
std::string fetchTimeout;
};
- virtual Arabica::DOM::Document<std::string> toXML() const;
+ virtual Arabica::DOM::Document<std::string> toXML(bool encapsulateInMMI = false) const;
static ContentRequest fromXML(Arabica::DOM::Node<std::string> node,
InterpreterImpl* interpreter = NULL);
operator Event() const;
@@ -284,7 +283,7 @@ public:
tagName = "ExtensionNotification";
type = EXTENSIONNOTIFICATION;
}
- virtual Arabica::DOM::Document<std::string> toXML() const;
+ virtual Arabica::DOM::Document<std::string> toXML(bool encapsulateInMMI = false) const;
static ExtensionNotification fromXML(Arabica::DOM::Node<std::string> node,
InterpreterImpl* interpreter = NULL);
operator Event() const;
@@ -307,7 +306,7 @@ public:
tagName = "StatusResponse";
type = STATUSRESPONSE;
}
- virtual Arabica::DOM::Document<std::string> toXML() const;
+ virtual Arabica::DOM::Document<std::string> toXML(bool encapsulateInMMI = false) const;
static StatusResponse fromXML(Arabica::DOM::Node<std::string> node,
InterpreterImpl* interpreter = NULL);
Status status;
@@ -317,7 +316,7 @@ protected:
class StatusInfoResponse : public StatusResponse {
public:
- virtual Arabica::DOM::Document<std::string> toXML() const;
+ virtual Arabica::DOM::Document<std::string> toXML(bool encapsulateInMMI = false) const;
StatusInfoResponse(const StatusResponse& father) : StatusResponse(father) {}
static StatusInfoResponse fromXML(Arabica::DOM::Node<std::string> node,
InterpreterImpl* interpreter = NULL);
diff --git a/src/uscxml/server/Socket.cpp b/src/uscxml/server/Socket.cpp
index 9c844e5..2d474ea 100644
--- a/src/uscxml/server/Socket.cpp
+++ b/src/uscxml/server/Socket.cpp
@@ -67,10 +67,16 @@ Socket::~Socket() {
}
void Socket::setupSockAddr(const std::string& address, int port) {
+
if (address == "*") {
_sin.sin_addr.s_addr = 0;
} else {
- _sin.sin_addr.s_addr = inet_addr(address.c_str());
+ struct hostent *he = NULL;
+ if ( (he = gethostbyname(address.c_str()) ) != NULL ) {
+ memcpy(&_sin.sin_addr, he->h_addr_list[0], he->h_length);
+ } else {
+ _sin.sin_addr.s_addr = inet_addr(address.c_str());
+ }
if (_sin.sin_addr.s_addr == INADDR_NONE)
throw std::runtime_error(std::string("inet_addr: ") + strerror(errno));
}
@@ -83,6 +89,34 @@ void Socket::setBlockSizeRead(size_t size) {
_blockSizeRead = size;
}
+void Socket::parseAddress(const std::string& address, std::string& protocol, std::string& hostName, uint16_t& port) {
+ // tcp://hostname:port
+ size_t protEnd = address.find("://");
+ if (protEnd != std::string::npos) {
+ protocol = address.substr(0, protEnd);
+ protEnd += 3;
+ } else {
+ protocol = "tcp";
+ protEnd = 0;
+ }
+
+ size_t hostEnd = address.find(":", protEnd);
+ if (hostEnd != std::string::npos) {
+ hostName = address.substr(protEnd, hostEnd - protEnd);
+ hostEnd += 1;
+ } else {
+ hostName = "127.0.0.1";
+ hostEnd = protEnd;
+ }
+
+ if (hostEnd < address.size()) {
+ port = strTo<uint16_t>(address.substr(hostEnd));
+ } else {
+ port = 0;
+ }
+}
+
+
ClientSocket::ClientSocket(int domain, int type, int protocol) : Socket(domain, type, protocol), _clientEvent(NULL) {
}
@@ -95,7 +129,7 @@ ClientSocket::~ClientSocket() {
}
void ClientSocket::errorCallback(struct bufferevent *bev, short error, void *ctx) {
- ClientSocket* instance = (ClientSocket*)ctx;
+// ClientSocket* instance = (ClientSocket*)ctx;
// tthread::lock_guard<tthread::recursive_mutex> lock(instance->_mutex);
if (error & BEV_EVENT_READING) {
@@ -115,6 +149,14 @@ void ClientSocket::errorCallback(struct bufferevent *bev, short error, void *ctx
// bufferevent_free(bev);
}
+void ClientSocket::connect(const std::string& address) {
+ std::string _prot;
+ std::string _address;
+ uint16_t _port;
+ parseAddress(address, _prot, _address, _port);
+ connect(_address, _port);
+}
+
void ClientSocket::connect(const std::string& address, int port) {
// tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
@@ -123,11 +165,15 @@ void ClientSocket::connect(const std::string& address, int port) {
throw std::runtime_error(std::string("connect: ") + strerror(errno));
}
- _clientEvent = bufferevent_socket_new(_base->base, _socketFD, 0); //BEV_OPT_THREADSAFE);
+ _clientEvent = bufferevent_socket_new(_base->base, _socketFD, BEV_OPT_THREADSAFE); //BEV_OPT_THREADSAFE);
bufferevent_setcb(_clientEvent, ClientSocket::readCallback, NULL, ClientSocket::errorCallback, this);
bufferevent_enable(_clientEvent, EV_READ|EV_WRITE);
}
+int ClientSocket::write(const std::string& data) {
+ return write(data.data(), data.size());
+}
+
int ClientSocket::write(const char* data, size_t size) {
// tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
bufferevent_write(_clientEvent, data, size);
@@ -138,14 +184,15 @@ void ClientSocket::readCallback(struct bufferevent *bev, void *ctx) {
ClientSocket* instance = (ClientSocket*)ctx;
// tthread::lock_guard<tthread::recursive_mutex> lock(instance->_mutex);
- size_t n;
+ int n;
struct evbuffer* input;
char* data = (char*)malloc(instance->_blockSizeRead);
input = bufferevent_get_input(bev);
- n = evbuffer_remove(input, data, instance->_blockSizeRead);
-
- instance->readCallback(data, n);
+
+ while((n = evbuffer_remove(input, data, instance->_blockSizeRead)) > 0) {
+ instance->readCallback(data, n);
+ }
free(data);
}
@@ -201,7 +248,6 @@ void ServerSocket::errorCallback(struct bufferevent *bev, short error, void *ctx
#else
close(conn->second.fd);
#endif
-
instance->_connections.erase(conn);
}
} else if (error & BEV_EVENT_EOF) {
@@ -229,9 +275,9 @@ void ServerSocket::readCallback(struct bufferevent *bev, void *ctx) {
char* data = (char*)malloc(instance->_blockSizeRead);
input = bufferevent_get_input(bev);
- n = evbuffer_remove(input, data, instance->_blockSizeRead);
-
- instance->readCallback(data, n, instance->_connections[bev]);
+ while((n = evbuffer_remove(input, data, instance->_blockSizeRead)) > 0) {
+ instance->readCallback(data, n, instance->_connections[bev]);
+ }
free(data);
}
@@ -241,11 +287,30 @@ void ServerSocket::bind() {
}
}
+void ServerSocket::listen(const std::string& address) {
+ std::string _prot;
+ std::string _address;
+ uint16_t _port;
+ parseAddress(address, _prot, _address, _port);
+ listen(_address, _port);
+}
+
void ServerSocket::listen(const std::string& address, int port) {
// tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
setupSockAddr(address, port);
bind();
+ int reuseaddr_on = 1;
+ setsockopt(_socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, sizeof(reuseaddr_on));
+
+ int flags = fcntl(_socketFD, F_GETFL);
+ if (flags >= 0) {
+ flags |= O_NONBLOCK;
+ if (fcntl(_socketFD, F_SETFL, flags) < 0) {
+ // could not set to non-blocj
+ }
+ }
+
_listenerEvent = event_new(_base->base, _socketFD, EV_READ|EV_PERSIST, acceptCallback, (void*)this);
/*XXX check it */
event_add(_listenerEvent, NULL);
@@ -275,7 +340,7 @@ void ServerSocket::acceptCallback(evutil_socket_t listener, short event, void *c
} else {
struct bufferevent *bev;
evutil_make_socket_nonblocking(fd);
- bev = bufferevent_socket_new(instance->_base->base, fd, BEV_OPT_THREADSAFE);
+ bev = bufferevent_socket_new(instance->_base->base, fd, BEV_OPT_THREADSAFE); //BEV_OPT_THREADSAFE
bufferevent_setcb(bev, ServerSocket::readCallback, NULL, ServerSocket::errorCallback, ctx);
bufferevent_enable(bev, EV_READ|EV_WRITE);
@@ -288,4 +353,24 @@ void ServerSocket::Connection::reply(const char* data, size_t size) {
bufferevent_write(bufferEvent, data, size);
}
+void PacketServerSocket::readCallback(const char* data, size_t size, Connection& conn) {
+ std::stringstream& fragment = _fragments[conn];
+ fragment << std::string(data, size);
+
+ size_t startPos = 0;
+ size_t endPos;
+ const std::string& buffer = fragment.str();
+ while((endPos = buffer.find(_sep, startPos)) != std::string::npos) {
+// std::cout << ">" << buffer.substr(startPos, endPos - startPos) << "<" << std::endl;
+ readCallback(buffer.substr(startPos, endPos - startPos), conn);
+ startPos = endPos + _sep.size();
+ }
+ if (startPos != 0 && startPos < buffer.size() + 1) {
+ std::string rest = buffer.substr(startPos);
+ fragment.str(std::string());
+ fragment.clear();
+ fragment << rest;
+ }
+}
+
}
diff --git a/src/uscxml/server/Socket.h b/src/uscxml/server/Socket.h
index 5854a46..9330c4b 100644
--- a/src/uscxml/server/Socket.h
+++ b/src/uscxml/server/Socket.h
@@ -23,6 +23,7 @@
#include "uscxml/Common.h" // for USCXML_API
#include "uscxml/concurrency/EventBase.h"
#include <string>
+#include <sstream>
#include <map>
#include <set>
@@ -49,6 +50,7 @@ public:
virtual ~Socket();
void setBlockSizeRead(size_t size);
+ static void parseAddress(const std::string& address, std::string& protocol, std::string& hostName, uint16_t& port);
protected:
@@ -67,6 +69,10 @@ class USCXML_API ServerSocket : public Socket {
public:
class Connection {
public:
+ bool operator<(const Connection& other) const {
+ return bufferEvent < other.bufferEvent;
+ }
+
struct bufferevent* bufferEvent;
int fd;
@@ -77,6 +83,7 @@ public:
virtual ~ServerSocket();
void listen(const std::string& address, int port);
+ void listen(const std::string& address);
virtual void readCallback(const char* data, size_t size, Connection& conn) {};
@@ -93,6 +100,19 @@ protected:
};
+class USCXML_API PacketServerSocket : public ServerSocket {
+public:
+ PacketServerSocket(int domain, int type, int protocol, const std::string& sep) : ServerSocket(domain, type, protocol), _sep(sep) {}
+ virtual ~PacketServerSocket() {}
+
+ void readCallback(const char* data, size_t size, Connection& conn);
+ virtual void readCallback(const std::string& packet, Connection& conn) = 0;
+
+protected:
+ std::string _sep;
+ std::map<Connection, std::stringstream> _fragments;
+};
+
class USCXML_API ClientSocket : public Socket {
public:
ClientSocket(int domain, int type, int protocol);
@@ -100,6 +120,8 @@ public:
virtual void readCallback(const char* data, size_t size) {};
void connect(const std::string& address, int port);
+ void connect(const std::string& address);
+ int write(const std::string& data);
int write(const char* data, size_t size);
diff --git a/src/uscxml/transform/ChartToFSM.cpp b/src/uscxml/transform/ChartToFSM.cpp
index 0a04771..c31853c 100644
--- a/src/uscxml/transform/ChartToFSM.cpp
+++ b/src/uscxml/transform/ChartToFSM.cpp
@@ -163,9 +163,9 @@ FlatteningInterpreter::~FlatteningInterpreter() {
}
Document<std::string> FlatteningInterpreter::getDocument() const {
-// std::cout << "######################" << std::endl;
-// std::cout << _flatDoc << std::endl;
-// std::cout << "######################" << std::endl;
+// std::cerr << "######################" << std::endl;
+// std::cerr << _flatDoc << std::endl;
+// std::cerr << "######################" << std::endl;
return _flatDoc;
}
@@ -175,7 +175,7 @@ InterpreterState FlatteningInterpreter::interpret() {
setupIOProcessors();
uint64_t complexity = ChartToFSM::stateMachineComplexity(_scxml) + 1;
- std::cout << "Approximate Complexity: " << complexity << std::endl;
+ std::cerr << "Approximate Complexity: " << complexity << std::endl;
// initialize the datamodel
std::string datamodelName;
@@ -227,10 +227,10 @@ InterpreterState FlatteningInterpreter::interpret() {
initialTransitions.push_back(transitionElem);
}
labelTransitions();
- weightTransitions();
+// weightTransitions();
indexTransitions(_scxml);
-// std::cout << _scxml << std::endl;
+// std::cerr << _scxml << std::endl;
GlobalTransition* globalTransition = new GlobalTransition(initialTransitions, _dataModel, this);
_start->outgoing[globalTransition->transitionId] = globalTransition;
@@ -245,9 +245,9 @@ InterpreterState FlatteningInterpreter::interpret() {
for(std::map<std::string, GlobalState*>::iterator globalConfIter = _globalConf.begin();
globalConfIter != _globalConf.end();
globalConfIter++) {
- std::cout << globalConfIter->first << std::endl;
+ std::cerr << globalConfIter->first << std::endl;
}
- std::cout << _globalConf.size() << std::endl;
+ std::cerr << _globalConf.size() << std::endl;
#endif
createDocument();
@@ -263,13 +263,13 @@ InterpreterState FlatteningInterpreter::interpret() {
}
}
- std::cout << "Actual Complexity: " << nrStates << std::endl;
+ std::cerr << "Actual Complexity: " << nrStates << std::endl;
return _state;
}
void FlatteningInterpreter::executeContent(const Arabica::DOM::Element<std::string>& content, bool rethrow) {
-// std::cout << content << std::endl;
-// std::cout << TAGNAME(content) << std::endl;
+// std::cerr << content << std::endl;
+// std::cerr << TAGNAME(content) << std::endl;
GlobalTransition::Action action;
@@ -306,7 +306,7 @@ void FlatteningInterpreter::internalDoneSend(const Arabica::DOM::Element<std::st
if (parentIsScxmlState(state))
return;
-// std::cout << "internalDoneSend: " << state << std::endl;
+// std::cerr << "internalDoneSend: " << state << std::endl;
// create onentry with a raise element
Element<std::string> onentry = _flatDoc.createElementNS(_nsInfo.nsURL, "onentry");
@@ -551,23 +551,23 @@ void FlatteningInterpreter::explode() {
break;
NodeSet<std::string> transitions;
-// std::cout << globalState->stateId << " [" << nrElements << "]: " << std::endl;
+// std::cerr << globalState->stateId << " [" << nrElements << "]: " << std::endl;
for (int i = 1; i <= k; i++) {
-// std::cout << stack[i] - 1 << ", ";
+// std::cerr << stack[i] - 1 << ", ";
transitions.push_back(allTransitions[stack[i] - 1]);
}
-// std::cout << std::endl;
+// std::cerr << std::endl;
_perfTotal++;
_perfProcessed++;
if (tthread::chrono::system_clock::now() - _lastTimeStamp > 1000) {
_lastTimeStamp = tthread::chrono::system_clock::now();
-// std::cout << globalState->stateId << " [" << nrElements << "]: " << std::endl;
- std::cout << "States: " << _globalConf.size() << " - ";
- std::cout << "Tested: " << _perfTotal << " [" << _perfProcessed << "/sec] - ";
- std::cout << "Current Complexity: 2**" << nrElements << " = " << pow(2.0, static_cast<double>(nrElements));
- std::cout << std::endl;
+// std::cerr << globalState->stateId << " [" << nrElements << "]: " << std::endl;
+ std::cerr << "States: " << _globalConf.size() << " - ";
+ std::cerr << "Tested: " << _perfTotal << " [" << _perfProcessed << "/sec] - ";
+ std::cerr << "Current Complexity: 2**" << nrElements << " = " << pow(2.0, static_cast<double>(nrElements));
+ std::cerr << std::endl;
_perfProcessed = 0;
}
@@ -595,11 +595,12 @@ void FlatteningInterpreter::explode() {
// two combinations might have projected onto the same conflict-free set
if (transitionSets.find(transition->transitionId) != transitionSets.end()) {
-// std::cout << "skipping as projected onto existing conflict-free subset" << std::endl;
+// std::cerr << "skipping as projected onto existing conflict-free subset" << std::endl;
delete transition;
continue;
}
+#if 0
for (int currDepth = 0; currDepth <= maxDepth; currDepth++) {
int lowestOrder = std::numeric_limits<int32_t>::max();
int nrDepth = 0;
@@ -618,7 +619,7 @@ void FlatteningInterpreter::explode() {
transition->firstElemPerLevel.push_back(lowestOrder);
transition->prioPerLevel.push_back(prioPerLevel);
}
-
+#endif
#if 0
// calculate priority
transition->priority = 0;
@@ -643,7 +644,7 @@ NEXT_DEPTH:
}
#endif
// remember this conflict-free set
-// std::cout << "New conflict-free subset: " << transition->transitionId << ":" << transition->eventDesc << std::endl;
+// std::cerr << "New conflict-free subset: " << transition->transitionId << ":" << transition->eventDesc << std::endl;
transitionSets[transition->transitionId] = transition;
}
@@ -746,9 +747,9 @@ void FlatteningInterpreter::createDocument() {
int index = 0;
for (std::list<Element<std::string> >::reverse_iterator transIter = indexedTransitions.rbegin(); transIter != indexedTransitions.rend(); transIter++) {
const Element<std::string>& refTrans = *transIter;
- std::cout << index++ << ": " << refTrans << std::endl;
+ std::cerr << index++ << ": " << refTrans << std::endl;
}
- std::cout << std::endl;
+ std::cerr << std::endl;
for (std::vector<std::pair<std::string,GlobalState*> >::iterator confIter = sortedStates.begin();
confIter != sortedStates.end();
@@ -766,9 +767,11 @@ template <typename T> bool PtrComp(const T * const & a, const T * const & b)
}
-bool isRedundantSubset (GlobalTransition* first, GlobalTransition* second) {
+/**
+ * subset only removes transitions without cond -> superset will always be enabled
+ */
+bool hasUnconditionalSuperset (GlobalTransition* first, GlobalTransition* second) {
if (isSuperset(second, first)) {
-// std::cout << second->transitions.size() << " / " << first->transitions.size() << std::endl;
for (int i = 0; i < first->transitions.size(); i++) {
if (!InterpreterImpl::isMember(first->transitions[i], second->transitions)) {
if (HAS_ATTR_CAST(first->transitions[i], "cond")) {
@@ -781,7 +784,16 @@ bool isRedundantSubset (GlobalTransition* first, GlobalTransition* second) {
return false; //second can't be removed
}
-std::list<GlobalTransition*> filterRedundantSubset(std::list<GlobalTransition*> list) {
+bool hasEarlierUnconditionalMatch(GlobalTransition* first, GlobalTransition* second) {
+ if (first->eventDesc == second->eventDesc) {
+ if (first->condition.size() == 0)
+ return true;
+ }
+ return false;
+}
+
+// for some reason, unique is not quite up to the task
+std::list<GlobalTransition*> reapplyUniquePredicates(std::list<GlobalTransition*> list) {
for (std::list<GlobalTransition*>::iterator outerIter = list.begin();
outerIter != list.end();
@@ -796,12 +808,17 @@ std::list<GlobalTransition*> filterRedundantSubset(std::list<GlobalTransition*>
GlobalTransition* t1 = *outerIter;
GlobalTransition* t2 = *innerIter;
- if (isRedundantSubset(t1, t2)) {
+ if (hasUnconditionalSuperset(t1, t2)) {
list.erase(outerIter++);
- } else if (isRedundantSubset(t2, t1)) {
+ continue;
+ } else if (hasUnconditionalSuperset(t2, t1)) {
list.erase(innerIter++);
+ continue;
+ }
+ if (hasEarlierUnconditionalMatch(t1, t2)) {
+ list.erase(innerIter++);
+ continue;
}
-
}
}
@@ -827,9 +844,10 @@ void FlatteningInterpreter::appendGlobalStateNode(GlobalState* globalState) {
// transitionList = sortTransitions(transitionList);
transitionList.sort(PtrComp<GlobalTransition>);
- transitionList.unique(isRedundantSubset);
+ transitionList.unique(hasUnconditionalSuperset);
+ transitionList.unique(hasEarlierUnconditionalMatch);
// unique is not quite like what we need, but it was a start
- transitionList = filterRedundantSubset(transitionList);
+ transitionList = reapplyUniquePredicates(transitionList);
// apend here, for transient state chains to trail the state
_scxml.appendChild(state);
@@ -854,23 +872,7 @@ Node<std::string> FlatteningInterpreter::globalTransitionToNode(GlobalTransition
// transition.setAttribute("ref", globalTransition->index);
#if 1
- std::string members;
- int index = 0;
- std::string seperator;
- for (std::list<Element<std::string> >::reverse_iterator transIter = indexedTransitions.rbegin(); transIter != indexedTransitions.rend(); transIter++) {
- const Element<std::string>& refTrans = *transIter;
- if (isMember(refTrans, globalTransition->transitions)) {
- members += seperator + toStr(index);
- } else {
- members += seperator;
- for (int i = 0; i < toStr(index).size(); i++) {
- members += " ";
- }
- }
- seperator = " ";
- index++;
- }
- transition.setAttribute("members", members);
+ transition.setAttribute("members", globalTransition->members);
#endif
if (!globalTransition->isEventless) {
@@ -910,9 +912,9 @@ Node<std::string> FlatteningInterpreter::globalTransitionToNode(GlobalTransition
#endif
-// std::cout << " firstPerLevel:" << feSS.str() << " " << globalTransition->transitionId << std::endl;
-// std::cout << "event: " << globalTransition->eventDesc << " firstPerLevel:" << feSS.str() << " numberPerLevel:" << nrSS.str() << " prioPerLevel:" << prSS.str() << " " << globalTransition->transitionId << std::endl;
-// std::cout << globalTransition->transitionId << std::endl;
+// std::cerr << " firstPerLevel:" << feSS.str() << " " << globalTransition->transitionId << std::endl;
+// std::cerr << "event: " << globalTransition->eventDesc << " firstPerLevel:" << feSS.str() << " numberPerLevel:" << nrSS.str() << " prioPerLevel:" << prSS.str() << " " << globalTransition->transitionId << std::endl;
+// std::cerr << globalTransition->transitionId << std::endl;
NodeSet<std::string> transientStateChain;
@@ -1031,6 +1033,7 @@ Node<std::string> FlatteningInterpreter::globalTransitionToNode(GlobalTransition
return transition;
}
+#if 0
void FlatteningInterpreter::weightTransitions() {
maxDepth = 0;
maxOrder = 0;
@@ -1055,6 +1058,7 @@ void FlatteningInterpreter::weightTransitions() {
states = getChildStates(states);
}
}
+#endif
void FlatteningInterpreter::labelTransitions() {
// put a unique id on each transition
@@ -1134,11 +1138,11 @@ GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet<std::string>& t
isEventless = true;
#if 0
- std::cout << "################" << std::endl;
+ std::cerr << "################" << std::endl;
for (int i = 0; i < transitions.size(); i++) {
- std::cout << transitions[i] << std::endl;
+ std::cerr << transitions[i] << std::endl;
}
- std::cout << "################" << std::endl;
+ std::cerr << "################" << std::endl;
#endif
std::list<std::string> conditions;
@@ -1156,6 +1160,22 @@ GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet<std::string>& t
}
transitionId = setId.str();
+ int index = 0;
+ std::string seperator;
+ for (std::list<Element<std::string> >::iterator transIter = interpreter->indexedTransitions.begin(); transIter != interpreter->indexedTransitions.end(); transIter++) {
+ const Element<std::string>& refTrans = *transIter;
+ if (InterpreterImpl::isMember(refTrans, transitions)) {
+ members += seperator + toStr(index);
+ } else {
+ members += seperator;
+ for (int i = 0; i < toStr(index).size(); i++) {
+ members += " ";
+ }
+ }
+ seperator = " ";
+ index++;
+ }
+
/**
* Can these events event occur together? They can't if:
* 1. event / eventless is mixed
@@ -1230,11 +1250,13 @@ GlobalTransition::GlobalTransition(const Arabica::XPath::NodeSet<std::string>& t
eventDesc = "*";
}
- if (conditions.size() > 0) {
+ if (conditions.size() > 1) {
condition = dataModel.andExpressions(conditions);
if (condition.size() == 0) {
LOG(ERROR) << "Datamodel does not support to conjungate expressions!" << std::endl;
}
+ } else if (conditions.size() == 1) {
+ condition = conditions.front();
}
}
diff --git a/src/uscxml/transform/ChartToFSM.h b/src/uscxml/transform/ChartToFSM.h
index 923304c..a60985d 100644
--- a/src/uscxml/transform/ChartToFSM.h
+++ b/src/uscxml/transform/ChartToFSM.h
@@ -77,15 +77,16 @@ public:
bool isTargetless; // whether or not all our transitions are eventless
bool isSubset; // there is a superset to this set
- std::vector<long> firstElemPerLevel;
- std::vector<long> nrElemPerLevel;
- std::vector<long> prioPerLevel;
+// std::vector<long> firstElemPerLevel;
+// std::vector<long> nrElemPerLevel;
+// std::vector<long> prioPerLevel;
Arabica::XPath::NodeSet<std::string> transitions; // constituting transitions
std::list<std::string> eventNames; // the list of longest event names that will enable this set
std::string eventDesc; // space-seperated eventnames for convenience
std::string condition; // conjunction of all the set's conditions
+ std::string members; // a convenience string listing all constituting transitions
// executable content we gathered when we took the transition
std::list<Action> actions;
@@ -140,7 +141,7 @@ protected:
void explode();
void labelTransitions();
- void weightTransitions();
+// void weightTransitions();
void createDocument();
void indexTransitions(const Arabica::DOM::Element<std::string>& root);
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index dc827d3..dbc5a15 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -146,6 +146,11 @@ 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")
+add_executable(test-vxml-mmi-http src/test-vxml-mmi-http.cpp)
+target_link_libraries(test-vxml-mmi-http uscxml)
+# add_test(test-datamodel ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-sockets)
+set_target_properties(test-vxml-mmi-http 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-sockets.cpp b/test/src/test-sockets.cpp
index a02eb9c..ad567f7 100644
--- a/test/src/test-sockets.cpp
+++ b/test/src/test-sockets.cpp
@@ -1,4 +1,5 @@
#include "uscxml/config.h"
+#include "uscxml/Convenience.h"
#include "uscxml/server/Socket.h"
#include <iostream>
#include <stdexcept>
@@ -25,6 +26,28 @@ public:
};
};
+int packetSeq = 0;
+
+class LogServer : public ServerSocket {
+public:
+ LogServer(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;
+ };
+};
+
+class CountingPacketServer : public PacketServerSocket {
+public:
+ CountingPacketServer(int domain, int type, int protocol, const std::string& sep) : PacketServerSocket(domain, type, protocol, sep) {}
+ virtual void readCallback(const std::string& packet, Connection& conn) {
+// std::cout << "-- " << packet << std::endl;
+ size_t seq = strTo<size_t>(packet);
+ assert(seq == packetSeq);
+ packetSeq++;
+ };
+};
+
class TestClient : public ClientSocket {
public:
TestClient(int domain, int type, int protocol) : ClientSocket(domain, type, protocol) {}
@@ -45,7 +68,49 @@ int main(int argc, char** argv) {
evthread_use_windows_threads();
#endif
- if (0) {
+ if (1) {
+ packetSeq = 0;
+ CountingPacketServer server(PF_INET, SOCK_STREAM, 0, std::string("tadaa!"));
+// LogServer server(PF_INET, SOCK_STREAM, 0);
+ server.listen("*", 1235);
+ server.setBlockSizeRead(1);
+
+ TestClient client(PF_INET, SOCK_STREAM, 0);
+ client.connect("127.0.0.1", 1235);
+
+ int iterations = 1000;
+ std::stringstream contentSS;
+ for (int i = 0; i < iterations; i++) {
+ contentSS << toStr(i);
+ contentSS << "tadaa!";
+ }
+ client.write(contentSS.str());
+
+ while(packetSeq != iterations)
+ usleep(10000);
+ }
+
+ if (1) {
+ packetSeq = 0;
+ CountingPacketServer server(PF_INET, SOCK_STREAM, 0, std::string("\0", 1));
+ server.listen("*", 1235);
+
+ TestClient client(PF_INET, SOCK_STREAM, 0);
+ client.connect("127.0.0.1", 1235);
+
+ int iterations = 1000;
+ for (int i = 0; i < iterations; i++) {
+ client.write(toStr(i));
+ client.write("\0", 1);
+ }
+
+ while(packetSeq != iterations)
+ usleep(10000);
+ }
+
+ exit(0);
+
+ if (1) {
// start server socket and connect
int iterations = 100;
diff --git a/test/src/test-vxml-mmi-http.cpp b/test/src/test-vxml-mmi-http.cpp
new file mode 100644
index 0000000..50a8dd0
--- /dev/null
+++ b/test/src/test-vxml-mmi-http.cpp
@@ -0,0 +1,165 @@
+#include "uscxml/config.h"
+#include "uscxml/server/Socket.h"
+#include "uscxml/UUID.h"
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/algorithm/string.hpp>
+
+#include <event2/event.h>
+#include "event2/thread.h"
+
+#ifdef HAS_SIGNAL_H
+#include <signal.h>
+#endif
+
+#include "uscxml/server/HTTPServer.h"
+#include "uscxml/URL.h"
+#include "uscxml/concurrency/tinythread.h"
+#include "uscxml/plugins/ioprocessor/modality/MMIMessages.h"
+#include <DOM/io/Stream.hpp>
+
+#ifdef _WIN32
+#include "XGetopt.h"
+#endif
+
+#include "uscxml/plugins/ioprocessor/modality/MMIMessages.cpp"
+
+#define ISSUE_REQUEST(name) {\
+ Arabica::DOM::Document<std::string> name##XML = name.toXML(true);\
+ name##XML.getDocumentElement().setPrefix("mmi");\
+ std::stringstream name##XMLSS;\
+ name##XMLSS << name##XML;\
+ URL name##URL(target);\
+ name##URL.setOutContent(name##XMLSS.str());\
+ name##URL.addOutHeader("Content-type", "application/xml");\
+ name##URL.download(true);\
+}
+
+using namespace uscxml;
+
+std::map<std::string, MMIEvent*> Requests;
+std::map<std::string, MMIEvent*> Replies;
+
+tthread::condition_variable Cond;
+tthread::mutex Mutex;
+
+class MMIServlet : public HTTPServlet {
+public:
+ bool httpRecvRequest(const HTTPServer::Request& request) {
+ tthread::lock_guard<tthread::mutex> lock(Mutex);
+
+ NameSpacingParser parser = NameSpacingParser::fromXML(request.content);
+ switch(MMIEvent::getType(parser.getDocument().getDocumentElement())) {
+ case MMIEvent::NEWCONTEXTRESPONSE: {
+ NewContextResponse* resp = new NewContextResponse(NewContextResponse::fromXML(parser.getDocument().getDocumentElement()));
+ Replies[resp->requestId] = resp;
+ }
+ case MMIEvent::STARTRESPONSE: {
+ StartResponse* resp = new StartResponse(StartResponse::fromXML(parser.getDocument().getDocumentElement()));
+ Replies[resp->requestId] = resp;
+ }
+ default: ;
+ }
+
+ Cond.notify_all();
+ return true;
+ }
+ void setURL(const std::string& url) {
+ this->url = url;
+ }
+ std::string url;
+};
+
+void printUsageAndExit(const char* progName) {
+ // remove path from program name
+ std::string progStr(progName);
+ if (progStr.find_last_of(PATH_SEPERATOR) != std::string::npos) {
+ progStr = progStr.substr(progStr.find_last_of(PATH_SEPERATOR) + 1, progStr.length() - (progStr.find_last_of(PATH_SEPERATOR) + 1));
+ }
+
+ 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(" [-tURL] URL");
+ printf("\n");
+ printf("Options\n");
+ printf("\t-tURL : URL of VoiceXML HTTP server\n");
+ printf("\tURL : URL of a VoiceXML document\n");
+ printf("\n");
+ exit(1);
+}
+
+int main(int argc, char** argv) {
+ try {
+ tthread::lock_guard<tthread::mutex> lock(Mutex);
+
+ std::string target;
+ std::string document;
+
+ if (argc < 2)
+ printUsageAndExit(argv[0]);
+
+ int option;
+ while ((option = getopt(argc, argv, "t:")) != -1) {
+ switch(option) {
+ case 't':
+ target = optarg;
+ break;
+ default:
+ printUsageAndExit(argv[0]);
+ }
+ }
+
+ if (argc < optind)
+ printUsageAndExit(argv[0]);
+
+ document = argv[optind];
+
+ if (!boost::starts_with(document, "http"))
+ document = "http://" + document;
+
+ if (!boost::starts_with(target, "http"))
+ document = "http://" + target;
+
+ // target = "http://130.83.163.167:9090/mmi";
+ // target = "http://localhost:9090/mmi";
+
+
+ MMIServlet servlet;
+ HTTPServer::getInstance(4344, 0);
+ HTTPServer::getInstance()->registerServlet("/mmi", &servlet);
+
+ std::string source = servlet.url;
+
+ NewContextRequest newCtxReq;
+ newCtxReq.source = source;
+ newCtxReq.target = target;
+ newCtxReq.requestId = UUID::getUUID();
+
+ Requests[newCtxReq.requestId] = &newCtxReq;
+ ISSUE_REQUEST(newCtxReq);
+
+ while(Replies.find(newCtxReq.requestId) == Replies.end())
+ Cond.wait(Mutex);
+
+ StartRequest startReq;
+ startReq.source = source;
+ startReq.target = target;
+ startReq.requestId = UUID::getUUID();
+ startReq.contentURL.href = document;
+ //"https://raw.githubusercontent.com/Roland-Taizun-Azhar/TaskAssistance-Project/master/WebContent/hello.vxml";
+
+ Requests[startReq.requestId] = &startReq;
+ ISSUE_REQUEST(startReq);
+
+ while(Replies.find(startReq.requestId) == Replies.end())
+ Cond.wait(Mutex);
+ } catch (Event e) {
+ std::cout << e << std::endl;
+ } catch (std::exception e) {
+ std::cout << e.what() << std::endl;
+ }
+
+
+} \ No newline at end of file
diff --git a/test/src/test-vxml-mmi-socket.cpp b/test/src/test-vxml-mmi-socket.cpp
index a79cec7..8246c3b 100644
--- a/test/src/test-vxml-mmi-socket.cpp
+++ b/test/src/test-vxml-mmi-socket.cpp
@@ -1,5 +1,6 @@
#include "uscxml/config.h"
#include "uscxml/server/Socket.h"
+#include "uscxml/UUID.h"
#include <iostream>
#include <stdexcept>
@@ -19,15 +20,70 @@
using namespace uscxml;
-class TestServer : public ServerSocket {
+bool testAddressParsing() {
+ std::string protocol;
+ std::string hostName;
+ uint16_t port;
+
+ {
+ Socket::parseAddress("4343", protocol, hostName, port);
+ assert(protocol == "tcp");
+ assert(hostName == "127.0.0.1");
+ assert(port == 4343);
+
+ Socket::parseAddress("localhost:4343", protocol, hostName, port);
+ assert(protocol == "tcp");
+ assert(hostName == "localhost");
+ assert(port == 4343);
+
+ Socket::parseAddress("tcp://localhost:4343", protocol, hostName, port);
+ assert(protocol == "tcp");
+ assert(hostName == "localhost");
+ assert(port == 4343);
+ }
+ return true;
+}
+
+bool testMMIEvents() {
+ {
+ NewContextRequest newCtxReq;
+ newCtxReq.source = "localhost:3434";
+ newCtxReq.target = "localhost:1212";
+ newCtxReq.requestId = "requestId";
+
+ Arabica::DOM::Document<std::string> newCtxReqXML1 = newCtxReq.toXML();
+ Arabica::DOM::Document<std::string> newCtxReqXML2 = newCtxReq.toXML(true);
+
+// std::cout << newCtxReqXML1 << std::endl;
+// std::cout << newCtxReqXML2 << std::endl;
+
+ NewContextRequest newCtxReq1 = NewContextRequest::fromXML(newCtxReqXML1.getDocumentElement());
+ NewContextRequest newCtxReq2 = NewContextRequest::fromXML(newCtxReqXML2.getDocumentElement());
+
+ assert(MMIEvent::getType(newCtxReqXML1.getDocumentElement()) == MMIEvent::NEWCONTEXTREQUEST);
+ assert(MMIEvent::getType(newCtxReqXML2.getDocumentElement()) == MMIEvent::NEWCONTEXTREQUEST);
+
+ assert(newCtxReq1.source == "localhost:3434");
+ assert(newCtxReq2.source == "localhost:3434");
+ assert(newCtxReq1.target == "localhost:1212");
+ assert(newCtxReq2.target == "localhost:1212");
+ assert(newCtxReq1.requestId == "requestId");
+ assert(newCtxReq2.requestId == "requestId");
+
+ }
+ return true;
+}
+
+class TestServer : public PacketServerSocket {
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;
+ TestServer(int domain, int type, int protocol) : PacketServerSocket(domain, type, protocol, std::string("\0", 1)) {}
+ virtual void readCallback(const std::string& packet, Connection& conn) {
+ std::cout << "Server got: " << packet << std::endl;
std::string urghs("hi!");
conn.reply(urghs.data(), urghs.size());
};
+
+ std::stringstream fragment;
};
class TestClient : public ClientSocket {
@@ -38,6 +94,9 @@ public:
};
};
+std::map<std::string, MMIEvent*> _requests;
+std::map<std::string, MMIEvent*> _replies;
+
int main(int argc, char** argv) {
#if defined(HAS_SIGNAL_H) && !defined(WIN32)
@@ -49,24 +108,58 @@ int main(int argc, char** argv) {
#else
evthread_use_windows_threads();
#endif
-
+ testAddressParsing();
+ testMMIEvents();
+
// TestClient client(PF_INET, SOCK_STREAM, 0);
// client.connect("epikur.local", 4343);
+ std::string target = "localhost:4343";
+ std::string source = "localhost:4344";
+
+ TestServer server(PF_INET, SOCK_STREAM, 0);
+ server.listen(source);
+
+// while(true)
+// sleep(1000);
+
+ TestClient client(PF_INET, SOCK_STREAM, 0);
+ client.connect(source);
+
+ NewContextRequest newCtxReq;
+ newCtxReq.source = source;
+ newCtxReq.target = target;
+ newCtxReq.requestId = UUID::getUUID();
+
+ _requests[newCtxReq.requestId] = &newCtxReq;
+
+ Arabica::DOM::Document<std::string> newCtxReqXML = newCtxReq.toXML(true);
+ std::stringstream newCtxReqXMLSS;
+ newCtxReqXMLSS << newCtxReqXML;
+
+ for (int i = 0; i < 100000; i++) {
+ std::string index = toStr(i);
+ client.write(index.c_str(), index.size() + 1);
+// client.write(newCtxReqXMLSS.str().data(), newCtxReqXMLSS.str().size());
+// client.write("\0", 1);
+ }
+
+ while(true)
+ sleep(1000);
- 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;
+// StartRequest startReq;
+// startReq.source = "localhost:4344";
+// startReq.target = "localhost: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