From f1700edcd08d6215888e226618555ba43b5324ec Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Sat, 15 Dec 2012 20:10:50 +0100 Subject: Refactoring and plugin support --- CMakeLists.txt | 293 +++++---- apps/mmi-browser.cpp | 3 +- config.h.in | 2 + contrib/cmake/CPackUSCXML.cmake | 2 +- src/uscxml/Factory.cpp | 114 +++- src/uscxml/Factory.h | 27 +- src/uscxml/Interpreter.h | 2 +- src/uscxml/URL.cpp | 358 ++++++++++- src/uscxml/URL.h | 33 +- src/uscxml/Utilities.cpp | 403 ------------ src/uscxml/Utilities.h | 51 -- .../concurrency/eventqueue/DelayedEventQueue.cpp | 91 +++ .../concurrency/eventqueue/DelayedEventQueue.h | 54 ++ .../eventqueue/libev/DelayedEventQueue.cpp | 57 -- .../eventqueue/libev/DelayedEventQueue.h | 45 -- .../eventqueue/libevent/DelayedEventQueue.cpp | 91 --- .../eventqueue/libevent/DelayedEventQueue.h | 54 -- src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp | 397 ------------ .../datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp | 219 ------- .../datamodel/ecmascript/v8/dom/V8SCXMLDOM.h | 61 -- src/uscxml/invoker/modality/MMIComponent.cpp | 42 -- src/uscxml/invoker/modality/MMIComponent.h | 109 ---- src/uscxml/invoker/modality/UmundoComponent.cpp | 49 -- src/uscxml/invoker/modality/UmundoComponent.h | 30 - src/uscxml/invoker/modality/miles/SpatialAudio.cpp | 189 ------ src/uscxml/invoker/modality/miles/SpatialAudio.h | 50 -- src/uscxml/invoker/scxml/USCXMLInvoker.cpp | 50 -- src/uscxml/invoker/scxml/USCXMLInvoker.h | 30 - src/uscxml/ioprocessor/basichttp/README.md | 2 - .../basichttp/mongoose/MongooseIOProcessor.cpp | 3 - .../basichttp/mongoose/MongooseIOProcessor.h | 15 - .../ioprocessor/basichttp/pion/PionIOProcessor.cpp | 74 --- .../ioprocessor/basichttp/pion/PionIOProcessor.h | 47 -- src/uscxml/plugins/Plugins.cpp | 11 + src/uscxml/plugins/Plugins.h | 17 + src/uscxml/plugins/Pluma/Config.hpp | 141 +++++ src/uscxml/plugins/Pluma/Connector.hpp | 86 +++ src/uscxml/plugins/Pluma/DLibrary.cpp | 106 ++++ src/uscxml/plugins/Pluma/DLibrary.hpp | 123 ++++ src/uscxml/plugins/Pluma/Dir.cpp | 103 ++++ src/uscxml/plugins/Pluma/Dir.hpp | 64 ++ src/uscxml/plugins/Pluma/Host.cpp | 179 ++++++ src/uscxml/plugins/Pluma/Host.hpp | 212 +++++++ src/uscxml/plugins/Pluma/PluginManager.cpp | 201 ++++++ src/uscxml/plugins/Pluma/PluginManager.hpp | 245 ++++++++ src/uscxml/plugins/Pluma/Pluma.hpp | 171 ++++++ src/uscxml/plugins/Pluma/Pluma.inl | 52 ++ src/uscxml/plugins/Pluma/Provider.cpp | 52 ++ src/uscxml/plugins/Pluma/Provider.hpp | 204 +++++++ src/uscxml/plugins/Pluma/uce-dirent.h | 679 +++++++++++++++++++++ .../datamodel/ecmascript/v8/V8DataModel.cpp | 409 +++++++++++++ .../plugins/datamodel/ecmascript/v8/V8DataModel.h | 92 +++ .../datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp | 219 +++++++ .../datamodel/ecmascript/v8/dom/V8SCXMLDOM.h | 61 ++ .../plugins/invoker/modality/MMIComponent.cpp | 42 ++ src/uscxml/plugins/invoker/modality/MMIComponent.h | 109 ++++ .../plugins/invoker/modality/UmundoComponent.cpp | 49 ++ .../plugins/invoker/modality/UmundoComponent.h | 30 + .../invoker/modality/miles/SpatialAudio.cpp | 197 ++++++ .../plugins/invoker/modality/miles/SpatialAudio.h | 58 ++ src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp | 62 ++ src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h | 45 ++ .../plugins/invoker/umundo/UmundoInvoker.cpp | 487 +++++++++++++++ src/uscxml/plugins/invoker/umundo/UmundoInvoker.h | 70 +++ .../basichttp/libevent/EventIOProcessor.cpp | 370 +++++++++++ .../basichttp/libevent/EventIOProcessor.h | 107 ++++ test/src/test-ecmascript-v8.cpp | 2 +- test/src/test-eventdelay.cpp | 2 +- 68 files changed, 5886 insertions(+), 2218 deletions(-) delete mode 100644 src/uscxml/Utilities.cpp delete mode 100644 src/uscxml/Utilities.h create mode 100644 src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp create mode 100644 src/uscxml/concurrency/eventqueue/DelayedEventQueue.h delete mode 100644 src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.cpp delete mode 100644 src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.h delete mode 100644 src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp delete mode 100644 src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h delete mode 100644 src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp delete mode 100644 src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp delete mode 100644 src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h delete mode 100644 src/uscxml/invoker/modality/MMIComponent.cpp delete mode 100644 src/uscxml/invoker/modality/MMIComponent.h delete mode 100644 src/uscxml/invoker/modality/UmundoComponent.cpp delete mode 100644 src/uscxml/invoker/modality/UmundoComponent.h delete mode 100644 src/uscxml/invoker/modality/miles/SpatialAudio.cpp delete mode 100644 src/uscxml/invoker/modality/miles/SpatialAudio.h delete mode 100644 src/uscxml/invoker/scxml/USCXMLInvoker.cpp delete mode 100644 src/uscxml/invoker/scxml/USCXMLInvoker.h delete mode 100644 src/uscxml/ioprocessor/basichttp/README.md delete mode 100644 src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.cpp delete mode 100644 src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.h delete mode 100644 src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.cpp delete mode 100644 src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.h create mode 100644 src/uscxml/plugins/Plugins.cpp create mode 100644 src/uscxml/plugins/Plugins.h create mode 100755 src/uscxml/plugins/Pluma/Config.hpp create mode 100755 src/uscxml/plugins/Pluma/Connector.hpp create mode 100755 src/uscxml/plugins/Pluma/DLibrary.cpp create mode 100755 src/uscxml/plugins/Pluma/DLibrary.hpp create mode 100755 src/uscxml/plugins/Pluma/Dir.cpp create mode 100755 src/uscxml/plugins/Pluma/Dir.hpp create mode 100755 src/uscxml/plugins/Pluma/Host.cpp create mode 100755 src/uscxml/plugins/Pluma/Host.hpp create mode 100755 src/uscxml/plugins/Pluma/PluginManager.cpp create mode 100755 src/uscxml/plugins/Pluma/PluginManager.hpp create mode 100755 src/uscxml/plugins/Pluma/Pluma.hpp create mode 100755 src/uscxml/plugins/Pluma/Pluma.inl create mode 100755 src/uscxml/plugins/Pluma/Provider.cpp create mode 100755 src/uscxml/plugins/Pluma/Provider.hpp create mode 100755 src/uscxml/plugins/Pluma/uce-dirent.h create mode 100644 src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp create mode 100644 src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h create mode 100644 src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp create mode 100644 src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h create mode 100644 src/uscxml/plugins/invoker/modality/MMIComponent.cpp create mode 100644 src/uscxml/plugins/invoker/modality/MMIComponent.h create mode 100644 src/uscxml/plugins/invoker/modality/UmundoComponent.cpp create mode 100644 src/uscxml/plugins/invoker/modality/UmundoComponent.h create mode 100644 src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp create mode 100644 src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h create mode 100644 src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp create mode 100644 src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h create mode 100644 src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp create mode 100644 src/uscxml/plugins/invoker/umundo/UmundoInvoker.h create mode 100644 src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp create mode 100644 src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h 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(); + pluma.acceptProviderType(); + pluma.acceptProviderType(); + 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 invokerProviders; + pluma.getProviders(invokerProviders); + for (std::vector::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 ioProcessorProviders; + pluma.getProviders(ioProcessorProviders); + for (std::vector::iterator it = ioProcessorProviders.begin() ; it != ioProcessorProviders.end() ; ++it) { + IOProcessor* ioProcessor = (*it)->create(); + registerIOProcessor(ioProcessor); + } + std::vector dataModelProviders; + pluma.getProviders(dataModelProviders); + for (std::vector::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 names = ioProcessor->getNames(); + std::set::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 names = dataModel->getNames(); + std::set::iterator nameIter = names.begin(); + while(nameIter != names.end()) { + _dataModels[*nameIter] = dataModel; + nameIter++; + } } + void Factory::registerInvoker(Invoker* invoker) { + std::set names = invoker->getNames(); + std::set::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 +#include namespace uscxml { + // see http://stackoverflow.com/questions/228005/alternative-to-itoa-for-converting-integer-to-string-c template 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 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 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 _dataModels; std::map _ioProcessors; - std::map _invoker; + std::map _invokers; std::map _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 #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 #include +#include +#include +#ifndef WIN32 +#include +#endif +#include +#include + +#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 +#include +#include 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 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 -#include -#ifndef WIN32 -#include -#endif -#include -#include - -#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 -#include -#include - -// see http://stackoverflow.com/questions/228005/alternative-to-itoa-for-converting-integer-to-string-c -template std::string toStr(T tmp) { - std::ostringstream out; - out << tmp; - return out.str(); -} - -template 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/DelayedEventQueue.cpp b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp new file mode 100644 index 0000000..e2a89b2 --- /dev/null +++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp @@ -0,0 +1,91 @@ +#include "DelayedEventQueue.h" +#include +#include + +namespace uscxml { + + DelayedEventQueue::DelayedEventQueue() { +#ifndef _WIN32 + evthread_use_pthreads(); +#else + evthread_use_windows_threads(); +#endif + _eventLoop = event_base_new(); + _thread = NULL; + } + + DelayedEventQueue::~DelayedEventQueue() { +// std::cout << "Deleting DelayedEventQueue" << std::endl; + stop(); + if (_thread) + _thread->join(); + if(_eventLoop) + event_base_free(_eventLoop); + } + + void DelayedEventQueue::run(void* instance) { + DelayedEventQueue* THIS = (DelayedEventQueue*)instance; + int result; + while(THIS->_isStarted) { + { + //result = event_base_dispatch(THIS->_eventLoop); + result = event_base_loop(THIS->_eventLoop, EVLOOP_NO_EXIT_ON_EMPTY); + } + } + } + + void DelayedEventQueue::addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData) { + if(_callbackData.find(eventId) != _callbackData.end()) { + cancelEvent(eventId); + } + + struct timeval delay = {delayMs / 1000, (delayMs % 1000) * 1000}; + struct event* event = event_new(_eventLoop, -1, 0, DelayedEventQueue::timerCallback, &_callbackData[eventId]); + + _callbackData[eventId].eventId = eventId; + _callbackData[eventId].userData = userData; + _callbackData[eventId].eventQueue = this; + _callbackData[eventId].callback = callback; + _callbackData[eventId].event = event; + + event_add(event, &delay); + } + + void DelayedEventQueue::cancelEvent(std::string eventId) { + tthread::lock_guard lock(_mutex); + + if(_callbackData.find(eventId) != _callbackData.end()) { + event_del(_callbackData[eventId].event); + event_free(_callbackData[eventId].event); + _callbackData.erase(eventId); + } + } + + void DelayedEventQueue::start() { + _isStarted = true; + _thread = new tthread::thread(DelayedEventQueue::run, this); + } + + void DelayedEventQueue::stop() { + if (_isStarted) { + _isStarted = false; + event_base_loopbreak(_eventLoop); + _thread->join(); + delete _thread; + } + } + + void DelayedEventQueue::dummyCallback(evutil_socket_t fd, short what, void *arg) { + } + + void DelayedEventQueue::timerCallback(evutil_socket_t fd, short what, void *arg) { + struct callbackData *data = (struct callbackData*)arg; + tthread::lock_guard lock(data->eventQueue->_mutex); + + std::string eventId = data->eventId; // copy eventId + event_free(data->event); + data->callback(data->userData, eventId); + data->eventQueue->_callbackData.erase(data->eventId); + } + +} \ No newline at end of file diff --git a/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h new file mode 100644 index 0000000..024e353 --- /dev/null +++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h @@ -0,0 +1,54 @@ +#ifndef DELAYEDEVENTQUEUE_H_JA6WRBVP +#define DELAYEDEVENTQUEUE_H_JA6WRBVP + +#include "uscxml/concurrency/tinythread.h" + +#include +#include +#include + +#include + +#include +#include +#include + +namespace uscxml { + +class DelayedEventQueue { +public: + + struct callbackData + { + void *userData; + void (*callback)(void*, const std::string eventId); + std::string eventId; + struct event *event; + DelayedEventQueue* eventQueue; + }; + + DelayedEventQueue(); + virtual ~DelayedEventQueue(); + + void addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData); + void cancelEvent(std::string eventId); + + void start(); + void stop(); + static void run(void*); + + static void timerCallback(evutil_socket_t fd, short what, void *arg); + static void dummyCallback(evutil_socket_t fd, short what, void *arg); + + bool _isStarted; + tthread::thread* _thread; + tthread::recursive_mutex _mutex; + + std::map _callbackData; + struct event_base* _eventLoop; +}; + +} + + +#endif /* end of include guard: DELAYEDEVENTQUEUE_H_JA6WRBVP */ 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 - -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 - -#include -#include -#include - -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 _timeoutWatcher; - struct ev_loop* _eventLoop; -}; - -} - - -#endif /* end of include guard: DELAYEDEVENTQUEUE_H_JA6WRBVP */ diff --git a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp b/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp deleted file mode 100644 index 170e5d9..0000000 --- a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h" -#include -#include - -namespace uscxml { - - DelayedEventQueue::DelayedEventQueue() { -#ifndef _WIN32 - evthread_use_pthreads(); -#else - evthread_use_windows_threads(); -#endif - _eventLoop = event_base_new(); - _thread = NULL; - } - - DelayedEventQueue::~DelayedEventQueue() { -// std::cout << "Deleting DelayedEventQueue" << std::endl; - stop(); - if (_thread) - _thread->join(); - if(_eventLoop) - event_base_free(_eventLoop); - } - - void DelayedEventQueue::run(void* instance) { - DelayedEventQueue* THIS = (DelayedEventQueue*)instance; - int result; - while(THIS->_isStarted) { - { - //result = event_base_dispatch(THIS->_eventLoop); - result = event_base_loop(THIS->_eventLoop, EVLOOP_NO_EXIT_ON_EMPTY); - } - } - } - - void DelayedEventQueue::addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData) { - if(_callbackData.find(eventId) != _callbackData.end()) { - cancelEvent(eventId); - } - - struct timeval delay = {delayMs / 1000, (delayMs % 1000) * 1000}; - struct event* event = event_new(_eventLoop, -1, 0, DelayedEventQueue::timerCallback, &_callbackData[eventId]); - - _callbackData[eventId].eventId = eventId; - _callbackData[eventId].userData = userData; - _callbackData[eventId].eventQueue = this; - _callbackData[eventId].callback = callback; - _callbackData[eventId].event = event; - - event_add(event, &delay); - } - - void DelayedEventQueue::cancelEvent(std::string eventId) { - tthread::lock_guard lock(_mutex); - - if(_callbackData.find(eventId) != _callbackData.end()) { - event_del(_callbackData[eventId].event); - event_free(_callbackData[eventId].event); - _callbackData.erase(eventId); - } - } - - void DelayedEventQueue::start() { - _isStarted = true; - _thread = new tthread::thread(DelayedEventQueue::run, this); - } - - void DelayedEventQueue::stop() { - if (_isStarted) { - _isStarted = false; - event_base_loopbreak(_eventLoop); - _thread->join(); - delete _thread; - } - } - - void DelayedEventQueue::dummyCallback(evutil_socket_t fd, short what, void *arg) { - } - - void DelayedEventQueue::timerCallback(evutil_socket_t fd, short what, void *arg) { - struct callbackData *data = (struct callbackData*)arg; - tthread::lock_guard lock(data->eventQueue->_mutex); - - std::string eventId = data->eventId; // copy eventId - event_free(data->event); - data->callback(data->userData, eventId); - data->eventQueue->_callbackData.erase(data->eventId); - } - -} \ No newline at end of file diff --git a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h b/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h deleted file mode 100644 index 024e353..0000000 --- a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef DELAYEDEVENTQUEUE_H_JA6WRBVP -#define DELAYEDEVENTQUEUE_H_JA6WRBVP - -#include "uscxml/concurrency/tinythread.h" - -#include -#include -#include - -#include - -#include -#include -#include - -namespace uscxml { - -class DelayedEventQueue { -public: - - struct callbackData - { - void *userData; - void (*callback)(void*, const std::string eventId); - std::string eventId; - struct event *event; - DelayedEventQueue* eventQueue; - }; - - DelayedEventQueue(); - virtual ~DelayedEventQueue(); - - void addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData); - void cancelEvent(std::string eventId); - - void start(); - void stop(); - static void run(void*); - - static void timerCallback(evutil_socket_t fd, short what, void *arg); - static void dummyCallback(evutil_socket_t fd, short what, void *arg); - - bool _isStarted; - tthread::thread* _thread; - tthread::recursive_mutex _mutex; - - std::map _callbackData; - struct event_base* _eventLoop; -}; - -} - - -#endif /* end of include guard: DELAYEDEVENTQUEUE_H_JA6WRBVP */ diff --git a/src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp deleted file mode 100644 index 7bdc34b..0000000 --- a/src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp +++ /dev/null @@ -1,397 +0,0 @@ -#include "uscxml/Common.h" -#include "uscxml/datamodel/ecmascript/v8/V8DataModel.h" -#include "dom/V8SCXMLDOM.h" -#include "uscxml/Message.h" -#include - -namespace uscxml { - -V8DataModel::V8DataModel() { -// _contexts.push_back(v8::Context::New()); -} - -DataModel* V8DataModel::create(Interpreter* interpreter) { - V8DataModel* dm = new V8DataModel(); - dm->_interpreter = interpreter; - v8::Locker locker; - v8::HandleScope scope; - - // see http://stackoverflow.com/questions/3171418/v8-functiontemplate-class-instance -// dm->_globalTemplate = v8::Persistent(v8::ObjectTemplate::New()); -// dm->_globalTemplate->Set(v8::String::New("In"), v8::FunctionTemplate::New(jsIn, v8::External::New(reinterpret_cast(this)))); - - v8::Handle global = v8::ObjectTemplate::New(); - global->Set(v8::String::New("In"), v8::FunctionTemplate::New(jsIn, v8::External::New(reinterpret_cast(dm)))); - global->Set(v8::String::New("print"), v8::FunctionTemplate::New(jsPrint, v8::External::New(reinterpret_cast(dm)))); - global->Set(v8::String::New("document"), V8SCXMLDOM::getDocument(interpreter->getDocument())); - - dm->_contexts.push_back(v8::Context::New(NULL, global)); - dm->setName(interpreter->getName()); - dm->setSessionId(interpreter->getSessionId()); - dm->eval("_ioprocessors = {};"); - - return dm; -} - -void V8DataModel::setSessionId(const std::string& sessionId) { - _sessionId = sessionId; - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - v8::Handle global = _contexts.front()->Global(); - - global->Set(v8::String::New("_sessionid"), v8::String::New(sessionId.c_str())); -} - -void V8DataModel::setName(const std::string& name) { - _name = name; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - v8::Handle global = _contexts.front()->Global(); - - global->Set(v8::String::New("_name"), v8::String::New(name.c_str())); -} - -V8DataModel::~V8DataModel() { - while(_contexts.size() > 0) { - _contexts.back().Dispose(); - _contexts.pop_back(); - } -} - -void V8DataModel::pushContext() { - _contexts.push_back(_contexts.back().New(_contexts.back())); -} - -void V8DataModel::popContext() { - if (_contexts.size() > 1) { - _contexts.back().Dispose(); - _contexts.pop_back(); - } -} - -void V8DataModel::initialize() { -} - -void V8DataModel::setEvent(const Event& event) { - _event = event; - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - v8::Handle global = _contexts.front()->Global(); - - // this is unfortunate - can't we store the template in the object? - if (_eventTemplate.IsEmpty()) { - v8::Handle localEventTemplate = v8::ObjectTemplate::New(); - localEventTemplate->SetInternalFieldCount(1); // we only have a single C++ object - localEventTemplate->SetAccessor(v8::String::New("name"), V8DataModel::jsGetEventName); - localEventTemplate->SetAccessor(v8::String::New("type"), V8DataModel::jsGetEventType); - localEventTemplate->SetAccessor(v8::String::New("sendid"), V8DataModel::jsGetEventSendId); - localEventTemplate->SetAccessor(v8::String::New("origin"), V8DataModel::jsGetEventOrigin); - localEventTemplate->SetAccessor(v8::String::New("origintype"), V8DataModel::jsGetEventOriginType); - localEventTemplate->SetAccessor(v8::String::New("invokeid"), V8DataModel::jsGetEventInvokeId); - _eventTemplate = v8::Persistent::New(localEventTemplate); - } - - assert(_eventTemplate->InternalFieldCount() == 1); - v8::Handle eventJS = _eventTemplate->NewInstance(); - eventJS->SetInternalField(0, v8::External::New(&_event)); - - eventJS->Set(v8::String::New("data"), getDataAsValue(event)); // set data part of _event - global->Set(v8::String::New("_event"), eventJS); -} - -Data V8DataModel::getStringAsData(const std::string& content) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - v8::Handle result = evalAsValue(content); - Data data = getValueAsData(result); - return data; -} - -Data V8DataModel::getValueAsData(const v8::Handle& value) { - Data data; - if (false) { - } else if (value->IsArray()) { - v8::Handle array = v8::Handle::Cast(value); - for (int i = 0; i < array->Length(); i++) { - data.array.push_back(getValueAsData(array->Get(i))); - } - } else if (value->IsBoolean()) { - data.atom = (value->ToBoolean()->Value() ? "true" : "false"); - } else if (value->IsBooleanObject()) { - LOG(ERROR) << "IsBooleanObject is unimplemented" << std::endl; - } else if (value->IsDate()) { - LOG(ERROR) << "IsDate is unimplemented" << std::endl; - } else if (value->IsExternal()) { - LOG(ERROR) << "IsExternal is unimplemented" << std::endl; - } else if (value->IsFalse()) { - LOG(ERROR) << "IsFalse is unimplemented" << std::endl; - } else if (value->IsFunction()) { - LOG(ERROR) << "IsFunction is unimplemented" << std::endl; - } else if (value->IsInt32()) { - int32_t prop = value->Int32Value(); - data.atom = toStr(prop); - } else if (value->IsNativeError()) { - LOG(ERROR) << "IsNativeError is unimplemented" << std::endl; - } else if (value->IsNull()) { - LOG(ERROR) << "IsNull is unimplemented" << std::endl; - } else if (value->IsNumber()) { - v8::String::AsciiValue prop(v8::Handle::Cast(v8::Handle::Cast(value))); - data.atom = *prop; - } else if (value->IsNumberObject()) { - LOG(ERROR) << "IsNumberObject is unimplemented" << std::endl; - } else if (value->IsObject()) { - v8::Handle object = v8::Handle::Cast(value); - v8::Local properties = object->GetPropertyNames(); - for (int i = 0; i < properties->Length(); i++) { - assert(properties->Get(i)->IsString()); - v8::String::AsciiValue key(v8::Handle::Cast(properties->Get(i))); - v8::Local property = object->Get(properties->Get(i)); - data.compound[*key] = getValueAsData(property); - } - } else if (value->IsRegExp()) { - LOG(ERROR) << "IsRegExp is unimplemented" << std::endl; - } else if(value->IsString()) { - v8::String::AsciiValue property(v8::Handle::Cast(value)); - data.atom = *property; - } else if(value->IsStringObject()) { - LOG(ERROR) << "IsStringObject is unimplemented" << std::endl; - } else if(value->IsTrue()) { - LOG(ERROR) << "IsTrue is unimplemented" << std::endl; - } else if(value->IsUint32()) { - LOG(ERROR) << "IsUint32 is unimplemented" << std::endl; - } else if(value->IsUndefined()) { - LOG(ERROR) << "IsUndefined is unimplemented" << std::endl; - } - return data; -} - -v8::Handle V8DataModel::getDataAsValue(const Data& data) { - if (data.compound.size() > 0) { - v8::Handle value = v8::Object::New(); - std::map::const_iterator compoundIter = data.compound.begin(); - while(compoundIter != data.compound.end()) { - value->Set(v8::String::New(compoundIter->first.c_str()), getDataAsValue(compoundIter->second)); - compoundIter++; - } - return value; - } - if (data.array.size() > 0) { - v8::Handle value = v8::Array::New(); - std::list::const_iterator arrayIter = data.array.begin(); - uint32_t index = 0; - while(arrayIter != data.array.end()) { - value->Set(index++, getDataAsValue(*arrayIter)); - arrayIter++; - } - return value; - } - if (data.type == Data::VERBATIM) { - return v8::String::New(data.atom.c_str()); - } else { - return evalAsValue(data.atom); - } -} - -v8::Handle V8DataModel::jsPrint(const v8::Arguments& args) { - if (args.Length() > 0) { - v8::String::AsciiValue printMsg(args[0]->ToString()); - std::cout << *printMsg; - } - return v8::Undefined(); -} - -v8::Handle V8DataModel::jsIn(const v8::Arguments& args) { - V8DataModel* INSTANCE = static_cast(v8::External::Unwrap(args.Data())); - for (unsigned int i = 0; i < args.Length(); i++) { - if (args[i]->IsString()) { - std::string stateName(*v8::String::AsciiValue(args[i]->ToString())); - if (Interpreter::isMember(INSTANCE->_interpreter->getState(stateName), INSTANCE->_interpreter->getConfiguration())) { - continue; - } - } - return v8::Boolean::New(false); - } - return v8::Boolean::New(true); -} - -v8::Handle V8DataModel::jsGetEventName(v8::Local property, - const v8::AccessorInfo &info) { - Event* event = static_cast(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); - return v8::String::New(event->name.c_str()); -} - -v8::Handle V8DataModel::jsGetEventType(v8::Local property, - const v8::AccessorInfo &info) { - Event* event = static_cast(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); - switch (event->type) { - case Event::PLATFORM: - return v8::String::New("platform"); - break; - case Event::INTERNAL: - return v8::String::New("internal"); - break; - case Event::EXTERNAL: - return v8::String::New("external"); - break; - default: - return v8::String::New(""); - break; - } -} - -v8::Handle V8DataModel::jsGetEventSendId(v8::Local property, - const v8::AccessorInfo &info) { - Event* event = static_cast(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); - return v8::String::New(event->sendid.c_str()); - -} - -v8::Handle V8DataModel::jsGetEventOrigin(v8::Local property, - const v8::AccessorInfo &info) { - Event* event = static_cast(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); - return v8::String::New(event->origin.c_str()); -} - -v8::Handle V8DataModel::jsGetEventOriginType(v8::Local property, - const v8::AccessorInfo &info) { - Event* event = static_cast(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); - return v8::String::New(event->origintype.c_str()); -} - -v8::Handle V8DataModel::jsGetEventInvokeId(v8::Local property, - const v8::AccessorInfo &info) { - Event* event = static_cast(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); - return v8::String::New(event->invokeid.c_str()); -} - -bool V8DataModel::validate(const std::string& location, const std::string& schema) { - return true; -} - -uint32_t V8DataModel::getLength(const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - v8::Handle result = evalAsValue(expr).As(); - return result->Length(); -} - -void V8DataModel::eval(const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - evalAsValue(expr); -} - -bool V8DataModel::evalAsBool(const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - v8::Handle result = evalAsValue(expr); - return(result->ToBoolean()->BooleanValue()); -} - -std::string V8DataModel::evalAsString(const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - v8::Handle result = evalAsValue(expr); - v8::String::AsciiValue data(result->ToString()); - return std::string(*data); -} - -void V8DataModel::assign(const std::string& location, const Data& data) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - - std::stringstream ssJSON; - ssJSON << data; - assign(location, ssJSON.str()); -// v8::Handle variable = evalAsValue(location).As(); -// assert(!variable.IsEmpty()); -// if (data.compound.size() > 0) { -// std::map::const_iterator compoundIter = data.compound.begin(); -// while(compoundIter != data.compound.end()) { -// variable->Set(v8::String::New(compoundIter->first.c_str()), getDataAsValue(compoundIter->second)); -// compoundIter++; -// } -// return; -// } else if (data.array.size() > 0) { -// std::list::const_iterator arrayIter = data.array.begin(); -// uint32_t index = 0; -// while(arrayIter != data.array.end()) { -// variable->Set(index++, getDataAsValue(*arrayIter)); -// arrayIter++; -// } -// } else if (data.type == Data::VERBATIM) { -// assign(location, "'" + data.atom + "'"); -// } else { -// assign(location, data.atom); -// } - -} - -void V8DataModel::assign(const std::string& location, const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - evalAsValue((location + " = " + expr).c_str()); -} - -v8::Handle V8DataModel::evalAsValue(const std::string& expr) { - v8::TryCatch tryCatch; - v8::Handle source = v8::String::New(expr.c_str()); - v8::Handle script = v8::Script::Compile(source); - - v8::Handle result; - if (!script.IsEmpty()) - result = script->Run(); - - if (script.IsEmpty() || result.IsEmpty()) { - // throw an exception - assert(tryCatch.HasCaught()); - Event exceptionEvent; - exceptionEvent.name = "error.execution"; - - std::string exceptionString(*v8::String::AsciiValue(tryCatch.Exception())); - exceptionEvent.compound["exception"] = Data(exceptionString, Data::VERBATIM);; - - v8::Handle message = tryCatch.Message(); - if (!message.IsEmpty()) { - std::string filename(*v8::String::AsciiValue(message->GetScriptResourceName())); - exceptionEvent.compound["filename"] = Data(filename, Data::VERBATIM); - - std::string sourceLine(*v8::String::AsciiValue(message->GetSourceLine())); - exceptionEvent.compound["sourceline"] = Data(sourceLine, Data::VERBATIM); - - std::stringstream ssLineNumber; - int lineNumber = message->GetLineNumber(); - ssLineNumber << lineNumber; - exceptionEvent.compound["linenumber"] = Data(ssLineNumber.str()); - - int startColumn = message->GetStartColumn(); - int endColumn = message->GetEndColumn(); - std::stringstream ssUnderline; - for (int i = 0; i < startColumn; i++) - ssUnderline << " "; - for (int i = startColumn; i < endColumn; i++) - ssUnderline << "^"; - exceptionEvent.compound["sourcemark"] = Data(ssUnderline.str(), Data::VERBATIM); - - std::string stackTrace(*v8::String::AsciiValue(tryCatch.StackTrace())); - exceptionEvent.compound["stacktrace"] = Data(stackTrace, Data::VERBATIM); - - } - - _interpreter->receiveInternal(exceptionEvent); - throw(exceptionEvent); - } - - return result; -} - -} \ No newline at end of file diff --git a/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp b/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp deleted file mode 100644 index 6452330..0000000 --- a/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp +++ /dev/null @@ -1,219 +0,0 @@ -#ifdef _WIN32 -#include -#include -#endif -#include "V8SCXMLDOM.h" - -#define ASSERT_ARGS1(args, type1) \ -assert(args.Length() == 1); \ -assert(args[0]->type1()); - -#define ASSERT_ARGS2(args, type1, type2) \ -assert(args.Length() == 2); \ -assert(args[0]->type1()); \ -assert(args[1]->type2()); - -namespace uscxml { - - using namespace Arabica::DOM; - using namespace Arabica::XPath; - - V8SCXMLDOM::V8SCXMLDOM() { - } - - v8::Handle V8SCXMLDOM::getDocument(Arabica::DOM::Document& document) { - v8::Handle documentTmpl = v8::ObjectTemplate::New(); - documentTmpl->Set(v8::String::New("createElement"), v8::FunctionTemplate::New(jsDocumentCreateElement, v8::External::New(reinterpret_cast(&document)))); - documentTmpl->Set(v8::String::New("evaluate"), v8::FunctionTemplate::New(jsDocumentEvaluate, v8::External::New(reinterpret_cast(&document)))); - return documentTmpl; - } - - v8::Handle V8SCXMLDOM::jsDocumentCreateElement(const v8::Arguments& args) { - assert(!args.Data().IsEmpty()); - assert(args.Data()->IsExternal()); - - ASSERT_ARGS1(args, IsString) - - Document* document = static_cast*>(v8::External::Unwrap(args.Data())); - v8::Persistent elementJS = v8::Persistent::New(getElementTmpl()->NewInstance()); - - v8::String::AsciiValue tagName(args[0]); - Element* element = new Element(document->createElement(*tagName)); - - elementJS->SetInternalField(0, v8::External::New(element)); - elementJS.MakeWeak(NULL, jsElementDestructor); - return elementJS; - } - - v8::Handle V8SCXMLDOM::jsDocumentEvaluate(const v8::Arguments& args) { - assert(!args.Data().IsEmpty()); - assert(args.Data()->IsExternal()); - - assert(args.Length() > 0); - assert(args[0]->IsString()); - - - Document* document = static_cast*>(v8::External::Unwrap(args.Data())); - Node context; - if (args.Length() > 1) { - assert(args[1]->ToObject()->InternalFieldCount() == 1); - context = *static_cast*>(v8::Local::Cast(args[1]->ToObject()->GetInternalField(0))->Value()); - } else { - context = *document; - } - v8::String::AsciiValue xpathExpr(args[0]); - XPath xpath; - XPathValue* xpathValue = new XPathValue(xpath.evaluate(*xpathExpr, context)); - - v8::Persistent xpathValueJS = v8::Persistent::New(getXPathValueTmpl()->NewInstance()); - xpathValueJS->SetInternalField(0, v8::External::New(xpathValue)); - xpathValueJS.MakeWeak(NULL, jsXPathValueDestructor); - return xpathValueJS; - } - - v8::Handle V8SCXMLDOM::jsElementTagName(v8::Local property, const v8::AccessorInfo &info) { - Element* element = static_cast*>(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); - return v8::String::New(element->getTagName().c_str()); - } - - v8::Handle V8SCXMLDOM::jsElementGetAttribute(const v8::Arguments& args) { - assert(!args.Data().IsEmpty()); - assert(args.Data()->IsExternal()); - - ASSERT_ARGS1(args, IsString); - - Element* element = static_cast*>(v8::External::Unwrap(args.Data())); - - v8::String::AsciiValue attribute(args[0]); - if (element->hasAttribute(*attribute)) { - return v8::String::New(element->getAttribute(*attribute).c_str()); - } - return v8::String::New(""); - } - - v8::Handle V8SCXMLDOM::jsElementSetAttribute(const v8::Arguments& args) { - v8::Local self = args.Holder(); - assert(self->InternalFieldCount() == 1); - - ASSERT_ARGS2(args, IsString, IsString); - - v8::String::AsciiValue attribute(args[0]); - v8::String::AsciiValue value(args[1]); - - Element* element = static_cast*>(v8::External::Unwrap(self->GetInternalField(0))); - element->setAttribute(*attribute, *value); - return v8::Undefined(); - } - - v8::Handle V8SCXMLDOM::jsXPathValueAsNodeSet(const v8::Arguments& args) { - v8::Local self = args.Holder(); - assert(self->InternalFieldCount() == 1); - XPathValue* xPathValue = static_cast*>(v8::External::Unwrap(self->GetInternalField(0))); - - v8::Persistent nodeSetJS = v8::Persistent::New(getNodeSetTmpl()->NewInstance()); - nodeSetJS->SetInternalField(0, v8::External::New(new NodeSet(xPathValue->asNodeSet()))); - nodeSetJS.MakeWeak(NULL, jsNodeSetDestructor); - return nodeSetJS; - - } - - void V8SCXMLDOM::jsNodeSetDestructor(v8::Persistent object, void* data) { - NodeSet* nodeSet = static_cast*>(v8::Local::Cast(object->ToObject()->GetInternalField(0))->Value()); - delete nodeSet; - } - - void V8SCXMLDOM::jsNodeDestructor(v8::Persistent object, void* data) { - Node* node = static_cast*>(v8::Local::Cast(object->ToObject()->GetInternalField(0))->Value()); - delete node; - } - - void V8SCXMLDOM::jsXPathValueDestructor(v8::Persistent object, void* data) { - XPathValue* xPathValue = static_cast*>(v8::Local::Cast(object->ToObject()->GetInternalField(0))->Value()); - delete xPathValue; - } - - void V8SCXMLDOM::jsElementDestructor(v8::Persistent object, void* data) { - Element* element = static_cast*>(v8::Local::Cast(object->ToObject()->GetInternalField(0))->Value()); - delete element; - } - - v8::Handle V8SCXMLDOM::jsNodeSetGetIndex(uint32_t index, const v8::AccessorInfo &info) { - v8::Local self = info.Holder(); - assert(self->InternalFieldCount() == 1); - NodeSet* nodeSet = static_cast*>(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); - - if (nodeSet->size() >= index) { - Node* node = new Node((*nodeSet)[index]); - v8::Persistent nodeJS = v8::Persistent::New(getNodeTmpl()->NewInstance()); - nodeJS->SetInternalField(0, v8::External::New(node)); - nodeJS.MakeWeak(NULL, jsNodeDestructor); - return nodeJS; - } - return v8::Undefined(); - } - - v8::Handle V8SCXMLDOM::jsNodeSetLength(const v8::Arguments& args) { - v8::Local self = args.Holder(); - assert(self->InternalFieldCount() == 1); - NodeSet* nodeSet = static_cast*>(v8::External::Unwrap(self->GetInternalField(0))); - return v8::Integer::New(nodeSet->size()); - } - - v8::Handle V8SCXMLDOM::jsNodeAppendChild(const v8::Arguments& args) { - v8::Local self = args.Holder(); - assert(self->InternalFieldCount() == 1); - Node* node = static_cast*>(v8::External::Unwrap(self->GetInternalField(0))); - - assert(args.Length() == 1); - assert(args[0]->IsObject()); - - Node* childToAppend = static_cast*>(v8::External::Unwrap(args[0]->ToObject()->GetInternalField(0))); - node->appendChild(*childToAppend); - - return v8::Undefined(); - } - - v8::Handle V8SCXMLDOM::xPathValueTmpl; - v8::Handle V8SCXMLDOM::getXPathValueTmpl() { - if (xPathValueTmpl.IsEmpty()) { - xPathValueTmpl = v8::ObjectTemplate::New(); - xPathValueTmpl->SetInternalFieldCount(1); - xPathValueTmpl->Set(v8::String::New("asNodeSet"), v8::FunctionTemplate::New(jsXPathValueAsNodeSet)); - } - return xPathValueTmpl; - } - - v8::Handle V8SCXMLDOM::nodeSetTmpl; - v8::Handle V8SCXMLDOM::getNodeSetTmpl() { - if (nodeSetTmpl.IsEmpty()) { - nodeSetTmpl = v8::ObjectTemplate::New(); - nodeSetTmpl->SetInternalFieldCount(1); - nodeSetTmpl->SetIndexedPropertyHandler(jsNodeSetGetIndex); - nodeSetTmpl->Set(v8::String::New("length"), v8::FunctionTemplate::New(jsNodeSetLength)); - } - return nodeSetTmpl; - } - - v8::Handle V8SCXMLDOM::nodeTmpl; - v8::Handle V8SCXMLDOM::getNodeTmpl() { - if (nodeTmpl.IsEmpty()) { - nodeTmpl = v8::ObjectTemplate::New(); - nodeTmpl->SetInternalFieldCount(1); - nodeTmpl->Set(v8::String::New("appendChild"), v8::FunctionTemplate::New(jsNodeAppendChild)); - } - return nodeTmpl; - } - - v8::Handle V8SCXMLDOM::elementTmpl; - v8::Handle V8SCXMLDOM::getElementTmpl() { - if (elementTmpl.IsEmpty()) { - elementTmpl = v8::ObjectTemplate::New(); - elementTmpl->SetAccessor(v8::String::New("tagName"), V8SCXMLDOM::jsElementTagName); - elementTmpl->Set(v8::String::New("getAttribute"), v8::FunctionTemplate::New(jsElementGetAttribute)); - elementTmpl->Set(v8::String::New("setAttribute"), v8::FunctionTemplate::New(jsElementSetAttribute)); - elementTmpl->SetInternalFieldCount(1); - } - return elementTmpl; - } - -} \ No newline at end of file diff --git a/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h b/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h deleted file mode 100644 index c513e48..0000000 --- a/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef V8SCXMLDOM_H_AREM0ZC4 -#define V8SCXMLDOM_H_AREM0ZC4 - -#include "uscxml/Interpreter.h" - -#include -#include - -#include - -namespace uscxml { - -class V8SCXMLDOM { -public: - V8SCXMLDOM(); - virtual ~V8SCXMLDOM() {}; - - static v8::Handle getDocument(Arabica::DOM::Document& document); - static v8::Handle jsDocumentCreateElement(const v8::Arguments& args); - static v8::Handle jsDocumentEvaluate(const v8::Arguments& args); - - static v8::Handle jsElementTagName(v8::Local property, const v8::AccessorInfo &info); - static v8::Handle jsElementGetAttribute(const v8::Arguments& args); - static v8::Handle jsElementSetAttribute(const v8::Arguments& args); - static void jsElementDestructor(v8::Persistent object, void* data); - - static v8::Handle jsXPathValueAsNodeSet(const v8::Arguments& args); - static void jsXPathValueDestructor(v8::Persistent object, void* data); - - static v8::Handle jsNodeSetGetIndex(uint32_t index, const v8::AccessorInfo &info); - static v8::Handle jsNodeSetLength(const v8::Arguments& args); - static void jsNodeSetDestructor(v8::Persistent object, void* data); - - static v8::Handle jsNodeAppendChild(const v8::Arguments& args); - static void jsNodeDestructor(v8::Persistent object, void* data); - - static v8::Handle getXPathValueTmpl(); - static v8::Handle getNodeSetTmpl(); - static v8::Handle getNodeTmpl(); - static v8::Handle getElementTmpl(); - - static v8::Handle xPathValueTmpl; - static v8::Handle nodeSetTmpl; - static v8::Handle nodeTmpl; - static v8::Handle elementTmpl; - -}; - -class V8Node { -}; - -class V8DOMDocument { - V8DOMDocument(); - virtual ~V8DOMDocument(); - - v8::Handle jsChildNodes(); -}; - -} - -#endif /* end of include guard: V8SCXMLDOM_H_AREM0ZC4 */ diff --git a/src/uscxml/invoker/modality/MMIComponent.cpp b/src/uscxml/invoker/modality/MMIComponent.cpp deleted file mode 100644 index 0655806..0000000 --- a/src/uscxml/invoker/modality/MMIComponent.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "MMIComponent.h" -#include "uscxml/Interpreter.h" - -namespace uscxml { - -MMIComponent::MMIComponent() { -} - - -MMIComponent::~MMIComponent() { -}; - -Invoker* MMIComponent::create(Interpreter* interpreter) { - MMIComponent* invoker = new MMIComponent(); - invoker->_interpreter = interpreter; - return invoker; -} - -Data MMIComponent::getDataModelVariables() { - Data data; - return data; -} - -void MMIComponent::send(SendRequest& req) { - -} - -void MMIComponent::cancel(const std::string sendId) { - assert(false); -} - -void MMIComponent::sendToParent(SendRequest& req) { - req.invokeid = _invokeId; - assert(false); -} - -void MMIComponent::invoke(InvokeRequest& req) { - _invokeId = req.invokeid; - -} - -} \ No newline at end of file diff --git a/src/uscxml/invoker/modality/MMIComponent.h b/src/uscxml/invoker/modality/MMIComponent.h deleted file mode 100644 index a83775f..0000000 --- a/src/uscxml/invoker/modality/MMIComponent.h +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef MMICOMPONENT_H_MZ1I550N -#define MMICOMPONENT_H_MZ1I550N - -#include "uscxml/Factory.h" - -namespace uscxml { - -class Interpreter; - -class MMIComponent : public Invoker { -public: - - enum State { - PAUSED, - RUNNING, - IDLE, - TERMINATED - }; - - MMIComponent(); - virtual ~MMIComponent(); - virtual Invoker* create(Interpreter* interpreter); - - 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); - -protected: - std::string _invokeId; - Interpreter* _interpreter; - - State _state; -}; - - -/** Base classes for MMI messages */ - -class MMICoreMessage { -public: - std::string source; - std::string target; - std::string data; - std::string requestId; -}; - -class MMICtxMessage : public MMICoreMessage { -public: - std::string context; -}; - -class MMIStartMessage : public MMICtxMessage { -public: - std::string content; - std::string contentURL; -}; - -class MMISimpleStatusMessage : public MMICtxMessage { -public: - std::string status; -}; - -class MMIStatusMessage : public MMISimpleStatusMessage { -public: - std::string statusInfo; -}; - -/** Concrete MMI messages */ - -class MMINewContextRequest : public MMICoreMessage {}; - -/***/ - -class MMIPauseRequest : public MMICtxMessage {}; -class MMIResumeRequest : public MMICtxMessage {}; -class MMICancelRequest : public MMICtxMessage {}; -class MMIClearContextRequest : public MMICtxMessage {}; -class MMIStatusRequest : public MMICtxMessage {}; - -/***/ - -class MMIStartRequest : public MMIStartMessage {}; -class MMIPrepareRequest : public MMIStartMessage {}; - -/***/ - -class MMIExtensionNotification : public MMICtxMessage { - std::string name; -}; - -/***/ - -class MMIStatusResponse : public MMISimpleStatusMessage {}; - -/***/ - -class MMIStartResponse : public MMIStatusMessage {}; -class MMIPrepareRespnse : public MMIStatusMessage {}; -class MMIPauseResponse : public MMIStatusMessage {}; -class MMIResumeResponse : public MMIStatusMessage {}; -class MMICancelResponse : public MMIStatusMessage {}; -class MMIDoneNotification : public MMIStatusMessage {}; -class MMINewContextResponse : public MMIStatusMessage {}; -class MMIClearContextResponse : public MMIStatusMessage {}; - -} - -#endif /* end of include guard: MMICOMPONENT_H_MZ1I550N */ diff --git a/src/uscxml/invoker/modality/UmundoComponent.cpp b/src/uscxml/invoker/modality/UmundoComponent.cpp deleted file mode 100644 index 22dd279..0000000 --- a/src/uscxml/invoker/modality/UmundoComponent.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "UmundoComponent.h" -#include "uscxml/Interpreter.h" - -namespace uscxml { - -UmundoComponent::UmundoComponent() { -} - - -UmundoComponent::~UmundoComponent() { - delete _invokedInterpreter; -}; - -Invoker* UmundoComponent::create(Interpreter* interpreter) { - UmundoComponent* invoker = new UmundoComponent(); - invoker->_parentInterpreter = interpreter; - return invoker; -} - -Data UmundoComponent::getDataModelVariables() { - Data data; - return data; -} - -void UmundoComponent::send(SendRequest& req) { - assert(false); -} - -void UmundoComponent::cancel(const std::string sendId) { - assert(false); -} - -void UmundoComponent::sendToParent(SendRequest& req) { - req.invokeid = _invokeId; - _parentInterpreter->receive(req); -} - -void UmundoComponent::invoke(InvokeRequest& req) { - _invokeId = req.invokeid; - _invokedInterpreter = Interpreter::fromURI(req.src); - DataModel* dataModel = _invokedInterpreter->getDataModel(); - if (dataModel != NULL) { - - } - _invokedInterpreter->setInvoker(this); - _invokedInterpreter->start(); -} - -} \ No newline at end of file diff --git a/src/uscxml/invoker/modality/UmundoComponent.h b/src/uscxml/invoker/modality/UmundoComponent.h deleted file mode 100644 index f2c76c4..0000000 --- a/src/uscxml/invoker/modality/UmundoComponent.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef UMUNDOCOMPONENT_H_VMW54W1R -#define UMUNDOCOMPONENT_H_VMW54W1R - -#include "MMIComponent.h" - -namespace uscxml { - -class Interpreter; - -class UmundoComponent : public MMIComponent { -public: - UmundoComponent(); - virtual ~UmundoComponent(); - virtual Invoker* create(Interpreter* interpreter); - - 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); - -protected: - std::string _invokeId; - Interpreter* _invokedInterpreter; - Interpreter* _parentInterpreter; -}; - -} - -#endif /* end of include guard: UMUNDOCOMPONENT_H_VMW54W1R */ diff --git a/src/uscxml/invoker/modality/miles/SpatialAudio.cpp b/src/uscxml/invoker/modality/miles/SpatialAudio.cpp deleted file mode 100644 index 5e394bd..0000000 --- a/src/uscxml/invoker/modality/miles/SpatialAudio.cpp +++ /dev/null @@ -1,189 +0,0 @@ -#include "uscxml/Common.h" -#include "SpatialAudio.h" -#include "uscxml/Interpreter.h" -#include "uscxml/URL.h" - -#include - -#ifdef _WIN32 -#define _USE_MATH_DEFINES -#endif -#include - -namespace uscxml { - -SpatialAudio::SpatialAudio() { - _audioDevOpen = false; - _audioDev = NULL; - _audioDevIndex = -1; - _pos = new float[3]; - _pos[0] = _pos[1] = _pos[2] = 0.0; - _listener = new float[3]; - _listener[0] = _listener[1] = _listener[2] = 0.0; -} - - -SpatialAudio::~SpatialAudio() { -}; - -Invoker* SpatialAudio::create(Interpreter* interpreter) { - SpatialAudio* invoker = new SpatialAudio(); - invoker->_interpreter = interpreter; - return invoker; -} - -Data SpatialAudio::getDataModelVariables() { - Data data; -// data.compound["foo"] = Data("32"); - return data; -} - -void SpatialAudio::send(SendRequest& req) { - if (!_audioDevOpen) { - _audioDev = miles_audio_device_open(_audioDevIndex, 0, 22050, 2, 1, 0); - if (_audioDev != NULL) { - _audioDevOpen = true; - float rolloffFactor = 0.2; - miles_audio_device_control(_audioDev, MILES_AUDIO_DEVICE_CTRL_SET_ROLLOFF_FACTOR, &rolloffFactor); - } - } - - if (boost::iequals(req.name, "play")) { - if (_audioDevOpen) { - getPosFromParams(req.params, _pos); - -// std::cout << "Source: "; -// for (int i = 0; i < 3; i++) { -// std::cout << _pos[i] << " "; -// } -// std::cout << std::endl; - - miles_audio_device_control(_audioDev, MILES_AUDIO_DEVICE_CTRL_SET_POSITION, _pos); - - char* buffer = (char*)malloc(_audioDev->chunk_size); - // skip wav header - _dataStream.seekg(44); - - while(_dataStream.readsome(buffer, _audioDev->chunk_size) != 0) { - miles_audio_device_write(_audioDev, buffer, _audioDev->chunk_size); - } - free(buffer); - } - } else if (boost::iequals(req.name, "move.listener")) { - if (_audioDevOpen) { - getPosFromParams(req.params, _listener); - - std::cout << "Listener: "; - for (int i = 0; i < 3; i++) { - std::cout << _listener[i] << " "; - } - std::cout << std::endl; - - miles_audio_device_control(_audioDev, MILES_AUDIO_DEVICE_CTRL_SET_LISTENER_POS, _listener); - - } - } -} - -void SpatialAudio::cancel(const std::string sendId) { - assert(false); -} - -void SpatialAudio::sendToParent(SendRequest& req) { - req.invokeid = _invokeId; - assert(false); -} - -void SpatialAudio::invoke(InvokeRequest& req) { - _invokeId = req.invokeid; - - if (req.src.length() > 0) { - Arabica::io::URI url(req.src); - if (!_interpreter->makeAbsolute(url)) { - LOG(ERROR) << "Source attribute for audio invoker has relative URI " << req.src << " with no base URI set for interpreter"; - return; - } - - URL scriptUrl(url.as_string()); - _dataStream << scriptUrl; - } - - getPosFromParams(req.params, _pos); - - struct miles_audio_device_description *devices; - int ndevs; - - ndevs = miles_audio_device_get_supported_devices(&devices); - - for (int i = 0; i < ndevs; i++) { - if ((devices[i].capabilities & MILES_AUDIO_DEVICE_CAPABILITY_SPATIAL) && - (devices[i].capabilities & MILES_AUDIO_DEVICE_CAPABILITY_OUTPUT)) { - _audioDevIndex = i; - break; - } - } -} - - void SpatialAudio::getPosFromParams(std::map >& params, float* position) { - // vector explicitly given - try { - if (params.find("x") != params.end()) - position[0] = boost::lexical_cast(params["x"].front()); - if (params.find("y") != params.end()) - position[1] = boost::lexical_cast(params["y"].front()); - if (params.find("z") != params.end()) - position[2] = boost::lexical_cast(params["z"].front()); - } catch (boost::bad_lexical_cast& e) { - LOG(ERROR) << "Cannot interpret x, y or z as float value in params: " << e.what(); - } - - try { - // right is an alias for x - if (params.find("right") != params.end()) - position[0] = boost::lexical_cast(params["right"].front()); - // height is an alias for y - if (params.find("height") != params.end()) - position[1] = boost::lexical_cast(params["height"].front()); - // front is an alias for z - if (params.find("front") != params.end()) - position[2] = boost::lexical_cast(params["front"].front()); - } catch (boost::bad_lexical_cast& e) { - LOG(ERROR) << "Cannot interpret right, height or front as float value in params: " << e.what(); - } - - // do we have a position on a circle? - try { - if (params.find("circle") != params.end()) { - float rad = posToRadian(params["circle"].front()); - position[0] = cosf(rad); - position[2] = -1 * sinf(rad); // z axis increases to front - } - } catch (boost::bad_lexical_cast& e) { - LOG(ERROR) << "Cannot interpret circle as float value in params: " << e.what(); - } -// std::cout << _pos[0] << ":" << _pos[1] << ":" << _pos[2] << std::endl; - -} - -float SpatialAudio::posToRadian(std::string& position) { - boost::trim(position); - float rad = 0; - - if (position.size() > 3 && boost::iequals("deg", position.substr(position.length() - 3, 3))) { - rad = boost::lexical_cast(position.substr(0, position.size() - 3)); - rad = fmodf(rad, 360); // into range [0-360] - rad /= 180; // into range [0-2] - rad *= M_PI; // into range [0-2PI] - rad -= M_PI_2; // 0 to top; - rad *= -1; // make clockwise - rad += 2 * M_PI; // make positive - } else if (position.size() > 3 && boost::iequals("rad", position.substr(position.length() - 3, 3))) { - rad = boost::lexical_cast(position.substr(0, position.size() - 3)); - rad = fmodf(rad, M_PI * 2); // into range [0-2*PI] - } else { - LOG(ERROR) << "Cannot make sense of position value " << position << ": does not end in 'deg', 'rad'"; - } - return rad; -} - -} \ No newline at end of file diff --git a/src/uscxml/invoker/modality/miles/SpatialAudio.h b/src/uscxml/invoker/modality/miles/SpatialAudio.h deleted file mode 100644 index f86e2ff..0000000 --- a/src/uscxml/invoker/modality/miles/SpatialAudio.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef SPATIALAUDIO_H_EH11SAQC -#define SPATIALAUDIO_H_EH11SAQC - -#include - -#include "uscxml/Utilities.h" -#include "../MMIComponent.h" - -extern "C" { -# include "miles/audio.h" -# include "miles/audio_codec.h" -# include "miles/audio_device.h" -} - -namespace uscxml { - -class Interpreter; - -class SpatialAudio : public MMIComponent { -public: - SpatialAudio(); - virtual ~SpatialAudio(); - virtual Invoker* create(Interpreter* interpreter); - - 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); - - void getPosFromParams(std::map >& params, float* position); - static float posToRadian(std::string& position); - -protected: - std::string _invokeId; - Interpreter* _invokedInterpreter; - - std::stringstream _dataStream; - - float* _pos; - float* _listener; - bool _audioDevOpen; - int _audioDevIndex; - struct miles_audio_device* _audioDev; - -}; - -} - -#endif /* end of include guard: SPATIALAUDIO_H_EH11SAQC */ diff --git a/src/uscxml/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/invoker/scxml/USCXMLInvoker.cpp deleted file mode 100644 index 70c2474..0000000 --- a/src/uscxml/invoker/scxml/USCXMLInvoker.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "uscxml/Common.h" -#include "USCXMLInvoker.h" -#include "uscxml/Interpreter.h" - -namespace uscxml { - -USCXMLInvoker::USCXMLInvoker() { -} - - -USCXMLInvoker::~USCXMLInvoker() { - delete _invokedInterpreter; -}; - -Invoker* USCXMLInvoker::create(Interpreter* interpreter) { - USCXMLInvoker* invoker = new USCXMLInvoker(); - invoker->_parentInterpreter = interpreter; - return invoker; -} - -Data USCXMLInvoker::getDataModelVariables() { - Data data; - return data; -} - -void USCXMLInvoker::send(SendRequest& req) { - assert(false); -} - -void USCXMLInvoker::cancel(const std::string sendId) { - assert(false); -} - -void USCXMLInvoker::sendToParent(SendRequest& req) { - req.invokeid = _invokeId; - _parentInterpreter->receive(req); -} - -void USCXMLInvoker::invoke(InvokeRequest& req) { - _invokeId = req.invokeid; - _invokedInterpreter = Interpreter::fromURI(req.src); - DataModel* dataModel = _invokedInterpreter->getDataModel(); - if (dataModel != NULL) { - - } - _invokedInterpreter->setInvoker(this); - _invokedInterpreter->start(); -} - -} \ No newline at end of file diff --git a/src/uscxml/invoker/scxml/USCXMLInvoker.h b/src/uscxml/invoker/scxml/USCXMLInvoker.h deleted file mode 100644 index 76657d8..0000000 --- a/src/uscxml/invoker/scxml/USCXMLInvoker.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef USCXMLINVOKER_H_OQFA21IO -#define USCXMLINVOKER_H_OQFA21IO - -#include "uscxml/Factory.h" - -namespace uscxml { - -class Interpreter; - -class USCXMLInvoker : public Invoker { -public: - USCXMLInvoker(); - virtual ~USCXMLInvoker(); - virtual Invoker* create(Interpreter* interpreter); - - 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); - -protected: - std::string _invokeId; - Interpreter* _invokedInterpreter; - Interpreter* _parentInterpreter; -}; - -} - -#endif /* end of include guard: USCXMLINVOKER_H_OQFA21IO */ 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 -#include - -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 -#include -#include - -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 +#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 +#include + + +///////////////////////////////////////////////////////////////// +// 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 +#include +#include + + +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 +#include + +// include OS dependent support for DLL +#ifdef PLUMA_SYS_WINDOWS + #include +#else + #include +#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 +#include +#include +#include + + +namespace pluma{ + +namespace dir{ + + +//////////////////////////////////////////////////////////// +void listFiles(std::list& 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 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 +#include +#include + + +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& 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 +#include + + +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& providers = it->second.providers; + std::list::iterator provIt; + for (provIt = providers.begin() ; provIt != providers.end() ; ++provIt){ + delete *provIt; + } + std::list().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* 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 lst = it->second; + std::list::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 lst = it->second; + std::list::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 +#include + +#include +#include +#include + +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* 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 providers; + }; + + typedef std::map ProvidersMap; + typedef std::map > 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 +#include +#include +#include + +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(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 files; + dir::listFiles(files, folder, PLUMA_LIB_EXTENSION, recursive); + // try to load every library + int res = 0; + std::list::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& 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* 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 +#include + +#include +#include + +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& 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* 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 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 +#include +#include + +//////////////////////////////////////////////////////////// +// 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 + 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 + void getProviders(std::vector& providers); +}; + +#include + +} + + +#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(); +/// // Load some dll +/// pluma.load("plugins/standard_devices"); +/// // Get device providers into a vector +/// std::vector 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 +void Pluma::acceptProviderType(){ + PluginManager::registerType( + ProviderType::PLUMA_PROVIDER_TYPE, + ProviderType::PLUMA_INTERFACE_VERSION, + ProviderType::PLUMA_INTERFACE_LOWEST_VERSION + ); +} + + +//////////////////////////////////////////////////////////// +template +void Pluma::getProviders(std::vector& providers){ + const std::list* lst = PluginManager::getProviders(ProviderType::PLUMA_PROVIDER_TYPE); + if (!lst) return; + providers.reserve(providers.size() + lst->size()); + std::list::const_iterator it; + for (it = lst->begin() ; it != lst->end() ; ++it) + providers.push_back(static_cast(*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 +#include + + +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 +#include + + +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 +/// 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 +/// +/// +///
+/// Keyboard code on the plugin side: +/// \code +/// #include +/// #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 +/// #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 +/// +/// #include "Device.hpp" +/// #include +/// #include +/// +/// int main(){ +/// +/// pluma::Pluma plugins; +/// // Tell plugins manager to accept providers of the type DeviceProvider +/// plugins.acceptProviderType(); +/// // Load library "standard_devices" from folder "plugins" +/// plugins.load("plugins", "standard_devices"); +/// +/// // Get device providers into a vector +/// std::vector 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 + * + * $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 +# 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 +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_NDIR_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIRECT_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIR_H) +# include +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_DIR_H) +# include +# include +# 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 +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (MAX_PATH) +# endif + + + /*** MS-DOS specifics ***/ +# elif defined(DIRENT_MSDOS_INTERFACE) +# include + + /* Borland defines file length macros in dir.h */ +# if defined(__BORLANDC__) +# include +# 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 +# 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 +#include +#include +#include +#include + +/* 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); + +/* + * + * open directory stream for reading + * DIR *opendir (const char *dirname); + * + * 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. + * + * 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: + * + * + * [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.] + *
+ *
+ */ +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; +} + + +/* + * + * read a directory entry + * struct dirent *readdir (DIR *dirp); + * + * 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. + * + * + * 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: + * + * + * [EBADF |dir parameter refers to an invalid directory stream. This value + * is not set reliably on all implementations.] + *
+ *
+ */ +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; +} + + +/* + * + * close directory stream. + * int closedir (DIR *dirp); + * + * Close directory stream opened by the `opendir' function. Close of + * directory stream invalidates the DIR structure as well as previously read + * dirent entry. + * + * 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. + * + */ +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; +} + + +/* + * + * rewind directory stream to the beginning + * void rewinddir (DIR *dirp); + * + * 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. + * + * 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/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp new file mode 100644 index 0000000..e25ece4 --- /dev/null +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -0,0 +1,409 @@ +#include "uscxml/Common.h" +#include "V8DataModel.h" +#include "dom/V8SCXMLDOM.h" +#include "uscxml/Message.h" +#include + +#ifdef BUILD_AS_PLUGINS +#include +#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()); +} + +DataModel* V8DataModel::create(Interpreter* interpreter) { + V8DataModel* dm = new V8DataModel(); + dm->_interpreter = interpreter; + v8::Locker locker; + v8::HandleScope scope; + + // see http://stackoverflow.com/questions/3171418/v8-functiontemplate-class-instance +// dm->_globalTemplate = v8::Persistent(v8::ObjectTemplate::New()); +// dm->_globalTemplate->Set(v8::String::New("In"), v8::FunctionTemplate::New(jsIn, v8::External::New(reinterpret_cast(this)))); + + v8::Handle global = v8::ObjectTemplate::New(); + global->Set(v8::String::New("In"), v8::FunctionTemplate::New(jsIn, v8::External::New(reinterpret_cast(dm)))); + global->Set(v8::String::New("print"), v8::FunctionTemplate::New(jsPrint, v8::External::New(reinterpret_cast(dm)))); + global->Set(v8::String::New("document"), V8SCXMLDOM::getDocument(interpreter->getDocument())); + + dm->_contexts.push_back(v8::Context::New(NULL, global)); + dm->setName(interpreter->getName()); + dm->setSessionId(interpreter->getSessionId()); + dm->eval("_ioprocessors = {};"); + + return dm; +} + +void V8DataModel::setSessionId(const std::string& sessionId) { + _sessionId = sessionId; + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.front()); + v8::Handle global = _contexts.front()->Global(); + + global->Set(v8::String::New("_sessionid"), v8::String::New(sessionId.c_str())); +} + +void V8DataModel::setName(const std::string& name) { + _name = name; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.front()); + v8::Handle global = _contexts.front()->Global(); + + global->Set(v8::String::New("_name"), v8::String::New(name.c_str())); +} + +V8DataModel::~V8DataModel() { + while(_contexts.size() > 0) { + _contexts.back().Dispose(); + _contexts.pop_back(); + } +} + +void V8DataModel::pushContext() { + _contexts.push_back(_contexts.back().New(_contexts.back())); +} + +void V8DataModel::popContext() { + if (_contexts.size() > 1) { + _contexts.back().Dispose(); + _contexts.pop_back(); + } +} + +void V8DataModel::initialize() { +} + +void V8DataModel::setEvent(const Event& event) { + _event = event; + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.front()); + v8::Handle global = _contexts.front()->Global(); + + // this is unfortunate - can't we store the template in the object? + if (_eventTemplate.IsEmpty()) { + v8::Handle localEventTemplate = v8::ObjectTemplate::New(); + localEventTemplate->SetInternalFieldCount(1); // we only have a single C++ object + localEventTemplate->SetAccessor(v8::String::New("name"), V8DataModel::jsGetEventName); + localEventTemplate->SetAccessor(v8::String::New("type"), V8DataModel::jsGetEventType); + localEventTemplate->SetAccessor(v8::String::New("sendid"), V8DataModel::jsGetEventSendId); + localEventTemplate->SetAccessor(v8::String::New("origin"), V8DataModel::jsGetEventOrigin); + localEventTemplate->SetAccessor(v8::String::New("origintype"), V8DataModel::jsGetEventOriginType); + localEventTemplate->SetAccessor(v8::String::New("invokeid"), V8DataModel::jsGetEventInvokeId); + _eventTemplate = v8::Persistent::New(localEventTemplate); + } + + assert(_eventTemplate->InternalFieldCount() == 1); + v8::Handle eventJS = _eventTemplate->NewInstance(); + eventJS->SetInternalField(0, v8::External::New(&_event)); + + eventJS->Set(v8::String::New("data"), getDataAsValue(event)); // set data part of _event + global->Set(v8::String::New("_event"), eventJS); +} + +Data V8DataModel::getStringAsData(const std::string& content) { + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.front()); + v8::Handle result = evalAsValue(content); + Data data = getValueAsData(result); + return data; +} + +Data V8DataModel::getValueAsData(const v8::Handle& value) { + Data data; + if (false) { + } else if (value->IsArray()) { + v8::Handle array = v8::Handle::Cast(value); + for (int i = 0; i < array->Length(); i++) { + data.array.push_back(getValueAsData(array->Get(i))); + } + } else if (value->IsBoolean()) { + data.atom = (value->ToBoolean()->Value() ? "true" : "false"); + } else if (value->IsBooleanObject()) { + LOG(ERROR) << "IsBooleanObject is unimplemented" << std::endl; + } else if (value->IsDate()) { + LOG(ERROR) << "IsDate is unimplemented" << std::endl; + } else if (value->IsExternal()) { + LOG(ERROR) << "IsExternal is unimplemented" << std::endl; + } else if (value->IsFalse()) { + LOG(ERROR) << "IsFalse is unimplemented" << std::endl; + } else if (value->IsFunction()) { + LOG(ERROR) << "IsFunction is unimplemented" << std::endl; + } else if (value->IsInt32()) { + int32_t prop = value->Int32Value(); + data.atom = toStr(prop); + } else if (value->IsNativeError()) { + LOG(ERROR) << "IsNativeError is unimplemented" << std::endl; + } else if (value->IsNull()) { + LOG(ERROR) << "IsNull is unimplemented" << std::endl; + } else if (value->IsNumber()) { + v8::String::AsciiValue prop(v8::Handle::Cast(v8::Handle::Cast(value))); + data.atom = *prop; + } else if (value->IsNumberObject()) { + LOG(ERROR) << "IsNumberObject is unimplemented" << std::endl; + } else if (value->IsObject()) { + v8::Handle object = v8::Handle::Cast(value); + v8::Local properties = object->GetPropertyNames(); + for (int i = 0; i < properties->Length(); i++) { + assert(properties->Get(i)->IsString()); + v8::String::AsciiValue key(v8::Handle::Cast(properties->Get(i))); + v8::Local property = object->Get(properties->Get(i)); + data.compound[*key] = getValueAsData(property); + } + } else if (value->IsRegExp()) { + LOG(ERROR) << "IsRegExp is unimplemented" << std::endl; + } else if(value->IsString()) { + v8::String::AsciiValue property(v8::Handle::Cast(value)); + data.atom = *property; + } else if(value->IsStringObject()) { + LOG(ERROR) << "IsStringObject is unimplemented" << std::endl; + } else if(value->IsTrue()) { + LOG(ERROR) << "IsTrue is unimplemented" << std::endl; + } else if(value->IsUint32()) { + LOG(ERROR) << "IsUint32 is unimplemented" << std::endl; + } else if(value->IsUndefined()) { + LOG(ERROR) << "IsUndefined is unimplemented" << std::endl; + } + return data; +} + +v8::Handle V8DataModel::getDataAsValue(const Data& data) { + if (data.compound.size() > 0) { + v8::Handle value = v8::Object::New(); + std::map::const_iterator compoundIter = data.compound.begin(); + while(compoundIter != data.compound.end()) { + value->Set(v8::String::New(compoundIter->first.c_str()), getDataAsValue(compoundIter->second)); + compoundIter++; + } + return value; + } + if (data.array.size() > 0) { + v8::Handle value = v8::Array::New(); + std::list::const_iterator arrayIter = data.array.begin(); + uint32_t index = 0; + while(arrayIter != data.array.end()) { + value->Set(index++, getDataAsValue(*arrayIter)); + arrayIter++; + } + return value; + } + if (data.type == Data::VERBATIM) { + return v8::String::New(data.atom.c_str()); + } else { + return evalAsValue(data.atom); + } +} + +v8::Handle V8DataModel::jsPrint(const v8::Arguments& args) { + if (args.Length() > 0) { + v8::String::AsciiValue printMsg(args[0]->ToString()); + std::cout << *printMsg; + } + return v8::Undefined(); +} + +v8::Handle V8DataModel::jsIn(const v8::Arguments& args) { + V8DataModel* INSTANCE = static_cast(v8::External::Unwrap(args.Data())); + for (unsigned int i = 0; i < args.Length(); i++) { + if (args[i]->IsString()) { + std::string stateName(*v8::String::AsciiValue(args[i]->ToString())); + if (Interpreter::isMember(INSTANCE->_interpreter->getState(stateName), INSTANCE->_interpreter->getConfiguration())) { + continue; + } + } + return v8::Boolean::New(false); + } + return v8::Boolean::New(true); +} + +v8::Handle V8DataModel::jsGetEventName(v8::Local property, + const v8::AccessorInfo &info) { + Event* event = static_cast(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); + return v8::String::New(event->name.c_str()); +} + +v8::Handle V8DataModel::jsGetEventType(v8::Local property, + const v8::AccessorInfo &info) { + Event* event = static_cast(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); + switch (event->type) { + case Event::PLATFORM: + return v8::String::New("platform"); + break; + case Event::INTERNAL: + return v8::String::New("internal"); + break; + case Event::EXTERNAL: + return v8::String::New("external"); + break; + default: + return v8::String::New(""); + break; + } +} + +v8::Handle V8DataModel::jsGetEventSendId(v8::Local property, + const v8::AccessorInfo &info) { + Event* event = static_cast(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); + return v8::String::New(event->sendid.c_str()); + +} + +v8::Handle V8DataModel::jsGetEventOrigin(v8::Local property, + const v8::AccessorInfo &info) { + Event* event = static_cast(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); + return v8::String::New(event->origin.c_str()); +} + +v8::Handle V8DataModel::jsGetEventOriginType(v8::Local property, + const v8::AccessorInfo &info) { + Event* event = static_cast(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); + return v8::String::New(event->origintype.c_str()); +} + +v8::Handle V8DataModel::jsGetEventInvokeId(v8::Local property, + const v8::AccessorInfo &info) { + Event* event = static_cast(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); + return v8::String::New(event->invokeid.c_str()); +} + +bool V8DataModel::validate(const std::string& location, const std::string& schema) { + return true; +} + +uint32_t V8DataModel::getLength(const std::string& expr) { + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.back()); + v8::Handle result = evalAsValue(expr).As(); + return result->Length(); +} + +void V8DataModel::eval(const std::string& expr) { + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.back()); + evalAsValue(expr); +} + +bool V8DataModel::evalAsBool(const std::string& expr) { + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.back()); + v8::Handle result = evalAsValue(expr); + return(result->ToBoolean()->BooleanValue()); +} + +std::string V8DataModel::evalAsString(const std::string& expr) { + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.back()); + v8::Handle result = evalAsValue(expr); + v8::String::AsciiValue data(result->ToString()); + return std::string(*data); +} + +void V8DataModel::assign(const std::string& location, const Data& data) { + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.front()); + + std::stringstream ssJSON; + ssJSON << data; + assign(location, ssJSON.str()); +// v8::Handle variable = evalAsValue(location).As(); +// assert(!variable.IsEmpty()); +// if (data.compound.size() > 0) { +// std::map::const_iterator compoundIter = data.compound.begin(); +// while(compoundIter != data.compound.end()) { +// variable->Set(v8::String::New(compoundIter->first.c_str()), getDataAsValue(compoundIter->second)); +// compoundIter++; +// } +// return; +// } else if (data.array.size() > 0) { +// std::list::const_iterator arrayIter = data.array.begin(); +// uint32_t index = 0; +// while(arrayIter != data.array.end()) { +// variable->Set(index++, getDataAsValue(*arrayIter)); +// arrayIter++; +// } +// } else if (data.type == Data::VERBATIM) { +// assign(location, "'" + data.atom + "'"); +// } else { +// assign(location, data.atom); +// } + +} + +void V8DataModel::assign(const std::string& location, const std::string& expr) { + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.back()); + evalAsValue((location + " = " + expr).c_str()); +} + +v8::Handle V8DataModel::evalAsValue(const std::string& expr) { + v8::TryCatch tryCatch; + v8::Handle source = v8::String::New(expr.c_str()); + v8::Handle script = v8::Script::Compile(source); + + v8::Handle result; + if (!script.IsEmpty()) + result = script->Run(); + + if (script.IsEmpty() || result.IsEmpty()) { + // throw an exception + assert(tryCatch.HasCaught()); + Event exceptionEvent; + exceptionEvent.name = "error.execution"; + + std::string exceptionString(*v8::String::AsciiValue(tryCatch.Exception())); + exceptionEvent.compound["exception"] = Data(exceptionString, Data::VERBATIM);; + + v8::Handle message = tryCatch.Message(); + if (!message.IsEmpty()) { + std::string filename(*v8::String::AsciiValue(message->GetScriptResourceName())); + exceptionEvent.compound["filename"] = Data(filename, Data::VERBATIM); + + std::string sourceLine(*v8::String::AsciiValue(message->GetSourceLine())); + exceptionEvent.compound["sourceline"] = Data(sourceLine, Data::VERBATIM); + + std::stringstream ssLineNumber; + int lineNumber = message->GetLineNumber(); + ssLineNumber << lineNumber; + exceptionEvent.compound["linenumber"] = Data(ssLineNumber.str()); + + int startColumn = message->GetStartColumn(); + int endColumn = message->GetEndColumn(); + std::stringstream ssUnderline; + for (int i = 0; i < startColumn; i++) + ssUnderline << " "; + for (int i = startColumn; i < endColumn; i++) + ssUnderline << "^"; + exceptionEvent.compound["sourcemark"] = Data(ssUnderline.str(), Data::VERBATIM); + + std::string stackTrace(*v8::String::AsciiValue(tryCatch.StackTrace())); + exceptionEvent.compound["stacktrace"] = Data(stackTrace, Data::VERBATIM); + + } + + _interpreter->receiveInternal(exceptionEvent); + throw(exceptionEvent); + } + + return result; +} + +} \ No newline at end of file diff --git a/src/uscxml/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 +#include + +#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 getNames() { + std::set 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& value); + + virtual std::string evalAsString(const std::string& expr); + virtual bool evalAsBool(const std::string& expr); + + static v8::Handle jsGetEventName(v8::Local property, + const v8::AccessorInfo &info); + static v8::Handle jsGetEventType(v8::Local property, + const v8::AccessorInfo &info); + static v8::Handle jsGetEventSendId(v8::Local property, + const v8::AccessorInfo &info); + static v8::Handle jsGetEventOrigin(v8::Local property, + const v8::AccessorInfo &info); + static v8::Handle jsGetEventOriginType(v8::Local property, + const v8::AccessorInfo &info); + static v8::Handle jsGetEventInvokeId(v8::Local property, + const v8::AccessorInfo &info); + + static v8::Handle jsIn(const v8::Arguments& args); + static v8::Handle jsPrint(const v8::Arguments& args); + + +protected: + std::list > _contexts; + Interpreter* _interpreter; + + std::string _sessionId; + std::string _name; + + Event _event; + v8::Persistent _globalTemplate; + v8::Persistent _eventTemplate; + + v8::Handle evalAsValue(const std::string& expr); + virtual v8::Handle 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/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp new file mode 100644 index 0000000..6452330 --- /dev/null +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp @@ -0,0 +1,219 @@ +#ifdef _WIN32 +#include +#include +#endif +#include "V8SCXMLDOM.h" + +#define ASSERT_ARGS1(args, type1) \ +assert(args.Length() == 1); \ +assert(args[0]->type1()); + +#define ASSERT_ARGS2(args, type1, type2) \ +assert(args.Length() == 2); \ +assert(args[0]->type1()); \ +assert(args[1]->type2()); + +namespace uscxml { + + using namespace Arabica::DOM; + using namespace Arabica::XPath; + + V8SCXMLDOM::V8SCXMLDOM() { + } + + v8::Handle V8SCXMLDOM::getDocument(Arabica::DOM::Document& document) { + v8::Handle documentTmpl = v8::ObjectTemplate::New(); + documentTmpl->Set(v8::String::New("createElement"), v8::FunctionTemplate::New(jsDocumentCreateElement, v8::External::New(reinterpret_cast(&document)))); + documentTmpl->Set(v8::String::New("evaluate"), v8::FunctionTemplate::New(jsDocumentEvaluate, v8::External::New(reinterpret_cast(&document)))); + return documentTmpl; + } + + v8::Handle V8SCXMLDOM::jsDocumentCreateElement(const v8::Arguments& args) { + assert(!args.Data().IsEmpty()); + assert(args.Data()->IsExternal()); + + ASSERT_ARGS1(args, IsString) + + Document* document = static_cast*>(v8::External::Unwrap(args.Data())); + v8::Persistent elementJS = v8::Persistent::New(getElementTmpl()->NewInstance()); + + v8::String::AsciiValue tagName(args[0]); + Element* element = new Element(document->createElement(*tagName)); + + elementJS->SetInternalField(0, v8::External::New(element)); + elementJS.MakeWeak(NULL, jsElementDestructor); + return elementJS; + } + + v8::Handle V8SCXMLDOM::jsDocumentEvaluate(const v8::Arguments& args) { + assert(!args.Data().IsEmpty()); + assert(args.Data()->IsExternal()); + + assert(args.Length() > 0); + assert(args[0]->IsString()); + + + Document* document = static_cast*>(v8::External::Unwrap(args.Data())); + Node context; + if (args.Length() > 1) { + assert(args[1]->ToObject()->InternalFieldCount() == 1); + context = *static_cast*>(v8::Local::Cast(args[1]->ToObject()->GetInternalField(0))->Value()); + } else { + context = *document; + } + v8::String::AsciiValue xpathExpr(args[0]); + XPath xpath; + XPathValue* xpathValue = new XPathValue(xpath.evaluate(*xpathExpr, context)); + + v8::Persistent xpathValueJS = v8::Persistent::New(getXPathValueTmpl()->NewInstance()); + xpathValueJS->SetInternalField(0, v8::External::New(xpathValue)); + xpathValueJS.MakeWeak(NULL, jsXPathValueDestructor); + return xpathValueJS; + } + + v8::Handle V8SCXMLDOM::jsElementTagName(v8::Local property, const v8::AccessorInfo &info) { + Element* element = static_cast*>(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); + return v8::String::New(element->getTagName().c_str()); + } + + v8::Handle V8SCXMLDOM::jsElementGetAttribute(const v8::Arguments& args) { + assert(!args.Data().IsEmpty()); + assert(args.Data()->IsExternal()); + + ASSERT_ARGS1(args, IsString); + + Element* element = static_cast*>(v8::External::Unwrap(args.Data())); + + v8::String::AsciiValue attribute(args[0]); + if (element->hasAttribute(*attribute)) { + return v8::String::New(element->getAttribute(*attribute).c_str()); + } + return v8::String::New(""); + } + + v8::Handle V8SCXMLDOM::jsElementSetAttribute(const v8::Arguments& args) { + v8::Local self = args.Holder(); + assert(self->InternalFieldCount() == 1); + + ASSERT_ARGS2(args, IsString, IsString); + + v8::String::AsciiValue attribute(args[0]); + v8::String::AsciiValue value(args[1]); + + Element* element = static_cast*>(v8::External::Unwrap(self->GetInternalField(0))); + element->setAttribute(*attribute, *value); + return v8::Undefined(); + } + + v8::Handle V8SCXMLDOM::jsXPathValueAsNodeSet(const v8::Arguments& args) { + v8::Local self = args.Holder(); + assert(self->InternalFieldCount() == 1); + XPathValue* xPathValue = static_cast*>(v8::External::Unwrap(self->GetInternalField(0))); + + v8::Persistent nodeSetJS = v8::Persistent::New(getNodeSetTmpl()->NewInstance()); + nodeSetJS->SetInternalField(0, v8::External::New(new NodeSet(xPathValue->asNodeSet()))); + nodeSetJS.MakeWeak(NULL, jsNodeSetDestructor); + return nodeSetJS; + + } + + void V8SCXMLDOM::jsNodeSetDestructor(v8::Persistent object, void* data) { + NodeSet* nodeSet = static_cast*>(v8::Local::Cast(object->ToObject()->GetInternalField(0))->Value()); + delete nodeSet; + } + + void V8SCXMLDOM::jsNodeDestructor(v8::Persistent object, void* data) { + Node* node = static_cast*>(v8::Local::Cast(object->ToObject()->GetInternalField(0))->Value()); + delete node; + } + + void V8SCXMLDOM::jsXPathValueDestructor(v8::Persistent object, void* data) { + XPathValue* xPathValue = static_cast*>(v8::Local::Cast(object->ToObject()->GetInternalField(0))->Value()); + delete xPathValue; + } + + void V8SCXMLDOM::jsElementDestructor(v8::Persistent object, void* data) { + Element* element = static_cast*>(v8::Local::Cast(object->ToObject()->GetInternalField(0))->Value()); + delete element; + } + + v8::Handle V8SCXMLDOM::jsNodeSetGetIndex(uint32_t index, const v8::AccessorInfo &info) { + v8::Local self = info.Holder(); + assert(self->InternalFieldCount() == 1); + NodeSet* nodeSet = static_cast*>(v8::Local::Cast(info.Holder()->GetInternalField(0))->Value()); + + if (nodeSet->size() >= index) { + Node* node = new Node((*nodeSet)[index]); + v8::Persistent nodeJS = v8::Persistent::New(getNodeTmpl()->NewInstance()); + nodeJS->SetInternalField(0, v8::External::New(node)); + nodeJS.MakeWeak(NULL, jsNodeDestructor); + return nodeJS; + } + return v8::Undefined(); + } + + v8::Handle V8SCXMLDOM::jsNodeSetLength(const v8::Arguments& args) { + v8::Local self = args.Holder(); + assert(self->InternalFieldCount() == 1); + NodeSet* nodeSet = static_cast*>(v8::External::Unwrap(self->GetInternalField(0))); + return v8::Integer::New(nodeSet->size()); + } + + v8::Handle V8SCXMLDOM::jsNodeAppendChild(const v8::Arguments& args) { + v8::Local self = args.Holder(); + assert(self->InternalFieldCount() == 1); + Node* node = static_cast*>(v8::External::Unwrap(self->GetInternalField(0))); + + assert(args.Length() == 1); + assert(args[0]->IsObject()); + + Node* childToAppend = static_cast*>(v8::External::Unwrap(args[0]->ToObject()->GetInternalField(0))); + node->appendChild(*childToAppend); + + return v8::Undefined(); + } + + v8::Handle V8SCXMLDOM::xPathValueTmpl; + v8::Handle V8SCXMLDOM::getXPathValueTmpl() { + if (xPathValueTmpl.IsEmpty()) { + xPathValueTmpl = v8::ObjectTemplate::New(); + xPathValueTmpl->SetInternalFieldCount(1); + xPathValueTmpl->Set(v8::String::New("asNodeSet"), v8::FunctionTemplate::New(jsXPathValueAsNodeSet)); + } + return xPathValueTmpl; + } + + v8::Handle V8SCXMLDOM::nodeSetTmpl; + v8::Handle V8SCXMLDOM::getNodeSetTmpl() { + if (nodeSetTmpl.IsEmpty()) { + nodeSetTmpl = v8::ObjectTemplate::New(); + nodeSetTmpl->SetInternalFieldCount(1); + nodeSetTmpl->SetIndexedPropertyHandler(jsNodeSetGetIndex); + nodeSetTmpl->Set(v8::String::New("length"), v8::FunctionTemplate::New(jsNodeSetLength)); + } + return nodeSetTmpl; + } + + v8::Handle V8SCXMLDOM::nodeTmpl; + v8::Handle V8SCXMLDOM::getNodeTmpl() { + if (nodeTmpl.IsEmpty()) { + nodeTmpl = v8::ObjectTemplate::New(); + nodeTmpl->SetInternalFieldCount(1); + nodeTmpl->Set(v8::String::New("appendChild"), v8::FunctionTemplate::New(jsNodeAppendChild)); + } + return nodeTmpl; + } + + v8::Handle V8SCXMLDOM::elementTmpl; + v8::Handle V8SCXMLDOM::getElementTmpl() { + if (elementTmpl.IsEmpty()) { + elementTmpl = v8::ObjectTemplate::New(); + elementTmpl->SetAccessor(v8::String::New("tagName"), V8SCXMLDOM::jsElementTagName); + elementTmpl->Set(v8::String::New("getAttribute"), v8::FunctionTemplate::New(jsElementGetAttribute)); + elementTmpl->Set(v8::String::New("setAttribute"), v8::FunctionTemplate::New(jsElementSetAttribute)); + elementTmpl->SetInternalFieldCount(1); + } + return elementTmpl; + } + +} \ No newline at end of file diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h new file mode 100644 index 0000000..c513e48 --- /dev/null +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h @@ -0,0 +1,61 @@ +#ifndef V8SCXMLDOM_H_AREM0ZC4 +#define V8SCXMLDOM_H_AREM0ZC4 + +#include "uscxml/Interpreter.h" + +#include +#include + +#include + +namespace uscxml { + +class V8SCXMLDOM { +public: + V8SCXMLDOM(); + virtual ~V8SCXMLDOM() {}; + + static v8::Handle getDocument(Arabica::DOM::Document& document); + static v8::Handle jsDocumentCreateElement(const v8::Arguments& args); + static v8::Handle jsDocumentEvaluate(const v8::Arguments& args); + + static v8::Handle jsElementTagName(v8::Local property, const v8::AccessorInfo &info); + static v8::Handle jsElementGetAttribute(const v8::Arguments& args); + static v8::Handle jsElementSetAttribute(const v8::Arguments& args); + static void jsElementDestructor(v8::Persistent object, void* data); + + static v8::Handle jsXPathValueAsNodeSet(const v8::Arguments& args); + static void jsXPathValueDestructor(v8::Persistent object, void* data); + + static v8::Handle jsNodeSetGetIndex(uint32_t index, const v8::AccessorInfo &info); + static v8::Handle jsNodeSetLength(const v8::Arguments& args); + static void jsNodeSetDestructor(v8::Persistent object, void* data); + + static v8::Handle jsNodeAppendChild(const v8::Arguments& args); + static void jsNodeDestructor(v8::Persistent object, void* data); + + static v8::Handle getXPathValueTmpl(); + static v8::Handle getNodeSetTmpl(); + static v8::Handle getNodeTmpl(); + static v8::Handle getElementTmpl(); + + static v8::Handle xPathValueTmpl; + static v8::Handle nodeSetTmpl; + static v8::Handle nodeTmpl; + static v8::Handle elementTmpl; + +}; + +class V8Node { +}; + +class V8DOMDocument { + V8DOMDocument(); + virtual ~V8DOMDocument(); + + v8::Handle jsChildNodes(); +}; + +} + +#endif /* end of include guard: V8SCXMLDOM_H_AREM0ZC4 */ diff --git a/src/uscxml/plugins/invoker/modality/MMIComponent.cpp b/src/uscxml/plugins/invoker/modality/MMIComponent.cpp new file mode 100644 index 0000000..0655806 --- /dev/null +++ b/src/uscxml/plugins/invoker/modality/MMIComponent.cpp @@ -0,0 +1,42 @@ +#include "MMIComponent.h" +#include "uscxml/Interpreter.h" + +namespace uscxml { + +MMIComponent::MMIComponent() { +} + + +MMIComponent::~MMIComponent() { +}; + +Invoker* MMIComponent::create(Interpreter* interpreter) { + MMIComponent* invoker = new MMIComponent(); + invoker->_interpreter = interpreter; + return invoker; +} + +Data MMIComponent::getDataModelVariables() { + Data data; + return data; +} + +void MMIComponent::send(SendRequest& req) { + +} + +void MMIComponent::cancel(const std::string sendId) { + assert(false); +} + +void MMIComponent::sendToParent(SendRequest& req) { + req.invokeid = _invokeId; + assert(false); +} + +void MMIComponent::invoke(InvokeRequest& req) { + _invokeId = req.invokeid; + +} + +} \ No newline at end of file diff --git a/src/uscxml/plugins/invoker/modality/MMIComponent.h b/src/uscxml/plugins/invoker/modality/MMIComponent.h new file mode 100644 index 0000000..a83775f --- /dev/null +++ b/src/uscxml/plugins/invoker/modality/MMIComponent.h @@ -0,0 +1,109 @@ +#ifndef MMICOMPONENT_H_MZ1I550N +#define MMICOMPONENT_H_MZ1I550N + +#include "uscxml/Factory.h" + +namespace uscxml { + +class Interpreter; + +class MMIComponent : public Invoker { +public: + + enum State { + PAUSED, + RUNNING, + IDLE, + TERMINATED + }; + + MMIComponent(); + virtual ~MMIComponent(); + virtual Invoker* create(Interpreter* interpreter); + + 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); + +protected: + std::string _invokeId; + Interpreter* _interpreter; + + State _state; +}; + + +/** Base classes for MMI messages */ + +class MMICoreMessage { +public: + std::string source; + std::string target; + std::string data; + std::string requestId; +}; + +class MMICtxMessage : public MMICoreMessage { +public: + std::string context; +}; + +class MMIStartMessage : public MMICtxMessage { +public: + std::string content; + std::string contentURL; +}; + +class MMISimpleStatusMessage : public MMICtxMessage { +public: + std::string status; +}; + +class MMIStatusMessage : public MMISimpleStatusMessage { +public: + std::string statusInfo; +}; + +/** Concrete MMI messages */ + +class MMINewContextRequest : public MMICoreMessage {}; + +/***/ + +class MMIPauseRequest : public MMICtxMessage {}; +class MMIResumeRequest : public MMICtxMessage {}; +class MMICancelRequest : public MMICtxMessage {}; +class MMIClearContextRequest : public MMICtxMessage {}; +class MMIStatusRequest : public MMICtxMessage {}; + +/***/ + +class MMIStartRequest : public MMIStartMessage {}; +class MMIPrepareRequest : public MMIStartMessage {}; + +/***/ + +class MMIExtensionNotification : public MMICtxMessage { + std::string name; +}; + +/***/ + +class MMIStatusResponse : public MMISimpleStatusMessage {}; + +/***/ + +class MMIStartResponse : public MMIStatusMessage {}; +class MMIPrepareRespnse : public MMIStatusMessage {}; +class MMIPauseResponse : public MMIStatusMessage {}; +class MMIResumeResponse : public MMIStatusMessage {}; +class MMICancelResponse : public MMIStatusMessage {}; +class MMIDoneNotification : public MMIStatusMessage {}; +class MMINewContextResponse : public MMIStatusMessage {}; +class MMIClearContextResponse : public MMIStatusMessage {}; + +} + +#endif /* end of include guard: MMICOMPONENT_H_MZ1I550N */ diff --git a/src/uscxml/plugins/invoker/modality/UmundoComponent.cpp b/src/uscxml/plugins/invoker/modality/UmundoComponent.cpp new file mode 100644 index 0000000..22dd279 --- /dev/null +++ b/src/uscxml/plugins/invoker/modality/UmundoComponent.cpp @@ -0,0 +1,49 @@ +#include "UmundoComponent.h" +#include "uscxml/Interpreter.h" + +namespace uscxml { + +UmundoComponent::UmundoComponent() { +} + + +UmundoComponent::~UmundoComponent() { + delete _invokedInterpreter; +}; + +Invoker* UmundoComponent::create(Interpreter* interpreter) { + UmundoComponent* invoker = new UmundoComponent(); + invoker->_parentInterpreter = interpreter; + return invoker; +} + +Data UmundoComponent::getDataModelVariables() { + Data data; + return data; +} + +void UmundoComponent::send(SendRequest& req) { + assert(false); +} + +void UmundoComponent::cancel(const std::string sendId) { + assert(false); +} + +void UmundoComponent::sendToParent(SendRequest& req) { + req.invokeid = _invokeId; + _parentInterpreter->receive(req); +} + +void UmundoComponent::invoke(InvokeRequest& req) { + _invokeId = req.invokeid; + _invokedInterpreter = Interpreter::fromURI(req.src); + DataModel* dataModel = _invokedInterpreter->getDataModel(); + if (dataModel != NULL) { + + } + _invokedInterpreter->setInvoker(this); + _invokedInterpreter->start(); +} + +} \ No newline at end of file diff --git a/src/uscxml/plugins/invoker/modality/UmundoComponent.h b/src/uscxml/plugins/invoker/modality/UmundoComponent.h new file mode 100644 index 0000000..f2c76c4 --- /dev/null +++ b/src/uscxml/plugins/invoker/modality/UmundoComponent.h @@ -0,0 +1,30 @@ +#ifndef UMUNDOCOMPONENT_H_VMW54W1R +#define UMUNDOCOMPONENT_H_VMW54W1R + +#include "MMIComponent.h" + +namespace uscxml { + +class Interpreter; + +class UmundoComponent : public MMIComponent { +public: + UmundoComponent(); + virtual ~UmundoComponent(); + virtual Invoker* create(Interpreter* interpreter); + + 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); + +protected: + std::string _invokeId; + Interpreter* _invokedInterpreter; + Interpreter* _parentInterpreter; +}; + +} + +#endif /* end of include guard: UMUNDOCOMPONENT_H_VMW54W1R */ diff --git a/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp new file mode 100644 index 0000000..13091ae --- /dev/null +++ b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp @@ -0,0 +1,197 @@ +#include "uscxml/Common.h" +#include "SpatialAudio.h" +#include "uscxml/Interpreter.h" +#include "uscxml/URL.h" + +#include + +#ifdef _WIN32 +#define _USE_MATH_DEFINES +#endif +#include + +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; + _audioDevIndex = -1; + _pos = new float[3]; + _pos[0] = _pos[1] = _pos[2] = 0.0; + _listener = new float[3]; + _listener[0] = _listener[1] = _listener[2] = 0.0; +} + + +SpatialAudio::~SpatialAudio() { +}; + +Invoker* SpatialAudio::create(Interpreter* interpreter) { + SpatialAudio* invoker = new SpatialAudio(); + invoker->_interpreter = interpreter; + return invoker; +} + +Data SpatialAudio::getDataModelVariables() { + Data data; +// data.compound["foo"] = Data("32"); + return data; +} + +void SpatialAudio::send(SendRequest& req) { + if (!_audioDevOpen) { + _audioDev = miles_audio_device_open(_audioDevIndex, 0, 22050, 2, 1, 0); + if (_audioDev != NULL) { + _audioDevOpen = true; + float rolloffFactor = 0.2; + miles_audio_device_control(_audioDev, MILES_AUDIO_DEVICE_CTRL_SET_ROLLOFF_FACTOR, &rolloffFactor); + } + } + + if (boost::iequals(req.name, "play")) { + if (_audioDevOpen) { + getPosFromParams(req.params, _pos); + +// std::cout << "Source: "; +// for (int i = 0; i < 3; i++) { +// std::cout << _pos[i] << " "; +// } +// std::cout << std::endl; + + miles_audio_device_control(_audioDev, MILES_AUDIO_DEVICE_CTRL_SET_POSITION, _pos); + + char* buffer = (char*)malloc(_audioDev->chunk_size); + // skip wav header + _dataStream.seekg(44); + + while(_dataStream.readsome(buffer, _audioDev->chunk_size) != 0) { + miles_audio_device_write(_audioDev, buffer, _audioDev->chunk_size); + } + free(buffer); + } + } else if (boost::iequals(req.name, "move.listener")) { + if (_audioDevOpen) { + getPosFromParams(req.params, _listener); + + std::cout << "Listener: "; + for (int i = 0; i < 3; i++) { + std::cout << _listener[i] << " "; + } + std::cout << std::endl; + + miles_audio_device_control(_audioDev, MILES_AUDIO_DEVICE_CTRL_SET_LISTENER_POS, _listener); + + } + } +} + +void SpatialAudio::cancel(const std::string sendId) { + assert(false); +} + +void SpatialAudio::sendToParent(SendRequest& req) { + req.invokeid = _invokeId; + assert(false); +} + +void SpatialAudio::invoke(InvokeRequest& req) { + _invokeId = req.invokeid; + + if (req.src.length() > 0) { + Arabica::io::URI url(req.src); + if (!_interpreter->makeAbsolute(url)) { + LOG(ERROR) << "Source attribute for audio invoker has relative URI " << req.src << " with no base URI set for interpreter"; + return; + } + + URL scriptUrl(url.as_string()); + _dataStream << scriptUrl; + } + + getPosFromParams(req.params, _pos); + + struct miles_audio_device_description *devices; + int ndevs; + + ndevs = miles_audio_device_get_supported_devices(&devices); + + for (int i = 0; i < ndevs; i++) { + if ((devices[i].capabilities & MILES_AUDIO_DEVICE_CAPABILITY_SPATIAL) && + (devices[i].capabilities & MILES_AUDIO_DEVICE_CAPABILITY_OUTPUT)) { + _audioDevIndex = i; + break; + } + } +} + + void SpatialAudio::getPosFromParams(std::map >& params, float* position) { + // vector explicitly given + try { + if (params.find("x") != params.end()) + position[0] = boost::lexical_cast(params["x"].front()); + if (params.find("y") != params.end()) + position[1] = boost::lexical_cast(params["y"].front()); + if (params.find("z") != params.end()) + position[2] = boost::lexical_cast(params["z"].front()); + } catch (boost::bad_lexical_cast& e) { + LOG(ERROR) << "Cannot interpret x, y or z as float value in params: " << e.what(); + } + + try { + // right is an alias for x + if (params.find("right") != params.end()) + position[0] = boost::lexical_cast(params["right"].front()); + // height is an alias for y + if (params.find("height") != params.end()) + position[1] = boost::lexical_cast(params["height"].front()); + // front is an alias for z + if (params.find("front") != params.end()) + position[2] = boost::lexical_cast(params["front"].front()); + } catch (boost::bad_lexical_cast& e) { + LOG(ERROR) << "Cannot interpret right, height or front as float value in params: " << e.what(); + } + + // do we have a position on a circle? + try { + if (params.find("circle") != params.end()) { + float rad = posToRadian(params["circle"].front()); + position[0] = cosf(rad); + position[2] = -1 * sinf(rad); // z axis increases to front + } + } catch (boost::bad_lexical_cast& e) { + LOG(ERROR) << "Cannot interpret circle as float value in params: " << e.what(); + } +// std::cout << _pos[0] << ":" << _pos[1] << ":" << _pos[2] << std::endl; + +} + +float SpatialAudio::posToRadian(std::string& position) { + boost::trim(position); + float rad = 0; + + if (position.size() > 3 && boost::iequals("deg", position.substr(position.length() - 3, 3))) { + rad = boost::lexical_cast(position.substr(0, position.size() - 3)); + rad = fmodf(rad, 360); // into range [0-360] + rad /= 180; // into range [0-2] + rad *= M_PI; // into range [0-2PI] + rad -= M_PI_2; // 0 to top; + rad *= -1; // make clockwise + rad += 2 * M_PI; // make positive + } else if (position.size() > 3 && boost::iequals("rad", position.substr(position.length() - 3, 3))) { + rad = boost::lexical_cast(position.substr(0, position.size() - 3)); + rad = fmodf(rad, M_PI * 2); // into range [0-2*PI] + } else { + LOG(ERROR) << "Cannot make sense of position value " << position << ": does not end in 'deg', 'rad'"; + } + return rad; +} + +} \ No newline at end of file diff --git a/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h new file mode 100644 index 0000000..bbbf478 --- /dev/null +++ b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h @@ -0,0 +1,58 @@ +#ifndef SPATIALAUDIO_H_EH11SAQC +#define SPATIALAUDIO_H_EH11SAQC + +#include + +#include "../MMIComponent.h" + +extern "C" { +# include "miles/audio.h" +# include "miles/audio_codec.h" +# include "miles/audio_device.h" +} + +namespace uscxml { + +class Interpreter; + +class SpatialAudio : public MMIComponent { +public: + SpatialAudio(); + virtual ~SpatialAudio(); + virtual Invoker* create(Interpreter* interpreter); + + virtual std::set getNames() { + std::set 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); + virtual void invoke(InvokeRequest& req); + virtual void sendToParent(SendRequest& req); + + void getPosFromParams(std::map >& params, float* position); + static float posToRadian(std::string& position); + +protected: + std::string _invokeId; + Interpreter* _invokedInterpreter; + + std::stringstream _dataStream; + + float* _pos; + float* _listener; + bool _audioDevOpen; + int _audioDevIndex; + struct miles_audio_device* _audioDev; + +}; + +} + +#endif /* end of include guard: SPATIALAUDIO_H_EH11SAQC */ diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp new file mode 100644 index 0000000..0e617b9 --- /dev/null +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp @@ -0,0 +1,62 @@ +#include "uscxml/Common.h" +#include "USCXMLInvoker.h" +#include "uscxml/Interpreter.h" + +#ifdef BUILD_AS_PLUGINS +#include +#endif + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host){ + host.add( new USCXMLInvokerProvider() ); + return true; +} +#endif + +USCXMLInvoker::USCXMLInvoker() { +} + + +USCXMLInvoker::~USCXMLInvoker() { + delete _invokedInterpreter; +}; + +Invoker* USCXMLInvoker::create(Interpreter* interpreter) { + USCXMLInvoker* invoker = new USCXMLInvoker(); + invoker->_parentInterpreter = interpreter; + return invoker; +} + +Data USCXMLInvoker::getDataModelVariables() { + Data data; + return data; +} + +void USCXMLInvoker::send(SendRequest& req) { + assert(false); +} + +void USCXMLInvoker::cancel(const std::string sendId) { + assert(false); +} + +void USCXMLInvoker::sendToParent(SendRequest& req) { + req.invokeid = _invokeId; + _parentInterpreter->receive(req); +} + +void USCXMLInvoker::invoke(InvokeRequest& req) { + _invokeId = req.invokeid; + _invokedInterpreter = Interpreter::fromURI(req.src); + DataModel* dataModel = _invokedInterpreter->getDataModel(); + if (dataModel != NULL) { + + } + _invokedInterpreter->setInvoker(this); + _invokedInterpreter->start(); +} + +} \ No newline at end of file diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h new file mode 100644 index 0000000..9068a24 --- /dev/null +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h @@ -0,0 +1,45 @@ +#ifndef USCXMLINVOKER_H_OQFA21IO +#define USCXMLINVOKER_H_OQFA21IO + +#include "uscxml/Factory.h" + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class Interpreter; + +class USCXMLInvoker : public Invoker { +public: + USCXMLInvoker(); + virtual ~USCXMLInvoker(); + virtual Invoker* create(Interpreter* interpreter); + virtual std::set getNames() { + std::set 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); + virtual void invoke(InvokeRequest& req); + virtual void sendToParent(SendRequest& req); + +protected: + std::string _invokeId; + 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 + +#ifdef BUILD_AS_PLUGINS +#include +#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::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::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::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::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::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 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::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(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetDouble(msg, fieldDesc, strTo(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(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetUInt32(msg, fieldDesc, strTo(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(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetUInt64(msg, fieldDesc, strTo(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(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetFloat(msg, fieldDesc, strTo(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(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetInt32(msg, fieldDesc, strTo(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(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetInt64(msg, fieldDesc, strTo(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 +#include +#include +#include +#include + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class Interpreter; + +class UmundoInvoker : public Invoker, public umundo::TypedReceiver, public umundo::ResultSet { +public: + UmundoInvoker(); + virtual ~UmundoInvoker(); + virtual Invoker* create(Interpreter* interpreter); + + virtual std::set getNames() { + std::set 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 _svcs; + + static std::map _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 +#include +#endif + +#include "uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h" +#include "uscxml/Message.h" +#include +#include +#include +#include + +#include + +#include +#include + +#ifndef _WIN32 +#include +#include +#endif + +#ifdef BUILD_AS_PLUGINS +#include +#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::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::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 lock(_instanceMutex); + if (_instance == NULL) { + _instance = new EventIOServer(8080); + _instance->start(); + } + return _instance; +} + +void EventIOServer::registerProcessor(EventIOProcessor* processor) { + EventIOServer* INSTANCE = getInstance(); + tthread::lock_guard 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 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 +#endif + +#include +#include + +#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 getNames() { + std::set 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 _sendData; + + std::string _url; + + uscxml::DelayedEventQueue _asyncQueue; + uscxml::Interpreter* _interpreter; + std::map _httpConnections; + std::map _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 _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; -- cgit v0.12