From 053e9bc973fbe88fc41a34064ffadc0deabac58d Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Mon, 13 Jun 2016 10:52:55 +0200 Subject: Fixed dozens of memory leaks --- .gitignore | 2 + CMakeLists.txt | 50 +- config.h.in | 16 +- contrib/src/easylogging++.h | 14 +- docs/BUILDING.md | 4 +- src/bindings/swig/java/CMakeLists.txt | 8 +- src/bindings/swig/java/build-jar.xml | 91 + src/uscxml/Common.h | 2 + src/uscxml/debug/InterpreterIssue.cpp | 20 +- src/uscxml/interpreter/BasicContentExecutor.cpp | 47 +- src/uscxml/interpreter/BasicEventQueue.cpp | 25 +- src/uscxml/interpreter/FastMicroStep.cpp | 60 +- src/uscxml/interpreter/FastMicroStep.h | 13 +- src/uscxml/interpreter/InterpreterImpl.cpp | 35 +- src/uscxml/plugins/DataModelImpl.h | 1 + src/uscxml/plugins/Factory.cpp | 117 +- .../datamodel/ecmascript/v8/V8DataModel.cpp | 4 +- .../plugins/datamodel/ecmascript/v8/V8DataModel.h | 2 +- src/uscxml/plugins/invoker/CMakeLists.txt | 24 +- .../plugins/invoker/dirmon/DirMonInvoker.cpp | 449 ++ src/uscxml/plugins/invoker/dirmon/DirMonInvoker.h | 140 + src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h | 1 - src/uscxml/plugins/ioprocessor/CMakeLists.txt | 33 +- .../ioprocessor/basichttp/BasicHTTPIOProcessor.cpp | 6 +- src/uscxml/server/HTTPServer.cpp | 6 - src/uscxml/util/DOM.cpp | 45 +- src/uscxml/util/DOM.h | 96 +- src/uscxml/util/Predicates.cpp | 51 +- src/uscxml/util/URL.cpp | 20 +- src/uscxml/util/URL.h | 7 +- test/CMakeLists.txt | 17 + test/bindings/java/build.properties | 9 + test/bindings/java/build.xml | 43 + test/bindings/java/libs/commons-jexl3-3.0.jar | Bin 0 -> 383861 bytes test/bindings/java/libs/commons-logging-1.2.jar | Bin 0 -> 61829 bytes .../java/org/uscxml/examples/BasicExample.java | 46 + .../java/org/uscxml/examples/DataModelExample.java | 60 + .../java/org/uscxml/examples/MonitorExample.java | 48 + .../java/org/uscxml/helper/TestMonitor.java | 76 + .../java/org/uscxml/tests/BasicExample.java | 43 - .../java/org/uscxml/tests/DataModelExample.java | 58 - .../java/org/uscxml/tests/JexlDataModelTest.java | 60 + .../java/org/uscxml/tests/MonitorExample.java | 46 - .../java/org/uscxml/tests/helper/TestMonitor.java | 76 - test/src/test-lifecycle.cpp | 4 +- test/src/test-stress.cpp | 109 + test/w3c/compound/test-ecma-all.scxml | 5841 -------------------- test/w3c/compound/test-ecma-all.scxml.foo | 5841 ++++++++++++++++++++ 48 files changed, 7456 insertions(+), 6310 deletions(-) create mode 100644 src/bindings/swig/java/build-jar.xml create mode 100644 src/uscxml/plugins/invoker/dirmon/DirMonInvoker.cpp create mode 100644 src/uscxml/plugins/invoker/dirmon/DirMonInvoker.h create mode 100644 test/bindings/java/build.properties create mode 100644 test/bindings/java/build.xml create mode 100644 test/bindings/java/libs/commons-jexl3-3.0.jar create mode 100644 test/bindings/java/libs/commons-logging-1.2.jar create mode 100644 test/bindings/java/org/uscxml/examples/BasicExample.java create mode 100644 test/bindings/java/org/uscxml/examples/DataModelExample.java create mode 100644 test/bindings/java/org/uscxml/examples/MonitorExample.java create mode 100644 test/bindings/java/org/uscxml/helper/TestMonitor.java delete mode 100644 test/bindings/java/org/uscxml/tests/BasicExample.java delete mode 100644 test/bindings/java/org/uscxml/tests/DataModelExample.java create mode 100644 test/bindings/java/org/uscxml/tests/JexlDataModelTest.java delete mode 100644 test/bindings/java/org/uscxml/tests/MonitorExample.java delete mode 100644 test/bindings/java/org/uscxml/tests/helper/TestMonitor.java create mode 100644 test/src/test-stress.cpp delete mode 100644 test/w3c/compound/test-ecma-all.scxml create mode 100644 test/w3c/compound/test-ecma-all.scxml.foo diff --git a/.gitignore b/.gitignore index aa448a5..a2a2350 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ package/windows* /test/w3c/graphs/ /.idea/* + +/test/bindings/java/logs/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ea51da..40743b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,16 +239,16 @@ CheckHasModule(XercesC) if (HAS_MODULE_XercesC) find_package(XercesC) else() - message(STATUS "Could NOT find XercesC (your CMake distribution does not include the FindXercesC module)") - # make a quick attempt to find xerces INCLUDE(FindPackageHandleStandardArgs) find_path(XercesC_INCLUDE_DIR NAMES "xercesc/util/PlatformUtils.hpp") find_library(XercesC_LIBRARY NAMES "xerces-c" "xerces-c_3") - mark_as_advanced(XercesC_LIBRARY) + mark_as_advanced(XercesC_LIBRARIES) mark_as_advanced(XercesC_INCLUDE_DIR) - if (XercesC_INCLUDE_DIR AND XercesC_LIBRARY) + if (XercesC_INCLUDE_DIR AND XercesC_LIBRARIES) set(XercesC_FOUND ON) + else() + message(STATUS "Could NOT find XercesC (your CMake distribution does not include the FindXercesC module)") endif() endif() @@ -324,8 +324,8 @@ find_package(SWIG) # JavaScriptCore -OPTION(IGNORE_JSC "Do not search for JavaScriptCore" OFF) -if (NOT IGNORE_JSC) +OPTION(WITH_DM_ECMA_JSC "Do search for JavaScriptCore" ON) +if (WITH_DM_ECMA_JSC) find_package(JSC) if (JSC_FOUND) set(ECMA_FOUND ON) @@ -333,23 +333,27 @@ if (NOT IGNORE_JSC) include_directories(${JSC_INCLUDE_DIR}) endif() list (APPEND USCXML_OPT_LIBS ${JSC_LIBRARY}) + else() + set(WITH_DM_ECMA_JSC OFF) endif() endif() # V8 -OPTION(IGNORE_V8 "Do not search for the V8 ECMAScript implementation" OFF) -if (NOT IGNORE_V8) +OPTION(WITH_DM_ECMA_V8 "Do search for the V8 ECMAScript implementation" ON) +if (WITH_DM_ECMA_V8) find_package(V8) if (V8_FOUND) set(ECMA_FOUND ON) include_directories(${V8_INCLUDE_DIR}) list (APPEND USCXML_OPT_LIBS ${V8_LIBRARY}) + else() + set(WITH_DM_ECMA_V8 OFF) endif() endif() # Lua -OPTION(IGNORE_LUA "Do not search for the Lua libraries" OFF) -if (NOT IGNORE_LUA) +OPTION(WITH_DM_LUA "Do search for the Lua libraries" ON) +if (WITH_DM_LUA) if (WIN32) # LuaForWindows https://code.google.com/archive/p/luaforwindows/downloads set(ENV{LUA_DIR} "C:/Program Files (x86)/Lua/5.1/") @@ -359,6 +363,8 @@ if (NOT IGNORE_LUA) include_directories (${LUA_INCLUDE_DIR}) include_directories(${PROJECT_SOURCE_DIR}/contrib/src/LuaBridge) list (APPEND USCXML_OPT_LIBS ${LUA_LIBRARIES}) + else() + set(WITH_DM_LUA OFF) endif() endif() @@ -423,6 +429,30 @@ endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/uscxml/config.h) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test/ctest/CTestCustom.ctest.in ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.ctest) +############################################################ +# Sort files into goups in IDEs +############################################################ + + +set(ALL_SOURCE_FILES ${USCXML_FILES} ${USCXML_TRANSFORM_FILES}) +list(SORT USCXML_FILES) +list(SORT USCXML_TRANSFORM_FILES) +# we cannot define source groups in sub directories! +foreach( FILE ${ALL_SOURCE_FILES} ) + + get_filename_component(PATH ${FILE} PATH) + file(RELATIVE_PATH REL_PATH ${PROJECT_SOURCE_DIR} "${PATH}") + string(REGEX REPLACE "src/uscxml" "" REL_PATH "${REL_PATH}") + string(REGEX REPLACE "contrib/src" "contrib" REL_PATH "${REL_PATH}") + + string(REGEX REPLACE "^/" "" REL_PATH "${REL_PATH}") # leading slash + string(REGEX REPLACE "/" "\\\\" SRC_GROUP "${REL_PATH}") # escape / + + source_group("${SRC_GROUP}" FILES ${FILE}) + +endforeach() + + # all variables that cmake knows about # get_cmake_property(_variableNames VARIABLES) # foreach (_variableName ${_variableNames}) diff --git a/config.h.in b/config.h.in index ebbb98a..31530e1 100644 --- a/config.h.in +++ b/config.h.in @@ -59,12 +59,15 @@ #cmakedefine SWI_BINARY "@SWI_BINARY@" /** whether we want some feature */ -#cmakedefine BUILD_MINIMAL -#cmakedefine BUILD_DM_PROLOG -#cmakedefine BUILD_DM_PROMELA -#cmakedefine BUILD_DM_ECMA -#cmakedefine BUILD_DM_XPATH -#cmakedefine BUILD_DM_LUA +#cmakedefine WITH_INV_SCXML +#cmakedefine WITH_INV_DIRMON + +#cmakedefine WITH_IOPROC_BASICHTTP +#cmakedefine WITH_IOPROC_SCXML + +#cmakedefine WITH_DM_ECMA_V8 +#cmakedefine WITH_DM_ECMA_JSC +#cmakedefine WITH_DM_LUA /** Optional libraries we found */ #cmakedefine UMUNDO_FOUND @@ -90,6 +93,7 @@ #cmakedefine EXPECT_FOUND #cmakedefine TCL_FOUND + /** Properties of the libraries we found */ #cmakedefine CURL_HAS_SMTP diff --git a/contrib/src/easylogging++.h b/contrib/src/easylogging++.h index 9bf18fd..7378d41 100644 --- a/contrib/src/easylogging++.h +++ b/contrib/src/easylogging++.h @@ -113,14 +113,14 @@ # define ELPP_ASSERT(expr, msg) if (!(expr)) { \ std::stringstream internalInfoStream; internalInfoStream << msg; \ ELPP_INTERNAL_DEBUGGING_OUT_ERROR \ - << "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" \ + << "ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" \ << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" << ELPP_INTERNAL_DEBUGGING_ENDL; base::utils::abort(1, \ "ELPP Assertion failure, please define ELPP_DEBUG_ASSERT_FAILURE"); } # else # define ELPP_ASSERT(expr, msg) if (!(expr)) { \ std::stringstream internalInfoStream; internalInfoStream << msg; \ ELPP_INTERNAL_DEBUGGING_OUT_ERROR\ - << "ASSERTION FAILURE FROM EASYLOGGING++ (LINE: " \ + << "ASSERTION FAILURE AT (LINE: " \ << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" \ << ELPP_INTERNAL_DEBUGGING_ENDL; } # endif // (defined(ELPP_DEBUG_ASSERT_FAILURE)) @@ -140,7 +140,7 @@ # define ELPP_INTERNAL_ERROR(msg, pe) { \ std::stringstream internalInfoStream; internalInfoStream << " " << msg; \ ELPP_INTERNAL_DEBUGGING_OUT_ERROR \ - << "ERROR FROM EASYLOGGING++ (LINE: " << __LINE__ << ") " \ + << "ERROR AT (LINE: " << __LINE__ << ") " \ << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << ELPP_INTERNAL_DEBUGGING_ENDL; \ if (pe) { ELPP_INTERNAL_DEBUGGING_OUT_ERROR << " "; ELPP_INTERNAL_DEBUGGING_WRITE_PERROR; }} (void)0 # endif @@ -784,12 +784,12 @@ namespace consts { #else # if ELPP_OS_UNIX # if ELPP_OS_ANDROID - static const char* kDefaultLogFile = "logs/myeasylog.log"; + static const char* kDefaultLogFile = "logs/uscxml.log"; # else - static const char* kDefaultLogFile = "logs/myeasylog.log"; + static const char* kDefaultLogFile = "logs/uscxml.log"; # endif // ELPP_OS_ANDROID # elif ELPP_OS_WINDOWS - static const char* kDefaultLogFile = "logs\\myeasylog.log"; + static const char* kDefaultLogFile = "logs\\uscxml.log"; # endif // ELPP_OS_UNIX #endif // defined(ELPP_DEFAULT_LOG_FILE) #if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) @@ -2608,7 +2608,7 @@ public: setGlobally(ConfigurationType::MaxLogFileSize, std::string("0"), true); setGlobally(ConfigurationType::LogFlushThreshold, std::string("0"), true); - setGlobally(ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"), true); + setGlobally(ConfigurationType::Format, std::string("%datetime %level %fbase:%line: %msg"), true); set(Level::Debug, ConfigurationType::Format, std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg")); // INFO and WARNING are set to default by Level::Global set(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 690d98e..d627208 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -337,7 +337,7 @@ In addition, you will need apache's ant in the path or in $ENV{ANT_ If both of these are given, you ought to get java as an available language binding and a new target called java for your build system. If you used plain Makefiles (default on unices), you will get everything you need via: - $ make && make java + $ make && make jar $ ls lib/*.jnilib lib/*.jar lib/libuscxmlNativeJava64.jnilib lib/uscxml.jar @@ -382,6 +382,6 @@ Command Prompt (2012) and type: > cd c:\path\to\build\dir > cmake -G"NMake Makefiles" c:\path\to\uscxml\source ... - > nmake && nmake csharp && nmake java + > nmake && nmake csharp && nmake jar ... diff --git a/src/bindings/swig/java/CMakeLists.txt b/src/bindings/swig/java/CMakeLists.txt index 148199e..6d5c695 100644 --- a/src/bindings/swig/java/CMakeLists.txt +++ b/src/bindings/swig/java/CMakeLists.txt @@ -57,7 +57,7 @@ if (ANT_EXECUTABLE) SET(JAR_JNI_ROOT_PATH ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) endif() - ADD_CUSTOM_TARGET(java + ADD_CUSTOM_TARGET(jar COMMAND ${ANT_EXECUTABLE} -Dlib.dir=${JAR_JNI_ROOT_PATH} -Dsrc.dir=${PROJECT_SOURCE_DIR} @@ -65,11 +65,11 @@ if (ANT_EXECUTABLE) -Dbuild.type=${CMAKE_BUILD_TYPE} -Dexclude.debug=${JAR_EXCLUDE_DEBUG} -Dexclude.jni=${JAR_EXCLUDE_JNI} - -f build-java.xml - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/contrib/java + -f build-jar.xml + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Creating the jar ...") - set_target_properties(java PROPERTIES FOLDER "Bindings") + set_target_properties(jar PROPERTIES FOLDER "Bindings") else() message(STATUS "Could not find ant binary - will not build jars") endif() diff --git a/src/bindings/swig/java/build-jar.xml b/src/bindings/swig/java/build-jar.xml new file mode 100644 index 0000000..0720ffa --- /dev/null +++ b/src/bindings/swig/java/build-jar.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${echo.all.jni} + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/uscxml/Common.h b/src/uscxml/Common.h index 017a177..c1029f1 100644 --- a/src/uscxml/Common.h +++ b/src/uscxml/Common.h @@ -20,6 +20,8 @@ #ifndef COMMON_H_YZ3CIYP #define COMMON_H_YZ3CIYP +#define ELPP_STACKTRACE_ON_CRASH 1 + #if __cplusplus >= 201402L #define DEPRECATED [[deprecated]] #elif defined(__GNUC__) diff --git a/src/uscxml/debug/InterpreterIssue.cpp b/src/uscxml/debug/InterpreterIssue.cpp index 86947c1..49d31c8 100644 --- a/src/uscxml/debug/InterpreterIssue.cpp +++ b/src/uscxml/debug/InterpreterIssue.cpp @@ -38,18 +38,14 @@ InterpreterIssue::InterpreterIssue(const std::string& msg, DOMNode* node, IssueS } // find all elements in the SCXML namespace in one traversal -void assembleNodeSets(const std::string nsPrefix, DOMNode* node, std::map >& sets) { - DOMNodeList* childs = node->getChildNodes(); - for (unsigned int i = 0; i < childs->getLength(); i++) { - if (childs->item(i)->getNodeType() != DOMNode::ELEMENT_NODE) - continue; - // std::cout << TAGNAME(childs.item(i)) << std::endl; +void assembleNodeSets(const std::string nsPrefix, DOMElement* node, std::map >& sets) { + for (auto childElem = node->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) { - if (TAGNAME_CAST(childs->item(i)).find(nsPrefix) == 0) { + if (TAGNAME(childElem).find(nsPrefix) == 0) { // correct namespace, insert via localname - sets[LOCALNAME_CAST(childs->item(i))].push_back(static_cast(childs->item(i))); + sets[LOCALNAME(childElem)].push_back(static_cast(childElem)); } - assembleNodeSets(nsPrefix, childs->item(i), sets); + assembleNodeSets(nsPrefix, childElem, sets); } } @@ -61,11 +57,7 @@ std::list > getAllConfigurations(const DOMElement* std::cout << *root; - DOMNodeList* children = root->getChildNodes(); - for (size_t i = 0; i < children->getLength(); i++) { - if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE) - continue; - DOMElement* childElem = static_cast(children->item(i)); + for (auto childElem = root->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) { std::cout << *childElem; if (XMLString::compareIString(childElem->getTagName(), X(nsPrefix + "state")) == 0 || diff --git a/src/uscxml/interpreter/BasicContentExecutor.cpp b/src/uscxml/interpreter/BasicContentExecutor.cpp index c1eb8f6..366c4bd 100644 --- a/src/uscxml/interpreter/BasicContentExecutor.cpp +++ b/src/uscxml/interpreter/BasicContentExecutor.cpp @@ -209,13 +209,7 @@ void BasicContentExecutor::processCancel(XERCESC_NS::DOMElement* content) { void BasicContentExecutor::processIf(XERCESC_NS::DOMElement* content) { bool blockIsTrue = _callbacks->isTrue(ATTR(content, "cond")); - DOMNodeList* children = content->getChildNodes(); - for (unsigned int i = 0; i < children->getLength(); i++) { - if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE) - continue; - - DOMElement* childElem = dynamic_cast(children->item(i)); - + for (auto childElem = content->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) { if (iequals(TAGNAME(childElem), XML_PREFIX(content).str() + "elseif")) { if (blockIsTrue) { // last block was true, break here @@ -257,11 +251,8 @@ void BasicContentExecutor::processForeach(XERCESC_NS::DOMElement* content) { for (uint32_t iteration = 0; iteration < iterations; iteration++) { _callbacks->setForeach(item, array, index, iteration); - DOMNodeList* children = content->getChildNodes(); - for (unsigned int i = 0; i < children->getLength(); i++) { - if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE) - continue; - process(dynamic_cast(children->item(i)), XML_PREFIX(content)); + for (auto childElem = content->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) { + process(childElem, XML_PREFIX(content)); } } } @@ -292,13 +283,10 @@ void BasicContentExecutor::process(XERCESC_NS::DOMElement* block, const X& xmlPr iequals(tagName, xmlPrefix.str() + "onexit") || iequals(tagName, xmlPrefix.str() + "transition")) { - DOMNodeList* children = block->getChildNodes(); try { - for(auto i = 0; i < children->getLength(); i++) { - if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE) - continue; + for (auto childElem = block->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) { // process any child eleents - process(dynamic_cast(children->item(i)), xmlPrefix); + process(childElem, xmlPrefix); } } catch (Event e) { // there has been an error in an executable content block @@ -415,6 +403,7 @@ void BasicContentExecutor::invoke(XERCESC_NS::DOMElement* element) { _callbacks->assign(ATTR(element, "idlocation"), Data(invokeEvent.invokeid, Data::VERBATIM)); } } + // we need the invokeid to uninvoke - TODO: This is leaking! char* invokeId = (char*)malloc(invokeEvent.invokeid.size() + 1); memcpy(invokeId, invokeEvent.invokeid.c_str(), invokeEvent.invokeid.size()); @@ -488,6 +477,7 @@ void BasicContentExecutor::uninvoke(XERCESC_NS::DOMElement* invoke) { _callbacks->uninvoke(invokeId); USCXML_MONITOR_CALLBACK2(_callbacks->getMonitor(), afterUninvoking, invoke, invokeId); + invoke->setUserData(X("invokeid"), NULL, NULL); free(invokeId); } @@ -589,25 +579,26 @@ Data BasicContentExecutor::elementAsData(XERCESC_NS::DOMElement* element) { std::string content = url.getInContent(); // make an attempt to parse as XML - try { - XERCESC_NS::XercesDOMParser* parser = new XERCESC_NS::XercesDOMParser(); - parser->setValidationScheme(XERCESC_NS::XercesDOMParser::Val_Always); - parser->setDoNamespaces(true); - parser->useScanner(XERCESC_NS::XMLUni::fgWFXMLScanner); + try { + XERCESC_NS::XercesDOMParser parser; + parser.setValidationScheme(XERCESC_NS::XercesDOMParser::Val_Never); + parser.setDoNamespaces(true); + parser.useScanner(XERCESC_NS::XMLUni::fgWFXMLScanner); - XERCESC_NS::ErrorHandler* errHandler = new XERCESC_NS::HandlerBase(); - parser->setErrorHandler(errHandler); + XERCESC_NS::HandlerBase errHandler; + parser.setErrorHandler(&errHandler); std::string tmp = url; XERCESC_NS::MemBufInputSource is((XMLByte*)content.c_str(), content.size(), X("fake")); - parser->parse(is); + parser.parse(is); Data d; - XERCESC_NS::DOMDocument* doc = parser->adoptDocument(); + XERCESC_NS::DOMDocument* doc = parser.adoptDocument(); d.adoptedDoc = std::make_shared(doc); d.node = doc->getDocumentElement(); - return d; + + return d; } catch (...) { // just ignore and return as an interpreted string below @@ -646,7 +637,7 @@ Data BasicContentExecutor::elementAsData(XERCESC_NS::DOMElement* element) { } } - LOG(WARNING) << "Element " << DOMUtils::xPathForNode(element) << " did not yield any data"; +// LOG(WARNING) << "Element " << DOMUtils::xPathForNode(element) << " did not yield any data"; return Data(); } diff --git a/src/uscxml/interpreter/BasicEventQueue.cpp b/src/uscxml/interpreter/BasicEventQueue.cpp index ee2346d..7309392 100644 --- a/src/uscxml/interpreter/BasicEventQueue.cpp +++ b/src/uscxml/interpreter/BasicEventQueue.cpp @@ -35,13 +35,26 @@ Event BasicEventQueue::dequeue(size_t blockMs) { std::lock_guard lock(_mutex); if (blockMs > 0) { - // block for given milliseconds or until queue is filled - std::chrono::time_point end, now; - now = std::chrono::system_clock::now(); - end = now + std::chrono::milliseconds(blockMs); - while (std::chrono::system_clock::now() < end && _queue.empty()) { - _cond.wait_for(_mutex, std::chrono::system_clock::now() - end); + // block for given milliseconds or until queue is filled + std::chrono::time_point updated, now; + std::chrono::milliseconds remain; + + if (blockMs > std::chrono::system_clock::duration::max().count()) { + blockMs = std::chrono::system_clock::duration::max().count(); + } + + updated = now = std::chrono::system_clock::now(); + remain = std::chrono::milliseconds(blockMs); + + while (remain.count() > 0 && _queue.empty()) { + _cond.wait_for(_mutex, remain); + + now = std::chrono::system_clock::now(); + + auto elapsed = now - updated; + remain -= std::chrono::duration_cast(elapsed); + updated = now; } } diff --git a/src/uscxml/interpreter/FastMicroStep.cpp b/src/uscxml/interpreter/FastMicroStep.cpp index 3ad5515..927fbbc 100644 --- a/src/uscxml/interpreter/FastMicroStep.cpp +++ b/src/uscxml/interpreter/FastMicroStep.cpp @@ -155,8 +155,35 @@ void FastMicroStep::resortStates(DOMNode* node, const X& xmlPrefix) { } } -void FastMicroStep::init(XERCESC_NS::DOMElement* scxml) { +std::list FastMicroStep::getExitSetCached(const XERCESC_NS::DOMElement* transition, + const XERCESC_NS::DOMElement* root) { + + if (_cache.exitSet.find(transition) == _cache.exitSet.end()) { + _cache.exitSet[transition] = getExitSet(transition, root); + } + + return _cache.exitSet[transition]; +} + +bool FastMicroStep::conflictsCached(const DOMElement* t1, const DOMElement* t2, const DOMElement* root) { + if (getSourceState(t1) == getSourceState(t2)) + return true; + + if (DOMUtils::isDescendant(getSourceState(t1), getSourceState(t2))) + return true; + if (DOMUtils::isDescendant(getSourceState(t2), getSourceState(t1))) + return true; + + if (DOMUtils::hasIntersection(getExitSetCached(t1, root), getExitSetCached(t2, root))) + return true; + + return false; +} + + +void FastMicroStep::init(XERCESC_NS::DOMElement* scxml) { + _scxml = scxml; _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY); _xmlPrefix = _scxml->getPrefix(); @@ -331,7 +358,9 @@ void FastMicroStep::init(XERCESC_NS::DOMElement* scxml) { // establish the transitions' exit set assert(_transitions[i]->element != NULL); // std::cout << "i: " << i << std::endl << std::flush; - std::list exitList = getExitSet(_transitions[i]->element, _scxml); + std::list exitList = getExitSetCached(_transitions[i]->element, _scxml); + _cache.exitSet[_transitions[i]->element] = exitList; + for (j = 0; j < _states.size(); j++) { if (!exitList.empty() && _states[j]->element == exitList.front()) { _transitions[i]->exitSet[j] = true; @@ -343,14 +372,21 @@ void FastMicroStep::init(XERCESC_NS::DOMElement* scxml) { assert(exitList.size() == 0); // establish the transitions' conflict set - for (j = 0; j < _transitions.size(); j++) { - if (conflicts(_transitions[i]->element, _transitions[j]->element, _scxml)) { + for (j = i; j < _transitions.size(); j++) { + if (conflictsCached(_transitions[i]->element, _transitions[j]->element, _scxml)) { _transitions[i]->conflicts[j] = true; } else { _transitions[i]->conflicts[j] = false; } +// std::cout << "."; } + + // conflicts matrix is symmetric + for (j = 0; j < i; j++) { + _transitions[i]->conflicts[j] = _transitions[j]->conflicts[i]; + } + // establish the transitions' target set std::list targets = tokenize(ATTR(_transitions[i]->element, "target")); for (auto tIter = targets.begin(); tIter != targets.end(); tIter++) { @@ -387,8 +423,10 @@ void FastMicroStep::init(XERCESC_NS::DOMElement* scxml) { // the transitions event and condition - _transitions[i]->event = (HAS_ATTR(_transitions[i]->element, "event") ? ATTR(_transitions[i]->element, "event") : ""); - _transitions[i]->cond = (HAS_ATTR(_transitions[i]->element, "cond") ? ATTR(_transitions[i]->element, "cond") : ""); + _transitions[i]->event = (HAS_ATTR(_transitions[i]->element, "event") ? + ATTR(_transitions[i]->element, "event") : ""); + _transitions[i]->cond = (HAS_ATTR(_transitions[i]->element, "cond") ? + ATTR(_transitions[i]->element, "cond") : ""); // is there executable content? if (_transitions[i]->element->getChildElementCount() > 0) { @@ -396,6 +434,7 @@ void FastMicroStep::init(XERCESC_NS::DOMElement* scxml) { } } + _cache.exitSet.clear(); _isInitialized = true; } @@ -1030,12 +1069,9 @@ std::list FastMicroStep::getCompletion(const DOMElement* state) { completion.push_back(initElems.front()); } else { // first child state - DOMNodeList* children = state->getChildNodes(); - for (size_t i = 0; i < children->getLength(); i++) { - if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE) - continue; - if (isState(dynamic_cast(children->item(i)))) { - completion.push_back(dynamic_cast(children->item(i))); + for (auto childElem = state->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) { + if (isState(childElem)) { + completion.push_back(childElem); break; } } diff --git a/src/uscxml/interpreter/FastMicroStep.h b/src/uscxml/interpreter/FastMicroStep.h index 023bb8f..b2477ee 100644 --- a/src/uscxml/interpreter/FastMicroStep.h +++ b/src/uscxml/interpreter/FastMicroStep.h @@ -26,6 +26,7 @@ #include "uscxml/util/DOM.h" // X #include +#include #include #include "MicroStepImpl.h" @@ -89,6 +90,11 @@ protected: unsigned char type; }; + class CachedPredicates { + public: + std::map > exitSet; + }; + virtual void init(XERCESC_NS::DOMElement* scxml); std::list getCompletion(const XERCESC_NS::DOMElement* state); @@ -120,7 +126,12 @@ private: std::list getHistoryCompletion(const XERCESC_NS::DOMElement* state); void resortStates(XERCESC_NS::DOMNode* node, const X& xmlPrefix); -// bool hasLegalConfiguration(); + bool conflictsCached(const XERCESC_NS::DOMElement* t1, const XERCESC_NS::DOMElement* t2, const XERCESC_NS::DOMElement* root); ///< overrides implementation Predicates::conflicts for speed + + std::list getExitSetCached(const XERCESC_NS::DOMElement* transition, + const XERCESC_NS::DOMElement* root); + + CachedPredicates _cache; #ifdef USCXML_VERBOSE void printStateNames(const boost::dynamic_bitset<>& bitset); diff --git a/src/uscxml/interpreter/InterpreterImpl.cpp b/src/uscxml/interpreter/InterpreterImpl.cpp index 3383411..0547f12 100644 --- a/src/uscxml/interpreter/InterpreterImpl.cpp +++ b/src/uscxml/interpreter/InterpreterImpl.cpp @@ -82,15 +82,31 @@ InterpreterImpl::InterpreterImpl() : _isInitialized(false), _document(NULL), _sc InterpreterImpl::~InterpreterImpl() { - if (_delayQueue) - _delayQueue.cancelAllDelayed(); - if (_document) - delete _document; - - { - std::lock_guard lock(_instanceMutex); - _instances.erase(getSessionId()); - } + + // make sure we deallocate all user-data in the DOM, + // this is neccesary if we were aborted early + std::list invokes = DOMUtils::filterChildElements(_xmlPrefix.str() + "invoke", _scxml, true); + for (auto invoke : invokes) { + char* invokeId = (char*)invoke->getUserData(X("invokeid")); + if (invokeId != NULL) { + free(invokeId); + invoke->setUserData(X("invokeid"), NULL, NULL); + } + } + + if (_delayQueue) + _delayQueue.cancelAllDelayed(); + if (_document) + delete _document; + + { + std::lock_guard lock(_instanceMutex); + _instances.erase(getSessionId()); + } + +// assert(_invokers.size() == 0); +// ::xercesc_3_1::XMLPlatformUtils::Terminate(); + } void InterpreterImpl::cancel() { @@ -361,6 +377,7 @@ void InterpreterImpl::uninvoke(const std::string& invokeId) { if (_invokers.find(invokeId) != _invokers.end()) { _invokers[invokeId].uninvoke(); _autoForwarders.erase(invokeId); + _invokers.erase(invokeId); } } diff --git a/src/uscxml/plugins/DataModelImpl.h b/src/uscxml/plugins/DataModelImpl.h index 403a213..a151141 100644 --- a/src/uscxml/plugins/DataModelImpl.h +++ b/src/uscxml/plugins/DataModelImpl.h @@ -43,6 +43,7 @@ class DataModelImpl; */ class USCXML_API DataModelCallbacks { public: + virtual ~DataModelCallbacks() {} ///< silence virtual destructor warning from swig virtual const std::string& getName() = 0; virtual const std::string& getSessionId() = 0; virtual const std::map& getIOProcessors() = 0; diff --git a/src/uscxml/plugins/Factory.cpp b/src/uscxml/plugins/Factory.cpp index 3600dd1..e551a61 100644 --- a/src/uscxml/plugins/Factory.cpp +++ b/src/uscxml/plugins/Factory.cpp @@ -28,23 +28,38 @@ // see http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system -// we will always include these in a build + +#ifdef WITH_IOPROC_SCXML +# include "uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.h" +#endif + +#ifdef WITH_IOPROC_BASICHTTP +# include "uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.h" +#endif + + #include "uscxml/plugins/datamodel/null/NULLDataModel.h" -#include "uscxml/plugins/invoker/scxml/USCXMLInvoker.h" -#include "uscxml/plugins/ioprocessor/scxml/SCXMLIOProcessor.h" -#include "uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.h" -# ifdef V8_FOUND +#ifdef WITH_DM_ECMA_V8 # include "uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h" -# endif +#endif -# ifdef JSC_FOUND +#ifdef WITH_DM_ECMA_JSC # include "uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h" -# endif +#endif -# ifdef LUA_FOUND +#ifdef WITH_DM_LUA # include "uscxml/plugins/datamodel/lua/LuaDataModel.h" -# endif +#endif + + +#ifdef WITH_INV_SCXML +# include "uscxml/plugins/invoker/scxml/USCXMLInvoker.h" +#endif + +#ifdef WITH_INV_DIRMON +# include "uscxml/plugins/invoker/dirmon/DirMonInvoker.h" +#endif namespace uscxml { @@ -69,47 +84,61 @@ std::string Factory::getDefaultPluginPath() { void Factory::registerPlugins() { - { - USCXMLInvoker* invoker = new USCXMLInvoker(); - registerInvoker(invoker); - } - - { - SCXMLIOProcessor* ioProcessor = new SCXMLIOProcessor(); - registerIOProcessor(ioProcessor); - } - - { - BasicHTTPIOProcessor* ioProcessor = new BasicHTTPIOProcessor(); - registerIOProcessor(ioProcessor); - } - - { - NULLDataModel* dataModel = new NULLDataModel(); - registerDataModel(dataModel); - } +#ifdef WITH_IOPROC_SCXML + { + SCXMLIOProcessor* ioProcessor = new SCXMLIOProcessor(); + registerIOProcessor(ioProcessor); + } +#endif -#ifdef V8_FOUND - { - V8DataModel* dataModel = new V8DataModel(); - registerDataModel(dataModel); - } +#ifdef WITH_IOPROC_BASICHTTP + { + BasicHTTPIOProcessor* ioProcessor = new BasicHTTPIOProcessor(); + registerIOProcessor(ioProcessor); + } #endif -#ifdef JSC_FOUND - { - JSCDataModel* dataModel = new JSCDataModel(); - registerDataModel(dataModel); - } + +#ifdef WITH_DM_ECMA_V8 + { + V8DataModel* dataModel = new V8DataModel(); + registerDataModel(dataModel); + } #endif -#ifdef LUA_FOUND - { - LuaDataModel* dataModel = new LuaDataModel(); - registerDataModel(dataModel); - } +#ifdef WITH_DM_ECMA_JSC + { + JSCDataModel* dataModel = new JSCDataModel(); + registerDataModel(dataModel); + } +#endif + +#ifdef WITH_DM_LUA + { + LuaDataModel* dataModel = new LuaDataModel(); + registerDataModel(dataModel); + } #endif + { + NULLDataModel* dataModel = new NULLDataModel(); + registerDataModel(dataModel); + } + + +#ifdef WITH_INV_SCXML + { + USCXMLInvoker* invoker = new USCXMLInvoker(); + registerInvoker(invoker); + } +#endif + +#ifdef WITH_INV_DIRMON + { + DirMonInvoker* inv = new DirMonInvoker(); + registerInvoker(inv); + } +#endif } diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index 3ccadcd..1db4f45 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -415,7 +415,9 @@ void V8DataModel::setEvent(const Event& event) { } // we cannot make _event v8::ReadOnly as it will ignore subsequent setEvents global->Set(v8::String::NewSymbol("_event"), eventObj); - _event.Reset(_isolate, eventObj); + +// _event.Reset(_isolate, eventObj); +// _event = eventObj; } Data V8DataModel::getAsData(const std::string& content) { diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h index 91ac48d..3b4d776 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h @@ -84,7 +84,7 @@ protected: static void jsIn(const v8::FunctionCallbackInfo& info); static void jsPrint(const v8::FunctionCallbackInfo& info); - v8::Persistent _event; + //v8::Local _event; // Persistent events leak .. v8::Persistent _context; static v8::Isolate* _isolate; diff --git a/src/uscxml/plugins/invoker/CMakeLists.txt b/src/uscxml/plugins/invoker/CMakeLists.txt index ec64899..5500e3f 100644 --- a/src/uscxml/plugins/invoker/CMakeLists.txt +++ b/src/uscxml/plugins/invoker/CMakeLists.txt @@ -1,11 +1,25 @@ # USCXML invoker -set(USCXML_INVOKERS "scxml ${USCXML_INVOKERS}") -file(GLOB_RECURSE USCXML_INVOKER - scxml/*.cpp - scxml/*.h) - list (APPEND USCXML_FILES ${USCXML_INVOKER}) +OPTION(WITH_INV_SCXML "Build the SCXML invoker" ON) +if (WITH_INV_SCXML) + set(USCXML_INVOKERS "scxml ${USCXML_INVOKERS}") + file(GLOB_RECURSE USCXML_INVOKER + scxml/*.cpp + scxml/*.h) + list (APPEND USCXML_FILES ${USCXML_INVOKER}) +endif() + +# Directoy Monitor +OPTION(WITH_INV_DIRMON "Build the directory monitor invoker" ON) +if (WITH_INV_DIRMON) + set(USCXML_INVOKERS "dirmon ${USCXML_INVOKERS}") + file(GLOB_RECURSE DIRMON_INVOKER + dirmon/*.cpp + dirmon/*.h) + list (APPEND USCXML_FILES ${DIRMON_INVOKER}) +endif() + set(USCXML_INCLUDE_DIRS ${USCXML_INCLUDE_DIRS} PARENT_SCOPE) set(USCXML_FILES ${USCXML_FILES} PARENT_SCOPE) set(USCXML_INVOKERS ${USCXML_INVOKERS} PARENT_SCOPE) diff --git a/src/uscxml/plugins/invoker/dirmon/DirMonInvoker.cpp b/src/uscxml/plugins/invoker/dirmon/DirMonInvoker.cpp new file mode 100644 index 0000000..f3b429f --- /dev/null +++ b/src/uscxml/plugins/invoker/dirmon/DirMonInvoker.cpp @@ -0,0 +1,449 @@ +/** + * @file + * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see . + * @endcond + */ + +#include "DirMonInvoker.h" + +#include "uscxml/config.h" + +#ifdef BUILD_AS_PLUGINS +#include +#endif + +#include +#ifndef WIN32 +#include +#else +#include +#endif + +#include +#include + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool pluginConnect(pluma::Host& host) { + host.add( new DirMonInvokerProvider() ); + return true; +} +#endif + +DirMonInvoker::DirMonInvoker() : + _reportExisting(true), + _reportHidden(false), + _recurse(false), + _thread(NULL), + _watcher(NULL) { +} + +DirMonInvoker::~DirMonInvoker() { + _isRunning = false; + if (_thread) { + _thread->join(); + delete _thread; + } + if (_watcher) + delete(_watcher); +}; + +std::shared_ptr DirMonInvoker::create(InterpreterImpl* interpreter) { + std::shared_ptr invoker(new DirMonInvoker()); + invoker->_interpreter = interpreter; + return invoker; +} + +Data DirMonInvoker::getDataModelVariables() { + std::lock_guard lock(_mutex); + + Data data; + data.compound["dir"] = Data(_dir, Data::VERBATIM); + + std::set::iterator suffixIter = _suffixes.begin(); + while(suffixIter != _suffixes.end()) { + data.compound["suffixes"].array.push_back(Data(*suffixIter, Data::VERBATIM)); + suffixIter++; + } + + std::map entries = _watcher->getAllEntries(); + std::map::iterator entryIter = entries.begin(); + while(entryIter != entries.end()) { + data.compound["file"].compound[entryIter->first].compound["mtime"] = Data(toStr(entryIter->second.st_mtime), Data::INTERPRETED); + data.compound["file"].compound[entryIter->first].compound["ctime"] = Data(toStr(entryIter->second.st_mtime), Data::INTERPRETED); + data.compound["file"].compound[entryIter->first].compound["atime"] = Data(toStr(entryIter->second.st_mtime), Data::INTERPRETED); + data.compound["file"].compound[entryIter->first].compound["size"] = Data(toStr(entryIter->second.st_mtime), Data::INTERPRETED); + entryIter++; + } + + return data; +} + +void DirMonInvoker::eventFromSCXML(const Event& event) { +} + +void DirMonInvoker::invoke(const std::string& source, const Event& req) { + if (req.params.find("dir") == req.params.end()) { + LOG(ERROR) << "No dir param given"; + return; + } + + if (req.params.find("reportexisting") != req.params.end() && + iequals(req.params.find("reportexisting")->second.atom, "false")) + _reportExisting = false; + if (req.params.find("recurse") != req.params.end() && + iequals(req.params.find("recurse")->second.atom, "true")) + _recurse = true; + if (req.params.find("reporthidden") != req.params.end() && + iequals(req.params.find("reporthidden")->second.atom, "true")) + _reportHidden = true; + + std::string suffixList; + if (req.params.find("suffix") != req.params.end()) { + suffixList = req.params.find("suffix")->second.atom; + } else if (req.params.find("suffixes") != req.params.end()) { + suffixList = req.params.find("suffixes")->second.atom; + } + + if (suffixList.size() > 0) { + // seperate path into components + std::stringstream ss(suffixList); + std::string item; + while(std::getline(ss, item, ' ')) { + if (item.length() == 0) + continue; + _suffixes.insert(item); + } + } + + std::multimap::const_iterator dirIter = req.params.find("dir"); + while(dirIter != req.params.upper_bound("dir")) { + // this is simplified - Data might be more elaborate than a simple string atom + URL url = URL::resolve(dirIter->second.atom, _interpreter->getBaseURL()); + + if (!url.isAbsolute()) { + LOG(ERROR) << "Given directory '" << dirIter->second << "' cannot be transformed to absolute path"; + } else { + _dir = url.path(); + } + break; + } + + _watcher = new DirectoryWatch(_dir, _recurse); + _watcher->addMonitor(this); + _watcher->updateEntries(true); + + _isRunning = true; + _thread = new std::thread(DirMonInvoker::run, this); +} + +void DirMonInvoker::uninvoke() { + _isRunning = false; + if (_thread) { + _thread->join(); + delete _thread; + } +} + +void DirMonInvoker::run(void* instance) { + while(((DirMonInvoker*)instance)->_isRunning) { + { + std::lock_guard lock(((DirMonInvoker*)instance)->_mutex); + ((DirMonInvoker*)instance)->_watcher->updateEntries(); + } + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + } +} + +void DirMonInvoker::handleChanges(DirectoryWatch::Action action, const std::string reportedDir, const std::string reportedFilename, struct stat fileStat) { + +// std::cout << action << " on " << reportedFilename << std::endl; + + std::string path; ///< complete path to the file including filename + std::string relPath; ///< path relative to monitored directory including filename + std::string dir; ///< the name of the directory we monitor + std::string relDir; ///< the directory from dir to the actual directory where we found a file + std::string basename; ///< filename including suffix + std::string strippedName; ///< filename without the suffix + std::string extension; ///< the extension + + dir = reportedDir; + + path = dir + reportedFilename; + boost::algorithm::replace_all(path, "\\", "/"); + boost::algorithm::replace_all(path, "//", "/"); + + assert(boost::algorithm::starts_with(path, dir)); + relPath = path.substr(dir.length()); + assert(boost::equal(path, dir + relPath)); + + size_t lastSep; + if ((lastSep = path.find_last_of(PATH_SEPERATOR)) != std::string::npos) { + lastSep++; + basename = path.substr(lastSep, path.length() - lastSep); + } else { + assert(false); + } + assert(boost::algorithm::ends_with(relPath, basename)); + + // extension is the suffix and strippedName the basename without the suffix + size_t lastDot; + if ((lastDot = basename.find_last_of(".")) != std::string::npos) { + if (lastDot == 0) { + // hidden file + strippedName = basename; + } else { + extension = basename.substr(lastDot + 1); + strippedName = basename.substr(0, lastDot); + } + } else { + strippedName = basename; + } + + relDir = relPath.substr(0, relPath.length() - basename.length()); + assert(boost::equal(path, dir + relDir + basename)); + + // return if this is a hidden file + if (boost::algorithm::starts_with(basename, ".") && !_reportHidden) + return; + + // ilter suffixes + if (_suffixes.size() > 0) { + bool validSuffix = false; + std::set::iterator suffixIter = _suffixes.begin(); + while(suffixIter != _suffixes.end()) { + if (boost::algorithm::ends_with(path, *suffixIter)) { + validSuffix = true; + break; + } + suffixIter++; + } + if (!validSuffix) + return; + } + + Event event; + event.invokeid = _invokeId; + + switch (action) { + case DirectoryWatch::EXISTING: + event.name = "file.existing"; + break; + case DirectoryWatch::ADDED: + event.name = "file.added"; + break; + case DirectoryWatch::DELETED: + event.name = "file.deleted"; + break; + case DirectoryWatch::MODIFIED: + event.name = "file.modified"; + break; + default: + break; + } + + if (action != DirectoryWatch::DELETED) { + event.data.compound["file"].compound["mtime"] = Data(toStr(fileStat.st_mtime), Data::INTERPRETED); + event.data.compound["file"].compound["ctime"] = Data(toStr(fileStat.st_ctime), Data::INTERPRETED); + event.data.compound["file"].compound["atime"] = Data(toStr(fileStat.st_atime), Data::INTERPRETED); + event.data.compound["file"].compound["size"] = Data(toStr(fileStat.st_size), Data::INTERPRETED); + } + + event.data.compound["file"].compound["name"] = Data(basename, Data::VERBATIM); + event.data.compound["file"].compound["extension"] = Data(extension, Data::VERBATIM); + event.data.compound["file"].compound["strippedName"] = Data(strippedName, Data::VERBATIM); + event.data.compound["file"].compound["relPath"] = Data(relPath, Data::VERBATIM); + event.data.compound["file"].compound["relDir"] = Data(relDir, Data::VERBATIM); + event.data.compound["file"].compound["path"] = Data(path, Data::VERBATIM); + event.data.compound["file"].compound["dir"] = Data(dir, Data::VERBATIM); + + eventToSCXML(event, "dimon", ""); +} + +DirectoryWatch::~DirectoryWatch() { + std::map::iterator dirIter = _knownDirs.begin(); + while(dirIter != _knownDirs.end()) { + delete(dirIter->second); + dirIter++; + } + +} + +void DirectoryWatch::reportAsDeleted() { + std::map::iterator fileIter = _knownEntries.begin(); + while(fileIter != _knownEntries.end()) { + if (fileIter->second.st_mode & S_IFDIR) { + _knownDirs[fileIter->first]->reportAsDeleted(); + delete _knownDirs[fileIter->first]; + _knownDirs.erase(fileIter->first); + } else { + _monitors_t::iterator monIter = _monitors.begin(); + while(monIter != _monitors.end()) { + (*monIter)->handleChanges(DELETED, _dir, _relDir + PATH_SEPERATOR + fileIter->first, fileIter->second); + monIter++; + } + } + _knownEntries.erase(fileIter++); +// fileIter++; + } + assert(_knownDirs.size() == 0); + assert(_knownEntries.size() == 0); +} + +void DirectoryWatch::updateEntries(bool reportAsExisting) { + _monitors_t::iterator monIter; + if (_dir[_dir.length() - 1] == PATH_SEPERATOR) + _dir = _dir.substr(0, _dir.length() - 1); + + // stat directory for modification date + struct stat dirStat; + if (stat((_dir + _relDir).c_str(), &dirStat) != 0) { + LOG(ERROR) << "Error with stat on directory " << _dir << ": " << strerror(errno); + return; + } + + if ((unsigned)dirStat.st_mtime >= (unsigned)_lastChecked) { +// std::cout << "dirStat.st_mtime: " << dirStat.st_mtime << " / _lastChecked: " << _lastChecked << std::endl; + + // there are changes in the directory + std::set currEntries; + +#ifndef WIN32 + DIR *dp; + dp = opendir((_dir + _relDir).c_str()); + if (dp == NULL) { + LOG(ERROR) << "Error opening directory " << _dir + _relDir << ": " << strerror(errno); + return; + } + // iterate all entries and see what changed + struct dirent* entry; + while((entry = readdir(dp))) { + std::string dname = entry->d_name; +#else + WIN32_FIND_DATA ffd; + HANDLE hFind = INVALID_HANDLE_VALUE; + TCHAR szDir[MAX_PATH]; + StringCchCopy(szDir, MAX_PATH, _dir.c_str()); + StringCchCat(szDir, MAX_PATH, TEXT("\\*")); + + hFind = FindFirstFile(szDir, &ffd); + do { + std::string dname = ffd.cFileName; +#endif + + // see if the file was changed + std::string filename = _dir + _relDir + "/" + dname; +// asprintf(&filename, "%s/%s", (_dir + _relDir).c_str(), dname.c_str()); + + struct stat fileStat; + if (stat(filename.c_str(), &fileStat) != 0) { + LOG(ERROR) << "Error with stat on directory entry: " << filename << ": " << strerror(errno); + continue; + } + + if (fileStat.st_mode & S_IFDIR) { + if (boost::equals(dname, ".") || boost::equals(dname, "..")) { + continue; // do not report . or .. + } + } + + currEntries.insert(dname); + + if (_knownEntries.find(dname) != _knownEntries.end()) { + // we have seen this entry before + struct stat oldStat = _knownEntries[dname]; + if (oldStat.st_mtime < fileStat.st_mtime) { + monIter = _monitors.begin(); + while(monIter != _monitors.end()) { + (*monIter)->handleChanges(MODIFIED, _dir, _relDir + PATH_SEPERATOR + dname, fileStat); + monIter++; + } + } + } else { + // we have not yet seen this entry + if (fileStat.st_mode & S_IFDIR) { + _knownDirs[dname] = new DirectoryWatch(_dir, _relDir + PATH_SEPERATOR + dname); + monIter = _monitors.begin(); + while(monIter != _monitors.end()) { + _knownDirs[dname]->addMonitor(*monIter); + monIter++; + } + } else { + monIter = _monitors.begin(); + while(monIter != _monitors.end()) { + if (reportAsExisting) { + (*monIter)->handleChanges(EXISTING, _dir, _relDir + PATH_SEPERATOR + dname, fileStat); + } else { + (*monIter)->handleChanges(ADDED, _dir, _relDir + PATH_SEPERATOR + dname, fileStat); + } + monIter++; + } + } + } + + _knownEntries[dname] = fileStat; // gets copied on insertion +#ifndef WIN32 + } + closedir(dp); +#else + } + while (FindNextFile(hFind, &ffd) != 0); + FindClose(hFind); +#endif + // are there any known entries we have not seen this time around? + std::map::iterator fileIter = _knownEntries.begin(); + while(fileIter != _knownEntries.end()) { + if (currEntries.find(fileIter->first) == currEntries.end()) { + // we used to know this file + if (fileIter->second.st_mode & S_IFDIR) { + if (_recurse) { + _knownDirs[fileIter->first]->reportAsDeleted(); + delete _knownDirs[fileIter->first]; + _knownDirs.erase(fileIter->first); + } + } else { + monIter = _monitors.begin(); + while(monIter != _monitors.end()) { + (*monIter)->handleChanges(DELETED, _dir, _relDir + PATH_SEPERATOR + fileIter->first, fileIter->second); + monIter++; + } + } + _knownEntries.erase(fileIter++); + } else { + fileIter++; + } + } + // remember when we last checked the directory for modifications +#ifndef WIN32 + time(&_lastChecked); +#else + // TODO: this will fail with sub-millisecond updates to the directory + _lastChecked = dirStat.st_mtime + 1; +#endif + // update all directories + } + if (_recurse) { + std::map::iterator dirIter = _knownDirs.begin(); + while(dirIter != _knownDirs.end()) { + dirIter->second->updateEntries(); + dirIter++; + } + } +} + +} \ No newline at end of file diff --git a/src/uscxml/plugins/invoker/dirmon/DirMonInvoker.h b/src/uscxml/plugins/invoker/dirmon/DirMonInvoker.h new file mode 100644 index 0000000..be510d9 --- /dev/null +++ b/src/uscxml/plugins/invoker/dirmon/DirMonInvoker.h @@ -0,0 +1,140 @@ +/** + * @file + * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see . + * @endcond + */ + +#ifndef DIRMONINVOKER_H_W09J90F0 +#define DIRMONINVOKER_H_W09J90F0 + +#include "uscxml/plugins/InvokerImpl.h" + +#include +#include +#include + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class DirectoryWatchMonitor; + +class DirectoryWatch { +public: + enum Action { + ADDED = 1, + MODIFIED = 2, + DELETED = 4, + EXISTING = 8 + }; + + DirectoryWatch(const std::string& dir, bool recurse = false) : _dir(dir), _recurse(recurse), _lastChecked(0) {} + ~DirectoryWatch(); + + void addMonitor(DirectoryWatchMonitor* monitor) { + _monitors.insert(monitor); + } + void removeMonitor(DirectoryWatchMonitor* monitor) { + _monitors.erase(monitor); + } + void updateEntries(bool reportAsExisting = false); + void reportAsDeleted(); + + std::map getAllEntries() { + std::map entries; + entries.insert(_knownEntries.begin(), _knownEntries.end()); + + std::map::iterator dirIter = _knownDirs.begin(); + while(dirIter != _knownDirs.end()) { + std::map dirEntries = dirIter->second->getAllEntries(); + std::map::iterator dirEntryIter = dirEntries.begin(); + while(dirEntryIter != dirEntries.end()) { + entries[dirIter->first + '/' + dirEntryIter->first] = dirEntryIter->second; + dirEntryIter++; + } + dirIter++; + } + + return entries; + } + +protected: + DirectoryWatch(const std::string& dir, const std::string& relDir) : _dir(dir), _relDir(relDir), _recurse(true), _lastChecked(0) {} + + std::string _dir; + std::string _relDir; + + bool _recurse; + std::map _knownEntries; + std::map _knownDirs; + std::set _monitors; + typedef std::set _monitors_t; + time_t _lastChecked; +}; + +class DirectoryWatchMonitor { +public: + virtual void handleChanges(DirectoryWatch::Action action, const std::string dir, const std::string file, struct stat fileStat) = 0; +}; + +class DirMonInvoker : public InvokerImpl, public DirectoryWatchMonitor { +public: + DirMonInvoker(); + virtual ~DirMonInvoker(); + virtual std::shared_ptr create(InterpreterImpl* interpreter); + + virtual std::list getNames() { + std::list names; + names.push_back("dirmon"); + names.push_back("DirectoryMonitor"); + names.push_back("http://uscxml.tk.informatik.tu-darmstadt.de/#dirmon"); + return names; + } + + virtual Data getDataModelVariables(); + virtual void eventFromSCXML(const Event& event); + virtual void invoke(const std::string& source, const Event& invokeEvent); + virtual void uninvoke(); + + virtual void handleChanges(DirectoryWatch::Action action, const std::string dir, const std::string file, struct stat fileStat); + + static void run(void* instance); + +protected: + bool _reportExisting; + bool _reportHidden; + bool _recurse; + + std::string _dir; + std::set _suffixes; + + bool _isRunning; + std::thread* _thread; + std::recursive_mutex _mutex; + + DirectoryWatch* _watcher; +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(DirMonInvoker, InvokerImpl); +#endif + +} + + +#endif /* end of include guard: DIRMONINVOKER_H_W09J90F0 */ diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h index f896bac..9509de3 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h @@ -23,7 +23,6 @@ #include "uscxml/interpreter/InterpreterImpl.h" #include "uscxml/interpreter/BasicEventQueue.h" -#include "uscxml/plugins/Invoker.h" #include "uscxml/plugins/InvokerImpl.h" #ifdef BUILD_AS_PLUGINS diff --git a/src/uscxml/plugins/ioprocessor/CMakeLists.txt b/src/uscxml/plugins/ioprocessor/CMakeLists.txt index 1171d73..3505920 100644 --- a/src/uscxml/plugins/ioprocessor/CMakeLists.txt +++ b/src/uscxml/plugins/ioprocessor/CMakeLists.txt @@ -1,20 +1,25 @@ # scxml ioprocessor -set(USCXML_IOPROCESSORS "scxml ${USCXML_IOPROCESSORS}") -file(GLOB_RECURSE SCXML_IOPROCESSOR - scxml/*.cpp - scxml/*.h -) -list (APPEND USCXML_FILES ${SCXML_IOPROCESSOR}) +OPTION(WITH_IOPROC_SCXML "Build the scxml i/o processor" ON) +if (WITH_IOPROC_SCXML) + set(USCXML_IOPROCESSORS "scxml ${USCXML_IOPROCESSORS}") + file(GLOB_RECURSE SCXML_IOPROCESSOR + scxml/*.cpp + scxml/*.h + ) + list (APPEND USCXML_FILES ${SCXML_IOPROCESSOR}) +endif() -set(USCXML_IOPROCESSORS "basichttp ${USCXML_IOPROCESSORS}") -file(GLOB_RECURSE BASICHTTP_IOPROCESSOR - basichttp/*.cpp - basichttp/*.h -) -list (APPEND BASICHTTP_IOPROCESSOR "") - -list (APPEND USCXML_FILES ${BASICHTTP_IOPROCESSOR}) +OPTION(WITH_IOPROC_BASICHTTP "Build the basichttp i/o processor" ON) +if (WITH_IOPROC_BASICHTTP) + set(USCXML_IOPROCESSORS "basichttp ${USCXML_IOPROCESSORS}") + file(GLOB_RECURSE BASICHTTP_IOPROCESSOR + basichttp/*.cpp + basichttp/*.h + ) + list (APPEND BASICHTTP_IOPROCESSOR "") + list (APPEND USCXML_FILES ${BASICHTTP_IOPROCESSOR}) +endif() set(USCXML_INCLUDE_DIRS ${USCXML_INCLUDE_DIRS} PARENT_SCOPE) set(USCXML_OPT_LIBS ${USCXML_OPT_LIBS} PARENT_SCOPE) diff --git a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp index f81cf54..317b94c 100644 --- a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp @@ -199,9 +199,9 @@ void BasicHTTPIOProcessor::eventFromSCXML(const std::string& target, const Event char* eventValueCStr = evhttp_encode_uri(event.name.c_str()); kvps << kvpSeperator << eventNameCStr << "=" << eventValueCStr; kvpSeperator = "&"; - free(eventNameCStr); - free(eventValueCStr); - targetURL.addOutHeader("_scxmleventname", evhttp_encode_uri(event.name.c_str())); + targetURL.addOutHeader("_scxmleventname", eventValueCStr); + free(eventNameCStr); + free(eventValueCStr); } // event namelist diff --git a/src/uscxml/server/HTTPServer.cpp b/src/uscxml/server/HTTPServer.cpp index cb80ec4..044cb6c 100644 --- a/src/uscxml/server/HTTPServer.cpp +++ b/src/uscxml/server/HTTPServer.cpp @@ -331,12 +331,6 @@ void HTTPServer::httpRecvReqCallback(struct evhttp_request *req, void *callbackD } raw << std::endl; - // This was used for debugging -// if (boost::ends_with(request.data.compound["path"].atom, ".png")) { -// evhttp_send_error(req, 404, NULL); -// return; -// } - // seperate path into components { std::stringstream ss(request.data.compound["path"].atom); diff --git a/src/uscxml/util/DOM.cpp b/src/uscxml/util/DOM.cpp index ecf0960..7793fb5 100644 --- a/src/uscxml/util/DOM.cpp +++ b/src/uscxml/util/DOM.cpp @@ -52,7 +52,7 @@ std::ostream& operator<< (std::ostream& os, const DOMNode& node) { } std::ostream& operator<< (std::ostream& os, const X& xmlString) { - os << xmlString._localForm; + os << xmlString.str(); return os; } @@ -236,20 +236,13 @@ void DOMUtils::inPostFixOrder(const std::set& elements, if (root == NULL) return; - DOMNodeList* children = root->getChildNodes(); - for (size_t i = 0; i < children->getLength(); i++) { - if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE) - continue; - const DOMElement* childElem = dynamic_cast(children->item(i)); + for (auto childElem = root->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) { if (!includeEmbeddedDoc && LOCALNAME(childElem) == "scxml") continue; inPostFixOrder(elements, childElem, includeEmbeddedDoc, nodes); } - for (size_t i = 0; i < children->getLength(); i++) { - if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE) - continue; - const DOMElement* childElem = dynamic_cast(children->item(i)); + for (auto childElem = root->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) { if (!includeEmbeddedDoc && TAGNAME(childElem) == XML_PREFIX(root).str() + "scxml") continue; @@ -278,14 +271,14 @@ void DOMUtils::inDocumentOrder(const std::set& elements, nodes.push_back((DOMElement*)root); } - DOMNodeList* children = root->getChildNodes(); - for (size_t i = 0; i < children->getLength(); i++) { - if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE) - continue; - const DOMElement* childElem = dynamic_cast(children->item(i)); - if (!includeEmbeddedDoc && TAGNAME(childElem) == XML_PREFIX(root).str() + "scxml") - continue; - inDocumentOrder(elements, childElem, includeEmbeddedDoc, nodes); + /// @todo: item from getChildNodes is O(N)! + DOMElement* child = root->getFirstElementChild(); + while(child) { + if (includeEmbeddedDoc || TAGNAME(child) != XML_PREFIX(root).str() + "scxml") { + inDocumentOrder(elements, child, includeEmbeddedDoc, nodes); + } + + child = child->getNextElementSibling(); } } @@ -350,12 +343,7 @@ std::list DOMUtils::filterChildElements(const std::string& tagName, if (!node) return filteredChildElems; - DOMNodeList* children = node->getChildNodes(); - for (unsigned int i = 0; i < children->getLength(); i++) { - if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE) - continue; - const DOMElement* childElem = dynamic_cast(children->item(i)); - + for (auto childElem = node->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) { // std::cerr << TAGNAME(childs.item(i)) << std::endl; if(iequals(TAGNAME(childElem), tagName)) { filteredChildElems.push_back((DOMElement*)childElem); @@ -391,12 +379,11 @@ std::list DOMUtils::filterChildType(const DOMNode::NodeType type, if (!node) return filteredChildTypes; - DOMNodeList* children = node->getChildNodes(); - for (unsigned int i = 0; i < children->getLength(); i++) { - if (children->item(i)->getNodeType() == type) - filteredChildTypes.push_back(children->item(i)); + for (auto child = node->getFirstChild(); child; child = child->getNextSibling()) { + if (child->getNodeType() == type) + filteredChildTypes.push_back(child); if (recurse) { - std::list nested = filterChildType(type, children->item(i), recurse); + std::list nested = filterChildType(type, child, recurse); filteredChildTypes.merge(nested); } diff --git a/src/uscxml/util/DOM.h b/src/uscxml/util/DOM.h index f259ea0..3ab27a3 100644 --- a/src/uscxml/util/DOM.h +++ b/src/uscxml/util/DOM.h @@ -117,17 +117,18 @@ protected: // create a prefix from a given element - useful for copying namespace information #define XML_PREFIX(element) X(element->getPrefix() ? X(element->getPrefix()).str() + ":" : "") +#if 1 class USCXML_API X { public : X(X const &other) { _localForm = other._localForm; - _otherForm = XERCESC_NS::XMLString::replicate(other._otherForm); + _unicodeForm = XERCESC_NS::XMLString::replicate(other._unicodeForm); _deallocOther = true; } void operator=(X const &other) { // did we maybe leak before? _localForm = other._localForm; - _otherForm = XERCESC_NS::XMLString::replicate(other._otherForm); + _unicodeForm = XERCESC_NS::XMLString::replicate(other._unicodeForm); _deallocOther = true; } @@ -138,39 +139,39 @@ public : _localForm = std::string(tmp); XERCESC_NS::XMLString::release(&tmp); } - _otherForm = NULL; + _unicodeForm = NULL; _deallocOther = false; } X(const std::string& fromTranscode) { // Call the private transcoding method _localForm = fromTranscode; - _otherForm = XERCESC_NS::XMLString::transcode(fromTranscode.c_str()); + _unicodeForm = XERCESC_NS::XMLString::transcode(fromTranscode.c_str()); _deallocOther = true; } X(const char* const fromTranscode) { // Call the private transcoding method _localForm = fromTranscode; - _otherForm = XERCESC_NS::XMLString::transcode(fromTranscode); + _unicodeForm = XERCESC_NS::XMLString::transcode(fromTranscode); _deallocOther = true; } X(char* fromTranscode) { // Call the private transcoding method _localForm = fromTranscode; - _otherForm = XERCESC_NS::XMLString::transcode(fromTranscode); + _unicodeForm = XERCESC_NS::XMLString::transcode(fromTranscode); _deallocOther = true; } X() { - _otherForm = NULL; + _unicodeForm = NULL; _deallocOther = false; } ~X() { if (_deallocOther) - XERCESC_NS::XMLString::release(&_otherForm); + XERCESC_NS::XMLString::release(&_unicodeForm); } const std::string& str() const { @@ -178,8 +179,8 @@ public : } operator const XMLCh* () { - assert(_otherForm != NULL); // constructor with XMLCh - return _otherForm; + assert(_unicodeForm != NULL); // constructor with XMLCh + return _unicodeForm; } operator bool () { @@ -196,9 +197,82 @@ protected: private: bool _deallocOther; std::string _localForm; - XMLCh* _otherForm; + XMLCh* _unicodeForm; }; + +#else +class USCXML_API X { +public : + X() { + } + + void operator=(X const &other) { + localForm = other.localForm; + if (unicodeForm != NULL) { + XERCESC_NS::XMLString::release(&unicodeForm); + } + unicodeForm = XERCESC_NS::XMLString::replicate(other.unicodeForm); + } + + X(X const &other) { + localForm = other.localForm; + unicodeForm = XERCESC_NS::XMLString::replicate(other.unicodeForm); + } + + X(const char* const toTranscode) { + if (toTranscode != NULL) { + localForm = toTranscode; + unicodeForm = XERCESC_NS::XMLString::transcode(toTranscode); + } + } + + X(const XMLCh* toTranscode) { + if (toTranscode != NULL) { + unicodeForm = XERCESC_NS::XMLString::replicate(toTranscode); + localForm = XERCESC_NS::XMLString::transcode(toTranscode); + } + } + + X(const std::string& toTranscode) { + localForm = toTranscode; + unicodeForm = XERCESC_NS::XMLString::transcode(toTranscode.c_str()); + } + + ~X() { + if (unicodeForm != NULL) { + XERCESC_NS::XMLString::release(&unicodeForm); + } + } + + operator XMLCh* () const { + return unicodeForm; + } + + operator const std::string& () { + return localForm; + } + + const std::string& str() const { + return localForm; + } + + const XMLCh* unicode() const { + return unicodeForm; + } + + +protected: + friend USCXML_API std::ostream& operator<< (std::ostream& os, const X& data); + +private: + XMLCh* unicodeForm = NULL; + std::string localForm; + +}; + +#endif + USCXML_API std::ostream& operator<< (std::ostream& os, const X& xmlString); USCXML_API std::ostream& operator<< (std::ostream& os, const XERCESC_NS::DOMNode& node); diff --git a/src/uscxml/util/Predicates.cpp b/src/uscxml/util/Predicates.cpp index 2f46d75..cd41089 100644 --- a/src/uscxml/util/Predicates.cpp +++ b/src/uscxml/util/Predicates.cpp @@ -27,11 +27,7 @@ using namespace XERCESC_NS; std::list getChildStates(const DOMElement* state, bool properOnly) { std::list children; - DOMNodeList* childElems = state->getChildNodes(); - for (size_t i = 0; i < childElems->getLength(); i++) { - if (childElems->item(i)->getNodeType() != DOMNode::ELEMENT_NODE) - continue; - DOMElement* childElem = dynamic_cast(childElems->item(i)); + for (auto childElem = state->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) { if (isState(childElem, properOnly)) { children.push_back(childElem); } @@ -74,17 +70,23 @@ DOMElement* getSourceState(const DOMElement* transition) { #define VERBOSE_FIND_LCCA 0 DOMElement* findLCCA(const std::list& states) { - + std::list ancestors = getProperAncestors(states.front(), NULL); DOMElement* ancestor = NULL; +#if VERBOSE_FIND_LCCA + std::cout << "states: " << states.size() << std::endl; + std::cout << "front: " << DOMUtils::xPathForNode(states.front()) << std::endl; + std::cout << "ancestors: " << ancestors.size() << std::endl; +#endif + for (auto ancIter = ancestors.begin(); ancIter != ancestors.end(); ancIter++) { if (!isCompound(dynamic_cast(*ancIter))) continue; for (auto stateIter = states.begin(); stateIter != states.end(); stateIter++) { #if VERBOSE_FIND_LCCA - std::cerr << "Checking " << ATTR_CAST(states[j], "id") << " and " << ATTR_CAST(ancestors[i], "id") << std::endl; + std::cerr << "Checking " << ATTR_CAST(*stateIter, "id") << " and " << ATTR_CAST(*ancIter, "id") << std::endl; #endif if (!DOMUtils::isDescendant(*stateIter, *ancIter)) @@ -97,11 +99,11 @@ NEXT_ANCESTOR: } // take uppermost root as ancestor - if (!ancestor) + if (!ancestor && ancestors.size() > 0) ancestor = ancestors.back(); #if VERBOSE_FIND_LCCA - std::cerr << " -> " << ATTR_CAST(ancestor, "id") << " " << ancestor.getLocalName() << std::endl; + std::cerr << " -> " << ATTR_CAST(ancestor, "id") << " " << ancestor->getLocalName() << std::endl; #endif return ancestor; } @@ -118,7 +120,9 @@ NEXT_ANCESTOR: std::list getProperAncestors(const DOMElement* s1, const DOMElement* s2) { std::list ancestors; - if (isState(s1)) { + if (isState(s1, false)) { + // is it correct to also consider pseudo-states? + // gcc bug in findLCCA with test387, test388, test579, test580 otherwise DOMNode* node = (DOMNode*)s1; while((node = node->getParentNode())) { if (node->getNodeType() != DOMNode::ELEMENT_NODE) @@ -127,9 +131,10 @@ std::list getProperAncestors(const DOMElement* s1, const DOMElement const DOMElement* nodeElem = dynamic_cast(node); if (!isState(nodeElem)) break; + if (!iequals(LOCALNAME(nodeElem), "parallel") && - !iequals(LOCALNAME(nodeElem), "state") && - !iequals(LOCALNAME(nodeElem), "scxml")) + !iequals(LOCALNAME(nodeElem), "state") && + !iequals(LOCALNAME(nodeElem), "scxml")) break; if (node == s2) break; @@ -143,10 +148,11 @@ std::list getExitSet(const DOMElement* transition, const DOMElement std::list statesToExit; if (HAS_ATTR(transition, "target")) { DOMElement* domain = getTransitionDomain(transition, root); - if (!domain) + if (domain == NULL) return statesToExit; - // std::cout << DOMUtils::xPathForNode(domain) << std::endl; +// std::cout << "transition: " << DOMUtils::xPathForNode(transition) << std::endl; +// std::cout << "domain: " << DOMUtils::xPathForNode(domain) << std::endl; std::set elements; elements.insert(XML_PREFIX(transition).str() + "parallel"); @@ -157,16 +163,20 @@ std::list getExitSet(const DOMElement* transition, const DOMElement if (statesToExit.front() == domain) { statesToExit.pop_front(); // do not include domain itself } +// std::cout << "OK" << std::endl; + } return statesToExit; } bool conflicts(const DOMElement* t1, const DOMElement* t2, const DOMElement* root) { - return (DOMUtils::hasIntersection(getExitSet(t1, root), getExitSet(t2, root)) || - (getSourceState(t1) == getSourceState(t2)) || + return ( + (getSourceState(t1) == getSourceState(t2)) || (DOMUtils::isDescendant(getSourceState(t1), getSourceState(t2))) || - (DOMUtils::isDescendant(getSourceState(t2), getSourceState(t1)))); + (DOMUtils::isDescendant(getSourceState(t2), getSourceState(t1))) || + (DOMUtils::hasIntersection(getExitSet(t1, root), getExitSet(t2, root))) + ); } bool isState(const DOMElement* state, bool properOnly) { @@ -280,6 +290,7 @@ DOMElement* getTransitionDomain(const DOMElement* transition, const DOMElement* BREAK_LOOP: tStates.push_front(source); + return findLCCA(tStates); } @@ -359,11 +370,7 @@ std::list getInitialStates(const DOMElement* state, const DOMElemen // first child state std::list initStates; - DOMNodeList* children = state->getChildNodes(); - for (size_t i = 0; i < children->getLength(); i++) { - if (children->item(i)->getNodeType() != DOMNode::ELEMENT_NODE) - continue; - DOMElement* childElem = dynamic_cast(children->item(i)); + for (auto childElem = state->getFirstElementChild(); childElem; childElem = childElem->getNextElementSibling()) { if (isState(childElem)) { initStates.push_back(childElem); return initStates; diff --git a/src/uscxml/util/URL.cpp b/src/uscxml/util/URL.cpp index a76c772..2e98fce 100644 --- a/src/uscxml/util/URL.cpp +++ b/src/uscxml/util/URL.cpp @@ -118,6 +118,8 @@ URLImpl::URLImpl(const std::string& url) : _orig(url), _handle(NULL), _isDownloa URLImpl::~URLImpl() { uriFreeUriMembersA(&_uri); + if (_handle != NULL) + curl_easy_cleanup(_handle); } URL URLImpl::resolve(URLImpl* relative, URLImpl* absolute) { @@ -590,7 +592,7 @@ void URLFetcher::fetchURL(URL& url) { 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); - + free(header); // curl_free(key); // curl_free(value); paramIter++; @@ -598,11 +600,12 @@ void URLFetcher::fetchURL(URL& url) { // Disable "Expect: 100-continue" headers = curl_slist_append(headers, "Expect:"); + instance->_handlesToHeaders[handle] = headers; - (curlError = curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers)) == CURLE_OK || + (curlError = curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers)) == CURLE_OK || LOG(ERROR) << "Cannot headers for " << std::string(url) << ": " << curl_easy_strerror(curlError); - //curl_slist_free_all(headers); +// curl_slist_free_all(headers); } else if (url._impl->_requestType == URLRequestType::GET) { @@ -629,6 +632,10 @@ void URLFetcher::breakURL(URL& url) { curl_multi_remove_handle(instance->_multiHandle, handle); instance->_handlesToURLs.erase(handle); } + if (instance->_handlesToHeaders.find(handle) != instance->_handlesToHeaders.end()) { + curl_slist_free_all(instance->_handlesToHeaders[handle]); + instance->_handlesToHeaders.erase(handle); + } } void URLFetcher::start() { @@ -745,7 +752,6 @@ void URLFetcher::perform() { LOG(WARNING) << "curl_multi_remove_handle: " << curl_multi_strerror(err); } - _handlesToURLs.erase(msg->easy_handle); break; default: _handlesToURLs[msg->easy_handle]._impl->downloadFailed(msg->data.result); @@ -753,9 +759,13 @@ void URLFetcher::perform() { if (err != CURLM_OK) { LOG(WARNING) << "curl_multi_remove_handle: " << curl_multi_strerror(err); } + break; - _handlesToURLs.erase(msg->easy_handle); } + _handlesToURLs.erase(msg->easy_handle); + curl_slist_free_all(_handlesToHeaders[msg->easy_handle]); + _handlesToHeaders.erase(msg->easy_handle); + } else { LOG(ERROR) << "Curl reports info on unfinished download?!"; } diff --git a/src/uscxml/util/URL.h b/src/uscxml/util/URL.h index 8127892..2b5c9e0 100644 --- a/src/uscxml/util/URL.h +++ b/src/uscxml/util/URL.h @@ -165,7 +165,7 @@ protected: static void prepareException(ErrorEvent& exception, int errorCode, const std::string& origUri, UriParserStateA* parser); - CURL* _handle; + CURL* _handle = NULL; std::stringstream _rawInContent; std::stringstream _rawInHeader; std::map _inHeaders; @@ -176,8 +176,8 @@ protected: std::string _statusCode; std::string _statusMsg; - bool _isDownloaded; - bool _hasFailed; + bool _isDownloaded = false; + bool _hasFailed = false; std::string _error; std::condition_variable_any _condVar; @@ -325,6 +325,7 @@ protected: bool _isStarted; std::map _handlesToURLs; + std::map _handlesToHeaders; CURLM* _multiHandle; char* _envProxy; }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2288e31..5ef92c6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -4,6 +4,7 @@ set(TEST_BENCHMARK_ITERATIONS 1000) find_program(SPIN spin) find_program(CC gcc) find_program(CXX g++) +find_program(ANT_EXECUTABLE ant) function(USCXML_TEST_COMPILE) set(options BUILD_ONLY) @@ -27,6 +28,7 @@ USCXML_TEST_COMPILE(NAME test-url LABEL general/test-url FILES src/test-url.cpp) USCXML_TEST_COMPILE(NAME test-lifecycle LABEL general/test-lifecycle FILES src/test-lifecycle.cpp) USCXML_TEST_COMPILE(NAME test-validating LABEL general/test-validating FILES src/test-validating.cpp) USCXML_TEST_COMPILE(NAME test-snippets LABEL general/test-snippets FILES src/test-snippets.cpp) +USCXML_TEST_COMPILE(NAME test-stress LABEL general/test-stress FILES src/test-stress.cpp) file(GLOB_RECURSE USCXML_WRAPPERS ${PROJECT_SOURCE_DIR}/src/bindings/swig/wrapped/*.cpp @@ -122,6 +124,9 @@ if (NOT BUILD_MINIMAL) # "gen/c/promela" # "gen/vhdl/ecma" + # bindings + "binding/java/jexl" + # state-machine interpreters # "fsm/ecma" # "fsm/xpath" @@ -224,6 +229,18 @@ if (NOT BUILD_MINIMAL) endif() + elseif (TEST_TYPE MATCHES "^binding.*") + get_filename_component(TEST_LANG ${TEST_TYPE} NAME) + + add_test(NAME "${TEST_NAME}" + COMMAND + ${ANT_EXECUTABLE} + -Dtest.file=${W3C_TEST} + -Duscxml.jar=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/uscxml.jar + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bindings/java + ) + set_tests_properties("${TEST_NAME}" PROPERTIES DEPENDS jar) + elseif (TEST_TYPE MATCHES "^spin.*") if (NOT ${TEST_DATAMODEL} STREQUAL "promela") diff --git a/test/bindings/java/build.properties b/test/bindings/java/build.properties new file mode 100644 index 0000000..dd0fe62 --- /dev/null +++ b/test/bindings/java/build.properties @@ -0,0 +1,9 @@ +# Default path on Windows (maybe with an '(x86)' in there for good measure) +#umundo.jar=C:\\Program Files\\uMundo\\share\\umundo\\lib\\umundo.jar + +# Default path on MacOSX and Linux +uscxml.library.path=/usr/local/share/uscxml/bindings/java +uscxml.jar=/usr/local/share/uscxml/bindings/uscxml.jar + +jexl.jar=libs/commons-jexl3-3.0.jar +logging.jar=libs/commons-logging-1.2.jar \ No newline at end of file diff --git a/test/bindings/java/build.xml b/test/bindings/java/build.xml new file mode 100644 index 0000000..2f1f362 --- /dev/null +++ b/test/bindings/java/build.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/bindings/java/libs/commons-jexl3-3.0.jar b/test/bindings/java/libs/commons-jexl3-3.0.jar new file mode 100644 index 0000000..94566bf Binary files /dev/null and b/test/bindings/java/libs/commons-jexl3-3.0.jar differ diff --git a/test/bindings/java/libs/commons-logging-1.2.jar b/test/bindings/java/libs/commons-logging-1.2.jar new file mode 100644 index 0000000..93a3b9f Binary files /dev/null and b/test/bindings/java/libs/commons-logging-1.2.jar differ diff --git a/test/bindings/java/org/uscxml/examples/BasicExample.java b/test/bindings/java/org/uscxml/examples/BasicExample.java new file mode 100644 index 0000000..129a116 --- /dev/null +++ b/test/bindings/java/org/uscxml/examples/BasicExample.java @@ -0,0 +1,46 @@ +package org.uscxml.examples; + +import org.uscxml.Interpreter; +import org.uscxml.InterpreterException; +import org.uscxml.InterpreterState; + +public class BasicExample { + + public static void main(String[] args) { + + String uSCXMLLibPath = "/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava.jnilib"; + if (System.getenv().containsKey("USCXML_JAVA_LIB")) { + uSCXMLLibPath = System.getenv("USCXML_JAVA_LIB"); + } + + System.load(uSCXMLLibPath); + + try { + Interpreter scxml = Interpreter.fromURL("https://raw.githubusercontent.com/tklab-tud/uscxml/master/test/w3c/null/test436.scxml"); + InterpreterState state = InterpreterState.USCXML_UNDEF; + while((state = scxml.step()) != InterpreterState.USCXML_FINISHED) { + switch (state) { + case USCXML_FINISHED: + case USCXML_UNDEF: + case USCXML_IDLE: + case USCXML_INITIALIZED: + case USCXML_INSTANTIATED: + case USCXML_MICROSTEPPED: + case USCXML_MACROSTEPPED: + case USCXML_CANCELLED: + break; + default: + break; + } + } + System.out.println("Machine finished"); + + } catch (InterpreterException e) { + e.printStackTrace(); + System.exit(-1); + } + System.exit(0); + + } + +} diff --git a/test/bindings/java/org/uscxml/examples/DataModelExample.java b/test/bindings/java/org/uscxml/examples/DataModelExample.java new file mode 100644 index 0000000..e6ad619 --- /dev/null +++ b/test/bindings/java/org/uscxml/examples/DataModelExample.java @@ -0,0 +1,60 @@ +package org.uscxml.examples; + +import java.io.File; +import java.net.MalformedURLException; + +import org.uscxml.Factory; +import org.uscxml.Interpreter; +import org.uscxml.InterpreterException; +import org.uscxml.InterpreterState; +import org.uscxml.dm.jexl.JEXLDataModel; +import org.uscxml.helper.TestMonitor; + +public class DataModelExample { + + public static void main(String[] args) { + String uSCXMLLibPath = "/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava.jnilib"; + if (System.getenv().containsKey("USCXML_JAVA_LIB")) { + uSCXMLLibPath = System.getenv("USCXML_JAVA_LIB"); + } + + System.load(uSCXMLLibPath); + + JEXLDataModel jdm = new JEXLDataModel(); + Factory.getInstance().registerDataModel(jdm);; + + TestMonitor tm = new TestMonitor(); + + File folder = new File("/Users/sradomski/Documents/TK/Code/uscxml/test/w3c/jexl"); + File[] listOfFiles = folder.listFiles(); + + try { + for (File file : listOfFiles) { + if (!file.getName().endsWith(".scxml")) + continue; + String testName = file.toURI().toURL().toString(); + System.out.println(testName); + + Interpreter scxml = Interpreter.fromURL(testName); +// scxml.setMonitor(tm); + + while(scxml.step() != InterpreterState.USCXML_FINISHED) {} + + if (!scxml.isInState("pass")) { + System.out.println("FAIL: " + testName); + + throw new RuntimeException(); + } + System.out.println("SUCCESS"); + + } + + } catch (InterpreterException | MalformedURLException e) { + e.printStackTrace(); + System.exit(-1); + } + System.exit(0); + + } + +} diff --git a/test/bindings/java/org/uscxml/examples/MonitorExample.java b/test/bindings/java/org/uscxml/examples/MonitorExample.java new file mode 100644 index 0000000..3e3781c --- /dev/null +++ b/test/bindings/java/org/uscxml/examples/MonitorExample.java @@ -0,0 +1,48 @@ +package org.uscxml.examples; + +import org.uscxml.Interpreter; +import org.uscxml.InterpreterException; +import org.uscxml.InterpreterState; +import org.uscxml.helper.TestMonitor; + + +public class MonitorExample { + + public static void main(String[] args) { + + String uSCXMLLibPath = "/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava.jnilib"; + if (System.getenv().containsKey("USCXML_JAVA_LIB")) { + uSCXMLLibPath = System.getenv("USCXML_JAVA_LIB"); + } + + System.load(uSCXMLLibPath); + + try { + TestMonitor tm = new TestMonitor(); + Interpreter scxml = Interpreter.fromURL("https://raw.githubusercontent.com/tklab-tud/uscxml/master/test/w3c/null/test436.scxml"); + scxml.setMonitor(tm); + InterpreterState state = InterpreterState.USCXML_UNDEF; + while((state = scxml.step()) != InterpreterState.USCXML_FINISHED) { + switch (state) { + case USCXML_FINISHED: + case USCXML_UNDEF: + case USCXML_IDLE: + case USCXML_INITIALIZED: + case USCXML_INSTANTIATED: + case USCXML_MICROSTEPPED: + case USCXML_MACROSTEPPED: + case USCXML_CANCELLED: + break; + default: + break; + } + } + + } catch (InterpreterException e) { + e.printStackTrace(); + System.exit(-1); + } + System.exit(0); + } + +} diff --git a/test/bindings/java/org/uscxml/helper/TestMonitor.java b/test/bindings/java/org/uscxml/helper/TestMonitor.java new file mode 100644 index 0000000..f8289bd --- /dev/null +++ b/test/bindings/java/org/uscxml/helper/TestMonitor.java @@ -0,0 +1,76 @@ +package org.uscxml.helper; + +import org.uscxml.InterpreterIssue; +import org.uscxml.InterpreterMonitor; +import org.uscxml.StringList; + +public class TestMonitor extends InterpreterMonitor { + + public TestMonitor() {} + + @Override + public void beforeExitingState(String stateId, String xpath, String stateXML) { + System.out.println("beforeExitingState: " + stateId + " " + xpath); + } + + @Override + public void afterExitingState(String stateId, String xpath, String stateXML) { + System.out.println("afterExitingState: " + stateId + " " + xpath); + } + + @Override + public void beforeExecutingContent(String tagName, String xpath, String contentXML) { + System.out.println("afterExecutingContent: " + tagName + " " + xpath); + } + + @Override + public void afterExecutingContent(String tagName, String xpath, String contentXML) { + System.out.println("afterExecutingContent: " + tagName + " " + xpath); + } + + @Override + public void beforeUninvoking(String xpath, String invokeid, String invokerXML) { + System.out.println("beforeUninvoking: " + xpath + " " + invokeid); + } + + @Override + public void afterUninvoking(String xpath, String invokeid, String invokerXML) { + System.out.println("beforeUninvoking: " + xpath + " " + invokeid); + } + + @Override + public void beforeTakingTransition(String xpath, String source, StringList targets, String transitionXML) { + System.out.println("beforeTakingTransition: " + xpath + " " + source + " " + targets); + } + + @Override + public void afterTakingTransition(String xpath, String source, StringList targets, String transitionXML) { + System.out.println("afterTakingTransition: " + xpath + " " + source + " " + targets); + } + + @Override + public void beforeEnteringState(String stateId, String xpath, String stateXML) { + System.out.println("beforeEnteringState: " + stateId + " " + xpath); + } + + @Override + public void afterEnteringState(String stateId, String xpath, String stateXML) { + System.out.println("afterEnteringState: " + stateId + " " + xpath); + } + + @Override + public void beforeInvoking(String xpath, String invokeid, String invokerXML) { + System.out.println("beforeInvoking: " + xpath + " " + invokeid); + } + + @Override + public void afterInvoking(String xpath, String invokeid, String invokerXML) { + System.out.println("afterInvoking: " + xpath + " " + invokeid); + } + + @Override + public void reportIssue(InterpreterIssue issue) { + System.out.println(issue); + } + +} diff --git a/test/bindings/java/org/uscxml/tests/BasicExample.java b/test/bindings/java/org/uscxml/tests/BasicExample.java deleted file mode 100644 index 32899e5..0000000 --- a/test/bindings/java/org/uscxml/tests/BasicExample.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.uscxml.tests; - -import org.uscxml.Interpreter; -import org.uscxml.InterpreterException; -import org.uscxml.InterpreterState; - -public class BasicExample { - - public static void main(String[] args) { - - String uSCXMLLibPath = "/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava.jnilib"; - if (System.getenv().containsKey("USCXML_JAVA_LIB")) { - uSCXMLLibPath = System.getenv("USCXML_JAVA_LIB"); - } - - System.load(uSCXMLLibPath); - - try { - Interpreter scxml = Interpreter.fromURL("https://raw.githubusercontent.com/tklab-tud/uscxml/master/test/w3c/null/test436.scxml"); - InterpreterState state = InterpreterState.USCXML_UNDEF; - while((state = scxml.step()) != InterpreterState.USCXML_FINISHED) { - switch (state) { - case USCXML_FINISHED: - case USCXML_UNDEF: - case USCXML_IDLE: - case USCXML_INITIALIZED: - case USCXML_INSTANTIATED: - case USCXML_MICROSTEPPED: - case USCXML_MACROSTEPPED: - case USCXML_CANCELLED: - break; - default: - break; - } - } - System.out.println("Machine finished"); - - } catch (InterpreterException e) { - e.printStackTrace(); - } - } - -} diff --git a/test/bindings/java/org/uscxml/tests/DataModelExample.java b/test/bindings/java/org/uscxml/tests/DataModelExample.java deleted file mode 100644 index db46a18..0000000 --- a/test/bindings/java/org/uscxml/tests/DataModelExample.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.uscxml.tests; - -import java.io.File; -import java.net.MalformedURLException; - -import org.uscxml.Factory; -import org.uscxml.Interpreter; -import org.uscxml.InterpreterException; -import org.uscxml.InterpreterState; -import org.uscxml.dm.jexl.JEXLDataModel; -import org.uscxml.tests.helper.TestMonitor; - -public class DataModelExample { - - public static void main(String[] args) { - String uSCXMLLibPath = "/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava.jnilib"; - if (System.getenv().containsKey("USCXML_JAVA_LIB")) { - uSCXMLLibPath = System.getenv("USCXML_JAVA_LIB"); - } - - System.load(uSCXMLLibPath); - - JEXLDataModel jdm = new JEXLDataModel(); - Factory.getInstance().registerDataModel(jdm);; - - TestMonitor tm = new TestMonitor(); - - File folder = new File("/Users/sradomski/Documents/TK/Code/uscxml/test/w3c/jexl"); - File[] listOfFiles = folder.listFiles(); - - try { - for (File file : listOfFiles) { - if (!file.getName().endsWith(".scxml")) - continue; - String testName = file.toURI().toURL().toString(); - System.out.println(testName); - - Interpreter scxml = Interpreter.fromURL(testName); -// scxml.setMonitor(tm); - - while(scxml.step() != InterpreterState.USCXML_FINISHED) {} - - if (!scxml.isInState("pass")) { - System.out.println("FAIL: " + testName); - - throw new RuntimeException(); - } - System.out.println("SUCCESS"); - - } - - } catch (InterpreterException | MalformedURLException e) { - e.printStackTrace(); - } - - } - -} diff --git a/test/bindings/java/org/uscxml/tests/JexlDataModelTest.java b/test/bindings/java/org/uscxml/tests/JexlDataModelTest.java new file mode 100644 index 0000000..bb681b0 --- /dev/null +++ b/test/bindings/java/org/uscxml/tests/JexlDataModelTest.java @@ -0,0 +1,60 @@ +package org.uscxml.tests; + +import java.io.File; +import java.net.MalformedURLException; + +import org.uscxml.Factory; +import org.uscxml.Interpreter; +import org.uscxml.InterpreterException; +import org.uscxml.InterpreterState; +import org.uscxml.dm.jexl.JEXLDataModel; +import org.uscxml.helper.TestMonitor; + +public class JexlDataModelTest { + + public static void main(String[] args) { + String uSCXMLLibPath = "/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava.jnilib"; + if (System.getenv().containsKey("USCXML_JAVA_LIB")) { + uSCXMLLibPath = System.getenv("USCXML_JAVA_LIB"); + } + + System.load(uSCXMLLibPath); + String testUri = "/Users/sradomski/Documents/TK/Code/uscxml/test/w3c/jexl/test144.scxml"; + + if (args.length > 0) { + testUri = args[0]; + } + + { + JEXLDataModel jdm = new JEXLDataModel(); + Factory.getInstance().registerDataModel(jdm); + + TestMonitor tm = new TestMonitor(); + + try { + File testFile = new File(testUri); + String testName = testFile.toURI().toURL().toString(); + System.out.println(testName); + + Interpreter scxml = Interpreter.fromURL(testName); + scxml.setMonitor(tm); + + while (scxml.step() != InterpreterState.USCXML_FINISHED) { + } + + if (!scxml.isInState("pass")) { + System.out.println("FAIL: " + testName); + throw new RuntimeException(); + } + System.out.println("SUCCESS"); + + } catch (InterpreterException | MalformedURLException e) { + e.printStackTrace(); + System.exit(-1); + } + } + + System.exit(0); + } + +} diff --git a/test/bindings/java/org/uscxml/tests/MonitorExample.java b/test/bindings/java/org/uscxml/tests/MonitorExample.java deleted file mode 100644 index 2f0689a..0000000 --- a/test/bindings/java/org/uscxml/tests/MonitorExample.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.uscxml.tests; - -import org.uscxml.Interpreter; -import org.uscxml.InterpreterException; -import org.uscxml.InterpreterState; -import org.uscxml.tests.helper.TestMonitor; - - -public class MonitorExample { - - public static void main(String[] args) { - - String uSCXMLLibPath = "/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava.jnilib"; - if (System.getenv().containsKey("USCXML_JAVA_LIB")) { - uSCXMLLibPath = System.getenv("USCXML_JAVA_LIB"); - } - - System.load(uSCXMLLibPath); - - try { - TestMonitor tm = new TestMonitor(); - Interpreter scxml = Interpreter.fromURL("https://raw.githubusercontent.com/tklab-tud/uscxml/master/test/w3c/null/test436.scxml"); - scxml.setMonitor(tm); - InterpreterState state = InterpreterState.USCXML_UNDEF; - while((state = scxml.step()) != InterpreterState.USCXML_FINISHED) { - switch (state) { - case USCXML_FINISHED: - case USCXML_UNDEF: - case USCXML_IDLE: - case USCXML_INITIALIZED: - case USCXML_INSTANTIATED: - case USCXML_MICROSTEPPED: - case USCXML_MACROSTEPPED: - case USCXML_CANCELLED: - break; - default: - break; - } - } - - } catch (InterpreterException e) { - e.printStackTrace(); - } - } - -} diff --git a/test/bindings/java/org/uscxml/tests/helper/TestMonitor.java b/test/bindings/java/org/uscxml/tests/helper/TestMonitor.java deleted file mode 100644 index 9266847..0000000 --- a/test/bindings/java/org/uscxml/tests/helper/TestMonitor.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.uscxml.tests.helper; - -import org.uscxml.InterpreterIssue; -import org.uscxml.InterpreterMonitor; -import org.uscxml.StringList; - -public class TestMonitor extends InterpreterMonitor { - - public TestMonitor() {} - - @Override - public void beforeExitingState(String stateId, String xpath, String stateXML) { - System.out.println("beforeExitingState: " + stateId + " " + xpath + " " + stateXML); - } - - @Override - public void afterExitingState(String stateId, String xpath, String stateXML) { - System.out.println("afterExitingState: " + stateId + " " + xpath + " " + stateXML); - } - - @Override - public void beforeExecutingContent(String tagName, String xpath, String contentXML) { - System.out.println("afterExecutingContent: " + tagName + " " + xpath + " " + contentXML); - } - - @Override - public void afterExecutingContent(String tagName, String xpath, String contentXML) { - System.out.println("afterExecutingContent: " + tagName + " " + xpath + " " + contentXML); - } - - @Override - public void beforeUninvoking(String xpath, String invokeid, String invokerXML) { - System.out.println("beforeUninvoking: " + xpath + " " + invokeid + " " + invokerXML); - } - - @Override - public void afterUninvoking(String xpath, String invokeid, String invokerXML) { - System.out.println("beforeUninvoking: " + xpath + " " + invokeid + " " + invokerXML); - } - - @Override - public void beforeTakingTransition(String xpath, String source, StringList targets, String transitionXML) { - System.out.println("beforeTakingTransition: " + xpath + " " + source + " " + targets + " " + transitionXML); - } - - @Override - public void afterTakingTransition(String xpath, String source, StringList targets, String transitionXML) { - System.out.println("afterTakingTransition: " + xpath + " " + source + " " + targets + " " + transitionXML); - } - - @Override - public void beforeEnteringState(String stateId, String xpath, String stateXML) { - System.out.println("beforeEnteringState: " + stateId + " " + xpath + " " + stateXML); - } - - @Override - public void afterEnteringState(String stateId, String xpath, String stateXML) { - System.out.println("afterEnteringState: " + stateId + " " + xpath + " " + stateXML); - } - - @Override - public void beforeInvoking(String xpath, String invokeid, String invokerXML) { - System.out.println("beforeInvoking: " + xpath + " " + invokeid + " " + invokerXML); - } - - @Override - public void afterInvoking(String xpath, String invokeid, String invokerXML) { - System.out.println("afterInvoking: " + xpath + " " + invokeid + " " + invokerXML); - } - - @Override - public void reportIssue(InterpreterIssue issue) { - System.out.println(issue); - } - -} diff --git a/test/src/test-lifecycle.cpp b/test/src/test-lifecycle.cpp index df77e96..14ebd94 100644 --- a/test/src/test-lifecycle.cpp +++ b/test/src/test-lifecycle.cpp @@ -342,8 +342,8 @@ int main(int argc, char** argv) { assert(interpreter.step() == USCXML_INITIALIZED); assert(interpreter.step() == USCXML_MICROSTEPPED); assert(interpreter.step() == USCXML_MACROSTEPPED); - assert(interpreter.step() == USCXML_IDLE); - assert(interpreter.step(true) == USCXML_MICROSTEPPED); + assert(interpreter.step(0) == USCXML_IDLE); + assert(interpreter.step() == USCXML_MICROSTEPPED); assert(interpreter.step() == USCXML_MICROSTEPPED); assert(interpreter.step() == USCXML_FINISHED); } diff --git a/test/src/test-stress.cpp b/test/src/test-stress.cpp new file mode 100644 index 0000000..588e0f7 --- /dev/null +++ b/test/src/test-stress.cpp @@ -0,0 +1,109 @@ +#include "uscxml/config.h" +#include "uscxml/Interpreter.h" +//#include "uscxml/Factory.h" +#include "uscxml/server/HTTPServer.h" + +#include + +#include "uscxml/plugins/invoker/dirmon/DirMonInvoker.h" +#include + +#ifdef _WIN32 +#include "XGetopt.h" +#endif + +int startedAt; +int lastTransitionAt; + +class StatusMonitor : public uscxml::InterpreterMonitor { + void beforeTakingTransition(const XERCESC_NS::DOMElement* transition) { + lastTransitionAt = time(NULL); + } + +}; + +void printUsageAndExit() { + printf("test-stress version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n"); + printf("Usage\n"); + printf("\ttest-stress"); +#ifdef BUILD_AS_PLUGINS + printf(" [-p pluginPath]"); +#endif + printf(" \n"); + printf("\n"); + exit(1); +} + +int main(int argc, char** argv) { + using namespace uscxml; + + if (argc < 2) { + printUsageAndExit(); + } + + HTTPServer::getInstance(8188, 8189); +#ifndef _WIN32 + opterr = 0; +#endif + int option; + while ((option = getopt(argc, argv, "vl:p:")) != -1) { + switch(option) { + case 'p': + uscxml::Factory::setDefaultPluginPath(optarg); + break; + case '?': + break; + default: + printUsageAndExit(); + break; + } + } + + DirectoryWatch* watcher = new DirectoryWatch(argv[optind], true); + watcher->updateEntries(true); + + std::map entries = watcher->getAllEntries(); + + StatusMonitor vm; + + std::map::iterator entryIter = entries.begin(); + while(entryIter != entries.end()) { + if (!boost::ends_with(entryIter->first, ".scxml")) { + entryIter++; + continue; + } + + startedAt = time(NULL); + lastTransitionAt = time(NULL); + + Interpreter interpreter = Interpreter::fromURL(std::string(argv[optind]) + PATH_SEPERATOR + entryIter->first); +// Interpreter interpreter = Interpreter::fromURL("/Users/sradomski/Documents/TK/Code/uscxml/test/w3c/ecma/test422.scxml"); + LOG(INFO) << "Processing " << interpreter.getImpl()->getBaseURL(); + if (interpreter) { + + interpreter.setMonitor(&vm); + + InterpreterState state = InterpreterState::USCXML_UNDEF; + int now = time(NULL); + + try { + while(state != USCXML_FINISHED && now - startedAt < 20 && now - lastTransitionAt < 2) { +// while(state != USCXML_FINISHED) { + state = interpreter.step(200); + now = time(NULL); + } + } catch (...) {} + } + entryIter++; + + // forever + if (entryIter == entries.end()) { + entryIter = entries.begin(); + std::this_thread::sleep_for(std::chrono::seconds(10)); + } + } + + delete watcher; + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/test/w3c/compound/test-ecma-all.scxml b/test/w3c/compound/test-ecma-all.scxml deleted file mode 100644 index ec5a3de..0000000 --- a/test/w3c/compound/test-ecma-all.scxml +++ /dev/null @@ -1,5841 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [1,2,3] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [1,2,3] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [1,2,3] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [1,2,3] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [1,2,3] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 123 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 123 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - foo - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - this is some content - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [1,2,3] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 21 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - some content - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [1,2,3] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - this is a - string - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { "productName" : "bar", "size" : 27 } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/w3c/compound/test-ecma-all.scxml.foo b/test/w3c/compound/test-ecma-all.scxml.foo new file mode 100644 index 0000000..ec5a3de --- /dev/null +++ b/test/w3c/compound/test-ecma-all.scxml.foo @@ -0,0 +1,5841 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [1,2,3] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [1,2,3] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [1,2,3] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [1,2,3] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [1,2,3] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 123 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 123 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + foo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + this is some content + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [1,2,3] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 21 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + some content + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [1,2,3] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + this is a + string + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { "productName" : "bar", "size" : 27 } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v0.12