summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2012-12-15 19:10:50 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2012-12-15 19:10:50 (GMT)
commitf1700edcd08d6215888e226618555ba43b5324ec (patch)
tree738f30de64f699c3f56d2e15963537c9493a24b4
parent2855a9ff7b423140237c9e988252fde0cbacd0a1 (diff)
downloaduscxml-f1700edcd08d6215888e226618555ba43b5324ec.zip
uscxml-f1700edcd08d6215888e226618555ba43b5324ec.tar.gz
uscxml-f1700edcd08d6215888e226618555ba43b5324ec.tar.bz2
Refactoring and plugin support
-rw-r--r--CMakeLists.txt293
-rw-r--r--apps/mmi-browser.cpp3
-rw-r--r--config.h.in2
-rw-r--r--contrib/cmake/CPackUSCXML.cmake2
-rw-r--r--src/uscxml/Factory.cpp114
-rw-r--r--src/uscxml/Factory.h27
-rw-r--r--src/uscxml/Interpreter.h2
-rw-r--r--src/uscxml/URL.cpp358
-rw-r--r--src/uscxml/URL.h33
-rw-r--r--src/uscxml/Utilities.cpp403
-rw-r--r--src/uscxml/Utilities.h51
-rw-r--r--src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp (renamed from src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp)2
-rw-r--r--src/uscxml/concurrency/eventqueue/DelayedEventQueue.h (renamed from src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h)0
-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/ioprocessor/basichttp/README.md2
-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--src/uscxml/plugins/Plugins.cpp11
-rw-r--r--src/uscxml/plugins/Plugins.h17
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Config.hpp141
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Connector.hpp86
-rwxr-xr-xsrc/uscxml/plugins/Pluma/DLibrary.cpp106
-rwxr-xr-xsrc/uscxml/plugins/Pluma/DLibrary.hpp123
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Dir.cpp103
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Dir.hpp64
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Host.cpp179
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Host.hpp212
-rwxr-xr-xsrc/uscxml/plugins/Pluma/PluginManager.cpp201
-rwxr-xr-xsrc/uscxml/plugins/Pluma/PluginManager.hpp245
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Pluma.hpp171
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Pluma.inl52
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Provider.cpp52
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Provider.hpp204
-rwxr-xr-xsrc/uscxml/plugins/Pluma/uce-dirent.h679
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp (renamed from src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp)14
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h92
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp (renamed from src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp)0
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h (renamed from src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h)0
-rw-r--r--src/uscxml/plugins/invoker/modality/MMIComponent.cpp (renamed from src/uscxml/invoker/modality/MMIComponent.cpp)0
-rw-r--r--src/uscxml/plugins/invoker/modality/MMIComponent.h (renamed from src/uscxml/invoker/modality/MMIComponent.h)0
-rw-r--r--src/uscxml/plugins/invoker/modality/UmundoComponent.cpp (renamed from src/uscxml/invoker/modality/UmundoComponent.cpp)0
-rw-r--r--src/uscxml/plugins/invoker/modality/UmundoComponent.h (renamed from src/uscxml/invoker/modality/UmundoComponent.h)0
-rw-r--r--src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp (renamed from src/uscxml/invoker/modality/miles/SpatialAudio.cpp)10
-rw-r--r--src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h (renamed from src/uscxml/invoker/modality/miles/SpatialAudio.h)10
-rw-r--r--src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp (renamed from src/uscxml/invoker/scxml/USCXMLInvoker.cpp)14
-rw-r--r--src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h (renamed from src/uscxml/invoker/scxml/USCXMLInvoker.h)19
-rw-r--r--src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp487
-rw-r--r--src/uscxml/plugins/invoker/umundo/UmundoInvoker.h70
-rw-r--r--src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp370
-rw-r--r--src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h107
-rw-r--r--test/src/test-ecmascript-v8.cpp2
-rw-r--r--test/src/test-eventdelay.cpp2
55 files changed, 4522 insertions, 854 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a7f5b6b..370e217 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8.4)
# specify USCXML version
SET(USCXML_VERSION_MAJOR "0")
SET(USCXML_VERSION_MINOR "0")
-SET(USCXML_VERSION_PATCH "1")
+SET(USCXML_VERSION_PATCH "2")
SET(USCXML_VERSION ${USCXML_VERSION_MAJOR}.${USCXML_VERSION_MINOR}.${USCXML_VERSION_PATCH})
# build type has to be set before the project definition
@@ -145,7 +145,7 @@ endif()
if (CMAKE_CROSSCOMPILING)
OPTION(BUILD_TESTS "Build USCXML tests" OFF)
else()
- OPTION(BUILD_TESTS "Build USCXML tests" OFF)
+ OPTION(BUILD_TESTS "Build USCXML tests" ON)
endif()
# a dummy target to depend on the targets needed for tests, see:
@@ -215,11 +215,12 @@ elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
add_definitions("-Wno-parentheses-equality")
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-fPIC")
-
else()
message(FATAL_ERROR "Unknown compiler: ${CMAKE_CXX_COMPILER_ID}")
endif()
+set(CMAKE_COMPILER_STRING "${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")
+
############################################################
# postfixes for all built targets depending on build type
############################################################
@@ -284,81 +285,165 @@ endforeach()
# Dependent libraries
############################################################
-set(USCXML_LIBS)
+set(USCXML_CORE_LIBS)
+set(USCXML_OPT_LIBS)
set(USCXML_FILES)
if (NOT WIN32)
# libxml2
find_package(LibXml2 REQUIRED)
include_directories(${LIBXML2_INCLUDE_DIR})
- list (APPEND USCXML_LIBS ${LIBXML2_LIBRARIES})
+ list (APPEND USCXML_CORE_LIBS ${LIBXML2_LIBRARIES})
+ set(XML_LIBRARIES ${LIBXML2_LIBRARIES})
elseif(WIN32)
- list (APPEND USCXML_LIBS "Ws2_32")
- list (APPEND USCXML_LIBS "Winmm")
- list (APPEND USCXML_LIBS "Iphlpapi")
- list (APPEND USCXML_LIBS "Netapi32")
+ list (APPEND XML_LIBRARIES "Ws2_32")
+ list (APPEND XML_LIBRARIES "Winmm")
+ list (APPEND XML_LIBRARIES "Iphlpapi")
+ list (APPEND XML_LIBRARIES "Netapi32")
+ list (APPEND USCXML_CORE_LIBS ${XML_LIBRARIES})
endif()
# prefer rest as static libraries
set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
-#glog
+################################
+# required libraries for core
+
+
+# GLOG
+
# set(ENV{GLOG_SRC} ${CMAKE_SOURCE_DIR}/../glog)
find_package(GLOG REQUIRED)
include_directories(${GLOG_INCLUDE_DIR})
-list (APPEND USCXML_LIBS ${GLOG_LIBRARY})
+list (APPEND USCXML_CORE_LIBS ${GLOG_LIBRARY})
add_definitions(-DGLOG_NO_ABBREVIATED_SEVERITIES)
-# arabica
+
+# ARABICA
+
find_package(Arabica REQUIRED)
include_directories(${ARABICA_INCLUDE_DIR})
-list (APPEND USCXML_LIBS ${ARABICA_LIBRARY})
+list (APPEND USCXML_CORE_LIBS ${ARABICA_LIBRARY})
if (WIN32)
add_definitions("-DUSE_MSXML")
endif()
-# boost - header only
+
+# BOOST - header only
+
FIND_PATH(Boost_INCLUDE_DIR boost/version.hpp)
include_directories(${Boost_INCLUDE_DIR})
-#event
+
+# CURL
+
+find_package(CURL REQUIRED)
+include_directories(${CURL_INCLUDE_DIRS})
+list (APPEND USCXML_CORE_LIBS ${CURL_LIBRARIES})
+if (WIN32)
+ add_definitions("-DCURL_STATICLIB")
+endif()
+
+
+# LIBEVENT
+
#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_CORE_LIBS ${EVENT_LIBRARY})
+
+############################################################
+# Actual files of core library
+############################################################
+
+file(GLOB_RECURSE USCXML_CONCURRENCY
+ src/uscxml/concurrency/*.cpp
+ src/uscxml/concurrency/*.h
)
-list (APPEND USCXML_FILES ${USCXML_IO_PROCESSOR_LIBEVENT})
+list (APPEND USCXML_FILES ${USCXML_CONCURRENCY})
-file(GLOB_RECURSE USCXML_EVENTQUEUE_LIBEVENT
- src/uscxml/concurrency/eventqueue/libevent/*.cpp
- src/uscxml/concurrency/eventqueue/libevent/*.h
+file(GLOB_RECURSE USCXML_DEBUG
+ src/uscxml/debug/*.cpp
+ src/uscxml/debug/*.h
)
-list (APPEND USCXML_FILES ${USCXML_EVENTQUEUE_LIBEVENT})
+list (APPEND USCXML_FILES ${USCXML_DEBUG})
-list (APPEND USCXML_LIBS ${EVENT_LIBRARY})
+file(GLOB USCXML_CORE
+ src/uscxml/*.cpp
+ src/uscxml/*.h
+)
+list (APPEND USCXML_FILES ${USCXML_CORE})
-# 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
+include_directories(src)
+
+#################################################
+# optional libraries we can build as plugins
+
+OPTION(BUILD_AS_PLUGINS "Build invokers, ioprocessors and datamodels as plugins" ON)
+if (BUILD_AS_PLUGINS)
+ include_directories(${PROJECT_SOURCE_DIR}/src/uscxml/plugins)
+ file(GLOB PLUMA
+ src/uscxml/plugins/Pluma/*.cpp
+ src/uscxml/plugins/Pluma/*.h
+ src/uscxml/plugins/*.cpp
+ src/uscxml/plugins/*.h
+ )
+ list (APPEND USCXML_FILES ${PLUMA})
+ add_definitions("-DBUILD_AS_PLUGINS")
+endif()
+
+
+# LIBEVENT basichttp ioprocessor - this one is already required above
+
+file(GLOB_RECURSE LIBEVENT_IOPROCESSOR
+ src/uscxml/concurrency/*.cpp
+ src/uscxml/concurrency/*.h
+ src/uscxml/plugins/ioprocessor/basichttp/*.cpp
+ src/uscxml/plugins/ioprocessor/basichttp/*.h
)
-list (APPEND USCXML_FILES ${USCXML_DATAMODEL_V8})
-list (APPEND USCXML_LIBS ${V8_LIBRARY})
+if (BUILD_AS_PLUGINS)
+ add_library(
+ ioprocessor_basichttp SHARED
+ ${LIBEVENT_IOPROCESSOR}
+ ${PLUMA}
+ ${USCXML_FILES})
+ target_link_libraries(ioprocessor_basichttp
+ ${USCXML_CORE_LIBS})
+ set_target_properties(ioprocessor_basichttp PROPERTIES FOLDER "Plugin IOProcessor")
+else()
+ list (APPEND USCXML_FILES ${LIBEVENT_IOPROCESSOR})
+endif()
-# curl
-find_package(CURL REQUIRED)
-include_directories(${CURL_INCLUDE_DIRS})
-list (APPEND USCXML_LIBS ${CURL_LIBRARIES})
-if (WIN32)
- add_definitions("-DCURL_STATICLIB")
+
+# GOOGLE V8 datamodel
+
+# set(ENV{V8_SRC} ${CMAKE_SOURCE_DIR}/../v8)
+find_package(V8)
+if (V8_FOUND)
+ include_directories(${V8_INCLUDE_DIR})
+ file(GLOB_RECURSE V8_DATAMODEL
+ src/uscxml/plugins/datamodel/ecmascript/v8/*.cpp
+ src/uscxml/plugins/datamodel/ecmascript/v8/*.h
+ )
+ if (BUILD_AS_PLUGINS)
+ add_library(
+ datamodel_v8 SHARED
+ ${V8_DATAMODEL}
+ ${PLUMA}
+ ${USCXML_FILES})
+ target_link_libraries(datamodel_v8
+ ${USCXML_CORE_LIBS}
+ ${V8_LIBRARY})
+ set_target_properties(datamodel_v8 PROPERTIES FOLDER "Plugin DataModel")
+ else()
+ list (APPEND USCXML_FILES ${V8_DATAMODEL})
+ list (APPEND USCXML_OPT_LIBS ${V8_LIBRARY})
+ endif()
endif()
-# uMundo
+
+# UMUNDO invoker
+
if (WIN32)
find_package(UMUNDO COMPONENTS convenience)
else()
@@ -366,56 +451,80 @@ else()
endif()
if (UMUNDO_FOUND)
include_directories(${UMUNDO_INCLUDE_DIR})
- file(GLOB_RECURSE UMUNDO_INVOKER src/uscxml/invoker/umundo/*.cpp src/uscxml/invoker/umundo/*.h)
- list (APPEND USCXML_FILES ${UMUNDO_INVOKER})
- list (APPEND USCXML_LIBS ${UMUNDO_LIBRARIES})
+ file(GLOB_RECURSE UMUNDO_INVOKER
+ src/uscxml/plugins/invoker/umundo/*.cpp
+ src/uscxml/plugins/invoker/umundo/*.h)
+ if (BUILD_AS_PLUGINS)
+ add_library(
+ invoker_umundo SHARED
+ ${UMUNDO_INVOKER}
+ ${PLUMA}
+ ${USCXML_FILES})
+ target_link_libraries(invoker_umundo
+ ${USCXML_CORE_LIBS}
+ ${UMUNDO_LIBRARIES})
+ set_target_properties(invoker_umundo PROPERTIES FOLDER "Plugin Invoker")
+ else()
+ list (APPEND USCXML_FILES ${UMUNDO_INVOKER})
+ list (APPEND USCXML_OPT_LIBS ${UMUNDO_LIBRARIES})
+ endif()
endif()
add_definitions("-DUMUNDO_STATIC")
-# miles
+
+# USCXML invoker
+
+file(GLOB_RECURSE USCXML_INVOKER
+ src/uscxml/plugins/invoker/scxml/*.cpp
+ src/uscxml/plugins/invoker/scxml/*.h)
+if (BUILD_AS_PLUGINS)
+ add_library(
+ invoker_uscxml SHARED
+ ${USCXML_INVOKER}
+ ${PLUMA}
+ ${USCXML_FILES})
+ target_link_libraries(invoker_uscxml
+ ${USCXML_CORE_LIBS})
+ set_target_properties(invoker_uscxml PROPERTIES FOLDER "Plugin Invoker")
+else()
+ list (APPEND USCXML_FILES ${USCXML_INVOKER})
+endif()
+
+
+# MILES modality components
+
find_package(MILES COMPONENTS core audio debug)
if (MILES_FOUND)
include_directories(${MILES_INCLUDE_DIR})
- file(GLOB_RECURSE MILES_INVOKER src/uscxml/invoker/modality/miles/*.cpp src/uscxml/invoker/modality/miles/*.h)
- list (APPEND USCXML_FILES ${MILES_INVOKER})
- list (APPEND USCXML_LIBS ${MILES_LIBRARIES})
# openal is only needed for miles
find_package(OpenAL REQUIRED)
include_directories(${OPENAL_INCLUDE_DIR})
- list(APPEND USCXML_LIBS ${OPENAL_LIBRARY})
+ file(GLOB_RECURSE MILES_INVOKER src/uscxml/invoker/modality/miles/*.cpp src/uscxml/invoker/modality/miles/*.h)
+ if (BUILD_AS_PLUGINS)
+ add_library(
+ invoker_miles SHARED
+ ${MILES_INVOKER}
+ ${PLUMA}
+ ${USCXML_FILES})
+ target_link_libraries(invoker_miles
+ ${MILES_LIBRARIES}
+ ${OPENAL_LIBRARY}
+ ${USCXML_CORE_LIBS})
+ set_target_properties(invoker_miles PROPERTIES FOLDER "Plugin Invoker")
+ else()
+ list (APPEND USCXML_FILES ${MILES_INVOKER})
+ list (APPEND USCXML_OPT_LIBS ${MILES_LIBRARIES})
+ list (APPEND USCXML_OPT_LIBS ${OPENAL_LIBRARY})
+ endif()
endif()
-# # protobuf
-# find_package(Protobuf REQUIRED)
-# LIST(APPEND USCXML_LIBS optimized ${PROTOBUF_LIBRARY})
-# LIST(APPEND USCXML_LIBS debug ${PROTOBUF_LIBRARY_DEBUG})
-# include_directories(${PROTOBUF_INCLUDE_DIRS})
-
-# the uscxml invoker
-file(GLOB_RECURSE USCXML_INVOKER src/uscxml/invoker/scxml/*.cpp src/uscxml/invoker/scxml/*.h)
-list (APPEND USCXML_FILES ${USCXML_INVOKER})
-
-# debug
-# file(GLOB_RECURSE USCXML_DEBUG src/uscxml/debug/*.cpp src/uscxml/debug/*.h)
-# list (APPEND USCXML_FILES ${USCXML_DEBUG})
-
-file(GLOB USCXML_CONCURRENCY src/uscxml/concurrency/*.cpp src/uscxml/concurrency/*.h)
-list (APPEND USCXML_FILES ${USCXML_CONCURRENCY})
-
-file(GLOB USCXML_MODALITIES src/uscxml/invoker/modality/*.cpp src/uscxml/invoker/modality/*.h)
-list (APPEND USCXML_FILES ${USCXML_MODALITIES})
-
-file(GLOB USCXML_INTERPRETER src/uscxml/*.cpp src/uscxml/*.h)
-list (APPEND USCXML_FILES ${USCXML_INTERPRETER})
-
-include_directories(src)
# order of libraries matters with some gcc versions?!
if (UNIX AND NOT APPLE)
- list (APPEND USCXML_LIBS "pthread")
- list (APPEND USCXML_LIBS "rt")
+ list (APPEND USCXML_CORE_LIBS "pthread")
+ list (APPEND USCXML_CORE_LIBS "rt")
endif()
############################################################
@@ -424,7 +533,7 @@ endif()
# build library
add_library(uscxml ${USCXML_FILES})
-target_link_libraries(uscxml ${USCXML_LIBS})
+target_link_libraries(uscxml ${USCXML_OPT_LIBS} ${USCXML_CORE_LIBS})
add_executable(mmi-browser apps/mmi-browser.cpp ${PROJECT_SOURCE_DIR}/contrib/snippets/XGetopt.cpp)
target_link_libraries(mmi-browser uscxml)
@@ -468,37 +577,3 @@ include(contrib/cmake/CPackUSCXML.cmake)
# This must always be last!
include(CPack)
-
-
-# ---- 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/apps/mmi-browser.cpp b/apps/mmi-browser.cpp
index f21bd20..52b376d 100644
--- a/apps/mmi-browser.cpp
+++ b/apps/mmi-browser.cpp
@@ -7,7 +7,7 @@
#endif
void printUsageAndExit() {
- printf("mmi-browser version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build)\n");
+ printf("mmi-browser version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n");
printf("Usage\n");
printf("\tmmi-browser URL\n");
printf("\n");
@@ -17,6 +17,7 @@ void printUsageAndExit() {
}
int main(int argc, char** argv) {
+ uscxml::Factory::getInstance();
if (argc < 2) {
printUsageAndExit();
}
diff --git a/config.h.in b/config.h.in
index 86614e0..b4036d0 100644
--- a/config.h.in
+++ b/config.h.in
@@ -43,6 +43,7 @@
/** build type */
#cmakedefine CMAKE_BUILD_TYPE "@CMAKE_BUILD_TYPE@"
+#cmakedefine CMAKE_COMPILER_STRING "@CMAKE_COMPILER_STRING@"
/** miscellaneous */
#cmakedefine PROJECT_SOURCE_DIR "@PROJECT_SOURCE_DIR@"
@@ -51,5 +52,6 @@
/** Optional libraries we found */
#cmakedefine UMUNDO_FOUND
#cmakedefine MILES_FOUND
+#cmakedefine V8_FOUND
#endif \ No newline at end of file
diff --git a/contrib/cmake/CPackUSCXML.cmake b/contrib/cmake/CPackUSCXML.cmake
index d0fd17c..63cfa32 100644
--- a/contrib/cmake/CPackUSCXML.cmake
+++ b/contrib/cmake/CPackUSCXML.cmake
@@ -335,7 +335,7 @@ set(CPACK_RESOURCE_FILE_WELCOME "${PROJECT_SOURCE_DIR}/installer/packageMaker/we
# Configuration for debian packages
#
set(CPACK_DEBIAN_PACKAGE_NAME "uscxml")
-set(CPACK_DEBIAN_PACKAGE_DEPENDS "libavahi-client3")
+set(CPACK_DEBIAN_PACKAGE_DEPENDS "libavahi-client3, libxml2")
set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "swig2.0, protobuf-compiler")
###
diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp
index 553e886..fdbbbc3 100644
--- a/src/uscxml/Factory.cpp
+++ b/src/uscxml/Factory.cpp
@@ -2,61 +2,121 @@
#include "uscxml/config.h"
#include "uscxml/Factory.h"
-#include "uscxml/datamodel/ecmascript/v8/V8DataModel.h"
-#include "uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.h"
-#include "uscxml/invoker/scxml/USCXMLInvoker.h"
+#include "uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h"
+#include "uscxml/plugins/invoker/scxml/USCXMLInvoker.h"
#ifdef UMUNDO_FOUND
-#include "uscxml/invoker/umundo/UmundoInvoker.h"
+#include "uscxml/plugins/invoker/umundo/UmundoInvoker.h"
#endif
#ifdef MILES_FOUND
-#include "uscxml/invoker/modality/miles/SpatialAudio.h"
+#include "uscxml/plugins/invoker/modality/miles/SpatialAudio.h"
+#endif
+
+#ifdef V8_FOUND
+#include "uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h"
#endif
namespace uscxml {
Factory::Factory() {
- _dataModels["ecmascript"] = new V8DataModel();
+#ifdef BUILD_AS_PLUGINS
+ pluma.acceptProviderType<InvokerProvider>();
+ pluma.acceptProviderType<IOProcessorProvider>();
+ pluma.acceptProviderType<DataModelProvider>();
+ pluma.loadFromFolder("/Users/sradomski/Documents/TK/Code/uscxml/build/xcode/lib");
- // use basichttp for transporting to/from scxml sessions as well
- _ioProcessors["basichttp"] = new EventIOProcessor();
- _ioProcessors["http://www.w3.org/TR/scxml/#SCXMLEventProcessor"] = _ioProcessors["basichttp"];
+ std::vector<InvokerProvider*> invokerProviders;
+ pluma.getProviders(invokerProviders);
+ for (std::vector<InvokerProvider*>::iterator it = invokerProviders.begin() ; it != invokerProviders.end() ; ++it) {
+ Invoker* invoker = (*it)->create();
+ registerInvoker(invoker);
+ }
- _invoker["scxml"] = new USCXMLInvoker();
- _invoker["http://www.w3.org/TR/scxml/"] = _invoker["scxml"];
+ std::vector<IOProcessorProvider*> ioProcessorProviders;
+ pluma.getProviders(ioProcessorProviders);
+ for (std::vector<IOProcessorProvider*>::iterator it = ioProcessorProviders.begin() ; it != ioProcessorProviders.end() ; ++it) {
+ IOProcessor* ioProcessor = (*it)->create();
+ registerIOProcessor(ioProcessor);
+ }
+ std::vector<DataModelProvider*> dataModelProviders;
+ pluma.getProviders(dataModelProviders);
+ for (std::vector<DataModelProvider*>::iterator it = dataModelProviders.begin() ; it != dataModelProviders.end() ; ++it) {
+ DataModel* dataModel = (*it)->create();
+ registerDataModel(dataModel);
+ }
+
+ pluma.unloadAll();
+
+#else
#ifdef UMUNDO_FOUND
- _invoker["umundo"] = new UmundoInvoker();
- _invoker["http://umundo.tk.informatik.tu-darmstadt.de/"] = _invoker["umundo"];
+ {
+ UmundoInvoker* invoker = new UmundoInvoker();
+ registerInvoker(invoker);
+ }
#endif
#ifdef MILES_FOUND
- _invoker["spatial-audio"] = new SpatialAudio();
- _invoker["audio"] = _invoker["spatial-audio"];
- _invoker["http://www.smartvortex.eu/mmi/spatial-audio/"] = _invoker["spatial-audio"];
+ {
+ SpatialAudio* invoker = new SpatialAudio();
+ registerInvoker(invoker);
+ }
#endif
+
+#ifdef V8_FOUND
+ {
+ V8DataModel* dataModel = new V8DataModel();
+ registerDataModel(dataModel);
+ }
+#endif
+
+ // these are always available
+ {
+ USCXMLInvoker* invoker = new USCXMLInvoker();
+ registerInvoker(invoker);
+ }
+ {
+ EventIOProcessor* ioProcessor = new EventIOProcessor();
+ registerIOProcessor(ioProcessor);
+ }
+#endif
}
- void Factory::registerIOProcessor(const std::string type, IOProcessor* ioProcessor) {
- getInstance()->_ioProcessors[type] = ioProcessor;
+ void Factory::registerIOProcessor(IOProcessor* ioProcessor) {
+ std::set<std::string> names = ioProcessor->getNames();
+ std::set<std::string>::iterator nameIter = names.begin();
+ while(nameIter != names.end()) {
+ _ioProcessors[*nameIter] = ioProcessor;
+ nameIter++;
+ }
}
- void Factory::registerDataModel(const std::string type, DataModel* dataModel) {
- getInstance()->_dataModels[type] = dataModel;
+ void Factory::registerDataModel(DataModel* dataModel) {
+ std::set<std::string> names = dataModel->getNames();
+ std::set<std::string>::iterator nameIter = names.begin();
+ while(nameIter != names.end()) {
+ _dataModels[*nameIter] = dataModel;
+ nameIter++;
+ }
}
+ void Factory::registerInvoker(Invoker* invoker) {
+ std::set<std::string> names = invoker->getNames();
+ std::set<std::string>::iterator nameIter = names.begin();
+ while(nameIter != names.end()) {
+ _invokers[*nameIter] = invoker;
+ nameIter++;
+ }
+ }
+
void Factory::registerExecutableContent(const std::string tag, ExecutableContent* executableContent) {
- getInstance()->_executableContent[tag] = executableContent;
+ _executableContent[tag] = executableContent;
}
- void Factory::registerInvoker(const std::string type, Invoker* invoker) {
- getInstance()->_invoker[type] = invoker;
- }
-
Invoker* Factory::getInvoker(const std::string type, Interpreter* interpreter) {
- if (Factory::getInstance()->_invoker.find(type) != getInstance()->_invoker.end()) {
- return (Invoker*)getInstance()->_invoker[type]->create(interpreter);
+ if (Factory::getInstance()->_invokers.find(type) != getInstance()->_invokers.end()) {
+ return (Invoker*)getInstance()->_invokers[type]->create(interpreter);
}
return NULL;
}
diff --git a/src/uscxml/Factory.h b/src/uscxml/Factory.h
index e2418f0..24d74e3 100644
--- a/src/uscxml/Factory.h
+++ b/src/uscxml/Factory.h
@@ -3,10 +3,16 @@
#include "uscxml/Message.h"
+#ifdef BUILD_AS_PLUGINS
+#include "Pluma/Pluma.hpp"
+#endif
+
#include <string>
+#include <set>
namespace uscxml {
+ // see http://stackoverflow.com/questions/228005/alternative-to-itoa-for-converting-integer-to-string-c
template <typename T> std::string toStr(T tmp) {
std::ostringstream out;
out << tmp;
@@ -33,9 +39,13 @@ namespace uscxml {
IOProcessor() {};
virtual ~IOProcessor() {};
virtual IOProcessor* create(Interpreter* interpreter) = 0;
+ virtual std::set<std::string> getNames() = 0;
+ virtual void setInterpreter(Interpreter* interpreter) { _interpreter = interpreter; }
virtual Data getDataModelVariables() = 0;
virtual void send(SendRequest& req) = 0;
+ protected:
+ Interpreter* _interpreter;
};
class Invoker : public IOProcessor {
@@ -46,8 +56,9 @@ namespace uscxml {
class DataModel {
public:
- virtual DataModel* create(Interpreter* interpreter) = 0;
virtual ~DataModel() {}
+ virtual DataModel* create(Interpreter* interpreter) = 0;
+ virtual std::set<std::string> getNames() = 0;
virtual bool validate(const std::string& location, const std::string& schema) = 0;
virtual void setEvent(const Event& event) = 0;
@@ -67,10 +78,10 @@ namespace uscxml {
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 void registerInvoker(const std::string type, Invoker* invoker);
+ void registerIOProcessor(IOProcessor* ioProcessor);
+ void registerDataModel(DataModel* dataModel);
+ void registerInvoker(Invoker* invoker);
+ 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);
@@ -81,10 +92,14 @@ namespace uscxml {
std::map<std::string, DataModel*> _dataModels;
std::map<std::string, IOProcessor*> _ioProcessors;
- std::map<std::string, Invoker*> _invoker;
+ std::map<std::string, Invoker*> _invokers;
std::map<std::string, ExecutableContent*> _executableContent;
protected:
+#ifdef BUILD_AS_PLUGINS
+ pluma::Pluma pluma;
+#endif
+
Factory();
static Factory* _instance;
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
index 773516e..6890baf 100644
--- a/src/uscxml/Interpreter.h
+++ b/src/uscxml/Interpreter.h
@@ -18,7 +18,7 @@
#include <SAX/helpers/CatchErrorHandler.hpp>
#include "uscxml/concurrency/tinythread.h"
-#include "uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h"
+#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h"
#include "uscxml/concurrency/BlockingQueue.h"
#include "uscxml/Message.h"
#include "uscxml/Factory.h"
diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp
index 722352d..991c875 100644
--- a/src/uscxml/URL.cpp
+++ b/src/uscxml/URL.cpp
@@ -1,7 +1,17 @@
-#include "URL.h"
#include <glog/logging.h>
#include <algorithm>
+#include <stdio.h>
+#include <string.h>
+#ifndef WIN32
+#include <sys/time.h>
+#endif
+#include <stdlib.h>
+#include <errno.h>
+
+#include "uscxml/Common.h"
+#include "URL.h"
+
namespace uscxml {
std::ostream & operator<<(std::ostream & stream, const URL& url) {
@@ -37,5 +47,349 @@ std::ostream & operator<<(std::ostream & stream, const URL& url) {
return stream;
}
-
+/* we use a global one for convenience */
+CURLM *multi_handle;
+
+/* curl calls this routine to get more data */
+static size_t write_callback(char *buffer,
+ size_t size,
+ size_t nitems,
+ void *userp)
+{
+ char *newbuff;
+ size_t rembuff;
+
+ URL_FILE *url = (URL_FILE *)userp;
+ size *= nitems;
+
+ rembuff=url->buffer_len - url->buffer_pos; /* remaining space in buffer */
+
+ if(size > rembuff) {
+ /* not enough space in buffer */
+ newbuff=(char*)realloc(url->buffer,url->buffer_len + (size - rembuff));
+ if(newbuff==NULL) {
+ fprintf(stderr,"callback buffer grow failed\n");
+ size=rembuff;
+ }
+ else {
+ /* realloc suceeded increase buffer size*/
+ url->buffer_len+=size - rembuff;
+ url->buffer=newbuff;
+ }
+ }
+
+ memcpy(&url->buffer[url->buffer_pos], buffer, size);
+ url->buffer_pos += size;
+
+ return size;
+}
+
+/* use to attempt to fill the read buffer up to requested number of bytes */
+static int fill_buffer(URL_FILE *file, size_t want)
+{
+ fd_set fdread;
+ fd_set fdwrite;
+ fd_set fdexcep;
+ struct timeval timeout;
+ int rc;
+
+ /* only attempt to fill buffer if transactions still running and buffer
+ * doesnt exceed required size already
+ */
+ if((!file->still_running) || (file->buffer_pos > want))
+ return 0;
+
+ /* attempt to fill buffer */
+ do {
+ int maxfd = -1;
+ long curl_timeo = -1;
+
+ FD_ZERO(&fdread);
+ FD_ZERO(&fdwrite);
+ FD_ZERO(&fdexcep);
+
+ /* set a suitable timeout to fail on */
+ timeout.tv_sec = 60; /* 1 minute */
+ timeout.tv_usec = 0;
+
+ curl_multi_timeout(multi_handle, &curl_timeo);
+ if(curl_timeo >= 0) {
+ timeout.tv_sec = curl_timeo / 1000;
+ if(timeout.tv_sec > 1)
+ timeout.tv_sec = 1;
+ else
+ timeout.tv_usec = (curl_timeo % 1000) * 1000;
+ }
+
+ /* get file descriptors from the transfers */
+ curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
+
+ /* In a real-world program you OF COURSE check the return code of the
+ function calls. On success, the value of maxfd is guaranteed to be
+ greater or equal than -1. We call select(maxfd + 1, ...), specially
+ in case of (maxfd == -1), we call select(0, ...), which is basically
+ equal to sleep. */
+
+ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+
+ switch(rc) {
+ case -1:
+ /* select error */
+ break;
+
+ case 0:
+ default:
+ /* timeout or readable/writable sockets */
+ curl_multi_perform(multi_handle, &file->still_running);
+ break;
+ }
+ } while(file->still_running && (file->buffer_pos < want));
+ return 1;
+}
+
+/* use to remove want bytes from the front of a files buffer */
+static int use_buffer(URL_FILE *file,int want)
+{
+ /* sort out buffer */
+ if((file->buffer_pos - want) <=0) {
+ /* ditch buffer - write will recreate */
+ if(file->buffer)
+ free(file->buffer);
+
+ file->buffer=NULL;
+ file->buffer_pos=0;
+ file->buffer_len=0;
+ }
+ else {
+ /* move rest down make it available for later */
+ memmove(file->buffer,
+ &file->buffer[want],
+ (file->buffer_pos - want));
+
+ file->buffer_pos -= want;
+ }
+ return 0;
+}
+
+URL_FILE *url_fopen(const char *url,const char *operation)
+{
+ /* this code could check for URLs or types in the 'url' and
+ basicly use the real fopen() for standard files */
+
+ URL_FILE *file;
+ (void)operation;
+
+ file = (URL_FILE*)malloc(sizeof(URL_FILE));
+ if(!file)
+ return NULL;
+
+ memset(file, 0, sizeof(URL_FILE));
+
+ if((file->handle.file=fopen(url,operation)))
+ file->type = CFTYPE_FILE; /* marked as URL */
+
+ else {
+ file->type = CFTYPE_CURL; /* marked as URL */
+ file->handle.curl = curl_easy_init();
+
+ curl_easy_setopt(file->handle.curl, CURLOPT_URL, url);
+ curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file);
+ curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0L);
+ curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback);
+
+ if(!multi_handle)
+ multi_handle = curl_multi_init();
+
+ curl_multi_add_handle(multi_handle, file->handle.curl);
+
+ /* lets start the fetch */
+ curl_multi_perform(multi_handle, &file->still_running);
+
+ if((file->buffer_pos == 0) && (!file->still_running)) {
+ /* if still_running is 0 now, we should return NULL */
+
+ /* make sure the easy handle is not in the multi handle anymore */
+ curl_multi_remove_handle(multi_handle, file->handle.curl);
+
+ /* cleanup */
+ curl_easy_cleanup(file->handle.curl);
+
+ free(file);
+
+ file = NULL;
+ }
+ }
+ return file;
+}
+
+int url_fclose(URL_FILE *file)
+{
+ int ret=0;/* default is good return */
+
+ switch(file->type) {
+ case CFTYPE_FILE:
+ ret=fclose(file->handle.file); /* passthrough */
+ break;
+
+ case CFTYPE_CURL:
+ /* make sure the easy handle is not in the multi handle anymore */
+ curl_multi_remove_handle(multi_handle, file->handle.curl);
+
+ /* cleanup */
+ curl_easy_cleanup(file->handle.curl);
+ break;
+
+ default: /* unknown or supported type - oh dear */
+ ret=EOF;
+ errno=EBADF;
+ break;
+ }
+
+ if(file->buffer)
+ free(file->buffer);/* free any allocated buffer space */
+
+ free(file);
+
+ return ret;
+}
+
+int url_feof(URL_FILE *file)
+{
+ int ret=0;
+
+ switch(file->type) {
+ case CFTYPE_FILE:
+ ret=feof(file->handle.file);
+ break;
+
+ case CFTYPE_CURL:
+ if((file->buffer_pos == 0) && (!file->still_running))
+ ret = 1;
+ break;
+
+ default: /* unknown or supported type - oh dear */
+ ret=-1;
+ errno=EBADF;
+ break;
+ }
+ return ret;
+}
+
+size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file)
+{
+ size_t want;
+
+ switch(file->type) {
+ case CFTYPE_FILE:
+ want=fread(ptr,size,nmemb,file->handle.file);
+ break;
+
+ case CFTYPE_CURL:
+ want = nmemb * size;
+
+ fill_buffer(file,want);
+
+ /* check if theres data in the buffer - if not fill_buffer()
+ * either errored or EOF */
+ if(!file->buffer_pos)
+ return 0;
+
+ /* ensure only available data is considered */
+ if(file->buffer_pos < want)
+ want = file->buffer_pos;
+
+ /* xfer data to caller */
+ memcpy(ptr, file->buffer, want);
+
+ use_buffer(file,want);
+
+ want = want / size; /* number of items */
+ break;
+
+ default: /* unknown or supported type - oh dear */
+ want=0;
+ errno=EBADF;
+ break;
+
+ }
+ return want;
+}
+
+char *url_fgets(char *ptr, size_t size, URL_FILE *file)
+{
+ size_t want = size - 1;/* always need to leave room for zero termination */
+ size_t loop;
+
+ switch(file->type) {
+ case CFTYPE_FILE:
+ ptr = fgets(ptr,size,file->handle.file);
+ break;
+
+ case CFTYPE_CURL:
+ fill_buffer(file,want);
+
+ /* check if theres data in the buffer - if not fill either errored or
+ * EOF */
+ if(!file->buffer_pos)
+ return NULL;
+
+ /* ensure only available data is considered */
+ if(file->buffer_pos < want)
+ want = file->buffer_pos;
+
+ /*buffer contains data */
+ /* look for newline or eof */
+ for(loop=0;loop < want;loop++) {
+ if(file->buffer[loop] == '\n') {
+ want=loop+1;/* include newline */
+ break;
+ }
+ }
+
+ /* xfer data to caller */
+ memcpy(ptr, file->buffer, want);
+ ptr[want]=0;/* allways null terminate */
+
+ use_buffer(file,want);
+
+ break;
+
+ default: /* unknown or supported type - oh dear */
+ ptr=NULL;
+ errno=EBADF;
+ break;
+ }
+
+ return ptr;/*success */
+}
+
+void url_rewind(URL_FILE *file)
+{
+ switch(file->type) {
+ case CFTYPE_FILE:
+ rewind(file->handle.file); /* passthrough */
+ break;
+
+ case CFTYPE_CURL:
+ /* halt transaction */
+ curl_multi_remove_handle(multi_handle, file->handle.curl);
+
+ /* restart */
+ curl_multi_add_handle(multi_handle, file->handle.curl);
+
+ /* ditch buffer - write will recreate - resets stream pos*/
+ if(file->buffer)
+ free(file->buffer);
+
+ file->buffer=NULL;
+ file->buffer_pos=0;
+ file->buffer_len=0;
+
+ break;
+
+ default: /* unknown or supported type - oh dear */
+ break;
+ }
+}
+
} \ No newline at end of file
diff --git a/src/uscxml/URL.h b/src/uscxml/URL.h
index d6fc9ed..8438d3a 100644
--- a/src/uscxml/URL.h
+++ b/src/uscxml/URL.h
@@ -1,10 +1,41 @@
#ifndef URL_H_27HPRH76
#define URL_H_27HPRH76
-#include "Utilities.h"
+#include <string>
+#include <sstream>
+#include <curl/curl.h>
namespace uscxml {
+enum fcurl_type_e {
+ CFTYPE_NONE=0,
+ CFTYPE_FILE=1,
+ CFTYPE_CURL=2
+};
+
+struct fcurl_data
+{
+ enum fcurl_type_e type; /* type of handle */
+ union {
+ CURL *curl;
+ FILE *file;
+ } handle; /* handle */
+
+ char *buffer; /* buffer to store cached data*/
+ size_t buffer_len; /* currently allocated buffers length */
+ size_t buffer_pos; /* end of data in buffer*/
+ int still_running; /* Is background url fetch still in progress */
+};
+
+typedef struct fcurl_data URL_FILE;
+
+URL_FILE *url_fopen(const char *url,const char *operation);
+int url_fclose(URL_FILE *file);
+int url_feof(URL_FILE *file);
+size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file);
+char * url_fgets(char *ptr, size_t size, URL_FILE *file);
+void url_rewind(URL_FILE *file);
+
class URL {
public:
URL(const std::string urlString) : _urlString(urlString) {}
diff --git a/src/uscxml/Utilities.cpp b/src/uscxml/Utilities.cpp
deleted file mode 100644
index 846d3fa..0000000
--- a/src/uscxml/Utilities.cpp
+++ /dev/null
@@ -1,403 +0,0 @@
-/*****************************************************************************
- *
- * Taken in its entirety from http://curl.haxx.se/libcurl/c/fopen.html
- *
- * This example source code introduces a c library buffered I/O interface to
- * URL reads it supports fopen(), fread(), fgets(), feof(), fclose(),
- * rewind(). Supported functions have identical prototypes to their normal c
- * lib namesakes and are preceaded by url_ .
- *
- * Using this code you can replace your program's fopen() with url_fopen()
- * and fread() with url_fread() and it become possible to read remote streams
- * instead of (only) local files. Local files (ie those that can be directly
- * fopened) will drop back to using the underlying clib implementations
- *
- * See the main() function at the bottom that shows an app that retrives from a
- * specified url using fgets() and fread() and saves as two output files.
- *
- * Copyright (c) 2003 Simtec Electronics
- *
- * Re-implemented by Vincent Sanders <vince@kyllikki.org> with extensive
- * reference to original curl example code
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * This example requires libcurl 7.9.7 or later.
- */
-
-#include <stdio.h>
-#include <string.h>
-#ifndef WIN32
-#include <sys/time.h>
-#endif
-#include <stdlib.h>
-#include <errno.h>
-
-#include "uscxml/Common.h"
-#include "uscxml/Utilities.h"
-
-/* we use a global one for convenience */
-CURLM *multi_handle;
-
-/* curl calls this routine to get more data */
-static size_t write_callback(char *buffer,
- size_t size,
- size_t nitems,
- void *userp)
-{
- char *newbuff;
- size_t rembuff;
-
- URL_FILE *url = (URL_FILE *)userp;
- size *= nitems;
-
- rembuff=url->buffer_len - url->buffer_pos; /* remaining space in buffer */
-
- if(size > rembuff) {
- /* not enough space in buffer */
- newbuff=(char*)realloc(url->buffer,url->buffer_len + (size - rembuff));
- if(newbuff==NULL) {
- fprintf(stderr,"callback buffer grow failed\n");
- size=rembuff;
- }
- else {
- /* realloc suceeded increase buffer size*/
- url->buffer_len+=size - rembuff;
- url->buffer=newbuff;
- }
- }
-
- memcpy(&url->buffer[url->buffer_pos], buffer, size);
- url->buffer_pos += size;
-
- return size;
-}
-
-/* use to attempt to fill the read buffer up to requested number of bytes */
-static int fill_buffer(URL_FILE *file, size_t want)
-{
- fd_set fdread;
- fd_set fdwrite;
- fd_set fdexcep;
- struct timeval timeout;
- int rc;
-
- /* only attempt to fill buffer if transactions still running and buffer
- * doesnt exceed required size already
- */
- if((!file->still_running) || (file->buffer_pos > want))
- return 0;
-
- /* attempt to fill buffer */
- do {
- int maxfd = -1;
- long curl_timeo = -1;
-
- FD_ZERO(&fdread);
- FD_ZERO(&fdwrite);
- FD_ZERO(&fdexcep);
-
- /* set a suitable timeout to fail on */
- timeout.tv_sec = 60; /* 1 minute */
- timeout.tv_usec = 0;
-
- curl_multi_timeout(multi_handle, &curl_timeo);
- if(curl_timeo >= 0) {
- timeout.tv_sec = curl_timeo / 1000;
- if(timeout.tv_sec > 1)
- timeout.tv_sec = 1;
- else
- timeout.tv_usec = (curl_timeo % 1000) * 1000;
- }
-
- /* get file descriptors from the transfers */
- curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
-
- /* In a real-world program you OF COURSE check the return code of the
- function calls. On success, the value of maxfd is guaranteed to be
- greater or equal than -1. We call select(maxfd + 1, ...), specially
- in case of (maxfd == -1), we call select(0, ...), which is basically
- equal to sleep. */
-
- rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
-
- switch(rc) {
- case -1:
- /* select error */
- break;
-
- case 0:
- default:
- /* timeout or readable/writable sockets */
- curl_multi_perform(multi_handle, &file->still_running);
- break;
- }
- } while(file->still_running && (file->buffer_pos < want));
- return 1;
-}
-
-/* use to remove want bytes from the front of a files buffer */
-static int use_buffer(URL_FILE *file,int want)
-{
- /* sort out buffer */
- if((file->buffer_pos - want) <=0) {
- /* ditch buffer - write will recreate */
- if(file->buffer)
- free(file->buffer);
-
- file->buffer=NULL;
- file->buffer_pos=0;
- file->buffer_len=0;
- }
- else {
- /* move rest down make it available for later */
- memmove(file->buffer,
- &file->buffer[want],
- (file->buffer_pos - want));
-
- file->buffer_pos -= want;
- }
- return 0;
-}
-
-URL_FILE *url_fopen(const char *url,const char *operation)
-{
- /* this code could check for URLs or types in the 'url' and
- basicly use the real fopen() for standard files */
-
- URL_FILE *file;
- (void)operation;
-
- file = (URL_FILE*)malloc(sizeof(URL_FILE));
- if(!file)
- return NULL;
-
- memset(file, 0, sizeof(URL_FILE));
-
- if((file->handle.file=fopen(url,operation)))
- file->type = CFTYPE_FILE; /* marked as URL */
-
- else {
- file->type = CFTYPE_CURL; /* marked as URL */
- file->handle.curl = curl_easy_init();
-
- curl_easy_setopt(file->handle.curl, CURLOPT_URL, url);
- curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file);
- curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0L);
- curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback);
-
- if(!multi_handle)
- multi_handle = curl_multi_init();
-
- curl_multi_add_handle(multi_handle, file->handle.curl);
-
- /* lets start the fetch */
- curl_multi_perform(multi_handle, &file->still_running);
-
- if((file->buffer_pos == 0) && (!file->still_running)) {
- /* if still_running is 0 now, we should return NULL */
-
- /* make sure the easy handle is not in the multi handle anymore */
- curl_multi_remove_handle(multi_handle, file->handle.curl);
-
- /* cleanup */
- curl_easy_cleanup(file->handle.curl);
-
- free(file);
-
- file = NULL;
- }
- }
- return file;
-}
-
-int url_fclose(URL_FILE *file)
-{
- int ret=0;/* default is good return */
-
- switch(file->type) {
- case CFTYPE_FILE:
- ret=fclose(file->handle.file); /* passthrough */
- break;
-
- case CFTYPE_CURL:
- /* make sure the easy handle is not in the multi handle anymore */
- curl_multi_remove_handle(multi_handle, file->handle.curl);
-
- /* cleanup */
- curl_easy_cleanup(file->handle.curl);
- break;
-
- default: /* unknown or supported type - oh dear */
- ret=EOF;
- errno=EBADF;
- break;
- }
-
- if(file->buffer)
- free(file->buffer);/* free any allocated buffer space */
-
- free(file);
-
- return ret;
-}
-
-int url_feof(URL_FILE *file)
-{
- int ret=0;
-
- switch(file->type) {
- case CFTYPE_FILE:
- ret=feof(file->handle.file);
- break;
-
- case CFTYPE_CURL:
- if((file->buffer_pos == 0) && (!file->still_running))
- ret = 1;
- break;
-
- default: /* unknown or supported type - oh dear */
- ret=-1;
- errno=EBADF;
- break;
- }
- return ret;
-}
-
-size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file)
-{
- size_t want;
-
- switch(file->type) {
- case CFTYPE_FILE:
- want=fread(ptr,size,nmemb,file->handle.file);
- break;
-
- case CFTYPE_CURL:
- want = nmemb * size;
-
- fill_buffer(file,want);
-
- /* check if theres data in the buffer - if not fill_buffer()
- * either errored or EOF */
- if(!file->buffer_pos)
- return 0;
-
- /* ensure only available data is considered */
- if(file->buffer_pos < want)
- want = file->buffer_pos;
-
- /* xfer data to caller */
- memcpy(ptr, file->buffer, want);
-
- use_buffer(file,want);
-
- want = want / size; /* number of items */
- break;
-
- default: /* unknown or supported type - oh dear */
- want=0;
- errno=EBADF;
- break;
-
- }
- return want;
-}
-
-char *url_fgets(char *ptr, size_t size, URL_FILE *file)
-{
- size_t want = size - 1;/* always need to leave room for zero termination */
- size_t loop;
-
- switch(file->type) {
- case CFTYPE_FILE:
- ptr = fgets(ptr,size,file->handle.file);
- break;
-
- case CFTYPE_CURL:
- fill_buffer(file,want);
-
- /* check if theres data in the buffer - if not fill either errored or
- * EOF */
- if(!file->buffer_pos)
- return NULL;
-
- /* ensure only available data is considered */
- if(file->buffer_pos < want)
- want = file->buffer_pos;
-
- /*buffer contains data */
- /* look for newline or eof */
- for(loop=0;loop < want;loop++) {
- if(file->buffer[loop] == '\n') {
- want=loop+1;/* include newline */
- break;
- }
- }
-
- /* xfer data to caller */
- memcpy(ptr, file->buffer, want);
- ptr[want]=0;/* allways null terminate */
-
- use_buffer(file,want);
-
- break;
-
- default: /* unknown or supported type - oh dear */
- ptr=NULL;
- errno=EBADF;
- break;
- }
-
- return ptr;/*success */
-}
-
-void url_rewind(URL_FILE *file)
-{
- switch(file->type) {
- case CFTYPE_FILE:
- rewind(file->handle.file); /* passthrough */
- break;
-
- case CFTYPE_CURL:
- /* halt transaction */
- curl_multi_remove_handle(multi_handle, file->handle.curl);
-
- /* restart */
- curl_multi_add_handle(multi_handle, file->handle.curl);
-
- /* ditch buffer - write will recreate - resets stream pos*/
- if(file->buffer)
- free(file->buffer);
-
- file->buffer=NULL;
- file->buffer_pos=0;
- file->buffer_len=0;
-
- break;
-
- default: /* unknown or supported type - oh dear */
- break;
- }
-}
- \ No newline at end of file
diff --git a/src/uscxml/Utilities.h b/src/uscxml/Utilities.h
deleted file mode 100644
index 8816c72..0000000
--- a/src/uscxml/Utilities.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef UTILITIES_H_A89E99LI
-#define UTILITIES_H_A89E99LI
-
-#include <string>
-#include <sstream>
-#include <curl/curl.h>
-
-// see http://stackoverflow.com/questions/228005/alternative-to-itoa-for-converting-integer-to-string-c
-template <typename T> std::string toStr(T tmp) {
- std::ostringstream out;
- out << tmp;
- return out.str();
-}
-
-template <typename T> T strTo(std::string tmp) {
- T output;
- std::istringstream in(tmp);
- in >> output;
- return output;
-}
-
-enum fcurl_type_e {
- CFTYPE_NONE=0,
- CFTYPE_FILE=1,
- CFTYPE_CURL=2
-};
-
-struct fcurl_data
-{
- enum fcurl_type_e type; /* type of handle */
- union {
- CURL *curl;
- FILE *file;
- } handle; /* handle */
-
- char *buffer; /* buffer to store cached data*/
- size_t buffer_len; /* currently allocated buffers length */
- size_t buffer_pos; /* end of data in buffer*/
- int still_running; /* Is background url fetch still in progress */
-};
-
-typedef struct fcurl_data URL_FILE;
-
-URL_FILE *url_fopen(const char *url,const char *operation);
-int url_fclose(URL_FILE *file);
-int url_feof(URL_FILE *file);
-size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file);
-char * url_fgets(char *ptr, size_t size, URL_FILE *file);
-void url_rewind(URL_FILE *file);
-
-#endif /* end of include guard: UTILITIES_H_A89E99LI */
diff --git a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp
index 170e5d9..e2a89b2 100644
--- a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp
+++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp
@@ -1,4 +1,4 @@
-#include "uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h"
+#include "DelayedEventQueue.h"
#include <assert.h>
#include <event2/event.h>
diff --git a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h
index 024e353..024e353 100644
--- a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h
+++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h
diff --git a/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.cpp b/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.cpp
deleted file mode 100644
index a93b14a..0000000
--- a/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-#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
deleted file mode 100644
index 2bc71b2..0000000
--- a/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#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/ioprocessor/basichttp/README.md b/src/uscxml/ioprocessor/basichttp/README.md
deleted file mode 100644
index de89944..0000000
--- a/src/uscxml/ioprocessor/basichttp/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-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/mongoose/MongooseIOProcessor.cpp b/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.cpp
deleted file mode 100644
index a62fefc..0000000
--- a/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#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
deleted file mode 100644
index bb7a0fc..0000000
--- a/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#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
deleted file mode 100644
index 7aa9169..0000000
--- a/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-#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
deleted file mode 100644
index 154acdb..0000000
--- a/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#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/src/uscxml/plugins/Plugins.cpp b/src/uscxml/plugins/Plugins.cpp
new file mode 100644
index 0000000..4e819bb
--- /dev/null
+++ b/src/uscxml/plugins/Plugins.cpp
@@ -0,0 +1,11 @@
+#include "Plugins.h"
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_PROVIDER_SOURCE(DataModel, 1, 1);
+PLUMA_PROVIDER_SOURCE(IOProcessor, 1, 1);
+PLUMA_PROVIDER_SOURCE(Invoker, 1, 1);
+#endif
+
+} \ No newline at end of file
diff --git a/src/uscxml/plugins/Plugins.h b/src/uscxml/plugins/Plugins.h
new file mode 100644
index 0000000..56dd1e2
--- /dev/null
+++ b/src/uscxml/plugins/Plugins.h
@@ -0,0 +1,17 @@
+#ifndef PLUGINS_H_M6G1NF1E
+#define PLUGINS_H_M6G1NF1E
+
+#include <Pluma/Pluma.hpp>
+#include "uscxml/Factory.h"
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_PROVIDER_HEADER(IOProcessor);
+PLUMA_PROVIDER_HEADER(Invoker);
+PLUMA_PROVIDER_HEADER(DataModel);
+#endif
+
+}
+
+#endif /* end of include guard: PLUGINS_H_M6G1NF1E */
diff --git a/src/uscxml/plugins/Pluma/Config.hpp b/src/uscxml/plugins/Pluma/Config.hpp
new file mode 100755
index 0000000..efd98c9
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Config.hpp
@@ -0,0 +1,141 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+//
+// Based on SFML configuration header
+// SFML Config.hpp:
+// http://www.sfml-dev.org/documentation/2.0/Config_8hpp-source.htm
+//
+// Acknowledgements to Simple and Fast Multimedia Library
+// http://www.sfml-dev.org/
+//
+////////////////////////////////////////////////////////////
+
+
+#ifndef PLUMA_CONFIG_HPP
+#define PLUMA_CONFIG_HPP
+
+
+////////////////////////////////////////////////////////////
+// Identify the operating system
+////////////////////////////////////////////////////////////
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+
+ // Windows
+ #define PLUMA_SYS_WINDOWS
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+ #ifndef NOMINMAX
+ #define NOMINMAX
+ #endif
+
+#elif defined(linux) || defined(__linux)
+
+ // Linux
+ #define PLUMA_SYS_LINUX
+
+#elif defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh)
+
+ // MacOS
+ #define PLUMA_SYS_MACOS
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+
+ // FreeBSD
+ #define PLUMA_SYS_FREEBSD
+
+#else
+
+ // Unsupported system
+ #error This operating system is not supported by this library
+
+#endif
+
+
+
+////////////////////////////////////////////////////////////
+// Define library file extension based on OS
+////////////////////////////////////////////////////////////
+#ifdef PLUMA_SYS_WINDOWS
+ #define PLUMA_LIB_EXTENSION "dll"
+#elif defined(PLUMA_SYS_MACOS)
+ #define PLUMA_LIB_EXTENSION "dylib"
+#elif defined(PLUMA_SYS_LINUX) || defined(PLUMA_SYS_FREEBSD)
+ #define PLUMA_LIB_EXTENSION "so"
+#else
+ // unknown library file type
+ #error Unknown library file extension for this operating system
+#endif
+
+
+////////////////////////////////////////////////////////////
+// Define portable import / export macros
+////////////////////////////////////////////////////////////
+#if defined(PLUMA_SYS_WINDOWS)
+
+ #ifndef PLUMA_STATIC
+
+ // Windows platforms
+ #ifdef PLUMA_EXPORTS
+
+ // From DLL side, we must export
+ #define PLUMA_API __declspec(dllexport)
+
+ #else
+
+ // From client application side, we must import
+ #define PLUMA_API __declspec(dllimport)
+
+ #endif
+
+ // For Visual C++ compilers, we also need to turn off this annoying C4251 warning.
+ // You can read lots ot different things about it, but the point is the code will
+ // just work fine, and so the simplest way to get rid of this warning is to disable it
+ #ifdef _MSC_VER
+
+ #pragma warning(disable : 4251)
+
+ #endif
+
+ #else
+
+ // No specific directive needed for static build
+ #define PLUMA_API
+
+ #endif
+
+#else
+
+ // Other platforms don't need to define anything
+ #define PLUMA_API
+
+#endif
+
+
+
+
+#endif // PLUMA_CONFIG_HPP
diff --git a/src/uscxml/plugins/Pluma/Connector.hpp b/src/uscxml/plugins/Pluma/Connector.hpp
new file mode 100755
index 0000000..3c227e7
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Connector.hpp
@@ -0,0 +1,86 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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 PLUMA_CONNECTOR_HPP
+#define PLUMA_CONNECTOR_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Pluma.hpp>
+
+
+/////////////////////////////////////////////////////////////////
+// Define portable import/export macros for Plugin registration
+/////////////////////////////////////////////////////////////////
+#if defined(PLUMA_SYS_WINDOWS)
+
+ #ifndef PLUMA_STATIC_PLUGIN
+
+ // Windows platforms
+ #ifndef PLUGIN_IMPORTS
+
+ // From DLL side, we must export
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C" __declspec(dllexport)
+ #else
+ #define PLUMA_CONNECTOR __declspec(dllexport)
+ #endif
+
+ #else
+
+ // From client application side, we must import
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C" __declspec(dllimport)
+ #else
+ #define PLUMA_CONNECTOR __declspec(dllimport)
+ #endif
+
+ #endif
+
+ #else
+
+ // Only define the extern "C" for static build
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C"
+ #else
+ #define PLUMA_CONNECTOR
+ #endif
+
+ #endif
+
+#else
+
+ // Only define the extern "C" for other platforms
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C"
+ #else
+ #define PLUMA_CONNECTOR
+ #endif
+
+#endif
+
+
+#endif // PLUMA_CONNECTOR_HPP
diff --git a/src/uscxml/plugins/Pluma/DLibrary.cpp b/src/uscxml/plugins/Pluma/DLibrary.cpp
new file mode 100755
index 0000000..9b617db
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/DLibrary.cpp
@@ -0,0 +1,106 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/DLibrary.hpp>
+#include <cstdio>
+#include <string>
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+DLibrary* DLibrary::load(const std::string& path){
+ if ( path.empty() ){
+ fprintf(stderr, "Failed to load library: Empty path\n");
+ return NULL;
+ }
+ void* handle = NULL;
+
+ // load library - OS dependent operation
+ #ifdef PLUMA_SYS_WINDOWS
+ handle = ::LoadLibraryA(path.c_str());
+ if (!handle){
+ fprintf(stderr, "Failed to load library \"%s\".\n", path.c_str());
+ return NULL;
+ }
+ #else
+ handle = ::dlopen(path.c_str(), RTLD_NOW);
+ if (!handle){
+ const char* errorString = ::dlerror();
+ fprintf(stderr, "Failed to load library \"%s\".", path.c_str());
+ if(errorString) fprintf(stderr, " OS returned error: \"%s\".", errorString);
+ fprintf(stderr, "\n");
+ return NULL;
+ }
+ #endif
+ // return a DLibrary with the DLL handle
+ return new DLibrary(handle);
+}
+
+
+////////////////////////////////////////////////////////////
+DLibrary::~DLibrary(){
+ if (handle){
+ #ifdef PLUMA_SYS_WINDOWS
+ ::FreeLibrary( (HMODULE)handle );
+ #else
+ ::dlclose(handle);
+ #endif
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void* DLibrary::getSymbol(const std::string& symbol){
+ if (!handle){
+ fprintf(stderr, "Cannot inspect library symbols, library isn't loaded.\n");
+ return NULL;
+ }
+ void* res;
+ #ifdef PLUMA_SYS_WINDOWS
+ res = (void*)(::GetProcAddress((HMODULE)handle, symbol.c_str()));
+ #else
+ res = (void*)(::dlsym(handle, symbol.c_str()));
+ #endif
+ if (!res){
+ fprintf(stderr, "Library symbol \"%s\" not found.\n", symbol.c_str());
+ return NULL;
+ }
+ return res;
+}
+
+
+////////////////////////////////////////////////////////////
+DLibrary::DLibrary(void* handle):
+ handle(handle)
+{
+ // Nothing to do
+}
+
+} // namespace pluma
+
diff --git a/src/uscxml/plugins/Pluma/DLibrary.hpp b/src/uscxml/plugins/Pluma/DLibrary.hpp
new file mode 100755
index 0000000..1bb9bac
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/DLibrary.hpp
@@ -0,0 +1,123 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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 PLUMA_DYNAMIC_LIBRARY_HPP
+#define PLUMA_DYNAMIC_LIBRARY_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <string>
+
+// include OS dependent support for DLL
+#ifdef PLUMA_SYS_WINDOWS
+ #include <Windows.h>
+#else
+ #include <dlfcn.h>
+#endif
+
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+/// \brief Manages a Dynamic Linking Library.
+///
+////////////////////////////////////////////////////////////
+class DLibrary{
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load a library.
+ ///
+ /// \param path Path to the library.
+ ///
+ /// \return Pointer to the loaded library, or NULL if failed.
+ ///
+ ////////////////////////////////////////////////////////////
+ static DLibrary* load(const std::string& path);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ /// Close and free the opened library (if any).
+ ///
+ ////////////////////////////////////////////////////////////
+ ~DLibrary();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get a symbol from the library.
+ ///
+ /// \param symbol Symbol that we're looking for.
+ ///
+ /// \return Pointer to what the symbol refers to, or NULL if
+ /// the symbol is not found.
+ ///
+ ////////////////////////////////////////////////////////////
+ void* getSymbol(const std::string& symbol);
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor.
+ ///
+ /// Library instances cannot be created, use load instead.
+ ///
+ /// \see load
+ ///
+ ////////////////////////////////////////////////////////////
+ DLibrary();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Constructor via library handle.
+ ///
+ /// Used on load function.
+ ///
+ /// \see load
+ ///
+ ////////////////////////////////////////////////////////////
+ DLibrary(void* handle);
+
+
+
+////////////////////////////////////////////////////////////
+// Member data
+////////////////////////////////////////////////////////////
+
+
+private:
+
+ void* handle; ///< Library handle.
+
+};
+
+
+} // namespace pluma
+
+
+#endif // PLUMA_DYNAMIC_LIBRARY_HPP
diff --git a/src/uscxml/plugins/Pluma/Dir.cpp b/src/uscxml/plugins/Pluma/Dir.cpp
new file mode 100755
index 0000000..860220e
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Dir.cpp
@@ -0,0 +1,103 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Dir.hpp>
+#include <Pluma/uce-dirent.h>
+#include <cstdio>
+#include <queue>
+
+
+namespace pluma{
+
+namespace dir{
+
+
+////////////////////////////////////////////////////////////
+void listFiles(std::list<std::string>& list, const std::string& folder, const std::string& extension, bool recursive){
+ DIR* dir;
+ DIR* subDir;
+ struct dirent *ent;
+ // try to open top folder
+ dir = opendir(folder.c_str());
+ if (dir == NULL){
+ // could not open directory
+ fprintf(stderr, "Could not open \"%s\" directory.\n", folder.c_str());
+ return;
+ }else{
+ // close, we'll process it next
+ closedir(dir);
+ }
+ // enqueue top folder
+ std::queue<std::string> folders;
+ folders.push(folder);
+
+ // run while has queued folders
+ while (!folders.empty()){
+ std::string currFolder = folders.front();
+ folders.pop();
+ dir = opendir(currFolder.c_str());
+ if (dir == NULL) continue;
+ // iterate through all the files and directories
+ while ((ent = readdir (dir)) != NULL) {
+ std::string name(ent->d_name);
+ // ignore "." and ".." directories
+ if ( name.compare(".") == 0 || name.compare("..") == 0) continue;
+ // add path to the file name
+ std::string path = currFolder;
+ path.append("/");
+ path.append(name);
+ // check if it's a folder by trying to open it
+ subDir = opendir(path.c_str());
+ if (subDir != NULL){
+ // it's a folder: close, we can process it later
+ closedir(subDir);
+ if (recursive) folders.push(path);
+ }else{
+ // it's a file
+ if (extension.empty()){
+ list.push_back(path);
+ }else{
+ // check file extension
+ size_t lastDot = name.find_last_of('.');
+ std::string ext = name.substr(lastDot+1);
+ if (ext.compare(extension) == 0){
+ // match
+ list.push_back(path);
+ }
+ } // endif (extension test)
+ } // endif (folder test)
+ } // endwhile (nextFile)
+ closedir(dir);
+ } // endwhile (queued folders)
+
+} // end listFiles
+
+
+} // namespace dir
+
+} // namespace pluma
diff --git a/src/uscxml/plugins/Pluma/Dir.hpp b/src/uscxml/plugins/Pluma/Dir.hpp
new file mode 100755
index 0000000..a94c477
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Dir.hpp
@@ -0,0 +1,64 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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 PLUMA_DIRECTORY_HPP
+#define PLUMA_DIRECTORY_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <string>
+#include <list>
+
+
+namespace pluma{
+
+namespace dir{
+
+////////////////////////////////////////////////////////////
+/// \brief List files of a directory.
+///
+/// \param list The output files list.
+/// \param folder The folder where to search in
+/// \param extension A file extension filter,
+/// empty extension will match all files.
+/// \param recursive If true it will list files in
+/// sub directories as well.
+///
+////////////////////////////////////////////////////////////
+void listFiles(
+ std::list<std::string>& list,
+ const std::string& folder,
+ const std::string& extension = "",
+ bool recursive = false
+);
+
+
+} // namespace dir
+
+} // namespace pluma
+
+
+#endif // PLUMA_DIRECTORY_HPP
diff --git a/src/uscxml/plugins/Pluma/Host.cpp b/src/uscxml/plugins/Pluma/Host.cpp
new file mode 100755
index 0000000..eb37c33
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Host.cpp
@@ -0,0 +1,179 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Host.hpp>
+#include <cstdio>
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+Host::Host(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::add(Provider* provider){
+ if (provider == NULL){
+ fprintf(stderr, "Trying to add a null provider.\n");
+ return false;
+ }
+ if (!validateProvider(provider)){
+ delete provider;
+ return false;
+ }
+ addRequests[ provider->plumaGetType() ].push_back(provider);
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+Host::~Host(){
+ clearProviders();
+ // map frees itself
+}
+
+
+////////////////////////////////////////////////////////////
+void Host::clearProviders(){
+ ProvidersMap::iterator it;
+ for (it = knownTypes.begin() ; it != knownTypes.end() ; ++it){
+ std::list<Provider*>& providers = it->second.providers;
+ std::list<Provider*>::iterator provIt;
+ for (provIt = providers.begin() ; provIt != providers.end() ; ++provIt){
+ delete *provIt;
+ }
+ std::list<Provider*>().swap(providers);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::knows(const std::string& type) const{
+ return knownTypes.find(type) != knownTypes.end();
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Host::getVersion(const std::string& type) const{
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return it->second.version;
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Host::getLowestVersion(const std::string& type) const{
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return it->second.lowestVersion;
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+void Host::registerType(const std::string& type, unsigned int version, unsigned int lowestVersion){
+ if (!knows(type)){
+ ProviderInfo pi;
+ pi.version = version;
+ pi.lowestVersion = lowestVersion;
+ knownTypes[type] = pi;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+const std::list<Provider*>* Host::getProviders(const std::string& type) const{
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return &it->second.providers;
+ return NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::validateProvider(Provider* provider) const{
+ const std::string& type = provider->plumaGetType();
+ if ( !knows(type) ){
+ fprintf(stderr, "%s provider type isn't registered.\n", type.c_str());
+ return false;
+ }
+ if (!provider->isCompatible(*this)){
+ fprintf(stderr, "Incompatible %s provider version.\n", type.c_str());
+ return false;
+ }
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::registerProvider(Provider* provider){
+ if (!validateProvider(provider)){
+ delete provider;
+ return false;
+ }
+ knownTypes[ provider->plumaGetType() ].providers.push_back(provider);
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void Host::cancelAddictions(){
+ TempProvidersMap::iterator it;
+ for( it = addRequests.begin() ; it != addRequests.end() ; ++it){
+ std::list<Provider*> lst = it->second;
+ std::list<Provider*>::iterator providerIt;
+ for (providerIt = lst.begin() ; providerIt != lst.end() ; ++providerIt){
+ delete *providerIt;
+ }
+ }
+ // clear map
+ TempProvidersMap().swap(addRequests);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::confirmAddictions(){
+ if (addRequests.empty()) return false;
+ TempProvidersMap::iterator it;
+ for( it = addRequests.begin() ; it != addRequests.end() ; ++it){
+ std::list<Provider*> lst = it->second;
+ std::list<Provider*>::iterator providerIt;
+ for (providerIt = lst.begin() ; providerIt != lst.end() ; ++providerIt){
+ knownTypes[it->first].providers.push_back(*providerIt);
+ }
+ }
+ // clear map
+ TempProvidersMap().swap(addRequests);
+ return true;
+}
+
+
+} //namespace pluma
diff --git a/src/uscxml/plugins/Pluma/Host.hpp b/src/uscxml/plugins/Pluma/Host.hpp
new file mode 100755
index 0000000..cf049f5
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Host.hpp
@@ -0,0 +1,212 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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 PLUMA_HOST_HPP
+#define PLUMA_HOST_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Provider.hpp>
+
+#include <vector>
+#include <list>
+#include <map>
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+/// \brief Manages providers.
+///
+////////////////////////////////////////////////////////////
+class PLUMA_API Host{
+friend class PluginManager;
+friend class Provider;
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Add provider.
+ ///
+ /// Provider type and version are checked. Only known and
+ /// valid provider types are accepted.
+ ///
+ /// \param provider Provider to be added.
+ ///
+ /// \return True if the provider is accepted.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool add(Provider* provider);
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor.
+ ///
+ /// New Host instances are not publicly allowed.
+ ///
+ ////////////////////////////////////////////////////////////
+ Host();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ /// Clears all hosted providers
+ ///
+ ////////////////////////////////////////////////////////////
+ ~Host();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Ckeck if a provider type is registered.
+ ///
+ /// \param type Provider type id.
+ ///
+ /// \return True if the type is registered
+ ///
+ ////////////////////////////////////////////////////////////
+ bool knows(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get version of a type of providers.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return The version of the provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ unsigned int getVersion(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get lowest compatible version of a type of providers.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return The lowest compatible version of the provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ unsigned int getLowestVersion(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Register a type of providers.
+ ///
+ /// \param type Provider type.
+ /// \param version Current version of that provider type.
+ /// \param lowestVersion Lowest compatible version of that provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ void registerType(const std::string& type, unsigned int version, unsigned int lowestVersion);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get providers of a certain type.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return Pointer to the list of providers of that \a type,
+ /// or NULL if \a type is not registered.
+ ///
+ ////////////////////////////////////////////////////////////
+ const std::list<Provider*>* getProviders(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Clears all hosted providers.
+ ///
+ ////////////////////////////////////////////////////////////
+ void clearProviders();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Validate provider type and version.
+ ///
+ /// \return True if the provider is acceptable.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool validateProvider(Provider* provider) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Clearly add a provider.
+ ///
+ /// Provider type and version are checked. Only known and
+ /// valid provider types are accepted.
+ /// If acepted, provider is directly stored.
+ ///
+ /// \param provider Provider to be added.
+ ///
+ /// \return True if the provider is accepted.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool registerProvider(Provider* provider);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Previous add calls are canceled.
+ ///
+ /// Added providers are not stored.
+ ///
+ /// \see add
+ ///
+ ////////////////////////////////////////////////////////////
+ void cancelAddictions();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Previous add calls are confirmed.
+ ///
+ /// Added providers are finally stored.
+ ///
+ /// \return True if something was stored.
+ ///
+ /// \see add
+ ///
+ ////////////////////////////////////////////////////////////
+ bool confirmAddictions();
+
+
+
+////////////////////////////////////////////////////////////
+// Member data
+////////////////////////////////////////////////////////////
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Structure with information about a provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ struct ProviderInfo{
+ unsigned int version;
+ unsigned int lowestVersion;
+ std::list<Provider*> providers;
+ };
+
+ typedef std::map<std::string, ProviderInfo > ProvidersMap;
+ typedef std::map<std::string, std::list<Provider*> > TempProvidersMap;
+
+ ProvidersMap knownTypes; ///< Map of registered types.
+ TempProvidersMap addRequests; ///< Temporarily added providers
+
+};
+
+} // namespace pluma
+
+#endif // PLUMA_HOST_HPP
diff --git a/src/uscxml/plugins/Pluma/PluginManager.cpp b/src/uscxml/plugins/Pluma/PluginManager.cpp
new file mode 100755
index 0000000..1124505
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/PluginManager.cpp
@@ -0,0 +1,201 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/PluginManager.hpp>
+#include <Pluma/DLibrary.hpp>
+#include <Pluma/Dir.hpp>
+#include <cstdio>
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+PluginManager::PluginManager(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+PluginManager::~PluginManager(){
+ unloadAll();
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::load(const std::string& path){
+ std::string plugName = getPluginName(path);
+ std::string realPath = resolvePathExtension(path);
+ DLibrary* lib = DLibrary::load(realPath);
+ if (!lib) return false;
+
+ fnRegisterPlugin* registerFunction;
+ registerFunction = reinterpret_cast<fnRegisterPlugin*>(lib->getSymbol("connect"));
+
+ if(!registerFunction){
+ fprintf(stderr, "Failed to initialize plugin \"%s\": connect function not found\n", plugName.c_str());
+ delete lib;
+ return false;
+ }
+ // try to initialize plugin:
+ if (!registerFunction(host)){
+ // plugin decided to fail
+ fprintf(stderr, "Self registry failed on plugin \"%s\".\n", plugName.c_str());
+ host.cancelAddictions();
+ delete lib;
+ return false;
+ }
+ // Store the library if addictions are confirmed
+ if (host.confirmAddictions())
+ libraries[plugName] = lib;
+ else{
+ // otherwise nothing was registered
+ fprintf(stderr, "Nothing registered by plugin \"%s\".\n", plugName.c_str());
+ delete lib;
+ return false;
+ }
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::load(const std::string& folder, const std::string& pluginName){
+ if (folder.empty())
+ return load(pluginName);
+ else if (folder[folder.size()-1] == '/' || folder[folder.size()-1] == '\\')
+ return load(folder + pluginName);
+ return load(folder + '/' + pluginName);
+}
+
+
+////////////////////////////////////////////////////////////
+int PluginManager::loadFromFolder(const std::string& folder, bool recursive){
+ std::list<std::string> files;
+ dir::listFiles(files, folder, PLUMA_LIB_EXTENSION, recursive);
+ // try to load every library
+ int res = 0;
+ std::list<std::string>::const_iterator it;
+ for (it = files.begin() ; it != files.end() ; ++it){
+ if ( load(*it) ) ++res;
+ }
+ return res;
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::unload(const std::string& pluginName){
+ std::string plugName = getPluginName(pluginName);
+ LibMap::iterator it = libraries.find(plugName);
+ if( it != libraries.end() ) {
+ delete it->second;
+ libraries.erase(it);
+ return true;
+ }
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void PluginManager::unloadAll(){
+
+ host.clearProviders();
+ LibMap::iterator it;
+ for (it = libraries.begin() ; it != libraries.end() ; ++it){
+ delete it->second;
+ }
+ libraries.clear();
+}
+
+
+////////////////////////////////////////////////////////////
+std::string PluginManager::getPluginName(const std::string& path){
+ size_t lastDash = path.find_last_of("/\\");
+ size_t lastDot = path.find_last_of('.');
+ if (lastDash == std::string::npos) lastDash = 0;
+ else ++lastDash;
+ if (lastDot < lastDash || lastDot == std::string::npos){
+ // path without extension
+ lastDot = path.length();
+ }
+ return path.substr(lastDash, lastDot-lastDash);
+}
+
+
+////////////////////////////////////////////////////////////
+std::string PluginManager::resolvePathExtension(const std::string& path){
+ size_t lastDash = path.find_last_of("/\\");
+ size_t lastDot = path.find_last_of('.');
+ if (lastDash == std::string::npos) lastDash = 0;
+ else ++lastDash;
+ if (lastDot < lastDash || lastDot == std::string::npos){
+ // path without extension, add it
+ return path + "." + PLUMA_LIB_EXTENSION;
+ }
+ return path;
+}
+
+
+////////////////////////////////////////////////////////////
+void PluginManager::registerType(const std::string& type, unsigned int version, unsigned int lowestVersion){
+ host.registerType(type, version, lowestVersion);
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::addProvider(Provider* provider){
+ if (provider == NULL){
+ fprintf(stderr, "Trying to add null provider\n");
+ return false;
+ }
+ return host.registerProvider(provider);
+}
+
+
+////////////////////////////////////////////////////////////
+void PluginManager::getLoadedPlugins(std::vector<const std::string*>& pluginNames) const{
+ pluginNames.reserve(pluginNames.size()+libraries.size());
+ LibMap::const_iterator it;
+ for(it = libraries.begin() ; it != libraries.end() ; ++it){
+ pluginNames.push_back(&(it->first));
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::isLoaded(const std::string& pluginName) const{
+ return libraries.find(getPluginName(pluginName)) != libraries.end();
+}
+
+
+////////////////////////////////////////////////////////////
+const std::list<Provider*>* PluginManager::getProviders(const std::string& type) const{
+ return host.getProviders(type);
+}
+
+
+
+} // namespace pluma
+
diff --git a/src/uscxml/plugins/Pluma/PluginManager.hpp b/src/uscxml/plugins/Pluma/PluginManager.hpp
new file mode 100755
index 0000000..e5ddf06
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/PluginManager.hpp
@@ -0,0 +1,245 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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 PLUMA_PLUGIN_MANAGER_HPP
+#define PLUMA_PLUGIN_MANAGER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Host.hpp>
+
+#include <string>
+#include <map>
+
+namespace pluma{
+class DLibrary;
+
+////////////////////////////////////////////////////////////
+/// \brief Manages loaded plugins.
+///
+////////////////////////////////////////////////////////////
+class PLUMA_API PluginManager{
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ ////////////////////////////////////////////////////////////
+ ~PluginManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load a plugin given it's path
+ ///
+ /// \param path Path for the plugin, including plugin name. File extension
+ /// may be included, but is discouraged for better cross platform code.
+ /// If file extension isn't present on the path, Pluma will deduce it
+ /// from the operating system.
+ ///
+ /// \return True if the plugin is successfully loaded.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see loadFromFolder
+ /// \see unload
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ bool load(const std::string& path);
+
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load a plugin from a given folder
+ ///
+ /// \param folder The folder path.
+ /// \param pluginName Name of the plugin. File extension
+ /// may be included, but is discouraged for better cross platform code.
+ /// If file extension is omitted, Pluma will deduce it
+ /// from the operating system.
+ ///
+ /// \return True if the plugin is successfully loaded.
+ ///
+ /// \see load(const std::string&)
+ /// \see loadFromFolder
+ /// \see unload
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ bool load(const std::string& folder, const std::string& pluginName);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load all plugins from a given folder
+ ///
+ /// \param folder Path for the folder where the plug-ins are.
+ /// \param recursive If true it will search on sub-folders as well
+ ///
+ /// \return Number of successfully loaded plug-ins.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see unload
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ int loadFromFolder(const std::string& folder, bool recursive = false);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Unload a plugin.
+ ///
+ /// \param pluginName Name or path of the plugin.
+ ///
+ /// \return True if the plugin is successfully unloaded,
+ /// false if no such plugin exists on the manager.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see loadFromFolder
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ bool unload(const std::string& pluginName);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Unload all loaded plugins.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see loadFromFolder
+ /// \see unload
+ ///
+ ////////////////////////////////////////////////////////////
+ void unloadAll();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Directly add a new provider.
+ ///
+ /// \param provider Provider.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool addProvider(Provider* provider);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the name of all loaded plugins.
+ ///
+ /// \param pluginNames A vector to fill with the plugins names.
+ ///
+ ////////////////////////////////////////////////////////////
+ void getLoadedPlugins(std::vector<const std::string*>& pluginNames) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a plug-in is loaded.
+ ///
+ /// \param pluginName the plug-in tname o check.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool isLoaded(const std::string& pluginName) const;
+
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor.
+ ///
+ /// PluginManager cannot be publicly instantiated.
+ ///
+ ////////////////////////////////////////////////////////////
+ PluginManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Register a provider type
+ ///
+ /// \param type Provider type.
+ /// \param version Current version of that provider type.
+ /// \param lowestVersion Lowest compatible version of that provider type.
+ ///
+ /// \see Host::registerType
+ ///
+ ////////////////////////////////////////////////////////////
+ void registerType(const std::string& type, unsigned int version, unsigned int lowestVersion);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get providers of a certain type.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return Pointer to the list of providers of that \a type,
+ /// or NULL if \a type is not registered.
+ ///
+ /// \see Host::getProviders
+ ///
+ ////////////////////////////////////////////////////////////
+ const std::list<Provider*>* getProviders(const std::string& type) const;
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the plugin name (without extension) from its path
+ ///
+ /// \param path Plugin path.
+ ///
+ /// \return Name of the plugin.
+ ///
+ /// \see resolvePathExtension
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see unload
+ ///
+ ////////////////////////////////////////////////////////////
+ static std::string getPluginName(const std::string& path);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief If the plugin path omits it's extension, this method returns
+ /// the path plus the OS specific dll extension.
+ /// Return a copy of the path otherwise.
+ ///
+ /// \param path Plugin path.
+ ///
+ /// \return Path with extension.
+ ///
+ /// \see getPluginName
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see unload
+ ///
+ ////////////////////////////////////////////////////////////
+ static std::string resolvePathExtension(const std::string& path);
+
+
+private:
+
+ /// Signature for the plugin's registration function
+ typedef bool fnRegisterPlugin(Host&);
+ typedef std::map<std::string,DLibrary*> LibMap;
+
+ LibMap libraries; ///< Map containing the loaded libraries
+ Host host; ///< Host app proxy, holding all providers
+
+};
+
+} // namespace pluma
+
+#endif // PLUMA_PLUGIN_MANAGER_HPP
diff --git a/src/uscxml/plugins/Pluma/Pluma.hpp b/src/uscxml/plugins/Pluma/Pluma.hpp
new file mode 100755
index 0000000..a9d614e
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Pluma.hpp
@@ -0,0 +1,171 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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 PLUMA_PLUMA_HPP
+#define PLUMA_PLUMA_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Provider.hpp>
+#include <Pluma/PluginManager.hpp>
+
+////////////////////////////////////////////////////////////
+// Andy macro to convert parameter to string
+////////////////////////////////////////////////////////////
+#define PLUMA_2STRING(X) #X
+
+////////////////////////////////////////////////////////////
+// Macro that helps host applications defining
+// their provider classes
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_HEADER(TYPE)\
+PLUMA_PROVIDER_HEADER_BEGIN(TYPE)\
+virtual TYPE* create() const = 0;\
+PLUMA_PROVIDER_HEADER_END
+
+////////////////////////////////////////////////////////////
+// Macro that generate first part of the provider definition
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_HEADER_BEGIN(TYPE)\
+class TYPE##Provider: public pluma::Provider{\
+private:\
+ friend class pluma::Pluma;\
+ static const unsigned int PLUMA_INTERFACE_VERSION;\
+ static const unsigned int PLUMA_INTERFACE_LOWEST_VERSION;\
+ static const std::string PLUMA_PROVIDER_TYPE;\
+ std::string plumaGetType() const{ return PLUMA_PROVIDER_TYPE; }\
+public:\
+ unsigned int getVersion() const{ return PLUMA_INTERFACE_VERSION; }
+
+////////////////////////////////////////////////////////////
+// Macro that generate last part of the provider definition
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_HEADER_END };
+
+////////////////////////////////////////////////////////////
+// Macro that generate the provider declaration
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_SOURCE(TYPE, Version, LowestVersion)\
+const std::string TYPE##Provider::PLUMA_PROVIDER_TYPE = PLUMA_2STRING( TYPE );\
+const unsigned int TYPE##Provider::PLUMA_INTERFACE_VERSION = Version;\
+const unsigned int TYPE##Provider::PLUMA_INTERFACE_LOWEST_VERSION = LowestVersion;
+
+
+////////////////////////////////////////////////////////////
+// Macro that helps plugins generating their provider implementations
+// PRE: SPECIALIZED_TYPE must inherit from BASE_TYPE
+////////////////////////////////////////////////////////////
+#define PLUMA_INHERIT_PROVIDER(SPECIALIZED_TYPE, BASE_TYPE)\
+class SPECIALIZED_TYPE##Provider: public BASE_TYPE##Provider{\
+public:\
+ BASE_TYPE * create() const{ return new SPECIALIZED_TYPE (); }\
+};
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+/// \brief Pluma plugins management
+///
+////////////////////////////////////////////////////////////
+class Pluma: public PluginManager{
+
+public:
+ ////////////////////////////////////////////////////////////
+ /// \brief Default Constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ Pluma();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Tell Pluma to accept a certain type of providers
+ ///
+ /// A Pluma object is able to accept multiple types of providers.
+ /// When a plugin is loaded, it tries to register it's providers
+ /// implementations. Those are only accepted by the host
+ /// application if it's accepting providers of that kind.
+ ///
+ /// \tparam ProviderType type of provider.
+ ///
+ ////////////////////////////////////////////////////////////
+ template<typename ProviderType>
+ void acceptProviderType();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the stored providers of a certain type.
+ ///
+ /// Providers are added at the end of the \a providers vector.
+ ///
+ /// \tparam ProviderType type of provider to be returned.
+ /// \param[out] providers Vector to fill with the existing
+ /// providers.
+ ///
+ ////////////////////////////////////////////////////////////
+ template<typename ProviderType>
+ void getProviders(std::vector<ProviderType*>& providers);
+};
+
+#include <Pluma/Pluma.inl>
+
+}
+
+
+#endif // PLUMA_PLUMA_HPP
+
+
+////////////////////////////////////////////////////////////
+/// \class pluma::Pluma
+///
+/// Pluma is the main class of Pluma library. Allows hosting
+/// applications to load/unload dlls in runtime (plugins), and
+/// to get providers of shared interface objects.
+///
+/// Example:
+/// \code
+/// pluma::Pluma pluma;
+/// // Tell it to accept providers of the type DeviceProvider
+/// pluma.acceptProviderType<DeviceProvider>();
+/// // Load some dll
+/// pluma.load("plugins/standard_devices");
+/// // Get device providers into a vector
+/// std::vector<DeviceProvider*> providers;
+/// pluma.getProviders(providers);
+/// // create a Device from the first provider
+/// if (!providers.empty()){
+/// Device* myDevice = providers.first()->create();
+/// // do something with myDevice
+/// std::cout << device->getDescription() << std::endl;
+/// // (...)
+/// delete myDevice;
+/// }
+/// \endcode
+///
+/// It is also possible to add local providers, providers that
+/// are defined directly on the host application. That can
+/// be useful to provide and use default implementations of certain
+/// interfaces, along with plugin implementations.
+///
+////////////////////////////////////////////////////////////
diff --git a/src/uscxml/plugins/Pluma/Pluma.inl b/src/uscxml/plugins/Pluma/Pluma.inl
new file mode 100755
index 0000000..c3b6ce7
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Pluma.inl
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+inline Pluma::Pluma(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+template<typename ProviderType>
+void Pluma::acceptProviderType(){
+ PluginManager::registerType(
+ ProviderType::PLUMA_PROVIDER_TYPE,
+ ProviderType::PLUMA_INTERFACE_VERSION,
+ ProviderType::PLUMA_INTERFACE_LOWEST_VERSION
+ );
+}
+
+
+////////////////////////////////////////////////////////////
+template<typename ProviderType>
+void Pluma::getProviders(std::vector<ProviderType*>& providers){
+ const std::list<Provider*>* lst = PluginManager::getProviders(ProviderType::PLUMA_PROVIDER_TYPE);
+ if (!lst) return;
+ providers.reserve(providers.size() + lst->size());
+ std::list<Provider*>::const_iterator it;
+ for (it = lst->begin() ; it != lst->end() ; ++it)
+ providers.push_back(static_cast<ProviderType*>(*it));
+}
diff --git a/src/uscxml/plugins/Pluma/Provider.cpp b/src/uscxml/plugins/Pluma/Provider.cpp
new file mode 100755
index 0000000..36d4da3
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Provider.cpp
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Provider.hpp>
+#include <Pluma/Host.hpp>
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+Provider::~Provider(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+bool Provider::isCompatible(const Host& host) const{
+ // check compatibility with host
+ const std::string& type = this->plumaGetType();
+ if (!host.knows(type)) return false;
+ unsigned int lowest = host.getLowestVersion(type);
+ unsigned int current = host.getVersion(type);
+ unsigned int myVersion = this->getVersion();
+ return lowest <= myVersion && myVersion <= current;
+}
+
+} // namespace pluma
diff --git a/src/uscxml/plugins/Pluma/Provider.hpp b/src/uscxml/plugins/Pluma/Provider.hpp
new file mode 100755
index 0000000..ea06497
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Provider.hpp
@@ -0,0 +1,204 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// 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 PLUMA_PROVIDER_HPP
+#define PLUMA_PROVIDER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <string>
+
+
+namespace pluma{
+class Host;
+
+////////////////////////////////////////////////////////////
+/// \brief Interface to provide applications with objects from plugins.
+///
+////////////////////////////////////////////////////////////
+class PLUMA_API Provider{
+friend class Host;
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual ~Provider();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get provider version.
+ ///
+ /// \return Version number.
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual unsigned int getVersion() const = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check compatibility with host.
+ ///
+ /// The same provider may be compiled with different versions
+ /// on host side and on plugins side. This function checks if
+ /// a plugin provider is compatible with the current version of
+ /// the same provider type on the host side.
+ ///
+ /// \param host Host, proxy of host application.
+ ///
+ /// \return True if it's compatible with \a host.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool isCompatible(const Host& host) const;
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get provider type.
+ ///
+ /// Each provider defined on the host application is identified by
+ /// a unique type. Those types are automatically managed internally by
+ /// pluma.
+ ///
+ /// \return Provider type id.
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual std::string plumaGetType() const = 0;
+
+};
+
+} // namespace pluma
+
+
+#endif // PLUMA_PROVIDER_HPP
+
+
+////////////////////////////////////////////////////////////
+/// \class pluma::Provider
+/// The plugin specific implementations are unknown at the host side,
+/// only their shared interfaces are known. Then, host app needs a generic
+/// way of create interface objects. That's what provider classes are for.
+/// It is the factory design pattern
+/// (http://www.oodesign.com/factory-pattern.html)
+///
+/// Shared interfaces define their provider types (by inheriting from
+/// pluma::Provider). Hosts then use those tipes to get objects from the
+/// plugins.
+/// Plugins derive the shared interface providers so that they can provide
+/// host with specific implementations of the shared interface.
+/// Those specific providers are given to the host through a connect function.
+///
+///
+/// Example: A host app uses objects of type Device. A certain plugin
+/// defines a Keyboard, witch is a Device.
+/// The Host will use DeviceProviders to create objects of type Device.
+/// The plugin will provide host specifically with a KeyboardProvider.
+/// Other plugins may provide host with other derived DeviceProvider types.
+///
+/// Device hpp (shared):
+/// \code
+/// #include <Pluma/Pluma.hpp>
+/// class Device{
+/// public:
+/// virtual std::string getDescription() const = 0;
+/// };
+/// // create DevicedProvider class
+/// PLUMA_PROVIDER_HEADER(Device);
+/// \endcode
+///
+/// Device cpp (shared):
+/// \code
+/// #include "Device.hpp"
+/// generate DevicedProvider with version 6, and compatible with at least v.3
+/// PLUMA_PROVIDER_SOURCE(Device, 6, 3);
+/// \endcode
+///
+///
+/// <br>
+/// Keyboard code on the plugin side:
+/// \code
+/// #include <Pluma/Pluma.hpp>
+/// #include "Device.hpp"
+///
+/// class Keyboard: public Device{
+/// public:
+/// std::string getDescription() const{
+/// return "keyboard";
+/// }
+/// };
+///
+/// // create KeyboardProvider, it implements DeviceProvider
+/// PLUMA_INHERIT_PROVIDER(Keyboard, Device);
+/// \endcode
+///
+/// plugin connector:
+/// \code
+/// #include <Pluma/Connector.hpp>
+/// #include "Keyboard.hpp"
+///
+/// PLUMA_CONNECTOR
+/// bool connect(pluma::Host& host){
+/// // add a keyboard provider to host
+/// host.add( new KeyboardProvider() );
+/// return true;
+/// }
+/// \endcode
+///
+///
+/// Host application code:
+/// \code
+/// #include <Pluma/Pluma.hpp>
+///
+/// #include "Device.hpp"
+/// #include <iostream>
+/// #include <vector>
+///
+/// int main(){
+///
+/// pluma::Pluma plugins;
+/// // Tell plugins manager to accept providers of the type DeviceProvider
+/// plugins.acceptProviderType<DeviceProvider>();
+/// // Load library "standard_devices" from folder "plugins"
+/// plugins.load("plugins", "standard_devices");
+///
+/// // Get device providers into a vector
+/// std::vector<DeviceProvider*> providers;
+/// plugins.getProviders(providers);
+///
+/// // create a Device from the first provider
+/// if (!providers.empty()){
+/// Device* myDevice = providers.first()->create();
+/// // do something with myDevice
+/// std::cout << device->getDescription() << std::endl;
+/// // and delete it in the end
+/// delete myDevice;
+/// }
+/// return 0;
+/// }
+/// \endcode
+///
+////////////////////////////////////////////////////////////
diff --git a/src/uscxml/plugins/Pluma/uce-dirent.h b/src/uscxml/plugins/Pluma/uce-dirent.h
new file mode 100755
index 0000000..ecf78eb
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/uce-dirent.h
@@ -0,0 +1,679 @@
+/*
+ * uce-dirent.h - operating system independent dirent implementation
+ *
+ * Copyright (C) 1998-2002 Toni Ronkko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * ``Software''), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * May 28 1998, Toni Ronkko <tronkko@messi.uku.fi>
+ *
+ * $Id: uce-dirent.h,v 1.7 2002/05/13 10:48:35 tr Exp $
+ *
+ * $Log: uce-dirent.h,v $
+ * Revision 1.7 2002/05/13 10:48:35 tr
+ * embedded some source code directly to the header so that no source
+ * modules need to be included in the MS Visual C project using the
+ * interface, removed all the dependencies to other headers of the `uce'
+ * library so that the header can be made public
+ *
+ * Revision 1.6 2002/04/12 16:22:04 tr
+ * Unified Compiling Environment (UCE) replaced `std' library
+ *
+ * Revision 1.5 2001/07/20 16:33:40 tr
+ * moved to `std' library and re-named defines accordingly
+ *
+ * Revision 1.4 2001/07/10 16:47:18 tronkko
+ * revised comments
+ *
+ * Revision 1.3 2001/01/11 13:16:43 tr
+ * using ``uce-machine.h'' for finding out defines such as `FREEBSD'
+ *
+ * Revision 1.2 2000/10/08 16:00:41 tr
+ * copy of FreeBSD man page
+ *
+ * Revision 1.1 2000/07/10 05:53:16 tr
+ * Initial revision
+ *
+ * Revision 1.2 1998/07/19 18:29:14 tr
+ * Added error reporting capabilities and some asserts.
+ *
+ * Revision 1.1 1998/07/04 16:27:51 tr
+ * Initial revision
+ *
+ *
+ * MSVC 1.0 scans automatic dependencies incorrectly when your project
+ * contains this very header. The problem is that MSVC cannot handle
+ * include directives inside #if..#endif block those are never entered.
+ * Since this header ought to compile in many different operating systems,
+ * there had to be several conditional blocks that are compiled only in
+ * operating systems for what they were designed for. MSVC 1.0 cannot
+ * handle inclusion of sys/dir.h in a part that is compiled only in Apollo
+ * operating system. To fix the problem you need to insert DIR.H into
+ * SYSINCL.DAT located in MSVC\BIN directory and restart visual C++.
+ * Consult manuals for more informaton about the problem.
+ *
+ * Since many UNIX systems have dirent.h we assume to have one also.
+ * However, if your UNIX system does not have dirent.h you can download one
+ * for example at: http://ftp.uni-mannheim.de/ftp/GNU/dirent/dirent.tar.gz.
+ * You can also see if you have one of dirent.h, direct.h, dir.h, ndir.h,
+ * sys/dir.h and sys/ndir.h somewhere. Try defining HAVE_DIRENT_H,
+ * HAVE_DIRECT_H, HAVE_DIR_H, HAVE_NDIR_H, HAVE_SYS_DIR_H and
+ * HAVE_SYS_NDIR_H according to the files found.
+ */
+#ifndef DIRENT_H
+#define DIRENT_H
+#define DIRENT_H_INCLUDED
+
+/* find out platform */
+#if defined(MSDOS) /* MS-DOS */
+#elif defined(__MSDOS__) /* Turbo C/Borland */
+# define MSDOS
+#elif defined(__DOS__) /* Watcom */
+# define MSDOS
+#endif
+
+#if defined(WIN32) /* MS-Windows */
+#elif defined(__NT__) /* Watcom */
+# define WIN32
+#elif defined(_WIN32) /* Microsoft */
+# define WIN32
+#elif defined(__WIN32__) /* Borland */
+# define WIN32
+#endif
+
+/*
+ * See what kind of dirent interface we have unless autoconf has already
+ * determinated that.
+ */
+#if !defined(HAVE_DIRENT_H) && !defined(HAVE_DIRECT_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_NDIR_H) && !defined(HAVE_DIR_H)
+# if defined(_MSC_VER) /* Microsoft C/C++ */
+ /* no dirent.h */
+# elif defined(__BORLANDC__) /* Borland C/C++ */
+# define HAVE_DIRENT_H
+# define VOID_CLOSEDIR
+# elif defined(__TURBOC__) /* Borland Turbo C */
+ /* no dirent.h */
+# elif defined(__WATCOMC__) /* Watcom C/C++ */
+# define HAVE_DIRECT_H
+# elif defined(__apollo) /* Apollo */
+# define HAVE_SYS_DIR_H
+# elif defined(__hpux) /* HP-UX */
+# define HAVE_DIRENT_H
+# elif defined(__alpha) || defined(__alpha__) /* Alpha OSF1 */
+# error "not implemented"
+# elif defined(__sgi) /* Silicon Graphics */
+# define HAVE_DIRENT_H
+# elif defined(sun) || defined(_sun) /* Sun Solaris */
+# define HAVE_DIRENT_H
+# elif defined(__FreeBSD__) /* FreeBSD */
+# define HAVE_DIRENT_H
+# elif defined(__linux__) /* Linux */
+# define HAVE_DIRENT_H
+# elif defined(__GNUC__) /* GNU C/C++ */
+# define HAVE_DIRENT_H
+# else
+# error "not implemented"
+# endif
+#endif
+
+/* include proper interface headers */
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+# ifdef FREEBSD
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+# else
+# define NAMLEN(dp) ((int)(strlen((dp)->d_name)))
+# endif
+
+#elif defined(HAVE_NDIR_H)
+# include <ndir.h>
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(HAVE_SYS_NDIR_H)
+# include <sys/ndir.h>
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(HAVE_DIRECT_H)
+# include <direct.h>
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(HAVE_DIR_H)
+# include <dir.h>
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(HAVE_SYS_DIR_H)
+# include <sys/types.h>
+# include <sys/dir.h>
+# ifndef dirent
+# define dirent direct
+# endif
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(MSDOS) || defined(WIN32)
+
+ /* figure out type of underlaying directory interface to be used */
+# if defined(WIN32)
+# define DIRENT_WIN32_INTERFACE
+# elif defined(MSDOS)
+# define DIRENT_MSDOS_INTERFACE
+# else
+# error "missing native dirent interface"
+# endif
+
+ /*** WIN32 specifics ***/
+# if defined(DIRENT_WIN32_INTERFACE)
+# include <windows.h>
+# if !defined(DIRENT_MAXNAMLEN)
+# define DIRENT_MAXNAMLEN (MAX_PATH)
+# endif
+
+
+ /*** MS-DOS specifics ***/
+# elif defined(DIRENT_MSDOS_INTERFACE)
+# include <dos.h>
+
+ /* Borland defines file length macros in dir.h */
+# if defined(__BORLANDC__)
+# include <dir.h>
+# if !defined(DIRENT_MAXNAMLEN)
+# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT))
+# endif
+# if !defined(_find_t)
+# define _find_t find_t
+# endif
+
+ /* Turbo C defines ffblk structure in dir.h */
+# elif defined(__TURBOC__)
+# include <dir.h>
+# if !defined(DIRENT_MAXNAMLEN)
+# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT))
+# endif
+# define DIRENT_USE_FFBLK
+
+ /* MSVC */
+# elif defined(_MSC_VER)
+# if !defined(DIRENT_MAXNAMLEN)
+# define DIRENT_MAXNAMLEN (12)
+# endif
+
+ /* Watcom */
+# elif defined(__WATCOMC__)
+# if !defined(DIRENT_MAXNAMLEN)
+# if defined(__OS2__) || defined(__NT__)
+# define DIRENT_MAXNAMLEN (255)
+# else
+# define DIRENT_MAXNAMLEN (12)
+# endif
+# endif
+
+# endif
+# endif
+
+ /*** generic MS-DOS and MS-Windows stuff ***/
+# if !defined(NAME_MAX) && defined(DIRENT_MAXNAMLEN)
+# define NAME_MAX DIRENT_MAXNAMLEN
+# endif
+# if NAME_MAX < DIRENT_MAXNAMLEN
+# error "assertion failed: NAME_MAX >= DIRENT_MAXNAMLEN"
+# endif
+
+
+ /*
+ * Substitute for real dirent structure. Note that `d_name' field is a
+ * true character array although we have it copied in the implementation
+ * dependent data. We could save some memory if we had declared `d_name'
+ * as a pointer refering the name within implementation dependent data.
+ * We have not done that since some code may rely on sizeof(d_name) to be
+ * something other than four. Besides, directory entries are typically so
+ * small that it takes virtually no time to copy them from place to place.
+ */
+ typedef struct dirent {
+ char d_name[NAME_MAX + 1];
+
+ /*** Operating system specific part ***/
+# if defined(DIRENT_WIN32_INTERFACE) /*WIN32*/
+ WIN32_FIND_DATA data;
+# elif defined(DIRENT_MSDOS_INTERFACE) /*MSDOS*/
+# if defined(DIRENT_USE_FFBLK)
+ struct ffblk data;
+# else
+ struct _find_t data;
+# endif
+# endif
+ } dirent;
+
+ /* DIR substitute structure containing directory name. The name is
+ * essential for the operation of ``rewinndir'' function. */
+ typedef struct DIR {
+ char *dirname; /* directory being scanned */
+ dirent current; /* current entry */
+ int dirent_filled; /* is current un-processed? */
+
+ /*** Operating system specific part ***/
+# if defined(DIRENT_WIN32_INTERFACE)
+ HANDLE search_handle;
+# elif defined(DIRENT_MSDOS_INTERFACE)
+# endif
+ } DIR;
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* supply prototypes for dirent functions */
+static DIR *opendir (const char *dirname);
+static struct dirent *readdir (DIR *dirp);
+static int closedir (DIR *dirp);
+static void rewinddir (DIR *dirp);
+
+/*
+ * Implement dirent interface as static functions so that the user does not
+ * need to change his project in any way to use dirent function. With this
+ * it is sufficient to include this very header from source modules using
+ * dirent functions and the functions will be pulled in automatically.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+/* use ffblk instead of _find_t if requested */
+#if defined(DIRENT_USE_FFBLK)
+# define _A_ARCH (FA_ARCH)
+# define _A_HIDDEN (FA_HIDDEN)
+# define _A_NORMAL (0)
+# define _A_RDONLY (FA_RDONLY)
+# define _A_SUBDIR (FA_DIREC)
+# define _A_SYSTEM (FA_SYSTEM)
+# define _A_VOLID (FA_LABEL)
+# define _dos_findnext(dest) findnext(dest)
+# define _dos_findfirst(name,flags,dest) findfirst(name,dest,flags)
+#endif
+
+static int _initdir (DIR *p);
+static const char *_getdirname (const struct dirent *dp);
+static void _setdirname (struct DIR *dirp);
+
+/*
+ * <function name="opendir">
+ * <intro>open directory stream for reading
+ * <syntax>DIR *opendir (const char *dirname);
+ *
+ * <desc>Open named directory stream for read and return pointer to the
+ * internal working area that is used for retrieving individual directory
+ * entries. The internal working area has no fields of your interest.
+ *
+ * <ret>Returns a pointer to the internal working area or NULL in case the
+ * directory stream could not be opened. Global `errno' variable will set
+ * in case of error as follows:
+ *
+ * <table>
+ * [EACESS |Permission denied.
+ * [EMFILE |Too many open files used by the process.
+ * [ENFILE |Too many open files in system.
+ * [ENOENT |Directory does not exist.
+ * [ENOMEM |Insufficient memory.
+ * [ENOTDIR |dirname does not refer to directory. This value is not
+ * reliable on MS-DOS and MS-Windows platforms. Many
+ * implementations return ENOENT even when the name refers to a
+ * file.]
+ * </table>
+ * </function>
+ */
+static DIR *
+opendir(
+ const char *dirname)
+{
+ DIR *dirp;
+ assert (dirname != NULL);
+
+ dirp = (DIR*)malloc (sizeof (struct DIR));
+ if (dirp != NULL) {
+ char *p;
+
+ /* allocate room for directory name */
+ dirp->dirname = (char*) malloc (strlen (dirname) + 1 + strlen ("\\*.*"));
+ if (dirp->dirname == NULL) {
+ /* failed to duplicate directory name. errno set by malloc() */
+ free (dirp);
+ return NULL;
+ }
+ /* Copy directory name while appending directory separator and "*.*".
+ * Directory separator is not appended if the name already ends with
+ * drive or directory separator. Directory separator is assumed to be
+ * '/' or '\' and drive separator is assumed to be ':'. */
+ strcpy (dirp->dirname, dirname);
+ p = strchr (dirp->dirname, '\0');
+ if (dirp->dirname < p &&
+ *(p - 1) != '\\' && *(p - 1) != '/' && *(p - 1) != ':')
+ {
+ strcpy (p++, "/");
+ }
+# ifdef DIRENT_WIN32_INTERFACE
+ strcpy (p, "*"); /*scan files with and without extension in win32*/
+# else
+ strcpy (p, "*.*"); /*scan files with and without extension in DOS*/
+# endif
+
+ /* open stream */
+ if (_initdir (dirp) == 0) {
+ /* initialization failed */
+ free (dirp->dirname);
+ free (dirp);
+ return NULL;
+ }
+ }
+ return dirp;
+}
+
+
+/*
+ * <function name="readdir">
+ * <intro>read a directory entry
+ * <syntax>struct dirent *readdir (DIR *dirp);
+ *
+ * <desc>Read individual directory entry and return pointer to a structure
+ * containing the name of the entry. Individual directory entries returned
+ * include normal files, sub-directories, pseudo-directories "." and ".."
+ * and also volume labels, hidden files and system files in MS-DOS and
+ * MS-Windows. You might want to use stat(2) function to determinate which
+ * one are you dealing with. Many dirent implementations already contain
+ * equivalent information in dirent structure but you cannot depend on
+ * this.
+ *
+ * The dirent structure contains several system dependent fields that
+ * generally have no interest to you. The only interesting one is char
+ * d_name[] that is also portable across different systems. The d_name
+ * field contains the name of the directory entry without leading path.
+ * While d_name is portable across different systems the actual storage
+ * capacity of d_name varies from system to system and there is no portable
+ * way to find out it at compile time as different systems define the
+ * capacity of d_name with different macros and some systems do not define
+ * capacity at all (besides actual declaration of the field). If you really
+ * need to find out storage capacity of d_name then you might want to try
+ * NAME_MAX macro. The NAME_MAX is defined in POSIX standard althought
+ * there are many MS-DOS and MS-Windows implementations those do not define
+ * it. There are also systems that declare d_name as "char d_name[1]" and
+ * then allocate suitable amount of memory at run-time. Thanks to Alain
+ * Decamps (Alain.Decamps@advalvas.be) for pointing it out to me.
+ *
+ * This all leads to the fact that it is difficult to allocate space
+ * for the directory names when the very same program is being compiled on
+ * number of operating systems. Therefore I suggest that you always
+ * allocate space for directory names dynamically.
+ *
+ * <ret>
+ * Returns a pointer to a structure containing name of the directory entry
+ * in `d_name' field or NULL if there was an error. In case of an error the
+ * global `errno' variable will set as follows:
+ *
+ * <table>
+ * [EBADF |dir parameter refers to an invalid directory stream. This value
+ * is not set reliably on all implementations.]
+ * </table>
+ * </function>
+ */
+static struct dirent *
+readdir (DIR *dirp)
+{
+ assert (dirp != NULL);
+ if (dirp == NULL) {
+ errno = EBADF;
+ return NULL;
+ }
+
+#if defined(DIRENT_WIN32_INTERFACE)
+ if (dirp->search_handle == INVALID_HANDLE_VALUE) {
+ /* directory stream was opened/rewound incorrectly or it ended normally */
+ errno = EBADF;
+ return NULL;
+ }
+#endif
+
+ if (dirp->dirent_filled != 0) {
+ /*
+ * Directory entry has already been retrieved and there is no need to
+ * retrieve a new one. Directory entry will be retrieved in advance
+ * when the user calls readdir function for the first time. This is so
+ * because real dirent has separate functions for opening and reading
+ * the stream whereas Win32 and DOS dirents open the stream
+ * automatically when we retrieve the first file. Therefore, we have to
+ * save the first file when opening the stream and later we have to
+ * return the saved entry when the user tries to read the first entry.
+ */
+ dirp->dirent_filled = 0;
+ } else {
+ /* fill in entry and return that */
+#if defined(DIRENT_WIN32_INTERFACE)
+ if (FindNextFile (dirp->search_handle, &dirp->current.data) == FALSE) {
+ /* Last file has been processed or an error occured */
+ FindClose (dirp->search_handle);
+ dirp->search_handle = INVALID_HANDLE_VALUE;
+ errno = ENOENT;
+ return NULL;
+ }
+
+# elif defined(DIRENT_MSDOS_INTERFACE)
+ if (_dos_findnext (&dirp->current.data) != 0) {
+ /* _dos_findnext and findnext will set errno to ENOENT when no
+ * more entries could be retrieved. */
+ return NULL;
+ }
+# endif
+
+ _setdirname (dirp);
+ assert (dirp->dirent_filled == 0);
+ }
+ return &dirp->current;
+}
+
+
+/*
+ * <function name="closedir">
+ * <intro>close directory stream.
+ * <syntax>int closedir (DIR *dirp);
+ *
+ * <desc>Close directory stream opened by the `opendir' function. Close of
+ * directory stream invalidates the DIR structure as well as previously read
+ * dirent entry.
+ *
+ * <ret>The function typically returns 0 on success and -1 on failure but
+ * the function may be declared to return void on same systems. At least
+ * Borland C/C++ and some UNIX implementations use void as a return type.
+ * The dirent wrapper tries to define VOID_CLOSEDIR whenever closedir is
+ * known to return nothing. The very same definition is made by the GNU
+ * autoconf if you happen to use it.
+ *
+ * The global `errno' variable will set to EBADF in case of error.
+ * </function>
+ */
+static int
+closedir (DIR *dirp)
+{
+ int retcode = 0;
+
+ /* make sure that dirp points to legal structure */
+ assert (dirp != NULL);
+ if (dirp == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ /* free directory name and search handles */
+ if (dirp->dirname != NULL) free (dirp->dirname);
+
+#if defined(DIRENT_WIN32_INTERFACE)
+ if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+ if (FindClose (dirp->search_handle) == FALSE) {
+ /* Unknown error */
+ retcode = -1;
+ errno = EBADF;
+ }
+ }
+#endif
+
+ /* clear dirp structure to make sure that it cannot be used anymore*/
+ memset (dirp, 0, sizeof (*dirp));
+# if defined(DIRENT_WIN32_INTERFACE)
+ dirp->search_handle = INVALID_HANDLE_VALUE;
+# endif
+
+ free (dirp);
+ return retcode;
+}
+
+
+/*
+ * <function name="rewinddir">
+ * <intro>rewind directory stream to the beginning
+ * <syntax>void rewinddir (DIR *dirp);
+ *
+ * <desc>Rewind directory stream to the beginning so that the next call of
+ * readdir() returns the very first directory entry again. However, note
+ * that next call of readdir() may not return the same directory entry as it
+ * did in first time. The directory stream may have been affected by newly
+ * created files.
+ *
+ * Almost every dirent implementation ensure that rewinddir will update
+ * the directory stream to reflect any changes made to the directory entries
+ * since the previous ``opendir'' or ``rewinddir'' call. Keep an eye on
+ * this if your program depends on the feature. I know at least one dirent
+ * implementation where you are required to close and re-open the stream to
+ * see the changes.
+ *
+ * <ret>Returns nothing. If something went wrong while rewinding, you will
+ * notice it later when you try to retrieve the first directory entry.
+ */
+static void
+rewinddir (DIR *dirp)
+{
+ /* make sure that dirp is legal */
+ assert (dirp != NULL);
+ if (dirp == NULL) {
+ errno = EBADF;
+ return;
+ }
+ assert (dirp->dirname != NULL);
+
+ /* close previous stream */
+#if defined(DIRENT_WIN32_INTERFACE)
+ if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+ if (FindClose (dirp->search_handle) == FALSE) {
+ /* Unknown error */
+ errno = EBADF;
+ }
+ }
+#endif
+
+ /* re-open previous stream */
+ if (_initdir (dirp) == 0) {
+ /* initialization failed but we cannot deal with error. User will notice
+ * error later when she tries to retrieve first directory enty. */
+ /*EMPTY*/;
+ }
+}
+
+
+/*
+ * Open native directory stream object and retrieve first file.
+ * Be sure to close previous stream before opening new one.
+ */
+static int
+_initdir (DIR *dirp)
+{
+ assert (dirp != NULL);
+ assert (dirp->dirname != NULL);
+ dirp->dirent_filled = 0;
+
+# if defined(DIRENT_WIN32_INTERFACE)
+ /* Open stream and retrieve first file */
+ dirp->search_handle = FindFirstFile (dirp->dirname, &dirp->current.data);
+ if (dirp->search_handle == INVALID_HANDLE_VALUE) {
+ /* something went wrong but we don't know what. GetLastError() could
+ * give us more information about the error, but then we should map
+ * the error code into errno. */
+ errno = ENOENT;
+ return 0;
+ }
+
+# elif defined(DIRENT_MSDOS_INTERFACE)
+ if (_dos_findfirst (dirp->dirname,
+ _A_SUBDIR | _A_RDONLY | _A_ARCH | _A_SYSTEM | _A_HIDDEN,
+ &dirp->current.data) != 0)
+ {
+ /* _dos_findfirst and findfirst will set errno to ENOENT when no
+ * more entries could be retrieved. */
+ return 0;
+ }
+# endif
+
+ /* initialize DIR and it's first entry */
+ _setdirname (dirp);
+ dirp->dirent_filled = 1;
+ return 1;
+}
+
+
+/*
+ * Return implementation dependent name of the current directory entry.
+ */
+static const char *
+_getdirname (const struct dirent *dp)
+{
+#if defined(DIRENT_WIN32_INTERFACE)
+ return dp->data.cFileName;
+
+#elif defined(DIRENT_USE_FFBLK)
+ return dp->data.ff_name;
+
+#else
+ return dp->data.name;
+#endif
+}
+
+
+/*
+ * Copy name of implementation dependent directory entry to the d_name field.
+ */
+static void
+_setdirname (struct DIR *dirp) {
+ /* make sure that d_name is long enough */
+ assert (strlen (_getdirname (&dirp->current)) <= NAME_MAX);
+
+ strncpy (dirp->current.d_name,
+ _getdirname (&dirp->current),
+ NAME_MAX);
+ dirp->current.d_name[NAME_MAX] = '\0'; /*char d_name[NAME_MAX+1]*/
+}
+
+# ifdef __cplusplus
+}
+# endif
+# define NAMLEN(dp) ((int)(strlen((dp)->d_name)))
+
+#else
+# error "missing dirent interface"
+#endif
+
+
+#endif /*DIRENT_H*/
+
diff --git a/src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
index 7bdc34b..e25ece4 100644
--- a/src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
@@ -1,11 +1,23 @@
#include "uscxml/Common.h"
-#include "uscxml/datamodel/ecmascript/v8/V8DataModel.h"
+#include "V8DataModel.h"
#include "dom/V8SCXMLDOM.h"
#include "uscxml/Message.h"
#include <glog/logging.h>
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
namespace uscxml {
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host){
+ host.add( new V8DataModelProvider() );
+ return true;
+}
+#endif
+
V8DataModel::V8DataModel() {
// _contexts.push_back(v8::Context::New());
}
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h
new file mode 100644
index 0000000..994ed18
--- /dev/null
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h
@@ -0,0 +1,92 @@
+#ifndef V8DATAMODEL_H_KN8TWG0V
+#define V8DATAMODEL_H_KN8TWG0V
+
+#include "uscxml/Interpreter.h"
+#include <list>
+#include <v8.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
+namespace uscxml {
+ class Event;
+ class Data;
+ class V8SCXMLDOM;
+}
+
+namespace uscxml {
+
+class V8DataModel : public DataModel {
+public:
+ V8DataModel();
+ virtual ~V8DataModel();
+ virtual DataModel* create(Interpreter* interpreter);
+
+ virtual std::set<std::string> getNames() {
+ std::set<std::string> names;
+ names.insert("ecmascript");
+ return names;
+ }
+
+ virtual void initialize();
+ virtual void setSessionId(const std::string& sessionId);
+ virtual void setName(const std::string& name);
+ virtual void setEvent(const Event& event);
+
+ 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 void assign(const std::string& location, const Data& data);
+
+ virtual Data getStringAsData(const std::string& content);
+ virtual Data getValueAsData(const v8::Handle<v8::Value>& value);
+
+ 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);
+ static v8::Handle<v8::Value> jsPrint(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);
+ virtual v8::Handle<v8::Value> getDataAsValue(const Data& data);
+
+};
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_INHERIT_PROVIDER(V8DataModel, DataModel);
+#endif
+
+}
+
+#endif /* end of include guard: V8DATAMODEL_H_KN8TWG0V */
diff --git a/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp
index 6452330..6452330 100644
--- a/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp
diff --git a/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h
index c513e48..c513e48 100644
--- a/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h
diff --git a/src/uscxml/invoker/modality/MMIComponent.cpp b/src/uscxml/plugins/invoker/modality/MMIComponent.cpp
index 0655806..0655806 100644
--- a/src/uscxml/invoker/modality/MMIComponent.cpp
+++ b/src/uscxml/plugins/invoker/modality/MMIComponent.cpp
diff --git a/src/uscxml/invoker/modality/MMIComponent.h b/src/uscxml/plugins/invoker/modality/MMIComponent.h
index a83775f..a83775f 100644
--- a/src/uscxml/invoker/modality/MMIComponent.h
+++ b/src/uscxml/plugins/invoker/modality/MMIComponent.h
diff --git a/src/uscxml/invoker/modality/UmundoComponent.cpp b/src/uscxml/plugins/invoker/modality/UmundoComponent.cpp
index 22dd279..22dd279 100644
--- a/src/uscxml/invoker/modality/UmundoComponent.cpp
+++ b/src/uscxml/plugins/invoker/modality/UmundoComponent.cpp
diff --git a/src/uscxml/invoker/modality/UmundoComponent.h b/src/uscxml/plugins/invoker/modality/UmundoComponent.h
index f2c76c4..f2c76c4 100644
--- a/src/uscxml/invoker/modality/UmundoComponent.h
+++ b/src/uscxml/plugins/invoker/modality/UmundoComponent.h
diff --git a/src/uscxml/invoker/modality/miles/SpatialAudio.cpp b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp
index 5e394bd..13091ae 100644
--- a/src/uscxml/invoker/modality/miles/SpatialAudio.cpp
+++ b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp
@@ -11,7 +11,15 @@
#include <math.h>
namespace uscxml {
-
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host){
+ host.add( new SpatialAudioProvider() );
+ return true;
+}
+#endif
+
SpatialAudio::SpatialAudio() {
_audioDevOpen = false;
_audioDev = NULL;
diff --git a/src/uscxml/invoker/modality/miles/SpatialAudio.h b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h
index f86e2ff..bbbf478 100644
--- a/src/uscxml/invoker/modality/miles/SpatialAudio.h
+++ b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h
@@ -3,7 +3,6 @@
#include <map>
-#include "uscxml/Utilities.h"
#include "../MMIComponent.h"
extern "C" {
@@ -22,6 +21,15 @@ public:
virtual ~SpatialAudio();
virtual Invoker* create(Interpreter* interpreter);
+ virtual std::set<std::string> getNames() {
+ std::set<std::string> names;
+ names.insert("spatial-audio");
+ names.insert("audio");
+ names.insert("http://www.smartvortex.eu/mmi/spatial-audio");
+ names.insert("http://www.smartvortex.eu/mmi/spatial-audio/");
+ return names;
+ }
+
virtual Data getDataModelVariables();
virtual void send(SendRequest& req);
virtual void cancel(const std::string sendId);
diff --git a/src/uscxml/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp
index 70c2474..0e617b9 100644
--- a/src/uscxml/invoker/scxml/USCXMLInvoker.cpp
+++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp
@@ -2,8 +2,20 @@
#include "USCXMLInvoker.h"
#include "uscxml/Interpreter.h"
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
namespace uscxml {
-
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host){
+ host.add( new USCXMLInvokerProvider() );
+ return true;
+}
+#endif
+
USCXMLInvoker::USCXMLInvoker() {
}
diff --git a/src/uscxml/invoker/scxml/USCXMLInvoker.h b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h
index 76657d8..9068a24 100644
--- a/src/uscxml/invoker/scxml/USCXMLInvoker.h
+++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h
@@ -3,6 +3,10 @@
#include "uscxml/Factory.h"
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
namespace uscxml {
class Interpreter;
@@ -12,7 +16,14 @@ public:
USCXMLInvoker();
virtual ~USCXMLInvoker();
virtual Invoker* create(Interpreter* interpreter);
-
+ virtual std::set<std::string> getNames() {
+ std::set<std::string> names;
+ names.insert("uscxml");
+ names.insert("http://www.w3.org/TR/scxml");
+ names.insert("http://www.w3.org/TR/scxml/");
+ return names;
+ }
+
virtual Data getDataModelVariables();
virtual void send(SendRequest& req);
virtual void cancel(const std::string sendId);
@@ -24,7 +35,11 @@ protected:
Interpreter* _invokedInterpreter;
Interpreter* _parentInterpreter;
};
-
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_INHERIT_PROVIDER(USCXMLInvoker, Invoker);
+#endif
+
}
#endif /* end of include guard: USCXMLINVOKER_H_OQFA21IO */
diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp
new file mode 100644
index 0000000..68ffe5a
--- /dev/null
+++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp
@@ -0,0 +1,487 @@
+#include "uscxml/config.h"
+#include "uscxml/Common.h"
+#include "UmundoInvoker.h"
+#include "uscxml/Interpreter.h"
+#include <glog/logging.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host){
+ host.add( new UmundoInvokerProvider() );
+ return true;
+}
+#endif
+
+UmundoInvoker::UmundoInvoker() {
+}
+
+UmundoInvoker::~UmundoInvoker() {
+ _node.removeSubscriber(_sub);
+ _node.removePublisher(_pub);
+};
+
+Invoker* UmundoInvoker::create(Interpreter* interpreter) {
+ UmundoInvoker* invoker = new UmundoInvoker();
+ invoker->_interpreter = interpreter;
+ return invoker;
+}
+
+Data UmundoInvoker::getDataModelVariables() {
+ Data data;
+ return data;
+}
+
+void UmundoInvoker::send(SendRequest& req) {
+ umundo::Message* msg = new umundo::Message();
+
+ if (req.name.length() > 0) {
+ msg->putMeta("event", req.name);
+ } else {
+ msg->putMeta("event", "umundo");
+ }
+
+ if (req.params.find("type") != req.params.end()) {
+ // assume JSON in content to transform to protobuf object
+ if (req.content.length() > 0 && _interpreter->getDataModel() != NULL) {
+ std::string type = req.params["type"].front();
+ const google::protobuf::Message* protoMsg = umundo::PBSerializer::getProto(type);
+ if (protoMsg == NULL) {
+ LOG(ERROR) << "No type " << type << " is known, pass a directory with proto .desc files via types param when invoking";
+ return;
+ }
+ try {
+ Data data = _interpreter->getDataModel()->getStringAsData(req.content);
+ google::protobuf::Message* pbMsg = protoMsg->New();
+ if (!dataToProtobuf(pbMsg, data)) {
+ LOG(ERROR) << "Cannot create message from JSON - not sending";
+ } else {
+ // add all s11n properties
+ if (!_isService) {
+ _pub.prepareMsg(msg, type, pbMsg);
+ _pub.send(msg);
+ } else {
+ std::map<umundo::ServiceDescription, umundo::ServiceStub*>::iterator svcIter = _svcs.begin();
+ while(svcIter != _svcs.end()) {
+ umundo::ServiceStub* stub = svcIter->second;
+ Event event;
+ void* rv = NULL;
+ stub->callStubMethod(req.name, pbMsg, type, rv, "");
+ protobufToData(event, *(const google::protobuf::Message*)rv);
+
+ event.name = _invokeId + ".reply." + req.name;
+ event.invokeid = _invokeId;
+ event.origin = msg->getMeta("um.channel");
+ event.origintype = "umundo";
+ event.type = Event::EXTERNAL;
+
+ _interpreter->receive(event);
+ svcIter++;
+ }
+ }
+ }
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error when invoking umundo:" << std::endl << e << std::endl;
+ return;
+ }
+ } else {
+ LOG(ERROR) << "Required JSON object in content" << std::endl;
+ return;
+ }
+ }
+}
+
+void UmundoInvoker::cancel(const std::string sendId) {
+ assert(false);
+}
+
+void UmundoInvoker::sendToParent(SendRequest& req) {
+ assert(false);
+}
+
+void UmundoInvoker::invoke(InvokeRequest& req) {
+ _invokeId = req.invokeid;
+
+ std::string channelName;
+ std::string serviceName;
+
+ if (req.params.find("channel") != req.params.end()) {
+ channelName = req.params["channel"].front();
+ _isService = false;
+ } else if (req.params.find("service") != req.params.end()) {
+ serviceName = req.params["service"].front();
+ _isService = true;
+ } else {
+ LOG(ERROR) << "Invoking umundo needs a service or a channel param";
+ return;
+ }
+
+ _node = getNode(_interpreter);
+
+ // add types from .proto or .desc files
+ if (req.params.find("types") != req.params.end()) {
+ std::list<std::string>::iterator typeIter = req.params["types"].begin();
+ while(typeIter != req.params["types"].end()) {
+ Arabica::io::URI srcURI(*typeIter);
+ // if (!_interpreter->makeAbsolute(srcURI)) {
+ // LOG(ERROR) << "Relative URI for types in umundo invoker " << *typeIter << " with no base URI set for interpreter";
+ // return;
+ // }
+ umundo::PBSerializer::addProto(srcURI.path());
+ typeIter++;
+ }
+ }
+
+ if (!_isService) {
+ // use umundo to publish objects on a channel
+ _pub = umundo::TypedPublisher(channelName);
+ _sub = umundo::TypedSubscriber(channelName, this);
+
+ _node.addPublisher(_pub);
+ _node.addSubscriber(_sub);
+
+ } else if (serviceName.length() > 0) {
+ // use umundo to access services
+ _svcFilter = umundo::ServiceFilter(serviceName);
+ _node.connect(&_svcMgr);
+ _svcMgr.startQuery(_svcFilter, this);
+ }
+}
+
+void UmundoInvoker::receive(void* object, umundo::Message* msg) {
+ uscxml::Event event;
+ if (msg->getMeta().find("event") != msg->getMeta().end()) {
+ event.name = msg->getMeta("event");
+ } else {
+ event.name = "umundo.rcvd";
+ }
+
+ event.invokeid = _invokeId;
+ event.origin = msg->getMeta("um.channel");
+ event.origintype = "umundo";
+ event.type = Event::EXTERNAL;
+
+// if (msg->getMeta().find("um.s11n.type") != msg->getMeta().end())
+// event.compound["class"] = msg->getMeta("um.s11n.type");
+
+ if (object != NULL)
+ protobufToData(event, *(const google::protobuf::Message*)object);
+
+ // get meta fields into event
+ std::map<std::string, std::string>::const_iterator metaIter = msg->getMeta().begin();
+ while(metaIter != msg->getMeta().end()) {
+ if (metaIter->first.substr(0,3).compare("um.") != 0)
+ event.compound[metaIter->first] = Data(metaIter->second, Data::VERBATIM);
+ metaIter++;
+ }
+
+ _interpreter->receive(event);
+}
+
+void UmundoInvoker::added(umundo::ServiceDescription desc) {
+ LOG(ERROR) << "Service found!";
+
+ umundo::ServiceStub* stub = new umundo::ServiceStub(desc);
+ _svcs[desc] = stub;
+
+ Event addedEvent;
+ addedEvent.invokeid = _invokeId;
+ addedEvent.origin = desc.getName();
+ addedEvent.origintype = "umundo";
+ addedEvent.type = Event::EXTERNAL;
+ addedEvent.name = _invokeId + ".added";
+
+ std::map<std::string, std::string>::const_iterator propIter = desc.getProperties().begin();
+ while(propIter != desc.getProperties().end()) {
+ addedEvent.compound[propIter->first] = Data(propIter->second, Data::VERBATIM);
+ propIter++;
+ }
+
+ _interpreter->receive(addedEvent);
+}
+
+void UmundoInvoker::removed(umundo::ServiceDescription desc) {
+ LOG(ERROR) << "Service lost!";
+
+ if (_svcs.find(desc) == _svcs.end()) {
+ return;
+ }
+
+ delete _svcs[desc];
+ _svcs.erase(desc);
+
+ Event addedEvent;
+ addedEvent.invokeid = _invokeId;
+ addedEvent.origin = desc.getName();
+ addedEvent.origintype = "umundo";
+ addedEvent.type = Event::EXTERNAL;
+ addedEvent.name = _invokeId + ".removed";
+
+ std::map<std::string, std::string>::const_iterator propIter = desc.getProperties().begin();
+ while(propIter != desc.getProperties().end()) {
+ addedEvent.compound[propIter->first] = Data(propIter->second, Data::VERBATIM);
+ propIter++;
+ }
+
+ _interpreter->receive(addedEvent);
+}
+
+void UmundoInvoker::changed(umundo::ServiceDescription desc) {
+}
+
+std::map<std::string, umundo::Node> UmundoInvoker::_nodes;
+umundo::Node UmundoInvoker::getNode(Interpreter* interpreter) {
+ if ((_nodes.find(interpreter->getName()) == _nodes.end())) {
+ _nodes[interpreter->getName()] = umundo::Node();
+ }
+ return _nodes[interpreter->getName()];
+}
+
+bool UmundoInvoker::protobufToData(Data& data, const google::protobuf::Message& msg) {
+ const google::protobuf::Descriptor* desc = msg.GetDescriptor();
+ const google::protobuf::Reflection* reflect = msg.GetReflection();
+
+ data.compound["type"] = Data(desc->name(), Data::VERBATIM);
+
+ for (int i = 0; i < desc->field_count(); i++) {
+ const google::protobuf::FieldDescriptor* fieldDesc = desc->field(i);
+ std::string key = fieldDesc->name();
+
+ if (!fieldDesc->is_repeated() && !reflect->HasField(msg, fieldDesc))
+ continue;
+
+ switch(fieldDesc->type()) {
+ case google::protobuf::FieldDescriptor::TYPE_BOOL:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(reflect->GetRepeatedBool(msg, fieldDesc, j) ? "true" : "false"));
+ }
+ } else {
+ data.compound[key].atom = (reflect->GetBool(msg, fieldDesc) ? "true" : "false");
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_BYTES:
+ case google::protobuf::FieldDescriptor::TYPE_STRING:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedString(msg, fieldDesc, j)), Data::VERBATIM));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetString(msg, fieldDesc));
+ data.compound[key].type = Data::VERBATIM;
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_DOUBLE:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedDouble(msg, fieldDesc, j))));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetDouble(msg, fieldDesc));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_ENUM:
+ LOG(ERROR) << "TYPE_ENUM is unimplemented" << std::endl;
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_FIXED32:
+ case google::protobuf::FieldDescriptor::TYPE_UINT32:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt32(msg, fieldDesc, j))));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetUInt32(msg, fieldDesc));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_FIXED64:
+ case google::protobuf::FieldDescriptor::TYPE_UINT64:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt64(msg, fieldDesc, j))));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetUInt64(msg, fieldDesc));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_FLOAT:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedFloat(msg, fieldDesc, j))));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetFloat(msg, fieldDesc));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_GROUP:
+ LOG(ERROR) << "TYPE_GROUP is unimplemented" << std::endl;
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_INT32:
+ case google::protobuf::FieldDescriptor::TYPE_SINT32:
+ case google::protobuf::FieldDescriptor::TYPE_SFIXED32:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt32(msg, fieldDesc, j))));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetInt32(msg, fieldDesc));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_INT64:
+ case google::protobuf::FieldDescriptor::TYPE_SINT64:
+ case google::protobuf::FieldDescriptor::TYPE_SFIXED64:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt64(msg, fieldDesc, j))));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetInt64(msg, fieldDesc));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_MESSAGE:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data());
+ protobufToData(data.compound[key].array.back(), reflect->GetRepeatedMessage(msg, fieldDesc, j));
+ }
+ } else {
+ protobufToData(data.compound[key], reflect->GetMessage(msg, fieldDesc));
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+bool UmundoInvoker::dataToProtobuf(google::protobuf::Message* msg, Data& data) {
+ const google::protobuf::Descriptor* desc = msg->GetDescriptor();
+ const google::protobuf::Reflection* reflect = msg->GetReflection();
+
+ for (int i = 0; i < desc->field_count(); i++) {
+ const google::protobuf::FieldDescriptor* fieldDesc = desc->field(i);
+ std::string key = fieldDesc->name();
+
+ if (data.compound.find(key) == data.compound.end()) {
+ if (fieldDesc->is_required()) {
+ LOG(ERROR) << "required field " << key << " not given in JSON";
+ return false;
+ }
+ continue;
+ }
+
+ std::list<Data>::iterator arrayIter = data.compound[key].array.begin();
+
+ switch(fieldDesc->type()) {
+ case google::protobuf::FieldDescriptor::TYPE_BOOL:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddBool(msg, fieldDesc, arrayIter->atom.compare("false") == 0 ? false : true);
+ arrayIter++;
+ }
+ } else {
+ reflect->SetBool(msg, fieldDesc, (data.compound[key].atom.compare("false") == 0 ? false : true));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_BYTES:
+ case google::protobuf::FieldDescriptor::TYPE_STRING:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddString(msg, fieldDesc, arrayIter->atom);
+ arrayIter++;
+ }
+ } else {
+ reflect->SetString(msg, fieldDesc, data.compound[key].atom);
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_DOUBLE:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddDouble(msg, fieldDesc, strTo<double>(arrayIter->atom));
+ arrayIter++;
+ }
+ } else {
+ reflect->SetDouble(msg, fieldDesc, strTo<double>(data.compound[key].atom));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_ENUM:
+ LOG(ERROR) << "TYPE_ENUM is unimplemented" << std::endl;
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_FIXED32:
+ case google::protobuf::FieldDescriptor::TYPE_UINT32:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddUInt32(msg, fieldDesc, strTo<uint32_t>(arrayIter->atom));
+ arrayIter++;
+ }
+ } else {
+ reflect->SetUInt32(msg, fieldDesc, strTo<uint32_t>(data.compound[key].atom));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_FIXED64:
+ case google::protobuf::FieldDescriptor::TYPE_UINT64:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddUInt64(msg, fieldDesc, strTo<uint64_t>(arrayIter->atom));
+ arrayIter++;
+ }
+ } else {
+ reflect->SetUInt64(msg, fieldDesc, strTo<uint64_t>(data.compound[key].atom));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_FLOAT:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddFloat(msg, fieldDesc, strTo<float>(arrayIter->atom));
+ arrayIter++;
+ }
+ } else {
+ reflect->SetFloat(msg, fieldDesc, strTo<float>(data.compound[key].atom));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_GROUP:
+ LOG(ERROR) << "TYPE_GROUP is unimplemented" << std::endl;
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_INT32:
+ case google::protobuf::FieldDescriptor::TYPE_SINT32:
+ case google::protobuf::FieldDescriptor::TYPE_SFIXED32:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddInt32(msg, fieldDesc, strTo<int32_t>(arrayIter->atom));
+ arrayIter++;
+ }
+ } else {
+ reflect->SetInt32(msg, fieldDesc, strTo<int32_t>(data.compound[key].atom));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_INT64:
+ case google::protobuf::FieldDescriptor::TYPE_SINT64:
+ case google::protobuf::FieldDescriptor::TYPE_SFIXED64:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddInt64(msg, fieldDesc, strTo<int64_t>(arrayIter->atom));
+ arrayIter++;
+ }
+ } else {
+ reflect->SetInt64(msg, fieldDesc, strTo<int64_t>(data.compound[key].atom));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_MESSAGE:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ dataToProtobuf(reflect->AddMessage(msg, fieldDesc), *arrayIter);
+ arrayIter++;
+ }
+ } else {
+ dataToProtobuf(reflect->MutableMessage(msg, fieldDesc), data.compound[key]);
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h
new file mode 100644
index 0000000..36a6217
--- /dev/null
+++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h
@@ -0,0 +1,70 @@
+#ifndef UMUNDOINVOKER_H_77YXQGU7
+#define UMUNDOINVOKER_H_77YXQGU7
+
+#include <umundo/core.h>
+#include <umundo/s11n.h>
+#include <umundo/rpc.h>
+#include <umundo/s11n/protobuf/PBSerializer.h>
+#include <google/protobuf/message.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
+namespace uscxml {
+
+class Interpreter;
+
+class UmundoInvoker : public Invoker, public umundo::TypedReceiver, public umundo::ResultSet<umundo::ServiceDescription> {
+public:
+ UmundoInvoker();
+ virtual ~UmundoInvoker();
+ virtual Invoker* create(Interpreter* interpreter);
+
+ virtual std::set<std::string> getNames() {
+ std::set<std::string> names;
+ names.insert("umundo");
+ names.insert("http://umundo.tk.informatik.tu-darmstadt.de/");
+ names.insert("http://umundo.tk.informatik.tu-darmstadt.de");
+ return names;
+ }
+
+ virtual Data getDataModelVariables();
+ virtual void send(SendRequest& req);
+ virtual void cancel(const std::string sendId);
+ virtual void invoke(InvokeRequest& req);
+ virtual void sendToParent(SendRequest& req);
+
+ virtual void receive(void* object, umundo::Message* msg);
+
+ virtual void added(umundo::ServiceDescription);
+ virtual void removed(umundo::ServiceDescription);
+ virtual void changed(umundo::ServiceDescription);
+
+protected:
+ std::string _invokeId;
+ bool _isService;
+
+ bool dataToProtobuf(google::protobuf::Message* msg, Data& data);
+ bool protobufToData(Data& data, const google::protobuf::Message& msg);
+
+ umundo::TypedPublisher _pub;
+ umundo::TypedSubscriber _sub;
+ umundo::Node _node;
+
+ umundo::ServiceFilter _svcFilter;
+ umundo::ServiceManager _svcMgr;
+ std::map<umundo::ServiceDescription, umundo::ServiceStub*> _svcs;
+
+ static std::map<std::string, umundo::Node> _nodes;
+ static umundo::Node getNode(Interpreter* interpreter);
+};
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_INHERIT_PROVIDER(UmundoInvoker, Invoker);
+#endif
+
+}
+
+
+#endif /* end of include guard: UMUNDOINVOKER_H_77YXQGU7 */
diff --git a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp
new file mode 100644
index 0000000..44c89ae
--- /dev/null
+++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp
@@ -0,0 +1,370 @@
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include "uscxml/plugins/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>
+
+#ifndef _WIN32
+#include <netdb.h>
+#include <arpa/inet.h>
+#endif
+
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host){
+ host.add( new EventIOProcessorProvider() );
+ return true;
+}
+#endif
+
+// see http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor
+
+EventIOProcessor::EventIOProcessor() {
+}
+
+EventIOProcessor::~EventIOProcessor() {
+ _asyncQueue.stop();
+ evdns_base_free(_dns, 1);
+ 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->_asyncQueue._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() {
+ _asyncQueue.start();
+}
+
+Data EventIOProcessor::getDataModelVariables() {
+ Data data;
+ assert(_url.length() > 0);
+ data.compound["location"] = Data(_url, Data::VERBATIM);
+ return data;
+}
+
+
+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;
+
+ int err = 0;
+ char uriBuf[1024];
+
+ struct evhttp_uri* targetURI = evhttp_uri_parse(_sendData[req.sendid].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(hostName && 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 (_httpConnections.find(endPoint) == _httpConnections.end())
+ _httpConnections[endPoint] = evhttp_connection_base_new(_asyncQueue._eventLoop, _dns, evhttp_uri_get_host(targetURI), evhttp_uri_get_port(targetURI));
+
+ struct evhttp_connection* httpConn = _httpConnections[endPoint];
+ struct evhttp_request* httpReq = evhttp_request_new(EventIOProcessor::httpSendReqDone, this);
+
+#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(req.toXMLString().c_str()));
+
+
+ _httpRequests[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 " << 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;
+ bool scxmlStructFound = false;
+
+ // 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));
+ scxmlStructFound = true;
+ 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);
+ }
+ }
+
+ if (!scxmlStructFound) {
+ // 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* INSTANCE = (EventIOProcessor*)arg;
+ INSTANCE->_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;
+ }
+}
+
+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* INSTANCE = getInstance();
+ tthread::lock_guard<tthread::recursive_mutex> lock(INSTANCE->_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(INSTANCE->_processors.find(actualPath.str()) != INSTANCE->_processors.end()) {
+ actualPath.str(std::string());
+ actualPath.clear();
+ actualPath << path << ++i;
+ }
+
+ std::stringstream processorURL;
+ processorURL << "http://" << INSTANCE->_address << ":" << INSTANCE->_port << "/" << actualPath.str();
+
+ INSTANCE->_processors[actualPath.str()] = processor;
+ processor->setURL(processorURL.str());
+
+ evhttp_set_cb(INSTANCE->_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* INSTANCE = getInstance();
+ tthread::lock_guard<tthread::recursive_mutex> lock(INSTANCE->_mutex);
+ evhttp_del_cb(INSTANCE->_http, processor->_url.c_str());
+}
+
+void EventIOServer::start() {
+ _isRunning = true;
+ _thread = new tthread::thread(EventIOServer::run, this);
+}
+
+void EventIOServer::run(void* instance) {
+ EventIOServer* INSTANCE = (EventIOServer*)instance;
+ while(INSTANCE->_isRunning) {
+ LOG(INFO) << "Dispatching HTTP Server" << std::endl;
+ event_base_dispatch(INSTANCE->_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/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h
new file mode 100644
index 0000000..af7aac7
--- /dev/null
+++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h
@@ -0,0 +1,107 @@
+#ifndef EVENTIOPROCESSOR_H_2CUY93KU
+#define EVENTIOPROCESSOR_H_2CUY93KU
+
+#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h"
+#include "uscxml/Interpreter.h"
+#include "uscxml/Factory.h"
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+
+#include <event2/http.h>
+#include <event2/http_struct.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
+namespace uscxml {
+
+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 std::set<std::string> getNames() {
+ std::set<std::string> names;
+ names.insert("basichttp");
+ names.insert("http://www.w3.org/TR/scxml/#SCXMLEventProcessor");
+ return names;
+ }
+
+ virtual void send(uscxml::SendRequest& req);
+
+ Data getDataModelVariables();
+ 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 _asyncQueue;
+ 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;
+};
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_INHERIT_PROVIDER(EventIOProcessor, IOProcessor);
+#endif
+
+}
+
+#endif /* end of include guard: EVENTIOPROCESSOR_H_2CUY93KU */ \ No newline at end of file
diff --git a/test/src/test-ecmascript-v8.cpp b/test/src/test-ecmascript-v8.cpp
index 9e7635b..bca9343 100644
--- a/test/src/test-ecmascript-v8.cpp
+++ b/test/src/test-ecmascript-v8.cpp
@@ -1,5 +1,5 @@
#include "uscxml/Interpreter.h"
-#include "uscxml/datamodel/ecmascript/v8/V8DataModel.h"
+#include "uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h"
int main(int argc, char** argv) {
if (argc != 2) {
diff --git a/test/src/test-eventdelay.cpp b/test/src/test-eventdelay.cpp
index 45a14b7..17a88ca 100644
--- a/test/src/test-eventdelay.cpp
+++ b/test/src/test-eventdelay.cpp
@@ -1,4 +1,4 @@
-#include "uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h"
+#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h"
int eventCalled = 0;