summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--CMakeLists.txt109
-rw-r--r--contrib/cmake/FindArabica.cmake21
-rw-r--r--contrib/cmake/FindEV.cmake20
-rw-r--r--contrib/cmake/FindEVENT.cmake34
-rw-r--r--contrib/cmake/FindGLOG.cmake20
-rw-r--r--contrib/cmake/FindICONV.cmake57
-rw-r--r--contrib/cmake/FindPION.cmake20
-rw-r--r--contrib/cmake/FindV8.cmake28
-rw-r--r--src/bindings/CMakeLists.txt12
-rw-r--r--src/bindings/swig/java/CMakeLists.txt31
-rw-r--r--src/bindings/swig/java/uscxml.i40
-rw-r--r--src/uscxml.h6
-rw-r--r--src/uscxml/Factory.cpp56
-rw-r--r--src/uscxml/Factory.h73
-rw-r--r--src/uscxml/Interpreter.cpp1712
-rw-r--r--src/uscxml/Interpreter.h314
-rw-r--r--src/uscxml/Message.cpp168
-rw-r--r--src/uscxml/Message.h122
-rw-r--r--src/uscxml/concurrency/BlockingQueue.h41
-rw-r--r--src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.cpp57
-rw-r--r--src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.h45
-rw-r--r--src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp87
-rw-r--r--src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h52
-rw-r--r--src/uscxml/concurrency/tinythread.cpp303
-rw-r--r--src/uscxml/concurrency/tinythread.h714
-rw-r--r--src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp289
-rw-r--r--src/uscxml/datamodel/ecmascript/v8/V8DataModel.h73
-rw-r--r--src/uscxml/ioprocessor/basichttp/README.md2
-rw-r--r--src/uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.cpp361
-rw-r--r--src/uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.h96
-rw-r--r--src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.cpp3
-rw-r--r--src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.h15
-rw-r--r--src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.cpp74
-rw-r--r--src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.h47
-rw-r--r--test/CMakeLists.txt29
-rw-r--r--test/samples/apache/actions-initial-test.xml57
-rw-r--r--test/samples/apache/actions-parallel-test.xml55
-rw-r--r--test/samples/apache/actions-state-test.xml52
-rw-r--r--test/samples/apache/assign-test-01.xml70
-rw-r--r--test/samples/apache/assign-test-02.xml46
-rw-r--r--test/samples/apache/bar.xml25
-rw-r--r--test/samples/apache/custom-hello-world-01.xml37
-rw-r--r--test/samples/apache/custom-hello-world-02.xml33
-rw-r--r--test/samples/apache/custom-hello-world-03.xml33
-rw-r--r--test/samples/apache/custom-hello-world-04-el.xml44
-rw-r--r--test/samples/apache/custom-hello-world-04-jexl.xml62
-rw-r--r--test/samples/apache/datamodel-01.xml107
-rw-r--r--test/samples/apache/datamodel-02.xml83
-rw-r--r--test/samples/apache/datamodel-03.xml259
-rw-r--r--test/samples/apache/datamodel-04.xml48
-rw-r--r--test/samples/apache/edit-profile-config.xml149
-rw-r--r--test/samples/apache/eventdata-01.xml47
-rw-r--r--test/samples/apache/eventdata-02.xml39
-rw-r--r--test/samples/apache/eventdata-03.xml49
-rw-r--r--test/samples/apache/eventdata-04.xml57
-rw-r--r--test/samples/apache/external-hello-world.xml33
-rw-r--r--test/samples/apache/foo.xml25
-rw-r--r--test/samples/apache/hello-world.xml31
-rw-r--r--test/samples/apache/history-deep-01.xml75
-rw-r--r--test/samples/apache/history-default-01.xml90
-rw-r--r--test/samples/apache/history-shallow-01.xml67
-rw-r--r--test/samples/apache/invoked-01.xml32
-rw-r--r--test/samples/apache/invoked-02.xml32
-rw-r--r--test/samples/apache/invoked-03-01.xml33
-rw-r--r--test/samples/apache/invoked-03.xml37
-rw-r--r--test/samples/apache/invoker-01.xml38
-rw-r--r--test/samples/apache/invoker-02.xml29
-rw-r--r--test/samples/apache/invoker-03.xml39
-rw-r--r--test/samples/apache/invoker-04.xml55
-rw-r--r--test/samples/apache/issue62-01-ext.xml27
-rw-r--r--test/samples/apache/issue62-01.xml29
-rw-r--r--test/samples/apache/issue62-02-ext.xml39
-rw-r--r--test/samples/apache/issue62-02.xml35
-rw-r--r--test/samples/apache/issue62-03-ext.xml39
-rw-r--r--test/samples/apache/issue62-03.xml35
-rw-r--r--test/samples/apache/issue64-01.xml39
-rw-r--r--test/samples/apache/issue64-02.xml55
-rw-r--r--test/samples/apache/jsp-rootctx-test.xml31
-rw-r--r--test/samples/apache/log-on-config.xml81
-rw-r--r--test/samples/apache/microwave-01.xml78
-rw-r--r--test/samples/apache/microwave-02-legacy.xml87
-rw-r--r--test/samples/apache/microwave-02.xml87
-rw-r--r--test/samples/apache/microwave-03.xml79
-rw-r--r--test/samples/apache/microwave-04.xml90
-rw-r--r--test/samples/apache/microwave-05.xml98
-rw-r--r--test/samples/apache/parallel-01.xml70
-rw-r--r--test/samples/apache/parallel-02.xml31
-rw-r--r--test/samples/apache/parallel-03.xml118
-rw-r--r--test/samples/apache/prefix-01.xml29
-rw-r--r--test/samples/apache/scxml-initial-attr.xml25
-rw-r--r--test/samples/apache/send-01.xml47
-rw-r--r--test/samples/apache/send-02.xml89
-rw-r--r--test/samples/apache/src-test-1.xml31
-rw-r--r--test/samples/apache/src-test-2.xml30
-rw-r--r--test/samples/apache/src-test-3.xml28
-rw-r--r--test/samples/apache/src-test-4.xml30
-rw-r--r--test/samples/apache/src-test-5.xml30
-rw-r--r--test/samples/apache/state-01.xml24
-rw-r--r--test/samples/apache/stateless-01.xml50
-rw-r--r--test/samples/apache/stateless-parallel-01.xml54
-rw-r--r--test/samples/apache/static-method.xml32
-rw-r--r--test/samples/apache/stopwatch.xml41
-rw-r--r--test/samples/apache/tie-breaker-01.xml35
-rw-r--r--test/samples/apache/tie-breaker-02.xml45
-rw-r--r--test/samples/apache/tie-breaker-03.xml56
-rw-r--r--test/samples/apache/tie-breaker-04.xml36
-rw-r--r--test/samples/apache/tie-breaker-05.xml64
-rw-r--r--test/samples/apache/tie-breaker-06.xml40
-rw-r--r--test/samples/apache/transitions-01-legacy.xml140
-rw-r--r--test/samples/apache/transitions-01.xml136
-rw-r--r--test/samples/apache/transitions-02.xml53
-rw-r--r--test/samples/apache/transitions-03.xml88
-rw-r--r--test/samples/apache/transitions-04.xml93
-rw-r--r--test/samples/apache/transitions-05.xml38
-rw-r--r--test/samples/apache/travel-dialog.xml54
-rw-r--r--test/samples/apache/wildcard-01.xml35
-rw-r--r--test/samples/apache/wildcard-02.xml32
-rw-r--r--test/samples/apache/wizard-01.xml41
-rw-r--r--test/samples/apache/wizard-02.xml65
-rw-r--r--test/samples/w3c/Blackjack.scxml99
-rw-r--r--test/samples/w3c/Main.scxml204
-rw-r--r--test/samples/w3c/Test2Sub1.xml9
-rw-r--r--test/samples/w3c/TrafficReport.scxml88
-rw-r--r--test/samples/w3c/calc.scxml158
-rw-r--r--test/samples/w3c/edit-profile-config.scxml70
-rw-r--r--test/samples/w3c/log-on-config.scxml32
-rw-r--r--test/samples/w3c/microwave-01.scxml50
-rw-r--r--test/samples/w3c/microwave-02.scxml63
-rw-r--r--test/samples/w3c/simple.xml9
-rw-r--r--test/schema/scxml-message.xsd122
-rw-r--r--test/schema/scxml.xsd176
-rw-r--r--test/src/test-apache-commons.cpp128
-rw-r--r--test/src/test-communication.cpp26
-rw-r--r--test/src/test-communication.scxml35
-rw-r--r--test/src/test-ecmascript-v8.cpp44
-rw-r--r--test/src/test-ecmascript.scxml112
-rw-r--r--test/src/test-eventdelay.cpp39
-rw-r--r--test/src/test-execution.cpp16
-rw-r--r--test/src/test-execution.scxml56
-rw-r--r--test/src/test-predicates.cpp60
-rw-r--r--test/src/test-predicates.scxml9
142 files changed, 11445 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f77e4ba
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+
+*.DS_Store
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..c462751
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,109 @@
+cmake_minimum_required(VERSION 2.8.4)
+
+project(uscxml)
+
+set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/contrib/cmake)
+
+set(USCXML_LIBS)
+set(USCXML_FILES)
+
+# libxml2
+find_package(LibXml2 REQUIRED)
+include_directories(${LIBXML2_INCLUDE_DIR})
+list (APPEND USCXML_LIBS ${LIBXML2_LIBRARIES})
+
+# prefer rest as static libraries
+set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+
+#glog
+set(ENV{GLOG_SRC} ${CMAKE_SOURCE_DIR}/../glog)
+find_package(GLOG REQUIRED)
+include_directories(${GLOG_INCLUDE_DIR})
+list (APPEND USCXML_LIBS ${GLOG_LIBRARY})
+
+# arabica
+find_package(Arabica REQUIRED)
+include_directories(${ARABICA_INCLUDE_DIR})
+list (APPEND USCXML_LIBS ${ARABICA_LIBRARY})
+
+# boost - header only
+FIND_PATH(Boost_INCLUDE_DIR boost/version.hpp PATHS /usr/include)
+include_directories(${Boost_INCLUDE_DIR})
+
+#event
+set(ENV{EVENT_SRC} ${CMAKE_SOURCE_DIR}/../libevent)
+find_package(EVENT REQUIRED)
+include_directories(${EVENT_INCLUDE_DIR})
+file(GLOB_RECURSE USCXML_IO_PROCESSOR_LIBEVENT
+ src/uscxml/ioprocessor/basichttp/libevent/*.cpp
+ src/uscxml/ioprocessor/basichttp/libevent/*.h
+)
+list (APPEND USCXML_FILES ${USCXML_IO_PROCESSOR_LIBEVENT})
+
+file(GLOB_RECURSE USCXML_EVENTQUEUE_LIBEVENT
+ src/uscxml/concurrency/eventqueue/libevent/*.cpp
+ src/uscxml/concurrency/eventqueue/libevent/*.h
+)
+list (APPEND USCXML_FILES ${USCXML_EVENTQUEUE_LIBEVENT})
+
+list (APPEND USCXML_LIBS ${EVENT_LIBRARY})
+
+# v8
+set(ENV{V8_SRC} ${CMAKE_SOURCE_DIR}/../v8)
+find_package(V8 REQUIRED)
+include_directories(${V8_INCLUDE_DIR})
+file(GLOB_RECURSE USCXML_DATAMODEL_V8
+ src/uscxml/datamodel/ecmascript/v8/*.cpp
+ src/uscxml/datamodel/ecmascript/v8/*.h
+)
+list (APPEND USCXML_FILES ${USCXML_DATAMODEL_V8})
+list (APPEND USCXML_LIBS ${V8_LIBRARY})
+
+
+file(GLOB USCXML_CONCURRENCY src/uscxml/concurrency/*.cpp src/uscxml/concurrency/*.h)
+list (APPEND USCXML_FILES ${USCXML_CONCURRENCY})
+
+file(GLOB USCXML_INTERPRETER src/uscxml/*.cpp src/uscxml/*.h)
+list (APPEND USCXML_FILES ${USCXML_INTERPRETER})
+
+include_directories(src)
+
+# build library
+add_library(uscxml ${USCXML_FILES})
+target_link_libraries(uscxml ${USCXML_LIBS})
+
+add_subdirectory(test)
+add_subdirectory(src/bindings)
+
+# ---- OLD DEPENDENCIES -------------
+
+#set(Boost_DEBUG 1)
+# find_package(Boost COMPONENTS thread regex system date_time REQUIRED)
+# INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR})
+
+#openssl - needed for pion
+# find_package(OPENSSL REQUIRED)
+# INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
+
+#zlib - needed for pion
+# find_package(ZLIB REQUIRED)
+# INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS})
+
+#iconv - needed for pion
+# find_package(ICONV REQUIRED)
+# INCLUDE_DIRECTORIES(${ICONV_INCLUDE_DIR})
+
+#ev - no longer supported
+# set(ENV{EV_SRC} ${CMAKE_SOURCE_DIR}/../libev)
+# find_package(EV REQUIRED)
+# include_directories(${EV_INCLUDE_DIR})
+
+#pion
+# set(ENV{PION_SRC} ${CMAKE_SOURCE_DIR}/../pion)
+# find_package(PION REQUIRED)
+# include_directories(${PION_INCLUDE_DIR})
+# file(GLOB_RECURSE USCXML_IO_PROCESSOR_PION
+# src/uscxml/ioprocessor/basichttp/pion/*.cpp
+# src/uscxml/ioprocessor/basichttp/pion/*.h
+# )
+
diff --git a/contrib/cmake/FindArabica.cmake b/contrib/cmake/FindArabica.cmake
new file mode 100644
index 0000000..bd4fe18
--- /dev/null
+++ b/contrib/cmake/FindArabica.cmake
@@ -0,0 +1,21 @@
+FIND_PATH(ARABICA_INCLUDE_DIR Arabica/getparam.hpp
+ PATH_SUFFIXES include/arabica include
+ PATHS
+ /usr/local
+ /usr
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt
+ HINTS $ENV{ARABICA_SRC}
+)
+
+FIND_LIBRARY(ARABICA_LIBRARY
+ NAMES arabica
+ HINTS $ENV{ARABICA_SRC}/src/.libs/
+
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Arabica DEFAULT_MSG ARABICA_LIBRARY ARABICA_INCLUDE_DIR)
+MARK_AS_ADVANCED(ARABICA_LIBRARY ARABICA_INCLUDE_DIR)
diff --git a/contrib/cmake/FindEV.cmake b/contrib/cmake/FindEV.cmake
new file mode 100644
index 0000000..f994aa1
--- /dev/null
+++ b/contrib/cmake/FindEV.cmake
@@ -0,0 +1,20 @@
+FIND_PATH(EV_INCLUDE_DIR ev.h
+ PATH_SUFFIXES include
+ PATHS
+ /usr/local
+ /usr
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt
+ HINTS $ENV{EV_SRC}
+)
+
+FIND_LIBRARY(EV_LIBRARY
+ NAMES ev
+ HINTS $ENV{EV_SRC}/.libs/
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(EV DEFAULT_MSG EV_LIBRARY EV_INCLUDE_DIR)
+MARK_AS_ADVANCED(EV_LIBRARY EV_INCLUDE_DIR)
diff --git a/contrib/cmake/FindEVENT.cmake b/contrib/cmake/FindEVENT.cmake
new file mode 100644
index 0000000..31e074c
--- /dev/null
+++ b/contrib/cmake/FindEVENT.cmake
@@ -0,0 +1,34 @@
+FIND_PATH(EVENT_INCLUDE_DIR event2/event.h
+ PATH_SUFFIXES include
+ PATHS
+ /usr/local
+ /usr
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt
+ HINTS $ENV{EVENT_SRC}
+)
+
+FIND_LIBRARY(EVENT_LIBRARY
+ NAMES event
+ HINTS $ENV{EVENT_SRC}/.libs/
+)
+
+if (NOT WIN32)
+ FIND_LIBRARY(EVENT_LIBRARY_THREADS
+ NAMES event_pthreads
+ HINTS $ENV{EVENT_SRC}/.libs/
+ )
+else()
+ FIND_LIBRARY(EVENT_LIBRARY_THREADS
+ NAMES event_pthreads
+ HINTS $ENV{EVENT_SRC}/.libs/
+ )
+endif()
+
+list (APPEND EVENT_LIBRARY ${EVENT_LIBRARY_THREADS})
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(EVENT DEFAULT_MSG EVENT_LIBRARY EVENT_INCLUDE_DIR)
+MARK_AS_ADVANCED(EVENT_LIBRARY EVENT_INCLUDE_DIR)
diff --git a/contrib/cmake/FindGLOG.cmake b/contrib/cmake/FindGLOG.cmake
new file mode 100644
index 0000000..fee9d78
--- /dev/null
+++ b/contrib/cmake/FindGLOG.cmake
@@ -0,0 +1,20 @@
+FIND_PATH(GLOG_INCLUDE_DIR glog/logging.h
+ PATH_SUFFIXES include src
+ PATHS
+ /usr/local
+ /usr
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt
+ HINTS $ENV{GLOG_SRC}
+)
+
+FIND_LIBRARY(GLOG_LIBRARY
+ NAMES glog
+ HINTS $ENV{GLOG_SRC}/.libs/
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLOG DEFAULT_MSG GLOG_LIBRARY GLOG_INCLUDE_DIR)
+MARK_AS_ADVANCED(GLOG_LIBRARY GLOG_INCLUDE_DIR)
diff --git a/contrib/cmake/FindICONV.cmake b/contrib/cmake/FindICONV.cmake
new file mode 100644
index 0000000..a95bc65
--- /dev/null
+++ b/contrib/cmake/FindICONV.cmake
@@ -0,0 +1,57 @@
+# - Try to find Iconv
+# Once done this will define
+#
+# ICONV_FOUND - system has Iconv
+# ICONV_INCLUDE_DIR - the Iconv include directory
+# ICONV_LIBRARIES - Link these to use Iconv
+# ICONV_SECOND_ARGUMENT_IS_CONST - the second argument for iconv() is const
+#
+include(CheckCXXSourceCompiles)
+
+IF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+ # Already in cache, be silent
+ SET(ICONV_FIND_QUIETLY TRUE)
+ENDIF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+
+FIND_PATH(ICONV_INCLUDE_DIR iconv.h)
+
+FIND_LIBRARY(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c)
+
+IF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+ SET(ICONV_FOUND TRUE)
+ENDIF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+
+set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
+set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES})
+IF(ICONV_FOUND)
+ check_cxx_source_compiles("
+ #include <iconv.h>
+ int main(){
+ iconv_t conv = 0;
+ const char* in = 0;
+ size_t ilen = 0;
+ char* out = 0;
+ size_t olen = 0;
+ iconv(conv, &in, &ilen, &out, &olen);
+ return 0;
+ }
+" ICONV_SECOND_ARGUMENT_IS_CONST )
+ENDIF(ICONV_FOUND)
+set(CMAKE_REQUIRED_INCLUDES)
+set(CMAKE_REQUIRED_LIBRARIES)
+
+IF(ICONV_FOUND)
+ IF(NOT ICONV_FIND_QUIETLY)
+ MESSAGE(STATUS "Found Iconv: ${ICONV_LIBRARIES}")
+ ENDIF(NOT ICONV_FIND_QUIETLY)
+ELSE(ICONV_FOUND)
+ IF(Iconv_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find Iconv")
+ ENDIF(Iconv_FIND_REQUIRED)
+ENDIF(ICONV_FOUND)
+
+MARK_AS_ADVANCED(
+ ICONV_INCLUDE_DIR
+ ICONV_LIBRARIES
+ ICONV_SECOND_ARGUMENT_IS_CONST
+) \ No newline at end of file
diff --git a/contrib/cmake/FindPION.cmake b/contrib/cmake/FindPION.cmake
new file mode 100644
index 0000000..3a4157a
--- /dev/null
+++ b/contrib/cmake/FindPION.cmake
@@ -0,0 +1,20 @@
+FIND_PATH(PION_INCLUDE_DIR pion/config.hpp
+ PATH_SUFFIXES include
+ PATHS
+ /usr/local
+ /usr
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt
+ HINTS $ENV{PION_SRC}
+)
+
+FIND_LIBRARY(PION_LIBRARY
+ NAMES pion
+ HINTS $ENV{PION_SRC}/src/.libs/
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(PION DEFAULT_MSG PION_LIBRARY PION_INCLUDE_DIR)
+MARK_AS_ADVANCED(PION_LIBRARY PION_INCLUDE_DIR)
diff --git a/contrib/cmake/FindV8.cmake b/contrib/cmake/FindV8.cmake
new file mode 100644
index 0000000..6836fb3
--- /dev/null
+++ b/contrib/cmake/FindV8.cmake
@@ -0,0 +1,28 @@
+FIND_PATH(V8_INCLUDE_DIR v8.h
+ PATH_SUFFIXES include
+ PATHS
+ /usr/local
+ /usr
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt
+ HINTS $ENV{V8_SRC}
+)
+
+FIND_LIBRARY(V8_LIBRARY_BASE
+ NAMES v8_base
+ HINTS $ENV{V8_SRC}/out/native/
+)
+list(APPEND V8_LIBRARY ${V8_LIBRARY_BASE})
+
+FIND_LIBRARY(V8_LIBRARY_SNAPSHOT
+ NAMES v8_snapshot
+ HINTS $ENV{V8_SRC}/out/native/
+
+)
+list(APPEND V8_LIBRARY ${V8_LIBRARY_SNAPSHOT})
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(V8 DEFAULT_MSG V8_LIBRARY V8_INCLUDE_DIR)
+MARK_AS_ADVANCED(V8_LIBRARY V8_INCLUDE_DIR)
diff --git a/src/bindings/CMakeLists.txt b/src/bindings/CMakeLists.txt
new file mode 100644
index 0000000..deac396
--- /dev/null
+++ b/src/bindings/CMakeLists.txt
@@ -0,0 +1,12 @@
+find_package(SWIG)
+if (SWIG_FOUND)
+ if(SWIG_VERSION VERSION_GREATER 2.0.4)
+ MARK_AS_ADVANCED(SWIG_DIR SWIG_EXECUTABLE SWIG_VERSION)
+ INCLUDE(${SWIG_USE_FILE})
+ add_subdirectory(swig/java)
+ else()
+ message("SWIG version 2.0.5 is required, found ${SWIG_VERSION} - skipping java wrapper generation")
+ endif()
+else()
+ message("SWIG not found - skipping wrapper generation")
+endif()
diff --git a/src/bindings/swig/java/CMakeLists.txt b/src/bindings/swig/java/CMakeLists.txt
new file mode 100644
index 0000000..a729b8e
--- /dev/null
+++ b/src/bindings/swig/java/CMakeLists.txt
@@ -0,0 +1,31 @@
+# generate JNI library and create a jar
+# Make from within Eclipse fails miserably with the whole thing
+
+find_package(JNI)
+if(JNI_FOUND)
+ include_directories(${JNI_INCLUDE_DIRS})
+else()
+ message(STATUS "No JNI libraries found - not building Java wrappers")
+ return()
+endif()
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+SET(CMAKE_SWIG_FLAGS "")
+SET(SCXMLPL_JAVA_PACKAGE "org.uscxml")
+SET(SCXMLPL_JAVA_DIR "org/uscxml")
+
+# we need ; to produce a space with the package .. weird
+SET_SOURCE_FILES_PROPERTIES(uscxml.i PROPERTIES SWIG_FLAGS "-package;${SCXMLPL_JAVA_PACKAGE}")
+SET_SOURCE_FILES_PROPERTIES(uscxml.i PROPERTIES CPLUSPLUS ON)
+SET(CMAKE_SWIG_OUTDIR "${CMAKE_CURRENT_BINARY_DIR}/${SCXMLPL_JAVA_DIR}")
+
+SWIG_ADD_MODULE(uscxmlNativeJava java uscxml.i)
+foreach(JNI_LIBRARY ${JNI_LIBRARIES})
+ if (NOT ${JNI_LIBRARY} MATCHES ".*jawt.*")
+ SWIG_LINK_LIBRARIES(uscxmlNativeJava ${JNI_LIBRARY})
+ endif()
+endforeach()
+set_target_properties(uscxmlNativeJava PROPERTIES FOLDER "Bindings")
+
+swig_link_libraries(uscxmlNativeJava uscxml)
diff --git a/src/bindings/swig/java/uscxml.i b/src/bindings/swig/java/uscxml.i
new file mode 100644
index 0000000..ccd6fe0
--- /dev/null
+++ b/src/bindings/swig/java/uscxml.i
@@ -0,0 +1,40 @@
+%module(directors="1", allprotected="1") uscxmlNativeJava
+
+// import swig typemaps
+//%include <arrays_java.i>
+//%include <inttypes.i>
+%include <boost_shared_ptr.i>
+
+// disable warning related to unknown base class
+#pragma SWIG nowarn=401
+//%ignore boost::enable_shared_from_this;
+
+%javaconst(1);
+
+# %shared_ptr(uscxml::dom::Element);
+# %shared_ptr(uscxml::dom::Executable);
+
+
+//**************************************************
+// This ends up in the generated wrapper code
+//**************************************************
+
+%{
+
+#include "../../../uscxml/Message.h"
+#include "../../../uscxml/Interpreter.h"
+
+using namespace uscxml;
+
+%}
+
+%rename(toString) operator<<;
+
+
+//***********************************************
+// Parse the header file to generate wrappers
+//***********************************************
+
+%include "../../../uscxml/Message.h"
+%include "../../../uscxml/Interpreter.h"
+
diff --git a/src/uscxml.h b/src/uscxml.h
new file mode 100644
index 0000000..792ba43
--- /dev/null
+++ b/src/uscxml.h
@@ -0,0 +1,6 @@
+#ifndef USCXML_H_2WZ0PBQH
+#define USCXML_H_2WZ0PBQH
+
+#include "uscxml/Interpreter.h"
+
+#endif /* end of include guard: USCXML_H_2WZ0PBQH */
diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp
new file mode 100644
index 0000000..91da562
--- /dev/null
+++ b/src/uscxml/Factory.cpp
@@ -0,0 +1,56 @@
+#include "uscxml/Factory.h"
+#include "uscxml/datamodel/ecmascript/v8/V8DataModel.h"
+//#include "uscxml/ioprocessor/basichttp/pion/PionIOProcessor.h"
+#include "uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.h"
+
+namespace uscxml {
+
+ Factory::Factory() {
+ _dataModels["ecmascript"] = new V8DataModel();
+// _ioProcessors["basichttp"] = new PionIOProcessor();
+ _ioProcessors["basichttp"] = new io::libevent::EventIOProcessor();
+ }
+
+ void Factory::registerIOProcessor(const std::string type, IOProcessor* ioProcessor) {
+ getInstance()->_ioProcessors[type] = ioProcessor;
+ }
+
+ void Factory::registerDataModel(const std::string type, DataModel* dataModel) {
+ getInstance()->_dataModels[type] = dataModel;
+ }
+
+ void Factory::registerExecutableContent(const std::string tag, ExecutableContent* executableContent) {
+ getInstance()->_executableContent[tag] = executableContent;
+ }
+
+ DataModel* Factory::getDataModel(const std::string type, Interpreter* interpreter) {
+ if (Factory::getInstance()->_dataModels.find(type) != getInstance()->_dataModels.end()) {
+ return getInstance()->_dataModels[type]->create(interpreter);
+ }
+ return NULL;
+ }
+
+ IOProcessor* Factory::getIOProcessor(const std::string type, Interpreter* interpreter) {
+ if (getInstance()->_ioProcessors.find(type) != getInstance()->_ioProcessors.end()) {
+ return getInstance()->_ioProcessors[type]->create(interpreter);
+ }
+ return NULL;
+ }
+
+ ExecutableContent* Factory::getExecutableContent(const std::string tag, Interpreter* interpreter) {
+ if (getInstance()->_executableContent.find(tag) != getInstance()->_executableContent.end()) {
+ return getInstance()->_executableContent[tag]->create(interpreter);
+ }
+ return NULL;
+ }
+
+ Factory* Factory::getInstance() {
+ if (_instance == NULL) {
+ _instance = new Factory();
+ }
+ return _instance;
+ }
+
+ Factory* Factory::_instance = NULL;
+
+} \ No newline at end of file
diff --git a/src/uscxml/Factory.h b/src/uscxml/Factory.h
new file mode 100644
index 0000000..f1840c6
--- /dev/null
+++ b/src/uscxml/Factory.h
@@ -0,0 +1,73 @@
+#ifndef FACTORY_H_5WKLGPRB
+#define FACTORY_H_5WKLGPRB
+
+#include "uscxml/Message.h"
+
+#include <string>
+
+namespace uscxml {
+
+ class Interpreter;
+
+ class ExecutableContent {
+ public:
+ ExecutableContent() {};
+ virtual ExecutableContent* create(Interpreter* interpreter) = 0;
+ };
+
+ class IOProcessor {
+ public:
+ IOProcessor() {};
+ virtual ~IOProcessor() {};
+ virtual IOProcessor* create(Interpreter* interpreter) = 0;
+
+ virtual std::string getURL() = 0;
+ virtual void send(SendRequest& req) = 0;
+ virtual void invoke(InvokeRequest& req) = 0;
+ virtual void cancel(const std::string sendId) = 0;
+ };
+
+ class DataModel {
+ public:
+ virtual DataModel* create(Interpreter* interpreter) = 0;
+
+ virtual bool validate(const std::string& location, const std::string& schema) = 0;
+ virtual void setEvent(Event& event) = 0;
+ virtual void setData(const std::string& key, Data& event) = 0;
+
+ // foreach
+ virtual uint32_t getLength(const std::string& expr) = 0;
+ virtual void pushContext() = 0;
+ virtual void popContext() = 0;
+
+ virtual void eval(const std::string& expr) = 0;
+ virtual std::string evalAsString(const std::string& expr) = 0;
+ virtual bool evalAsBool(const std::string& expr) = 0;
+ virtual void assign(const std::string& location, const std::string& expr) = 0;
+ };
+
+ class Factory {
+ public:
+ static void registerIOProcessor(const std::string type, IOProcessor* ioProcessor);
+ static void registerDataModel(const std::string type, DataModel* dataModel);
+ static void registerExecutableContent(const std::string tag, ExecutableContent* executableContent);
+
+ static DataModel* getDataModel(const std::string type, Interpreter* interpreter);
+ static IOProcessor* getIOProcessor(const std::string type, Interpreter* interpreter);
+ static ExecutableContent* getExecutableContent(const std::string tag, Interpreter* interpreter);
+ static Factory* getInstance();
+
+ std::map<std::string, DataModel*> _dataModels;
+ std::map<std::string, IOProcessor*> _ioProcessors;
+ std::map<std::string, ExecutableContent*> _executableContent;
+
+ protected:
+ Factory();
+ static Factory* _instance;
+
+ };
+
+
+}
+
+#endif /* end of include guard: FACTORY_H_5WKLGPRB */
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
new file mode 100644
index 0000000..7189f12
--- /dev/null
+++ b/src/uscxml/Interpreter.cpp
@@ -0,0 +1,1712 @@
+#include "uscxml/Interpreter.h"
+
+#include <DOM/Simple/DOMImplementation.hpp>
+
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_generators.hpp>
+#include <boost/uuid/uuid_io.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/tokenizer.hpp>
+
+#include <glog/logging.h>
+
+#include <assert.h>
+#include <algorithm>
+
+namespace uscxml {
+
+using namespace Arabica::XPath;
+using namespace Arabica::DOM;
+
+boost::uuids::random_generator Interpreter::uuidGen;
+const std::string Interpreter::getUUID() {
+ return boost::lexical_cast<std::string>(uuidGen());
+}
+
+Interpreter::Interpreter(const std::string& url) {
+ _thread = NULL;
+ _url = url;
+
+ LOG(INFO) << "runtime started with " << _url;
+ Arabica::SAX::InputSource<std::string> inputSource(_url);
+
+ Arabica::SAX2DOM::Parser<std::string> domParser;
+ Arabica::SAX::CatchErrorHandler<std::string> errorHandler;
+ domParser.setErrorHandler(errorHandler);
+ if(!domParser.parse(inputSource) || !domParser.getDocument().hasChildNodes()) {
+ LOG(INFO) << "could not parse " << _url << ":";
+ if(errorHandler.errorsReported()) {
+ LOG(ERROR) << errorHandler.errors() << std::endl;
+ } else {
+ Arabica::SAX::InputSourceResolver resolver(inputSource, Arabica::default_string_adaptor<std::string>());
+ if (!resolver.resolve()) {
+ LOG(ERROR) << "no such file";
+ }
+ }
+ } else {
+ _doc = domParser.getDocument();
+ }
+
+ if (_doc) {
+ // do we have a xmlns attribute?
+ std::string ns = _doc.getDocumentElement().getNamespaceURI();
+ if(ns.size() > 0) {
+ _nsContext.addNamespaceDeclaration(ns, "sc");
+ _xpath.setNamespaceContext(_nsContext);
+ _nsPrefix = "sc:";
+ }
+ NodeList<std::string> scxmls = _doc.getElementsByTagName("scxml");
+ if (scxmls.getLength() > 0) {
+ _scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0);
+ } else {
+ LOG(ERROR) << "Cannot find SCXML element" << std::endl;
+ }
+ _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : getUUID());
+ }
+}
+
+Interpreter::~Interpreter() {
+ std::map<std::string, IOProcessor*>::iterator ioProcessorIter = _ioProcessors.begin();
+ while(ioProcessorIter != _ioProcessors.end()) {
+ delete ioProcessorIter->second;
+ ioProcessorIter++;
+ }
+ if (_thread) {
+ _thread->join();
+ delete(_thread);
+ }
+}
+
+void Interpreter::start() {
+ _thread = new tthread::thread(Interpreter::run, this);
+}
+
+void Interpreter::stop() {
+}
+
+void Interpreter::run(void* instance) {
+ ((Interpreter*)instance)->interpret();
+}
+
+void Interpreter::waitForStabilization() {
+ tthread::lock_guard<tthread::mutex> lock(_mutex);
+ _stabilized.wait(_mutex);
+}
+
+// see: http://www.w3.org/TR/scxml/#AlgorithmforSCXMLInterpretation
+void Interpreter::interpret() {
+ if (!_scxml)
+ return;
+// dump();
+
+ _sessionId = getUUID();
+ normalize(_doc);
+
+ if(HAS_ATTR(_scxml, "datamodel")) {
+ _dataModel = Factory::getDataModel(ATTR(_scxml, "datamodel"), this);
+ if(_dataModel == NULL) {
+ LOG(ERROR) << "No datamodel for " << ATTR(_scxml, "datamodel") << " registered";
+ return;
+ }
+ }
+
+ setupIOProcessors();
+
+ // executeGlobalScriptElements
+ NodeSet<std::string> globalScriptElems = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "script", _doc).asNodeSet();
+ for (unsigned int i = 0; i < globalScriptElems.size(); i++) {
+// std::cout << globalScriptElems[i].getFirstChild().getNodeValue() << std::endl;
+ if (_dataModel)
+ executeContent(globalScriptElems[i]);
+ }
+
+ _running = true;
+
+ std::string binding = _xpath.evaluate("/" + _nsPrefix + "scxml/@binding", _doc).asString();
+ _binding = (boost::iequals(binding, "late") ? LATE : EARLY);
+
+ // initialize all data elements
+ if (_dataModel && _binding == EARLY) {
+ NodeSet<std::string> dataElems = _xpath.evaluate("//" + _nsPrefix + "data", _doc).asNodeSet();
+ for (unsigned int i = 0; i < dataElems.size(); i++) {
+ initializeData(dataElems[i]);
+ }
+ } else if(_dataModel) {
+ NodeSet<std::string> topDataElems = _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "datamodel/" + _nsPrefix + "data", _doc).asNodeSet();
+ for (unsigned int i = 0; i < topDataElems.size(); i++) {
+ initializeData(topDataElems[i]);
+ }
+ }
+
+ // executeTransitionContent
+ Arabica::DOM::Element<std::string> initialState = (Arabica::DOM::Element<std::string>)getInitialState();
+
+ // create a pseudo initial and transition element
+ NodeSet<std::string> initialTransitions;
+ Arabica::DOM::Element<std::string> initialElem = _doc.createElement("initial");
+ Arabica::DOM::Element<std::string> transitionElem = _doc.createElement("transition");
+ transitionElem.setAttribute("target", initialState.getAttribute("id"));
+
+ initialElem.appendChild(transitionElem);
+ _scxml.appendChild(initialElem);
+
+ assert(boost::iequals(TAGNAME(initialElem), "initial"));
+
+ initialTransitions.push_back(transitionElem);
+ enterStates(initialTransitions);
+
+ mainEventLoop();
+}
+
+void Interpreter::initializeData(const Arabica::DOM::Node<std::string>& data) {
+ if (!_dataModel) {
+ LOG(ERROR) << "Cannot initialize data when no datamodel is given!";
+ return;
+ }
+ try {
+ if (!HAS_ATTR(data, "id"))
+ return;
+ std::string value = "undefined";
+
+ if (HAS_ATTR(data, "expr")) {
+ value = ATTR(data, "expr");
+ goto VALUE_INITIALIZED;
+ }
+ if (HAS_ATTR(data, "src")) {
+ Arabica::SAX::InputSourceResolver resolver(Arabica::SAX::InputSource<std::string>(ATTR(data, "src")),
+ Arabica::default_string_adaptor<std::string>());
+ value = std::string(std::istreambuf_iterator<char>(*resolver.resolve()), std::istreambuf_iterator<char>());
+ goto VALUE_INITIALIZED;
+ }
+ if (data.hasChildNodes()) {
+ // search for the text node with the actual script
+ if (data.getFirstChild().getNodeType() == Node_base::TEXT_NODE) {
+ value = data.getFirstChild().getNodeValue();
+ }
+ }
+
+VALUE_INITIALIZED:
+ _dataModel->assign(ATTR(data, "id"), value);
+
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in send element:" << std::endl << e << std::endl;
+ }
+}
+
+void Interpreter::normalize(const Arabica::DOM::Node<std::string>& node) {
+ // make sure every state has an id and set isFirstEntry to true
+ Arabica::XPath::NodeSet<std::string> states = _xpath.evaluate("//" + _nsPrefix + "state", _doc).asNodeSet();
+ for (int i = 0; i < states.size(); i++) {
+ Arabica::DOM::Element<std::string> stateElem = Arabica::DOM::Element<std::string>(states[i]);
+ stateElem.setAttribute("isFirstEntry", "true");
+ if (!stateElem.hasAttribute("id")) {
+ stateElem.setAttribute("id", getUUID());
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> finals = _xpath.evaluate("//" + _nsPrefix + "final", _doc).asNodeSet();
+ for (int i = 0; i < finals.size(); i++) {
+ Arabica::DOM::Element<std::string> finalElem = Arabica::DOM::Element<std::string>(finals[i]);
+ finalElem.setAttribute("isFirstEntry", "true");
+ if (!finalElem.hasAttribute("id")) {
+ finalElem.setAttribute("id", getUUID());
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> histories = _xpath.evaluate("//" + _nsPrefix + "history", _doc).asNodeSet();
+ for (int i = 0; i < histories.size(); i++) {
+ Arabica::DOM::Element<std::string> historyElem = Arabica::DOM::Element<std::string>(histories[i]);
+ if (!historyElem.hasAttribute("id")) {
+ historyElem.setAttribute("id", getUUID());
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> scxml = _xpath.evaluate("/" + _nsPrefix + "scxml", _doc).asNodeSet();
+ if (!((Arabica::DOM::Element<std::string>)scxml[0]).hasAttribute("id")) {
+ ((Arabica::DOM::Element<std::string>)scxml[0]).setAttribute("id", getUUID());
+ }
+}
+
+void Interpreter::mainEventLoop() {
+ while(_running) {
+ NodeSet<std::string> enabledTransitions;
+ _stable = false;
+
+ // Here we handle eventless transitions and transitions
+ // triggered by internal events until machine is stable
+ while(_running && !_stable) {
+#if 0
+ std::cout << "Configuration: ";
+ for (int i = 0; i < _configuration.size(); i++) {
+ std::cout << ((Arabica::DOM::Element<std::string>)_configuration[i]).getAttribute("id") << ", ";
+ }
+ std::cout << std::endl;
+#endif
+ enabledTransitions = selectEventlessTransitions();
+ if (enabledTransitions.size() == 0) {
+ if (_internalQueue.size() == 0) {
+ _stable = true;
+ } else {
+ Event internalEvent = _internalQueue.front();
+ _internalQueue.pop_front();
+ _dataModel->setEvent(internalEvent);
+ enabledTransitions = selectTransitions(internalEvent.name);
+ }
+ }
+ if (!enabledTransitions.empty())
+ microstep(enabledTransitions);
+ }
+
+ for (unsigned int i = 0; i < _statesToInvoke.size(); i++) {
+ NodeSet<std::string> invokes = _xpath.evaluate("" + _nsPrefix + "invoke", _statesToInvoke[i]).asNodeSet();
+ for (unsigned int j = 0; j < invokes.size(); j++) {
+ // @TODO:
+ // boost::shared_ptr<Invoke> invoke = boost::static_pointer_cast<Invoke>(interpreter::Factory::create("invoke", invokes[j]));
+ // invoke->invoke(this);
+ }
+ }
+
+ _statesToInvoke = NodeSet<std::string>();
+ if (!_internalQueue.empty())
+ continue;
+
+ {
+ tthread::lock_guard<tthread::mutex> lock(_mutex);
+ _stabilized.notify_all();
+ }
+
+ Event externalEvent = _externalQueue.pop();
+ if (!_running)
+ exitInterpreter();
+
+ if (_dataModel && boost::iequals(externalEvent.name, "cancel.invoke." + _sessionId))
+ break;
+
+ if (_dataModel)
+ _dataModel->setEvent(externalEvent);
+ for (unsigned int i = 0; i < _configuration.size(); i++) {
+ NodeSet<std::string> invokes = _xpath.evaluate("" + _nsPrefix + "invoke", _configuration[i]).asNodeSet();
+ for (unsigned int j = 0; j < invokes.size(); j++) {
+ std::string invokeId = ((Arabica::DOM::Element<std::string>)invokes[i]).getAttribute("id");
+ std::string autoForward = ((Arabica::DOM::Element<std::string>)invokes[i]).getAttribute("autoforward");
+ if (boost::iequals(invokeId, externalEvent.invokeid)) {
+ // @TODO
+ // boost::shared_ptr<Invoke> invoke = boost::static_pointer_cast<Invoke>(interpreter::Factory::create("invoke", invokes[j]));
+ // invoke->applyFinalize(this);
+ }
+ if (autoForward.length() > 0) {
+ send(invokeId, externalEvent);
+ }
+ }
+ }
+ enabledTransitions = selectTransitions(externalEvent.name);
+ if (!enabledTransitions.empty())
+ microstep(enabledTransitions);
+ }
+ exitInterpreter();
+}
+
+void Interpreter::send(const std::string invokeId, Event& event) {
+}
+
+void Interpreter::send(const Arabica::DOM::Node<std::string>& element) {
+ SendRequest sendReq;
+ try {
+ // event
+ if (HAS_ATTR(element, "eventexpr") && _dataModel) {
+ sendReq.name = _dataModel->evalAsString(ATTR(element, "eventexpr"));
+ } else if (HAS_ATTR(element, "event")) {
+ sendReq.name = ATTR(element, "event");
+ } else {
+ LOG(ERROR) << "send element does not feature event, or eventexpr without datamodel given";
+ return;
+ }
+ // target
+ if (HAS_ATTR(element, "targetexpr") && _dataModel) {
+ sendReq.target = _dataModel->evalAsString(ATTR(element, "targetexpr"));
+ } else if (HAS_ATTR(element, "target")) {
+ sendReq.target = ATTR(element, "target");
+ }
+ // type
+ if (HAS_ATTR(element, "typeexpr") && _dataModel) {
+ sendReq.type = _dataModel->evalAsString(ATTR(element, "typeexpr"));
+ } else if (HAS_ATTR(element, "type")) {
+ sendReq.type = ATTR(element, "type");
+ } else {
+ sendReq.type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor";
+ }
+ // id
+ if (HAS_ATTR(element, "idlocation") && _dataModel) {
+ sendReq.sendid = _dataModel->evalAsString(ATTR(element, "idlocation"));
+ } else if (HAS_ATTR(element, "id")) {
+ sendReq.sendid = ATTR(element, "id");
+ } else {
+ /*
+ * The ids for <send> and <invoke> are subtly different. In a conformant
+ * SCXML document, they must be unique within the session, but in the case
+ * where the author does not provide them, the processor must generate a
+ * new unique ID not at load time but each time the element is executed.
+ * Furthermore the attribute 'idlocation' can be used to capture this
+ * automatically generated id. Finally note that the automatically generated
+ * id for <invoke> has a special format. See 6.4.1 Attribute Details for
+ * details. The SCXML processor may generate all other ids in any format,
+ * as long as they are unique.
+ */
+ sendReq.sendid = getUUID();
+ }
+ /** @TODO:
+ *
+ * If 'idlocation' is present, the SCXML Processor must generate an id when
+ * the parent <send> element is evaluated and store it in this location.
+ * See 3.14 IDs for details.
+ *
+ */
+
+ // delay
+ std::string delay;
+ sendReq.delayMs = 0;
+ if (HAS_ATTR(element, "delayexpr") && _dataModel) {
+ delay = _dataModel->evalAsString(ATTR(element, "delayexpr"));
+ } else if (HAS_ATTR(element, "delay")) {
+ delay = ATTR(element, "delay");
+ }
+ if (delay.size() > 0) {
+ boost::trim(delay);
+ std::stringstream delayTime;
+ if (delay.size() > 2 && boost::iequals("ms", delay.substr(delay.length() - 2, 2))) {
+ delayTime << delay.substr(0, delay.size() - 2);
+ delayTime >> sendReq.delayMs;
+ } else if (delay.size() > 1 && boost::iequals("s", delay.substr(delay.length() - 1, 1))) {
+ delayTime << delay.substr(0, delay.size() - 1);
+ delayTime >> sendReq.delayMs;
+ sendReq.delayMs *= 1000;
+ } else {
+ LOG(ERROR) << "Cannot make sense of delay value " << delay << ": does not end in 's' or 'ms'";
+ }
+ }
+ // namelist
+ if (HAS_ATTR(element, "namelist")) {
+ std::vector<std::string> names = tokenizeIdRefs(ATTR(element, "namelist"));
+ for (int i = 0; i < names.size(); i++) {
+ sendReq.namelist[names[i]] = _dataModel->evalAsString(names[i]);
+ }
+ }
+
+ // params
+ NodeSet<std::string> params = _xpath.evaluate("" + _nsPrefix + "param", element).asNodeSet();
+ for (int i = 0; i < params.size(); i++) {
+ if (!HAS_ATTR(params[i], "name")) {
+ LOG(ERROR) << "param element is missing name attribut";
+ continue;
+ }
+ std::string paramValue;
+ if (HAS_ATTR(params[i], "expr") && _dataModel) {
+ std::string location = _dataModel->evalAsString(ATTR(params[i], "expr"));
+ paramValue = _dataModel->evalAsString(location);
+ } else if(HAS_ATTR(params[i], "location") && _dataModel) {
+ paramValue = _dataModel->evalAsString(ATTR(params[i], "location"));
+ } else {
+ LOG(ERROR) << "param element is missing expr or location or no datamodel is specified";
+ continue;
+ }
+ sendReq.params[ATTR(params[i], "name")] = paramValue;
+ }
+
+ // content
+ NodeSet<std::string> contents = _xpath.evaluate("" + _nsPrefix + "content", element).asNodeSet();
+ if (contents.size() > 1)
+ LOG(ERROR) << "Only a single content element is allowed for send elements - using first one";
+ if (contents.size() > 0) {
+ if (HAS_ATTR(contents[0], "expr")) {
+ if (_dataModel) {
+ sendReq.content = _dataModel->evalAsString(ATTR(contents[0], "expr"));
+ } else {
+ LOG(ERROR) << "content element has expr attribute but no datamodel is specified.";
+ }
+ } else if (contents[0].hasChildNodes()) {
+// dump(contents[0].getFirstChild());
+ sendReq.content = contents[0].getFirstChild().getNodeValue();
+ } else {
+ LOG(ERROR) << "content element does not specify any content.";
+ }
+ }
+
+ IOProcessor* ioProc = getIOProcessor(sendReq.type);
+ if (ioProc != NULL) {
+ _ioProcessorsIds[sendReq.sendid] = ioProc;
+ ioProc->send(sendReq);
+ }
+
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in send element:" << std::endl << e << std::endl;
+ }
+}
+
+void Interpreter::invoke(const Arabica::DOM::Node<std::string>& element) {
+ InvokeRequest invokeReq;
+ try {
+ // type
+ if (HAS_ATTR(element, "typeexpr") && _dataModel) {
+ invokeReq.type = _dataModel->evalAsString(ATTR(element, "typeexpr"));
+ } else if (HAS_ATTR(element, "type")) {
+ invokeReq.type = ATTR(element, "type");
+ } else {
+ LOG(ERROR) << "invoke element is missing expr or typeexpr or no datamodel is specified";
+ }
+
+ // src
+ if (HAS_ATTR(element, "srcexpr") && _dataModel) {
+ invokeReq.src = _dataModel->evalAsString(ATTR(element, "srcexpr"));
+ } else if (HAS_ATTR(element, "src")) {
+ invokeReq.src = ATTR(element, "src");
+ } else {
+ LOG(ERROR) << "invoke element is missing src or srcexpr or no datamodel is specified";
+ }
+
+ // id
+ if (HAS_ATTR(element, "idlocation") && _dataModel) {
+ invokeReq.invokeid = _dataModel->evalAsString(ATTR(element, "idlocation"));
+ } else if (HAS_ATTR(element, "id")) {
+ invokeReq.invokeid = ATTR(element, "id");
+ } else {
+ invokeReq.invokeid = getUUID();
+ }
+
+ // namelist
+ if (HAS_ATTR(element, "namelist")) {
+ invokeReq.namelist = ATTR(element, "namelist");
+ }
+
+ // autoforward
+ if (HAS_ATTR(element, "autoforward")) {
+ if (boost::iequals(ATTR(element, "autoforward"), "true")) {
+ invokeReq.autoForward = true;
+ }
+ } else {
+ invokeReq.autoForward = false;
+ }
+
+ // params
+ NodeSet<std::string> params = _xpath.evaluate("" + _nsPrefix + "param", element).asNodeSet();
+ for (int i = 0; i < params.size(); i++) {
+ if (HAS_ATTR(params[i], "name")) {
+ LOG(ERROR) << "param element is missing name attribut";
+ continue;
+ }
+ std::string paramValue;
+ if (HAS_ATTR(params[i], "expr") && _dataModel) {
+ paramValue = _dataModel->evalAsString(ATTR(params[i], "expr"));
+ } else if(HAS_ATTR(params[i], "location") && _dataModel) {
+ paramValue = _dataModel->evalAsString(ATTR(params[i], "location"));
+ } else {
+ LOG(ERROR) << "param element is missing expr or location or no datamodel is specified";
+ continue;
+ }
+ invokeReq.params[ATTR(params[i], "name")] = paramValue;
+ }
+
+ // content
+ NodeSet<std::string> contents = _xpath.evaluate("" + _nsPrefix + "content", element).asNodeSet();
+ if (contents.size() > 1)
+ LOG(ERROR) << "Only a single content element is allowed for send elements - using first one";
+ if (contents.size() > 0) {
+ invokeReq.content = contents[0].getNodeValue();
+ }
+
+ IOProcessor* ioProc = getIOProcessor(invokeReq.type);
+ if (ioProc != NULL) {
+ _ioProcessorsIds[invokeReq.invokeid] = ioProc;
+ ioProc->invoke(invokeReq);
+ }
+
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in invoke element:" << std::endl << e << std::endl;
+ }
+
+}
+
+Arabica::XPath::NodeSet<std::string> Interpreter::selectTransitions(const std::string& event) {
+ Arabica::XPath::NodeSet<std::string> enabledTransitions;
+
+ NodeSet<std::string> atomicStates;
+ for (unsigned int i = 0; i < _configuration.size(); i++) {
+ if (isAtomic(_configuration[i]))
+ atomicStates.push_back(_configuration[i]);
+ }
+ atomicStates.to_document_order();
+
+ for (unsigned int i = 0; i < atomicStates.size(); i++) {
+ NodeSet<std::string> ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node<std::string>());
+ ancestors.push_back(atomicStates[i]);
+ for (unsigned int j = 0; j < ancestors.size(); j++) {
+ NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", ancestors[j]).asNodeSet();
+ for (unsigned int k = 0; k < transitions.size(); k++) {
+ if (((Arabica::DOM::Element<std::string>)transitions[k]).hasAttribute("event") &&
+ nameMatch(((Arabica::DOM::Element<std::string>)transitions[k]).getAttribute("event"), event) &&
+ hasConditionMatch(transitions[k])) {
+ enabledTransitions.push_back(transitions[k]);
+ goto LOOP;
+ }
+ }
+ }
+ LOOP:;
+ }
+ return enabledTransitions;
+}
+
+// see: http://www.w3.org/TR/scxml/#EventDescriptors
+bool Interpreter::nameMatch(const std::string& transitionEvent, const std::string& event) {
+ assert(transitionEvent.size() > 0);
+ assert(event.size() > 0);
+
+ // naive case of single descriptor and exact match
+ if (boost::equals(transitionEvent, event))
+ return true;
+
+ boost::char_separator<char> sep(" ");
+ boost::tokenizer<boost::char_separator<char> > tokens(transitionEvent, sep);
+ boost::tokenizer<boost::char_separator<char> >::iterator tokenIter = tokens.begin();
+
+ while(tokenIter != tokens.end()) {
+ std::string eventDesc(*tokenIter++);
+
+ // remove optional trailing .* for CCXML compatibility
+ if (eventDesc.find("*", eventDesc.size() - 1) != std::string::npos)
+ eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
+ if (eventDesc.find(".", eventDesc.size() - 1) != std::string::npos)
+ eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
+
+ // are they already equal?
+ if (boost::equals(eventDesc, event))
+ return true;
+
+ // eventDesc has to be a real prefix of event now and therefore shorter
+ if (eventDesc.size() >= event.size())
+ continue;
+
+ // it is a prefix of the event name and event continues with .something
+ if (eventDesc.compare(event.substr(0, eventDesc.size())) == 0)
+ if (event.find(".", eventDesc.size()) == eventDesc.size())
+ return true;
+ }
+ return false;
+}
+
+Arabica::XPath::NodeSet<std::string> Interpreter::selectEventlessTransitions() {
+ Arabica::XPath::NodeSet<std::string> enabledTransitions;
+
+ NodeSet<std::string> atomicStates;
+ for (unsigned int i = 0; i < _configuration.size(); i++) {
+ if (isAtomic(_configuration[i]))
+ atomicStates.push_back(_configuration[i]);
+ }
+ atomicStates.to_document_order();
+
+ for (unsigned int i = 0; i < atomicStates.size(); i++) {
+ NodeSet<std::string> ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node<std::string>());
+ ancestors.push_back(atomicStates[i]);
+ for (unsigned int j = 0; j < ancestors.size(); j++) {
+ NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", ancestors[j]).asNodeSet();
+ for (unsigned int k = 0; k < transitions.size(); k++) {
+ if (!((Arabica::DOM::Element<std::string>)transitions[k]).hasAttribute("event") && hasConditionMatch(transitions[k])) {
+ enabledTransitions.push_back(transitions[k]);
+ goto LOOP;
+ }
+ }
+ }
+ LOOP:;
+ }
+
+ enabledTransitions = filterPreempted(enabledTransitions);
+ return enabledTransitions;
+}
+
+bool Interpreter::hasConditionMatch(const Arabica::DOM::Node<std::string>& conditional) {
+ try {
+ if (_dataModel && HAS_ATTR(conditional, "cond"))
+ return _dataModel->evalAsBool(ATTR(conditional, "cond"));
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in cond attribute of " << TAGNAME(conditional) << " element:" << std::endl << e << std::endl;
+ return false;
+ }
+ return true; // no condition is always true
+}
+
+Arabica::XPath::NodeSet<std::string> Interpreter::filterPreempted(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
+ Arabica::XPath::NodeSet<std::string> filteredTransitions;
+ for (unsigned int i = 0; i < enabledTransitions.size(); i++) {
+ Arabica::DOM::Node<std::string> t = enabledTransitions[i];
+ for (unsigned int j = i+1; j < enabledTransitions.size(); j++) {
+ Arabica::DOM::Node<std::string> t2 = enabledTransitions[j];
+ if (isPreemptingTransition(t2, t))
+ goto LOOP;
+ }
+ filteredTransitions.push_back(t);
+ LOOP:;
+ }
+ return filteredTransitions;
+}
+
+bool Interpreter::isPreemptingTransition(const Arabica::DOM::Node<std::string>& t1, const Arabica::DOM::Node<std::string>& t2) {
+ if (t1 == t2)
+ return false;
+ if (isWithinSameChild(t1) && (!isTargetless(t2) && !isWithinSameChild(t2)))
+ return true;
+ if (!isTargetless(t1) && !isWithinSameChild(t1))
+ return true;
+ return false;
+}
+
+void Interpreter::microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
+#if 0
+ std::cout << "Transitions: ";
+ for (int i = 0; i < enabledTransitions.size(); i++) {
+ std::cout << ((Arabica::DOM::Element<std::string>)getSourceState(enabledTransitions[i])).getAttribute("id") << " -> " << std::endl;
+ NodeSet<std::string> targetSet = getTargetStates(enabledTransitions[i]);
+ for (int j = 0; j < targetSet.size(); j++) {
+ std::cout << " " << ((Arabica::DOM::Element<std::string>)targetSet[i]).getAttribute("id") << std::endl;
+ }
+ }
+ std::cout << std::endl;
+#endif
+
+ exitStates(enabledTransitions);
+ executeTransitionContent(enabledTransitions);
+ enterStates(enabledTransitions);
+}
+
+void Interpreter::exitInterpreter() {
+ NodeSet<std::string> statesToExit = _configuration;
+ statesToExit.to_document_order();
+ statesToExit.reverse();
+
+ for (int i = 0; i < statesToExit.size(); i++) {
+ Arabica::XPath::NodeSet<std::string> onExitElems = _xpath.evaluate("" + _nsPrefix + "onexit", statesToExit[i]).asNodeSet();
+ for (int j = 0; j < onExitElems.size(); j++) {
+ executeContent(onExitElems[j]);
+ }
+ Arabica::XPath::NodeSet<std::string> invokeElems = _xpath.evaluate("" + _nsPrefix + "invoke", statesToExit[i]).asNodeSet();
+ for (int j = 0; j < invokeElems.size(); j++) {
+ cancelInvoke(invokeElems[j]);
+ }
+ if (isFinal(statesToExit[i]) && parentIsScxmlState(statesToExit[i])) {
+ returnDoneEvent(statesToExit[i]);
+ }
+ }
+ _configuration = NodeSet<std::string>();
+}
+
+void Interpreter::executeTransitionContent(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
+ for (int i = 0; i < enabledTransitions.size(); i++) {
+ executeContent(enabledTransitions[i]);
+ }
+}
+
+void Interpreter::executeContent(const NodeList<std::string>& content) {
+ for (unsigned int i = 0; i < content.getLength(); i++) {
+ if (content.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ executeContent(content.item(i));
+ }
+}
+
+void Interpreter::executeContent(const Arabica::DOM::Node<std::string>& content) {
+ if (content.getNodeType() != Node_base::ELEMENT_NODE)
+ return;
+
+ if (false) {
+ } else if (boost::iequals(TAGNAME(content), "raise")) {
+ // --- RAISE --------------------------
+ if (HAS_ATTR(content, "event")) {
+ Event event;
+ event.name = ATTR(content, "event");
+ _internalQueue.push_back(event);
+ }
+ } else if (boost::iequals(TAGNAME(content), "if")) {
+ // --- IF / ELSEIF / ELSE --------------
+ Arabica::DOM::Element<std::string> ifElem = (Arabica::DOM::Element<std::string>)content;
+ if(hasConditionMatch(ifElem)) {
+ // condition is true, execute all content up to an elseif, else or end
+ if (ifElem.hasChildNodes()) {
+ NodeList<std::string> childs = ifElem.getChildNodes();
+ for (unsigned int i = 0; i < childs.getLength(); i++) {
+ if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(childs.item(i)), "elsif") ||
+ boost::iequals(TAGNAME(childs.item(i)), "else"))
+ break;
+ executeContent(childs.item(i));
+ }
+ }
+ } else {
+ // condition does not match - do we have an elsif?
+ if (ifElem.hasChildNodes()) {
+ NodeList<std::string> elseifElem = ifElem.getElementsByTagName("elseif");
+ for (unsigned int i = 0; i < elseifElem.getLength(); i++) {
+ if (hasConditionMatch(elseifElem.item(i))) {
+ executeContent(elseifElem.item(i).getChildNodes());
+ goto ELSIF_ELEM_MATCH;
+ }
+ }
+ NodeList<std::string> elseElem = ifElem.getElementsByTagName("else");
+ if (elseElem.getLength() > 0)
+ executeContent(elseElem.item(0).getChildNodes());
+ }
+ }
+ ELSIF_ELEM_MATCH:;
+ } else if (boost::iequals(TAGNAME(content), "elseif")) {
+ std::cerr << "Found single elsif to evaluate!" << std::endl;
+ } else if (boost::iequals(TAGNAME(content), "else")) {
+ std::cerr << "Found single else to evaluate!" << std::endl;
+ } else if (boost::iequals(TAGNAME(content), "foreach")) {
+ // --- FOREACH --------------------------
+ if (_dataModel) {
+ if (HAS_ATTR(content, "array") && HAS_ATTR(content, "item")) {
+ std::string array = ATTR(content, "array");
+ std::string item = ATTR(content, "item");
+ std::string index = (HAS_ATTR(content, "index") ? ATTR(content, "index") : "");
+ uint32_t iterations = _dataModel->getLength(array);
+ _dataModel->pushContext(); // copy old and enter new context
+ for (uint32_t iteration = 0; iteration < iterations; iteration++) {
+ {
+ // assign array element to item
+ std::stringstream ss;
+ ss << array << "[" << iteration << "]";
+ _dataModel->assign(item, ss.str());
+ }
+ if (index.length() > 0) {
+ // assign iteration element to index
+ std::stringstream ss;
+ ss << iteration;
+ _dataModel->assign(index,ss.str());
+ }
+ if (content.hasChildNodes())
+ executeContent(content.getChildNodes());
+ }
+ _dataModel->popContext(); // leave stacked context
+ } else {
+ LOG(ERROR) << "Expected array and item attributes with foreach element!" << std::endl;
+ }
+ }
+ } else if (boost::iequals(TAGNAME(content), "log")) {
+ // --- LOG --------------------------
+ Arabica::DOM::Element<std::string> logElem = (Arabica::DOM::Element<std::string>)content;
+ if (logElem.hasAttribute("expr")) {
+ if (_dataModel) {
+ try {
+ std::cout << _dataModel->evalAsString(logElem.getAttribute("expr")) << std::endl;
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in expr attribute of log element:" << std::endl << e << std::endl;
+ }
+ } else {
+ std::cout << logElem.getAttribute("expr") << std::endl;
+ }
+ }
+ } else if (boost::iequals(TAGNAME(content), "assign")) {
+ // --- ASSIGN --------------------------
+ if (_dataModel && HAS_ATTR(content, "location") && HAS_ATTR(content, "expr")) {
+ try {
+ _dataModel->assign(ATTR(content, "location"), ATTR(content, "expr"));
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in attributes of assign element:" << std::endl << e << std::endl;
+ }
+ }
+ } else if (boost::iequals(TAGNAME(content), "validate")) {
+ // --- VALIDATE --------------------------
+ if (_dataModel) {
+ std::string location = (HAS_ATTR(content, "location") ? ATTR(content, "location") : "");
+ std::string schema = (HAS_ATTR(content, "schema") ? ATTR(content, "schema") : "");
+ _dataModel->validate(location, schema);
+ }
+ } else if (boost::iequals(TAGNAME(content), "script")) {
+ // --- SCRIPT --------------------------
+ if (_dataModel) {
+ if (HAS_ATTR(content, "src")) {
+ Arabica::SAX::InputSourceResolver resolver(Arabica::SAX::InputSource<std::string>(ATTR(content, "src")),
+ Arabica::default_string_adaptor<std::string>());
+ std::string srcContent(std::istreambuf_iterator<char>(*resolver.resolve()), std::istreambuf_iterator<char>());
+ try {
+ _dataModel->eval(srcContent);
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error while executing script element from '" << ATTR(content, "src") << "':" << std::endl << e << std::endl;
+ }
+ } else {
+ if (content.hasChildNodes()) {
+ // search for the text node with the actual script
+ if (content.getFirstChild().getNodeType() == Node_base::TEXT_NODE) {
+ try {
+ _dataModel->eval(content.getFirstChild().getNodeValue());
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error while executing script element" << std::endl << e << std::endl;
+ }
+ }
+ }
+ }
+ }
+ } else if (boost::iequals(TAGNAME(content), "send")) {
+ // --- SEND --------------------------
+ send(content);
+ } else if (boost::iequals(TAGNAME(content), "cancel")) {
+ // --- CANCEL --------------------------
+ std::string sendId;
+ try {
+ if (HAS_ATTR(content, "sendidexpr")) {
+ sendId = _dataModel->evalAsString(ATTR(content, "sendidexpr"));
+ } else if(HAS_ATTR(content, "sendid")) {
+ sendId = ATTR(content, "sendid");
+ } else {
+ LOG(ERROR) << "Expected sendidexpr or sendid attribute in cancel element";
+ return;
+ }
+
+ IOProcessor* ioProc = getIOProcessorForId(sendId);
+ if (ioProc != NULL) {
+ ioProc->cancel(sendId);
+ }
+
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error while executing cancel element" << std::endl << e << std::endl;
+ }
+
+ } else if (boost::iequals(TAGNAME(content), "invoke")) {
+ // --- INVOKE --------------------------
+ } else {
+ NodeList<std::string> executable = content.getChildNodes();
+ for (int i = 0; i < executable.getLength(); i++) {
+ executeContent(executable.item(i));
+ }
+ }
+}
+
+void Interpreter::cancelInvoke(const Arabica::DOM::Node<std::string>& content) {
+}
+
+void Interpreter::returnDoneEvent(const Arabica::DOM::Node<std::string>& state) {
+}
+
+void Interpreter::exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
+ NodeSet<std::string> statesToExit;
+ for (int i = 0; i < enabledTransitions.size(); i++) {
+ Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]);
+ if (!isTargetless(transition)) {
+ std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external");
+ NodeSet<std::string> tStates = getTargetStates(transition);
+ Arabica::DOM::Node<std::string> ancestor;
+ Arabica::DOM::Node<std::string> source = getSourceState(transition);
+
+ bool allDescendants = true;
+ for (int j = 0; j < tStates.size(); j++) {
+ if (!isDescendant(tStates[j], source)) {
+ allDescendants = false;
+ break;
+ }
+ }
+ if (boost::iequals(transitionType, "internal") &&
+ isCompound(source) &&
+ allDescendants)
+ {
+ ancestor = source;
+ } else {
+ NodeSet<std::string> tmpStates;
+ tmpStates.push_back(source);
+ tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end());
+
+ ancestor = findLCCA(tmpStates);
+ }
+
+ for (int j = 0; j < _configuration.size(); j++) {
+ if (isDescendant(_configuration[j], ancestor))
+ statesToExit.push_back(_configuration[j]);
+ }
+ }
+ }
+ // remove statesToExit from _statesToInvoke
+ std::list<Arabica::DOM::Node<std::string> > tmp;
+ for (int i = 0; i < _statesToInvoke.size(); i++) {
+ if (!isMember(_statesToInvoke[i], statesToExit)) {
+ tmp.push_back(_statesToInvoke[i]);
+ }
+ }
+ _statesToInvoke = NodeSet<std::string>();
+ _statesToInvoke.insert(_statesToInvoke.end(), tmp.begin(), tmp.end());
+
+ statesToExit.to_document_order();
+ statesToExit.reverse();
+
+ for (int i = 0; i < statesToExit.size(); i++) {
+ NodeSet<std::string> historyElems = _xpath.evaluate("" + _nsPrefix + "history", statesToExit[i]).asNodeSet();
+ for (int j = 0; j < historyElems.size(); j++) {
+ Arabica::DOM::Element<std::string> historyElem = (Arabica::DOM::Element<std::string>)historyElems[j];
+ std::string historyType = (historyElem.hasAttribute("type") ? historyElem.getAttribute("type") : "shallow");
+ NodeSet<std::string> historyNodes;
+ for (int k = 0; k < _configuration.size(); k++) {
+ if (boost::iequals(historyType, "deep")) {
+ if (isAtomic(_configuration[k]) && isDescendant(_configuration[k], statesToExit[i]))
+ historyNodes.push_back(_configuration[k]);
+ } else {
+ if (_configuration[k].getParentNode() == statesToExit[i])
+ historyNodes.push_back(_configuration[k]);
+ }
+ }
+ _historyValue[historyElem.getAttribute("id")] = historyNodes;
+ }
+ }
+
+ for (int i = 0; i < statesToExit.size(); i++) {
+ Arabica::XPath::NodeSet<std::string> onExitElems = _xpath.evaluate("" + _nsPrefix + "onexit", statesToExit[i]).asNodeSet();
+ for (int j = 0; j < onExitElems.size(); j++) {
+ executeContent(onExitElems[j]);
+ }
+ Arabica::XPath::NodeSet<std::string> invokeElems = _xpath.evaluate("" + _nsPrefix + "invoke", statesToExit[i]).asNodeSet();
+ for (int j = 0; j < invokeElems.size(); j++) {
+ cancelInvoke(invokeElems[j]);
+ }
+ }
+
+// std::cout << "States to Exit: ";
+// for (int i = 0; i < statesToExit.size(); i++) {
+// std::cout << ((Arabica::DOM::Element<std::string>)statesToExit[i]).getAttribute("id") << ", ";
+// }
+// std::cout << std::endl;
+
+ // remove statesToExit from _configuration
+ tmp.clear();
+ for (int i = 0; i < _configuration.size(); i++) {
+ if (!isMember(_configuration[i], statesToExit)) {
+ tmp.push_back(_configuration[i]);
+ }
+ }
+ _configuration = NodeSet<std::string>();
+ _configuration.insert(_configuration.end(), tmp.begin(), tmp.end());
+
+
+}
+
+void Interpreter::enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
+ NodeSet<std::string> statesToEnter;
+ NodeSet<std::string> statesForDefaultEntry;
+
+ for (int i = 0; i < enabledTransitions.size(); i++) {
+ Arabica::DOM::Element<std::string> transition = ((Arabica::DOM::Element<std::string>)enabledTransitions[i]);
+ if (!isTargetless(transition)) {
+ std::string transitionType = (boost::iequals(transition.getAttribute("type"), "internal") ? "internal" : "external");
+ NodeSet<std::string> tStates = getTargetStates(transition);
+ Arabica::DOM::Node<std::string> ancestor;
+ Arabica::DOM::Node<std::string> source = getSourceState(transition);
+ assert(source);
+
+ bool allDescendants = true;
+ for (int j = 0; j < tStates.size(); j++) {
+ if (!isDescendant(tStates[j], source)) {
+ allDescendants = false;
+ break;
+ }
+ }
+ if (boost::iequals(transitionType, "internal") &&
+ isCompound(source) &&
+ allDescendants)
+ {
+ ancestor = source;
+ } else {
+ NodeSet<std::string> tmpStates;
+ tmpStates.push_back(source);
+ tmpStates.insert(tmpStates.end(), tStates.begin(), tStates.end());
+
+ ancestor = findLCCA(tmpStates);
+ }
+
+ for (int j = 0; j < tStates.size(); j++) {
+ addStatesToEnter(tStates[j], statesToEnter, statesForDefaultEntry);
+ }
+
+ for (int j = 0; j < tStates.size(); j++) {
+ NodeSet<std::string> ancestors = getProperAncestors(tStates[j], ancestor);
+ for (int k = 0; k < ancestors.size(); k++) {
+ statesToEnter.push_back(ancestors[k]);
+ if(isParallel(ancestors[k])) {
+ NodeSet<std::string> childs = getChildStates(ancestors[k]);
+ for (int l = 0; l < childs.size(); l++) {
+ bool someIsDescendant = false;
+ for (int m = 0; m < statesToEnter.size(); m++) {
+ if (isDescendant(statesToEnter[m], childs[l])) {
+ someIsDescendant = true;
+ break;
+ }
+ }
+ if (!someIsDescendant) {
+ addStatesToEnter(childs[l], statesToEnter, statesForDefaultEntry);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ statesToEnter.to_document_order();
+ for (int i = 0; i < statesToEnter.size(); i++) {
+ Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)statesToEnter[i];
+ _configuration.push_back(stateElem);
+ _statesToInvoke.push_back(stateElem);
+ if (_binding == LATE && stateElem.getAttribute("isFirstEntry").size() > 0) {
+ Arabica::XPath::NodeSet<std::string> dataModelElems = _xpath.evaluate("" + _nsPrefix + "datamodel", stateElem).asNodeSet();
+ if(dataModelElems.size() > 0 && _dataModel) {
+ Arabica::XPath::NodeSet<std::string> dataElems = _xpath.evaluate("" + _nsPrefix + "data", dataModelElems[0]).asNodeSet();
+ for (int j = 0; j < dataElems.size(); j++) {
+ initializeData(dataElems[j]);
+ }
+ }
+ stateElem.setAttribute("isFirstEntry", "");
+ }
+ // execute onentry executable content
+ Arabica::XPath::NodeSet<std::string> onEntryElems = _xpath.evaluate("" + _nsPrefix + "onentry", stateElem).asNodeSet();
+ for (int j = 0; j < onEntryElems.size(); j++) {
+ executeContent(onEntryElems[j]);
+ }
+ if (isMember(stateElem, statesForDefaultEntry)) {
+ // execute initial transition content for compund states
+ Arabica::XPath::NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "initial/" + _nsPrefix + "transition", stateElem).asNodeSet();
+ for (int j = 0; j < transitions.size(); j++) {
+ executeContent(transitions[j]);
+ }
+ }
+
+ if (isFinal(stateElem)) {
+ Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)stateElem.getParentNode();
+
+ Event event;
+ event.name = "done.state." + parent.getAttribute("id");
+ Arabica::XPath::NodeSet<std::string> doneData = _xpath.evaluate("" + _nsPrefix + "donedata", stateElem).asNodeSet();
+ if (doneData.size() > 0) {
+ event.dom = doneData[0];
+ }
+ _internalQueue.push_back(event);
+
+ if (isParallel(parent.getParentNode())) {
+ Arabica::DOM::Element<std::string> grandParent = (Arabica::DOM::Element<std::string>)parent.getParentNode();
+
+ Arabica::XPath::NodeSet<std::string> childs = getChildStates(grandParent);
+ bool inFinalState = true;
+ for (int j = 0; j < childs.size(); j++) {
+ if (!isInFinalState(childs[j])) {
+ inFinalState = false;
+ break;
+ }
+ }
+ if (inFinalState) {
+ Event event;
+ event.name = "done.state." + grandParent.getAttribute("id");
+ _internalQueue.push_back(event);
+ }
+ }
+ }
+ }
+ for (int i = 0; i < _configuration.size(); i++) {
+ Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)_configuration[i];
+ if (isFinal(stateElem) && parentIsScxmlState(stateElem))
+ _running = false;
+ }
+}
+
+bool Interpreter::parentIsScxmlState(Arabica::DOM::Node<std::string> state) {
+ Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state;
+ Arabica::DOM::Element<std::string> parentElem = (Arabica::DOM::Element<std::string>)state.getParentNode();
+ if (boost::iequals(parentElem.getTagName(), "scxml"))
+ return true;
+ return false;
+}
+
+bool Interpreter::isInFinalState(const Arabica::DOM::Node<std::string>& state) {
+ if (isCompound(state)) {
+ Arabica::XPath::NodeSet<std::string> childs = getChildStates(state);
+ for (int i = 0; i < childs.size(); i++) {
+ if (isFinal(childs[i]) && isMember(childs[i], _configuration))
+ return true;
+ }
+ } else if (isParallel(state)) {
+ Arabica::XPath::NodeSet<std::string> childs = getChildStates(state);
+ for (int i = 0; i < childs.size(); i++) {
+ if (!isInFinalState(childs[i]))
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Interpreter::isMember(const Arabica::DOM::Node<std::string>& node, const Arabica::XPath::NodeSet<std::string>& set) {
+ for (int i = 0; i < set.size(); i++) {
+ if (set[i] == node)
+ return true;
+ }
+ return false;
+}
+
+void Interpreter::addStatesToEnter(const Arabica::DOM::Node<std::string>& state,
+ Arabica::XPath::NodeSet<std::string>& statesToEnter,
+ Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
+ std::string stateId = ((Arabica::DOM::Element<std::string>)state).getAttribute("id");
+ if (isHistory(state)) {
+ if (_historyValue.find(stateId) != _historyValue.end()) {
+ Arabica::XPath::NodeSet<std::string> historyValue = _historyValue[stateId];
+ for (int i = 0; i < historyValue.size(); i++) {
+ addStatesToEnter(historyValue[i], statesToEnter, statesForDefaultEntry);
+ NodeSet<std::string> ancestors = getProperAncestors(historyValue[i], state);
+ for (int j = 0; j < ancestors.size(); j++) {
+ statesToEnter.push_back(ancestors[j]);
+ }
+ }
+ } else {
+ NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", state).asNodeSet();
+ for (int i = 0; i < transitions.size(); i++) {
+ NodeSet<std::string> targets = getTargetStates(transitions[i]);
+ for (int j = 0; j < targets.size(); j++) {
+ addStatesToEnter(targets[j], statesToEnter, statesForDefaultEntry);
+ }
+ }
+ }
+ } else {
+ statesToEnter.push_back(state);
+ if (isCompound(state)) {
+ statesForDefaultEntry.push_back(state);
+ NodeSet<std::string> tStates = getTargetStates(getInitialState(state));
+ for (int i = 0; i < tStates.size(); i++) {
+ addStatesToEnter(tStates[i], statesToEnter, statesForDefaultEntry);
+ }
+ } else if(isParallel(state)) {
+ NodeSet<std::string> childStates = getChildStates(state);
+ for (int i = 0; i < childStates.size(); i++) {
+ addStatesToEnter(childStates[i], statesToEnter, statesForDefaultEntry);
+ }
+ }
+ }
+}
+
+Arabica::XPath::NodeSet<std::string> Interpreter::getChildStates(const Arabica::DOM::Node<std::string>& state) {
+ Arabica::XPath::NodeSet<std::string> childs;
+ Arabica::XPath::NodeSet<std::string> stateChilds = _xpath.evaluate("" + _nsPrefix + "state", state).asNodeSet();
+ Arabica::XPath::NodeSet<std::string> parallelChilds = _xpath.evaluate("" + _nsPrefix + "parallel", state).asNodeSet();
+
+ childs.insert(childs.begin(), stateChilds.begin(), stateChilds.end());
+ childs.insert(childs.begin(), parallelChilds.begin(), parallelChilds.end());
+
+ return childs;
+}
+
+Arabica::DOM::Node<std::string> Interpreter::findLCCA(const Arabica::XPath::NodeSet<std::string>& states) {
+// std::cout << "findLCCA: ";
+// for (int i = 0; i < states.size(); i++) {
+// std::cout << ((Arabica::DOM::Element<std::string>)states[i]).getAttribute("id") << " - " << states[i].getLocalName() << ", ";
+// }
+// std::cout << std::flush;
+
+ Arabica::XPath::NodeSet<std::string> ancestors = getProperAncestors(states[0], Arabica::DOM::Node<std::string>());
+ ancestors.push_back(states[0]); // state[0] may already be the ancestor - bug in W3C spec?
+ Arabica::DOM::Node<std::string> ancestor;
+ for (int i = 0; i < ancestors.size(); i++) {
+ for (int j = 0; j < states.size(); j++) {
+// std::cout << "Checking " << TAGNAME(state) << " and " << TAGNAME(ancestors[i]) << std::endl;
+ if (!isDescendant(states[j], ancestors[i]) && (states[j] != ancestors[i]))
+ goto NEXT_ANCESTOR;
+ }
+ ancestor = ancestors[i];
+ break;
+ NEXT_ANCESTOR:;
+ }
+ assert(ancestor);
+// std::cout << " -> " << ((Arabica::DOM::Element<std::string>)ancestor).getAttribute("id") << " " << ancestor.getLocalName() << std::endl;
+ return ancestor;
+}
+
+Arabica::DOM::Node<std::string> Interpreter::getState(const std::string& stateId) {
+ // first try atomic and compund states
+ NodeSet<std::string> target = _xpath.evaluate("//" + _nsPrefix + "state[@id='" + stateId + "']", _doc).asNodeSet();
+ if (target.size() > 0)
+ goto FOUND;
+
+ // now parallel states
+ target = _xpath.evaluate("//" + _nsPrefix + "parallel[@id='" + stateId + "']", _doc).asNodeSet();
+ if (target.size() > 0)
+ goto FOUND;
+
+ // now final states
+ target = _xpath.evaluate("//" + _nsPrefix + "final[@id='" + stateId + "']", _doc).asNodeSet();
+ if (target.size() > 0)
+ goto FOUND;
+
+FOUND:
+ if (target.size() > 0) {
+ assert(target.size() == 1);
+ return target[0];
+ }
+ // return the empty node
+ return Arabica::DOM::Node<std::string>();
+}
+
+Arabica::DOM::Node<std::string> Interpreter::getSourceState(const Arabica::DOM::Node<std::string>& transition) {
+ if (boost::iequals(TAGNAME(transition.getParentNode()), "initial"))
+ return transition.getParentNode().getParentNode();
+ return transition.getParentNode();
+}
+
+ /**
+ * In a conformant SCXML document, a compound state may specify either an "initial"
+ * attribute or an <initial> element, but not both. See 3.6 <initial> for a
+ * discussion of the difference between the two notations. If neither the "initial"
+ * attribute nor an <initial> element is specified, the SCXML Processor must use
+ * the first child state in document order as the default initial state.
+ */
+Arabica::DOM::Node<std::string> Interpreter::getInitialState(Arabica::DOM::Node<std::string> state) {
+ if (!state) {
+ state = _doc.getFirstChild();
+ while(!isState(state))
+ state = state.getNextSibling();
+ }
+
+ assert(isCompound(state) || isParallel(state));
+
+ // initial attribute at element
+ Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state;
+ if (stateElem.hasAttribute("initial")) {
+ return getState(stateElem.getAttribute("initial"));
+ }
+
+ // initial element as child
+ NodeSet<std::string> initialStates = _xpath.evaluate("" + _nsPrefix + "initial", state).asNodeSet();
+ if(initialStates.size() == 1)
+ return initialStates[0];
+
+ // first child state
+ NodeList<std::string> childs = state.getChildNodes();
+ for (int i = 0; i < childs.getLength(); i++) {
+ if (isState(childs.item(i)))
+ return childs.item(i);
+ }
+ // nothing found
+ return Arabica::DOM::Node<std::string>();
+}
+
+NodeSet<std::string> Interpreter::getTargetStates(const Arabica::DOM::Node<std::string>& transition) {
+ NodeSet<std::string> targetStates;
+ std::string targetId = ((Arabica::DOM::Element<std::string>)transition).getAttribute("target");
+
+ std::vector<std::string> targetIds = Interpreter::tokenizeIdRefs(ATTR(transition, "target"));
+ for (int i = 0; i < targetIds.size(); i++) {
+ targetStates.push_back(getState(targetIds[i]));
+ }
+ return targetStates;
+}
+
+std::vector<std::string> Interpreter::tokenizeIdRefs(const std::string& idRefs) {
+ std::vector<std::string> ids;
+
+ if (idRefs.length() > 0) {
+ std::istringstream iss(idRefs);
+
+ std::copy(std::istream_iterator<std::string>(iss),
+ std::istream_iterator<std::string>(),
+ std::back_inserter<std::vector<std::string> >(ids));
+ }
+
+ return ids;
+}
+
+NodeSet<std::string> Interpreter::getProperAncestors(const Arabica::DOM::Node<std::string>& s1,
+ const Arabica::DOM::Node<std::string>& s2) {
+ NodeSet<std::string> ancestors;
+ if (isState(s1)) {
+ Arabica::DOM::Node<std::string> node = s1;
+ while((node = node.getParentNode())) {
+ if (!isState(node))
+ break;
+ if (!boost::iequals(TAGNAME(node), "parallel") && !boost::iequals(TAGNAME(node), "state") && !boost::iequals(TAGNAME(node), "scxml"))
+ break;
+ if (node == s2)
+ break;
+ ancestors.push_back(node);
+ }
+ }
+ return ancestors;
+}
+
+bool Interpreter::isDescendant(const Arabica::DOM::Node<std::string>& s1,
+ const Arabica::DOM::Node<std::string>& s2) {
+ Arabica::DOM::Node<std::string> parent = s1.getParentNode();
+ while(parent) {
+ if (s2 == parent)
+ return true;
+ parent = parent.getParentNode();
+ }
+ return false;
+}
+
+bool Interpreter::isTargetless(const Arabica::DOM::Node<std::string>& transition) {
+ if (transition.hasAttributes()) {
+ if (((Arabica::DOM::Element<std::string>)transition).hasAttribute("target"))
+ return false;
+ }
+ return true;
+}
+
+bool Interpreter::isWithinSameChild(const Arabica::DOM::Node<std::string>& transition) {
+ if (!isTargetless(transition)) {
+ std::string target = ((Arabica::DOM::Element<std::string>)transition).getAttribute("target");
+ Arabica::XPath::XPath<std::string> xpath;
+ // @todo: do we need to look at parallel as well?
+ if (xpath.evaluate("" + _nsPrefix + "state[id=\"" + target + "\"]", transition.getParentNode()).asNodeSet().size() > 0)
+ return true;
+ }
+ return false;
+}
+
+bool Interpreter::isState(const Arabica::DOM::Node<std::string>& state) {
+ if (!state)
+ return false;
+ if (state.getNodeType() != Arabica::DOM::Node_base::ELEMENT_NODE)
+ return false;
+
+ std::string tagName = TAGNAME(state);
+ if (boost::iequals("state", tagName))
+ return true;
+ if (boost::iequals("scxml", tagName))
+ return true;
+ if (boost::iequals("parallel", tagName))
+ return true;
+ if (boost::iequals("final", tagName))
+ return true;
+ return false;
+}
+
+bool Interpreter::isFinal(const Arabica::DOM::Node<std::string>& state) {
+ std::string tagName = TAGNAME(state);
+ if (boost::iequals("final", tagName))
+ return true;
+ if (HAS_ATTR(state, "final") && boost::iequals("true", ATTR(state, "final")))
+ return true;
+ return false;
+}
+
+bool Interpreter::isPseudoState(const Arabica::DOM::Node<std::string>& state) {
+ std::string tagName = TAGNAME(state);
+ if (boost::iequals("initial", tagName))
+ return true;
+ if (boost::iequals("history", tagName))
+ return true;
+ return false;
+}
+
+bool Interpreter::isTransitionTarget(const Arabica::DOM::Node<std::string>& elem) {
+ return (isState(elem) || boost::iequals(TAGNAME(elem), "history"));
+}
+
+bool Interpreter::isAtomic(const Arabica::DOM::Node<std::string>& state) {
+ if (boost::iequals("final", TAGNAME(state)))
+ return true;
+
+ // I will assume that parallel states are not meant to be atomic.
+ if (boost::iequals("parallel", TAGNAME(state)))
+ return false;
+
+ Arabica::DOM::NodeList<std::string> childs = state.getChildNodes();
+ for (unsigned int i = 0; i < childs.getLength(); i++) {
+ if (isState(childs.item(i)))
+ return false;
+ }
+ return true;
+}
+
+bool Interpreter::isHistory(const Arabica::DOM::Node<std::string>& state) {
+ if (boost::iequals("history", TAGNAME(state)))
+ return true;
+ return false;
+}
+
+bool Interpreter::isParallel(const Arabica::DOM::Node<std::string>& state) {
+ if (!isState(state))
+ return false;
+ if (boost::iequals("parallel", TAGNAME(state)))
+ return true;
+ return false;
+}
+
+
+bool Interpreter::isCompound(const Arabica::DOM::Node<std::string>& state) {
+ if (!isState(state))
+ return false;
+
+ if (boost::iequals(TAGNAME(state), "parallel"))
+ return false;
+
+ Arabica::DOM::NodeList<std::string> childs = state.getChildNodes();
+ for (unsigned int i = 0; i < childs.getLength(); i++) {
+ if (isState(childs.item(i)))
+ return true;
+ }
+ return false;
+}
+
+void Interpreter::setupIOProcessors() {
+ std::map<std::string, IOProcessor*>::iterator ioProcIter = Factory::getInstance()->_ioProcessors.begin();
+ while(ioProcIter != Factory::getInstance()->_ioProcessors.end()) {
+ _ioProcessors[ioProcIter->first] = Factory::getIOProcessor(ioProcIter->first, this);
+ if (_dataModel) {
+ try {
+ _dataModel->assign("_ioprocessors['" + ioProcIter->first + "']", "'" + _ioProcessors[ioProcIter->first]->getURL() + "'");
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error when setting _ioprocessors:" << std::endl << e << std::endl;
+ }
+ } else {
+ LOG(INFO) << "Not registering " << ioProcIter->first << " at _ioprocessors in datamodel, no datamodel specified";
+ }
+ ioProcIter++;
+ }
+}
+
+IOProcessor* Interpreter::getIOProcessor(const std::string& type) {
+ if (_ioProcessors.find(type) == _ioProcessors.end()) {
+ LOG(ERROR) << "No ioProcessor known for type " << type;
+ return NULL;
+ }
+ return _ioProcessors[type];
+}
+
+IOProcessor* Interpreter::getIOProcessorForId(const std::string& sendId) {
+ if (_ioProcessorsIds.find(sendId) == _ioProcessorsIds.end()) {
+ LOG(ERROR) << "No ioProcessor with pending send id " << sendId << sendId;
+ return NULL;
+ }
+ return _ioProcessorsIds[sendId];
+}
+
+bool Interpreter::validate() {
+ bool validationErrors = false;
+
+ if (!_doc) {
+ LOG(ERROR) << "Document " << _url << " was not parsed successfully" << std::endl;
+ return false;
+ }
+
+ // semantic issues ------------
+ if ((_xpath.evaluate("/" + _nsPrefix + "scxml/@datamodel", _doc).asNodeSet().size() == 0) &&
+ _xpath.evaluate("/" + _nsPrefix + "scxml/" + _nsPrefix + "script", _doc).asNodeSet().size() > 0) {
+ LOG(ERROR) << "Script elements used, but no datamodel specified" << std::endl;
+ }
+
+ // element issues ------------
+ Arabica::XPath::NodeSet<std::string> scxmlElems = _xpath.evaluate(_nsPrefix + "scxml", _doc).asNodeSet();
+ if (scxmlElems.size() > 0)
+ LOG(ERROR) << "More than one scxml element found" << std::endl;
+ for (unsigned int i = 0; i < scxmlElems.size(); i++) {
+ if (!HAS_ATTR(scxmlElems[i], "xmlns"))
+ LOG(ERROR) << "scxml element has no xmlns attribute" << std::endl;
+ if (!HAS_ATTR(scxmlElems[i], "version"))
+ LOG(ERROR) << "scxml element has no version attribute" << std::endl;
+ NodeList<std::string> childs = scxmlElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(childs.item(j)), "state") ||
+ boost::iequals(TAGNAME(childs.item(j)), "parallel") ||
+ boost::iequals(TAGNAME(childs.item(j)), "final") ||
+ boost::iequals(TAGNAME(childs.item(j)), "datamodel") ||
+ boost::iequals(TAGNAME(childs.item(j)), "script")) {
+ LOG(ERROR) << "scxml element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> stateElems = _xpath.evaluate(_nsPrefix + "state", _doc).asNodeSet();
+ for (unsigned int i = 0; i < stateElems.size(); i++) {
+ NodeList<std::string> childs = stateElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(childs.item(j)), "onentry") ||
+ boost::iequals(TAGNAME(childs.item(j)), "onexit") ||
+ boost::iequals(TAGNAME(childs.item(j)), "transition") ||
+ boost::iequals(TAGNAME(childs.item(j)), "initial") ||
+ boost::iequals(TAGNAME(childs.item(j)), "state") ||
+ boost::iequals(TAGNAME(childs.item(j)), "parallel") ||
+ boost::iequals(TAGNAME(childs.item(j)), "final") ||
+ boost::iequals(TAGNAME(childs.item(j)), "history") ||
+ boost::iequals(TAGNAME(childs.item(j)), "datamodel") ||
+ boost::iequals(TAGNAME(childs.item(j)), "invoke")) {
+ LOG(ERROR) << "state element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> parallelElems = _xpath.evaluate(_nsPrefix + "parallel", _doc).asNodeSet();
+ for (unsigned int i = 0; i < parallelElems.size(); i++) {
+ NodeList<std::string> childs = parallelElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(childs.item(j)), "onentry") ||
+ boost::iequals(TAGNAME(childs.item(j)), "onexit") ||
+ boost::iequals(TAGNAME(childs.item(j)), "transition") ||
+ boost::iequals(TAGNAME(childs.item(j)), "state") ||
+ boost::iequals(TAGNAME(childs.item(j)), "parallel") ||
+ boost::iequals(TAGNAME(childs.item(j)), "history") ||
+ boost::iequals(TAGNAME(childs.item(j)), "datamodel") ||
+ boost::iequals(TAGNAME(childs.item(j)), "invoke")) {
+ LOG(ERROR) << "parallel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> transitionElems = _xpath.evaluate(_nsPrefix + "transition", _doc).asNodeSet();
+ for (unsigned int i = 0; i < transitionElems.size(); i++) {
+ if (HAS_ATTR(transitionElems[i], "cond") &&
+ !HAS_ATTR(transitionElems[i], "event")) {
+ LOG(ERROR) << "transition element with cond attribute but without event attribute not allowed" << std::endl;
+ }
+ NodeList<std::string> childs = scxmlElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> initialElems = _xpath.evaluate(_nsPrefix + "initial", _doc).asNodeSet();
+ for (unsigned int i = 0; i < initialElems.size(); i++) {
+ NodeList<std::string> childs = initialElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(childs.item(j)), "transition")) {
+ LOG(ERROR) << "initial element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> finalElems = _xpath.evaluate(_nsPrefix + "final", _doc).asNodeSet();
+ for (unsigned int i = 0; i < finalElems.size(); i++) {
+ NodeList<std::string> childs = finalElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (!boost::iequals(TAGNAME(childs.item(j)), "onentry") ||
+ !boost::iequals(TAGNAME(childs.item(j)), "onexit") ||
+ !boost::iequals(TAGNAME(childs.item(j)), "donedata")) {
+ LOG(ERROR) << "parallel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> historyElems = _xpath.evaluate(_nsPrefix + "history", _doc).asNodeSet();
+ for (unsigned int i = 0; i < historyElems.size(); i++) {
+ NodeList<std::string> childs = historyElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (boost::iequals(TAGNAME(childs.item(j)), "transition")) {
+ LOG(ERROR) << "history element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> datamodelElems = _xpath.evaluate(_nsPrefix + "datamodel", _doc).asNodeSet();
+ for (unsigned int i = 0; i < datamodelElems.size(); i++) {
+ NodeList<std::string> childs = datamodelElems[i].getChildNodes();
+ for (unsigned int j = 0; j < childs.getLength(); j++) {
+ if (childs.item(j).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (!boost::iequals(TAGNAME(childs.item(j)), "data")) {
+ LOG(ERROR) << "datamodel element has unspecified child " << TAGNAME(childs.item(j)) << std::endl;
+ }
+ }
+ }
+
+ Arabica::XPath::NodeSet<std::string> dataElems = _xpath.evaluate(_nsPrefix + "data", _doc).asNodeSet();
+ for (unsigned int i = 0; i < dataElems.size(); i++) {
+ if (!HAS_ATTR(dataElems[i], "id"))
+ LOG(ERROR) << "data element has no id attribute" << std::endl;
+ }
+
+ return validationErrors;
+}
+
+void Interpreter::dump() {
+ if (!_doc)
+ return;
+ dump(_doc);
+}
+
+void Interpreter::dump(const Arabica::DOM::Node<std::string>& node, int lvl) {
+ if (!node)
+ return;
+
+ std::string indent = "";
+ for (unsigned int i = 0; i < lvl; i++)
+ indent += " ";
+
+ std::cout << indent;
+ switch(node.getNodeType()) {
+ case Arabica::DOM::Node_base::ELEMENT_NODE: {
+ std::cout << "ELEMENT_NODE: ";
+ Arabica::DOM::Element<std::string> elem = (Arabica::DOM::Element<std::string>)node;
+ break;
+ }
+ case Arabica::DOM::Node_base::ATTRIBUTE_NODE:
+ std::cout << "ATTRIBUTE_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::TEXT_NODE:
+ std::cout << "TEXT_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::CDATA_SECTION_NODE:
+ std::cout << "CDATA_SECTION_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::ENTITY_REFERENCE_NODE:
+ std::cout << "ENTITY_REFERENCE_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::ENTITY_NODE:
+ std::cout << "ENTITY_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::PROCESSING_INSTRUCTION_NODE:
+ std::cout << "PROCESSING_INSTRUCTION_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::COMMENT_NODE:
+ std::cout << "COMMENT_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::DOCUMENT_NODE:
+ std::cout << "DOCUMENT_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::DOCUMENT_TYPE_NODE:
+ std::cout << "DOCUMENT_TYPE_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::DOCUMENT_FRAGMENT_NODE:
+ std::cout << "DOCUMENT_FRAGMENT_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::NOTATION_NODE:
+ std::cout << "NOTATION_NODE: ";
+ break;
+ case Arabica::DOM::Node_base::MAX_TYPE:
+ std::cout << "MAX_TYPE: ";
+ break;
+ }
+ std::cout << node.getNamespaceURI() << " " << node.getNodeName() << std::endl;
+
+ if (node.getNodeValue().length() > 0 && node.getNodeValue().find_first_not_of(" \t\n") != std::string::npos)
+ std::cout << indent << "Value: '" << node.getNodeValue() << "'" << std::endl;
+
+
+ if (node.hasAttributes()) {
+ Arabica::DOM::NamedNodeMap<std::string> attrs = node.getAttributes();
+ for (unsigned int i = 0; i < attrs.getLength(); i++) {
+ std::cout << indent << " " << attrs.item(i).getLocalName() << " = " << attrs.item(i).getNodeValue() << " (" << std::endl;
+ std::cout << indent << " namespace: " << attrs.item(i).getNamespaceURI() << std::endl;
+ std::cout << indent << " nodeName: " << attrs.item(i).getNodeName() << std::endl;
+ std::cout << indent << " prefix: " << attrs.item(i).getPrefix() << std::endl;
+ std::cout << indent << " )" << std::endl;
+ }
+ }
+
+ if (node.hasChildNodes()) {
+ Arabica::DOM::NodeList<std::string> childs = node.getChildNodes();
+ for (unsigned int i = 0; i < childs.getLength(); i++) {
+ dump(childs.item(i), lvl+1);
+ }
+ }
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
new file mode 100644
index 0000000..fb913d1
--- /dev/null
+++ b/src/uscxml/Interpreter.h
@@ -0,0 +1,314 @@
+#ifndef RUNTIME_H_SQ1MBKGN
+#define RUNTIME_H_SQ1MBKGN
+
+#include <boost/uuid/uuid_generators.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <iostream>
+#include <set>
+#include <map>
+
+#include <XPath/XPath.hpp>
+#include <DOM/Document.hpp>
+
+#include <DOM/SAX2DOM/SAX2DOM.hpp>
+#include <SAX/helpers/CatchErrorHandler.hpp>
+
+#include "uscxml/concurrency/tinythread.h"
+#include "uscxml/concurrency/BlockingQueue.h"
+#include "uscxml/Message.h"
+#include "uscxml/Factory.h"
+
+namespace uscxml {
+
+ class Interpreter {
+ public:
+ enum Binding {
+ EARLY = 0,
+ LATE = 1
+ };
+
+ Interpreter(const std::string& url);
+ virtual ~Interpreter();
+
+ void start();
+ void stop();
+ static void run(void*);
+
+ void interpret();
+ bool validate();
+
+ void waitForStabilization();
+
+ void receive(Event& event) { _externalQueue.push(event); }
+ void receiveInternal(Event& event) { _internalQueue.push_back(event); }
+ Arabica::XPath::NodeSet<std::string> getConfiguration() { return _configuration; }
+ Arabica::DOM::Node<std::string> getState(const std::string& stateId);
+
+ const std::string& getName() { return _name; }
+ const std::string& getSessionId() { return _sessionId; }
+
+ static bool isMember(const Arabica::DOM::Node<std::string>& node, const Arabica::XPath::NodeSet<std::string>& set);
+
+ void dump();
+ static void dump(const Arabica::DOM::Node<std::string>& node, int lvl = 0);
+
+ protected:
+ void normalize(const Arabica::DOM::Node<std::string>& node);
+ void setupIOProcessors();
+
+ void mainEventLoop();
+
+ bool _stable;
+ tthread::thread* _thread;
+ tthread::mutex _mutex;
+ tthread::condition_variable _stabilized;
+
+ std::string _url;
+ Arabica::DOM::Document<std::string> _doc;
+ Arabica::DOM::Element<std::string> _scxml;
+ Arabica::XPath::XPath<std::string> _xpath;
+ Arabica::XPath::StandardNamespaceContext<std::string> _nsContext;
+ std::string _nsPrefix;
+
+ bool _running;
+ Binding _binding;
+ Arabica::XPath::NodeSet<std::string> _configuration;
+ Arabica::XPath::NodeSet<std::string> _statesToInvoke;
+
+ DataModel* _dataModel;
+ std::map<std::string, Arabica::XPath::NodeSet<std::string> > _historyValue;
+
+ std::list<Event > _internalQueue;
+ uscxml::concurrency::BlockingQueue<Event> _externalQueue;
+
+ void microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
+ void exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
+ void enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
+ void executeTransitionContent(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
+ void executeContent(const Arabica::DOM::Node<std::string>& content);
+ void executeContent(const Arabica::DOM::NodeList<std::string>& content);
+ void initializeData(const Arabica::DOM::Node<std::string>& data);
+ void exitInterpreter();
+
+ void addStatesToEnter(const Arabica::DOM::Node<std::string>& state,
+ Arabica::XPath::NodeSet<std::string>& statesToEnter,
+ Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry);
+
+ Arabica::XPath::NodeSet<std::string> selectEventlessTransitions();
+ Arabica::XPath::NodeSet<std::string> selectTransitions(const std::string& event);
+ Arabica::XPath::NodeSet<std::string> getTargetStates(const Arabica::DOM::Node<std::string>& transition);
+ Arabica::XPath::NodeSet<std::string> getChildStates(const Arabica::DOM::Node<std::string>& state);
+ Arabica::DOM::Node<std::string> getInitialState(Arabica::DOM::Node<std::string> state = Arabica::DOM::Node<std::string>());
+ Arabica::DOM::Node<std::string> getSourceState(const Arabica::DOM::Node<std::string>& transition);
+ Arabica::DOM::Node<std::string> findLCCA(const Arabica::XPath::NodeSet<std::string>& states);
+ static Arabica::XPath::NodeSet<std::string> getProperAncestors(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2);
+
+
+ void send(const std::string invokeId, Event& event);
+ void send(const Arabica::DOM::Node<std::string>& element);
+ void invoke(const Arabica::DOM::Node<std::string>& element);
+ void cancelInvoke(const Arabica::DOM::Node<std::string>& content);
+ void returnDoneEvent(const Arabica::DOM::Node<std::string>& state);
+
+ static bool nameMatch(const std::string& transitionEvent, const std::string& event);
+ Arabica::XPath::NodeSet<std::string> filterPreempted(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
+ bool hasConditionMatch(const Arabica::DOM::Node<std::string>& conditional);
+ bool isPreemptingTransition(const Arabica::DOM::Node<std::string>& t1, const Arabica::DOM::Node<std::string>& t2);
+ bool isInFinalState(const Arabica::DOM::Node<std::string>& state);
+ bool isWithinSameChild(const Arabica::DOM::Node<std::string>& transition);
+ bool parentIsScxmlState(Arabica::DOM::Node<std::string> state);
+
+ static bool isState(const Arabica::DOM::Node<std::string>& state);
+ static bool isPseudoState(const Arabica::DOM::Node<std::string>& state);
+ static bool isTransitionTarget(const Arabica::DOM::Node<std::string>& elem);
+ static bool isTargetless(const Arabica::DOM::Node<std::string>& transition);
+ static bool isAtomic(const Arabica::DOM::Node<std::string>& state);
+ static bool isFinal(const Arabica::DOM::Node<std::string>& state);
+ static bool isHistory(const Arabica::DOM::Node<std::string>& state);
+ static bool isParallel(const Arabica::DOM::Node<std::string>& state);
+ static bool isCompound(const Arabica::DOM::Node<std::string>& state);
+ static bool isDescendant(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2);
+
+ static std::vector<std::string> tokenizeIdRefs(const std::string& idRefs);
+
+ static boost::uuids::random_generator uuidGen;
+ static const std::string getUUID();
+
+ std::string _name;
+ std::string _sessionId;
+
+ IOProcessor* getIOProcessor(const std::string& type);
+ IOProcessor* getIOProcessorForId(const std::string& sendId);
+
+ std::map<std::string, IOProcessor*> _ioProcessorsIds;
+ std::map<std::string, IOProcessor*> _ioProcessors;
+
+ };
+
+#if 0
+ class SCXMLParseHandler :
+ public Arabica::SAX::EntityResolver<std::string>,
+ public Arabica::SAX::DTDHandler<std::string>,
+ public Arabica::SAX::ContentHandler<std::string>,
+ public Arabica::SAX::CatchErrorHandler<std::string>,
+ public Arabica::SAX::LexicalHandler<std::string>,
+ public Arabica::SAX::DeclHandler<std::string>
+ {
+ public:
+ SCXMLParseHandler() { }
+ virtual ~SCXMLParseHandler() { }
+
+ // EntityResolver
+ virtual InputSourceT resolveEntity(const std::string& publicId , const std::string& systemId) {
+ return InputSourceT();
+ }
+
+ // DTDHandler
+ virtual void notationDecl(const std::string& name,
+ const std::string& publicId,
+ const std::string& systemId) {
+ std::cout << "notationDecl" << std::endl;
+ std::cout << " name:" << name << std::endl;
+ std::cout << " publicId:" << publicId << std::endl;
+ std::cout << " systemId:" << systemId << std::endl;
+ }
+ virtual void unparsedEntityDecl(const std::string& name,
+ const std::string& publicId,
+ const std::string& systemId,
+ const std::string& notationName) {
+ std::cout << "unparsedEntityDecl" << std::endl;
+ std::cout << " name:" << name << std::endl;
+ std::cout << " publicId:" << publicId << std::endl;
+ std::cout << " systemId:" << systemId << std::endl;
+ std::cout << " notationName:" << notationName << std::endl;
+ }
+
+ // ContentHandler
+ virtual void setDocumentLocator(const LocatorT& locator) {
+ std::cout << "setDocumentLocator" << std::endl;
+ }
+ virtual void startDocument() {
+ std::cout << "startDocument" << std::endl;
+ }
+ virtual void endDocument() {
+ std::cout << "endDocument" << std::endl;
+ }
+ virtual void startPrefixMapping(const std::string& prefix, const std::string& uri) {
+ std::cout << "startPrefixMapping" << std::endl;
+ std::cout << " prefix:" << prefix << std::endl;
+ std::cout << " uri:" << uri << std::endl;
+ }
+ virtual void endPrefixMapping(const std::string& prefix) {
+ std::cout << "endPrefixMapping" << std::endl;
+ std::cout << " prefix:" << prefix << std::endl;
+ }
+ virtual void startElement(const std::string& namespaceURI, const std::string& localName,
+ const std::string& qName, const AttributesT& atts) {
+ std::cout << "startElement" << std::endl;
+ std::cout << " namespaceURI:" << namespaceURI << std::endl;
+ std::cout << " localName:" << localName << std::endl;
+ std::cout << " qName:" << qName << std::endl;
+ std::cout << " atts:" << atts.getLength() << std::endl;
+ }
+ virtual void endElement(const std::string& namespaceURI, const std::string& localName,
+ const std::string& qName) {
+ std::cout << "endElement" << std::endl;
+ std::cout << " namespaceURI:" << namespaceURI << std::endl;
+ std::cout << " localName:" << localName << std::endl;
+ std::cout << " qName:" << qName << std::endl;
+ }
+ virtual void characters(const std::string& ch) {
+ std::cout << "characters" << std::endl;
+ std::cout << " ch:" << ch << std::endl;
+ }
+ virtual void ignorableWhitespace(const std::string& ch) {
+ std::cout << "ignorableWhitespace" << std::endl;
+ std::cout << " ch:" << ch << std::endl;
+ }
+ virtual void processingInstruction(const std::string& target, const std::string& data) {
+ std::cout << "processingInstruction" << std::endl;
+ std::cout << " target:" << target << std::endl;
+ std::cout << " data:" << data << std::endl;
+ }
+ virtual void skippedEntity(const std::string& name) {
+ std::cout << "skippedEntity" << std::endl;
+ std::cout << " name:" << name << std::endl;
+ }
+
+ // ErrorHandler
+ virtual void warning(const SAXParseExceptionT& e) { Arabica::SAX::CatchErrorHandler<std::string>::warning(e); }
+ virtual void error(const SAXParseExceptionT& e) { Arabica::SAX::CatchErrorHandler<std::string>::error(e); }
+ virtual void fatalError(const SAXParseExceptionT& e) {
+ Arabica::SAX::CatchErrorHandler<std::string>::fatalError(e);
+ }
+
+ // LexicalHandler
+ virtual void startDTD(const std::string& name,
+ const std::string& publicId,
+ const std::string& systemId) {
+ std::cout << "startDTD" << std::endl;
+ std::cout << " name:" << name << std::endl;
+ std::cout << " publicId:" << publicId << std::endl;
+ std::cout << " systemId:" << systemId << std::endl;
+ }
+
+ virtual void endDTD() {
+ std::cout << "endDTD" << std::endl;
+ }
+ virtual void startEntity(const std::string& name) {
+ std::cout << "startEntity" << std::endl;
+ std::cout << " name:" << name << std::endl;
+ }
+ virtual void endEntity(const std::string& name) {
+ std::cout << "endEntity" << std::endl;
+ std::cout << " name:" << name << std::endl;
+ }
+ virtual void startCDATA() {
+ std::cout << "startCDATA" << std::endl;
+ }
+ virtual void endCDATA() {
+ std::cout << "endCDATA" << std::endl;
+ }
+ virtual void comment(const std::string& text) {
+ std::cout << "comment" << std::endl;
+ std::cout << " text:" << text << std::endl;
+ }
+
+ // DeclHandler
+ virtual void elementDecl(const std::string& name, const std::string& model) {
+ std::cout << "elementDecl" << std::endl;
+ std::cout << " name:" << name << std::endl;
+ std::cout << " model:" << model << std::endl;
+ }
+ virtual void attributeDecl(const std::string& elementName,
+ const std::string& attributeName,
+ const std::string& type,
+ const std::string& valueDefault,
+ const std::string& value) {
+ std::cout << "attributeDecl" << std::endl;
+ std::cout << " elementName:" << elementName << std::endl;
+ std::cout << " attributeName:" << attributeName << std::endl;
+ std::cout << " type:" << type << std::endl;
+ std::cout << " valueDefault:" << valueDefault << std::endl;
+ std::cout << " value:" << value << std::endl;
+ }
+ virtual void internalEntityDecl(const std::string& name, const std::string& value) {
+ std::cout << "internalEntityDecl" << std::endl;
+ std::cout << " name:" << name << std::endl;
+ std::cout << " value:" << value << std::endl;
+ }
+ virtual void externalEntityDecl(const std::string& name,
+ const std::string& publicId,
+ const std::string& systemId) {
+ std::cout << "externalEntityDecl" << std::endl;
+ std::cout << " name:" << name << std::endl;
+ std::cout << " publicId:" << publicId << std::endl;
+ std::cout << " systemId:" << systemId << std::endl;
+ }
+
+ };
+#endif
+}
+
+#endif
diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp
new file mode 100644
index 0000000..3d3048b
--- /dev/null
+++ b/src/uscxml/Message.cpp
@@ -0,0 +1,168 @@
+#include "uscxml/Message.h"
+#include <DOM/SAX2DOM/SAX2DOM.hpp>
+#include <SAX/helpers/CatchErrorHandler.hpp>
+
+namespace uscxml {
+
+static int _dataIndentation = 1;
+
+
+Arabica::DOM::Document<std::string> Data::toDocument() {
+ Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation();
+ Arabica::DOM::Document<std::string> document = domFactory.createDocument("http://www.w3.org/2005/07/scxml", "message", 0);
+ Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement();
+ scxmlMsg.setPrefix("scxml");
+ scxmlMsg.setAttribute("version", "1.0");
+
+ if (compound.size() > 0 || array.size() > 0) {
+ Arabica::DOM::Element<std::string> payloadElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "scxml:payload");
+ scxmlMsg.appendChild(payloadElem);
+
+ // we do not support nested attibutes
+ if (compound.size() > 0) {
+ std::map<std::string, Data>::iterator compoundIter = compound.begin();
+ while(compoundIter != compound.end()) {
+ if (compoundIter->second.atom.size() > 0) {
+ Arabica::DOM::Element<std::string> propertyElem = document.createElementNS("http://www.w3.org/2005/07/scxml", "scxml:property");
+ propertyElem.setAttribute("name", compoundIter->first);
+ Arabica::DOM::Text<std::string> textElem = document.createTextNode(compoundIter->second.atom);
+ propertyElem.appendChild(textElem);
+ payloadElem.appendChild(propertyElem);
+ }
+ compoundIter++;
+ }
+ }
+ }
+ return document;
+}
+
+Arabica::DOM::Document<std::string> Event::toDocument() {
+ Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation();
+ Arabica::DOM::Document<std::string> document = Data::toDocument();
+ Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement();
+
+ scxmlMsg.setAttribute("source", origin);
+ scxmlMsg.setAttribute("name", name);
+
+ return document;
+}
+
+Arabica::DOM::Document<std::string> SendRequest::toDocument() {
+ Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation();
+ Arabica::DOM::Document<std::string> document = Event::toDocument();
+ Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement();
+
+ scxmlMsg.setAttribute("sendid", sendid);
+
+ return document;
+}
+
+Arabica::DOM::Document<std::string> InvokeRequest::toDocument() {
+ Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation();
+ Arabica::DOM::Document<std::string> document = Event::toDocument();
+ Arabica::DOM::Element<std::string> scxmlMsg = document.getDocumentElement();
+
+ scxmlMsg.setAttribute("invokeid", invokeid);
+
+ return document;
+}
+
+Data Data::fromXML(const std::string& xmlString) {
+}
+
+Event Event::fromXML(const std::string& xmlString) {
+ Arabica::SAX2DOM::Parser<std::string> eventParser;
+ Arabica::SAX::CatchErrorHandler<std::string> errorHandler;
+ eventParser.setErrorHandler(errorHandler);
+
+ std::istringstream is(xmlString);
+ Arabica::SAX::InputSource<std::string> inputSource;
+ inputSource.setByteStream(is);
+
+ Event event;
+ if(eventParser.parse(inputSource) && eventParser.getDocument().hasChildNodes()) {
+ Arabica::DOM::Element<std::string> scxmlMsg = eventParser.getDocument().getDocumentElement();
+ if (HAS_ATTR(scxmlMsg, "name"))
+ event.name = ATTR(scxmlMsg, "name");
+ if (HAS_ATTR(scxmlMsg, "sendid"))
+ event.sendid = ATTR(scxmlMsg, "sendid");
+ }
+ return event;
+}
+
+SendRequest SendRequest::fromXML(const std::string& xmlString) {
+ Event::fromXML(xmlString);
+}
+
+InvokeRequest InvokeRequest::fromXML(const std::string& xmlString) {
+ Event::fromXML(xmlString);
+}
+
+#ifndef SWIGJAVA
+std::ostream& operator<< (std::ostream& os, const Event& event) {
+ os << (event.type == Event::EXTERNAL ? "External" : "Internal") << " Event " << (event.dom ? "with DOM attached" : "") << std::endl;
+
+ if (event.name.size() > 0)
+ os << " name: " << event.name << std::endl;
+ if (event.origin.size() > 0)
+ os << " origin: " << event.origin << std::endl;
+ if (event.origintype.size() > 0)
+ os << " origintype: " << event.origintype << std::endl;
+ _dataIndentation++;
+ os << " data: " << (Data)event << std::endl;
+ _dataIndentation--;
+ return os;
+}
+#endif
+
+#ifndef SWIGJAVA
+std::ostream& operator<< (std::ostream& os, const Data& data) {
+ std::string indent;
+ for (int i = 0; i < _dataIndentation; i++) {
+ indent += " ";
+ }
+ if (false) {
+ } else if (data.compound.size() > 0) {
+ int longestKey = 0;
+ std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin();
+ while(compoundIter != data.compound.end()) {
+ if (compoundIter->first.size() > longestKey)
+ longestKey = compoundIter->first.size();
+ compoundIter++;
+ }
+ std::string keyPadding;
+ for (unsigned int i = 0; i < longestKey; i++)
+ keyPadding += " ";
+
+ os << "{" << std::endl;
+ compoundIter = data.compound.begin();
+ while(compoundIter != data.compound.end()) {
+ os << indent << " \"" << compoundIter->first << "\" " << keyPadding.substr(0, longestKey - compoundIter->first.size()) << "= ";
+ _dataIndentation += 2;
+ os << compoundIter->second << "," << std::endl;
+ _dataIndentation -= 2;
+ compoundIter++;
+ }
+ os << indent << "}" << std::endl;
+ } else if (data.array.size() > 0) {
+ os << "[" << std::endl;
+ std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin();
+ while(compoundIter != data.compound.end()) {
+ _dataIndentation += 2;
+ os << indent << " " << compoundIter->second << "," << std::endl;
+ _dataIndentation -= 2;
+ compoundIter++;
+ }
+ os << indent << "]" << std::endl;
+ } else if (data.atom.size() > 0) {
+ if (data.type == Data::VERBATIM) {
+ os << indent << "\"" << data.atom << "\"";
+ } else {
+ os << indent << data.atom;
+ }
+ }
+ return os;
+}
+#endif
+
+} \ No newline at end of file
diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h
new file mode 100644
index 0000000..a520ff5
--- /dev/null
+++ b/src/uscxml/Message.h
@@ -0,0 +1,122 @@
+#ifndef EVENT_H_XZAQ4HR
+#define EVENT_H_XZAQ4HR
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include <DOM/Document.hpp>
+#include <DOM/io/Stream.hpp>
+
+#define TAGNAME(elem) ((Arabica::DOM::Element<std::string>)elem).getTagName()
+#define ATTR(elem, attr) ((Arabica::DOM::Element<std::string>)elem).getAttribute(attr)
+#define HAS_ATTR(elem, attr) ((Arabica::DOM::Element<std::string>)elem).hasAttribute(attr)
+
+namespace uscxml {
+
+class Data {
+public:
+ enum Type {
+ VERBATIM,
+ INTERPRETED
+ };
+
+ Data() {}
+ Data(const std::string& atom_, Type type_ = INTERPRETED) : atom(atom_), type(type_) {}
+ virtual ~Data() {}
+
+ static Data fromXML(const std::string& xmlString);
+ Arabica::DOM::Document<std::string> toDocument();
+ std::string toXMLString() {
+ std::stringstream ss;
+ ss << toDocument();
+ return ss.str();
+ }
+
+ std::map<std::string, Data> compound;
+ std::vector<Data> array;
+ std::string atom;
+ Type type;
+
+protected:
+ Arabica::DOM::Document<std::string> toNode(const Arabica::DOM::Document<std::string>& factory, const Data& data);
+
+#ifndef SWIGJAVA
+ friend std::ostream& operator<< (std::ostream& os, const Data& data);
+#endif
+};
+
+class Event : public Data {
+public:
+ enum Type {
+ PLATFORM,
+ INTERNAL,
+ EXTERNAL
+ };
+
+ Event() : type(INTERNAL) {}
+
+ std::string name;
+ Type type;
+ std::string origin;
+ std::string origintype;
+ Arabica::DOM::Node<std::string> dom;
+ std::string sendid;
+ std::string invokeid;
+
+ static Event fromXML(const std::string& xmlString);
+ Arabica::DOM::Document<std::string> toDocument();
+ std::string toXMLString() {
+ std::stringstream ss;
+ ss << toDocument();
+ return ss.str();
+ }
+
+#ifndef SWIGJAVA
+ friend std::ostream& operator<< (std::ostream& os, const Event& event);
+#endif
+};
+
+class InvokeRequest : public Event {
+public:
+ std::string type;
+ std::string src;
+ std::string namelist;
+ bool autoForward;
+ Arabica::DOM::Node<std::string> finalize;
+ std::map<std::string, std::string> params;
+ std::string content;
+
+ static InvokeRequest fromXML(const std::string& xmlString);
+ Arabica::DOM::Document<std::string> toDocument();
+ std::string toXMLString() {
+ std::stringstream ss;
+ ss << toDocument();
+ return ss.str();
+ }
+
+};
+
+class SendRequest : public Event {
+public:
+ std::string target;
+ std::string type;
+ uint32_t delayMs;
+ std::map<std::string, std::string> params;
+ std::map<std::string, std::string> namelist;
+ std::string content;
+
+ static SendRequest fromXML(const std::string& xmlString);
+ Arabica::DOM::Document<std::string> toDocument();
+ std::string toXMLString() {
+ std::stringstream ss;
+ ss << toDocument();
+ return ss.str();
+ }
+
+};
+
+}
+
+
+#endif /* end of include guard: EVENT_H_XZAQ4HR */
diff --git a/src/uscxml/concurrency/BlockingQueue.h b/src/uscxml/concurrency/BlockingQueue.h
new file mode 100644
index 0000000..90094bf
--- /dev/null
+++ b/src/uscxml/concurrency/BlockingQueue.h
@@ -0,0 +1,41 @@
+#ifndef BLOCKINGQUEUE_H_4LEVMY0N
+#define BLOCKINGQUEUE_H_4LEVMY0N
+
+#include "uscxml/concurrency/tinythread.h"
+#include <list>
+
+namespace uscxml {
+namespace concurrency {
+
+template <class T>
+class BlockingQueue {
+public:
+ BlockingQueue() {}
+ virtual ~BlockingQueue() {
+ }
+
+ void push(T elem) {
+ tthread::lock_guard<tthread::mutex> lock(_mutex);
+ _queue.push_back(elem);
+ _cond.notify_all();
+ }
+
+ T pop() {
+ tthread::lock_guard<tthread::mutex> lock(_mutex);
+ while (_queue.empty()) {
+ _cond.wait(_mutex);
+ }
+ T ret = _queue.front();
+ _queue.pop_front();
+ return ret;
+ }
+
+ tthread::mutex _mutex;
+ tthread::condition_variable _cond;
+ std::list<T> _queue;
+};
+
+}
+}
+
+#endif /* end of include guard: BLOCKINGQUEUE_H_4LEVMY0N */
diff --git a/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.cpp b/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.cpp
new file mode 100644
index 0000000..a93b14a
--- /dev/null
+++ b/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.cpp
@@ -0,0 +1,57 @@
+#include "uscxml/concurrency/DelayedEventQueue.h"
+#include <assert.h>
+
+namespace uscxml {
+
+ DelayedEventQueue::DelayedEventQueue() {
+ _eventLoop = EV_DEFAULT;
+ _thread = NULL;
+ }
+
+ DelayedEventQueue::~DelayedEventQueue() {
+ ev_break(_eventLoop);
+ if (_thread)
+ _thread->join();
+ }
+
+ void DelayedEventQueue::addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData) {
+ if(_timeoutWatcher.find(eventId) != _timeoutWatcher.end()) {
+ cancelEvent(eventId);
+ }
+
+ _timeoutWatcher[eventId].eventId = eventId;
+ _timeoutWatcher[eventId].userData = userData;
+ _timeoutWatcher[eventId].eventQueue = this;
+ _timeoutWatcher[eventId].callback = callback;
+
+ ev_timer_init (&_timeoutWatcher[eventId].io, DelayedEventQueue::timerCallback, ((float)delayMs)/1000.0f, 0.);
+ ev_timer_start (_eventLoop, &_timeoutWatcher[eventId].io);
+
+ }
+
+ void DelayedEventQueue::cancelEvent(std::string eventId) {
+ if(_timeoutWatcher.find(eventId) != _timeoutWatcher.end()) {
+ ev_timer_stop(_eventLoop, &_timeoutWatcher[eventId].io);
+ _timeoutWatcher.erase(eventId);
+ }
+ }
+
+ void DelayedEventQueue::start() {
+ _thread = new tthread::thread(DelayedEventQueue::run, this);
+ }
+
+ void DelayedEventQueue::stop() {
+ }
+
+ void DelayedEventQueue::run(void* instance) {
+ ev_run (((DelayedEventQueue*)instance)->_eventLoop, 0);
+ }
+
+ void DelayedEventQueue::timerCallback(EV_P_ ev_timer *w, int revents) {
+ struct callbackData *data = (struct callbackData*)w;
+ std::string eventId = data->eventId; // copy eventId
+ data->eventQueue->_timeoutWatcher.erase(data->eventId);
+ data->callback(data->userData, eventId);
+ }
+
+} \ No newline at end of file
diff --git a/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.h b/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.h
new file mode 100644
index 0000000..2bc71b2
--- /dev/null
+++ b/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.h
@@ -0,0 +1,45 @@
+#ifndef DELAYEDEVENTQUEUE_H_JA6WRBVP
+#define DELAYEDEVENTQUEUE_H_JA6WRBVP
+
+#include "tinythread.h"
+#include <ev.h>
+
+#include <map>
+#include <string>
+#include <iostream>
+
+namespace uscxml {
+
+class DelayedEventQueue {
+public:
+
+ struct callbackData
+ {
+ ev_timer io;
+ void *userData;
+ void (*callback)(void*, const std::string eventId);
+ std::string eventId;
+ DelayedEventQueue* eventQueue;
+ };
+
+ DelayedEventQueue();
+ virtual ~DelayedEventQueue();
+
+ void addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData);
+ void cancelEvent(std::string eventId);
+
+ void start();
+ void stop();
+ static void run(void*);
+
+ static void timerCallback(EV_P_ ev_timer *w, int revents);
+
+ tthread::thread* _thread;
+ std::map<std::string, callbackData> _timeoutWatcher;
+ struct ev_loop* _eventLoop;
+};
+
+}
+
+
+#endif /* end of include guard: DELAYEDEVENTQUEUE_H_JA6WRBVP */
diff --git a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp b/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp
new file mode 100644
index 0000000..ce42af7
--- /dev/null
+++ b/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp
@@ -0,0 +1,87 @@
+#include "uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h"
+#include <assert.h>
+#include <event2/event.h>
+
+namespace uscxml {
+
+ DelayedEventQueue::DelayedEventQueue() {
+ evthread_use_pthreads();
+ _eventLoop = event_base_new();
+ _thread = NULL;
+ }
+
+ DelayedEventQueue::~DelayedEventQueue() {
+ std::cout << "Deleting DelayedEventQueue" << std::endl;
+ if(_eventLoop)
+ event_base_loopbreak(_eventLoop);
+ if (_thread)
+ _thread->join();
+ if(_eventLoop)
+ event_base_free(_eventLoop);
+ }
+
+ void DelayedEventQueue::run(void* instance) {
+ DelayedEventQueue* THIS = (DelayedEventQueue*)instance;
+ int result;
+ while(THIS->_isStarted) {
+ {
+ //result = event_base_dispatch(THIS->_eventLoop);
+ result = event_base_loop(THIS->_eventLoop, EVLOOP_NO_EXIT_ON_EMPTY);
+ }
+ }
+ }
+
+ void DelayedEventQueue::addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData) {
+ if(_callbackData.find(eventId) != _callbackData.end()) {
+ cancelEvent(eventId);
+ }
+
+ struct timeval delay = {delayMs / 1000, (delayMs % 1000) * 1000};
+ struct event* event = event_new(_eventLoop, -1, 0, DelayedEventQueue::timerCallback, &_callbackData[eventId]);
+
+ _callbackData[eventId].eventId = eventId;
+ _callbackData[eventId].userData = userData;
+ _callbackData[eventId].eventQueue = this;
+ _callbackData[eventId].callback = callback;
+ _callbackData[eventId].event = event;
+
+ event_add(event, &delay);
+ }
+
+ void DelayedEventQueue::cancelEvent(std::string eventId) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+
+ if(_callbackData.find(eventId) != _callbackData.end()) {
+ event_del(_callbackData[eventId].event);
+ event_free(_callbackData[eventId].event);
+ _callbackData.erase(eventId);
+ }
+ }
+
+ void DelayedEventQueue::start() {
+ _isStarted = true;
+ _thread = new tthread::thread(DelayedEventQueue::run, this);
+ }
+
+ void DelayedEventQueue::stop() {
+ if (_isStarted) {
+ _isStarted = false;
+ _thread->join();
+ delete _thread;
+ }
+ }
+
+ void DelayedEventQueue::dummyCallback(evutil_socket_t fd, short what, void *arg) {
+ }
+
+ void DelayedEventQueue::timerCallback(evutil_socket_t fd, short what, void *arg) {
+ struct callbackData *data = (struct callbackData*)arg;
+ tthread::lock_guard<tthread::recursive_mutex> lock(data->eventQueue->_mutex);
+
+ std::string eventId = data->eventId; // copy eventId
+ event_free(data->event);
+ data->eventQueue->_callbackData.erase(data->eventId);
+ data->callback(data->userData, eventId);
+ }
+
+} \ No newline at end of file
diff --git a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h b/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h
new file mode 100644
index 0000000..4c59ce1
--- /dev/null
+++ b/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h
@@ -0,0 +1,52 @@
+#ifndef DELAYEDEVENTQUEUE_H_JA6WRBVP
+#define DELAYEDEVENTQUEUE_H_JA6WRBVP
+
+#include "uscxml/concurrency/tinythread.h"
+
+#include <event2/thread.h>
+#include <event2/http.h>
+#include <event2/event.h>
+
+#include <map>
+#include <string>
+#include <iostream>
+
+namespace uscxml {
+
+class DelayedEventQueue {
+public:
+
+ struct callbackData
+ {
+ void *userData;
+ void (*callback)(void*, const std::string eventId);
+ std::string eventId;
+ struct event *event;
+ DelayedEventQueue* eventQueue;
+ };
+
+ DelayedEventQueue();
+ virtual ~DelayedEventQueue();
+
+ void addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData);
+ void cancelEvent(std::string eventId);
+
+ void start();
+ void stop();
+ static void run(void*);
+
+ static void timerCallback(evutil_socket_t fd, short what, void *arg);
+ static void dummyCallback(evutil_socket_t fd, short what, void *arg);
+
+ bool _isStarted;
+ tthread::thread* _thread;
+ tthread::recursive_mutex _mutex;
+
+ std::map<std::string, callbackData> _callbackData;
+ struct event_base* _eventLoop;
+};
+
+}
+
+
+#endif /* end of include guard: DELAYEDEVENTQUEUE_H_JA6WRBVP */
diff --git a/src/uscxml/concurrency/tinythread.cpp b/src/uscxml/concurrency/tinythread.cpp
new file mode 100644
index 0000000..690ecee
--- /dev/null
+++ b/src/uscxml/concurrency/tinythread.cpp
@@ -0,0 +1,303 @@
+/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*-
+Copyright (c) 2010-2012 Marcus Geelnard
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+ distribution.
+*/
+
+#include <exception>
+#include "tinythread.h"
+
+#if defined(_TTHREAD_POSIX_)
+ #include <unistd.h>
+ #include <map>
+#elif defined(_TTHREAD_WIN32_)
+ #include <process.h>
+#endif
+
+
+namespace tthread {
+
+//------------------------------------------------------------------------------
+// condition_variable
+//------------------------------------------------------------------------------
+// NOTE 1: The Win32 implementation of the condition_variable class is based on
+// the corresponding implementation in GLFW, which in turn is based on a
+// description by Douglas C. Schmidt and Irfan Pyarali:
+// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+//
+// NOTE 2: Windows Vista actually has native support for condition variables
+// (InitializeConditionVariable, WakeConditionVariable, etc), but we want to
+// be portable with pre-Vista Windows versions, so TinyThread++ does not use
+// Vista condition variables.
+//------------------------------------------------------------------------------
+
+#if defined(_TTHREAD_WIN32_)
+ #define _CONDITION_EVENT_ONE 0
+ #define _CONDITION_EVENT_ALL 1
+#endif
+
+#if defined(_TTHREAD_WIN32_)
+condition_variable::condition_variable() : mWaitersCount(0)
+{
+ mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL);
+ mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL);
+ InitializeCriticalSection(&mWaitersCountLock);
+}
+#endif
+
+#if defined(_TTHREAD_WIN32_)
+condition_variable::~condition_variable()
+{
+ CloseHandle(mEvents[_CONDITION_EVENT_ONE]);
+ CloseHandle(mEvents[_CONDITION_EVENT_ALL]);
+ DeleteCriticalSection(&mWaitersCountLock);
+}
+#endif
+
+#if defined(_TTHREAD_WIN32_)
+void condition_variable::_wait()
+{
+ // Wait for either event to become signaled due to notify_one() or
+ // notify_all() being called
+ int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE);
+
+ // Check if we are the last waiter
+ EnterCriticalSection(&mWaitersCountLock);
+ -- mWaitersCount;
+ bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) &&
+ (mWaitersCount == 0);
+ LeaveCriticalSection(&mWaitersCountLock);
+
+ // If we are the last waiter to be notified to stop waiting, reset the event
+ if(lastWaiter)
+ ResetEvent(mEvents[_CONDITION_EVENT_ALL]);
+}
+#endif
+
+#if defined(_TTHREAD_WIN32_)
+void condition_variable::notify_one()
+{
+ // Are there any waiters?
+ EnterCriticalSection(&mWaitersCountLock);
+ bool haveWaiters = (mWaitersCount > 0);
+ LeaveCriticalSection(&mWaitersCountLock);
+
+ // If we have any waiting threads, send them a signal
+ if(haveWaiters)
+ SetEvent(mEvents[_CONDITION_EVENT_ONE]);
+}
+#endif
+
+#if defined(_TTHREAD_WIN32_)
+void condition_variable::notify_all()
+{
+ // Are there any waiters?
+ EnterCriticalSection(&mWaitersCountLock);
+ bool haveWaiters = (mWaitersCount > 0);
+ LeaveCriticalSection(&mWaitersCountLock);
+
+ // If we have any waiting threads, send them a signal
+ if(haveWaiters)
+ SetEvent(mEvents[_CONDITION_EVENT_ALL]);
+}
+#endif
+
+
+//------------------------------------------------------------------------------
+// POSIX pthread_t to unique thread::id mapping logic.
+// Note: Here we use a global thread safe std::map to convert instances of
+// pthread_t to small thread identifier numbers (unique within one process).
+// This method should be portable across different POSIX implementations.
+//------------------------------------------------------------------------------
+
+#if defined(_TTHREAD_POSIX_)
+static thread::id _pthread_t_to_ID(const pthread_t &aHandle)
+{
+ static mutex idMapLock;
+ static std::map<pthread_t, unsigned long int> idMap;
+ static unsigned long int idCount(1);
+
+ lock_guard<mutex> guard(idMapLock);
+ if(idMap.find(aHandle) == idMap.end())
+ idMap[aHandle] = idCount ++;
+ return thread::id(idMap[aHandle]);
+}
+#endif // _TTHREAD_POSIX_
+
+
+//------------------------------------------------------------------------------
+// thread
+//------------------------------------------------------------------------------
+
+/// Information to pass to the new thread (what to run).
+struct _thread_start_info {
+ void (*mFunction)(void *); ///< Pointer to the function to be executed.
+ void * mArg; ///< Function argument for the thread function.
+ thread * mThread; ///< Pointer to the thread object.
+};
+
+// Thread wrapper function.
+#if defined(_TTHREAD_WIN32_)
+unsigned WINAPI thread::wrapper_function(void * aArg)
+#elif defined(_TTHREAD_POSIX_)
+void * thread::wrapper_function(void * aArg)
+#endif
+{
+ // Get thread startup information
+ _thread_start_info * ti = (_thread_start_info *) aArg;
+
+ try
+ {
+ // Call the actual client thread function
+ ti->mFunction(ti->mArg);
+ }
+ catch(...)
+ {
+ // Uncaught exceptions will terminate the application (default behavior
+ // according to C++11)
+ std::terminate();
+ }
+
+ // The thread is no longer executing
+ lock_guard<mutex> guard(ti->mThread->mDataMutex);
+ ti->mThread->mNotAThread = true;
+
+ // The thread is responsible for freeing the startup information
+ delete ti;
+
+ return 0;
+}
+
+thread::thread(void (*aFunction)(void *), void * aArg)
+{
+ // Serialize access to this thread structure
+ lock_guard<mutex> guard(mDataMutex);
+
+ // Fill out the thread startup information (passed to the thread wrapper,
+ // which will eventually free it)
+ _thread_start_info * ti = new _thread_start_info;
+ ti->mFunction = aFunction;
+ ti->mArg = aArg;
+ ti->mThread = this;
+
+ // The thread is now alive
+ mNotAThread = false;
+
+ // Create the thread
+#if defined(_TTHREAD_WIN32_)
+ mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID);
+#elif defined(_TTHREAD_POSIX_)
+ if(pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0)
+ mHandle = 0;
+#endif
+
+ // Did we fail to create the thread?
+ if(!mHandle)
+ {
+ mNotAThread = true;
+ delete ti;
+ }
+}
+
+thread::~thread()
+{
+ if(joinable())
+ std::terminate();
+}
+
+void thread::join()
+{
+ if(joinable())
+ {
+#if defined(_TTHREAD_WIN32_)
+ WaitForSingleObject(mHandle, INFINITE);
+ CloseHandle(mHandle);
+#elif defined(_TTHREAD_POSIX_)
+ pthread_join(mHandle, NULL);
+#endif
+ }
+}
+
+bool thread::joinable() const
+{
+ mDataMutex.lock();
+ bool result = !mNotAThread;
+ mDataMutex.unlock();
+ return result;
+}
+
+void thread::detach()
+{
+ mDataMutex.lock();
+ if(!mNotAThread)
+ {
+#if defined(_TTHREAD_WIN32_)
+ CloseHandle(mHandle);
+#elif defined(_TTHREAD_POSIX_)
+ pthread_detach(mHandle);
+#endif
+ mNotAThread = true;
+ }
+ mDataMutex.unlock();
+}
+
+thread::id thread::get_id() const
+{
+ if(!joinable())
+ return id();
+#if defined(_TTHREAD_WIN32_)
+ return id((unsigned long int) mWin32ThreadID);
+#elif defined(_TTHREAD_POSIX_)
+ return _pthread_t_to_ID(mHandle);
+#endif
+}
+
+unsigned thread::hardware_concurrency()
+{
+#if defined(_TTHREAD_WIN32_)
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return (int) si.dwNumberOfProcessors;
+#elif defined(_SC_NPROCESSORS_ONLN)
+ return (int) sysconf(_SC_NPROCESSORS_ONLN);
+#elif defined(_SC_NPROC_ONLN)
+ return (int) sysconf(_SC_NPROC_ONLN);
+#else
+ // The standard requires this function to return zero if the number of
+ // hardware cores could not be determined.
+ return 0;
+#endif
+}
+
+
+//------------------------------------------------------------------------------
+// this_thread
+//------------------------------------------------------------------------------
+
+thread::id this_thread::get_id()
+{
+#if defined(_TTHREAD_WIN32_)
+ return thread::id((unsigned long int) GetCurrentThreadId());
+#elif defined(_TTHREAD_POSIX_)
+ return _pthread_t_to_ID(pthread_self());
+#endif
+}
+
+}
diff --git a/src/uscxml/concurrency/tinythread.h b/src/uscxml/concurrency/tinythread.h
new file mode 100644
index 0000000..aed7b58
--- /dev/null
+++ b/src/uscxml/concurrency/tinythread.h
@@ -0,0 +1,714 @@
+/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*-
+Copyright (c) 2010-2012 Marcus Geelnard
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+ distribution.
+*/
+
+#ifndef _TINYTHREAD_H_
+#define _TINYTHREAD_H_
+
+/// @file
+/// @mainpage TinyThread++ API Reference
+///
+/// @section intro_sec Introduction
+/// TinyThread++ is a minimal, portable implementation of basic threading
+/// classes for C++.
+///
+/// They closely mimic the functionality and naming of the C++11 standard, and
+/// should be easily replaceable with the corresponding std:: variants.
+///
+/// @section port_sec Portability
+/// The Win32 variant uses the native Win32 API for implementing the thread
+/// classes, while for other systems, the POSIX threads API (pthread) is used.
+///
+/// @section class_sec Classes
+/// In order to mimic the threading API of the C++11 standard, subsets of
+/// several classes are provided. The fundamental classes are:
+/// @li tthread::thread
+/// @li tthread::mutex
+/// @li tthread::recursive_mutex
+/// @li tthread::condition_variable
+/// @li tthread::lock_guard
+/// @li tthread::fast_mutex
+///
+/// @section misc_sec Miscellaneous
+/// The following special keywords are available: #thread_local.
+///
+/// For more detailed information (including additional classes), browse the
+/// different sections of this documentation. A good place to start is:
+/// tinythread.h.
+
+// Which platform are we on?
+#if !defined(_TTHREAD_PLATFORM_DEFINED_)
+ #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
+ #define _TTHREAD_WIN32_
+ #else
+ #define _TTHREAD_POSIX_
+ #endif
+ #define _TTHREAD_PLATFORM_DEFINED_
+#endif
+
+// Platform specific includes
+#if defined(_TTHREAD_WIN32_)
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #define __UNDEF_LEAN_AND_MEAN
+ #endif
+ #include <windows.h>
+ #ifdef __UNDEF_LEAN_AND_MEAN
+ #undef WIN32_LEAN_AND_MEAN
+ #undef __UNDEF_LEAN_AND_MEAN
+ #endif
+#else
+ #include <pthread.h>
+ #include <signal.h>
+ #include <sched.h>
+ #include <unistd.h>
+#endif
+
+// Generic includes
+#include <ostream>
+
+/// TinyThread++ version (major number).
+#define TINYTHREAD_VERSION_MAJOR 1
+/// TinyThread++ version (minor number).
+#define TINYTHREAD_VERSION_MINOR 1
+/// TinyThread++ version (full version).
+#define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR)
+
+// Do we have a fully featured C++11 compiler?
+#if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L))
+ #define _TTHREAD_CPP11_
+#endif
+
+// ...at least partial C++11?
+#if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__)
+ #define _TTHREAD_CPP11_PARTIAL_
+#endif
+
+// Macro for disabling assignments of objects.
+#ifdef _TTHREAD_CPP11_PARTIAL_
+ #define _TTHREAD_DISABLE_ASSIGNMENT(name) \
+ name(const name&) = delete; \
+ name& operator=(const name&) = delete;
+#else
+ #define _TTHREAD_DISABLE_ASSIGNMENT(name) \
+ name(const name&); \
+ name& operator=(const name&);
+#endif
+
+/// @def thread_local
+/// Thread local storage keyword.
+/// A variable that is declared with the @c thread_local keyword makes the
+/// value of the variable local to each thread (known as thread-local storage,
+/// or TLS). Example usage:
+/// @code
+/// // This variable is local to each thread.
+/// thread_local int variable;
+/// @endcode
+/// @note The @c thread_local keyword is a macro that maps to the corresponding
+/// compiler directive (e.g. @c __declspec(thread)). While the C++11 standard
+/// allows for non-trivial types (e.g. classes with constructors and
+/// destructors) to be declared with the @c thread_local keyword, most pre-C++11
+/// compilers only allow for trivial types (e.g. @c int). So, to guarantee
+/// portable code, only use trivial types for thread local storage.
+/// @note This directive is currently not supported on Mac OS X (it will give
+/// a compiler error), since compile-time TLS is not supported in the Mac OS X
+/// executable format. Also, some older versions of MinGW (before GCC 4.x) do
+/// not support this directive.
+/// @hideinitializer
+
+#if !defined(_TTHREAD_CPP11_) && !defined(thread_local)
+ #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
+ #define thread_local __thread
+ #else
+ #define thread_local __declspec(thread)
+ #endif
+#endif
+
+
+/// Main name space for TinyThread++.
+/// This namespace is more or less equivalent to the @c std namespace for the
+/// C++11 thread classes. For instance, the tthread::mutex class corresponds to
+/// the std::mutex class.
+namespace tthread {
+
+/// Mutex class.
+/// This is a mutual exclusion object for synchronizing access to shared
+/// memory areas for several threads. The mutex is non-recursive (i.e. a
+/// program may deadlock if the thread that owns a mutex object calls lock()
+/// on that object).
+/// @see recursive_mutex
+class mutex {
+ public:
+ /// Constructor.
+ mutex()
+#if defined(_TTHREAD_WIN32_)
+ : mAlreadyLocked(false)
+#endif
+ {
+#if defined(_TTHREAD_WIN32_)
+ InitializeCriticalSection(&mHandle);
+#else
+ pthread_mutex_init(&mHandle, NULL);
+#endif
+ }
+
+ /// Destructor.
+ ~mutex()
+ {
+#if defined(_TTHREAD_WIN32_)
+ DeleteCriticalSection(&mHandle);
+#else
+ pthread_mutex_destroy(&mHandle);
+#endif
+ }
+
+ /// Lock the mutex.
+ /// The method will block the calling thread until a lock on the mutex can
+ /// be obtained. The mutex remains locked until @c unlock() is called.
+ /// @see lock_guard
+ inline void lock()
+ {
+#if defined(_TTHREAD_WIN32_)
+ EnterCriticalSection(&mHandle);
+ while(mAlreadyLocked) Sleep(1000); // Simulate deadlock...
+ mAlreadyLocked = true;
+#else
+ pthread_mutex_lock(&mHandle);
+#endif
+ }
+
+ /// Try to lock the mutex.
+ /// The method will try to lock the mutex. If it fails, the function will
+ /// return immediately (non-blocking).
+ /// @return @c true if the lock was acquired, or @c false if the lock could
+ /// not be acquired.
+ inline bool try_lock()
+ {
+#if defined(_TTHREAD_WIN32_)
+ bool ret = (TryEnterCriticalSection(&mHandle) ? true : false);
+ if(ret && mAlreadyLocked)
+ {
+ LeaveCriticalSection(&mHandle);
+ ret = false;
+ }
+ return ret;
+#else
+ return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
+#endif
+ }
+
+ /// Unlock the mutex.
+ /// If any threads are waiting for the lock on this mutex, one of them will
+ /// be unblocked.
+ inline void unlock()
+ {
+#if defined(_TTHREAD_WIN32_)
+ mAlreadyLocked = false;
+ LeaveCriticalSection(&mHandle);
+#else
+ pthread_mutex_unlock(&mHandle);
+#endif
+ }
+
+ _TTHREAD_DISABLE_ASSIGNMENT(mutex)
+
+ private:
+#if defined(_TTHREAD_WIN32_)
+ CRITICAL_SECTION mHandle;
+ bool mAlreadyLocked;
+#else
+ pthread_mutex_t mHandle;
+#endif
+
+ friend class condition_variable;
+};
+
+/// Recursive mutex class.
+/// This is a mutual exclusion object for synchronizing access to shared
+/// memory areas for several threads. The mutex is recursive (i.e. a thread
+/// may lock the mutex several times, as long as it unlocks the mutex the same
+/// number of times).
+/// @see mutex
+class recursive_mutex {
+ public:
+ /// Constructor.
+ recursive_mutex()
+ {
+#if defined(_TTHREAD_WIN32_)
+ InitializeCriticalSection(&mHandle);
+#else
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&mHandle, &attr);
+#endif
+ }
+
+ /// Destructor.
+ ~recursive_mutex()
+ {
+#if defined(_TTHREAD_WIN32_)
+ DeleteCriticalSection(&mHandle);
+#else
+ pthread_mutex_destroy(&mHandle);
+#endif
+ }
+
+ /// Lock the mutex.
+ /// The method will block the calling thread until a lock on the mutex can
+ /// be obtained. The mutex remains locked until @c unlock() is called.
+ /// @see lock_guard
+ inline void lock()
+ {
+#if defined(_TTHREAD_WIN32_)
+ EnterCriticalSection(&mHandle);
+#else
+ pthread_mutex_lock(&mHandle);
+#endif
+ }
+
+ /// Try to lock the mutex.
+ /// The method will try to lock the mutex. If it fails, the function will
+ /// return immediately (non-blocking).
+ /// @return @c true if the lock was acquired, or @c false if the lock could
+ /// not be acquired.
+ inline bool try_lock()
+ {
+#if defined(_TTHREAD_WIN32_)
+ return TryEnterCriticalSection(&mHandle) ? true : false;
+#else
+ return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
+#endif
+ }
+
+ /// Unlock the mutex.
+ /// If any threads are waiting for the lock on this mutex, one of them will
+ /// be unblocked.
+ inline void unlock()
+ {
+#if defined(_TTHREAD_WIN32_)
+ LeaveCriticalSection(&mHandle);
+#else
+ pthread_mutex_unlock(&mHandle);
+#endif
+ }
+
+ _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex)
+
+ private:
+#if defined(_TTHREAD_WIN32_)
+ CRITICAL_SECTION mHandle;
+#else
+ pthread_mutex_t mHandle;
+#endif
+
+ friend class condition_variable;
+};
+
+/// Lock guard class.
+/// The constructor locks the mutex, and the destructor unlocks the mutex, so
+/// the mutex will automatically be unlocked when the lock guard goes out of
+/// scope. Example usage:
+/// @code
+/// mutex m;
+/// int counter;
+///
+/// void increment()
+/// {
+/// lock_guard<mutex> guard(m);
+/// ++ counter;
+/// }
+/// @endcode
+
+template <class T>
+class lock_guard {
+ public:
+ typedef T mutex_type;
+
+ lock_guard() : mMutex(0) {}
+
+ /// The constructor locks the mutex.
+ explicit lock_guard(mutex_type &aMutex)
+ {
+ mMutex = &aMutex;
+ mMutex->lock();
+ }
+
+ /// The destructor unlocks the mutex.
+ ~lock_guard()
+ {
+ if(mMutex)
+ mMutex->unlock();
+ }
+
+ private:
+ mutex_type * mMutex;
+};
+
+/// Condition variable class.
+/// This is a signalling object for synchronizing the execution flow for
+/// several threads. Example usage:
+/// @code
+/// // Shared data and associated mutex and condition variable objects
+/// int count;
+/// mutex m;
+/// condition_variable cond;
+///
+/// // Wait for the counter to reach a certain number
+/// void wait_counter(int targetCount)
+/// {
+/// lock_guard<mutex> guard(m);
+/// while(count < targetCount)
+/// cond.wait(m);
+/// }
+///
+/// // Increment the counter, and notify waiting threads
+/// void increment()
+/// {
+/// lock_guard<mutex> guard(m);
+/// ++ count;
+/// cond.notify_all();
+/// }
+/// @endcode
+class condition_variable {
+ public:
+ /// Constructor.
+#if defined(_TTHREAD_WIN32_)
+ condition_variable();
+#else
+ condition_variable()
+ {
+ pthread_cond_init(&mHandle, NULL);
+ }
+#endif
+
+ /// Destructor.
+#if defined(_TTHREAD_WIN32_)
+ ~condition_variable();
+#else
+ ~condition_variable()
+ {
+ pthread_cond_destroy(&mHandle);
+ }
+#endif
+
+ /// Wait for the condition.
+ /// The function will block the calling thread until the condition variable
+ /// is woken by @c notify_one(), @c notify_all() or a spurious wake up.
+ /// @param[in] aMutex A mutex that will be unlocked when the wait operation
+ /// starts, an locked again as soon as the wait operation is finished.
+ template <class _mutexT>
+ inline void wait(_mutexT &aMutex)
+ {
+#if defined(_TTHREAD_WIN32_)
+ // Increment number of waiters
+ EnterCriticalSection(&mWaitersCountLock);
+ ++ mWaitersCount;
+ LeaveCriticalSection(&mWaitersCountLock);
+
+ // Release the mutex while waiting for the condition (will decrease
+ // the number of waiters when done)...
+ aMutex.unlock();
+ _wait();
+ aMutex.lock();
+#else
+ pthread_cond_wait(&mHandle, &aMutex.mHandle);
+#endif
+ }
+
+ /// Notify one thread that is waiting for the condition.
+ /// If at least one thread is blocked waiting for this condition variable,
+ /// one will be woken up.
+ /// @note Only threads that started waiting prior to this call will be
+ /// woken up.
+#if defined(_TTHREAD_WIN32_)
+ void notify_one();
+#else
+ inline void notify_one()
+ {
+ pthread_cond_signal(&mHandle);
+ }
+#endif
+
+ /// Notify all threads that are waiting for the condition.
+ /// All threads that are blocked waiting for this condition variable will
+ /// be woken up.
+ /// @note Only threads that started waiting prior to this call will be
+ /// woken up.
+#if defined(_TTHREAD_WIN32_)
+ void notify_all();
+#else
+ inline void notify_all()
+ {
+ pthread_cond_broadcast(&mHandle);
+ }
+#endif
+
+ _TTHREAD_DISABLE_ASSIGNMENT(condition_variable)
+
+ private:
+#if defined(_TTHREAD_WIN32_)
+ void _wait();
+ HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs.
+ unsigned int mWaitersCount; ///< Count of the number of waiters.
+ CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount.
+#else
+ pthread_cond_t mHandle;
+#endif
+};
+
+
+/// Thread class.
+class thread {
+ public:
+#if defined(_TTHREAD_WIN32_)
+ typedef HANDLE native_handle_type;
+#else
+ typedef pthread_t native_handle_type;
+#endif
+
+ class id;
+
+ /// Default constructor.
+ /// Construct a @c thread object without an associated thread of execution
+ /// (i.e. non-joinable).
+ thread() : mHandle(0), mNotAThread(true)
+#if defined(_TTHREAD_WIN32_)
+ , mWin32ThreadID(0)
+#endif
+ {}
+
+ /// Thread starting constructor.
+ /// Construct a @c thread object with a new thread of execution.
+ /// @param[in] aFunction A function pointer to a function of type:
+ /// <tt>void fun(void * arg)</tt>
+ /// @param[in] aArg Argument to the thread function.
+ /// @note This constructor is not fully compatible with the standard C++
+ /// thread class. It is more similar to the pthread_create() (POSIX) and
+ /// CreateThread() (Windows) functions.
+ thread(void (*aFunction)(void *), void * aArg);
+
+ /// Destructor.
+ /// @note If the thread is joinable upon destruction, @c std::terminate()
+ /// will be called, which terminates the process. It is always wise to do
+ /// @c join() before deleting a thread object.
+ ~thread();
+
+ /// Wait for the thread to finish (join execution flows).
+ /// After calling @c join(), the thread object is no longer associated with
+ /// a thread of execution (i.e. it is not joinable, and you may not join
+ /// with it nor detach from it).
+ void join();
+
+ /// Check if the thread is joinable.
+ /// A thread object is joinable if it has an associated thread of execution.
+ bool joinable() const;
+
+ /// Detach from the thread.
+ /// After calling @c detach(), the thread object is no longer assicated with
+ /// a thread of execution (i.e. it is not joinable). The thread continues
+ /// execution without the calling thread blocking, and when the thread
+ /// ends execution, any owned resources are released.
+ void detach();
+
+ /// Return the thread ID of a thread object.
+ id get_id() const;
+
+ /// Get the native handle for this thread.
+ /// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this
+ /// is a @c pthread_t.
+ inline native_handle_type native_handle()
+ {
+ return mHandle;
+ }
+
+ /// Determine the number of threads which can possibly execute concurrently.
+ /// This function is useful for determining the optimal number of threads to
+ /// use for a task.
+ /// @return The number of hardware thread contexts in the system.
+ /// @note If this value is not defined, the function returns zero (0).
+ static unsigned hardware_concurrency();
+
+ _TTHREAD_DISABLE_ASSIGNMENT(thread)
+
+ private:
+ native_handle_type mHandle; ///< Thread handle.
+ mutable mutex mDataMutex; ///< Serializer for access to the thread private data.
+ bool mNotAThread; ///< True if this object is not a thread of execution.
+#if defined(_TTHREAD_WIN32_)
+ unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex).
+#endif
+
+ // This is the internal thread wrapper function.
+#if defined(_TTHREAD_WIN32_)
+ static unsigned WINAPI wrapper_function(void * aArg);
+#else
+ static void * wrapper_function(void * aArg);
+#endif
+};
+
+/// Thread ID.
+/// The thread ID is a unique identifier for each thread.
+/// @see thread::get_id()
+class thread::id {
+ public:
+ /// Default constructor.
+ /// The default constructed ID is that of thread without a thread of
+ /// execution.
+ id() : mId(0) {};
+
+ id(unsigned long int aId) : mId(aId) {};
+
+ id(const id& aId) : mId(aId.mId) {};
+
+ inline id & operator=(const id &aId)
+ {
+ mId = aId.mId;
+ return *this;
+ }
+
+ inline friend bool operator==(const id &aId1, const id &aId2)
+ {
+ return (aId1.mId == aId2.mId);
+ }
+
+ inline friend bool operator!=(const id &aId1, const id &aId2)
+ {
+ return (aId1.mId != aId2.mId);
+ }
+
+ inline friend bool operator<=(const id &aId1, const id &aId2)
+ {
+ return (aId1.mId <= aId2.mId);
+ }
+
+ inline friend bool operator<(const id &aId1, const id &aId2)
+ {
+ return (aId1.mId < aId2.mId);
+ }
+
+ inline friend bool operator>=(const id &aId1, const id &aId2)
+ {
+ return (aId1.mId >= aId2.mId);
+ }
+
+ inline friend bool operator>(const id &aId1, const id &aId2)
+ {
+ return (aId1.mId > aId2.mId);
+ }
+
+ inline friend std::ostream& operator <<(std::ostream &os, const id &obj)
+ {
+ os << obj.mId;
+ return os;
+ }
+
+ private:
+ unsigned long int mId;
+};
+
+
+// Related to <ratio> - minimal to be able to support chrono.
+typedef long long __intmax_t;
+
+/// Minimal implementation of the @c ratio class. This class provides enough
+/// functionality to implement some basic @c chrono classes.
+template <__intmax_t N, __intmax_t D = 1> class ratio {
+ public:
+ static double _as_double() { return double(N) / double(D); }
+};
+
+/// Minimal implementation of the @c chrono namespace.
+/// The @c chrono namespace provides types for specifying time intervals.
+namespace chrono {
+ /// Duration template class. This class provides enough functionality to
+ /// implement @c this_thread::sleep_for().
+ template <class _Rep, class _Period = ratio<1> > class duration {
+ private:
+ _Rep rep_;
+ public:
+ typedef _Rep rep;
+ typedef _Period period;
+
+ /// Construct a duration object with the given duration.
+ template <class _Rep2>
+ explicit duration(const _Rep2& r) : rep_(r) {};
+
+ /// Return the value of the duration object.
+ rep count() const
+ {
+ return rep_;
+ }
+ };
+
+ // Standard duration types.
+ typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds.
+ typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds.
+ typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds.
+ typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds.
+ typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes.
+ typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours.
+}
+
+/// The namespace @c this_thread provides methods for dealing with the
+/// calling thread.
+namespace this_thread {
+ /// Return the thread ID of the calling thread.
+ thread::id get_id();
+
+ /// Yield execution to another thread.
+ /// Offers the operating system the opportunity to schedule another thread
+ /// that is ready to run on the current processor.
+ inline void yield()
+ {
+#if defined(_TTHREAD_WIN32_)
+ Sleep(0);
+#else
+ sched_yield();
+#endif
+ }
+
+ /// Blocks the calling thread for a period of time.
+ /// @param[in] aTime Minimum time to put the thread to sleep.
+ /// Example usage:
+ /// @code
+ /// // Sleep for 100 milliseconds
+ /// this_thread::sleep_for(chrono::milliseconds(100));
+ /// @endcode
+ /// @note Supported duration types are: nanoseconds, microseconds,
+ /// milliseconds, seconds, minutes and hours.
+ template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period>& aTime)
+ {
+#if defined(_TTHREAD_WIN32_)
+ Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5));
+#else
+ usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5));
+#endif
+ }
+}
+
+}
+
+// Define/macro cleanup
+#undef _TTHREAD_DISABLE_ASSIGNMENT
+
+#endif // _TINYTHREAD_H_
diff --git a/src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp
new file mode 100644
index 0000000..e31438a
--- /dev/null
+++ b/src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp
@@ -0,0 +1,289 @@
+#include "uscxml/datamodel/ecmascript/v8/V8DataModel.h"
+#include "uscxml/Message.h"
+
+namespace uscxml {
+
+V8DataModel::V8DataModel() {
+// _contexts.push_back(v8::Context::New());
+}
+
+DataModel* V8DataModel::create(Interpreter* interpreter) {
+ V8DataModel* dm = new V8DataModel();
+ dm->_interpreter = interpreter;
+ v8::Locker locker;
+ v8::HandleScope scope;
+
+ // see http://stackoverflow.com/questions/3171418/v8-functiontemplate-class-instance
+ dm->_globalTemplate = v8::Persistent<v8::ObjectTemplate>(v8::ObjectTemplate::New());
+ dm->_globalTemplate->Set(v8::String::New("In"), v8::FunctionTemplate::New(jsIn, v8::External::New(reinterpret_cast<void*>(this))));
+
+ dm->_contexts.push_back(v8::Context::New(0, _globalTemplate));
+ dm->setName(interpreter->getName());
+ dm->setSessionId(interpreter->getSessionId());
+ dm->eval("_ioprocessors = {};");
+ return dm;
+}
+
+void V8DataModel::setSessionId(const std::string& sessionId) {
+ _sessionId = sessionId;
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.front());
+ v8::Handle<v8::Object> global = _contexts.front()->Global();
+
+ global->Set(v8::String::New("_sessionid"), v8::String::New(sessionId.c_str()));
+}
+
+void V8DataModel::setName(const std::string& name) {
+ _name = name;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.front());
+ v8::Handle<v8::Object> global = _contexts.front()->Global();
+
+ global->Set(v8::String::New("_name"), v8::String::New(name.c_str()));
+}
+
+V8DataModel::~V8DataModel() {
+ while(_contexts.size() > 0) {
+ _contexts.back().Dispose();
+ _contexts.pop_back();
+ }
+}
+
+void V8DataModel::pushContext() {
+ _contexts.push_back(_contexts.back().New(_contexts.back()));
+}
+
+void V8DataModel::popContext() {
+ if (_contexts.size() > 1) {
+ _contexts.back().Dispose();
+ _contexts.pop_back();
+ }
+}
+
+void V8DataModel::initialize() {
+}
+
+void V8DataModel::setEvent(Event& event) {
+ _event = event;
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.front());
+ v8::Handle<v8::Object> global = _contexts.front()->Global();
+
+ // this is unfortunate - can't we store the template in the object?
+ if (_eventTemplate.IsEmpty()) {
+ v8::Handle<v8::ObjectTemplate> localEventTemplate = v8::ObjectTemplate::New();
+ localEventTemplate->SetInternalFieldCount(1); // we only have a single C++ object
+ localEventTemplate->SetAccessor(v8::String::New("name"), V8DataModel::jsGetEventName);
+ localEventTemplate->SetAccessor(v8::String::New("type"), V8DataModel::jsGetEventType);
+ localEventTemplate->SetAccessor(v8::String::New("sendid"), V8DataModel::jsGetEventSendId);
+ localEventTemplate->SetAccessor(v8::String::New("origin"), V8DataModel::jsGetEventOrigin);
+ localEventTemplate->SetAccessor(v8::String::New("origintype"), V8DataModel::jsGetEventOriginType);
+ localEventTemplate->SetAccessor(v8::String::New("invokeid"), V8DataModel::jsGetEventInvokeId);
+ _eventTemplate = v8::Persistent<v8::ObjectTemplate>::New(localEventTemplate);
+ }
+
+ assert(_eventTemplate->InternalFieldCount() == 1);
+ v8::Handle<v8::Object> eventJS = _eventTemplate->NewInstance();
+ eventJS->SetInternalField(0, v8::External::New(&event));
+
+ eventJS->Set(v8::String::New("data"), getDataAsValue(event)); // set data part of _event
+ global->Set(v8::String::New("_event"), eventJS);
+}
+
+void V8DataModel::setData(const std::string& key, Data& data) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.front());
+ v8::Handle<v8::Object> global = _contexts.front()->Global();
+ global->Set(v8::String::New(key.c_str()), getDataAsValue(data));
+}
+
+v8::Handle<v8::Value> V8DataModel::getDataAsValue(Data& data) {
+ if (data.compound.size() > 0) {
+ v8::Handle<v8::Object> value = v8::Array::New();
+ std::map<std::string, Data>::iterator compoundIter = data.compound.begin();
+ while(compoundIter != data.compound.end()) {
+ value->Set(v8::String::New(compoundIter->first.c_str()), getDataAsValue(compoundIter->second));
+ compoundIter++;
+ }
+ return value;
+ }
+ if (data.array.size() > 0) {
+ v8::Handle<v8::Object> value = v8::Array::New();
+ std::vector<Data>::iterator arrayIter = data.array.begin();
+ uint32_t index = 0;
+ while(arrayIter != data.array.end()) {
+ value->Set(index++, getDataAsValue(*arrayIter));
+ arrayIter++;
+ }
+ return value;
+ }
+ if (data.type == Data::VERBATIM) {
+ return v8::String::New(data.atom.c_str());
+ } else {
+ return evalAsValue(data.atom);
+ }
+}
+
+v8::Handle<v8::Value> V8DataModel::jsIn(const v8::Arguments& args) {
+ V8DataModel* THIS = static_cast<V8DataModel*>(v8::External::Unwrap(args.Data()));
+ for (unsigned int i = 0; i < args.Length(); i++) {
+ if (args[i]->IsString()) {
+ std::string stateName(*v8::String::AsciiValue(args[i]->ToString()));
+ if (Interpreter::isMember(THIS->_interpreter->getState(stateName), THIS->_interpreter->getConfiguration())) {
+ continue;
+ }
+ }
+ return v8::Boolean::New(false);
+ }
+ return v8::Boolean::New(true);
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventName(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->name.c_str());
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventType(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ switch (event->type) {
+ case Event::PLATFORM:
+ return v8::String::New("platform");
+ break;
+ case Event::INTERNAL:
+ return v8::String::New("internal");
+ break;
+ case Event::EXTERNAL:
+ return v8::String::New("external");
+ break;
+ default:
+ return v8::String::New("");
+ break;
+ }
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventSendId(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->sendid.c_str());
+
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventOrigin(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->origin.c_str());
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventOriginType(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->origintype.c_str());
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventInvokeId(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->invokeid.c_str());
+}
+
+bool V8DataModel::validate(const std::string& location, const std::string& schema) {
+ return true;
+}
+
+uint32_t V8DataModel::getLength(const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ v8::Handle<v8::Array> result = evalAsValue(expr).As<v8::Array>();
+ return result->Length();
+}
+
+void V8DataModel::eval(const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ evalAsValue(expr);
+}
+
+bool V8DataModel::evalAsBool(const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ v8::Handle<v8::Value> result = evalAsValue(expr);
+ return(result->ToBoolean()->BooleanValue());
+}
+
+std::string V8DataModel::evalAsString(const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ v8::Handle<v8::Value> result = evalAsValue(expr);
+ v8::String::AsciiValue data(result->ToString());
+ return std::string(*data);
+}
+
+void V8DataModel::assign(const std::string& location, const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ evalAsValue((location + " = " + expr).c_str());
+}
+
+v8::Handle<v8::Value> V8DataModel::evalAsValue(const std::string& expr) {
+ v8::TryCatch tryCatch;
+ v8::Handle<v8::String> source = v8::String::New(expr.c_str());
+ v8::Handle<v8::Script> script = v8::Script::Compile(source);
+
+ v8::Handle<v8::Value> result;
+ if (!script.IsEmpty())
+ result = script->Run();
+
+ if (script.IsEmpty() || result.IsEmpty()) {
+ // throw an exception
+ assert(tryCatch.HasCaught());
+ Event exceptionEvent;
+ exceptionEvent.name = "error.execution";
+
+ std::string exceptionString(*v8::String::AsciiValue(tryCatch.Exception()));
+ exceptionEvent.compound["exception"] = Data(exceptionString, Data::VERBATIM);;
+
+ v8::Handle<v8::Message> message = tryCatch.Message();
+ if (!message.IsEmpty()) {
+ std::string filename(*v8::String::AsciiValue(message->GetScriptResourceName()));
+ exceptionEvent.compound["filename"] = Data(filename, Data::VERBATIM);
+
+ std::string sourceLine(*v8::String::AsciiValue(message->GetSourceLine()));
+ exceptionEvent.compound["sourceline"] = Data(sourceLine, Data::VERBATIM);
+
+ std::stringstream ssLineNumber;
+ int lineNumber = message->GetLineNumber();
+ ssLineNumber << lineNumber;
+ exceptionEvent.compound["linenumber"] = Data(ssLineNumber.str());
+
+ int startColumn = message->GetStartColumn();
+ int endColumn = message->GetEndColumn();
+ std::stringstream ssUnderline;
+ for (int i = 0; i < startColumn; i++)
+ ssUnderline << " ";
+ for (int i = startColumn; i < endColumn; i++)
+ ssUnderline << "^";
+ exceptionEvent.compound["sourcemark"] = Data(ssUnderline.str(), Data::VERBATIM);
+
+ std::string stackTrace(*v8::String::AsciiValue(tryCatch.StackTrace()));
+ exceptionEvent.compound["stacktrace"] = Data(stackTrace, Data::VERBATIM);
+
+ }
+
+ _interpreter->receiveInternal(exceptionEvent);
+ throw(exceptionEvent);
+ }
+
+ return result;
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/datamodel/ecmascript/v8/V8DataModel.h
new file mode 100644
index 0000000..7522679
--- /dev/null
+++ b/src/uscxml/datamodel/ecmascript/v8/V8DataModel.h
@@ -0,0 +1,73 @@
+#ifndef V8DATAMODEL_H_KN8TWG0V
+#define V8DATAMODEL_H_KN8TWG0V
+
+#include "uscxml/Interpreter.h"
+#include <list>
+#include <v8.h>
+
+namespace uscxml {
+ class Event;
+ class Data;
+}
+
+namespace uscxml {
+
+class V8DataModel : public DataModel {
+public:
+ V8DataModel();
+ virtual ~V8DataModel();
+ virtual DataModel* create(Interpreter* interpreter);
+
+ virtual void initialize();
+ virtual void setSessionId(const std::string& sessionId);
+ virtual void setName(const std::string& name);
+ virtual void setEvent(Event& event);
+ virtual void setData(const std::string& key, Data& event);
+ virtual v8::Handle<v8::Value> getDataAsValue(Data& data);
+
+ virtual bool validate(const std::string& location, const std::string& schema);
+
+ virtual uint32_t getLength(const std::string& expr);
+ virtual void pushContext();
+ virtual void popContext();
+
+ virtual void eval(const std::string& expr);
+ virtual void assign(const std::string& location, const std::string& expr);
+
+ virtual std::string evalAsString(const std::string& expr);
+ virtual bool evalAsBool(const std::string& expr);
+
+ static v8::Handle<v8::Value> jsGetEventName(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> jsGetEventType(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> jsGetEventSendId(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> jsGetEventOrigin(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> jsGetEventOriginType(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> jsGetEventInvokeId(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+
+ static v8::Handle<v8::Value> jsIn(const v8::Arguments& args);
+
+
+protected:
+ std::list<v8::Persistent<v8::Context> > _contexts;
+ Interpreter* _interpreter;
+
+ std::string _sessionId;
+ std::string _name;
+
+ Event _event;
+ v8::Persistent<v8::ObjectTemplate> _globalTemplate;
+ v8::Persistent<v8::ObjectTemplate> _eventTemplate;
+
+ v8::Handle<v8::Value> evalAsValue(const std::string& expr);
+
+};
+
+}
+
+#endif /* end of include guard: V8DATAMODEL_H_KN8TWG0V */
diff --git a/src/uscxml/ioprocessor/basichttp/README.md b/src/uscxml/ioprocessor/basichttp/README.md
new file mode 100644
index 0000000..de89944
--- /dev/null
+++ b/src/uscxml/ioprocessor/basichttp/README.md
@@ -0,0 +1,2 @@
+Only the libevent basichttp ioprocessor is supported. Mongoose seemed somewhat
+unmaintained and pion comes with too many dependencies. \ No newline at end of file
diff --git a/src/uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.cpp b/src/uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.cpp
new file mode 100644
index 0000000..c06c7e8
--- /dev/null
+++ b/src/uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.cpp
@@ -0,0 +1,361 @@
+#include "uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.h"
+#include "uscxml/Message.h"
+#include <iostream>
+#include <event2/dns.h>
+#include <event2/buffer.h>
+#include <event2/keyvalq_struct.h>
+
+#include <string.h>
+
+#include <io/uri.hpp>
+#include <glog/logging.h>
+
+#include <netdb.h>
+#include <arpa/inet.h>
+
+namespace uscxml {
+namespace io {
+namespace libevent {
+
+// see http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor
+
+EventIOProcessor::EventIOProcessor() {
+}
+
+EventIOProcessor::~EventIOProcessor() {
+ _eventQueue.stop();
+ EventIOServer* httpServer = EventIOServer::getInstance();
+ httpServer->unregisterProcessor(this);
+}
+
+IOProcessor* EventIOProcessor::create(Interpreter* interpreter) {
+ EventIOProcessor* io = new EventIOProcessor();
+ io->_interpreter = interpreter;
+
+ io->_dns = evdns_base_new(io->_eventQueue._eventLoop, 1);
+ assert(io->_dns);
+ assert(evdns_base_count_nameservers(io->_dns) > 0);
+
+ // register at http server
+ EventIOServer* httpServer = EventIOServer::getInstance();
+ httpServer->registerProcessor(io);
+
+ io->start();
+ return io;
+}
+
+void EventIOProcessor::start() {
+ _eventQueue.start();
+}
+
+void EventIOProcessor::send(SendRequest& req) {
+ // I cant figure out how to copy the reference into the struct :(
+ _sendData[req.sendid].req = req;
+ _sendData[req.sendid].ioProcessor = this;
+
+ if (req.delayMs > 0) {
+ LOG(INFO) << "Enqueing HTTP send request";
+ _eventQueue.addEvent(req.sendid, EventIOProcessor::httpMakeSendReq, req.delayMs, &_sendData[req.sendid]);
+ } else {
+ LOG(INFO) << "Sending HTTP send request";
+ EventIOProcessor::httpMakeSendReq(&_sendData[req.sendid], req.sendid);
+ }
+}
+
+void EventIOProcessor::httpMakeSendReq(void* userdata, std::string eventName) {
+ SendData* sendData = ((SendData*)userdata);
+ EventIOProcessor* THIS = sendData->ioProcessor;
+ int err = 0;
+ char uriBuf[1024];
+
+ struct evhttp_uri* targetURI = evhttp_uri_parse(sendData->req.target.c_str());
+ if (evhttp_uri_get_port(targetURI) == 0)
+ evhttp_uri_set_port(targetURI, 80);
+ const char* hostName = evhttp_uri_get_host(targetURI);
+
+ // use synchronous dns resolving for multicast dns
+ if(strlen(hostName) >= strlen(".local")) {
+ if(strcmp(hostName + strlen(hostName) - strlen(".local"), ".local") == 0) {
+ evhttp_uri_set_host(targetURI, EventIOServer::syncResolve(hostName).c_str());
+ }
+ }
+ evhttp_uri_join(targetURI, uriBuf, 1024);
+
+ LOG(INFO) << "URI for send request: " << uriBuf << std::endl;
+
+ std::stringstream ssEndPoint;
+ ssEndPoint << evhttp_uri_get_host(targetURI) << ":" << evhttp_uri_get_port(targetURI);
+ std::string endPoint = ssEndPoint.str();
+
+ std::stringstream ssLocalURI;
+ ssLocalURI << evhttp_uri_get_path(targetURI) << evhttp_uri_get_fragment(targetURI);
+ std::string localURI = ssLocalURI.str();
+
+ if (THIS->_httpConnections.find(endPoint) == THIS->_httpConnections.end())
+ THIS->_httpConnections[endPoint] = evhttp_connection_base_new(THIS->_eventQueue._eventLoop, THIS->_dns, evhttp_uri_get_host(targetURI), evhttp_uri_get_port(targetURI));
+
+ struct evhttp_connection* httpConn = THIS->_httpConnections[endPoint];
+ struct evhttp_request* httpReq = evhttp_request_new(EventIOProcessor::httpSendReqDone, userdata);
+
+#if 0
+ // event name
+ if (sendData->req.event.size() > 0) {
+ evhttp_add_header(evhttp_request_get_output_headers(httpReq), "_scxmleventname", evhttp_encode_uri(sendData->req.event.c_str()));
+ }
+
+ // event namelist
+ if (sendData->req.namelist.size() > 0) {
+ std::map<std::string, std::string>::iterator namelistIter = sendData->req.namelist.begin();
+ while (namelistIter != sendData->req.namelist.end()) {
+ evhttp_add_header(evhttp_request_get_output_headers(httpReq),
+ namelistIter->first.c_str(),
+ evhttp_encode_uri(namelistIter->second.c_str()));
+ namelistIter++;
+ }
+ }
+
+ // event params
+ if (sendData->req.params.size() > 0) {
+ std::map<std::string, std::string>::iterator paramIter = sendData->req.params.begin();
+ while (paramIter != sendData->req.params.end()) {
+ evhttp_add_header(evhttp_request_get_output_headers(httpReq),
+ paramIter->first.c_str(),
+ evhttp_encode_uri(paramIter->second.c_str()));
+ paramIter++;
+ }
+ }
+
+ // content
+ if (sendData->req.content.size() > 0)
+ evbuffer_add(evhttp_request_get_output_buffer(httpReq), sendData->req.content.c_str(), sendData->req.content.size());
+#endif
+
+ evhttp_add_header(evhttp_request_get_output_headers(httpReq), "_scxmleventstruct", evhttp_encode_uri(sendData->req.toXMLString().c_str()));
+
+
+ THIS->_httpRequests[sendData->req.sendid] = httpReq;
+ err = evhttp_make_request(httpConn,
+ httpReq,
+ EVHTTP_REQ_POST, localURI.c_str());
+ if (err) {
+ LOG(ERROR) << "Could not make http request to " << sendData->req.target;
+ }
+}
+
+void EventIOProcessor::httpRecvReq(struct evhttp_request *req, void *arg) {
+
+ const char *cmdtype;
+ struct evkeyvalq *headers;
+ struct evkeyval *header;
+ struct evbuffer *buf;
+
+ switch (evhttp_request_get_command(req)) {
+ case EVHTTP_REQ_GET: cmdtype = "GET"; break;
+ case EVHTTP_REQ_POST: cmdtype = "POST"; break;
+ case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break;
+ case EVHTTP_REQ_PUT: cmdtype = "PUT"; break;
+ case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break;
+ case EVHTTP_REQ_OPTIONS: cmdtype = "OPTIONS"; break;
+ case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break;
+ case EVHTTP_REQ_CONNECT: cmdtype = "CONNECT"; break;
+ case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break;
+ default: cmdtype = "unknown"; break;
+ }
+
+ Event reqEvent;
+ reqEvent.type = Event::EXTERNAL;
+
+ // map headers to event structure
+ headers = evhttp_request_get_input_headers(req);
+ for (header = headers->tqh_first; header;
+ header = header->next.tqe_next) {
+// std::cout << "Header: " << header->key << std::endl;
+// std::cout << "Value: " << evhttp_decode_uri(header->value) << std::endl;
+ if (boost::iequals("_scxmleventstruct", header->key)) {
+ reqEvent = Event::fromXML(evhttp_decode_uri(header->value));
+ break;
+ } else if (boost::iequals("_scxmleventname", header->key)) {
+ reqEvent.name = evhttp_decode_uri(header->value);
+ } else {
+ reqEvent.compound[header->key] = Data(evhttp_decode_uri(header->value), Data::VERBATIM);
+ }
+ }
+
+ // get content into event
+ std::string content;
+ buf = evhttp_request_get_input_buffer(req);
+ while (evbuffer_get_length(buf)) {
+ int n;
+ char cbuf[128];
+ n = evbuffer_remove(buf, cbuf, sizeof(buf)-1);
+ if (n > 0) {
+ content.append(cbuf, n);
+ }
+ }
+ reqEvent.compound["content"] = Data(content, Data::VERBATIM);
+
+ EventIOProcessor* THIS = (EventIOProcessor*)arg;
+ THIS->_interpreter->receive(reqEvent);
+
+ evhttp_send_reply(req, 200, "OK", NULL);
+}
+
+void EventIOProcessor::httpSendReqDone(struct evhttp_request *req, void *cb_arg) {
+ if (req) {
+ LOG(INFO) << "got return code " << evhttp_request_get_response_code(req) << std::endl;
+ }
+}
+
+void EventIOProcessor::invoke(InvokeRequest& req) {
+
+}
+void EventIOProcessor::cancel(const std::string sendId) {
+
+}
+
+EventIOServer::EventIOServer(unsigned short port) {
+ _port = port;
+ _base = event_base_new();
+ _http = evhttp_new(_base);
+ _handle = NULL;
+ while((_handle = evhttp_bind_socket_with_handle(_http, INADDR_ANY, _port)) == NULL) {
+ _port++;
+ }
+ determineAddress();
+}
+
+EventIOServer::~EventIOServer() {
+}
+
+EventIOServer* EventIOServer::_instance = NULL;
+tthread::recursive_mutex EventIOServer::_instanceMutex;
+
+EventIOServer* EventIOServer::getInstance() {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_instanceMutex);
+ if (_instance == NULL) {
+ _instance = new EventIOServer(8080);
+ _instance->start();
+ }
+ return _instance;
+}
+
+void EventIOServer::registerProcessor(EventIOProcessor* processor) {
+ EventIOServer* THIS = getInstance();
+ tthread::lock_guard<tthread::recursive_mutex> lock(THIS->_mutex);
+
+ /**
+ * Determine path for interpreter.
+ *
+ * If the interpreter has a name and it is not yet taken, choose it as the path
+ * for requests. If the interpreters name path is already taken, append digits
+ * until we have an available path.
+ *
+ * If the interpreter does not specify a name, take its sessionid.
+ */
+
+ std::string path = processor->_interpreter->getName();
+ if (path.size() == 0) {
+ path = processor->_interpreter->getSessionId();
+ }
+ assert(path.size() > 0);
+
+ std::stringstream actualPath(path);
+ int i = 1;
+ while(THIS->_processors.find(actualPath.str()) != THIS->_processors.end()) {
+ actualPath.str(std::string());
+ actualPath.clear();
+ actualPath << path << ++i;
+ }
+
+ std::stringstream processorURL;
+ processorURL << "http://" << THIS->_address << ":" << THIS->_port << "/" << actualPath.str();
+
+ THIS->_processors[actualPath.str()] = processor;
+ processor->setURL(processorURL.str());
+
+ evhttp_set_cb(THIS->_http, ("/" + actualPath.str()).c_str(), EventIOProcessor::httpRecvReq, processor);
+// evhttp_set_cb(THIS->_http, "/", EventIOProcessor::httpRecvReq, processor);
+// evhttp_set_gencb(THIS->_http, EventIOProcessor::httpRecvReq, NULL);
+}
+
+void EventIOServer::unregisterProcessor(EventIOProcessor* processor) {
+ EventIOServer* THIS = getInstance();
+ tthread::lock_guard<tthread::recursive_mutex> lock(THIS->_mutex);
+ evhttp_del_cb(THIS->_http, processor->getURL().c_str());
+}
+
+void EventIOServer::start() {
+ _isRunning = true;
+ _thread = new tthread::thread(EventIOServer::run, this);
+}
+
+void EventIOServer::run(void* instance) {
+ EventIOServer* THIS = (EventIOServer*)instance;
+ while(THIS->_isRunning) {
+ LOG(INFO) << "Dispatching HTTP Server" << std::endl;
+ event_base_dispatch(THIS->_base);
+ }
+ LOG(INFO) << "HTTP Server stopped" << std::endl;
+}
+
+std::string EventIOServer::syncResolve(const std::string& hostname) {
+ struct hostent *he;
+ struct in_addr **addr_list;
+ int i;
+
+ if ( (he = gethostbyname( hostname.c_str() ) ) != NULL) {
+ addr_list = (struct in_addr **) he->h_addr_list;
+ for(i = 0; addr_list[i] != NULL; i++) {
+ return std::string(inet_ntoa(*addr_list[i]));
+ }
+ }
+ return "";
+}
+
+void EventIOServer::determineAddress() {
+
+ char hostname[1024];
+ gethostname(hostname, 1024);
+ _address = std::string(hostname);
+
+#if 0
+ struct sockaddr_storage ss;
+ evutil_socket_t fd;
+ ev_socklen_t socklen = sizeof(ss);
+ char addrbuf[128];
+
+ void *inaddr;
+ const char *addr;
+ int got_port = -1;
+ fd = evhttp_bound_socket_get_fd(_handle);
+ memset(&ss, 0, sizeof(ss));
+ if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) {
+ perror("getsockname() failed");
+ return;
+ }
+
+ if (ss.ss_family == AF_INET) {
+ got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
+ inaddr = &((struct sockaddr_in*)&ss)->sin_addr;
+ } else if (ss.ss_family == AF_INET6) {
+ got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
+ inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr;
+ } else {
+ fprintf(stderr, "Weird address family %d\n",
+ ss.ss_family);
+ return;
+ }
+ addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf,
+ sizeof(addrbuf));
+ if (addr) {
+ _address = std::string(addr);
+ } else {
+ fprintf(stderr, "evutil_inet_ntop failed\n");
+ return;
+ }
+#endif
+}
+
+}
+}
+} \ No newline at end of file
diff --git a/src/uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.h b/src/uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.h
new file mode 100644
index 0000000..7e8eaa9
--- /dev/null
+++ b/src/uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.h
@@ -0,0 +1,96 @@
+#ifndef EVENTIOPROCESSOR_H_2CUY93KU
+#define EVENTIOPROCESSOR_H_2CUY93KU
+
+#include "uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h"
+#include "uscxml/Interpreter.h"
+#include "uscxml/Factory.h"
+#include <sys/time.h>
+
+#include <event2/http.h>
+#include <event2/http_struct.h>
+
+namespace uscxml {
+namespace io {
+namespace libevent {
+
+class EventIOServer;
+
+class EventIOProcessor : public uscxml::IOProcessor {
+public:
+ struct SendData {
+ EventIOProcessor* ioProcessor;
+ uscxml::SendRequest req;
+ };
+
+ EventIOProcessor();
+ virtual ~EventIOProcessor();
+ virtual IOProcessor* create(uscxml::Interpreter* interpreter);
+
+ virtual void send(uscxml::SendRequest& req);
+ virtual void invoke(uscxml::InvokeRequest& req);
+ virtual void cancel(const std::string sendId);
+
+ std::string getURL() { return _url; }
+ void setURL(const std::string& url) { _url = url; }
+
+ void start();
+ static void run(void* instance);
+
+ static void httpMakeSendReq(void* userdata, std::string eventName);
+ static void httpSendReqDone(struct evhttp_request *req, void *cb_arg);
+ static void httpRecvReq(struct evhttp_request *req, void *arg);
+
+protected:
+ std::map<std::string, SendData> _sendData;
+
+ std::string _url;
+
+ uscxml::DelayedEventQueue _eventQueue;
+ uscxml::Interpreter* _interpreter;
+ std::map<std::string, struct evhttp_connection*> _httpConnections;
+ std::map<std::string, struct evhttp_request*> _httpRequests;
+ struct evdns_base* _dns;
+
+ friend class EventIOServer;
+};
+
+class EventIOServer {
+private:
+ static EventIOServer* getInstance();
+ EventIOServer(unsigned short port);
+ ~EventIOServer();
+
+ void start();
+ void stop();
+ static void run(void* instance);
+
+ void determineAddress();
+ static std::string syncResolve(const std::string& hostname);
+
+ static void registerProcessor(EventIOProcessor* processor);
+ static void unregisterProcessor(EventIOProcessor* processor);
+
+
+ std::map<std::string, EventIOProcessor*> _processors;
+
+ struct event_base* _base;
+ struct evhttp* _http;
+ struct evhttp_bound_socket* _handle;
+
+ unsigned short _port;
+ std::string _address;
+
+ static EventIOServer* _instance;
+ static tthread::recursive_mutex _instanceMutex;
+ tthread::thread* _thread;
+ tthread::recursive_mutex _mutex;
+ bool _isRunning;
+
+ friend class EventIOProcessor;
+};
+
+}
+}
+}
+
+#endif /* end of include guard: EVENTIOPROCESSOR_H_2CUY93KU */ \ No newline at end of file
diff --git a/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.cpp b/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.cpp
new file mode 100644
index 0000000..a62fefc
--- /dev/null
+++ b/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.cpp
@@ -0,0 +1,3 @@
+#include "uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.h"
+#include "uscxml/Message.h"
+
diff --git a/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.h b/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.h
new file mode 100644
index 0000000..bb7a0fc
--- /dev/null
+++ b/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.h
@@ -0,0 +1,15 @@
+#ifndef MONGOOSEIOPROCESSOR_H_JS0GMSFO
+#define MONGOOSEIOPROCESSOR_H_JS0GMSFO
+
+#include "uscxml/Interpreter.h"
+#include "uscxml/Factory.h"
+
+namespace uscxml {
+
+class MongooseIOProcessor : public IOProcessor {
+
+};
+
+}
+
+#endif /* end of include guard: MONGOOSEIOPROCESSOR_H_JS0GMSFO */
diff --git a/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.cpp b/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.cpp
new file mode 100644
index 0000000..7aa9169
--- /dev/null
+++ b/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.cpp
@@ -0,0 +1,74 @@
+#include "uscxml/ioprocessor/basichttp/pion/PionIOProcessor.h"
+#include "uscxml/Message.h"
+
+#include <pion/http/request.hpp>
+#include <pion/http/message.hpp>
+
+namespace uscxml {
+
+using namespace pion;
+
+PionIOProcessor::PionIOProcessor() {
+}
+
+PionIOProcessor::~PionIOProcessor() {
+
+}
+
+IOProcessor* PionIOProcessor::create(Interpreter* interpreter) {
+ PionIOProcessor* io = new PionIOProcessor();
+ io->_interpreter = interpreter;
+ io->_ioServer = PionIOServer::getInstance();
+ return io;
+}
+
+void handle_connection(pion::tcp::connection_ptr& tcp_conn) {
+}
+
+void PionIOProcessor::send(SendRequest& req) {
+
+ boost::system::error_code error_code;
+ boost::asio::io_service io_service;
+
+ pion::tcp::connection tcp_conn(io_service, 0);
+ error_code = tcp_conn.connect("localhost", 8080);
+ if (error_code) throw error_code; // connection failed
+
+
+
+ http::request httpReq;
+ httpReq.set_method("POST");
+ if (req.event.size() > 0)
+ httpReq.add_header("_scxmleventname", req.event);
+
+ httpReq.send(tcp_conn, error_code);
+
+// http::request_writer writer;
+// writer.
+
+}
+void PionIOProcessor::invoke(InvokeRequest& req) {
+
+}
+void PionIOProcessor::cancel(const std::string sendId) {
+
+}
+
+PionIOServer::PionIOServer() : pion::tcp::server(0) {
+}
+
+PionIOServer::~PionIOServer() {
+}
+
+void PionIOServer::handle_connection(pion::tcp::connection_ptr& tcp_conn) {
+}
+
+PionIOServer* PionIOServer::_instance = NULL;
+PionIOServer* PionIOServer::getInstance() {
+ if (_instance == NULL) {
+ _instance = new PionIOServer();
+ }
+ return _instance;
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.h b/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.h
new file mode 100644
index 0000000..154acdb
--- /dev/null
+++ b/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.h
@@ -0,0 +1,47 @@
+#ifndef PIONIOPROCESSOR_H_VAITDNCN
+#define PIONIOPROCESSOR_H_VAITDNCN
+
+#include "uscxml/Interpreter.h"
+#include "uscxml/Factory.h"
+#include "uscxml/concurrency/DelayedEventQueue.h"
+
+#include <pion/http/request_writer.hpp>
+#include <pion/http/request_writer.hpp>
+#include <pion/tcp/server.hpp>
+
+namespace uscxml {
+
+class PionIOServer : public pion::tcp::server {
+public:
+ PionIOServer();
+ virtual ~PionIOServer();
+ DelayedEventQueue _eventQueue;
+
+ virtual void handle_connection(pion::tcp::connection_ptr& tcp_conn);
+
+ static PionIOServer* getInstance();
+ static PionIOServer* _instance;
+
+ pion::http::request_writer_ptr _writer;
+ pion::tcp::connection_ptr _conn;
+
+};
+
+class PionIOProcessor : public IOProcessor {
+public:
+ PionIOProcessor();
+ virtual ~PionIOProcessor();
+ virtual IOProcessor* create(Interpreter* interpreter);
+
+ virtual void send(SendRequest& req);
+ virtual void invoke(InvokeRequest& req);
+ virtual void cancel(const std::string sendId);
+
+protected:
+ Interpreter* _interpreter;
+ PionIOServer* _ioServer;
+};
+
+}
+
+#endif /* end of include guard: PIONIOPROCESSOR_H_VAITDNCN */
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..297428c
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,29 @@
+add_executable(test-predicates src/test-predicates.cpp)
+target_link_libraries(test-predicates uscxml)
+add_test(test-predicates ${CMAKE_SOURCE_DIR}/test/src/test-predicates.scxml)
+set_target_properties(test-predicates PROPERTIES FOLDER "Tests")
+
+add_executable(test-execution src/test-execution.cpp)
+target_link_libraries(test-execution uscxml)
+add_test(test-execution ${CMAKE_SOURCE_DIR}/test/src/test-execution.scxml)
+set_target_properties(test-execution PROPERTIES FOLDER "Tests")
+
+add_executable(test-apache-commons src/test-apache-commons.cpp)
+target_link_libraries(test-apache-commons uscxml)
+add_test(test-apache-commons ${CMAKE_SOURCE_DIR}/test/apache)
+set_target_properties(test-apache-commons PROPERTIES FOLDER "Tests")
+
+add_executable(test-ecmascript-v8 src/test-ecmascript-v8.cpp)
+target_link_libraries(test-ecmascript-v8 uscxml)
+add_test(test-ecmascript-v8 test-ecmascript-v8)
+set_target_properties(test-ecmascript-v8 PROPERTIES FOLDER "Tests")
+
+add_executable(test-communication src/test-communication.cpp)
+target_link_libraries(test-communication uscxml)
+add_test(test-communication test-communication)
+set_target_properties(test-communication PROPERTIES FOLDER "Tests")
+
+add_executable(test-eventdelay src/test-eventdelay.cpp)
+target_link_libraries(test-eventdelay uscxml)
+add_test(test-eventdelay test-eventdelay)
+set_target_properties(test-eventdelay PROPERTIES FOLDER "Tests")
diff --git a/test/samples/apache/actions-initial-test.xml b/test/samples/apache/actions-initial-test.xml
new file mode 100644
index 0000000..d2d3e48
--- /dev/null
+++ b/test/samples/apache/actions-initial-test.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:cs="http://commons.apache.org/scxml"
+ version="1.0"
+ initial="actionsTest">
+
+ <state id="actionsTest">
+ <initial>
+ <transition target="child1">
+ <cs:var name="foo"/>
+ <cs:var name="delta" expr="${1+2+3}" />
+ <cs:var name="eventsent"/>
+ <if cond="${delta le 3}">
+ <assign name="foo" expr="bar" />
+ <elseif cond="${delta eq 3}"/>
+ <assign name="foo" expr="fubar" />
+ <else/>
+ <assign name="foo" expr="foobar" />
+ </if>
+ <cs:var name="drink" expr="water" />
+ <cs:var name="eat" expr="flies" />
+ <send sendid="send12345" target="freddy" type="frog"
+ event="croak" namelist="drink eat" hints="h2o bzz"
+ delay="${1000+500}" />
+ <cancel sendId="send12345"/>
+ <log expr="leaving" label="entry001" />
+ <event name="event.test"/>
+ <!-- exit will be ignored, makes little sense in initial -->
+ <cs:exit expr="later" namelist="freddy" />
+ </transition>
+ </initial>
+
+ <transition event="event.test">
+ <assign name="eventsent" expr="true"/>
+ </transition>
+
+ <state id="child1"/>
+
+ </state>
+
+</scxml> \ No newline at end of file
diff --git a/test/samples/apache/actions-parallel-test.xml b/test/samples/apache/actions-parallel-test.xml
new file mode 100644
index 0000000..be9d25c
--- /dev/null
+++ b/test/samples/apache/actions-parallel-test.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:cs="http://commons.apache.org/scxml"
+ version="1.0"
+ initial="actionsTest">
+
+ <parallel id="actionsTest">
+ <onentry>
+ <cs:var name="foo"/>
+ <cs:var name="delta" expr="${1+2+3}" />
+ <cs:var name="eventsent"/>
+ <if cond="${delta le 3}">
+ <assign name="foo" expr="bar" />
+ <elseif cond="${delta eq 3}"/>
+ <assign name="foo" expr="fubar" />
+ <else/>
+ <assign name="foo" expr="foobar" />
+ </if>
+ <cs:var name="drink" expr="water" />
+ <cs:var name="eat" expr="flies" />
+ <send sendid="send12345" target="freddy" type="frog"
+ event="croak" namelist="drink eat" hints="h2o bzz"
+ delay="${1000+500}" />
+ <cancel sendId="send12345"/>
+ <log expr="leaving" label="entry001" />
+ <event name="event.test"/>
+ <cs:exit expr="later" namelist="freddy" />
+ </onentry>
+
+ <transition event="event.test">
+ <assign name="eventsent" expr="true"/>
+ </transition>
+
+ <!-- dummy regions -->
+ <state id="state01"/>
+ <state id="state02"/>
+ </parallel>
+
+</scxml> \ No newline at end of file
diff --git a/test/samples/apache/actions-state-test.xml b/test/samples/apache/actions-state-test.xml
new file mode 100644
index 0000000..3374e21
--- /dev/null
+++ b/test/samples/apache/actions-state-test.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:cs="http://commons.apache.org/scxml"
+ version="1.0"
+ initialstate="actionsTest">
+
+ <state id="actionsTest" final="true">
+ <onentry>
+ <cs:var name="foo"/>
+ <cs:var name="delta" expr="${1+2+3}" />
+ <cs:var name="eventsent"/>
+ <if cond="${delta le 3}">
+ <assign name="foo" expr="bar" />
+ <elseif cond="${delta eq 3}"/>
+ <assign name="foo" expr="fubar" />
+ <else/>
+ <assign name="foo" expr="foobar" />
+ </if>
+ <cs:var name="drink" expr="water" />
+ <cs:var name="eat" expr="flies" />
+ <send sendid="send12345" target="freddy" type="frog"
+ event="croak" namelist="drink eat" hints="h2o bzz"
+ delay="${1000+500}" />
+ <cancel sendId="send12345"/>
+ <log expr="leaving" label="entry001" />
+ <event name="event.test"/>
+ <cs:exit expr="later" namelist="freddy" />
+ </onentry>
+
+ <transition event="event.test">
+ <assign name="eventsent" expr="true"/>
+ </transition>
+
+ </state>
+
+</scxml> \ No newline at end of file
diff --git a/test/samples/apache/assign-test-01.xml b/test/samples/apache/assign-test-01.xml
new file mode 100644
index 0000000..ed7e977
--- /dev/null
+++ b/test/samples/apache/assign-test-01.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Test "src" attribute of assign element -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:rad="http://foo/bar"
+ version="1.0"
+ initialstate="assign1">
+
+ <state id="assign1" final="true">
+
+ <datamodel>
+ <data id="foo">
+ <root xmlns="">
+ <foo/>
+ </root>
+ </data>
+ <data id="bar">
+ <root xmlns="">
+ <bar>5</bar>
+ </root>
+ </data>
+ </datamodel>
+
+ <onentry>
+ <assign location="Data(foo,'root/foo')" src="assign-src.xml"/>
+ </onentry>
+
+ <transition cond="Data(foo,'root/foo/a') + Data(bar,'root/bar') eq 15"
+ target="assign2" />
+
+ </state>
+
+ <state id="assign2">
+
+ <datamodel>
+ <data id="jira51data1">
+ <rad:timeout>10</rad:timeout>
+ </data>
+ <data id="jira51data2">
+ <rad:short xmlns="">20</rad:short>
+ </data>
+ </datamodel>
+
+ <onentry>
+ <assign location="Data(jira51data1,'rad:timeout')" expr="Data(jira51data2,'rad:short')"/>
+ </onentry>
+
+ <transition cond="Data(jira51data1,'rad:timeout') eq 20"
+ target="assign3" />
+
+ </state>
+
+ <state id="assign3" final="true"/>
+
+</scxml>
diff --git a/test/samples/apache/assign-test-02.xml b/test/samples/apache/assign-test-02.xml
new file mode 100644
index 0000000..38ab9b3
--- /dev/null
+++ b/test/samples/apache/assign-test-02.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Regress JIRA 89, incomplete child removal -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:rad="http://foo/bar" version="1.0" initialstate="assign1">
+ <datamodel>
+ <data name="source">
+ <rad:foo>
+ <rad:a>1</rad:a>
+ <rad:b>2</rad:b>
+ </rad:foo>
+ </data>
+ <data name="destination">
+ <rad:bar>
+ <rad:a>3</rad:a>
+ <rad:b>4</rad:b>
+ </rad:bar>
+ </data>
+ </datamodel>
+ <!-- verify the destination contents -->
+ <state id="assign1" final="true">
+ <transition cond="Data(destination,'rad:bar/rad:a') eq 3 and Data(destination,'rad:bar/rad:b') eq 4" target="assign2" />
+ </state>
+ <!-- copy the new contents and verify -->
+ <state id="assign2">
+ <onentry>
+ <assign location="Data(destination,'rad:bar')" expr="Data(source,'rad:foo')" />
+ </onentry>
+ <transition cond="Data(destination,'rad:bar/rad:a') eq 1 and Data(destination,'rad:bar/rad:b') eq 2" target="assign3" />
+ </state>
+ <state id="assign3" final="true" />
+</scxml>
diff --git a/test/samples/apache/bar.xml b/test/samples/apache/bar.xml
new file mode 100644
index 0000000..3901080
--- /dev/null
+++ b/test/samples/apache/bar.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="bar">
+
+ <state id="bar"/>
+
+</scxml>
+
diff --git a/test/samples/apache/custom-hello-world-01.xml b/test/samples/apache/custom-hello-world-01.xml
new file mode 100644
index 0000000..5d8a348
--- /dev/null
+++ b/test/samples/apache/custom-hello-world-01.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used for comparison with hello-world.xml by
+ CustomActionTest.java in model package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:my="http://my.custom-actions.domain/CUSTOM1"
+ xmlns:foo="http://my.custom-actions.domain/CUSTOM2"
+ version="1.0"
+ initialstate="custom">
+
+ <state id="custom" final="true">
+
+ <onentry>
+ <my:hello name="world" />
+ <!-- foo:bar also maps to Hello action -->
+ <foo:bar name="custom action" />
+ </onentry>
+
+ </state>
+
+</scxml>
+
diff --git a/test/samples/apache/custom-hello-world-02.xml b/test/samples/apache/custom-hello-world-02.xml
new file mode 100644
index 0000000..7b27ccf
--- /dev/null
+++ b/test/samples/apache/custom-hello-world-02.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used for CustomActionTest.java in model package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:my="http://my.custom-actions.domain/CUSTOM"
+ version="1.0"
+ initialstate="custom">
+
+ <state id="custom" final="true">
+
+ <onentry>
+ <my:hello name="child (included) document" />
+ </onentry>
+
+ </state>
+
+</scxml>
+
diff --git a/test/samples/apache/custom-hello-world-03.xml b/test/samples/apache/custom-hello-world-03.xml
new file mode 100644
index 0000000..c8cfc5e
--- /dev/null
+++ b/test/samples/apache/custom-hello-world-03.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used for CustomActionTest.java in model package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:my="http://my.custom-actions.domain/CUSTOM"
+ version="1.0"
+ initialstate="custom">
+
+ <state id="custom" final="true">
+
+ <onentry>
+ <my:send name="overridden local name" />
+ </onentry>
+
+ </state>
+
+</scxml>
+
diff --git a/test/samples/apache/custom-hello-world-04-el.xml b/test/samples/apache/custom-hello-world-04-el.xml
new file mode 100644
index 0000000..0d5300b
--- /dev/null
+++ b/test/samples/apache/custom-hello-world-04-el.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used for CustomActionTest.java in model package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:my="http://my.custom-actions.domain/CUSTOM"
+ version="1.0" initialstate="init">
+ <datamodel>
+ <data id="helloName1" />
+ </datamodel>
+
+ <state id="init">
+ <onentry>
+ <my:hello name="custom04" />
+ </onentry>
+
+ <transition event="helloevent" target="middle1">
+ <assign name="helloName1" expr="${_eventdatamap.helloevent}" />
+ </transition>
+ </state>
+
+ <state id="middle1">
+ <transition target="custom" cond="${helloName1 eq 'custom04'}" />
+ </state>
+
+ <state id="custom" final="true"/>
+
+</scxml>
+
+
diff --git a/test/samples/apache/custom-hello-world-04-jexl.xml b/test/samples/apache/custom-hello-world-04-jexl.xml
new file mode 100644
index 0000000..c44e9b3
--- /dev/null
+++ b/test/samples/apache/custom-hello-world-04-jexl.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used for CustomActionTest.java in model package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:my="http://my.custom-actions.domain/CUSTOM"
+ version="1.0" initialstate="init">
+ <datamodel>
+ <data id="helloName1" />
+ </datamodel>
+
+ <state id="init">
+ <onentry>
+ <my:hello name="custom04a" />
+ </onentry>
+
+ <transition event="helloevent" target="middle1">
+ <assign name="helloName1" expr="_eventdatamap['helloevent']" />
+ </transition>
+ </state>
+
+ <state id="middle1">
+ <transition target="custom1" cond="helloName1 eq 'custom04a'" />
+ </state>
+
+ <state id="custom1">
+ <transition event="custom.next" target="custom2"/>
+ </state>
+
+ <state id="custom2">
+ <onentry>
+ <my:hello name="custom04b" />
+ </onentry>
+
+ <transition event="helloevent" target="custom3">
+ <assign name="helloName1" expr="_eventdatamap.helloevent" />
+ </transition>
+ </state>
+
+ <state id="custom3">
+ <transition target="end" cond="helloName1 eq 'custom04b'" />
+ </state>
+
+ <state id="end" final="true"/>
+
+</scxml>
+
+
diff --git a/test/samples/apache/datamodel-01.xml b/test/samples/apache/datamodel-01.xml
new file mode 100644
index 0000000..cc874fb
--- /dev/null
+++ b/test/samples/apache/datamodel-01.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- A fictitious state machine used by test cases.
+ Meant to illustrate the usage of SCXML <datamodel> element
+ and the Commons SCXML Data() function -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="main">
+
+ <!-- Root or document datamodel -->
+ <datamodel>
+ <data id="docdata">
+ <root xmlns="">
+ <foo>foo</foo>
+ </root>
+ </data>
+ </datamodel>
+
+ <state id="main">
+
+ <initial>
+ <transition target="ten"/>
+ </initial>
+
+ <!-- datamodel scoped to state "main" -->
+ <datamodel>
+ <data id="mainvar" expr="${0}" />
+ <data id="maindata">
+ <root xmlns="">
+ <foo>
+ <bar>bar</bar>
+ </foo>
+ </root>
+ </data>
+ </datamodel>
+
+ <state id="ten">
+ <onentry>
+ <!-- Assign Usage 1: name is previously defined
+ <var> or degenerate <data> (as in this case) -->
+ <assign name="mainvar" expr="${10}" />
+ </onentry>
+ <!-- Commons SCXML defines a Data() function to use in conjunction
+ with the Commons EL expression language. The
+ first argument is the named XML data tree and the second is
+ the XPath expression to a node whose value is to be
+ examined -->
+ <transition event="ten.done"
+ cond="${mainvar eq 10 and Data(maindata,'root/foo/bar') eq 'bar'}"
+ target="twenty" />
+ <onexit>
+ <!-- Assign Usage 2: location must point to an existing
+ node -->
+ <assign location="${Data(maindata,'root/foo/bar')}" expr="baz" />
+ </onexit>
+ </state>
+
+ <state id="twenty">
+ <onentry>
+ <assign name="mainvar" expr="${20}" />
+ </onentry>
+ <transition event="twenty.done"
+ cond="${Data(maindata,'root/foo/bar') eq 'baz' and mainvar eq 20}"
+ target="thirty" />
+ <onexit>
+ <!-- Assign Usage 3: location points to an existing
+ node, and expr points to an existing node.
+ In this case, location adopts expr's child nodes. -->
+ <assign location="${Data(docdata,'root/foo')}"
+ expr="${Data(maindata,'root/foo')}" />
+ <assign location="${Data(docdata,'root/foo/bar')}"
+ expr="${10}" />
+ </onexit>
+ </state>
+
+ <state id="thirty">
+ <!-- Arithmetic operations are possible with results from
+ the Data() function. Note that data "docdata"
+ did not have a node at 'root/foo/bar' to begin with,
+ the XML tree was manipulated by the <assign> above -->
+ <transition event="thirty.done"
+ cond="${Data(docdata,'root/foo/bar') gt 5}"
+ target="forty" />
+ </state>
+
+ <state id="forty" final="true" />
+
+ </state>
+
+</scxml>
+
+
diff --git a/test/samples/apache/datamodel-02.xml b/test/samples/apache/datamodel-02.xml
new file mode 100644
index 0000000..b719b8b
--- /dev/null
+++ b/test/samples/apache/datamodel-02.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- A fictitious state machine used by test cases. Meant to illustrate
+ prefixed XPath expressions in the Commons SCXML Data() function -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="ten">
+
+ <!-- Start with a prefixless XPath (see transition cond) -->
+ <state id="ten">
+
+ <datamodel>
+ <data id="data10">
+ <root xmlns="">
+ <foo>10</foo>
+ </root>
+ </data>
+ </datamodel>
+
+ <transition event="ten.done" cond="${Data(data10,'root/foo') eq 10}"
+ target="twenty" />
+
+ </state>
+
+ <!-- Already defined (and identical) prefixes -->
+ <state id="twenty" xmlns:ns1="http://namespace.test.domain/1"
+ xmlns:ns2="http://namespace.test.domain/2">
+
+ <datamodel>
+ <!-- Start with a prefixless XPath -->
+ <data id="data20">
+ <ns1:root>
+ <ns2:foo>20</ns2:foo>
+ </ns1:root>
+ </data>
+ </datamodel>
+
+ <transition event="twenty.done" cond="${Data(data20,'ns1:root/ns2:foo') eq 20}"
+ target="thirty" />
+
+ </state>
+
+ <!-- Data without prefixes -->
+ <state id="thirty">
+
+ <datamodel>
+ <!-- Start with a prefixless XPath -->
+ <data id="data30">
+ <root xmlns="http://namespace.test.domain/1">
+ <foo xmlns="http://namespace.test.domain/2">30</foo>
+ </root>
+ </data>
+ </datamodel>
+
+ <transition event="thirty.done"
+ xmlns:ns1="http://namespace.test.domain/1"
+ xmlns:ns2="http://namespace.test.domain/2"
+ xmlns:ns3="http://namespace.test.domain/3"
+ cond="${Data(data30,'ns1:root/ns2:foo') eq 30}"
+ target="forty" />
+
+ </state>
+
+ <state id="forty" final="true" />
+
+</scxml>
+
+
diff --git a/test/samples/apache/datamodel-03.xml b/test/samples/apache/datamodel-03.xml
new file mode 100644
index 0000000..f8a3310
--- /dev/null
+++ b/test/samples/apache/datamodel-03.xml
@@ -0,0 +1,259 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- A fictitious state machine used by test cases. Meant to illustrate
+ prefixed XPath expressions in the Commons SCXML Data() function.
+ Used by org.apache.commons.scxml.NamespacePrefixedPathsTest
+ Also serves as testing the underlying functionality of the
+ underlying parsing technology (here, Digester 1.8) -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:cs="http://commons.apache.org/scxml"
+ version="1.0"
+ initialstate="ten">
+
+ <!-- Root data model -->
+ <datamodel>
+
+ <!-- We'll use this for XPaths -->
+ <data id="rootdata"
+ xmlns:ns1="scheme://namespace.test.domain/1"
+ xmlns:ns2="scheme://namespace.test.domain/2"
+ xmlns:ns3="scheme://namespace.test.domain/3">
+ <ns1:root>
+ <ns2:foo>
+ <ns3:bar>1</ns3:bar>
+ </ns2:foo>
+ </ns1:root>
+ </data>
+
+ <!-- We'll use this for the JUnit test
+ NamespacePrefixedPathsTest.java (scxml package) -->
+ <data id="retval" />
+
+ </datamodel>
+
+ <!-- State data model -->
+ <state id="ten">
+
+ <datamodel>
+
+ <data id="data10" xmlns:ns4="scheme://namespace.test.domain/1">
+ <root xmlns="">
+ <ns4:foo>
+ <bar>10</bar>
+ </ns4:foo>
+ </root>
+ </data>
+
+ </datamodel>
+
+ <onentry>
+ <cs:var xmlns:pre1="scheme://namespace.test.domain/1"
+ xmlns:pre2="scheme://namespace.test.domain/2"
+ xmlns:pre3="scheme://namespace.test.domain/3"
+ name="tentest"
+ expr="${Data(rootdata,'pre1:root/pre2:foo/pre3:bar') + Data(data10,'root/pre1:foo/bar')}" />
+ </onentry>
+
+ <transition event="ten.done"
+ cond="${tentest eq 11}"
+ target="twenty" />
+
+ <onexit>
+ <assign name="retval"
+ expr="${tentest}" />
+ </onexit>
+
+ </state>
+
+ <!-- Already defined (and different) prefixes -->
+ <state id="twenty" xmlns:ns1="scheme://namespace.test.domain/1"
+ xmlns:ns2="scheme://namespace.test.domain/2"
+ xmlns:ns3="scheme://namespace.test.domain/3">
+
+ <datamodel>
+
+ <data id="data20">
+ <ns1:root>
+ <ns2:foo>20</ns2:foo>
+ </ns1:root>
+ </data>
+
+ </datamodel>
+
+ <onentry>
+ <assign location="${Data(rootdata,'ns1:root/ns2:foo/ns3:bar')}"
+ expr="${2}" />
+ </onentry>
+
+
+ <!-- Redefine namespace prefixes -->
+ <transition event="twenty.done"
+ xmlns:ns1="scheme://namespace.test.domain/1"
+ xmlns:ns2="scheme://namespace.test.domain/2"
+ cond="${Data(data20,'ns1:root/ns2:foo') eq 20 and Data(rootdata,'ns1:root/ns2:foo/ns3:bar') eq 2}"
+ target="thirty" />
+
+ <onexit>
+
+ <!-- Redefine different prefixes bound to above namespaces -->
+ <if xmlns:pre1="scheme://namespace.test.domain/1"
+ xmlns:pre2="scheme://namespace.test.domain/2"
+ cond="${Data(data20,'pre1:root/pre2:foo') lt 20}">
+
+ <assign name="retval" expr="Less than 20" />
+
+ <elseif cond="${Data(data20,'pre1:root/pre2:foo') eq 20}" />
+
+ <assign name="retval" expr="Equal to 20" />
+
+ <else/>
+
+ <assign name="retval" expr="Greater than 20" />
+
+ </if>
+
+ </onexit>
+
+ </state>
+
+ <!-- XPath looking at attribute -->
+ <state id="thirty">
+
+ <datamodel>
+
+ <data id="data30">
+ <root xmlns="scheme://namespace.test.domain/1">
+ <foo xmlns="scheme://namespace.test.domain/2"
+ xmlns:ns1="scheme://namespace.test.domain/3"
+ ns1:attfoo="30" attbar="300"/>
+ </root>
+ </data>
+
+ </datamodel>
+
+ <transition event="thirty.done"
+ xmlns:ns1="scheme://namespace.test.domain/1"
+ xmlns:ns2="scheme://namespace.test.domain/2"
+ xmlns:ns3="scheme://namespace.test.domain/3"
+ cond="${Data(data30,'ns1:root/ns2:foo/@ns3:attfoo') + Data(data30,'ns1:root/ns2:foo/@attbar') eq 330}"
+ target="forty" />
+
+ </state>
+
+ <!-- Multiple data, already defined prefixes -->
+ <state id="forty" xmlns:ns1="scheme://namespace.test.domain/1"
+ xmlns:ns2="scheme://namespace.test.domain/2"
+ xmlns:ns3="scheme://namespace.test.domain/3"
+ xmlns:ns4="scheme://namespace.test.domain/4">
+
+ <datamodel>
+
+ <data id="data40">
+ <root xmlns="">
+ <ns1:foo ns2:attfoo="40"/>
+ </root>
+ </data>
+
+ <data id="data41">
+ <ns3:root>
+ <ns4:foo>41</ns4:foo>
+ </ns3:root>
+ </data>
+
+ </datamodel>
+
+ <transition event="forty.done"
+ cond="${Data(data40,'root/ns1:foo/@ns2:attfoo') + Data(data41,'ns3:root/ns4:foo') eq 81}"
+ target="fifty" />
+
+ </state>
+
+ <!-- Multiple data, prefixes on elements -->
+ <state id="fifty">
+
+ <datamodel>
+
+ <data id="data50" xmlns:ns1="scheme://namespace.test.domain/1"
+ xmlns:ns2="scheme://namespace.test.domain/2"
+ xmlns:ns3="scheme://namespace.test.domain/3">
+ <ns1:root>
+ <ns2:foo ns3:attfoo="50"/>
+ </ns1:root>
+ </data>
+
+ <data id="data51" xmlns:ns3="scheme://namespace.test.domain/3"
+ xmlns:ns4="scheme://namespace.test.domain/4">
+ <ns3:root>
+ <ns4:foo attfoo="51"/>
+ </ns3:root>
+ </data>
+
+ </datamodel>
+
+ <transition event="fifty.done"
+ xmlns:ns1="scheme://namespace.test.domain/1"
+ xmlns:ns2="scheme://namespace.test.domain/2"
+ xmlns:ns3="scheme://namespace.test.domain/3"
+ xmlns:ns4="scheme://namespace.test.domain/4"
+ cond="${Data(data50,'ns1:root/ns2:foo/@ns3:attfoo') + Data(rootdata,'ns1:root/ns2:foo/ns3:bar') eq 52}"
+ target="sixty" />
+
+ </state>
+
+ <!-- Multiple data, prefixes on datamodel and transition elements -->
+ <state id="sixty">
+
+ <datamodel xmlns:ns1="scheme://namespace.test.domain/1"
+ xmlns:ns2="scheme://namespace.test.domain/2"
+ xmlns:ns3="scheme://namespace.test.domain/3"
+ xmlns:ns4="scheme://namespace.test.domain/4">
+
+ <data id="data60">
+ <root xmlns="">
+ <ns1:foo ns2:attfoo="60"/>
+ </root>
+ </data>
+
+ <data id="data61">
+ <ns3:root>
+ <ns4:foo attfoo="61"/>
+ </ns3:root>
+ </data>
+
+ </datamodel>
+
+ <transition event="sixty.done"
+ xmlns:pre1="scheme://namespace.test.domain/1"
+ xmlns:pre2="scheme://namespace.test.domain/2"
+ xmlns:pre3="scheme://namespace.test.domain/3"
+ xmlns:pre4="scheme://namespace.test.domain/4"
+ cond="${Data(data60,'root/pre1:foo/@pre2:attfoo') + Data(data61,'pre3:root/pre4:foo/@attfoo') eq 121}"
+ target="seventy">
+
+ <!-- should be 121 -->
+ <log expr="${Data(data60,'root/pre1:foo/@pre2:attfoo') + Data(data61,'pre3:root/pre4:foo/@attfoo')}"/>
+
+ </transition>
+
+ </state>
+
+ <state id="seventy" final="true" />
+
+</scxml>
+
+
diff --git a/test/samples/apache/datamodel-04.xml b/test/samples/apache/datamodel-04.xml
new file mode 100644
index 0000000..503a858
--- /dev/null
+++ b/test/samples/apache/datamodel-04.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- A fictitious state machine used by test cases.
+ Meant to illustrate the usage of SCXML <datamodel> element
+ to persist some _eventdata -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="ten">
+
+ <!-- Root or document datamodel -->
+ <datamodel>
+ <data id="payload"/>
+ </datamodel>
+
+ <state id="ten">
+ <transition event="ten.done" target="twenty">
+ <assign name="payload" expr="_eventdata" />
+ </transition>
+ </state>
+
+ <state id="twenty">
+ <transition event="twenty.done" target="thirty" />
+ <onexit>
+ <log label="Persisted eventdata.one" expr="payload.one"/>
+ <log label="Persisted eventdata.two" expr="payload.two"/>
+ </onexit>
+ </state>
+
+ <state id="thirty" final="true"/>
+
+</scxml>
+
+
diff --git a/test/samples/apache/edit-profile-config.xml b/test/samples/apache/edit-profile-config.xml
new file mode 100644
index 0000000..cdab498
--- /dev/null
+++ b/test/samples/apache/edit-profile-config.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ $Id: edit-profile-config.xml 462838 2006-10-11 16:08:36Z rahul $
+
+-->
+
+<!--
+
+ Dialog definitions for Shale Use Cases Example Web Application
+ written out as SCXML to demonstrate use of Commons SCXML as one
+ of Shale's Dialog Manager implementations.
+
+ Related artifacts from <dialog name="Edit Profile">...</dialog>
+ in original dialogs definition file from Shale nightlies.
+
+-->
+
+<scxml xmlns="http://www.w3.org/2005/01/SCXML" version="1.0"
+ initialstate="edit">
+
+ <state id="edit">
+
+ <initial>
+ <transition>
+ <target next="setup"/>
+ </transition>
+ </initial>
+
+ <!-- global transitions (within state "edit") -->
+
+ <transition event="faces.outcome"
+ cond="${outcome eq 'cancel'}">
+ <target next="cancel"/>
+ </transition>
+
+ <transition event="faces.outcome"
+ cond="${outcome eq 'finish'}">
+ <target next="finish"/>
+ </transition>
+
+ <state id="setup">
+
+ <onentry>
+ <var name="setupOutcome"
+ expr="#{profile$edit.setup}" />
+ </onentry>
+
+ <transition cond="${setupOutcome eq 'success'}">
+ <target next="page1"/>
+ </transition>
+
+ </state>
+
+ <state id="page1">
+
+ <transition event="faces.outcome"
+ cond="${outcome eq 'next'}">
+ <target next="page2"/>
+ </transition>
+
+ </state>
+
+ <state id="page2">
+
+ <transition event="faces.outcome"
+ cond="${outcome eq 'previous'}">
+ <target next="page1"/>
+ </transition>
+
+ <transition event="faces.outcome"
+ cond="${outcome eq 'next'}">
+ <target next="page3"/>
+ </transition>
+
+ </state>
+
+ <state id="page3">
+
+ <transition event="faces.outcome"
+ cond="${outcome eq 'previous'}">
+ <target next="page2"/>
+ </transition>
+
+ <transition event="faces.outcome"
+ cond="${outcome eq 'next'}">
+ <target next="editExit"/>
+ </transition>
+
+ </state>
+
+ </state>
+
+ <state id="cancel">
+
+ <onentry>
+ <var name="cancelOutcome"
+ expr="#{profile$edit.cancel}" />
+ </onentry>
+
+ <transition cond="${cancelOutcome eq 'success'}">
+ <var name="outcome"
+ expr="cancel"/>
+ <target next="editExit"/>
+ </transition>
+
+ </state>
+
+ <state id="finish">
+
+ <onentry>
+ <var name="finishOutcome"
+ expr="#{profile$edit.finish}" />
+ </onentry>
+
+ <transition cond="${finishOutcome eq 'username'}">
+ <target next="page1"/>
+ </transition>
+
+ <transition cond="${finishOutcome eq 'password'}">
+ <target next="page1"/>
+ </transition>
+
+ <transition cond="${finishOutcome eq 'success'}">
+ <var name="outcome"
+ expr="success"/>
+ <target next="editExit"/>
+ </transition>
+
+ </state>
+
+ <state id="editExit"
+ final="true" />
+
+</scxml>
diff --git a/test/samples/apache/eventdata-01.xml b/test/samples/apache/eventdata-01.xml
new file mode 100644
index 0000000..c07d42d
--- /dev/null
+++ b/test/samples/apache/eventdata-01.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ datamodel="ecmascript"
+ initialstate="state1">
+ <state id="state1">
+ <transition event="event.foo" cond="_event.data == 2"
+ target="state2"/>
+ <transition event="event.foo" cond="_event.data == 3"
+ target="state3"/>
+ <transition event="event.foo">
+ <log expr="'event.name: ' + _event.name" />
+ </transition>
+ </state>
+ <state id="state2" final="true"/>
+ <state id="state3">
+ <transition event="event.bar" target="state4"
+ cond="_event.data == 4"/>
+ <transition event="event.bar" target="state5"
+ cond="_event.data == 5"/>
+ <transition event="event.bar" target="state6"
+ cond="_event.data == 6"/>
+ </state>
+ <state id="state4" final="true"/>
+ <state id="state5" final="true"/>
+ <state id="state6">
+ <transition event="event.baz" target="state7"
+ cond="_event.data == 7"/>
+ </state>
+ <state id="state7" final="true"/>
+</scxml>
diff --git a/test/samples/apache/eventdata-02.xml b/test/samples/apache/eventdata-02.xml
new file mode 100644
index 0000000..df130ae
--- /dev/null
+++ b/test/samples/apache/eventdata-02.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ datamodel="ecmascript"
+ initialstate="state0">
+ <state id="state0">
+ <!-- Payload can be any object, such as a String ... -->
+ <transition event="connection.alerting"
+ cond="_event.data == 'line1'" target="state1"/>
+ <transition event="connection.alerting"
+ cond="_event.data == 'line2'" target="state2"/>
+ </state>
+ <state id="state1" final="true"/>
+ <state id="state2">
+ <!-- ... or an arbitrary, user defined object. -->
+ <transition event="connection.alerting"
+ cond="_event.data.line == 3" target="state3"/>
+ <transition event="connection.alerting"
+ cond="_event.data.line == 4" target="state4"/>
+ </state>
+ <state id="state3" final="true"/>
+ <state id="state4" final="true"/>
+</scxml>
diff --git a/test/samples/apache/eventdata-03.xml b/test/samples/apache/eventdata-03.xml
new file mode 100644
index 0000000..d4c4388
--- /dev/null
+++ b/test/samples/apache/eventdata-03.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:cs="http://commons.apache.org/scxml"
+ version="1.0"
+ initialstate="ten">
+
+ <datamodel>
+ <data id="rootdata">
+ <root xmlns="">
+ <one>1</one>
+ <two>2</two>
+ </root>
+ </data>
+ </datamodel>
+
+ <state id="ten">
+ <transition event="event.foo" target="twenty"/>
+ </state>
+
+ <state id="twenty">
+ <onentry>
+ <cs:var name="one" expr="Data(rootdata,'root/one')"/>
+ <cs:var name="two" expr="Data(rootdata,'root/two')"/>
+ <send event="'event.bar'" namelist="one two"/>
+ </onentry>
+ <transition event="event.bar"
+ cond="_eventdatamap['event.bar'].one + _eventdatamap['event.bar'].two eq 3"
+ target="thirty"/>
+ </state>
+
+ <state id="thirty" final="true"/>
+
+</scxml>
diff --git a/test/samples/apache/eventdata-04.xml b/test/samples/apache/eventdata-04.xml
new file mode 100644
index 0000000..541d2e9
--- /dev/null
+++ b/test/samples/apache/eventdata-04.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="start">
+
+ <parallel id="start">
+
+ <state id="simulatedUser">
+ <datamodel>
+ <data name="one" expr="1" />
+ <data name="two" expr="2" />
+ </datamodel>
+
+ <onentry>
+ <send event="'event.bar'" namelist="one two" delay="'100ms'"/>
+ </onentry>
+ <transition event="event.bar">
+ <log label="'simulatedUser'" expr="_eventdatamap['event.bar'].one + ', ' + _eventdatamap['event.bar'].two"/>
+ </transition>
+ </state>
+
+ <state id="counter">
+ <initial>
+ <transition target="twenty"/>
+ </initial>
+
+ <state id="twenty">
+ <transition event="event.bar"
+ cond="_eventdatamap['event.bar'].one + _eventdatamap['event.bar'].two eq 3"
+ target="thirty"/>
+ <transition event="event.bar">
+ <log label="'event.bar in twenty state'" expr="_eventdatamap['event.bar'].one + ', ' + _eventdatamap['event.bar'].two"/>
+ </transition>
+ </state>
+
+ <state id="thirty" final="true"/>
+ </state>
+
+ </parallel>
+
+</scxml>
diff --git a/test/samples/apache/external-hello-world.xml b/test/samples/apache/external-hello-world.xml
new file mode 100644
index 0000000..b6d1b9f
--- /dev/null
+++ b/test/samples/apache/external-hello-world.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used for testing custom actions in external document pulled in via
+ the src attributes by ExternalCustomActionTest.java in model package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:my="http://my.custom-actions.domain/CUSTOM"
+ version="1.0"
+ initialstate="external-hello">
+
+ <state id="external-hello" final="true" src="custom-hello-world-02.xml">
+
+ <onentry>
+ <my:hello name="parent document" />
+ </onentry>
+
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/foo.xml b/test/samples/apache/foo.xml
new file mode 100644
index 0000000..486d36e
--- /dev/null
+++ b/test/samples/apache/foo.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="foo">
+
+ <state id="foo"/>
+
+</scxml>
+
diff --git a/test/samples/apache/hello-world.xml b/test/samples/apache/hello-world.xml
new file mode 100644
index 0000000..7647899
--- /dev/null
+++ b/test/samples/apache/hello-world.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used for comparison with custom-hello-world.xml by
+ CustomActionTest.java in model package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="hello">
+
+ <state id="hello" final="true">
+ <onentry>
+ <log expr="'hello world'" />
+ </onentry>
+ </state>
+
+</scxml>
+
diff --git a/test/samples/apache/history-deep-01.xml b/test/samples/apache/history-deep-01.xml
new file mode 100644
index 0000000..209a974
--- /dev/null
+++ b/test/samples/apache/history-deep-01.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ This document is an example of using deep history
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
+ initialstate="flow">
+
+ <state id="flow">
+ <initial>
+ <transition target="phases"/>
+ </initial>
+
+ <!-- deep history is specified by setting the type attribute
+ to "deep" -->
+
+ <history id="hist" type="deep">
+
+ <!-- This is the transition to be followed if no
+ prior history is available -->
+
+ <transition target="phases"/>
+
+ </history>
+
+ <state id="phases">
+
+ <initial>
+ <transition target="phase1"/>
+ </initial>
+
+ <state id="phase1">
+ <transition event="phase.done" target="phase2"/>
+ </state>
+
+ <state id="phase2">
+ <transition event="phase.done" target="phase3"/>
+ </state>
+
+ <state id="phase3" final="true" />
+
+ </state>
+
+ <transition event="flow.pause" target="interrupted"/>
+
+ <transition event="flow.terminate" target="terminated"/>
+
+ </state>
+
+ <state id="interrupted">
+
+ <transition event="flow.resume" target="hist"/>
+
+ <transition event="flow.terminate" target="terminated"/>
+
+ </state>
+
+ <state id="terminated" final="true"/>
+
+</scxml>
diff --git a/test/samples/apache/history-default-01.xml b/test/samples/apache/history-default-01.xml
new file mode 100644
index 0000000..cf2f70f
--- /dev/null
+++ b/test/samples/apache/history-default-01.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ This document is an example of specifying default transitions for
+ history states (if the parent state has never been visited before)
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
+ initialstate="state1">
+
+ <state id="state1">
+ <initial>
+ <transition target="history1"/>
+ </initial>
+
+ <!-- shallow history, explicit default transition -->
+
+ <history id="history1">
+ <transition next="state11"/>
+ </history>
+
+ <state id="state11">
+ <transition event="state.next" target="state2"/>
+ </state>
+
+ </state>
+
+ <state id="state2">
+ <initial>
+ <transition target="history2"/>
+ </initial>
+
+ <!-- deep history, explicit default transition -->
+
+ <history id="history2" type="deep">
+ <transition next="state211"/>
+ </history>
+
+ <state id="state21">
+
+ <initial>
+ <transition target="state212"/>
+ </initial>
+
+ <state id="state211">
+ <transition event="state.next" target="history3"/>
+ </state>
+
+ <state id="state212">
+ <transition event="state.next" target="history3"/>
+ </state>
+
+ </state>
+
+ </state>
+
+ <state id="state3">
+
+ <initial>
+ <transition target="state31"/>
+ </initial>
+
+ <!-- shallow history, no default transition specified,
+ reuse initial as default transition -->
+
+ <history id="history3"/>
+
+ <state id="state31">
+ <transition event="state.next" target="state4"/>
+ </state>
+
+ </state>
+
+ <state id="state4" final="true"/>
+
+</scxml>
diff --git a/test/samples/apache/history-shallow-01.xml b/test/samples/apache/history-shallow-01.xml
new file mode 100644
index 0000000..20b5bb5
--- /dev/null
+++ b/test/samples/apache/history-shallow-01.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ This document is an example of using shallow history
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
+ initialstate="flow">
+
+ <state id="flow">
+ <initial>
+ <transition target="phase1"/>
+ </initial>
+
+ <!-- history defaults to shallow, optionally one can set
+ the type attribute to "shallow" for identical results -->
+
+ <history id="hist">
+
+ <!-- This is the transition to be followed if no
+ prior history is available -->
+
+ <transition target="phase1"/>
+
+ </history>
+
+ <state id="phase1">
+ <transition event="phase.done" target="phase2"/>
+ </state>
+
+ <state id="phase2">
+ <transition event="phase.done" target="phase3"/>
+ </state>
+
+ <state id="phase3" final="true"/>
+
+ <transition event="flow.pause" target="interrupted"/>
+
+ <transition event="flow.terminate" target="terminated"/>
+
+ </state>
+
+ <state id="interrupted">
+
+ <transition event="flow.resume" target="hist"/>
+
+ <transition event="flow.terminate" target="terminated"/>
+
+ </state>
+
+ <state id="terminated" final="true"/>
+
+</scxml>
diff --git a/test/samples/apache/invoked-01.xml b/test/samples/apache/invoked-01.xml
new file mode 100644
index 0000000..a523995
--- /dev/null
+++ b/test/samples/apache/invoked-01.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="state1">
+
+ <state id="state1">
+ <onentry>
+ <log expr="'foo is ' + foo + ' and bar is ' + bar" />
+ </onentry>
+ <transition event="invoked.next" target="state2" />
+ </state>
+
+ <state id="state2" final="true" />
+
+</scxml>
+
diff --git a/test/samples/apache/invoked-02.xml b/test/samples/apache/invoked-02.xml
new file mode 100644
index 0000000..b1b471a
--- /dev/null
+++ b/test/samples/apache/invoked-02.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="state1">
+
+ <state id="state1">
+ <onentry>
+ <send event="'invoked.next'" />
+ </onentry>
+ <transition event="invoked.next" target="state2" />
+ </state>
+
+ <state id="state2" final="true" />
+
+</scxml>
+
diff --git a/test/samples/apache/invoked-03-01.xml b/test/samples/apache/invoked-03-01.xml
new file mode 100644
index 0000000..3b73a66
--- /dev/null
+++ b/test/samples/apache/invoked-03-01.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used by InvokeTest#testInvoke03Sample() -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="s1">
+
+ <state id="s1">
+ <onentry>
+ <log expr="' Inner invoke ...'"/>
+ </onentry>
+ <transition event="s1.next" target="s2"/>
+ </state>
+
+ <state id="s2" final="true"/>
+
+</scxml>
+
diff --git a/test/samples/apache/invoked-03.xml b/test/samples/apache/invoked-03.xml
new file mode 100644
index 0000000..91244e8
--- /dev/null
+++ b/test/samples/apache/invoked-03.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used by InvokeTest#testInvoke03Sample() -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="state1">
+
+ <state id="state1">
+ <onentry>
+ <log expr="' Outer invoke ...'"/>
+ </onentry>
+ <invoke type="scxml" src="invoked-03-01.xml"/>
+ <transition event="state1.next" target="end1" />
+ </state>
+
+ <state id="end1" final="true">
+ <onentry>
+ <log expr="' Inner invoke completed'"/>
+ </onentry>
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/invoker-01.xml b/test/samples/apache/invoker-01.xml
new file mode 100644
index 0000000..5355896
--- /dev/null
+++ b/test/samples/apache/invoker-01.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="invoker">
+
+ <state id="invoker">
+ <onentry>
+ <log expr="'Begin invoke test ...'" />
+ </onentry>
+ <invoke type="scxml" src="invoked-01.xml">
+ <param name="foo" expr="'foo'" />
+ <param name="bar" expr="'bar'" />
+ <finalize>
+ <log expr="'Finalizing ...'" />
+ </finalize>
+ </invoke>
+ <transition event="invoker.invoke.done" target="end" />
+ </state>
+
+ <state id="end" final="true" />
+
+</scxml>
diff --git a/test/samples/apache/invoker-02.xml b/test/samples/apache/invoker-02.xml
new file mode 100644
index 0000000..a6fb2cb
--- /dev/null
+++ b/test/samples/apache/invoker-02.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="invoker">
+
+ <state id="invoker">
+ <invoke type="scxml" src="invoked-02.xml"/>
+ <transition event="invoker.invoke.done" target="end" />
+ </state>
+
+ <state id="end" final="true" />
+
+</scxml>
diff --git a/test/samples/apache/invoker-03.xml b/test/samples/apache/invoker-03.xml
new file mode 100644
index 0000000..be2d1fa
--- /dev/null
+++ b/test/samples/apache/invoker-03.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used by InvokeTest#testInvoke03Sample() -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="invoker">
+
+ <state id="invoker">
+ <onentry>
+ <log expr="'Invoker ...'"/>
+ </onentry>
+ <invoke type="scxml" src="invoked-03.xml"/>
+ <transition event="invoker.invoke.done" target="end">
+ <log expr="' Outer invoke completed'"/>
+ </transition>
+ </state>
+
+ <state id="end" final="true">
+ <onentry>
+ <log expr="'Invoker completed'"/>
+ </onentry>
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/invoker-04.xml b/test/samples/apache/invoker-04.xml
new file mode 100644
index 0000000..81c1bb8
--- /dev/null
+++ b/test/samples/apache/invoker-04.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- A fictitious state machine used by test cases.
+ Meant to illustrate the usage of SCXML <param> element as part
+ of an invocation using a custom invoker -->
+
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="wait">
+
+ <datamodel>
+ <data id="foo">
+ <bar>foo</bar>
+ </data>
+ </datamodel>
+
+ <state id="wait">
+ <transition event="test.trigger" target="first"/>
+ </state>
+
+ <state id="first">
+ <invoke src="FirstTestSrc" type="x-test">
+ <param name="ding" expr="Data(foo,'node()')"/>
+ </invoke>
+ <transition event="test.trigger" target="second"/>
+ </state>
+
+ <state id="second">
+ <invoke src="SecondTestSrc" type="x-test">
+ <param name="Data(foo,'node()')"/>
+ </invoke>
+ <transition event="test.trigger" target="third"/>
+ </state>
+
+ <state id="third">
+ <invoke src="ThirdTestSrc" type="x-test">
+ <param name="Data(foo,'gibberish')"/>
+ </invoke>
+ </state>
+</scxml> \ No newline at end of file
diff --git a/test/samples/apache/issue62-01-ext.xml b/test/samples/apache/issue62-01-ext.xml
new file mode 100644
index 0000000..8c65a78
--- /dev/null
+++ b/test/samples/apache/issue62-01-ext.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
+ initialstate="ext">
+
+ <state id="ext">
+ <transition event="foo">
+ <log expr="'Stay transition in issue 62 test'"/>
+ </transition>
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/issue62-01.xml b/test/samples/apache/issue62-01.xml
new file mode 100644
index 0000000..3599e5e
--- /dev/null
+++ b/test/samples/apache/issue62-01.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
+ initialstate="s1">
+
+ <state id="s1">
+ <initial>
+ <transition target="s1.1" />
+ </initial>
+ <state id="s1.1" src="issue62-01-ext.xml#ext" />
+ <state id="s1.2" src="issue62-01-ext.xml#ext" />
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/issue62-02-ext.xml b/test/samples/apache/issue62-02-ext.xml
new file mode 100644
index 0000000..98da5d6
--- /dev/null
+++ b/test/samples/apache/issue62-02-ext.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
+ initialstate="e1">
+
+ <state id="e1">
+ <initial>
+ <transition target="e1.1"/>
+ </initial>
+ <state id="e1.1">
+ <initial>
+ <transition target="e1.1.1"/>
+ </initial>
+ <state id="e1.1.1">
+ <transition event="bar" target="e1.1.2"/>
+ </state>
+ <state id="e1.1.2">
+ <transition event="baz" target="e1.2"/>
+ </state>
+ </state>
+ <state id="e1.2" final="true"/>
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/issue62-02.xml b/test/samples/apache/issue62-02.xml
new file mode 100644
index 0000000..8e52e42
--- /dev/null
+++ b/test/samples/apache/issue62-02.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
+ initialstate="s1">
+
+ <state id="s1">
+ <transition event="foo" target="s2" />
+ </state>
+
+ <state id="s2">
+ <initial>
+ <transition target="s2.1"/>
+ </initial>
+ <state id="s2.1" src="issue62-02-ext.xml#e1" />
+ <transition event="s2.1.done" target="s3"/>
+ </state>
+
+ <state id="s3" final="true"/>
+
+</scxml>
diff --git a/test/samples/apache/issue62-03-ext.xml b/test/samples/apache/issue62-03-ext.xml
new file mode 100644
index 0000000..0168447
--- /dev/null
+++ b/test/samples/apache/issue62-03-ext.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
+ initialstate="e1">
+
+ <state id="e1">
+ <initial>
+ <transition target="e1.1"/>
+ </initial>
+ <state id="e1.1">
+ <initial>
+ <transition target="e1.1.1"/>
+ </initial>
+ <state id="e1.1.1">
+ <transition event="bar" target="e1.1.2"/>
+ </state>
+ <state id="e1.1.2">
+ <transition event="baz" target="e1.2"/>
+ </state>
+ </state>
+ <final id="e1.2"/>
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/issue62-03.xml b/test/samples/apache/issue62-03.xml
new file mode 100644
index 0000000..46b8991
--- /dev/null
+++ b/test/samples/apache/issue62-03.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
+ initialstate="s1">
+
+ <state id="s1">
+ <transition event="foo" target="s2" />
+ </state>
+
+ <state id="s2">
+ <initial>
+ <transition target="s2.1"/>
+ </initial>
+ <state id="s2.1" src="issue62-03-ext.xml#e1" />
+ <transition event="s2.1.done" target="s3"/>
+ </state>
+
+ <final id="s3"/>
+
+</scxml>
diff --git a/test/samples/apache/issue64-01.xml b/test/samples/apache/issue64-01.xml
new file mode 100644
index 0000000..bb848fe
--- /dev/null
+++ b/test/samples/apache/issue64-01.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Correct SCXML document -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="tranbug">
+
+ <state id="tranbug">
+ <datamodel>
+ <data id="dummy" expr="'somedata'"/>
+ </datamodel>
+ <onentry>
+ <log expr="'Begin transition bug test ...'" />
+ </onentry>
+ <transition event="show.bug" target="end">
+ <log expr="dummy" />
+ <log expr="'*****' + dummy" />
+ </transition>
+ </state>
+ <state id="end" final="true" />
+
+</scxml>
+
+
diff --git a/test/samples/apache/issue64-02.xml b/test/samples/apache/issue64-02.xml
new file mode 100644
index 0000000..7e44d30
--- /dev/null
+++ b/test/samples/apache/issue64-02.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Bad SCXML document, many elements will be ignored with warnings from parser -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:my="http://my.foo.example/"
+ version="1.0"
+ initialstate="tranbug">
+
+ <datamodel>
+ <data id="foo">
+ <alpha xmlns="">
+ <beta/>
+ </alpha>
+ </data>
+ <misplaced/>
+ </datamodel>
+
+ <state id="tranbug">
+ <onentry>
+ <log expr="'Begin transition bug test ...'" />
+ <foo/>
+ <my:bar/>
+ </onentry>
+ <transition event="show.bug" target="end">
+ <!-- For example, FOLLOWING datamodel IS MISPLACED -->
+ <datamodel>
+ <data id="dummy" expr="'somedata'"/>
+ </datamodel>
+ <log expr="dummy" />
+ <log expr="'*****' + dummy" />
+ </transition>
+ </state>
+
+ <my:baz/>
+
+ <state id="end" final="true" />
+
+</scxml>
+
+
diff --git a/test/samples/apache/jsp-rootctx-test.xml b/test/samples/apache/jsp-rootctx-test.xml
new file mode 100644
index 0000000..6a71579
--- /dev/null
+++ b/test/samples/apache/jsp-rootctx-test.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:cs="http://commons.apache.org/scxml"
+ version="1.0"
+ initialstate="rootCtxTest">
+
+ <state id="rootCtxTest" final="true">
+ <onentry>
+ <!-- 'foo' must exist in host JSP context -->
+ <assign name="foo" expr="${foo+1}" />
+ <cs:var name="bar" expr="a brand new value" />
+ </onentry>
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/log-on-config.xml b/test/samples/apache/log-on-config.xml
new file mode 100644
index 0000000..b57780e
--- /dev/null
+++ b/test/samples/apache/log-on-config.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ $Id: log-on-config.xml 462838 2006-10-11 16:08:36Z rahul $
+
+-->
+
+<!--
+
+ Dialog definitions for Shale Use Cases Example Web Application
+ written out as SCXML to demonstrate use of Commons SCXML as one
+ of Shale's Dialog Manager implementations.
+
+ Related artifacts from <dialog name="Log On">...</dialog>
+ in original dialogs definition file from Shale nightlies.
+
+-->
+
+<scxml xmlns="http://www.w3.org/2005/01/SCXML" version="1.0"
+ initialstate="checkCookie">
+
+
+ <state id="checkCookie">
+
+ <onentry>
+ <var name="cookieOutcome"
+ expr="#{profile$logon.check}" />
+ </onentry>
+
+ <transition cond="${cookieOutcome eq 'authenticated'}">
+ <target next="exit"/>
+ </transition>
+
+ <transition cond="${cookieOutcome eq 'unauthenticated'}">
+ <target next="logon"/>
+ </transition>
+
+ </state>
+
+ <state id="logon">
+
+ <transition event="faces.outcome"
+ cond="${outcome eq 'authenticated'}">
+ <target next="exit"/>
+ </transition>
+
+ <transition event="faces.outcome"
+ cond="${outcome eq 'create'}">
+ <target next="createProfile"/>
+ </transition>
+
+ </state>
+
+ <state id="createProfile"
+ src="edit-profile-config.xml" >
+
+ <transition event="createProfile.done"
+ cond="${outcome eq 'success' or outcome eq 'cancel'}">
+ <target next="exit"/>
+ </transition>
+
+ </state>
+
+ <state id="exit"
+ final="true" />
+
+</scxml>
diff --git a/test/samples/apache/microwave-01.xml b/test/samples/apache/microwave-01.xml
new file mode 100644
index 0000000..86efa26
--- /dev/null
+++ b/test/samples/apache/microwave-01.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ This document uses JSP 2.0 EL as the expressions language.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:cs="http://commons.apache.org/scxml"
+ version="1.0"
+ initialstate="off">
+
+ <!-- trivial microwave oven example -->
+ <state id="off">
+ <!-- off state -->
+ <transition event="turn_on" target="on"/>
+ </state>
+
+ <state id="on">
+ <initial>
+ <transition target="idle"/>
+ </initial>
+
+ <!-- on/pause state -->
+ <onentry>
+ <!-- we assume the cook_time is passed in as a context parameter -->
+ <if cond="${empty cook_time}">
+ <!-- default setting -->
+ <cs:var name="cook_time" expr="${5}"/>
+ </if>
+ <!-- again, door_closed should be a part of a global context -->
+ <if cond="${empty door_closed}">
+ <!-- default setting -->
+ <cs:var name="door_closed" expr="${true}"/>
+ </if>
+ <!-- timer variable -->
+ <cs:var name="timer" expr="${0}"/>
+ </onentry>
+
+ <transition event="turn_off" target="off"/>
+
+ <transition cond="${timer ge cook_time}" target="off"/>
+
+ <state id="idle">
+ <!-- default immediate transition -->
+ <transition cond="${door_closed}" target="cooking"/>
+
+ <!-- start cooking -->
+ <transition event="door_close" target="cooking">
+ <assign name="door_closed" expr="${true}"/>
+ </transition>
+ </state>
+
+ <state id="cooking">
+ <transition event="door_open" target="idle">
+ <assign name="door_closed" expr="${false}"/>
+ </transition>
+ <transition event="time" target="cooking">
+ <assign name="timer" expr="${timer + 1}"/>
+ </transition>
+ </state>
+
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/microwave-02-legacy.xml b/test/samples/apache/microwave-02-legacy.xml
new file mode 100644
index 0000000..eaeb14a
--- /dev/null
+++ b/test/samples/apache/microwave-02-legacy.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ This document uses JSP 2.0 EL as the expressions language.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
+ initialstate="microwave">
+
+ <!-- trivial microwave oven example -->
+ <!-- using parallel and In() predicate -->
+
+ <state id="microwave">
+ <parallel id="parts">
+ <state id="oven">
+ <initial>
+ <transition target="off"/>
+ </initial>
+
+ <state id="off">
+ <!-- off state -->
+ <transition event="turn_on" target="on"/>
+ </state>
+
+ <state id="on">
+ <initial>
+ <transition target="idle"/>
+ </initial>
+
+ <!-- on/pause state -->
+ <onentry>
+ <!-- we assume the cook_time is passed in as a context parameter -->
+ <if cond="${empty cook_time}">
+ <!-- default setting -->
+ <var name="cook_time" expr="${5}"/>
+ </if>
+ <!-- timer variable -->
+ <var name="timer" expr="${0}"/>
+ </onentry>
+
+ <transition event="turn_off" target="off"/>
+
+ <transition cond="${timer ge cook_time}" target="off"/>
+
+ <state id="idle">
+ <transition cond="${In('closed')}" target="cooking"/>
+ </state>
+
+ <state id="cooking">
+ <transition cond="${not In('closed')}" target="idle"/>
+
+ <transition event="time" target="cooking">
+ <assign name="timer" expr="${timer + 1}"/>
+ </transition>
+ </state>
+ </state>
+ </state>
+
+ <state id="door">
+ <initial>
+ <transition target="closed"/>
+ </initial>
+ <state id="closed">
+ <transition event="door_open" target="open"/>
+ </state>
+ <state id="open">
+ <transition event="door_close" target="closed"/>
+ </state>
+ </state>
+ </parallel>
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/microwave-02.xml b/test/samples/apache/microwave-02.xml
new file mode 100644
index 0000000..c03fe05
--- /dev/null
+++ b/test/samples/apache/microwave-02.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ This document uses JSP 2.0 EL as the expressions language.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:cs="http://commons.apache.org/scxml"
+ version="1.0"
+ initialstate="microwave">
+
+ <!-- trivial microwave oven example -->
+ <!-- using parallel and In() predicate -->
+
+ <parallel id="microwave">
+ <state id="oven">
+ <initial>
+ <transition target="off"/>
+ </initial>
+
+ <state id="off">
+ <!-- off state -->
+ <transition event="turn_on" target="on"/>
+ </state>
+
+ <state id="on">
+ <initial>
+ <transition target="idle"/>
+ </initial>
+
+ <!-- on/pause state -->
+ <onentry>
+ <!-- we assume the cook_time is passed in as a context parameter -->
+ <if cond="${empty cook_time}">
+ <!-- default setting -->
+ <cs:var name="cook_time" expr="${5}"/>
+ </if>
+ <!-- timer variable -->
+ <cs:var name="timer" expr="${0}"/>
+ </onentry>
+
+ <transition event="turn_off" target="off"/>
+
+ <transition cond="${timer ge cook_time}" target="off"/>
+
+ <state id="idle">
+ <transition cond="${In('closed')}" target="cooking"/>
+ </state>
+
+ <state id="cooking">
+ <transition cond="${not In('closed')}" target="idle"/>
+
+ <transition event="time" target="cooking">
+ <assign name="timer" expr="${timer + 1}"/>
+ </transition>
+ </state>
+ </state>
+ </state>
+
+ <state id="door">
+ <initial>
+ <transition target="closed"/>
+ </initial>
+ <state id="closed">
+ <transition event="door_open" target="open"/>
+ </state>
+ <state id="open">
+ <transition event="door_close" target="closed"/>
+ </state>
+ </state>
+ </parallel>
+
+</scxml>
diff --git a/test/samples/apache/microwave-03.xml b/test/samples/apache/microwave-03.xml
new file mode 100644
index 0000000..887b1a6
--- /dev/null
+++ b/test/samples/apache/microwave-03.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ This document uses Commons JEXL as the expressions language.
+ Needs SCXMLParser.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:cs="http://commons.apache.org/scxml"
+ version="1.0"
+ initialstate="off">
+
+ <!-- trivial microwave oven example -->
+ <state id="off">
+ <!-- off state -->
+ <transition event="turn_on" target="on"/>
+ </state>
+
+ <state id="on">
+ <initial>
+ <transition target="idle"/>
+ </initial>
+
+ <!-- on/pause state -->
+ <onentry>
+ <!-- we assume the cook_time is passed in as a context parameter -->
+ <if cond="empty(cook_time)">
+ <!-- default setting -->
+ <cs:var name="cook_time" expr="5"/>
+ </if>
+ <!-- again, door_closed should be a part of a global context -->
+ <if cond="empty(door_closed)">
+ <!-- default setting -->
+ <cs:var name="door_closed" expr="true"/>
+ </if>
+ <!-- timer variable -->
+ <cs:var name="timer" expr="0"/>
+ </onentry>
+
+ <transition event="turn_off" target="off"/>
+
+ <transition cond="timer ge cook_time" target="off"/>
+
+ <state id="idle">
+ <!-- default immediate transition -->
+ <transition cond="door_closed" target="cooking"/>
+
+ <!-- start cooking -->
+ <transition event="door_close" target="cooking">
+ <assign name="door_closed" expr="true"/>
+ </transition>
+ </state>
+
+ <state id="cooking">
+ <transition event="door_open" target="idle">
+ <assign name="door_closed" expr="false"/>
+ </transition>
+ <transition event="time" target="cooking">
+ <assign name="timer" expr="timer + 1"/>
+ </transition>
+ </state>
+
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/microwave-04.xml b/test/samples/apache/microwave-04.xml
new file mode 100644
index 0000000..96656dd
--- /dev/null
+++ b/test/samples/apache/microwave-04.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ This document uses Commons JEXL as the expressions language.
+ Needs SCXMLParser.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:cs="http://commons.apache.org/scxml"
+ version="1.0"
+ initialstate="microwave">
+
+ <!-- trivial microwave oven example -->
+ <!-- using parallel and In() predicate -->
+
+ <parallel id="microwave">
+
+ <state id="oven">
+ <initial>
+ <transition target="off"/>
+ </initial>
+
+ <state id="off">
+ <!-- off state -->
+ <transition event="turn_on" target="on"/>
+ </state>
+
+ <state id="on">
+ <initial>
+ <transition target="idle"/>
+ </initial>
+
+ <!-- on/pause state -->
+ <onentry>
+ <!-- we assume the cook_time is passed in as a context parameter -->
+ <if cond="empty(cook_time)">
+ <!-- default setting, note namespace of this custom action -->
+ <cs:var name="cook_time" expr="5"/>
+ </if>
+ <!-- timer variable -->
+ <cs:var name="timer" expr="0"/>
+ </onentry>
+
+ <transition event="turn_off" target="off"/>
+
+ <transition cond="timer ge cook_time" target="off"/>
+
+ <state id="idle">
+ <transition cond="In('closed')" target="cooking"/>
+ </state>
+
+ <state id="cooking">
+ <transition cond="not In('closed')" target="idle"/>
+
+ <transition event="time" target="cooking">
+ <assign name="timer" expr="timer + 1"/>
+ </transition>
+ </state>
+ </state>
+ </state>
+
+ <state id="door">
+ <initial>
+ <transition target="closed"/>
+ </initial>
+ <state id="closed">
+ <transition event="door_open" target="open"/>
+ </state>
+ <state id="open">
+ <transition event="door_close" target="closed"/>
+ </state>
+ </state>
+
+ </parallel>
+
+</scxml>
diff --git a/test/samples/apache/microwave-05.xml b/test/samples/apache/microwave-05.xml
new file mode 100644
index 0000000..06b9fc9
--- /dev/null
+++ b/test/samples/apache/microwave-05.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ This document uses Commons JEXL as the expressions language.
+ Needs SCXMLParser.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:cs="http://commons.apache.org/scxml"
+ version="1.0"
+ initialstate="microwave">
+
+ <!-- trivial microwave oven example -->
+ <!-- using parallel (part of composite state) and In() predicate -->
+
+ <state id="microwave">
+
+ <initial>
+ <transition target="parts"/>
+ </initial>
+
+ <parallel id="parts">
+
+ <state id="oven">
+ <initial>
+ <transition target="off"/>
+ </initial>
+
+ <state id="off">
+ <!-- off state -->
+ <transition event="turn_on" target="on"/>
+ </state>
+
+ <state id="on">
+ <initial>
+ <transition target="idle"/>
+ </initial>
+
+ <!-- on/pause state -->
+ <onentry>
+ <!-- we assume the cook_time is passed in as a context parameter -->
+ <if cond="empty(cook_time)">
+ <!-- default setting, note namespace of this custom action -->
+ <cs:var name="cook_time" expr="5"/>
+ </if>
+ <!-- timer variable -->
+ <cs:var name="timer" expr="0"/>
+ </onentry>
+
+ <transition event="turn_off" target="off"/>
+
+ <transition cond="timer ge cook_time" target="off"/>
+
+ <state id="idle">
+ <transition cond="In('closed')" target="cooking"/>
+ </state>
+
+ <state id="cooking">
+ <transition cond="not In('closed')" target="idle"/>
+
+ <transition event="time" target="cooking">
+ <assign name="timer" expr="timer + 1"/>
+ </transition>
+ </state>
+ </state>
+ </state>
+
+ <state id="door">
+ <initial>
+ <transition target="closed"/>
+ </initial>
+ <state id="closed">
+ <transition event="door_open" target="open"/>
+ </state>
+ <state id="open">
+ <transition event="door_close" target="closed"/>
+ </state>
+ </state>
+
+ </parallel>
+
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/parallel-01.xml b/test/samples/apache/parallel-01.xml
new file mode 100644
index 0000000..e822285
--- /dev/null
+++ b/test/samples/apache/parallel-01.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ Needs SCXMLParser
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="para">
+
+ <parallel id="para">
+
+ <state id="para1">
+
+ <initial>
+ <transition target="para11"/>
+ </initial>
+
+ <state id="para11">
+ <transition event="foo" target="para12"/>
+ </state>
+
+ <state id="para12">
+ <onexit>
+ <log expr="'Exiting para12'" />
+ </onexit>
+ </state>
+
+ </state>
+
+ <state id="para2">
+
+ <initial>
+ <transition target="para21"/>
+ </initial>
+
+ <state id="para21">
+ <transition cond="In('para12')" target="para22"/>
+ </state>
+
+ <state id="para22">
+ <onexit>
+ <log expr="'Exiting para22'" />
+ </onexit>
+
+ <transition target="end"/>
+ </state>
+
+ </state>
+
+ </parallel>
+
+ <state id="end" final="true" />
+
+</scxml>
+
diff --git a/test/samples/apache/parallel-02.xml b/test/samples/apache/parallel-02.xml
new file mode 100644
index 0000000..106fc86
--- /dev/null
+++ b/test/samples/apache/parallel-02.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ Needs SCXMLParser
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initialstate="state0">
+
+ <parallel id="state0">
+ <transition event="event1" target="state1" />
+ <!-- dummy regions -->
+ <state id="state01"/>
+ <state id="state02"/>
+ </parallel>
+ <final id="state1"/>
+
+</scxml>
diff --git a/test/samples/apache/parallel-03.xml b/test/samples/apache/parallel-03.xml
new file mode 100644
index 0000000..d57196a
--- /dev/null
+++ b/test/samples/apache/parallel-03.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ Needs SCXMLParser
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initial="para">
+
+ <datamodel>
+ <data id="root">
+ <root xmlns="">
+ <count>0</count>
+ </root>
+ </data>
+ </datamodel>
+
+ <parallel id="para">
+
+ <onentry>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onentry>
+
+ <state id="para1">
+
+ <initial>
+ <transition target="para11"/>
+ </initial>
+ <onentry>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onentry>
+
+ <state id="para11">
+ <onentry>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onentry>
+ <transition event="foo" target="para12"/>
+ <onexit>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onexit>
+ </state>
+
+ <final id="para12">
+ <onentry>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onentry>
+ <onexit>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onexit>
+ </final>
+
+ <onexit>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onexit>
+
+ </state>
+
+ <state id="para2">
+
+ <initial>
+ <transition target="para21"/>
+ </initial>
+ <onentry>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onentry>
+
+ <state id="para21">
+ <onentry>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onentry>
+ <transition event="bar" target="para22"/>
+ <onexit>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onexit>
+ </state>
+
+ <final id="para22">
+ <onentry>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onentry>
+ <onexit>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onexit>
+ </final>
+
+ <onexit>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onexit>
+
+ </state>
+
+ <transition event="para.done" target="end"/>
+
+ <onexit>
+ <assign location="Data(root, 'root/count')" expr="Data(root, 'root/count') + 1"/>
+ </onexit>
+
+ </parallel>
+
+ <state id="end" final="true" />
+
+</scxml>
+
diff --git a/test/samples/apache/prefix-01.xml b/test/samples/apache/prefix-01.xml
new file mode 100644
index 0000000..79cbe69
--- /dev/null
+++ b/test/samples/apache/prefix-01.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml:scxml xmlns:scxml="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="ten">
+
+ <scxml:state id="ten">
+ <scxml:transition event="ten.done" target="twenty"/>
+ </scxml:state>
+
+ <scxml:state id="twenty" final="true" />
+
+</scxml:scxml>
+
diff --git a/test/samples/apache/scxml-initial-attr.xml b/test/samples/apache/scxml-initial-attr.xml
new file mode 100644
index 0000000..0965653
--- /dev/null
+++ b/test/samples/apache/scxml-initial-attr.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used for SrcTest.java in io package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initial="foo">
+
+ <final id="foo"/>
+
+</scxml>
diff --git a/test/samples/apache/send-01.xml b/test/samples/apache/send-01.xml
new file mode 100644
index 0000000..4f3cf40
--- /dev/null
+++ b/test/samples/apache/send-01.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="ten">
+
+ <state id="ten">
+ <transition event="ten.done" target="twenty">
+ <send sendid="send1" delay="'0'"
+ target="'http://localhost:8080/VXMLInterpreter'" type="'v3'"
+ xmlns:v3="http://foo.bar.com/vxml3"
+ xmlns:test="http://my.test.namespace">
+ <v3:form id="Confirm">
+ <v3:grammar type="application/srgs+xml"
+ src="/grammars/boolean.grxml"/>
+ <v3:block>
+ <v3:prompt>Say yes or no.</v3:prompt>
+ </v3:block>
+ </v3:form>
+ <test:foo id="foo1">
+ <test:bar id="bar1" />
+ </test:foo>
+ <test:foo id="foo2">
+ <v3:prompt>This is just an example.</v3:prompt>
+ </test:foo>
+ </send>
+ </transition>
+ </state>
+
+ <state id="twenty" final="true" />
+
+</scxml>
diff --git a/test/samples/apache/send-02.xml b/test/samples/apache/send-02.xml
new file mode 100644
index 0000000..9685385
--- /dev/null
+++ b/test/samples/apache/send-02.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Various send usages that fire the events on the existing execution
+ engine. -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="ten">
+
+ <!-- We are expected to just fall all the way through down to
+ the state "seventy", then hop over and end up in "ninety" -->
+ <state id="ten">
+ <onentry>
+ <send event="'ten.' + 'done'" />
+ </onentry>
+ <transition event="ten.done" target="twenty" />
+ </state>
+
+ <state id="twenty">
+ <onentry>
+ <send event="'twenty.done'" type="'scxml'" />
+ </onentry>
+ <transition event="twenty.done" target="thirty" />
+ </state>
+
+ <state id="thirty">
+ <onentry>
+ <send event="'thirty.done'" type="' sCxML '" />
+ </onentry>
+ <transition event="thirty.done" target="forty" />
+ </state>
+
+ <state id="forty">
+ <onentry>
+ <send event="'forty.done'" type=" " target=" " />
+ </onentry>
+ <transition event="forty.done" target="fifty" />
+ </state>
+
+ <state id="fifty">
+ <onentry>
+ <send event="'fifty.done'" target="' '" />
+ </onentry>
+ <transition event="fifty.done" target="sixty" />
+ </state>
+
+ <state id="sixty">
+ <onentry>
+ <send event="'sixty.done'" type="'scxml'" target=" " />
+ </onentry>
+ <transition event="sixty.done" target="seventy" />
+ </state>
+
+ <state id="seventy">
+ <onentry>
+ <send event="'seventy.done'" type="'scxml'" target="'foo'" />
+ </onentry>
+
+ <!-- This transition should not be followed since
+ target "foo" is unavailable (any target other
+ than an empty target is unavailable, empty target
+ is current execution i.e. this state machine) -->
+ <transition event="seventy.done" target="eighty" />
+
+ <!-- Since "foo" it not available, the event
+ "error.send.targetunavailable" should be raised -->
+ <transition event="error.send.targetunavailable" target="ninety" />
+
+ </state>
+
+ <state id="eighty" final="true" />
+
+ <state id="ninety" final="true" />
+
+</scxml>
diff --git a/test/samples/apache/src-test-1.xml b/test/samples/apache/src-test-1.xml
new file mode 100644
index 0000000..74e6ce2
--- /dev/null
+++ b/test/samples/apache/src-test-1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used for SrcTest.java in io package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="srctest1">
+
+ <state id="srctest1" src="src-test-2.xml">
+ <transition event="src.test" target="srctest3end"/>
+ <transition event="srctest1.done" target="srctest1end"/>
+ </state>
+
+ <state id="srctest1end" final="true"/>
+
+</scxml>
+
diff --git a/test/samples/apache/src-test-2.xml b/test/samples/apache/src-test-2.xml
new file mode 100644
index 0000000..16789ab
--- /dev/null
+++ b/test/samples/apache/src-test-2.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used for SrcTest.java in io package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="srctest2">
+
+ <state id="srctest2" src="src-test-3.xml">
+ <transition event="srctest2.done" target="srctest2end"/>
+ </state>
+
+ <state id="srctest2end" final="true"/>
+
+</scxml>
+
diff --git a/test/samples/apache/src-test-3.xml b/test/samples/apache/src-test-3.xml
new file mode 100644
index 0000000..d675687
--- /dev/null
+++ b/test/samples/apache/src-test-3.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used for SrcTest.java in io package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="srctest3">
+
+ <state id="srctest3"/>
+
+ <state id="srctest3end" final="true"/>
+
+</scxml>
+
diff --git a/test/samples/apache/src-test-4.xml b/test/samples/apache/src-test-4.xml
new file mode 100644
index 0000000..4fe18e5
--- /dev/null
+++ b/test/samples/apache/src-test-4.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used for SrcTest.java in io package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="srctest1">
+
+ <state id="srctest1" src="bad-document-404.xml">
+ <transition event="srctest1.done" target="srctest1end"/>
+ </state>
+
+ <state id="srctest1end" final="true"/>
+
+</scxml>
+
diff --git a/test/samples/apache/src-test-5.xml b/test/samples/apache/src-test-5.xml
new file mode 100644
index 0000000..a36e112
--- /dev/null
+++ b/test/samples/apache/src-test-5.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Used for SrcTest.java in io package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="srctest1">
+
+ <state id="srctest1" src="src-test-3.xml#badstateid404">
+ <transition event="srctest1.done" target="srctest1end"/>
+ </state>
+
+ <state id="srctest1end" final="true"/>
+
+</scxml>
+
diff --git a/test/samples/apache/state-01.xml b/test/samples/apache/state-01.xml
new file mode 100644
index 0000000..22a9018
--- /dev/null
+++ b/test/samples/apache/state-01.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="s1">
+
+ <state id="s1" initial="s11">
+ <final id="s11"/>
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/stateless-01.xml b/test/samples/apache/stateless-01.xml
new file mode 100644
index 0000000..1229b8f
--- /dev/null
+++ b/test/samples/apache/stateless-01.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="main">
+
+ <state id="main">
+
+ <initial>
+ <transition target="ten"/>
+ </initial>
+
+ <onentry>
+ <var name="instancevar" expr="${20}" />
+ </onentry>
+
+ <state id="ten">
+ <transition event="ten.done" cond="${instancevar eq 20}"
+ target="twenty" />
+ <onexit>
+ <assign name="instancevar" expr="${30}" />
+ </onexit>
+ </state>
+
+ <state id="twenty">
+ <transition event="twenty.done" cond="${instancevar eq 30}"
+ target="thirty" />
+ </state>
+
+ <state id="thirty" final="true" />
+
+ </state>
+
+</scxml>
+
diff --git a/test/samples/apache/stateless-parallel-01.xml b/test/samples/apache/stateless-parallel-01.xml
new file mode 100644
index 0000000..f2e9017
--- /dev/null
+++ b/test/samples/apache/stateless-parallel-01.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="main">
+
+ <state id="main">
+
+ <parallel id="main.parallel">
+
+ <state id="state1">
+ <initial>
+ <transition target="state1.init"/>
+ </initial>
+ <state id="state1.init">
+ <transition event="state1.event" target="state1.final" />
+ </state>
+ <state id="state1.final" final="true" />
+ </state>
+
+ <state id="state2">
+ <initial>
+ <transition target="state2.init"/>
+ </initial>
+ <state id="state2.init">
+ <transition event="state2.event" target="state2.final" />
+ </state>
+ <state id="state2.final" final="true" />
+ </state>
+
+ </parallel>
+
+ <transition event="main.parallel.done" target="next" />
+
+ </state>
+
+ <state id="next" final="true"/>
+
+</scxml>
diff --git a/test/samples/apache/static-method.xml b/test/samples/apache/static-method.xml
new file mode 100644
index 0000000..7ad034a
--- /dev/null
+++ b/test/samples/apache/static-method.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- Example of invoking a static method when using JEXL, for example:
+ (public static) java.lang.System#currentTimeMillis()
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="static">
+
+ <state id="static" final="true">
+ <onentry>
+ <log expr="'Current time millis: ' + System.currentTimeMillis()" />
+ </onentry>
+ </state>
+
+</scxml>
+
diff --git a/test/samples/apache/stopwatch.xml b/test/samples/apache/stopwatch.xml
new file mode 100644
index 0000000..57572a1
--- /dev/null
+++ b/test/samples/apache/stopwatch.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="reset">
+
+ <state id="reset">
+ <transition event="watch.start" target="running"/>
+ </state>
+
+ <state id="running">
+ <transition event="watch.split" target="paused"/>
+ <transition event="watch.stop" target="stopped"/>
+ </state>
+
+ <state id="paused">
+ <transition event="watch.unsplit" target="running"/>
+ <transition event="watch.stop" target="stopped"/>
+ </state>
+
+ <state id="stopped">
+ <transition event="watch.reset" target="reset"/>
+ </state>
+
+</scxml>
+
diff --git a/test/samples/apache/tie-breaker-01.xml b/test/samples/apache/tie-breaker-01.xml
new file mode 100644
index 0000000..7cff894
--- /dev/null
+++ b/test/samples/apache/tie-breaker-01.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ Used by TieBreakerTest
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="ten">
+ <state id="ten">
+ <!-- twenty should win, document order -->
+ <transition event="ten.done" target="twenty" />
+ <transition event="ten.done" target="thirty" />
+ </state>
+
+ <state id="twenty" final="true" />
+
+ <state id="thirty" final="true" />
+
+</scxml>
+
diff --git a/test/samples/apache/tie-breaker-02.xml b/test/samples/apache/tie-breaker-02.xml
new file mode 100644
index 0000000..62118dd
--- /dev/null
+++ b/test/samples/apache/tie-breaker-02.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ Used by TieBreakerTest
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="ten">
+
+ <state id="ten">
+ <initial>
+ <transition target="eleven"/>
+ </initial>
+
+ <transition event="ten.done" target="twenty" />
+
+ <state id="eleven">
+ <!-- thirty wins since eleven trumps
+ ten in the state heirarchy -->
+ <transition event="ten.done" target="thirty" />
+ </state>
+
+ </state>
+
+ <state id="twenty" final="true" />
+
+ <state id="thirty" final="true" />
+
+</scxml>
+
diff --git a/test/samples/apache/tie-breaker-03.xml b/test/samples/apache/tie-breaker-03.xml
new file mode 100644
index 0000000..d850865
--- /dev/null
+++ b/test/samples/apache/tie-breaker-03.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ Used by TieBreakerTest
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="ten">
+
+ <state id="ten">
+ <initial>
+ <transition target="eleven"/>
+ </initial>
+
+ <transition event="ten.done" target="twenty" />
+
+ <transition event="ten.done" target="thirty" />
+
+ <state id="eleven">
+
+ <!-- forty wins due to document order and the fact
+ that since eleven trumps ten in the state
+ heirarchy -->
+ <transition event="ten.done" target="forty" />
+
+ <transition event="ten.done" target="fifty" />
+
+ </state>
+
+ </state>
+
+ <state id="twenty" final="true" />
+
+ <state id="thirty" final="true" />
+
+ <state id="forty" final="true" />
+
+ <state id="fifty" final="true" />
+
+</scxml>
+
diff --git a/test/samples/apache/tie-breaker-04.xml b/test/samples/apache/tie-breaker-04.xml
new file mode 100644
index 0000000..df87e63
--- /dev/null
+++ b/test/samples/apache/tie-breaker-04.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initialstate="s1">
+
+ <state id="s1">
+ <initial>
+ <transition target="s11"/>
+ </initial>
+
+ <transition event="event_1"/>
+
+ <transition event="event_2" target="s1"/>
+
+ <state id="s11">
+ <transition event="event_1"/>
+ <transition event="event_2" target="s11"/>
+ </state>
+ </state>
+
+ <state id="s2" final="true" />
+</scxml>
diff --git a/test/samples/apache/tie-breaker-05.xml b/test/samples/apache/tie-breaker-05.xml
new file mode 100644
index 0000000..1fcbd35
--- /dev/null
+++ b/test/samples/apache/tie-breaker-05.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initialstate="para">
+
+<!--
+ Testing dispute resolution in regions
+ {s11,s2111,s212} -event1-> {s12,s2112,s212}
+-->
+
+ <parallel id="para"> <!-- Outer parallel -->
+
+ <state id="s1">
+ <initial>
+ <transition target="s11"/>
+ </initial>
+ <state id="s11">
+ <transition event="event1" target="s12"/>
+ <transition event="event1" target="s13"/>
+ </state>
+ <state id="s12"/>
+ <state id="s13"/>
+ </state>
+
+ <state id="s2">
+ <initial>
+ <transition target="para1"/>
+ </initial>
+
+ <parallel id="para1"> <!-- Inner parallel -->
+ <state id="s211">
+ <initial>
+ <transition target="s2111"/>
+ </initial>
+ <state id="s2111">
+ <transition event="event1" target="s2112"/>
+ <transition event="event1" target="s2113"/>
+ </state>
+ <state id="s2112"/>
+ <state id="s2113"/>
+ </state>
+ <state id="s212"/>
+ </parallel>
+
+ <state id="s22"/>
+ </state>
+
+ </parallel>
+
+</scxml>
diff --git a/test/samples/apache/tie-breaker-06.xml b/test/samples/apache/tie-breaker-06.xml
new file mode 100644
index 0000000..a7f26ff
--- /dev/null
+++ b/test/samples/apache/tie-breaker-06.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- A fictitious state machine used by test cases.
+ <send>s in the same executable content block -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initialstate="main">
+
+ <state id="main">
+
+ <onentry>
+ <event name="internal_event1"/>
+ <event name="internal_event2"/>
+ </onentry>
+
+ <transition event="internal_event1">
+ <log label="Expected"
+ expr="'Transition for first event (internal_event1) followed'"/>
+ </transition>
+ <transition event="internal_event2">
+ <log label="Unexpected"
+ expr="'Transition for second event (internal_event2) followed'"/>
+ </transition>
+
+ </state>
+
+</scxml>
diff --git a/test/samples/apache/transitions-01-legacy.xml b/test/samples/apache/transitions-01-legacy.xml
new file mode 100644
index 0000000..f46bc74
--- /dev/null
+++ b/test/samples/apache/transitions-01-legacy.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="ten">
+
+ <!-- Start with a simple state -->
+ <state id="ten">
+ <transition event="ten.done" target="twenty" />
+ </state>
+
+ <!-- Follow up with a composite state -->
+ <state id="twenty">
+
+ <initial>
+ <transition target="twenty_one"/>
+ </initial>
+
+ <onentry>
+ <log expr="'In twenty'" />
+ </onentry>
+
+ <state id="twenty_one">
+ <transition event="twenty_one.done" target="twenty_two"/>
+ </state>
+
+ <state id="twenty_two">
+ <transition event="twenty_two.done" target="thirty"/>
+ </state>
+
+ </state>
+
+ <!-- Finally, try an orthogonal state -->
+ <state id="thirty">
+
+ <parallel id="thirties_parallel">
+
+ <!-- The first (of three) regions in thirties_parallel -->
+ <state id="thirty_one">
+
+ <initial>
+ <transition target="thirty_one_child_one"/>
+ </initial>
+ <onentry>
+ <log expr="'Entering thirty_one'" />
+ </onentry>
+ <transition event="thirty_one.done" target="forty"/>
+
+ <state id="thirty_one_child_one">
+ <onexit>
+ <log expr="'Exiting thirty_one_child_one'" />
+ </onexit>
+ <transition event="thirty_one_child_one.done"
+ target="thirty_one_child_two"/>
+ </state>
+
+ <state id="thirty_one_child_two">
+ <onexit>
+ <log expr="'Exiting thirty_one_child_two'" />
+ </onexit>
+ </state>
+
+ </state>
+
+ <!-- The second (of three) regions in thirties_parallel -->
+ <state id="thirty_two">
+
+ <initial>
+ <transition target="thirty_two_child_one"/>
+ </initial>
+ <onentry>
+ <log expr="'Entering thirty_two'" />
+ </onentry>
+
+ <state id="thirty_two_child_one">
+ <onexit>
+ <log expr="'Exiting thirty_two_child_one'" />
+ </onexit>
+ <transition event="thirty_two_child_one.done"
+ target="thirty_two_child_two"/>
+ </state>
+
+ <state id="thirty_two_child_two">
+ <onexit>
+ <log expr="'Exiting thirty_two_child_two'" />
+ </onexit>
+ </state>
+
+ </state>
+
+ <!-- The third (of three) regions in thirties_parallel -->
+ <state id="thirty_three">
+
+ <initial>
+ <transition target="thirty_three_child_one"/>
+ </initial>
+ <onentry>
+ <log expr="'Entering thirty_three'" />
+ </onentry>
+
+ <state id="thirty_three_child_one">
+ <onexit>
+ <log expr="'Exiting thirty_three_child_one'" />
+ </onexit>
+ <transition event="thirty_three_child_one.done"
+ target="thirty_three_child_two"/>
+ </state>
+
+ <state id="thirty_three_child_two">
+ <onexit>
+ <log expr="'Exiting thirty_three_child_two'" />
+ </onexit>
+ </state>
+
+ </state>
+
+ </parallel>
+
+ </state>
+
+ <!-- Declare victory -->
+ <state id="forty" final="true" />
+
+</scxml>
+
diff --git a/test/samples/apache/transitions-01.xml b/test/samples/apache/transitions-01.xml
new file mode 100644
index 0000000..ee5133f
--- /dev/null
+++ b/test/samples/apache/transitions-01.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml
+ version="1.0"
+ initial="ten">
+
+ <!-- Start with a simple state -->
+ <state id="ten">
+ <transition event="ten.done" target="twenty" />
+ </state>
+
+ <!-- Follow up with a composite state -->
+ <state id="twenty">
+
+ <initial>
+ <transition target="twenty_one"/>
+ </initial>
+
+ <onentry>
+ <log expr="'In twenty'" />
+ </onentry>
+
+ <state id="twenty_one">
+ <transition event="twenty_one.done" target="twenty_two"/>
+ </state>
+
+ <state id="twenty_two">
+ <transition event="twenty_two.done" target="thirty"/>
+ </state>
+
+ </state>
+
+ <!-- Finally, try an orthogonal state -->
+ <parallel id="thirty">
+
+ <!-- The first (of three) regions in thirties_parallel -->
+ <state id="thirty_one">
+
+ <initial>
+ <transition target="thirty_one_child_one"/>
+ </initial>
+ <onentry>
+ <log expr="'Entering thirty_one'" />
+ </onentry>
+ <transition event="thirty_one.done" target="forty"/>
+
+ <state id="thirty_one_child_one">
+ <onexit>
+ <log expr="'Exiting thirty_one_child_one'" />
+ </onexit>
+ <transition event="thirty_one_child_one.done"
+ target="thirty_one_child_two"/>
+ </state>
+
+ <state id="thirty_one_child_two">
+ <onexit>
+ <log expr="'Exiting thirty_one_child_two'" />
+ </onexit>
+ </state>
+
+ </state>
+
+ <!-- The second (of three) regions in thirties_parallel -->
+ <state id="thirty_two">
+
+ <initial>
+ <transition target="thirty_two_child_one"/>
+ </initial>
+ <onentry>
+ <log expr="'Entering thirty_two'" />
+ </onentry>
+
+ <state id="thirty_two_child_one">
+ <onexit>
+ <log expr="'Exiting thirty_two_child_one'" />
+ </onexit>
+ <transition event="thirty_two_child_one.done"
+ target="thirty_two_child_two"/>
+ </state>
+
+ <state id="thirty_two_child_two">
+ <onexit>
+ <log expr="'Exiting thirty_two_child_two'" />
+ </onexit>
+ </state>
+
+ </state>
+
+ <!-- The third (of three) regions in thirties_parallel -->
+ <state id="thirty_three">
+
+ <initial>
+ <transition target="thirty_three_child_one"/>
+ </initial>
+ <onentry>
+ <log expr="'Entering thirty_three'" />
+ </onentry>
+
+ <state id="thirty_three_child_one">
+ <onexit>
+ <log expr="'Exiting thirty_three_child_one'" />
+ </onexit>
+ <transition event="thirty_three_child_one.done"
+ target="thirty_three_child_two"/>
+ </state>
+
+ <state id="thirty_three_child_two">
+ <onexit>
+ <log expr="'Exiting thirty_three_child_two'" />
+ </onexit>
+ </state>
+
+ </state>
+
+ </parallel>
+
+ <!-- Declare victory -->
+ <state id="forty" final="true" />
+
+</scxml>
+
diff --git a/test/samples/apache/transitions-02.xml b/test/samples/apache/transitions-02.xml
new file mode 100644
index 0000000..7c1dcf5
--- /dev/null
+++ b/test/samples/apache/transitions-02.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:cs="http://commons.apache.org/scxml"
+ version="1.0"
+ initialstate="ten">
+
+ <state id="ten">
+
+ <onentry>
+ <cs:var name="foo" expr="1" />
+ <log expr="'Foo is:' + foo" />
+ </onentry>
+
+ <!-- stay transition -->
+ <transition event="ten.stay">
+ <assign name="foo" expr="foo + 1" />
+ <log expr="'Foo is:' + foo" />
+ </transition>
+
+ <!-- self transition -->
+ <transition event="ten.self" target="ten">
+ <assign name="foo" expr="foo + 1" />
+ <log expr="'Foo is:' + foo" />
+ </transition>
+
+ <!-- "regular" transition -->
+ <transition event="ten.done" target="twenty">
+ <assign name="foo" expr="foo + 1" />
+ <log expr="'Foo is:' + foo" />
+ </transition>
+
+ </state>
+
+ <state id="twenty" final="true" />
+
+</scxml>
+
diff --git a/test/samples/apache/transitions-03.xml b/test/samples/apache/transitions-03.xml
new file mode 100644
index 0000000..303d673
--- /dev/null
+++ b/test/samples/apache/transitions-03.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="ten">
+
+ <state id="ten">
+ <transition event="ten.done"
+ target="twenty_one_2 twenty_two_2 twenty_three_2" />
+ </state>
+
+ <parallel id="twenty">
+
+ <state id="twenty_one">
+
+ <initial>
+ <transition target="twenty_one_1"/>
+ </initial>
+
+ <state id="twenty_one_1">
+ <transition event="foo" target="twenty_one_2"/>
+ </state>
+
+ <state id="twenty_one_2">
+ <onexit>
+ <log expr="'Exiting twenty_two_2'" />
+ </onexit>
+ </state>
+
+ </state>
+
+ <state id="twenty_two">
+
+ <initial>
+ <transition target="twenty_two_1"/>
+ </initial>
+
+ <state id="twenty_two_1">
+ <transition event="foo" target="twenty_two_2"/>
+ </state>
+
+ <state id="twenty_two_2">
+ <onexit>
+ <log expr="'Exiting twenty_two_2'" />
+ </onexit>
+ </state>
+
+ </state>
+
+ <state id="twenty_three">
+
+ <initial>
+ <transition target="twenty_three_1"/>
+ </initial>
+
+ <state id="twenty_three_1">
+ <transition event="foo" target="twenty_three_2"/>
+ </state>
+
+ <state id="twenty_three_2">
+ <onexit>
+ <log expr="'Exiting twenty_three_2'" />
+ </onexit>
+ </state>
+
+ </state>
+
+ </parallel>
+
+ <state id="thirty" final="true" />
+
+</scxml>
+
diff --git a/test/samples/apache/transitions-04.xml b/test/samples/apache/transitions-04.xml
new file mode 100644
index 0000000..547b702
--- /dev/null
+++ b/test/samples/apache/transitions-04.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!--
+ Needs SCXMLParser
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="ten">
+
+ <state id="ten">
+ <transition event="ten.done"
+ target="twenty" />
+ </state>
+
+ <parallel id="twenty">
+
+ <state id="twenty_one">
+
+ <initial>
+ <transition target="twenty_one_1"/>
+ </initial>
+
+ <transition event="bar" target="thirty"/>
+
+ <state id="twenty_one_1">
+ <transition event="foo" target="twenty_one_2"/>
+ </state>
+
+ <state id="twenty_one_2">
+ <onexit>
+ <log expr="'Exiting twenty_two_2'" />
+ </onexit>
+ </state>
+
+ </state>
+
+ <state id="twenty_two">
+
+ <initial>
+ <transition target="twenty_two_1"/>
+ </initial>
+
+ <state id="twenty_two_1">
+ <transition event="foo" target="twenty_two_2"/>
+ </state>
+
+ <state id="twenty_two_2">
+ <onexit>
+ <log expr="'Exiting twenty_two_2'" />
+ </onexit>
+ </state>
+
+ </state>
+
+ <state id="twenty_three">
+
+ <initial>
+ <transition target="twenty_three_1"/>
+ </initial>
+
+ <state id="twenty_three_1">
+ <transition event="foo" target="twenty_three_2"/>
+ </state>
+
+ <state id="twenty_three_2">
+ <onexit>
+ <log expr="'Exiting twenty_three_2'" />
+ </onexit>
+ </state>
+
+ </state>
+
+ </parallel>
+
+ <state id="thirty" final="true" />
+
+</scxml>
+
diff --git a/test/samples/apache/transitions-05.xml b/test/samples/apache/transitions-05.xml
new file mode 100644
index 0000000..7400359
--- /dev/null
+++ b/test/samples/apache/transitions-05.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="init">
+ <state id="init">
+ <transition event="start" target="onetwo" />
+ </state>
+ <parallel id="onetwo">
+ <transition event="onetwo_three" target="three" />
+ <state id="one">
+ </state>
+ <state id="two">
+ <transition event="two_four" target="four" />
+ </state>
+ </parallel>
+ <state id="three">
+ <transition event="three_one" target="one" />
+ <transition event="three_four" target="four" />
+ </state>
+ <state id="four">
+ <transition event="four_onetwo" target="onetwo" />
+ <transition event="four_three" target="three" />
+ </state>
+</scxml>
diff --git a/test/samples/apache/travel-dialog.xml b/test/samples/apache/travel-dialog.xml
new file mode 100644
index 0000000..08ebc99
--- /dev/null
+++ b/test/samples/apache/travel-dialog.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/01/SCXML"
+ version="1.0"
+ initialstate="tripType">
+
+ <state id="tripType">
+ <transition event="tripType.done">
+ <target next="departureCity"/>
+ </transition>
+ </state>
+
+ <state id="departureCity">
+ <transition event="departureCity.done">
+ <target next="arrivalCity"/>
+ </transition>
+ </state>
+
+ <state id="arrivalCity">
+ <transition event="arrivalCity.done">
+ <target next="departureDate"/>
+ </transition>
+ </state>
+
+ <state id="departureDate">
+ <transition event="departureDate.done"
+ cond="${tripType == 'round'}">
+ <target next="arrivalDate"/>
+ </transition>
+ <transition event="departureDate.done"
+ cond="${tripType == '1way'}">
+ <exit />
+ </transition>
+ </state>
+
+ <state id="arrivalDate"
+ final="true" />
+
+</scxml>
diff --git a/test/samples/apache/wildcard-01.xml b/test/samples/apache/wildcard-01.xml
new file mode 100644
index 0000000..9f7ddc3
--- /dev/null
+++ b/test/samples/apache/wildcard-01.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ xmlns:cs="http://commons.apache.org/scxml"
+ version="1.0"
+ initialstate="state1">
+ <state id="state1">
+ <onentry>
+ <cs:var name="switch" expr="4" />
+ </onentry>
+ <!-- We'll trigger 'foo.bar.baz' event,
+ and therefore, must end up in state4 -->
+ <transition event="*" cond="switch eq 2" target="state2"/>
+ <transition event="foo.*" cond="switch eq 3" target="state3"/>
+ <transition event="foo.bar.*" cond="switch eq 4" target="state4"/>
+ </state>
+ <state id="state2" final="true"/>
+ <state id="state3" final="true"/>
+ <state id="state4" final="true"/>
+</scxml>
diff --git a/test/samples/apache/wildcard-02.xml b/test/samples/apache/wildcard-02.xml
new file mode 100644
index 0000000..d039f69
--- /dev/null
+++ b/test/samples/apache/wildcard-02.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="state1">
+
+ <state id="state1">
+ <onentry>
+ <event name="success.start"/>
+ </onentry>
+ <transition event="success.*" target="state2"/>
+ </state>
+
+ <state id="state2"/>
+
+</scxml>
+
diff --git a/test/samples/apache/wizard-01.xml b/test/samples/apache/wizard-01.xml
new file mode 100644
index 0000000..87492a6
--- /dev/null
+++ b/test/samples/apache/wizard-01.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="state1">
+ <state id="state1">
+ <transition event="event2" target="state2"/>
+ <transition event="event3" target="state3"/>
+ <transition event="event4" target="state4"/>
+ </state>
+ <state id="state2">
+ <transition event="event1" target="state1"/>
+ <transition event="event3" target="state3"/>
+ <transition event="event4" target="state4"/>
+ </state>
+ <state id="state3">
+ <transition event="event1" target="state1"/>
+ <transition event="event2" target="state2"/>
+ <transition event="event4" target="state4"/>
+ </state>
+ <state id="state4">
+ <transition event="event1" target="state1"/>
+ <transition event="event2" target="state2"/>
+ <transition event="event3" target="state3"/>
+ </state>
+</scxml>
diff --git a/test/samples/apache/wizard-02.xml b/test/samples/apache/wizard-02.xml
new file mode 100644
index 0000000..924b83f
--- /dev/null
+++ b/test/samples/apache/wizard-02.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initialstate="state1">
+ <state id="state1">
+ <onentry>
+ <!-- Send without a type causes the
+ default to be chosen as "scxml".
+ This will cause the first transition
+ to state2 to be immediately followed. -->
+ <send event="'event2'" />
+ </onentry>
+ <transition event="event2" target="state2"/>
+ <transition event="event3" target="state3"/>
+ <transition event="event4" target="state4"/>
+ </state>
+ <state id="state2">
+ <onentry>
+ <var name="aValue" expr="2"/>
+ <!-- Send with a non-empty (and not "scxml")
+ type causes the callback on the
+ EventDispatcher implementation. See
+ testWizard02Sample() in WizardsTest
+ (org.apache.commons.scxml test package) -->
+ <send namelist="aValue" type="'foo'" />
+ </onentry>
+ <transition event="event1" target="state1"/>
+ <transition event="event3" target="state3"/>
+ <transition event="event4" target="state4"/>
+ </state>
+ <state id="state3">
+ <onentry>
+ <var name="aValue" expr="3"/>
+ <send namelist="aValue" type="'foo'" />
+ </onentry>
+ <transition event="event1" target="state1"/>
+ <transition event="event2" target="state2"/>
+ <transition event="event4" target="state4"/>
+ </state>
+ <state id="state4">
+ <onentry>
+ <var name="aValue" expr="4"/>
+ <send namelist="aValue" type="'foo'" />
+ </onentry>
+ <transition event="event1" target="state1"/>
+ <transition event="event2" target="state2"/>
+ <transition event="event3" target="state3"/>
+ </state>
+</scxml> \ No newline at end of file
diff --git a/test/samples/w3c/Blackjack.scxml b/test/samples/w3c/Blackjack.scxml
new file mode 100644
index 0000000..4f55e53
--- /dev/null
+++ b/test/samples/w3c/Blackjack.scxml
@@ -0,0 +1,99 @@
+<?xml version="1.0"?>
+<?access-control allow="*"?>
+<scxml version="1.0" datamodel="ecmascript" initial="master"> <state id="master">
+ <initial id="init1">
+ <transition target="_home"/>
+ </initial>
+ <transition event="new_dealer" target="NewDealer"/>
+ <transition event="mumble" target="_home"/> <!-- bail out to caller -->
+ <transition event="silence" target="_home"/> <!-- bail out to caller -->
+ <state id="_home">
+ <onenter>
+ <script>
+ _data = {};
+ </script>
+ </onenter>
+ <invoke src="datamodel.v3#InitDataModel" type="vxml3">
+ <finalize>
+ <script>
+ var n;
+ for (n in event) {
+ _data[n] = event[n];
+ }
+ </script>
+ </finalize>
+ </invoke>
+ <transition event="success" target="Welcome"/>
+ </state>
+
+ <state id="Welcome">
+ <invoke src="dialog.vxml#Welcome" type="vxml3">
+ <param name="skinpath" expr="skinpath"/>
+ </invoke>
+ <transition event="success" target="Intro2"/>
+ </state>
+
+ <state id="Intro2">
+ <invoke src="dialog.vxml#Intro2" type="vxml3">
+ <param name="skinpath" expr="skinpath"/>
+ </invoke>
+ <transition event="success" target="EvalDeal"/>
+ </state>
+
+ <state id="EvalDeal">
+ <onenter>
+ <script>enterEvalDeal();</script>
+ </onenter>
+ <invoke src="dialog.vxml#EvalDeal" type="vxml3">
+ <param name="skinpath" expr="skinpath"/>
+ <param name="playercard1" expr="playercard1"/>
+ <param name="playercard2" expr="playercard2"/>
+ <param name="playertotal" expr="blackjack.GetTotalOf('caller').toString()"/>
+ <param name="dealercardshowing" expr="dealercardshowing"/>
+ </invoke>
+ <transition event="success" target="AskHit"/>
+ </state>
+
+ <state id="AskHit">
+ <invoke src="dialog.vxml#AskHit" type="vxml3">
+ <param name="skinpath" expr="skinpath"/>
+ <finalize>
+ <script>finalizeAskHit();</script>
+ </finalize>
+ </invoke>
+ <transition event="hit" target="PlayNewCard"/>
+ <transition event="stand" target="PlayDone"/>
+ </state>
+
+ <state id="PlayNewCard">
+ <invoke src="dialog.vxml#PlayNewCard" type="vxml3">
+ <param name="skinpath" expr="skinpath"/>
+ <param name="playernewcard" expr="playernewcard"/>
+ <param name="playertotal" expr="blackjack.GetTotalOf('caller').toString()"/>
+ </invoke>
+ <transition event="success" cond="blackjack.GetTotalOf('caller') &gt;= 21" target="PlayDone"/>
+ <transition event="success" target="AskHit"/> <!-- less than 21 -->
+ </state>
+
+ <state id="PlayDone">
+ <onenter>
+ <script>enterPlayDone();</script>
+ </onenter>
+ <invoke src="dialog.vxml#PlayDone" type="vxml3">
+ <param name="skinpath" expr="skinpath"/>
+ <param name="gameresult" expr="blackjack.GetGameResult()"/>
+ <param name="dealertotal" expr="blackjack.GetTotalOf('dealer').toString()"/>
+ </invoke>
+ <transition event="playagain" target="Intro2"/>
+ <transition event="quit" target="_home"/>
+ </state>
+
+ <state id="NewDealer">
+ <onenter>
+ <script>enterNewDealer();</script>
+ </onenter>
+ <invoke src="dialog.vxml#Dummy" type="vxml3"/>
+ <transition event="success" target="Welcome"/>
+ </state>
+ </state>
+</scxml>
diff --git a/test/samples/w3c/Main.scxml b/test/samples/w3c/Main.scxml
new file mode 100644
index 0000000..4c03631
--- /dev/null
+++ b/test/samples/w3c/Main.scxml
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- A wrapper state that contains all other states in this file
+- it represents the complete state machine -->
+<scxml
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ version="1.0"
+ initial="Main"
+ datamodel="ecmascript">
+ <state id="Main">
+ <!-- its initial state is Test1 -->
+ <initial>
+ <transition target="Test1"/>
+ </initial>
+
+ <!-- Really simple state showing the basic syntax. -->
+ <state id="Test1">
+ <initial>
+ <transition target="Test1Sub1"/>
+ </initial>
+ <!-- Runs before we go into the substate -->
+ <onentry>
+ <log expr="'Inside Test1'"/>
+ </onentry>
+
+ <!-- Here is our first substate -->
+ <state id="Test1Sub1">
+ <onentry>
+ <log expr="'Inside Test1Sub1.'"/>
+ </onentry>
+ <onexit>
+ <log expr="'Leaving Test1Sub1'"/>
+ </onexit>
+ <!-- Go to Sub2 on Event1 -->
+ <transition event="Event1" target="Test1Sub2"/>
+ </state>
+
+ <!-- Here is the second substate
+ It is final, so Test1 is done when we get here -->
+ <final id="Test1Sub2"/>
+
+ <!-- We get this event when we reach Test1Sub2. -->
+ <transition event="Test1.done" target="Test2"/>
+
+ <!-- We run this on the way out of Test1 -->
+ <onexit>
+ <log expr="'Leaving Test1...'"/>
+ </onexit>
+ </state>
+
+ <state id="Test2">
+ <initial>
+ <transition target="Test2Sub1"/>
+ </initial>
+
+ <!-- This time we reference a state
+ defined in an external file. -->
+ <xi:include href="Test2Sub1.xml" parse="text"/>
+
+ <final id="Test2Sub2"/>
+
+ <!-- Test2Sub2 is defined as final, so this
+ event is generated when we reach it -->
+ <transition event="done.state.Test2" next="Test3"/>
+ </state>
+
+ <state id="Test3">
+ <initial>
+ <transition target="Test3Sub1"/>
+ </initial>
+
+ <state id="Test3Sub1">
+ <onentry>
+ <log expr="'Inside Test3Sub1...'"/>
+ <!-- Send our self an event in 5s -->
+ <send event="'Timer'" delay="'5s'"/>
+ </onentry>
+ <!-- Transition on to Test4.
+ This will exit both us and our parent. -->
+ <transition event="Timer" target="Test4"/>
+ <onexit>
+ <log expr="'Leaving Test3Sub1...'"/>
+ </onexit>
+ </state>
+
+ <onexit>
+ <log expr="'Leaving Test3...'"/>
+ </onexit>
+ </state>
+
+ <state id="Test4">
+ <onentry>
+ <log expr="'Inside Test4...'"/>
+ </onentry>
+ <initial>
+ <transition target="Test4Sub1"/>
+ </initial>
+
+ <state id="Test4Sub1">
+ <onexit>
+ <log expr="'Leaving Test4Sub1...'"/>
+ </onexit>
+ <!-- This transition causes the state to exit immediately
+ after entering Test4Sub1. The transition has no event
+ or guard so it is always active -->
+ <transition target="Test5"/>
+ </state>
+ </state>
+
+ <state id="Test5">
+ <onentry>
+ <log expr="'Inside Test5...'"/>
+ </onentry>
+ <initial>
+ <transition target="Test5P"/>
+ </initial>
+
+ <!-- Fire off parallel states. In a more realistic example
+ the parallel substates Test5PSub1 and Test5PSub2 would themselves
+ have substates and would do some real work before transitioning to final substates -->
+ <parallel id="Test5P">
+ <state id="Test5PSub1" initial="Test5PSub1Final">
+ <final id="Test5PSub1Final"/>
+ </state>
+ <state id="Test5PSub2" initial="Test5PSub2Final">
+ <final id="Test5PSub2Final"/>
+ </state>
+ <onexit>
+ <log expr="'all parallel states done'"/>
+ </onexit>
+ </parallel>
+
+ <!-- The parallel states immediately transition to final substates,
+ so this event is generated immediately. -->
+ <transition event="done.state.Test5P" target="Test6"/>
+ </state>
+
+ <!--
+ - This state shows invocation of an external component.
+ - We will use CCXML + VoiceXML actions as an example
+ - as it is a good smoke test to show how it all
+ - fits together.
+ - Note: In a real app you would likely
+ - split this over several states but we
+ - are trying to keep it simple here.
+ -->
+ <state id="Test6"
+ xmlns:ccxml="http://www.w3.org/2002/09/ccxml"
+ xmlns:v3="http://www.w3.org/2005/07/vxml3">
+ <datamodel>
+ <data name="ccxmlid" expr="32459"/>
+ <date name="v3id" expr="17620"/>
+ <data name="dest" expr="'tel:+18315552020'"/>
+ <data name="src" expr="'helloworld2.vxml'"/>
+ <data name="id" expr="'HelloWorld'"/>
+ </datamodel>
+
+ <onentry>
+ <!-- Use <send> a message to a CCXML Processor asking it to run createcall -->
+ <send target="ccxmlid" type="basichttp" event="ccxml:createcall" namelist="dest"/>
+ </onentry>
+
+ <transition event="ccxml:connection.connected">
+ <!-- Here as a platform-specific extension we use example V3
+ Custom Action Elements instead of send. The implementation of this logic
+ would be platform-dependent. -->
+ <v3:form id="HelloWorld">
+ <v3:block><v3:prompt>Hello World!</v3:prompt></v3:block>
+ </v3:form>
+ </transition>
+
+ <transition event="v3:HelloWorld.done">
+ <!-- Here we are using the low level <send>
+ element to run a v3 form. Note that the event "v3:HelloWorld.done"
+ is assumed either to be set/sent explicitly by the v3:form code or
+ implicitly by some process outside of the v3:form -->
+ <send target="v3id" type="basichttp" event="v3:formstart" namelist="src id"/>
+ </transition>
+
+ <transition event="v3:HelloWorld2.done">
+ <!-- we use _event.data to access data in the event we're processing.
+ Again we assume the v3:HelloWorld2.done is set/sent from outside
+ this document -->
+ <ccxml:disconnect connectionid="_event.data.connectionid"/>
+ </transition>
+
+ <transition event="ccxml:connection.disconnected" target="Done"/>
+
+ <transition event="send.failed" target="Done">
+ <!-- If we get an error event we move to the Done state that
+ is a final state. -->
+ <log expr="'Sending to and External component failed'"/>
+ </transition>
+
+ <onexit>
+ <log expr="'Finished with external component'"/>
+ </onexit>
+ </state>
+
+ <!-- This final state is an immediate child of Main
+ - when we get here, Main.done is generated. -->
+ <final id="Done"/>
+ <!-- End of Main > -->
+ </state>
+</scxml> \ No newline at end of file
diff --git a/test/samples/w3c/Test2Sub1.xml b/test/samples/w3c/Test2Sub1.xml
new file mode 100644
index 0000000..6ab7b98
--- /dev/null
+++ b/test/samples/w3c/Test2Sub1.xml
@@ -0,0 +1,9 @@
+<!-- This is an example substate defined in
+- an external file and included by Main.scxml.
+-->
+<state id="Test2Sub1">
+<onentry>
+ <log expr="'Inside Test2Sub1'"/>
+</onentry>
+<transition event="Event2" target="Test2Sub2"/>
+</state>
diff --git a/test/samples/w3c/TrafficReport.scxml b/test/samples/w3c/TrafficReport.scxml
new file mode 100644
index 0000000..09e2e93
--- /dev/null
+++ b/test/samples/w3c/TrafficReport.scxml
@@ -0,0 +1,88 @@
+<?xml version="1.0"?>
+<?access-control allow="*"?>
+<!-- A comment! -->
+<scxml version="1.0" initial="Intro" datamodel="ecmascript">
+ <state id="Intro">
+ <invoke src="dialog.vxml#Intro" type="vxml2"/>
+ <transition event="success" cond="sessionChrome.playAds" target="PlayAds"/>
+ <transition event="success" cond="!sessionChrome.playAds &amp;&amp; ANIQuality"
+ target="ShouldGoBack"/>
+ <transition event="success" cond="!sessionChrome.playAds &amp;&amp; !ANIQuality"
+ target="StartOver"/>
+ </state>
+
+ <state id="PlayAds">
+ <invoke src="dialog.vxml#PlayAds" type="vxml2"/>
+ <transition event="success" cond="ANIQuality" target="ShouldGoBack"/>
+ <transition event="success" cond="!ANIQuality" target="StartOver"/>
+ </state>
+
+ <state id="StartOver">
+ <onentry>
+ <script>enterStartOver();</script>
+ </onentry>
+ <invoke src="dialog.vxml#StartOver" type="vxml2">
+ <param name="gotItFromANI" expr="gotItFromANI"/>
+ <finalize>
+ <script>finalizeStartOver();</script>
+ </finalize>
+ </invoke>
+ <transition event="success" target="ShouldGoBack"/>
+ <transition event="doOver" target="StartOver"/>
+ <transition event="restart" target="Intro"/> <!-- bail out to caller -->
+ </state>
+
+ <state id="ShouldGoBack">
+ <invoke src="dialog.vxml#ShouldGoBack" type="vxml2">
+ <param name="cityState" expr="cityState"/>
+ <param name="gotItFromANI" expr="gotItFromANI"/>
+ <finalize>
+ <script>finalizeShouldGoBack();</script>
+ </finalize>
+ </invoke>
+ <transition event="highWay" target="HighwayReport"/>
+ <transition event="go_back" target="StartOver"/>
+ <transition event="doOver" target="ShouldGoBack"/>
+ <transition event="restart" target="Intro"/>
+ </state>
+
+ <state id="HighwayReport">
+ <invoke src="dialog.vxml#HighwayReport" type="vxml2">
+ <param name="cityState" expr="cityState"/>
+ <param name="gotItFromANI" expr="gotItFromANI"/>
+ <param name="playHRPrompt" expr="playHRPrompt"/>
+ <param name="metroArea" expr="metroArea"/>
+ <finalize>
+ <script>finalizeHighwayReport();</script>
+ </finalize>
+ </invoke>
+ <transition event="highway" target="PlayHighway"/>
+ <transition event="go_back" target="StartOver"/>
+ <transition event="doOver" target="HighwayReport"/>
+ <transition event="fullreport" target="FullReport"/>
+ <transition event="restart" target="Intro"/>
+ </state>
+
+ <state id="FullReport">
+ <invoke src="dialog.vxml#FullReport" type="vxml2">
+ <param name="cityState" expr="cityState"/>
+ <param name="metroArea" expr="metroArea"/>
+ <finalize>
+ <script>finalizeFullReport();</script>
+ </finalize>
+ </invoke>
+ <transition event="go_back" target="HighwayReport"/>
+ <transition event="new_city" target="StartOver"/>
+ </state>
+
+ <state id="PlayHighway">
+ <invoke src="dialog.vxml#PlayHighway" type="vxml2">
+ <param name="cityState" expr="cityState"/>
+ <param name="curHighway" expr="curHighway"/>
+ <finalize>
+ <script>finalizePlayHighway();</script>
+ </finalize>
+ </invoke>
+ <transition event="go_back" target="HighwayReport"/>
+ </state>
+</scxml>
diff --git a/test/samples/w3c/calc.scxml b/test/samples/w3c/calc.scxml
new file mode 100644
index 0000000..e759b45
--- /dev/null
+++ b/test/samples/w3c/calc.scxml
@@ -0,0 +1,158 @@
+<?xml version="1.0" ?>
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"
+ initial="on" datamodel="ecmascript" name="calc">
+ <datamodel>
+ <data id="long_expr" />
+ <data id="short_expr" expr="0" />
+ <data id="res" />
+ </datamodel>
+ <state id="wrapper" initial="on">
+ <state id="on" initial="ready">
+ <onentry>
+ <send event="DISPLAY.UPDATE" />
+ </onentry>
+ <state id="ready" initial="begin">
+ <state id="begin">
+ <transition event="OPER.MINUS" target="negated1" />
+ <onentry>
+ <send event="DISPLAY.UPDATE" />
+ </onentry>
+ </state>
+ <state id="result">
+ </state>
+ <transition event="OPER" target="opEntered" />
+ <transition event="DIGIT.0" target="zero1">
+ <assign location="short_expr" expr="''" />
+ </transition>
+ <transition event="DIGIT" target="int1">
+ <assign location="short_expr" expr="''" />
+ </transition>
+ <transition event="POINT" target="frac1">
+ <assign location="short_expr" expr="''" />
+ </transition>
+ </state>
+ <state id="negated1">
+ <onentry>
+ <assign location="short_expr" expr="'-'" />
+ <send event="DISPLAY.UPDATE" />
+ </onentry>
+ <transition event="DIGIT.0" target="zero1" />
+ <transition event="DIGIT" target="int1" />
+ <transition event="POINT" target="frac1" />
+ </state>
+ <state id="operand1">
+ <state id="zero1">
+ <transition event="DIGIT" cond="_event.name != 'DIGIT.0'" target="int1" />
+ <transition event="POINT" target="frac1" />
+ </state>
+ <state id="int1">
+ <transition event="POINT" target="frac1" />
+ <transition event="DIGIT">
+ <assign location="short_expr" expr="short_expr+_event.name.substr(_event.name.lastIndexOf('.')+1)" />
+ <send event="DISPLAY.UPDATE" />
+ </transition>
+ <onentry>
+ <assign location="short_expr" expr="short_expr+_event.name.substr(_event.name.lastIndexOf('.')+1)" />
+ <send event="DISPLAY.UPDATE" />
+ </onentry>
+ </state>
+ <state id="frac1">
+ <onentry>
+ <assign location="short_expr" expr="short_expr+'.'" />
+ <send event="DISPLAY.UPDATE" />
+ </onentry>
+ <transition event="DIGIT">
+ <assign location="short_expr" expr="short_expr+_event.name.substr(_event.name.lastIndexOf('.')+1)" />
+ <send event="DISPLAY.UPDATE" />
+ </transition>
+ </state>
+ <transition event="OPER" target="opEntered" />
+ </state>
+ <state id="opEntered">
+ <transition event="OPER.MINUS" target="negated2" />
+ <transition event="POINT" target="frac2" />
+ <transition event="DIGIT.0" target="zero2" />
+ <transition event="DIGIT" target="int2" />
+ <onentry>
+ <raise event="CALC.SUB" />
+ <send target="_internal" event="OP.INSERT">
+ <param name="operator" expr="_event.name" />
+ </send>
+ </onentry>
+ </state>
+ <state id="negated2">
+ <onentry>
+ <assign location="short_expr" expr="'-'" />
+ <send event="DISPLAY.UPDATE" />
+ </onentry>
+ <transition event="DIGIT.0" target="zero2" />
+ <transition event="DIGIT" target="int2" />
+ <transition event="POINT" target="frac2" />
+ </state>
+ <state id="operand2">
+ <state id="zero2">
+ <transition event="DIGIT" cond="_event.name != 'DIGIT.0'" target="int2" />
+ <transition event="POINT" target="frac2" />
+ </state>
+ <state id="int2">
+ <transition event="DIGIT">
+ <assign location="short_expr" expr="short_expr+_event.name.substr(_event.name.lastIndexOf('.')+1)" />
+ <send event="DISPLAY.UPDATE" />
+ </transition>
+ <onentry>
+ <assign location="short_expr" expr="short_expr+_event.name.substr(_event.name.lastIndexOf('.')+1)" />
+ <send event="DISPLAY.UPDATE" />
+ </onentry>
+ <transition event="POINT" target="frac2" />
+ </state>
+ <state id="frac2">
+ <onentry>
+ <assign location="short_expr" expr="short_expr +'.'" />
+ <send event="DISPLAY.UPDATE" />
+ </onentry>
+ <transition event="DIGIT">
+ <assign location="short_expr" expr="short_expr +_event.name.substr(_event.name.lastIndexOf('.')+1)" />
+ <send event="DISPLAY.UPDATE" />
+ </transition>
+ </state>
+ <transition event="OPER" target="opEntered">
+ <raise event="CALC.SUB" />
+ <raise event="OP.INSERT" />
+ </transition>
+ <transition event="EQUALS" target="result">
+ <raise event="CALC.SUB" />
+ <raise event="CALC.DO" />
+ </transition>
+ </state>
+ <transition event="C" target="on" />
+ </state>
+ <transition event="CALC.DO">
+ <assign location="short_expr" expr="''+ res" />
+ <assign location="long_expr" expr="''" />
+ <assign location="res" expr="0" />
+ </transition>
+ <transition event="CALC.SUB">
+ <if cond="short_expr!=''">
+ <assign location="long_expr" expr="long_expr+'('+short_expr+')'" />
+ </if>
+ <assign location="res" expr="eval(long_expr)" />
+ <assign location="short_expr" expr="''" />
+ <send event="DISPLAY.UPDATE" />
+ </transition>
+ <transition event="DISPLAY.UPDATE">
+ <log level="0" label="'result'" expr=".short_expr==''?res:short_expr" />
+ </transition>
+ <transition event="OP.INSERT">
+ <log level="0" expr="_event.data[0]" />
+ <if cond="_event.data[0] == 'OPER.PLUS'">
+ <assign location="long_expr" expr="long_expr+'+'" />
+ <elseif cond="_event.data[0]=='OPER.MINUS'" />
+ <assign location="long_expr" expr="long_expr+'-'" />
+ <elseif cond="_event.data[0]=='OPER.STAR'" />
+ <assign location="long_expr" expr="long_expr+'*'" />
+ <elseif cond="_event.data[0]=='OPER.DIV'" />
+ <assign location="long_expr" expr="long_expr+'/'" />
+ </if>
+ </transition>
+ </state>
+</scxml>
diff --git a/test/samples/w3c/edit-profile-config.scxml b/test/samples/w3c/edit-profile-config.scxml
new file mode 100644
index 0000000..2f8753e
--- /dev/null
+++ b/test/samples/w3c/edit-profile-config.scxml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Dialog definitions for Shale Use Cases Example Web Application
+ written out as SCXML to demonstrate use of Commons SCXML as one
+ of Shale's Dialog Manager implementations.
+ For details, see: http://shale.apache.org/shale-dialog-scxml/
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:my="http://scxml.example.com/"
+ version="1.0" initial="edit" datamodel="el">
+
+ <state id="edit">
+ <initial>
+ <transition target="setup"/>
+ </initial>
+
+ <!-- global transitions (within state "edit") -->
+ <transition event="faces.outcome" cond="${outcome eq 'cancel'}" target="cancel"/>
+ <transition event="faces.outcome" cond="${outcome eq 'finish'}" target="finish"/>
+
+ <state id="setup">
+ <onentry>
+ <my:var name="setupOutcome" expr="#{profile$edit.setup}" />
+ </onentry>
+ <transition cond="${setupOutcome eq 'success'}" target="page1"/>
+ </state>
+
+ <state id="page1">
+ <transition event="faces.outcome" cond="${outcome eq 'next'}" target="page2"/>
+ </state>
+
+ <state id="page2">
+
+ <transition event="faces.outcome" cond="${outcome eq 'previous'}" target="page1"/>
+ <transition event="faces.outcome" cond="${outcome eq 'next'}" target="page3"/>
+
+ </state>
+
+ <state id="page3">
+ <transition event="faces.outcome" cond="${outcome eq 'previous'}" target="page2"/>
+ <transition event="faces.outcome" cond="${outcome eq 'next'}" target="editExit"/>
+ </state>
+
+ </state>
+
+ <state id="cancel">
+
+ <onentry>
+ <my:var name="cancelOutcome" expr="#{profile$edit.cancel}" />
+ </onentry>
+ <transition cond="${cancelOutcome eq 'success'}" target="editExit">
+ <my:var name="outcome" expr="cancel"/>
+ </transition>
+ </state>
+
+ <state id="finish">
+
+ <onentry>
+ <my:var name="finishOutcome" expr="#{profile$edit.finish}" />
+ </onentry>
+
+ <transition cond="${finishOutcome eq 'username'}" target="page1"/>
+ <transition cond="${finishOutcome eq 'password'}" target="page1"/>
+ <transition cond="${finishOutcome eq 'success'}" target="editExit">
+ <my:var name="outcome" expr="success"/>
+ </transition>
+ </state>
+
+ <final id="editExit"/>
+
+</scxml>
diff --git a/test/samples/w3c/log-on-config.scxml b/test/samples/w3c/log-on-config.scxml
new file mode 100644
index 0000000..01f45d6
--- /dev/null
+++ b/test/samples/w3c/log-on-config.scxml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Dialog definitions for Shale Use Cases Example Web Application
+ written out as SCXML to demonstrate use of Commons SCXML as one
+ of Shale's Dialog Manager implementations.
+ For details, see: http://shale.apache.org/shale-dialog-scxml/
+-->
+<scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:my="http://scxml.example.com/"
+ version="1.0" initial="checkCookie" datamodel="el" >
+
+ <state id="checkCookie">
+ <onentry>
+ <my:var name="cookieOutcome" expr="#{profile$logon.check}" />
+ </onentry>
+ <transition cond="${cookieOutcome eq 'authenticated'}" target="exit"/>
+ <transition cond="${cookieOutcome eq 'unauthenticated'}" target="logon"/>
+
+ </state>
+
+ <state id="logon">
+ <transition event="faces.outcome" cond="${outcome eq 'authenticated'}" target="exit"/>
+ <transition event="faces.outcome" cond="${outcome eq 'create'}" target="createProfile"/>
+ </state>
+
+
+ <state id="createProfile" src="edit-profile-config.xml" >
+ <transition event="createProfile.done" cond="${outcome eq 'success' or outcome eq 'cancel'}" target="exit"/>
+ </state>
+
+ <final id="exit"/>
+
+</scxml>
diff --git a/test/samples/w3c/microwave-01.scxml b/test/samples/w3c/microwave-01.scxml
new file mode 100644
index 0000000..71e2f98
--- /dev/null
+++ b/test/samples/w3c/microwave-01.scxml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ datamodel="ecmascript"
+ initial="off">
+
+ <!-- trivial 5 second microwave oven example -->
+ <datamodel>
+ <data id="cook_time" expr="5"/>
+ <data id="door_closed" expr="true"/>
+ <data id="timer" expr="0"/>
+ </datamodel>
+
+ <state id="off">
+ <!-- off state -->
+ <transition event="turn.on" target="on"/>
+ </state>
+
+ <state id="on">
+ <initial>
+ <transition target="idle"/>
+ </initial>
+ <!-- on/pause state -->
+
+ <transition event="turn.off" target="off"/>
+ <transition cond="timer &gt;= cook_time" target="off"/>
+
+ <state id="idle">
+ <!-- default immediate transition if door is shut -->
+ <transition cond="door_closed" target="cooking"/>
+ <transition event="door.close" target="cooking">
+ <assign location="door_closed" expr="true"/>
+ <!-- start cooking -->
+ </transition>
+ </state>
+
+ <state id="cooking">
+ <transition event="door.open" target="idle">
+ <assign location="door_closed" expr="false"/>
+ </transition>
+
+ <!-- a 'time' event is seen once a second -->
+ <transition event="time">
+ <assign location="timer" expr="timer + 1"/>
+ </transition>
+ </state>
+
+ </state>
+
+</scxml>
diff --git a/test/samples/w3c/microwave-02.scxml b/test/samples/w3c/microwave-02.scxml
new file mode 100644
index 0000000..a96f1fd
--- /dev/null
+++ b/test/samples/w3c/microwave-02.scxml
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ datamodel="ecmascript"
+ initial="oven">
+
+ <!-- trivial 5 second microwave oven example -->
+ <!-- using parallel and In() predicate -->
+ <datamodel>
+ <data id="cook_time" expr="5"/>
+ <data id="door_closed" expr="true"/>
+ <data id="timer" expr="0"/>
+ </datamodel>
+
+ <parallel id="oven">
+
+ <!-- this region tracks the microwave state and timer -->
+ <state id="engine">
+ <transition target="off"/>
+
+ <state id="off">
+ <!-- off state -->
+ <transition event="turn.on" target="on"/>
+ </state>
+
+ <state id="on">
+ <transition target="idle"/>
+ <!-- on/pause state -->
+
+ <transition event="turn.off" target="off"/>
+ <transition cond="timer &gt;= cook_time" target="off"/>
+
+ <state id="idle">
+ <transition cond="In('closed')" target="cooking"/>
+ </state>
+
+ <state id="cooking">
+ <transition cond="In('open')" target="idle"/>
+
+ <!-- a 'time' event is seen once a second -->
+ <transition event="time">
+ <assign location="timer" expr="timer + 1"/>
+ </transition>
+ </state>
+ </state>
+ </state>
+
+ <!-- this region tracks the microwave door state -->
+ <state id="door">
+ <initial>
+ <transition target="closed"/>
+ </initial>
+ <state id="closed">
+ <transition event="door.open" target="open"/>
+ </state>
+ <state id="open">
+ <transition event="door.close" target="closed"/>
+ </state>
+ </state>
+
+ </parallel>
+
+</scxml>
diff --git a/test/samples/w3c/simple.xml b/test/samples/w3c/simple.xml
new file mode 100644
index 0000000..d3badc8
--- /dev/null
+++ b/test/samples/w3c/simple.xml
@@ -0,0 +1,9 @@
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ initial="Main"
+ datamodel="ecmascript">
+ <state />
+ <state />
+ <state />
+ <state />
+</scxml> \ No newline at end of file
diff --git a/test/schema/scxml-message.xsd b/test/schema/scxml-message.xsd
new file mode 100644
index 0000000..de4b4b8
--- /dev/null
+++ b/test/schema/scxml-message.xsd
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ XML Schema for sending messages to SCXML processors.
+-->
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://www.w3.org/2005/07/scxml"
+ xmlns="http://www.w3.org/2005/07/scxml"
+ elementFormDefault="qualified">
+
+ <xsd:annotation>
+ <xsd:documentation xml:lang="en">
+ XML Schema for sending messages to SCXML processors.
+ Version 1.0
+ </xsd:documentation>
+ <xsd:documentation source="scxml-copyright.xsd" />
+ </xsd:annotation>
+
+ <xsd:attributeGroup name="scxmlmessage.extra.attribs">
+ <xsd:annotation>
+ <xsd:documentation>
+ Group allowing attributes from other namespaces
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:anyAttribute namespace="##other" processContents="lax" />
+ </xsd:attributeGroup>
+
+ <xsd:attributeGroup name="scxmlmessage.message.attlist">
+ <xsd:attribute name="version" type="xsd:string" fixed="1.0" use="required" />
+ <xsd:attribute name="source" type="xsd:anyURI" use="required" />
+ <xsd:attribute name="target" type="xsd:anyURI" use="required" />
+ <xsd:attribute name="sendid" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ Non SCXML senders are not required to specify a sendid
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="name" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defaults to "external.event"
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="sourcetype" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defaults to "scxml"
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attributeGroup ref="scxmlmessage.extra.attribs" />
+ </xsd:attributeGroup>
+
+ <xsd:group name="scxmlmessage.message.content">
+ <xsd:sequence>
+ <xsd:element ref="payload" minOccurs="1" maxOccurs="1" />
+ </xsd:sequence>
+ </xsd:group>
+
+ <xsd:complexType name="scxmlmessage.message.type">
+ <xsd:group ref="scxmlmessage.message.content" />
+ <xsd:attributeGroup ref="scxmlmessage.message.attlist" />
+ </xsd:complexType>
+
+ <xsd:element name="message" type="scxmlmessage.message.type" />
+
+ <xsd:attributeGroup name="scxmlmessage.payload.attlist">
+ <xsd:attributeGroup ref="scxmlmessage.extra.attribs" />
+ <xsd:attribute name="contenttype" type="xsd:string" use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ The mime type of the child content.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:attributeGroup>
+
+ <xsd:group name="scxmlmessage.payload.content">
+ <xsd:choice>
+ <xsd:sequence>
+ <xsd:element ref="property" minOccurs="0"
+ maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:sequence>
+ <xsd:any namespace="##other" minOccurs="1"
+ maxOccurs="unbounded" processContents="lax" />
+ </xsd:sequence>
+ </xsd:choice>
+ </xsd:group>
+
+ <xsd:complexType name="scxmlmessage.payload.type">
+ <xsd:group ref="scxmlmessage.payload.content" />
+ <xsd:attributeGroup ref="scxmlmessage.payload.attlist" />
+ </xsd:complexType>
+
+ <xsd:element name="payload" type="scxmlmessage.payload.type" />
+
+ <xsd:attributeGroup name="scxmlmessage.property.attlist">
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ <xsd:attributeGroup ref="scxmlmessage.extra.attribs" />
+ </xsd:attributeGroup>
+
+ <xsd:group name="scxmlmessage.property.content">
+ <xsd:sequence>
+ <xsd:element ref="hint" minOccurs="0"
+ maxOccurs="1" />
+ <xsd:any namespace="##other" minOccurs="0"
+ maxOccurs="unbounded" processContents="skip" />
+ </xsd:sequence>
+ </xsd:group>
+
+ <xsd:complexType name="scxmlmessage.property.type" mixed="true">
+ <xsd:group ref="scxmlmessage.property.content" />
+ <xsd:attributeGroup ref="scxmlmessage.property.attlist" />
+ </xsd:complexType>
+
+ <xsd:element name="property" type="scxmlmessage.property.type" />
+
+ <xsd:element name="hint" type="xsd:string" />
+
+</xsd:schema>
diff --git a/test/schema/scxml.xsd b/test/schema/scxml.xsd
new file mode 100644
index 0000000..ebc0654
--- /dev/null
+++ b/test/schema/scxml.xsd
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://www.w3.org/2005/07/scxml"
+ xmlns="http://www.w3.org/2005/07/scxml"
+ elementFormDefault="qualified">
+
+ <xsd:annotation>
+ <xsd:documentation>
+ This is the XML Schema driver for SCXML 1.0.
+ Please use this namespace for SCXML 1.0 elements:
+
+ "http://www.w3.org/2005/07/scxml"
+
+ </xsd:documentation>
+ <xsd:documentation source="scxml-copyright.xsd"/>
+ </xsd:annotation>
+ <xsd:annotation>
+ <xsd:documentation>
+ This is the XML Schema driver file for SCXML 1.0.
+
+ This schema:
+ + sets the namespace for SCXML 1.0
+ + imports external schemas (xml.xsd)
+ + imports SCXML common datatypes, attributes and content models
+ + imports modular schemas
+
+ SCXML 1.0 includes:
+ + SCXML core constructs
+ + SCXML executable content
+ + SCXML data model and manipulation
+ + SCXML external communications
+
+ This schema is permissive such that it accomodates all
+ datamodels, but validating documents may contain markup that
+ is ignored in certain datamodels.
+ </xsd:documentation>
+ </xsd:annotation>
+
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd">
+ <xsd:annotation>
+ <xsd:documentation>
+ This import brings in the XML namespace attributes
+ The XML attributes are used by various modules.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:import>
+
+ <xsd:include schemaLocation="scxml-attribs.xsd">
+ <xsd:annotation>
+ <xsd:documentation>
+ This includes brings in the common attributes for SCXML.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:include>
+
+ <xsd:include schemaLocation="scxml-contentmodels.xsd">
+ <xsd:annotation>
+ <xsd:documentation>
+ This includes the common content models.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:include>
+
+ <xsd:include schemaLocation="scxml-datatypes.xsd">
+ <xsd:annotation>
+ <xsd:documentation>
+ This includes brings in the common data types for SCXML.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:include>
+
+ <xsd:redefine schemaLocation="scxml-module-data.xsd">
+ <xsd:annotation>
+ <xsd:documentation>
+ This imports the data module for SCXML and redefines the following.
+ [1] Redefines assign attribute group to allow type and attr
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:attributeGroup name="scxml.assign.attlist">
+ <xsd:attributeGroup ref="scxml.assign.attlist"/>
+ <xsd:attribute name="type" type="AssignType.datatype" default="replacechildren"/>
+ <xsd:attribute name="attr" type="xsd:NMTOKEN"/>
+ </xsd:attributeGroup>
+ </xsd:redefine>
+
+ <xsd:include schemaLocation="scxml-module-script.xsd">
+ <xsd:annotation>
+ <xsd:documentation>
+ This includes the script module for SCXML.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:include>
+
+ <xsd:redefine schemaLocation="scxml-module-external.xsd">
+ <xsd:annotation>
+ <xsd:documentation>
+ This imports the external module for SCXML and redefines the following.
+ [1] Redefines send and invoke mix group to allow
+ param
+ [2] Redefines finalize mix group to allow:
+ executable content
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:group name="scxml.send.mix">
+ <xsd:choice>
+ <xsd:group ref="scxml.send.mix"/>
+ <xsd:element ref="param" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:choice>
+ </xsd:group>
+ <xsd:group name="scxml.invoke.mix">
+ <xsd:choice>
+ <xsd:group ref="scxml.invoke.mix"/>
+ <xsd:element ref="param" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:choice>
+ </xsd:group>
+ <xsd:group name="scxml.finalize.mix">
+ <xsd:choice>
+ <xsd:group ref="scxml.finalize.mix"/>
+ <xsd:group ref="scxml.core.executablecontent"/>
+ </xsd:choice>
+ </xsd:group>
+ </xsd:redefine>
+
+ <xsd:redefine schemaLocation="scxml-module-core.xsd">
+ <xsd:annotation>
+ <xsd:documentation>
+ This imports the core module for SCXML and redefines the following.
+ [1] Redefines executable content to allow
+ send, assign, validate, cancel and script elements
+ [2] Redefines state and parallel mix group to allow
+ invoke and datamodel
+ [3] Redefines scxml group to allow
+ datamodel and script
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:group name="scxml.core.executablecontent">
+ <xsd:choice>
+ <xsd:group ref="scxml.core.executablecontent"/>
+ <xsd:element ref="send"/>
+ <xsd:element ref="assign"/>
+ <xsd:element ref="script"/>
+ <xsd:element ref="validate"/>
+ <xsd:element ref="cancel"/>
+ </xsd:choice>
+ </xsd:group>
+ <xsd:group name="scxml.scxml.mix">
+ <xsd:choice>
+ <xsd:group ref="scxml.scxml.mix"/>
+ <xsd:element ref="datamodel" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element ref="script" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:choice>
+ </xsd:group>
+ <xsd:group name="scxml.state.mix">
+ <xsd:choice>
+ <xsd:group ref="scxml.state.mix"/>
+ <xsd:element ref="datamodel" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element ref="invoke" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:choice>
+ </xsd:group>
+ <xsd:group name="scxml.parallel.mix">
+ <xsd:choice>
+ <xsd:group ref="scxml.parallel.mix"/>
+ <xsd:element ref="datamodel" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element ref="invoke" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:choice>
+ </xsd:group>
+ <xsd:group name="scxml.donedata.content">
+ <xsd:choice>
+ <xsd:group ref="scxml.donedata.content"/>
+ <xsd:element ref="param" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:choice>
+ </xsd:group>
+
+ </xsd:redefine>
+
+</xsd:schema>
diff --git a/test/src/test-apache-commons.cpp b/test/src/test-apache-commons.cpp
new file mode 100644
index 0000000..51c275d
--- /dev/null
+++ b/test/src/test-apache-commons.cpp
@@ -0,0 +1,128 @@
+#include "uscxml/Interpreter.h"
+#include <glog/logging.h>
+
+using namespace uscxml;
+using namespace Arabica::DOM;
+using namespace Arabica::XPath;
+
+static std::string path;
+
+bool testEvents1() {
+ LOG(INFO) << "---- testEvent1 ";
+ Interpreter* interpreter = new Interpreter(path + "/eventdata-01.xml");
+ interpreter->start();
+ interpreter->waitForStabilization();
+ assert(interpreter->getConfiguration().size() == 1);
+ assert(Interpreter::isMember(interpreter->getState("state1"), interpreter->getConfiguration()));
+
+ Event eventFoo;
+ eventFoo.name = "event.foo";
+ eventFoo.atom = "3";
+ interpreter->receive(eventFoo);
+ interpreter->waitForStabilization();
+ assert(interpreter->getConfiguration().size() == 1);
+ assert(Interpreter::isMember(interpreter->getState("state3"), interpreter->getConfiguration()));
+
+ Event eventBar;
+ eventBar.name = "event.bar";
+ eventBar.atom = "6";
+ interpreter->receive(eventBar);
+ interpreter->waitForStabilization();
+ assert(interpreter->getConfiguration().size() == 1);
+ assert(Interpreter::isMember(interpreter->getState("state6"), interpreter->getConfiguration()));
+
+ Event eventBaz;
+ eventBaz.name = "event.baz";
+ eventBaz.atom = "7";
+ interpreter->receive(eventBaz);
+
+ delete interpreter;
+ return true;
+}
+
+bool testEvents2() {
+ LOG(INFO) << "---- testEvent2 ";
+ Interpreter* interpreter = new Interpreter(path + "/eventdata-02.xml");
+ interpreter->start();
+ interpreter->waitForStabilization();
+ assert(interpreter->getConfiguration().size() == 1);
+ assert(Interpreter::isMember(interpreter->getState("state0"), interpreter->getConfiguration()));
+
+ Event eventConnAlert;
+ eventConnAlert.name = "connection.alerting";
+ eventConnAlert.atom = "'line2'";
+ interpreter->receive(eventConnAlert);
+ interpreter->waitForStabilization();
+ assert(interpreter->getConfiguration().size() == 1);
+ assert(Interpreter::isMember(interpreter->getState("state2"), interpreter->getConfiguration()));
+
+ Event eventConnAlert2;
+ eventConnAlert2.name = "connection.alerting";
+ eventConnAlert2.compound["line"] = Data(std::string("4"));
+ interpreter->receive(eventConnAlert2);
+
+ delete interpreter;
+ return true;
+}
+
+//bool testEvents3() {
+// LOG(INFO) << "---- testEvent3 ";
+// Interpreter* Interpreter = new Interpreter(path + "/eventdata-03.xml");
+// interpreter->start();
+// interpreter->waitForStabilization();
+// Thread::sleepMs(200);
+// assert(interpreter->getConfiguration().size() == 1);
+// assert(Interpreter::isMember(interpreter->getState("state0"), interpreter->getConfiguration()));
+//
+// Event eventConnAlert;
+// eventConnAlert.name = "connection.alerting";
+// eventConnAlert.atom = "'line2'";
+// interpreter->receive(eventConnAlert);
+// Thread::sleepMs(200);
+// assert(interpreter->getConfiguration().size() == 1);
+// assert(Interpreter::isMember(interpreter->getState("state2"), interpreter->getConfiguration()));
+//
+// Event eventConnAlert2;
+// eventConnAlert2.name = "connection.alerting";
+// eventConnAlert2.compound["line"] = Data(std::string("4"));
+// interpreter->receive(eventConnAlert2);
+// Thread::sleepMs(200);
+// assert(interpreter->getConfiguration().size() == 1);
+// assert(Interpreter::isMember(interpreter->getState("state4"), interpreter->getConfiguration()));
+//
+// delete Interpreter;
+// return true;
+//}
+
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ std::cerr << "Expected path to scxml file from apache commons distribution" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ path = "file://";
+ path += argv[1];
+
+ if (!testEvents1())
+ return EXIT_FAILURE;
+ if (!testEvents2())
+ return EXIT_FAILURE;
+// if (!testEvents3())
+// return EXIT_FAILURE;
+
+//
+// Interpreter* scxmlInterpreter = new Interpreter(path + "/tie-breaker-01.xml");
+// SCXMLRunner* scxmlRun = new SCXMLRunner(scxmlInterpreter);
+// scxmlRun->start();
+//
+// Thread::sleepMs(100);
+// assert(Interpreter::isMember(scxmlinterpreter->getState("ten"), scxmlinterpreter->getConfiguration()));
+//
+// boost::shared_ptr<Event> event = boost::shared_ptr<Event>(new Event());
+// event->name = "ten.done";
+// scxmlinterpreter->receive(event);
+// scxmlRun->join();
+// scxmlinterpreter->receive(event);
+
+} \ No newline at end of file
diff --git a/test/src/test-communication.cpp b/test/src/test-communication.cpp
new file mode 100644
index 0000000..97584b8
--- /dev/null
+++ b/test/src/test-communication.cpp
@@ -0,0 +1,26 @@
+#include "uscxml/Interpreter.h"
+#include <DOM/io/Stream.hpp>
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ std::cerr << "Expected path to test-communication.scxml" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+
+ using namespace uscxml;
+ std::list<Interpreter*> _interpreters;
+
+// Event e;
+// e.compound["foo"] = Data("bar", Data::VERBATIM);
+// e.compound["foo2"] = Data("bar2", Data::VERBATIM);
+// std::cout << e.toDocument() << std::endl;
+
+ for (int i = 0; i < 1; i++) {
+ _interpreters.push_back(new Interpreter(argv[1]));
+ _interpreters.back()->start();
+ }
+
+ tthread::this_thread::sleep_for(tthread::chrono::milliseconds(100000));
+
+} \ No newline at end of file
diff --git a/test/src/test-communication.scxml b/test/src/test-communication.scxml
new file mode 100644
index 0000000..cc3f577
--- /dev/null
+++ b/test/src/test-communication.scxml
@@ -0,0 +1,35 @@
+<scxml datamodel="ecmascript" initial="start" binding="late" name="foo">
+ <state id="start">
+ <datamodel>
+ <data id="foo" expr="'this is the foo data'" />
+ <data id="bar" expr="'this is the bar data'" />
+ </datamodel>
+ <onentry>
+ <log expr="'basichttp listening as ' + _ioprocessors['basichttp']" />
+ <log expr="'Entered step1'" />
+ <log expr="'Sending ourself an event'" />
+ <send targetexpr="_ioprocessors['basichttp']" namelist="foo" type="basichttp" event="transitionToNext">
+ <param name="bar" expr="'b' + 'ar'" />
+ <content>
+<![CDATA[
+This is some content you got there dude!
+]]>
+ </content>
+ </send>
+ </onentry>
+ <transition event="transitionToNext" target="step1" />
+ </state>
+ <state id="step1">
+ <onentry>
+ <log expr="'Entered step1'" />
+ <log expr="'Sending ourself a 2s delayed event'" />
+ <send delay="2s" targetexpr="_ioprocessors['basichttp']" type="basichttp" event="transitionToNext" />
+ </onentry>
+ <transition event="transitionToNext" target="final" />
+ </state>
+ <final id="final">
+ <onentry>
+ <log expr="'Finished!'" />
+ </onentry>
+ </final>
+</scxml> \ No newline at end of file
diff --git a/test/src/test-ecmascript-v8.cpp b/test/src/test-ecmascript-v8.cpp
new file mode 100644
index 0000000..d0b69ba
--- /dev/null
+++ b/test/src/test-ecmascript-v8.cpp
@@ -0,0 +1,44 @@
+#include "uscxml/Interpreter.h"
+#include "uscxml/datamodel/ecmascript/v8/V8DataModel.h"
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ std::cerr << "Expected path to test-ecmascript.scxml" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ using namespace uscxml;
+ using namespace Arabica::DOM;
+ using namespace Arabica::XPath;
+
+// class SCXMLRunner : public Thread {
+// public:
+// SCXMLRunner(Runtime* runtime) : _runtime(runtime) {}
+// void run() {
+// _runtime->interpret();
+// }
+//
+// Runtime* _runtime;
+// };
+
+// boost::shared_ptr<V8DataModel> v8 = boost::static_pointer_cast<V8DataModel>(Factory::create("datamodel:ecmascript", Arabica::DOM::Node<std::string>()));
+// v8->eval("var x = 4;");
+// assert(v8->evalAsBool("x == 4"));
+// assert(!v8->evalAsBool("x == 5"));
+
+ Interpreter* scxml = new Interpreter(argv[1]);
+ scxml->dump();
+// scxml->interpret();
+ scxml->start();
+ scxml->waitForStabilization();
+
+ Event event1;
+ event1.name = "event1";
+ scxml->receive(event1);
+ scxml->waitForStabilization();
+ tthread::this_thread::sleep_for(tthread::chrono::milliseconds(200));
+
+// SCXMLRunner* scxmlRun = new SCXMLRunner(scxmlRuntime);
+// scxmlRun->start();
+
+} \ No newline at end of file
diff --git a/test/src/test-ecmascript.scxml b/test/src/test-ecmascript.scxml
new file mode 100644
index 0000000..aa88f17
--- /dev/null
+++ b/test/src/test-ecmascript.scxml
@@ -0,0 +1,112 @@
+<scxml datamodel="ecmascript" initial="comparison" binding="late">
+ <datamodel>
+ <data id="year" expr="2008" />
+ <data id="CEO" expr="'Mr Big'" />
+ <data id="profitable" />
+ <data id="json">
+ {
+ "id": 1,
+ "name": "Foo",
+ "price": 123,
+ "tags": [ "Bar", "Eek" ],
+ "stock": {
+ "warehouse": 300,
+ "retail": 20,
+ }
+ }
+ </data>
+ </datamodel>
+ <script>
+ var x = 4;
+ var a = ["a", "b", "c"];
+ var b = [10,20,30];
+ </script>
+ <script>
+ var y;
+ if (x > 10) {
+ y = 'true';
+ } else {
+ y = 'false';
+ }
+ </script>
+ <state id="comparison">
+ <onentry>
+ <log expr="'-- Testing comparisons'" />
+ <log expr="'x is ' + x + ', y is ' + y" />
+ </onentry>
+ <transition cond="x &gt;= 2" target="builtin">
+ <log expr="'x is greater or equal to 2'" />
+ </transition>
+ <transition cond="x &lt; 2" target="builtin">
+ <log expr="'x is smaller than 2'" />
+ </transition>
+ </state>
+ <state id="builtin">
+ <onentry>
+ <log expr="'-- Testing built ins'" />
+ <if cond="In('builtin')">
+ <log expr="'We are in state builtin'" />
+ <else>
+ <log expr="'We are not in state builtin'" />
+ </else>
+ </if>
+ </onentry>
+ <transition target="conditionals" />
+ </state>
+ <state id="conditionals">
+ <onentry>
+ <log expr="'-- Testing conditionals'" />
+ <if cond="y == true">
+ <log expr="'x is great and y is'" />
+ <elseif cond="x > 3">
+ <log expr="'x is somewhat great and y is not'" />
+ </elseif>
+ <else>
+ <log expr="'x is great and y is not'" />
+ </else>
+ </if>
+ </onentry>
+ <transition target="foreach" />
+ </state>
+ <state id="foreach">
+ <onentry>
+ <log expr="'-- Testing loops'" />
+ <foreach array="a" item="itemA" index="indexA">
+ <foreach array="b" item="itemB" index="indexB">
+ <log expr="indexA + '.' + indexB + ' = ' + itemA + '.' + itemB" />
+ </foreach>
+ </foreach>
+ </onentry>
+ <transition target="externalEvents" />
+ </state>
+ <state id="externalEvents">
+ <onentry>
+ <log expr="'-- External Events'" />
+ </onentry>
+ <transition target="datamodels" event="event1" cond="_event.name == 'event1'" />
+ </state>
+ <state id="datamodels">
+ <datamodel>
+ <data id="bar" expr="'yeah, bar!'"/>
+ </datamodel>
+ <onentry>
+ <log expr="'-- DataModels'" />
+ <log expr="'year = ' + year" />
+ <log expr="'bar = ' + bar" />
+ <log expr="'json.stock.warehouse = ' + json.stock.warehouse" />
+ </onentry>
+ <transition target="syntaxerror" />
+ </state>
+ <state id="syntaxerror">
+ <onentry>
+ <log expr="'-- Syntax Error'" />
+ <log expr="year = ' + year" />
+ </onentry>
+ <transition event="error.execution" target="final" />
+ </state>
+ <final id="final">
+ <onentry>
+ <log expr="'Finished!'" />
+ </onentry>
+ </final>
+</scxml> \ No newline at end of file
diff --git a/test/src/test-eventdelay.cpp b/test/src/test-eventdelay.cpp
new file mode 100644
index 0000000..6a28e44
--- /dev/null
+++ b/test/src/test-eventdelay.cpp
@@ -0,0 +1,39 @@
+#include "uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h"
+
+int eventCalled = 0;
+
+#include <sstream>
+
+static void callback(void* userData, const std::string eventId) {
+// std::cout << eventId << ": " << (const char*)userData << std::endl;
+ std::cout << eventId << std::endl << std::flush;
+ eventCalled++;
+}
+
+int main(int argc, char** argv) {
+
+ using namespace uscxml;
+ DelayedEventQueue* eq = new DelayedEventQueue();
+
+ std::cout << "Starting" << std::endl;
+ eq->start();
+ tthread::this_thread::sleep_for(tthread::chrono::milliseconds(10));
+
+// eq->addEvent("foo", callback, 200, (void*)"event foo");
+// eq->addEvent("bar", callback, 400, (void*)"event bar");
+// eq->addEvent("bar", callback, 600, (void*)"event bar");
+// eq->cancelEvent("bar");
+// eq->addEvent("bar", callback, 300, (void*)"event bar");
+// eq->addEvent("baz", callback, 400, (void*)"event baz");
+
+ for (unsigned int i = 0; i <= 5000; i += 500) {
+// eq->stop();
+ std::stringstream ss;
+ ss << i;
+ eq->addEvent(ss.str(), callback, i, NULL);
+ std::cout << "Added " << i << std::endl;
+// eq->start();
+ }
+ tthread::this_thread::sleep_for(tthread::chrono::milliseconds(20000));
+
+} \ No newline at end of file
diff --git a/test/src/test-execution.cpp b/test/src/test-execution.cpp
new file mode 100644
index 0000000..e484eb4
--- /dev/null
+++ b/test/src/test-execution.cpp
@@ -0,0 +1,16 @@
+#include "uscxml/Interpreter.h"
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ std::cerr << "Expected path to test-execution.scxml" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ using namespace uscxml;
+ using namespace Arabica::DOM;
+ using namespace Arabica::XPath;
+
+ Interpreter* interpreter = new Interpreter(argv[1]);
+ interpreter->dump();
+ interpreter->interpret();
+} \ No newline at end of file
diff --git a/test/src/test-execution.scxml b/test/src/test-execution.scxml
new file mode 100644
index 0000000..ada1a17
--- /dev/null
+++ b/test/src/test-execution.scxml
@@ -0,0 +1,56 @@
+<scxml initial="step2">
+ <state id="start">
+ <onentry>
+ <log expr="'Entered State: start'" />
+ </onentry>
+ <transition target="step1">
+ <log expr="'Transition start -> step1'" />
+ </transition>
+ <onexit>
+ <log expr="'Exited State: start'" />
+ </onexit>
+ </state>
+ <state id="step1">
+ <onentry>
+ <log expr="'Entered State: step1'" />
+ </onentry>
+ <transition target="step2">
+ <log expr="'Transition step1 -> step2'" />
+ </transition>
+ <onexit>
+ <log expr="'Exited State: step1'" />
+ </onexit>
+ </state>
+ <parallel id="step2">
+ <state id="parallel1">
+ <onentry>
+ <log expr="'Entered State: parallel1'" />
+ </onentry>
+ <transition target="step3">
+ <log expr="'Transition parallel1 -> step3'" />
+ </transition>
+ <onexit>
+ <log expr="'Exited State: parallel1'" />
+ </onexit>
+ </state>
+ <state id="parallel2">
+ <onentry>
+ <log expr="'Entered State: parallel2'" />
+ </onentry>
+ <transition target="step3">
+ <log expr="'Transition parallel2 -> step3'" />
+ </transition>
+ <onexit>
+ <log expr="'Exited State: parallel2'" />
+ </onexit>
+ </state>
+ </parallel>
+ <final id="step3">
+ <onentry>
+ <log expr="'Entered Final State: step3'" />
+ </onentry>
+ <onexit>
+ <log expr="'Exited Final State: step3'" />
+ </onexit>
+ </final>
+</scxml> \ No newline at end of file
diff --git a/test/src/test-predicates.cpp b/test/src/test-predicates.cpp
new file mode 100644
index 0000000..73c37dc
--- /dev/null
+++ b/test/src/test-predicates.cpp
@@ -0,0 +1,60 @@
+#define protected public
+#include "uscxml/Interpreter.h"
+#undef protected
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ std::cerr << "Expected path to test-predicates.scxml" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ using namespace uscxml;
+ using namespace Arabica::DOM;
+ using namespace Arabica::XPath;
+
+ Interpreter* interpreter = new Interpreter(argv[1]);
+
+ Node<std::string> atomicState = interpreter->getState("atomic");
+ assert(Interpreter::isAtomic(atomicState));
+ assert(!Interpreter::isParallel(atomicState));
+ assert(!Interpreter::isCompound(atomicState));
+
+ Node<std::string> compoundState = interpreter->getState("compound");
+ assert(!Interpreter::isAtomic(compoundState));
+ assert(!Interpreter::isParallel(compoundState));
+ assert(Interpreter::isCompound(compoundState));
+
+ Node<std::string> parallelState = interpreter->getState("parallel");
+ assert(!Interpreter::isAtomic(parallelState));
+ assert(Interpreter::isParallel(parallelState));
+ assert(!Interpreter::isCompound(parallelState)); // parallel states are not compound!
+
+ Node<std::string> initialState = interpreter->getInitialState();
+ assert(initialState == atomicState);
+
+ NodeSet<std::string> childs = interpreter->getChildStates(compoundState);
+ Node<std::string> compundChild1 = interpreter->getState("compundChild1");
+ Node<std::string> compundChild2 = interpreter->getState("compundChild2");
+ assert(childs.size() > 0);
+ assert(Interpreter::isMember(compundChild1, childs));
+ assert(Interpreter::isMember(compundChild2, childs));
+ assert(!Interpreter::isMember(compoundState, childs));
+
+ assert(Interpreter::isDescendant(compundChild1, compoundState));
+
+ std::string transEvents;
+ transEvents = "error";
+ assert(Interpreter::nameMatch(transEvents, "error"));
+ assert(!Interpreter::nameMatch(transEvents, "foo"));
+
+ transEvents = "error foo";
+ assert(Interpreter::nameMatch(transEvents, "error"));
+ assert(Interpreter::nameMatch(transEvents, "error.send"));
+ assert(Interpreter::nameMatch(transEvents, "error.send.failed"));
+ assert(Interpreter::nameMatch(transEvents, "foo"));
+ assert(Interpreter::nameMatch(transEvents, "foo.bar"));
+ assert(!Interpreter::nameMatch(transEvents, "errors.my.custom"));
+ assert(!Interpreter::nameMatch(transEvents, "errorhandler.mistake"));
+ assert(!Interpreter::nameMatch(transEvents, "errOr.send"));
+ assert(!Interpreter::nameMatch(transEvents, "foobar"));
+} \ No newline at end of file
diff --git a/test/src/test-predicates.scxml b/test/src/test-predicates.scxml
new file mode 100644
index 0000000..98848a2
--- /dev/null
+++ b/test/src/test-predicates.scxml
@@ -0,0 +1,9 @@
+<scxml>
+ <state id="atomic" />
+ <state id="compound">
+ <state id="compundChild1" />
+ <state id="compundChild2" />
+ </state>
+ <parallel id="parallel">
+ </parallel>
+</scxml> \ No newline at end of file