summaryrefslogtreecommitdiffstats
path: root/src/uscxml/plugins
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2012-12-15 19:10:50 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2012-12-15 19:10:50 (GMT)
commitf1700edcd08d6215888e226618555ba43b5324ec (patch)
tree738f30de64f699c3f56d2e15963537c9493a24b4 /src/uscxml/plugins
parent2855a9ff7b423140237c9e988252fde0cbacd0a1 (diff)
downloaduscxml-f1700edcd08d6215888e226618555ba43b5324ec.zip
uscxml-f1700edcd08d6215888e226618555ba43b5324ec.tar.gz
uscxml-f1700edcd08d6215888e226618555ba43b5324ec.tar.bz2
Refactoring and plugin support
Diffstat (limited to 'src/uscxml/plugins')
-rw-r--r--src/uscxml/plugins/Plugins.cpp11
-rw-r--r--src/uscxml/plugins/Plugins.h17
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Config.hpp141
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Connector.hpp86
-rwxr-xr-xsrc/uscxml/plugins/Pluma/DLibrary.cpp106
-rwxr-xr-xsrc/uscxml/plugins/Pluma/DLibrary.hpp123
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Dir.cpp103
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Dir.hpp64
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Host.cpp179
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Host.hpp212
-rwxr-xr-xsrc/uscxml/plugins/Pluma/PluginManager.cpp201
-rwxr-xr-xsrc/uscxml/plugins/Pluma/PluginManager.hpp245
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Pluma.hpp171
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Pluma.inl52
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Provider.cpp52
-rwxr-xr-xsrc/uscxml/plugins/Pluma/Provider.hpp204
-rwxr-xr-xsrc/uscxml/plugins/Pluma/uce-dirent.h679
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp409
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h92
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp219
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h61
-rw-r--r--src/uscxml/plugins/invoker/modality/MMIComponent.cpp42
-rw-r--r--src/uscxml/plugins/invoker/modality/MMIComponent.h109
-rw-r--r--src/uscxml/plugins/invoker/modality/UmundoComponent.cpp49
-rw-r--r--src/uscxml/plugins/invoker/modality/UmundoComponent.h30
-rw-r--r--src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp197
-rw-r--r--src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h58
-rw-r--r--src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp62
-rw-r--r--src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h45
-rw-r--r--src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp487
-rw-r--r--src/uscxml/plugins/invoker/umundo/UmundoInvoker.h70
-rw-r--r--src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp370
-rw-r--r--src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h107
33 files changed, 5053 insertions, 0 deletions
diff --git a/src/uscxml/plugins/Plugins.cpp b/src/uscxml/plugins/Plugins.cpp
new file mode 100644
index 0000000..4e819bb
--- /dev/null
+++ b/src/uscxml/plugins/Plugins.cpp
@@ -0,0 +1,11 @@
+#include "Plugins.h"
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_PROVIDER_SOURCE(DataModel, 1, 1);
+PLUMA_PROVIDER_SOURCE(IOProcessor, 1, 1);
+PLUMA_PROVIDER_SOURCE(Invoker, 1, 1);
+#endif
+
+} \ No newline at end of file
diff --git a/src/uscxml/plugins/Plugins.h b/src/uscxml/plugins/Plugins.h
new file mode 100644
index 0000000..56dd1e2
--- /dev/null
+++ b/src/uscxml/plugins/Plugins.h
@@ -0,0 +1,17 @@
+#ifndef PLUGINS_H_M6G1NF1E
+#define PLUGINS_H_M6G1NF1E
+
+#include <Pluma/Pluma.hpp>
+#include "uscxml/Factory.h"
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_PROVIDER_HEADER(IOProcessor);
+PLUMA_PROVIDER_HEADER(Invoker);
+PLUMA_PROVIDER_HEADER(DataModel);
+#endif
+
+}
+
+#endif /* end of include guard: PLUGINS_H_M6G1NF1E */
diff --git a/src/uscxml/plugins/Pluma/Config.hpp b/src/uscxml/plugins/Pluma/Config.hpp
new file mode 100755
index 0000000..efd98c9
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Config.hpp
@@ -0,0 +1,141 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+//
+// Based on SFML configuration header
+// SFML Config.hpp:
+// http://www.sfml-dev.org/documentation/2.0/Config_8hpp-source.htm
+//
+// Acknowledgements to Simple and Fast Multimedia Library
+// http://www.sfml-dev.org/
+//
+////////////////////////////////////////////////////////////
+
+
+#ifndef PLUMA_CONFIG_HPP
+#define PLUMA_CONFIG_HPP
+
+
+////////////////////////////////////////////////////////////
+// Identify the operating system
+////////////////////////////////////////////////////////////
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+
+ // Windows
+ #define PLUMA_SYS_WINDOWS
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+ #ifndef NOMINMAX
+ #define NOMINMAX
+ #endif
+
+#elif defined(linux) || defined(__linux)
+
+ // Linux
+ #define PLUMA_SYS_LINUX
+
+#elif defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh)
+
+ // MacOS
+ #define PLUMA_SYS_MACOS
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+
+ // FreeBSD
+ #define PLUMA_SYS_FREEBSD
+
+#else
+
+ // Unsupported system
+ #error This operating system is not supported by this library
+
+#endif
+
+
+
+////////////////////////////////////////////////////////////
+// Define library file extension based on OS
+////////////////////////////////////////////////////////////
+#ifdef PLUMA_SYS_WINDOWS
+ #define PLUMA_LIB_EXTENSION "dll"
+#elif defined(PLUMA_SYS_MACOS)
+ #define PLUMA_LIB_EXTENSION "dylib"
+#elif defined(PLUMA_SYS_LINUX) || defined(PLUMA_SYS_FREEBSD)
+ #define PLUMA_LIB_EXTENSION "so"
+#else
+ // unknown library file type
+ #error Unknown library file extension for this operating system
+#endif
+
+
+////////////////////////////////////////////////////////////
+// Define portable import / export macros
+////////////////////////////////////////////////////////////
+#if defined(PLUMA_SYS_WINDOWS)
+
+ #ifndef PLUMA_STATIC
+
+ // Windows platforms
+ #ifdef PLUMA_EXPORTS
+
+ // From DLL side, we must export
+ #define PLUMA_API __declspec(dllexport)
+
+ #else
+
+ // From client application side, we must import
+ #define PLUMA_API __declspec(dllimport)
+
+ #endif
+
+ // For Visual C++ compilers, we also need to turn off this annoying C4251 warning.
+ // You can read lots ot different things about it, but the point is the code will
+ // just work fine, and so the simplest way to get rid of this warning is to disable it
+ #ifdef _MSC_VER
+
+ #pragma warning(disable : 4251)
+
+ #endif
+
+ #else
+
+ // No specific directive needed for static build
+ #define PLUMA_API
+
+ #endif
+
+#else
+
+ // Other platforms don't need to define anything
+ #define PLUMA_API
+
+#endif
+
+
+
+
+#endif // PLUMA_CONFIG_HPP
diff --git a/src/uscxml/plugins/Pluma/Connector.hpp b/src/uscxml/plugins/Pluma/Connector.hpp
new file mode 100755
index 0000000..3c227e7
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Connector.hpp
@@ -0,0 +1,86 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_CONNECTOR_HPP
+#define PLUMA_CONNECTOR_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Pluma.hpp>
+
+
+/////////////////////////////////////////////////////////////////
+// Define portable import/export macros for Plugin registration
+/////////////////////////////////////////////////////////////////
+#if defined(PLUMA_SYS_WINDOWS)
+
+ #ifndef PLUMA_STATIC_PLUGIN
+
+ // Windows platforms
+ #ifndef PLUGIN_IMPORTS
+
+ // From DLL side, we must export
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C" __declspec(dllexport)
+ #else
+ #define PLUMA_CONNECTOR __declspec(dllexport)
+ #endif
+
+ #else
+
+ // From client application side, we must import
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C" __declspec(dllimport)
+ #else
+ #define PLUMA_CONNECTOR __declspec(dllimport)
+ #endif
+
+ #endif
+
+ #else
+
+ // Only define the extern "C" for static build
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C"
+ #else
+ #define PLUMA_CONNECTOR
+ #endif
+
+ #endif
+
+#else
+
+ // Only define the extern "C" for other platforms
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C"
+ #else
+ #define PLUMA_CONNECTOR
+ #endif
+
+#endif
+
+
+#endif // PLUMA_CONNECTOR_HPP
diff --git a/src/uscxml/plugins/Pluma/DLibrary.cpp b/src/uscxml/plugins/Pluma/DLibrary.cpp
new file mode 100755
index 0000000..9b617db
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/DLibrary.cpp
@@ -0,0 +1,106 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/DLibrary.hpp>
+#include <cstdio>
+#include <string>
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+DLibrary* DLibrary::load(const std::string& path){
+ if ( path.empty() ){
+ fprintf(stderr, "Failed to load library: Empty path\n");
+ return NULL;
+ }
+ void* handle = NULL;
+
+ // load library - OS dependent operation
+ #ifdef PLUMA_SYS_WINDOWS
+ handle = ::LoadLibraryA(path.c_str());
+ if (!handle){
+ fprintf(stderr, "Failed to load library \"%s\".\n", path.c_str());
+ return NULL;
+ }
+ #else
+ handle = ::dlopen(path.c_str(), RTLD_NOW);
+ if (!handle){
+ const char* errorString = ::dlerror();
+ fprintf(stderr, "Failed to load library \"%s\".", path.c_str());
+ if(errorString) fprintf(stderr, " OS returned error: \"%s\".", errorString);
+ fprintf(stderr, "\n");
+ return NULL;
+ }
+ #endif
+ // return a DLibrary with the DLL handle
+ return new DLibrary(handle);
+}
+
+
+////////////////////////////////////////////////////////////
+DLibrary::~DLibrary(){
+ if (handle){
+ #ifdef PLUMA_SYS_WINDOWS
+ ::FreeLibrary( (HMODULE)handle );
+ #else
+ ::dlclose(handle);
+ #endif
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void* DLibrary::getSymbol(const std::string& symbol){
+ if (!handle){
+ fprintf(stderr, "Cannot inspect library symbols, library isn't loaded.\n");
+ return NULL;
+ }
+ void* res;
+ #ifdef PLUMA_SYS_WINDOWS
+ res = (void*)(::GetProcAddress((HMODULE)handle, symbol.c_str()));
+ #else
+ res = (void*)(::dlsym(handle, symbol.c_str()));
+ #endif
+ if (!res){
+ fprintf(stderr, "Library symbol \"%s\" not found.\n", symbol.c_str());
+ return NULL;
+ }
+ return res;
+}
+
+
+////////////////////////////////////////////////////////////
+DLibrary::DLibrary(void* handle):
+ handle(handle)
+{
+ // Nothing to do
+}
+
+} // namespace pluma
+
diff --git a/src/uscxml/plugins/Pluma/DLibrary.hpp b/src/uscxml/plugins/Pluma/DLibrary.hpp
new file mode 100755
index 0000000..1bb9bac
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/DLibrary.hpp
@@ -0,0 +1,123 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_DYNAMIC_LIBRARY_HPP
+#define PLUMA_DYNAMIC_LIBRARY_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <string>
+
+// include OS dependent support for DLL
+#ifdef PLUMA_SYS_WINDOWS
+ #include <Windows.h>
+#else
+ #include <dlfcn.h>
+#endif
+
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+/// \brief Manages a Dynamic Linking Library.
+///
+////////////////////////////////////////////////////////////
+class DLibrary{
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load a library.
+ ///
+ /// \param path Path to the library.
+ ///
+ /// \return Pointer to the loaded library, or NULL if failed.
+ ///
+ ////////////////////////////////////////////////////////////
+ static DLibrary* load(const std::string& path);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ /// Close and free the opened library (if any).
+ ///
+ ////////////////////////////////////////////////////////////
+ ~DLibrary();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get a symbol from the library.
+ ///
+ /// \param symbol Symbol that we're looking for.
+ ///
+ /// \return Pointer to what the symbol refers to, or NULL if
+ /// the symbol is not found.
+ ///
+ ////////////////////////////////////////////////////////////
+ void* getSymbol(const std::string& symbol);
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor.
+ ///
+ /// Library instances cannot be created, use load instead.
+ ///
+ /// \see load
+ ///
+ ////////////////////////////////////////////////////////////
+ DLibrary();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Constructor via library handle.
+ ///
+ /// Used on load function.
+ ///
+ /// \see load
+ ///
+ ////////////////////////////////////////////////////////////
+ DLibrary(void* handle);
+
+
+
+////////////////////////////////////////////////////////////
+// Member data
+////////////////////////////////////////////////////////////
+
+
+private:
+
+ void* handle; ///< Library handle.
+
+};
+
+
+} // namespace pluma
+
+
+#endif // PLUMA_DYNAMIC_LIBRARY_HPP
diff --git a/src/uscxml/plugins/Pluma/Dir.cpp b/src/uscxml/plugins/Pluma/Dir.cpp
new file mode 100755
index 0000000..860220e
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Dir.cpp
@@ -0,0 +1,103 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Dir.hpp>
+#include <Pluma/uce-dirent.h>
+#include <cstdio>
+#include <queue>
+
+
+namespace pluma{
+
+namespace dir{
+
+
+////////////////////////////////////////////////////////////
+void listFiles(std::list<std::string>& list, const std::string& folder, const std::string& extension, bool recursive){
+ DIR* dir;
+ DIR* subDir;
+ struct dirent *ent;
+ // try to open top folder
+ dir = opendir(folder.c_str());
+ if (dir == NULL){
+ // could not open directory
+ fprintf(stderr, "Could not open \"%s\" directory.\n", folder.c_str());
+ return;
+ }else{
+ // close, we'll process it next
+ closedir(dir);
+ }
+ // enqueue top folder
+ std::queue<std::string> folders;
+ folders.push(folder);
+
+ // run while has queued folders
+ while (!folders.empty()){
+ std::string currFolder = folders.front();
+ folders.pop();
+ dir = opendir(currFolder.c_str());
+ if (dir == NULL) continue;
+ // iterate through all the files and directories
+ while ((ent = readdir (dir)) != NULL) {
+ std::string name(ent->d_name);
+ // ignore "." and ".." directories
+ if ( name.compare(".") == 0 || name.compare("..") == 0) continue;
+ // add path to the file name
+ std::string path = currFolder;
+ path.append("/");
+ path.append(name);
+ // check if it's a folder by trying to open it
+ subDir = opendir(path.c_str());
+ if (subDir != NULL){
+ // it's a folder: close, we can process it later
+ closedir(subDir);
+ if (recursive) folders.push(path);
+ }else{
+ // it's a file
+ if (extension.empty()){
+ list.push_back(path);
+ }else{
+ // check file extension
+ size_t lastDot = name.find_last_of('.');
+ std::string ext = name.substr(lastDot+1);
+ if (ext.compare(extension) == 0){
+ // match
+ list.push_back(path);
+ }
+ } // endif (extension test)
+ } // endif (folder test)
+ } // endwhile (nextFile)
+ closedir(dir);
+ } // endwhile (queued folders)
+
+} // end listFiles
+
+
+} // namespace dir
+
+} // namespace pluma
diff --git a/src/uscxml/plugins/Pluma/Dir.hpp b/src/uscxml/plugins/Pluma/Dir.hpp
new file mode 100755
index 0000000..a94c477
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Dir.hpp
@@ -0,0 +1,64 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_DIRECTORY_HPP
+#define PLUMA_DIRECTORY_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <string>
+#include <list>
+
+
+namespace pluma{
+
+namespace dir{
+
+////////////////////////////////////////////////////////////
+/// \brief List files of a directory.
+///
+/// \param list The output files list.
+/// \param folder The folder where to search in
+/// \param extension A file extension filter,
+/// empty extension will match all files.
+/// \param recursive If true it will list files in
+/// sub directories as well.
+///
+////////////////////////////////////////////////////////////
+void listFiles(
+ std::list<std::string>& list,
+ const std::string& folder,
+ const std::string& extension = "",
+ bool recursive = false
+);
+
+
+} // namespace dir
+
+} // namespace pluma
+
+
+#endif // PLUMA_DIRECTORY_HPP
diff --git a/src/uscxml/plugins/Pluma/Host.cpp b/src/uscxml/plugins/Pluma/Host.cpp
new file mode 100755
index 0000000..eb37c33
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Host.cpp
@@ -0,0 +1,179 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Host.hpp>
+#include <cstdio>
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+Host::Host(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::add(Provider* provider){
+ if (provider == NULL){
+ fprintf(stderr, "Trying to add a null provider.\n");
+ return false;
+ }
+ if (!validateProvider(provider)){
+ delete provider;
+ return false;
+ }
+ addRequests[ provider->plumaGetType() ].push_back(provider);
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+Host::~Host(){
+ clearProviders();
+ // map frees itself
+}
+
+
+////////////////////////////////////////////////////////////
+void Host::clearProviders(){
+ ProvidersMap::iterator it;
+ for (it = knownTypes.begin() ; it != knownTypes.end() ; ++it){
+ std::list<Provider*>& providers = it->second.providers;
+ std::list<Provider*>::iterator provIt;
+ for (provIt = providers.begin() ; provIt != providers.end() ; ++provIt){
+ delete *provIt;
+ }
+ std::list<Provider*>().swap(providers);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::knows(const std::string& type) const{
+ return knownTypes.find(type) != knownTypes.end();
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Host::getVersion(const std::string& type) const{
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return it->second.version;
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Host::getLowestVersion(const std::string& type) const{
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return it->second.lowestVersion;
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+void Host::registerType(const std::string& type, unsigned int version, unsigned int lowestVersion){
+ if (!knows(type)){
+ ProviderInfo pi;
+ pi.version = version;
+ pi.lowestVersion = lowestVersion;
+ knownTypes[type] = pi;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+const std::list<Provider*>* Host::getProviders(const std::string& type) const{
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return &it->second.providers;
+ return NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::validateProvider(Provider* provider) const{
+ const std::string& type = provider->plumaGetType();
+ if ( !knows(type) ){
+ fprintf(stderr, "%s provider type isn't registered.\n", type.c_str());
+ return false;
+ }
+ if (!provider->isCompatible(*this)){
+ fprintf(stderr, "Incompatible %s provider version.\n", type.c_str());
+ return false;
+ }
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::registerProvider(Provider* provider){
+ if (!validateProvider(provider)){
+ delete provider;
+ return false;
+ }
+ knownTypes[ provider->plumaGetType() ].providers.push_back(provider);
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void Host::cancelAddictions(){
+ TempProvidersMap::iterator it;
+ for( it = addRequests.begin() ; it != addRequests.end() ; ++it){
+ std::list<Provider*> lst = it->second;
+ std::list<Provider*>::iterator providerIt;
+ for (providerIt = lst.begin() ; providerIt != lst.end() ; ++providerIt){
+ delete *providerIt;
+ }
+ }
+ // clear map
+ TempProvidersMap().swap(addRequests);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::confirmAddictions(){
+ if (addRequests.empty()) return false;
+ TempProvidersMap::iterator it;
+ for( it = addRequests.begin() ; it != addRequests.end() ; ++it){
+ std::list<Provider*> lst = it->second;
+ std::list<Provider*>::iterator providerIt;
+ for (providerIt = lst.begin() ; providerIt != lst.end() ; ++providerIt){
+ knownTypes[it->first].providers.push_back(*providerIt);
+ }
+ }
+ // clear map
+ TempProvidersMap().swap(addRequests);
+ return true;
+}
+
+
+} //namespace pluma
diff --git a/src/uscxml/plugins/Pluma/Host.hpp b/src/uscxml/plugins/Pluma/Host.hpp
new file mode 100755
index 0000000..cf049f5
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Host.hpp
@@ -0,0 +1,212 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_HOST_HPP
+#define PLUMA_HOST_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Provider.hpp>
+
+#include <vector>
+#include <list>
+#include <map>
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+/// \brief Manages providers.
+///
+////////////////////////////////////////////////////////////
+class PLUMA_API Host{
+friend class PluginManager;
+friend class Provider;
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Add provider.
+ ///
+ /// Provider type and version are checked. Only known and
+ /// valid provider types are accepted.
+ ///
+ /// \param provider Provider to be added.
+ ///
+ /// \return True if the provider is accepted.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool add(Provider* provider);
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor.
+ ///
+ /// New Host instances are not publicly allowed.
+ ///
+ ////////////////////////////////////////////////////////////
+ Host();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ /// Clears all hosted providers
+ ///
+ ////////////////////////////////////////////////////////////
+ ~Host();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Ckeck if a provider type is registered.
+ ///
+ /// \param type Provider type id.
+ ///
+ /// \return True if the type is registered
+ ///
+ ////////////////////////////////////////////////////////////
+ bool knows(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get version of a type of providers.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return The version of the provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ unsigned int getVersion(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get lowest compatible version of a type of providers.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return The lowest compatible version of the provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ unsigned int getLowestVersion(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Register a type of providers.
+ ///
+ /// \param type Provider type.
+ /// \param version Current version of that provider type.
+ /// \param lowestVersion Lowest compatible version of that provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ void registerType(const std::string& type, unsigned int version, unsigned int lowestVersion);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get providers of a certain type.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return Pointer to the list of providers of that \a type,
+ /// or NULL if \a type is not registered.
+ ///
+ ////////////////////////////////////////////////////////////
+ const std::list<Provider*>* getProviders(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Clears all hosted providers.
+ ///
+ ////////////////////////////////////////////////////////////
+ void clearProviders();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Validate provider type and version.
+ ///
+ /// \return True if the provider is acceptable.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool validateProvider(Provider* provider) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Clearly add a provider.
+ ///
+ /// Provider type and version are checked. Only known and
+ /// valid provider types are accepted.
+ /// If acepted, provider is directly stored.
+ ///
+ /// \param provider Provider to be added.
+ ///
+ /// \return True if the provider is accepted.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool registerProvider(Provider* provider);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Previous add calls are canceled.
+ ///
+ /// Added providers are not stored.
+ ///
+ /// \see add
+ ///
+ ////////////////////////////////////////////////////////////
+ void cancelAddictions();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Previous add calls are confirmed.
+ ///
+ /// Added providers are finally stored.
+ ///
+ /// \return True if something was stored.
+ ///
+ /// \see add
+ ///
+ ////////////////////////////////////////////////////////////
+ bool confirmAddictions();
+
+
+
+////////////////////////////////////////////////////////////
+// Member data
+////////////////////////////////////////////////////////////
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Structure with information about a provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ struct ProviderInfo{
+ unsigned int version;
+ unsigned int lowestVersion;
+ std::list<Provider*> providers;
+ };
+
+ typedef std::map<std::string, ProviderInfo > ProvidersMap;
+ typedef std::map<std::string, std::list<Provider*> > TempProvidersMap;
+
+ ProvidersMap knownTypes; ///< Map of registered types.
+ TempProvidersMap addRequests; ///< Temporarily added providers
+
+};
+
+} // namespace pluma
+
+#endif // PLUMA_HOST_HPP
diff --git a/src/uscxml/plugins/Pluma/PluginManager.cpp b/src/uscxml/plugins/Pluma/PluginManager.cpp
new file mode 100755
index 0000000..1124505
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/PluginManager.cpp
@@ -0,0 +1,201 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/PluginManager.hpp>
+#include <Pluma/DLibrary.hpp>
+#include <Pluma/Dir.hpp>
+#include <cstdio>
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+PluginManager::PluginManager(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+PluginManager::~PluginManager(){
+ unloadAll();
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::load(const std::string& path){
+ std::string plugName = getPluginName(path);
+ std::string realPath = resolvePathExtension(path);
+ DLibrary* lib = DLibrary::load(realPath);
+ if (!lib) return false;
+
+ fnRegisterPlugin* registerFunction;
+ registerFunction = reinterpret_cast<fnRegisterPlugin*>(lib->getSymbol("connect"));
+
+ if(!registerFunction){
+ fprintf(stderr, "Failed to initialize plugin \"%s\": connect function not found\n", plugName.c_str());
+ delete lib;
+ return false;
+ }
+ // try to initialize plugin:
+ if (!registerFunction(host)){
+ // plugin decided to fail
+ fprintf(stderr, "Self registry failed on plugin \"%s\".\n", plugName.c_str());
+ host.cancelAddictions();
+ delete lib;
+ return false;
+ }
+ // Store the library if addictions are confirmed
+ if (host.confirmAddictions())
+ libraries[plugName] = lib;
+ else{
+ // otherwise nothing was registered
+ fprintf(stderr, "Nothing registered by plugin \"%s\".\n", plugName.c_str());
+ delete lib;
+ return false;
+ }
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::load(const std::string& folder, const std::string& pluginName){
+ if (folder.empty())
+ return load(pluginName);
+ else if (folder[folder.size()-1] == '/' || folder[folder.size()-1] == '\\')
+ return load(folder + pluginName);
+ return load(folder + '/' + pluginName);
+}
+
+
+////////////////////////////////////////////////////////////
+int PluginManager::loadFromFolder(const std::string& folder, bool recursive){
+ std::list<std::string> files;
+ dir::listFiles(files, folder, PLUMA_LIB_EXTENSION, recursive);
+ // try to load every library
+ int res = 0;
+ std::list<std::string>::const_iterator it;
+ for (it = files.begin() ; it != files.end() ; ++it){
+ if ( load(*it) ) ++res;
+ }
+ return res;
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::unload(const std::string& pluginName){
+ std::string plugName = getPluginName(pluginName);
+ LibMap::iterator it = libraries.find(plugName);
+ if( it != libraries.end() ) {
+ delete it->second;
+ libraries.erase(it);
+ return true;
+ }
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void PluginManager::unloadAll(){
+
+ host.clearProviders();
+ LibMap::iterator it;
+ for (it = libraries.begin() ; it != libraries.end() ; ++it){
+ delete it->second;
+ }
+ libraries.clear();
+}
+
+
+////////////////////////////////////////////////////////////
+std::string PluginManager::getPluginName(const std::string& path){
+ size_t lastDash = path.find_last_of("/\\");
+ size_t lastDot = path.find_last_of('.');
+ if (lastDash == std::string::npos) lastDash = 0;
+ else ++lastDash;
+ if (lastDot < lastDash || lastDot == std::string::npos){
+ // path without extension
+ lastDot = path.length();
+ }
+ return path.substr(lastDash, lastDot-lastDash);
+}
+
+
+////////////////////////////////////////////////////////////
+std::string PluginManager::resolvePathExtension(const std::string& path){
+ size_t lastDash = path.find_last_of("/\\");
+ size_t lastDot = path.find_last_of('.');
+ if (lastDash == std::string::npos) lastDash = 0;
+ else ++lastDash;
+ if (lastDot < lastDash || lastDot == std::string::npos){
+ // path without extension, add it
+ return path + "." + PLUMA_LIB_EXTENSION;
+ }
+ return path;
+}
+
+
+////////////////////////////////////////////////////////////
+void PluginManager::registerType(const std::string& type, unsigned int version, unsigned int lowestVersion){
+ host.registerType(type, version, lowestVersion);
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::addProvider(Provider* provider){
+ if (provider == NULL){
+ fprintf(stderr, "Trying to add null provider\n");
+ return false;
+ }
+ return host.registerProvider(provider);
+}
+
+
+////////////////////////////////////////////////////////////
+void PluginManager::getLoadedPlugins(std::vector<const std::string*>& pluginNames) const{
+ pluginNames.reserve(pluginNames.size()+libraries.size());
+ LibMap::const_iterator it;
+ for(it = libraries.begin() ; it != libraries.end() ; ++it){
+ pluginNames.push_back(&(it->first));
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::isLoaded(const std::string& pluginName) const{
+ return libraries.find(getPluginName(pluginName)) != libraries.end();
+}
+
+
+////////////////////////////////////////////////////////////
+const std::list<Provider*>* PluginManager::getProviders(const std::string& type) const{
+ return host.getProviders(type);
+}
+
+
+
+} // namespace pluma
+
diff --git a/src/uscxml/plugins/Pluma/PluginManager.hpp b/src/uscxml/plugins/Pluma/PluginManager.hpp
new file mode 100755
index 0000000..e5ddf06
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/PluginManager.hpp
@@ -0,0 +1,245 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_PLUGIN_MANAGER_HPP
+#define PLUMA_PLUGIN_MANAGER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Host.hpp>
+
+#include <string>
+#include <map>
+
+namespace pluma{
+class DLibrary;
+
+////////////////////////////////////////////////////////////
+/// \brief Manages loaded plugins.
+///
+////////////////////////////////////////////////////////////
+class PLUMA_API PluginManager{
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ ////////////////////////////////////////////////////////////
+ ~PluginManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load a plugin given it's path
+ ///
+ /// \param path Path for the plugin, including plugin name. File extension
+ /// may be included, but is discouraged for better cross platform code.
+ /// If file extension isn't present on the path, Pluma will deduce it
+ /// from the operating system.
+ ///
+ /// \return True if the plugin is successfully loaded.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see loadFromFolder
+ /// \see unload
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ bool load(const std::string& path);
+
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load a plugin from a given folder
+ ///
+ /// \param folder The folder path.
+ /// \param pluginName Name of the plugin. File extension
+ /// may be included, but is discouraged for better cross platform code.
+ /// If file extension is omitted, Pluma will deduce it
+ /// from the operating system.
+ ///
+ /// \return True if the plugin is successfully loaded.
+ ///
+ /// \see load(const std::string&)
+ /// \see loadFromFolder
+ /// \see unload
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ bool load(const std::string& folder, const std::string& pluginName);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load all plugins from a given folder
+ ///
+ /// \param folder Path for the folder where the plug-ins are.
+ /// \param recursive If true it will search on sub-folders as well
+ ///
+ /// \return Number of successfully loaded plug-ins.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see unload
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ int loadFromFolder(const std::string& folder, bool recursive = false);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Unload a plugin.
+ ///
+ /// \param pluginName Name or path of the plugin.
+ ///
+ /// \return True if the plugin is successfully unloaded,
+ /// false if no such plugin exists on the manager.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see loadFromFolder
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ bool unload(const std::string& pluginName);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Unload all loaded plugins.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see loadFromFolder
+ /// \see unload
+ ///
+ ////////////////////////////////////////////////////////////
+ void unloadAll();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Directly add a new provider.
+ ///
+ /// \param provider Provider.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool addProvider(Provider* provider);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the name of all loaded plugins.
+ ///
+ /// \param pluginNames A vector to fill with the plugins names.
+ ///
+ ////////////////////////////////////////////////////////////
+ void getLoadedPlugins(std::vector<const std::string*>& pluginNames) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a plug-in is loaded.
+ ///
+ /// \param pluginName the plug-in tname o check.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool isLoaded(const std::string& pluginName) const;
+
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor.
+ ///
+ /// PluginManager cannot be publicly instantiated.
+ ///
+ ////////////////////////////////////////////////////////////
+ PluginManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Register a provider type
+ ///
+ /// \param type Provider type.
+ /// \param version Current version of that provider type.
+ /// \param lowestVersion Lowest compatible version of that provider type.
+ ///
+ /// \see Host::registerType
+ ///
+ ////////////////////////////////////////////////////////////
+ void registerType(const std::string& type, unsigned int version, unsigned int lowestVersion);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get providers of a certain type.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return Pointer to the list of providers of that \a type,
+ /// or NULL if \a type is not registered.
+ ///
+ /// \see Host::getProviders
+ ///
+ ////////////////////////////////////////////////////////////
+ const std::list<Provider*>* getProviders(const std::string& type) const;
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the plugin name (without extension) from its path
+ ///
+ /// \param path Plugin path.
+ ///
+ /// \return Name of the plugin.
+ ///
+ /// \see resolvePathExtension
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see unload
+ ///
+ ////////////////////////////////////////////////////////////
+ static std::string getPluginName(const std::string& path);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief If the plugin path omits it's extension, this method returns
+ /// the path plus the OS specific dll extension.
+ /// Return a copy of the path otherwise.
+ ///
+ /// \param path Plugin path.
+ ///
+ /// \return Path with extension.
+ ///
+ /// \see getPluginName
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see unload
+ ///
+ ////////////////////////////////////////////////////////////
+ static std::string resolvePathExtension(const std::string& path);
+
+
+private:
+
+ /// Signature for the plugin's registration function
+ typedef bool fnRegisterPlugin(Host&);
+ typedef std::map<std::string,DLibrary*> LibMap;
+
+ LibMap libraries; ///< Map containing the loaded libraries
+ Host host; ///< Host app proxy, holding all providers
+
+};
+
+} // namespace pluma
+
+#endif // PLUMA_PLUGIN_MANAGER_HPP
diff --git a/src/uscxml/plugins/Pluma/Pluma.hpp b/src/uscxml/plugins/Pluma/Pluma.hpp
new file mode 100755
index 0000000..a9d614e
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Pluma.hpp
@@ -0,0 +1,171 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_PLUMA_HPP
+#define PLUMA_PLUMA_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Provider.hpp>
+#include <Pluma/PluginManager.hpp>
+
+////////////////////////////////////////////////////////////
+// Andy macro to convert parameter to string
+////////////////////////////////////////////////////////////
+#define PLUMA_2STRING(X) #X
+
+////////////////////////////////////////////////////////////
+// Macro that helps host applications defining
+// their provider classes
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_HEADER(TYPE)\
+PLUMA_PROVIDER_HEADER_BEGIN(TYPE)\
+virtual TYPE* create() const = 0;\
+PLUMA_PROVIDER_HEADER_END
+
+////////////////////////////////////////////////////////////
+// Macro that generate first part of the provider definition
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_HEADER_BEGIN(TYPE)\
+class TYPE##Provider: public pluma::Provider{\
+private:\
+ friend class pluma::Pluma;\
+ static const unsigned int PLUMA_INTERFACE_VERSION;\
+ static const unsigned int PLUMA_INTERFACE_LOWEST_VERSION;\
+ static const std::string PLUMA_PROVIDER_TYPE;\
+ std::string plumaGetType() const{ return PLUMA_PROVIDER_TYPE; }\
+public:\
+ unsigned int getVersion() const{ return PLUMA_INTERFACE_VERSION; }
+
+////////////////////////////////////////////////////////////
+// Macro that generate last part of the provider definition
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_HEADER_END };
+
+////////////////////////////////////////////////////////////
+// Macro that generate the provider declaration
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_SOURCE(TYPE, Version, LowestVersion)\
+const std::string TYPE##Provider::PLUMA_PROVIDER_TYPE = PLUMA_2STRING( TYPE );\
+const unsigned int TYPE##Provider::PLUMA_INTERFACE_VERSION = Version;\
+const unsigned int TYPE##Provider::PLUMA_INTERFACE_LOWEST_VERSION = LowestVersion;
+
+
+////////////////////////////////////////////////////////////
+// Macro that helps plugins generating their provider implementations
+// PRE: SPECIALIZED_TYPE must inherit from BASE_TYPE
+////////////////////////////////////////////////////////////
+#define PLUMA_INHERIT_PROVIDER(SPECIALIZED_TYPE, BASE_TYPE)\
+class SPECIALIZED_TYPE##Provider: public BASE_TYPE##Provider{\
+public:\
+ BASE_TYPE * create() const{ return new SPECIALIZED_TYPE (); }\
+};
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+/// \brief Pluma plugins management
+///
+////////////////////////////////////////////////////////////
+class Pluma: public PluginManager{
+
+public:
+ ////////////////////////////////////////////////////////////
+ /// \brief Default Constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ Pluma();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Tell Pluma to accept a certain type of providers
+ ///
+ /// A Pluma object is able to accept multiple types of providers.
+ /// When a plugin is loaded, it tries to register it's providers
+ /// implementations. Those are only accepted by the host
+ /// application if it's accepting providers of that kind.
+ ///
+ /// \tparam ProviderType type of provider.
+ ///
+ ////////////////////////////////////////////////////////////
+ template<typename ProviderType>
+ void acceptProviderType();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the stored providers of a certain type.
+ ///
+ /// Providers are added at the end of the \a providers vector.
+ ///
+ /// \tparam ProviderType type of provider to be returned.
+ /// \param[out] providers Vector to fill with the existing
+ /// providers.
+ ///
+ ////////////////////////////////////////////////////////////
+ template<typename ProviderType>
+ void getProviders(std::vector<ProviderType*>& providers);
+};
+
+#include <Pluma/Pluma.inl>
+
+}
+
+
+#endif // PLUMA_PLUMA_HPP
+
+
+////////////////////////////////////////////////////////////
+/// \class pluma::Pluma
+///
+/// Pluma is the main class of Pluma library. Allows hosting
+/// applications to load/unload dlls in runtime (plugins), and
+/// to get providers of shared interface objects.
+///
+/// Example:
+/// \code
+/// pluma::Pluma pluma;
+/// // Tell it to accept providers of the type DeviceProvider
+/// pluma.acceptProviderType<DeviceProvider>();
+/// // Load some dll
+/// pluma.load("plugins/standard_devices");
+/// // Get device providers into a vector
+/// std::vector<DeviceProvider*> providers;
+/// pluma.getProviders(providers);
+/// // create a Device from the first provider
+/// if (!providers.empty()){
+/// Device* myDevice = providers.first()->create();
+/// // do something with myDevice
+/// std::cout << device->getDescription() << std::endl;
+/// // (...)
+/// delete myDevice;
+/// }
+/// \endcode
+///
+/// It is also possible to add local providers, providers that
+/// are defined directly on the host application. That can
+/// be useful to provide and use default implementations of certain
+/// interfaces, along with plugin implementations.
+///
+////////////////////////////////////////////////////////////
diff --git a/src/uscxml/plugins/Pluma/Pluma.inl b/src/uscxml/plugins/Pluma/Pluma.inl
new file mode 100755
index 0000000..c3b6ce7
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Pluma.inl
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+inline Pluma::Pluma(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+template<typename ProviderType>
+void Pluma::acceptProviderType(){
+ PluginManager::registerType(
+ ProviderType::PLUMA_PROVIDER_TYPE,
+ ProviderType::PLUMA_INTERFACE_VERSION,
+ ProviderType::PLUMA_INTERFACE_LOWEST_VERSION
+ );
+}
+
+
+////////////////////////////////////////////////////////////
+template<typename ProviderType>
+void Pluma::getProviders(std::vector<ProviderType*>& providers){
+ const std::list<Provider*>* lst = PluginManager::getProviders(ProviderType::PLUMA_PROVIDER_TYPE);
+ if (!lst) return;
+ providers.reserve(providers.size() + lst->size());
+ std::list<Provider*>::const_iterator it;
+ for (it = lst->begin() ; it != lst->end() ; ++it)
+ providers.push_back(static_cast<ProviderType*>(*it));
+}
diff --git a/src/uscxml/plugins/Pluma/Provider.cpp b/src/uscxml/plugins/Pluma/Provider.cpp
new file mode 100755
index 0000000..36d4da3
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Provider.cpp
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Provider.hpp>
+#include <Pluma/Host.hpp>
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+Provider::~Provider(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+bool Provider::isCompatible(const Host& host) const{
+ // check compatibility with host
+ const std::string& type = this->plumaGetType();
+ if (!host.knows(type)) return false;
+ unsigned int lowest = host.getLowestVersion(type);
+ unsigned int current = host.getVersion(type);
+ unsigned int myVersion = this->getVersion();
+ return lowest <= myVersion && myVersion <= current;
+}
+
+} // namespace pluma
diff --git a/src/uscxml/plugins/Pluma/Provider.hpp b/src/uscxml/plugins/Pluma/Provider.hpp
new file mode 100755
index 0000000..ea06497
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/Provider.hpp
@@ -0,0 +1,204 @@
+////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_PROVIDER_HPP
+#define PLUMA_PROVIDER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <string>
+
+
+namespace pluma{
+class Host;
+
+////////////////////////////////////////////////////////////
+/// \brief Interface to provide applications with objects from plugins.
+///
+////////////////////////////////////////////////////////////
+class PLUMA_API Provider{
+friend class Host;
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual ~Provider();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get provider version.
+ ///
+ /// \return Version number.
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual unsigned int getVersion() const = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check compatibility with host.
+ ///
+ /// The same provider may be compiled with different versions
+ /// on host side and on plugins side. This function checks if
+ /// a plugin provider is compatible with the current version of
+ /// the same provider type on the host side.
+ ///
+ /// \param host Host, proxy of host application.
+ ///
+ /// \return True if it's compatible with \a host.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool isCompatible(const Host& host) const;
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get provider type.
+ ///
+ /// Each provider defined on the host application is identified by
+ /// a unique type. Those types are automatically managed internally by
+ /// pluma.
+ ///
+ /// \return Provider type id.
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual std::string plumaGetType() const = 0;
+
+};
+
+} // namespace pluma
+
+
+#endif // PLUMA_PROVIDER_HPP
+
+
+////////////////////////////////////////////////////////////
+/// \class pluma::Provider
+/// The plugin specific implementations are unknown at the host side,
+/// only their shared interfaces are known. Then, host app needs a generic
+/// way of create interface objects. That's what provider classes are for.
+/// It is the factory design pattern
+/// (http://www.oodesign.com/factory-pattern.html)
+///
+/// Shared interfaces define their provider types (by inheriting from
+/// pluma::Provider). Hosts then use those tipes to get objects from the
+/// plugins.
+/// Plugins derive the shared interface providers so that they can provide
+/// host with specific implementations of the shared interface.
+/// Those specific providers are given to the host through a connect function.
+///
+///
+/// Example: A host app uses objects of type Device. A certain plugin
+/// defines a Keyboard, witch is a Device.
+/// The Host will use DeviceProviders to create objects of type Device.
+/// The plugin will provide host specifically with a KeyboardProvider.
+/// Other plugins may provide host with other derived DeviceProvider types.
+///
+/// Device hpp (shared):
+/// \code
+/// #include <Pluma/Pluma.hpp>
+/// class Device{
+/// public:
+/// virtual std::string getDescription() const = 0;
+/// };
+/// // create DevicedProvider class
+/// PLUMA_PROVIDER_HEADER(Device);
+/// \endcode
+///
+/// Device cpp (shared):
+/// \code
+/// #include "Device.hpp"
+/// generate DevicedProvider with version 6, and compatible with at least v.3
+/// PLUMA_PROVIDER_SOURCE(Device, 6, 3);
+/// \endcode
+///
+///
+/// <br>
+/// Keyboard code on the plugin side:
+/// \code
+/// #include <Pluma/Pluma.hpp>
+/// #include "Device.hpp"
+///
+/// class Keyboard: public Device{
+/// public:
+/// std::string getDescription() const{
+/// return "keyboard";
+/// }
+/// };
+///
+/// // create KeyboardProvider, it implements DeviceProvider
+/// PLUMA_INHERIT_PROVIDER(Keyboard, Device);
+/// \endcode
+///
+/// plugin connector:
+/// \code
+/// #include <Pluma/Connector.hpp>
+/// #include "Keyboard.hpp"
+///
+/// PLUMA_CONNECTOR
+/// bool connect(pluma::Host& host){
+/// // add a keyboard provider to host
+/// host.add( new KeyboardProvider() );
+/// return true;
+/// }
+/// \endcode
+///
+///
+/// Host application code:
+/// \code
+/// #include <Pluma/Pluma.hpp>
+///
+/// #include "Device.hpp"
+/// #include <iostream>
+/// #include <vector>
+///
+/// int main(){
+///
+/// pluma::Pluma plugins;
+/// // Tell plugins manager to accept providers of the type DeviceProvider
+/// plugins.acceptProviderType<DeviceProvider>();
+/// // Load library "standard_devices" from folder "plugins"
+/// plugins.load("plugins", "standard_devices");
+///
+/// // Get device providers into a vector
+/// std::vector<DeviceProvider*> providers;
+/// plugins.getProviders(providers);
+///
+/// // create a Device from the first provider
+/// if (!providers.empty()){
+/// Device* myDevice = providers.first()->create();
+/// // do something with myDevice
+/// std::cout << device->getDescription() << std::endl;
+/// // and delete it in the end
+/// delete myDevice;
+/// }
+/// return 0;
+/// }
+/// \endcode
+///
+////////////////////////////////////////////////////////////
diff --git a/src/uscxml/plugins/Pluma/uce-dirent.h b/src/uscxml/plugins/Pluma/uce-dirent.h
new file mode 100755
index 0000000..ecf78eb
--- /dev/null
+++ b/src/uscxml/plugins/Pluma/uce-dirent.h
@@ -0,0 +1,679 @@
+/*
+ * uce-dirent.h - operating system independent dirent implementation
+ *
+ * Copyright (C) 1998-2002 Toni Ronkko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * ``Software''), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * May 28 1998, Toni Ronkko <tronkko@messi.uku.fi>
+ *
+ * $Id: uce-dirent.h,v 1.7 2002/05/13 10:48:35 tr Exp $
+ *
+ * $Log: uce-dirent.h,v $
+ * Revision 1.7 2002/05/13 10:48:35 tr
+ * embedded some source code directly to the header so that no source
+ * modules need to be included in the MS Visual C project using the
+ * interface, removed all the dependencies to other headers of the `uce'
+ * library so that the header can be made public
+ *
+ * Revision 1.6 2002/04/12 16:22:04 tr
+ * Unified Compiling Environment (UCE) replaced `std' library
+ *
+ * Revision 1.5 2001/07/20 16:33:40 tr
+ * moved to `std' library and re-named defines accordingly
+ *
+ * Revision 1.4 2001/07/10 16:47:18 tronkko
+ * revised comments
+ *
+ * Revision 1.3 2001/01/11 13:16:43 tr
+ * using ``uce-machine.h'' for finding out defines such as `FREEBSD'
+ *
+ * Revision 1.2 2000/10/08 16:00:41 tr
+ * copy of FreeBSD man page
+ *
+ * Revision 1.1 2000/07/10 05:53:16 tr
+ * Initial revision
+ *
+ * Revision 1.2 1998/07/19 18:29:14 tr
+ * Added error reporting capabilities and some asserts.
+ *
+ * Revision 1.1 1998/07/04 16:27:51 tr
+ * Initial revision
+ *
+ *
+ * MSVC 1.0 scans automatic dependencies incorrectly when your project
+ * contains this very header. The problem is that MSVC cannot handle
+ * include directives inside #if..#endif block those are never entered.
+ * Since this header ought to compile in many different operating systems,
+ * there had to be several conditional blocks that are compiled only in
+ * operating systems for what they were designed for. MSVC 1.0 cannot
+ * handle inclusion of sys/dir.h in a part that is compiled only in Apollo
+ * operating system. To fix the problem you need to insert DIR.H into
+ * SYSINCL.DAT located in MSVC\BIN directory and restart visual C++.
+ * Consult manuals for more informaton about the problem.
+ *
+ * Since many UNIX systems have dirent.h we assume to have one also.
+ * However, if your UNIX system does not have dirent.h you can download one
+ * for example at: http://ftp.uni-mannheim.de/ftp/GNU/dirent/dirent.tar.gz.
+ * You can also see if you have one of dirent.h, direct.h, dir.h, ndir.h,
+ * sys/dir.h and sys/ndir.h somewhere. Try defining HAVE_DIRENT_H,
+ * HAVE_DIRECT_H, HAVE_DIR_H, HAVE_NDIR_H, HAVE_SYS_DIR_H and
+ * HAVE_SYS_NDIR_H according to the files found.
+ */
+#ifndef DIRENT_H
+#define DIRENT_H
+#define DIRENT_H_INCLUDED
+
+/* find out platform */
+#if defined(MSDOS) /* MS-DOS */
+#elif defined(__MSDOS__) /* Turbo C/Borland */
+# define MSDOS
+#elif defined(__DOS__) /* Watcom */
+# define MSDOS
+#endif
+
+#if defined(WIN32) /* MS-Windows */
+#elif defined(__NT__) /* Watcom */
+# define WIN32
+#elif defined(_WIN32) /* Microsoft */
+# define WIN32
+#elif defined(__WIN32__) /* Borland */
+# define WIN32
+#endif
+
+/*
+ * See what kind of dirent interface we have unless autoconf has already
+ * determinated that.
+ */
+#if !defined(HAVE_DIRENT_H) && !defined(HAVE_DIRECT_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_NDIR_H) && !defined(HAVE_DIR_H)
+# if defined(_MSC_VER) /* Microsoft C/C++ */
+ /* no dirent.h */
+# elif defined(__BORLANDC__) /* Borland C/C++ */
+# define HAVE_DIRENT_H
+# define VOID_CLOSEDIR
+# elif defined(__TURBOC__) /* Borland Turbo C */
+ /* no dirent.h */
+# elif defined(__WATCOMC__) /* Watcom C/C++ */
+# define HAVE_DIRECT_H
+# elif defined(__apollo) /* Apollo */
+# define HAVE_SYS_DIR_H
+# elif defined(__hpux) /* HP-UX */
+# define HAVE_DIRENT_H
+# elif defined(__alpha) || defined(__alpha__) /* Alpha OSF1 */
+# error "not implemented"
+# elif defined(__sgi) /* Silicon Graphics */
+# define HAVE_DIRENT_H
+# elif defined(sun) || defined(_sun) /* Sun Solaris */
+# define HAVE_DIRENT_H
+# elif defined(__FreeBSD__) /* FreeBSD */
+# define HAVE_DIRENT_H
+# elif defined(__linux__) /* Linux */
+# define HAVE_DIRENT_H
+# elif defined(__GNUC__) /* GNU C/C++ */
+# define HAVE_DIRENT_H
+# else
+# error "not implemented"
+# endif
+#endif
+
+/* include proper interface headers */
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+# ifdef FREEBSD
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+# else
+# define NAMLEN(dp) ((int)(strlen((dp)->d_name)))
+# endif
+
+#elif defined(HAVE_NDIR_H)
+# include <ndir.h>
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(HAVE_SYS_NDIR_H)
+# include <sys/ndir.h>
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(HAVE_DIRECT_H)
+# include <direct.h>
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(HAVE_DIR_H)
+# include <dir.h>
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(HAVE_SYS_DIR_H)
+# include <sys/types.h>
+# include <sys/dir.h>
+# ifndef dirent
+# define dirent direct
+# endif
+# define NAMLEN(dp) ((int)((dp)->d_namlen))
+
+#elif defined(MSDOS) || defined(WIN32)
+
+ /* figure out type of underlaying directory interface to be used */
+# if defined(WIN32)
+# define DIRENT_WIN32_INTERFACE
+# elif defined(MSDOS)
+# define DIRENT_MSDOS_INTERFACE
+# else
+# error "missing native dirent interface"
+# endif
+
+ /*** WIN32 specifics ***/
+# if defined(DIRENT_WIN32_INTERFACE)
+# include <windows.h>
+# if !defined(DIRENT_MAXNAMLEN)
+# define DIRENT_MAXNAMLEN (MAX_PATH)
+# endif
+
+
+ /*** MS-DOS specifics ***/
+# elif defined(DIRENT_MSDOS_INTERFACE)
+# include <dos.h>
+
+ /* Borland defines file length macros in dir.h */
+# if defined(__BORLANDC__)
+# include <dir.h>
+# if !defined(DIRENT_MAXNAMLEN)
+# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT))
+# endif
+# if !defined(_find_t)
+# define _find_t find_t
+# endif
+
+ /* Turbo C defines ffblk structure in dir.h */
+# elif defined(__TURBOC__)
+# include <dir.h>
+# if !defined(DIRENT_MAXNAMLEN)
+# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT))
+# endif
+# define DIRENT_USE_FFBLK
+
+ /* MSVC */
+# elif defined(_MSC_VER)
+# if !defined(DIRENT_MAXNAMLEN)
+# define DIRENT_MAXNAMLEN (12)
+# endif
+
+ /* Watcom */
+# elif defined(__WATCOMC__)
+# if !defined(DIRENT_MAXNAMLEN)
+# if defined(__OS2__) || defined(__NT__)
+# define DIRENT_MAXNAMLEN (255)
+# else
+# define DIRENT_MAXNAMLEN (12)
+# endif
+# endif
+
+# endif
+# endif
+
+ /*** generic MS-DOS and MS-Windows stuff ***/
+# if !defined(NAME_MAX) && defined(DIRENT_MAXNAMLEN)
+# define NAME_MAX DIRENT_MAXNAMLEN
+# endif
+# if NAME_MAX < DIRENT_MAXNAMLEN
+# error "assertion failed: NAME_MAX >= DIRENT_MAXNAMLEN"
+# endif
+
+
+ /*
+ * Substitute for real dirent structure. Note that `d_name' field is a
+ * true character array although we have it copied in the implementation
+ * dependent data. We could save some memory if we had declared `d_name'
+ * as a pointer refering the name within implementation dependent data.
+ * We have not done that since some code may rely on sizeof(d_name) to be
+ * something other than four. Besides, directory entries are typically so
+ * small that it takes virtually no time to copy them from place to place.
+ */
+ typedef struct dirent {
+ char d_name[NAME_MAX + 1];
+
+ /*** Operating system specific part ***/
+# if defined(DIRENT_WIN32_INTERFACE) /*WIN32*/
+ WIN32_FIND_DATA data;
+# elif defined(DIRENT_MSDOS_INTERFACE) /*MSDOS*/
+# if defined(DIRENT_USE_FFBLK)
+ struct ffblk data;
+# else
+ struct _find_t data;
+# endif
+# endif
+ } dirent;
+
+ /* DIR substitute structure containing directory name. The name is
+ * essential for the operation of ``rewinndir'' function. */
+ typedef struct DIR {
+ char *dirname; /* directory being scanned */
+ dirent current; /* current entry */
+ int dirent_filled; /* is current un-processed? */
+
+ /*** Operating system specific part ***/
+# if defined(DIRENT_WIN32_INTERFACE)
+ HANDLE search_handle;
+# elif defined(DIRENT_MSDOS_INTERFACE)
+# endif
+ } DIR;
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* supply prototypes for dirent functions */
+static DIR *opendir (const char *dirname);
+static struct dirent *readdir (DIR *dirp);
+static int closedir (DIR *dirp);
+static void rewinddir (DIR *dirp);
+
+/*
+ * Implement dirent interface as static functions so that the user does not
+ * need to change his project in any way to use dirent function. With this
+ * it is sufficient to include this very header from source modules using
+ * dirent functions and the functions will be pulled in automatically.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+/* use ffblk instead of _find_t if requested */
+#if defined(DIRENT_USE_FFBLK)
+# define _A_ARCH (FA_ARCH)
+# define _A_HIDDEN (FA_HIDDEN)
+# define _A_NORMAL (0)
+# define _A_RDONLY (FA_RDONLY)
+# define _A_SUBDIR (FA_DIREC)
+# define _A_SYSTEM (FA_SYSTEM)
+# define _A_VOLID (FA_LABEL)
+# define _dos_findnext(dest) findnext(dest)
+# define _dos_findfirst(name,flags,dest) findfirst(name,dest,flags)
+#endif
+
+static int _initdir (DIR *p);
+static const char *_getdirname (const struct dirent *dp);
+static void _setdirname (struct DIR *dirp);
+
+/*
+ * <function name="opendir">
+ * <intro>open directory stream for reading
+ * <syntax>DIR *opendir (const char *dirname);
+ *
+ * <desc>Open named directory stream for read and return pointer to the
+ * internal working area that is used for retrieving individual directory
+ * entries. The internal working area has no fields of your interest.
+ *
+ * <ret>Returns a pointer to the internal working area or NULL in case the
+ * directory stream could not be opened. Global `errno' variable will set
+ * in case of error as follows:
+ *
+ * <table>
+ * [EACESS |Permission denied.
+ * [EMFILE |Too many open files used by the process.
+ * [ENFILE |Too many open files in system.
+ * [ENOENT |Directory does not exist.
+ * [ENOMEM |Insufficient memory.
+ * [ENOTDIR |dirname does not refer to directory. This value is not
+ * reliable on MS-DOS and MS-Windows platforms. Many
+ * implementations return ENOENT even when the name refers to a
+ * file.]
+ * </table>
+ * </function>
+ */
+static DIR *
+opendir(
+ const char *dirname)
+{
+ DIR *dirp;
+ assert (dirname != NULL);
+
+ dirp = (DIR*)malloc (sizeof (struct DIR));
+ if (dirp != NULL) {
+ char *p;
+
+ /* allocate room for directory name */
+ dirp->dirname = (char*) malloc (strlen (dirname) + 1 + strlen ("\\*.*"));
+ if (dirp->dirname == NULL) {
+ /* failed to duplicate directory name. errno set by malloc() */
+ free (dirp);
+ return NULL;
+ }
+ /* Copy directory name while appending directory separator and "*.*".
+ * Directory separator is not appended if the name already ends with
+ * drive or directory separator. Directory separator is assumed to be
+ * '/' or '\' and drive separator is assumed to be ':'. */
+ strcpy (dirp->dirname, dirname);
+ p = strchr (dirp->dirname, '\0');
+ if (dirp->dirname < p &&
+ *(p - 1) != '\\' && *(p - 1) != '/' && *(p - 1) != ':')
+ {
+ strcpy (p++, "/");
+ }
+# ifdef DIRENT_WIN32_INTERFACE
+ strcpy (p, "*"); /*scan files with and without extension in win32*/
+# else
+ strcpy (p, "*.*"); /*scan files with and without extension in DOS*/
+# endif
+
+ /* open stream */
+ if (_initdir (dirp) == 0) {
+ /* initialization failed */
+ free (dirp->dirname);
+ free (dirp);
+ return NULL;
+ }
+ }
+ return dirp;
+}
+
+
+/*
+ * <function name="readdir">
+ * <intro>read a directory entry
+ * <syntax>struct dirent *readdir (DIR *dirp);
+ *
+ * <desc>Read individual directory entry and return pointer to a structure
+ * containing the name of the entry. Individual directory entries returned
+ * include normal files, sub-directories, pseudo-directories "." and ".."
+ * and also volume labels, hidden files and system files in MS-DOS and
+ * MS-Windows. You might want to use stat(2) function to determinate which
+ * one are you dealing with. Many dirent implementations already contain
+ * equivalent information in dirent structure but you cannot depend on
+ * this.
+ *
+ * The dirent structure contains several system dependent fields that
+ * generally have no interest to you. The only interesting one is char
+ * d_name[] that is also portable across different systems. The d_name
+ * field contains the name of the directory entry without leading path.
+ * While d_name is portable across different systems the actual storage
+ * capacity of d_name varies from system to system and there is no portable
+ * way to find out it at compile time as different systems define the
+ * capacity of d_name with different macros and some systems do not define
+ * capacity at all (besides actual declaration of the field). If you really
+ * need to find out storage capacity of d_name then you might want to try
+ * NAME_MAX macro. The NAME_MAX is defined in POSIX standard althought
+ * there are many MS-DOS and MS-Windows implementations those do not define
+ * it. There are also systems that declare d_name as "char d_name[1]" and
+ * then allocate suitable amount of memory at run-time. Thanks to Alain
+ * Decamps (Alain.Decamps@advalvas.be) for pointing it out to me.
+ *
+ * This all leads to the fact that it is difficult to allocate space
+ * for the directory names when the very same program is being compiled on
+ * number of operating systems. Therefore I suggest that you always
+ * allocate space for directory names dynamically.
+ *
+ * <ret>
+ * Returns a pointer to a structure containing name of the directory entry
+ * in `d_name' field or NULL if there was an error. In case of an error the
+ * global `errno' variable will set as follows:
+ *
+ * <table>
+ * [EBADF |dir parameter refers to an invalid directory stream. This value
+ * is not set reliably on all implementations.]
+ * </table>
+ * </function>
+ */
+static struct dirent *
+readdir (DIR *dirp)
+{
+ assert (dirp != NULL);
+ if (dirp == NULL) {
+ errno = EBADF;
+ return NULL;
+ }
+
+#if defined(DIRENT_WIN32_INTERFACE)
+ if (dirp->search_handle == INVALID_HANDLE_VALUE) {
+ /* directory stream was opened/rewound incorrectly or it ended normally */
+ errno = EBADF;
+ return NULL;
+ }
+#endif
+
+ if (dirp->dirent_filled != 0) {
+ /*
+ * Directory entry has already been retrieved and there is no need to
+ * retrieve a new one. Directory entry will be retrieved in advance
+ * when the user calls readdir function for the first time. This is so
+ * because real dirent has separate functions for opening and reading
+ * the stream whereas Win32 and DOS dirents open the stream
+ * automatically when we retrieve the first file. Therefore, we have to
+ * save the first file when opening the stream and later we have to
+ * return the saved entry when the user tries to read the first entry.
+ */
+ dirp->dirent_filled = 0;
+ } else {
+ /* fill in entry and return that */
+#if defined(DIRENT_WIN32_INTERFACE)
+ if (FindNextFile (dirp->search_handle, &dirp->current.data) == FALSE) {
+ /* Last file has been processed or an error occured */
+ FindClose (dirp->search_handle);
+ dirp->search_handle = INVALID_HANDLE_VALUE;
+ errno = ENOENT;
+ return NULL;
+ }
+
+# elif defined(DIRENT_MSDOS_INTERFACE)
+ if (_dos_findnext (&dirp->current.data) != 0) {
+ /* _dos_findnext and findnext will set errno to ENOENT when no
+ * more entries could be retrieved. */
+ return NULL;
+ }
+# endif
+
+ _setdirname (dirp);
+ assert (dirp->dirent_filled == 0);
+ }
+ return &dirp->current;
+}
+
+
+/*
+ * <function name="closedir">
+ * <intro>close directory stream.
+ * <syntax>int closedir (DIR *dirp);
+ *
+ * <desc>Close directory stream opened by the `opendir' function. Close of
+ * directory stream invalidates the DIR structure as well as previously read
+ * dirent entry.
+ *
+ * <ret>The function typically returns 0 on success and -1 on failure but
+ * the function may be declared to return void on same systems. At least
+ * Borland C/C++ and some UNIX implementations use void as a return type.
+ * The dirent wrapper tries to define VOID_CLOSEDIR whenever closedir is
+ * known to return nothing. The very same definition is made by the GNU
+ * autoconf if you happen to use it.
+ *
+ * The global `errno' variable will set to EBADF in case of error.
+ * </function>
+ */
+static int
+closedir (DIR *dirp)
+{
+ int retcode = 0;
+
+ /* make sure that dirp points to legal structure */
+ assert (dirp != NULL);
+ if (dirp == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ /* free directory name and search handles */
+ if (dirp->dirname != NULL) free (dirp->dirname);
+
+#if defined(DIRENT_WIN32_INTERFACE)
+ if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+ if (FindClose (dirp->search_handle) == FALSE) {
+ /* Unknown error */
+ retcode = -1;
+ errno = EBADF;
+ }
+ }
+#endif
+
+ /* clear dirp structure to make sure that it cannot be used anymore*/
+ memset (dirp, 0, sizeof (*dirp));
+# if defined(DIRENT_WIN32_INTERFACE)
+ dirp->search_handle = INVALID_HANDLE_VALUE;
+# endif
+
+ free (dirp);
+ return retcode;
+}
+
+
+/*
+ * <function name="rewinddir">
+ * <intro>rewind directory stream to the beginning
+ * <syntax>void rewinddir (DIR *dirp);
+ *
+ * <desc>Rewind directory stream to the beginning so that the next call of
+ * readdir() returns the very first directory entry again. However, note
+ * that next call of readdir() may not return the same directory entry as it
+ * did in first time. The directory stream may have been affected by newly
+ * created files.
+ *
+ * Almost every dirent implementation ensure that rewinddir will update
+ * the directory stream to reflect any changes made to the directory entries
+ * since the previous ``opendir'' or ``rewinddir'' call. Keep an eye on
+ * this if your program depends on the feature. I know at least one dirent
+ * implementation where you are required to close and re-open the stream to
+ * see the changes.
+ *
+ * <ret>Returns nothing. If something went wrong while rewinding, you will
+ * notice it later when you try to retrieve the first directory entry.
+ */
+static void
+rewinddir (DIR *dirp)
+{
+ /* make sure that dirp is legal */
+ assert (dirp != NULL);
+ if (dirp == NULL) {
+ errno = EBADF;
+ return;
+ }
+ assert (dirp->dirname != NULL);
+
+ /* close previous stream */
+#if defined(DIRENT_WIN32_INTERFACE)
+ if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+ if (FindClose (dirp->search_handle) == FALSE) {
+ /* Unknown error */
+ errno = EBADF;
+ }
+ }
+#endif
+
+ /* re-open previous stream */
+ if (_initdir (dirp) == 0) {
+ /* initialization failed but we cannot deal with error. User will notice
+ * error later when she tries to retrieve first directory enty. */
+ /*EMPTY*/;
+ }
+}
+
+
+/*
+ * Open native directory stream object and retrieve first file.
+ * Be sure to close previous stream before opening new one.
+ */
+static int
+_initdir (DIR *dirp)
+{
+ assert (dirp != NULL);
+ assert (dirp->dirname != NULL);
+ dirp->dirent_filled = 0;
+
+# if defined(DIRENT_WIN32_INTERFACE)
+ /* Open stream and retrieve first file */
+ dirp->search_handle = FindFirstFile (dirp->dirname, &dirp->current.data);
+ if (dirp->search_handle == INVALID_HANDLE_VALUE) {
+ /* something went wrong but we don't know what. GetLastError() could
+ * give us more information about the error, but then we should map
+ * the error code into errno. */
+ errno = ENOENT;
+ return 0;
+ }
+
+# elif defined(DIRENT_MSDOS_INTERFACE)
+ if (_dos_findfirst (dirp->dirname,
+ _A_SUBDIR | _A_RDONLY | _A_ARCH | _A_SYSTEM | _A_HIDDEN,
+ &dirp->current.data) != 0)
+ {
+ /* _dos_findfirst and findfirst will set errno to ENOENT when no
+ * more entries could be retrieved. */
+ return 0;
+ }
+# endif
+
+ /* initialize DIR and it's first entry */
+ _setdirname (dirp);
+ dirp->dirent_filled = 1;
+ return 1;
+}
+
+
+/*
+ * Return implementation dependent name of the current directory entry.
+ */
+static const char *
+_getdirname (const struct dirent *dp)
+{
+#if defined(DIRENT_WIN32_INTERFACE)
+ return dp->data.cFileName;
+
+#elif defined(DIRENT_USE_FFBLK)
+ return dp->data.ff_name;
+
+#else
+ return dp->data.name;
+#endif
+}
+
+
+/*
+ * Copy name of implementation dependent directory entry to the d_name field.
+ */
+static void
+_setdirname (struct DIR *dirp) {
+ /* make sure that d_name is long enough */
+ assert (strlen (_getdirname (&dirp->current)) <= NAME_MAX);
+
+ strncpy (dirp->current.d_name,
+ _getdirname (&dirp->current),
+ NAME_MAX);
+ dirp->current.d_name[NAME_MAX] = '\0'; /*char d_name[NAME_MAX+1]*/
+}
+
+# ifdef __cplusplus
+}
+# endif
+# define NAMLEN(dp) ((int)(strlen((dp)->d_name)))
+
+#else
+# error "missing dirent interface"
+#endif
+
+
+#endif /*DIRENT_H*/
+
diff --git a/src/uscxml/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 <glog/logging.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host){
+ host.add( new V8DataModelProvider() );
+ return true;
+}
+#endif
+
+V8DataModel::V8DataModel() {
+// _contexts.push_back(v8::Context::New());
+}
+
+DataModel* V8DataModel::create(Interpreter* interpreter) {
+ V8DataModel* dm = new V8DataModel();
+ dm->_interpreter = interpreter;
+ v8::Locker locker;
+ v8::HandleScope scope;
+
+ // see http://stackoverflow.com/questions/3171418/v8-functiontemplate-class-instance
+// dm->_globalTemplate = v8::Persistent<v8::ObjectTemplate>(v8::ObjectTemplate::New());
+// dm->_globalTemplate->Set(v8::String::New("In"), v8::FunctionTemplate::New(jsIn, v8::External::New(reinterpret_cast<void*>(this))));
+
+ v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
+ global->Set(v8::String::New("In"), v8::FunctionTemplate::New(jsIn, v8::External::New(reinterpret_cast<void*>(dm))));
+ global->Set(v8::String::New("print"), v8::FunctionTemplate::New(jsPrint, v8::External::New(reinterpret_cast<void*>(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<v8::Object> global = _contexts.front()->Global();
+
+ global->Set(v8::String::New("_sessionid"), v8::String::New(sessionId.c_str()));
+}
+
+void V8DataModel::setName(const std::string& name) {
+ _name = name;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.front());
+ v8::Handle<v8::Object> global = _contexts.front()->Global();
+
+ global->Set(v8::String::New("_name"), v8::String::New(name.c_str()));
+}
+
+V8DataModel::~V8DataModel() {
+ while(_contexts.size() > 0) {
+ _contexts.back().Dispose();
+ _contexts.pop_back();
+ }
+}
+
+void V8DataModel::pushContext() {
+ _contexts.push_back(_contexts.back().New(_contexts.back()));
+}
+
+void V8DataModel::popContext() {
+ if (_contexts.size() > 1) {
+ _contexts.back().Dispose();
+ _contexts.pop_back();
+ }
+}
+
+void V8DataModel::initialize() {
+}
+
+void V8DataModel::setEvent(const Event& event) {
+ _event = event;
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.front());
+ v8::Handle<v8::Object> global = _contexts.front()->Global();
+
+ // this is unfortunate - can't we store the template in the object?
+ if (_eventTemplate.IsEmpty()) {
+ v8::Handle<v8::ObjectTemplate> localEventTemplate = v8::ObjectTemplate::New();
+ localEventTemplate->SetInternalFieldCount(1); // we only have a single C++ object
+ localEventTemplate->SetAccessor(v8::String::New("name"), V8DataModel::jsGetEventName);
+ localEventTemplate->SetAccessor(v8::String::New("type"), V8DataModel::jsGetEventType);
+ localEventTemplate->SetAccessor(v8::String::New("sendid"), V8DataModel::jsGetEventSendId);
+ localEventTemplate->SetAccessor(v8::String::New("origin"), V8DataModel::jsGetEventOrigin);
+ localEventTemplate->SetAccessor(v8::String::New("origintype"), V8DataModel::jsGetEventOriginType);
+ localEventTemplate->SetAccessor(v8::String::New("invokeid"), V8DataModel::jsGetEventInvokeId);
+ _eventTemplate = v8::Persistent<v8::ObjectTemplate>::New(localEventTemplate);
+ }
+
+ assert(_eventTemplate->InternalFieldCount() == 1);
+ v8::Handle<v8::Object> eventJS = _eventTemplate->NewInstance();
+ eventJS->SetInternalField(0, v8::External::New(&_event));
+
+ eventJS->Set(v8::String::New("data"), getDataAsValue(event)); // set data part of _event
+ global->Set(v8::String::New("_event"), eventJS);
+}
+
+Data V8DataModel::getStringAsData(const std::string& content) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.front());
+ v8::Handle<v8::Value> result = evalAsValue(content);
+ Data data = getValueAsData(result);
+ return data;
+}
+
+Data V8DataModel::getValueAsData(const v8::Handle<v8::Value>& value) {
+ Data data;
+ if (false) {
+ } else if (value->IsArray()) {
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::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<v8::String>::Cast(v8::Handle<v8::Number>::Cast(value)));
+ data.atom = *prop;
+ } else if (value->IsNumberObject()) {
+ LOG(ERROR) << "IsNumberObject is unimplemented" << std::endl;
+ } else if (value->IsObject()) {
+ v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
+ v8::Local<v8::Array> properties = object->GetPropertyNames();
+ for (int i = 0; i < properties->Length(); i++) {
+ assert(properties->Get(i)->IsString());
+ v8::String::AsciiValue key(v8::Handle<v8::String>::Cast(properties->Get(i)));
+ v8::Local<v8::Value> 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<v8::String>::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<v8::Value> V8DataModel::getDataAsValue(const Data& data) {
+ if (data.compound.size() > 0) {
+ v8::Handle<v8::Object> value = v8::Object::New();
+ std::map<std::string, Data>::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<v8::Object> value = v8::Array::New();
+ std::list<Data>::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<v8::Value> 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<v8::Value> V8DataModel::jsIn(const v8::Arguments& args) {
+ V8DataModel* INSTANCE = static_cast<V8DataModel*>(v8::External::Unwrap(args.Data()));
+ for (unsigned int i = 0; i < args.Length(); i++) {
+ if (args[i]->IsString()) {
+ std::string stateName(*v8::String::AsciiValue(args[i]->ToString()));
+ if (Interpreter::isMember(INSTANCE->_interpreter->getState(stateName), INSTANCE->_interpreter->getConfiguration())) {
+ continue;
+ }
+ }
+ return v8::Boolean::New(false);
+ }
+ return v8::Boolean::New(true);
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventName(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->name.c_str());
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventType(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ switch (event->type) {
+ case Event::PLATFORM:
+ return v8::String::New("platform");
+ break;
+ case Event::INTERNAL:
+ return v8::String::New("internal");
+ break;
+ case Event::EXTERNAL:
+ return v8::String::New("external");
+ break;
+ default:
+ return v8::String::New("");
+ break;
+ }
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventSendId(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->sendid.c_str());
+
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventOrigin(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->origin.c_str());
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventOriginType(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->origintype.c_str());
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventInvokeId(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->invokeid.c_str());
+}
+
+bool V8DataModel::validate(const std::string& location, const std::string& schema) {
+ return true;
+}
+
+uint32_t V8DataModel::getLength(const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ v8::Handle<v8::Array> result = evalAsValue(expr).As<v8::Array>();
+ return result->Length();
+}
+
+void V8DataModel::eval(const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ evalAsValue(expr);
+}
+
+bool V8DataModel::evalAsBool(const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ v8::Handle<v8::Value> result = evalAsValue(expr);
+ return(result->ToBoolean()->BooleanValue());
+}
+
+std::string V8DataModel::evalAsString(const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ v8::Handle<v8::Value> result = evalAsValue(expr);
+ v8::String::AsciiValue data(result->ToString());
+ return std::string(*data);
+}
+
+void V8DataModel::assign(const std::string& location, const 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<v8::Object> variable = evalAsValue(location).As<v8::Object>();
+// assert(!variable.IsEmpty());
+// if (data.compound.size() > 0) {
+// std::map<std::string, Data>::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<Data>::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<v8::Value> V8DataModel::evalAsValue(const std::string& expr) {
+ v8::TryCatch tryCatch;
+ v8::Handle<v8::String> source = v8::String::New(expr.c_str());
+ v8::Handle<v8::Script> script = v8::Script::Compile(source);
+
+ v8::Handle<v8::Value> result;
+ if (!script.IsEmpty())
+ result = script->Run();
+
+ if (script.IsEmpty() || result.IsEmpty()) {
+ // throw an exception
+ assert(tryCatch.HasCaught());
+ Event exceptionEvent;
+ exceptionEvent.name = "error.execution";
+
+ std::string exceptionString(*v8::String::AsciiValue(tryCatch.Exception()));
+ exceptionEvent.compound["exception"] = Data(exceptionString, Data::VERBATIM);;
+
+ v8::Handle<v8::Message> message = tryCatch.Message();
+ if (!message.IsEmpty()) {
+ std::string filename(*v8::String::AsciiValue(message->GetScriptResourceName()));
+ exceptionEvent.compound["filename"] = Data(filename, Data::VERBATIM);
+
+ std::string sourceLine(*v8::String::AsciiValue(message->GetSourceLine()));
+ exceptionEvent.compound["sourceline"] = Data(sourceLine, Data::VERBATIM);
+
+ std::stringstream ssLineNumber;
+ int lineNumber = message->GetLineNumber();
+ ssLineNumber << lineNumber;
+ exceptionEvent.compound["linenumber"] = Data(ssLineNumber.str());
+
+ int startColumn = message->GetStartColumn();
+ int endColumn = message->GetEndColumn();
+ std::stringstream ssUnderline;
+ for (int i = 0; i < startColumn; i++)
+ ssUnderline << " ";
+ for (int i = startColumn; i < endColumn; i++)
+ ssUnderline << "^";
+ exceptionEvent.compound["sourcemark"] = Data(ssUnderline.str(), Data::VERBATIM);
+
+ std::string stackTrace(*v8::String::AsciiValue(tryCatch.StackTrace()));
+ exceptionEvent.compound["stacktrace"] = Data(stackTrace, Data::VERBATIM);
+
+ }
+
+ _interpreter->receiveInternal(exceptionEvent);
+ throw(exceptionEvent);
+ }
+
+ return result;
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h
new file mode 100644
index 0000000..994ed18
--- /dev/null
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h
@@ -0,0 +1,92 @@
+#ifndef V8DATAMODEL_H_KN8TWG0V
+#define V8DATAMODEL_H_KN8TWG0V
+
+#include "uscxml/Interpreter.h"
+#include <list>
+#include <v8.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
+namespace uscxml {
+ class Event;
+ class Data;
+ class V8SCXMLDOM;
+}
+
+namespace uscxml {
+
+class V8DataModel : public DataModel {
+public:
+ V8DataModel();
+ virtual ~V8DataModel();
+ virtual DataModel* create(Interpreter* interpreter);
+
+ virtual std::set<std::string> getNames() {
+ std::set<std::string> names;
+ names.insert("ecmascript");
+ return names;
+ }
+
+ virtual void initialize();
+ virtual void setSessionId(const std::string& sessionId);
+ virtual void setName(const std::string& name);
+ virtual void setEvent(const Event& event);
+
+ virtual bool validate(const std::string& location, const std::string& schema);
+
+ virtual uint32_t getLength(const std::string& expr);
+ virtual void pushContext();
+ virtual void popContext();
+
+ virtual void eval(const std::string& expr);
+ virtual void assign(const std::string& location, const std::string& expr);
+ virtual void assign(const std::string& location, const Data& data);
+
+ virtual Data getStringAsData(const std::string& content);
+ virtual Data getValueAsData(const v8::Handle<v8::Value>& value);
+
+ virtual std::string evalAsString(const std::string& expr);
+ virtual bool evalAsBool(const std::string& expr);
+
+ static v8::Handle<v8::Value> jsGetEventName(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> jsGetEventType(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> jsGetEventSendId(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> jsGetEventOrigin(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> jsGetEventOriginType(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> jsGetEventInvokeId(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+
+ static v8::Handle<v8::Value> jsIn(const v8::Arguments& args);
+ static v8::Handle<v8::Value> jsPrint(const v8::Arguments& args);
+
+
+protected:
+ std::list<v8::Persistent<v8::Context> > _contexts;
+ Interpreter* _interpreter;
+
+ std::string _sessionId;
+ std::string _name;
+
+ Event _event;
+ v8::Persistent<v8::ObjectTemplate> _globalTemplate;
+ v8::Persistent<v8::ObjectTemplate> _eventTemplate;
+
+ v8::Handle<v8::Value> evalAsValue(const std::string& expr);
+ virtual v8::Handle<v8::Value> getDataAsValue(const Data& data);
+
+};
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_INHERIT_PROVIDER(V8DataModel, DataModel);
+#endif
+
+}
+
+#endif /* end of include guard: V8DATAMODEL_H_KN8TWG0V */
diff --git a/src/uscxml/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 <winsock2.h>
+#include <windows.h>
+#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<v8::ObjectTemplate> V8SCXMLDOM::getDocument(Arabica::DOM::Document<std::string>& document) {
+ v8::Handle<v8::ObjectTemplate> documentTmpl = v8::ObjectTemplate::New();
+ documentTmpl->Set(v8::String::New("createElement"), v8::FunctionTemplate::New(jsDocumentCreateElement, v8::External::New(reinterpret_cast<void*>(&document))));
+ documentTmpl->Set(v8::String::New("evaluate"), v8::FunctionTemplate::New(jsDocumentEvaluate, v8::External::New(reinterpret_cast<void*>(&document))));
+ return documentTmpl;
+ }
+
+ v8::Handle<v8::Value> V8SCXMLDOM::jsDocumentCreateElement(const v8::Arguments& args) {
+ assert(!args.Data().IsEmpty());
+ assert(args.Data()->IsExternal());
+
+ ASSERT_ARGS1(args, IsString)
+
+ Document<std::string>* document = static_cast<Document<std::string>*>(v8::External::Unwrap(args.Data()));
+ v8::Persistent<v8::Object> elementJS = v8::Persistent<v8::Object>::New(getElementTmpl()->NewInstance());
+
+ v8::String::AsciiValue tagName(args[0]);
+ Element<std::string>* element = new Element<std::string>(document->createElement(*tagName));
+
+ elementJS->SetInternalField(0, v8::External::New(element));
+ elementJS.MakeWeak(NULL, jsElementDestructor);
+ return elementJS;
+ }
+
+ v8::Handle<v8::Value> V8SCXMLDOM::jsDocumentEvaluate(const v8::Arguments& args) {
+ assert(!args.Data().IsEmpty());
+ assert(args.Data()->IsExternal());
+
+ assert(args.Length() > 0);
+ assert(args[0]->IsString());
+
+
+ Document<std::string>* document = static_cast<Document<std::string>*>(v8::External::Unwrap(args.Data()));
+ Node<std::string> context;
+ if (args.Length() > 1) {
+ assert(args[1]->ToObject()->InternalFieldCount() == 1);
+ context = *static_cast<Node<std::string>*>(v8::Local<v8::External>::Cast(args[1]->ToObject()->GetInternalField(0))->Value());
+ } else {
+ context = *document;
+ }
+ v8::String::AsciiValue xpathExpr(args[0]);
+ XPath<std::string> xpath;
+ XPathValue<std::string>* xpathValue = new XPathValue<std::string>(xpath.evaluate(*xpathExpr, context));
+
+ v8::Persistent<v8::Object> xpathValueJS = v8::Persistent<v8::Object>::New(getXPathValueTmpl()->NewInstance());
+ xpathValueJS->SetInternalField(0, v8::External::New(xpathValue));
+ xpathValueJS.MakeWeak(NULL, jsXPathValueDestructor);
+ return xpathValueJS;
+ }
+
+ v8::Handle<v8::Value> V8SCXMLDOM::jsElementTagName(v8::Local<v8::String> property, const v8::AccessorInfo &info) {
+ Element<std::string>* element = static_cast<Element<std::string>*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(element->getTagName().c_str());
+ }
+
+ v8::Handle<v8::Value> V8SCXMLDOM::jsElementGetAttribute(const v8::Arguments& args) {
+ assert(!args.Data().IsEmpty());
+ assert(args.Data()->IsExternal());
+
+ ASSERT_ARGS1(args, IsString);
+
+ Element<std::string>* element = static_cast<Element<std::string>*>(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<v8::Value> V8SCXMLDOM::jsElementSetAttribute(const v8::Arguments& args) {
+ v8::Local<v8::Object> 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<std::string>* element = static_cast<Element<std::string>*>(v8::External::Unwrap(self->GetInternalField(0)));
+ element->setAttribute(*attribute, *value);
+ return v8::Undefined();
+ }
+
+ v8::Handle<v8::Value> V8SCXMLDOM::jsXPathValueAsNodeSet(const v8::Arguments& args) {
+ v8::Local<v8::Object> self = args.Holder();
+ assert(self->InternalFieldCount() == 1);
+ XPathValue<std::string>* xPathValue = static_cast<XPathValue<std::string>*>(v8::External::Unwrap(self->GetInternalField(0)));
+
+ v8::Persistent<v8::Object> nodeSetJS = v8::Persistent<v8::Object>::New(getNodeSetTmpl()->NewInstance());
+ nodeSetJS->SetInternalField(0, v8::External::New(new NodeSet<std::string>(xPathValue->asNodeSet())));
+ nodeSetJS.MakeWeak(NULL, jsNodeSetDestructor);
+ return nodeSetJS;
+
+ }
+
+ void V8SCXMLDOM::jsNodeSetDestructor(v8::Persistent<v8::Value> object, void* data) {
+ NodeSet<std::string>* nodeSet = static_cast<NodeSet<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value());
+ delete nodeSet;
+ }
+
+ void V8SCXMLDOM::jsNodeDestructor(v8::Persistent<v8::Value> object, void* data) {
+ Node<std::string>* node = static_cast<Node<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value());
+ delete node;
+ }
+
+ void V8SCXMLDOM::jsXPathValueDestructor(v8::Persistent<v8::Value> object, void* data) {
+ XPathValue<std::string>* xPathValue = static_cast<XPathValue<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value());
+ delete xPathValue;
+ }
+
+ void V8SCXMLDOM::jsElementDestructor(v8::Persistent<v8::Value> object, void* data) {
+ Element<std::string>* element = static_cast<Element<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value());
+ delete element;
+ }
+
+ v8::Handle<v8::Value> V8SCXMLDOM::jsNodeSetGetIndex(uint32_t index, const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> self = info.Holder();
+ assert(self->InternalFieldCount() == 1);
+ NodeSet<std::string>* nodeSet = static_cast<NodeSet<std::string>*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+
+ if (nodeSet->size() >= index) {
+ Node<std::string>* node = new Node<std::string>((*nodeSet)[index]);
+ v8::Persistent<v8::Object> nodeJS = v8::Persistent<v8::Object>::New(getNodeTmpl()->NewInstance());
+ nodeJS->SetInternalField(0, v8::External::New(node));
+ nodeJS.MakeWeak(NULL, jsNodeDestructor);
+ return nodeJS;
+ }
+ return v8::Undefined();
+ }
+
+ v8::Handle<v8::Value> V8SCXMLDOM::jsNodeSetLength(const v8::Arguments& args) {
+ v8::Local<v8::Object> self = args.Holder();
+ assert(self->InternalFieldCount() == 1);
+ NodeSet<std::string>* nodeSet = static_cast<NodeSet<std::string>*>(v8::External::Unwrap(self->GetInternalField(0)));
+ return v8::Integer::New(nodeSet->size());
+ }
+
+ v8::Handle<v8::Value> V8SCXMLDOM::jsNodeAppendChild(const v8::Arguments& args) {
+ v8::Local<v8::Object> self = args.Holder();
+ assert(self->InternalFieldCount() == 1);
+ Node<std::string>* node = static_cast<Node<std::string>*>(v8::External::Unwrap(self->GetInternalField(0)));
+
+ assert(args.Length() == 1);
+ assert(args[0]->IsObject());
+
+ Node<std::string>* childToAppend = static_cast<Node<std::string>*>(v8::External::Unwrap(args[0]->ToObject()->GetInternalField(0)));
+ node->appendChild(*childToAppend);
+
+ return v8::Undefined();
+ }
+
+ v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::xPathValueTmpl;
+ v8::Handle<v8::ObjectTemplate> 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<v8::ObjectTemplate> V8SCXMLDOM::nodeSetTmpl;
+ v8::Handle<v8::ObjectTemplate> 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<v8::ObjectTemplate> V8SCXMLDOM::nodeTmpl;
+ v8::Handle<v8::ObjectTemplate> 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<v8::ObjectTemplate> V8SCXMLDOM::elementTmpl;
+ v8::Handle<v8::ObjectTemplate> 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 <DOM/Document.hpp>
+#include <v8.h>
+
+#include <list>
+
+namespace uscxml {
+
+class V8SCXMLDOM {
+public:
+ V8SCXMLDOM();
+ virtual ~V8SCXMLDOM() {};
+
+ static v8::Handle<v8::ObjectTemplate> getDocument(Arabica::DOM::Document<std::string>& document);
+ static v8::Handle<v8::Value> jsDocumentCreateElement(const v8::Arguments& args);
+ static v8::Handle<v8::Value> jsDocumentEvaluate(const v8::Arguments& args);
+
+ static v8::Handle<v8::Value> jsElementTagName(v8::Local<v8::String> property, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> jsElementGetAttribute(const v8::Arguments& args);
+ static v8::Handle<v8::Value> jsElementSetAttribute(const v8::Arguments& args);
+ static void jsElementDestructor(v8::Persistent<v8::Value> object, void* data);
+
+ static v8::Handle<v8::Value> jsXPathValueAsNodeSet(const v8::Arguments& args);
+ static void jsXPathValueDestructor(v8::Persistent<v8::Value> object, void* data);
+
+ static v8::Handle<v8::Value> jsNodeSetGetIndex(uint32_t index, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> jsNodeSetLength(const v8::Arguments& args);
+ static void jsNodeSetDestructor(v8::Persistent<v8::Value> object, void* data);
+
+ static v8::Handle<v8::Value> jsNodeAppendChild(const v8::Arguments& args);
+ static void jsNodeDestructor(v8::Persistent<v8::Value> object, void* data);
+
+ static v8::Handle<v8::ObjectTemplate> getXPathValueTmpl();
+ static v8::Handle<v8::ObjectTemplate> getNodeSetTmpl();
+ static v8::Handle<v8::ObjectTemplate> getNodeTmpl();
+ static v8::Handle<v8::ObjectTemplate> getElementTmpl();
+
+ static v8::Handle<v8::ObjectTemplate> xPathValueTmpl;
+ static v8::Handle<v8::ObjectTemplate> nodeSetTmpl;
+ static v8::Handle<v8::ObjectTemplate> nodeTmpl;
+ static v8::Handle<v8::ObjectTemplate> elementTmpl;
+
+};
+
+class V8Node {
+};
+
+class V8DOMDocument {
+ V8DOMDocument();
+ virtual ~V8DOMDocument();
+
+ v8::Handle<v8::Array> 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 <glog/logging.h>
+
+#ifdef _WIN32
+#define _USE_MATH_DEFINES
+#endif
+#include <math.h>
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host){
+ host.add( new SpatialAudioProvider() );
+ return true;
+}
+#endif
+
+SpatialAudio::SpatialAudio() {
+ _audioDevOpen = false;
+ _audioDev = NULL;
+ _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<std::string, std::list<std::string> >& params, float* position) {
+ // vector explicitly given
+ try {
+ if (params.find("x") != params.end())
+ position[0] = boost::lexical_cast<float>(params["x"].front());
+ if (params.find("y") != params.end())
+ position[1] = boost::lexical_cast<float>(params["y"].front());
+ if (params.find("z") != params.end())
+ position[2] = boost::lexical_cast<float>(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<float>(params["right"].front());
+ // height is an alias for y
+ if (params.find("height") != params.end())
+ position[1] = boost::lexical_cast<float>(params["height"].front());
+ // front is an alias for z
+ if (params.find("front") != params.end())
+ position[2] = boost::lexical_cast<float>(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<float>(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<float>(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 <map>
+
+#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<std::string> getNames() {
+ std::set<std::string> names;
+ names.insert("spatial-audio");
+ names.insert("audio");
+ names.insert("http://www.smartvortex.eu/mmi/spatial-audio");
+ names.insert("http://www.smartvortex.eu/mmi/spatial-audio/");
+ return names;
+ }
+
+ virtual Data getDataModelVariables();
+ virtual void send(SendRequest& req);
+ virtual void cancel(const std::string sendId);
+ virtual void invoke(InvokeRequest& req);
+ virtual void sendToParent(SendRequest& req);
+
+ void getPosFromParams(std::map<std::string, std::list<std::string> >& 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 <Pluma/Connector.hpp>
+#endif
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host){
+ host.add( new USCXMLInvokerProvider() );
+ return true;
+}
+#endif
+
+USCXMLInvoker::USCXMLInvoker() {
+}
+
+
+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<std::string> getNames() {
+ std::set<std::string> names;
+ names.insert("uscxml");
+ names.insert("http://www.w3.org/TR/scxml");
+ names.insert("http://www.w3.org/TR/scxml/");
+ return names;
+ }
+
+ virtual Data getDataModelVariables();
+ virtual void send(SendRequest& req);
+ virtual void cancel(const std::string sendId);
+ 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 <glog/logging.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host){
+ host.add( new UmundoInvokerProvider() );
+ return true;
+}
+#endif
+
+UmundoInvoker::UmundoInvoker() {
+}
+
+UmundoInvoker::~UmundoInvoker() {
+ _node.removeSubscriber(_sub);
+ _node.removePublisher(_pub);
+};
+
+Invoker* UmundoInvoker::create(Interpreter* interpreter) {
+ UmundoInvoker* invoker = new UmundoInvoker();
+ invoker->_interpreter = interpreter;
+ return invoker;
+}
+
+Data UmundoInvoker::getDataModelVariables() {
+ Data data;
+ return data;
+}
+
+void UmundoInvoker::send(SendRequest& req) {
+ umundo::Message* msg = new umundo::Message();
+
+ if (req.name.length() > 0) {
+ msg->putMeta("event", req.name);
+ } else {
+ msg->putMeta("event", "umundo");
+ }
+
+ if (req.params.find("type") != req.params.end()) {
+ // assume JSON in content to transform to protobuf object
+ if (req.content.length() > 0 && _interpreter->getDataModel() != NULL) {
+ std::string type = req.params["type"].front();
+ const google::protobuf::Message* protoMsg = umundo::PBSerializer::getProto(type);
+ if (protoMsg == NULL) {
+ LOG(ERROR) << "No type " << type << " is known, pass a directory with proto .desc files via types param when invoking";
+ return;
+ }
+ try {
+ Data data = _interpreter->getDataModel()->getStringAsData(req.content);
+ google::protobuf::Message* pbMsg = protoMsg->New();
+ if (!dataToProtobuf(pbMsg, data)) {
+ LOG(ERROR) << "Cannot create message from JSON - not sending";
+ } else {
+ // add all s11n properties
+ if (!_isService) {
+ _pub.prepareMsg(msg, type, pbMsg);
+ _pub.send(msg);
+ } else {
+ std::map<umundo::ServiceDescription, umundo::ServiceStub*>::iterator svcIter = _svcs.begin();
+ while(svcIter != _svcs.end()) {
+ umundo::ServiceStub* stub = svcIter->second;
+ Event event;
+ void* rv = NULL;
+ stub->callStubMethod(req.name, pbMsg, type, rv, "");
+ protobufToData(event, *(const google::protobuf::Message*)rv);
+
+ event.name = _invokeId + ".reply." + req.name;
+ event.invokeid = _invokeId;
+ event.origin = msg->getMeta("um.channel");
+ event.origintype = "umundo";
+ event.type = Event::EXTERNAL;
+
+ _interpreter->receive(event);
+ svcIter++;
+ }
+ }
+ }
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error when invoking umundo:" << std::endl << e << std::endl;
+ return;
+ }
+ } else {
+ LOG(ERROR) << "Required JSON object in content" << std::endl;
+ return;
+ }
+ }
+}
+
+void UmundoInvoker::cancel(const std::string sendId) {
+ assert(false);
+}
+
+void UmundoInvoker::sendToParent(SendRequest& req) {
+ assert(false);
+}
+
+void UmundoInvoker::invoke(InvokeRequest& req) {
+ _invokeId = req.invokeid;
+
+ std::string channelName;
+ std::string serviceName;
+
+ if (req.params.find("channel") != req.params.end()) {
+ channelName = req.params["channel"].front();
+ _isService = false;
+ } else if (req.params.find("service") != req.params.end()) {
+ serviceName = req.params["service"].front();
+ _isService = true;
+ } else {
+ LOG(ERROR) << "Invoking umundo needs a service or a channel param";
+ return;
+ }
+
+ _node = getNode(_interpreter);
+
+ // add types from .proto or .desc files
+ if (req.params.find("types") != req.params.end()) {
+ std::list<std::string>::iterator typeIter = req.params["types"].begin();
+ while(typeIter != req.params["types"].end()) {
+ Arabica::io::URI srcURI(*typeIter);
+ // if (!_interpreter->makeAbsolute(srcURI)) {
+ // LOG(ERROR) << "Relative URI for types in umundo invoker " << *typeIter << " with no base URI set for interpreter";
+ // return;
+ // }
+ umundo::PBSerializer::addProto(srcURI.path());
+ typeIter++;
+ }
+ }
+
+ if (!_isService) {
+ // use umundo to publish objects on a channel
+ _pub = umundo::TypedPublisher(channelName);
+ _sub = umundo::TypedSubscriber(channelName, this);
+
+ _node.addPublisher(_pub);
+ _node.addSubscriber(_sub);
+
+ } else if (serviceName.length() > 0) {
+ // use umundo to access services
+ _svcFilter = umundo::ServiceFilter(serviceName);
+ _node.connect(&_svcMgr);
+ _svcMgr.startQuery(_svcFilter, this);
+ }
+}
+
+void UmundoInvoker::receive(void* object, umundo::Message* msg) {
+ uscxml::Event event;
+ if (msg->getMeta().find("event") != msg->getMeta().end()) {
+ event.name = msg->getMeta("event");
+ } else {
+ event.name = "umundo.rcvd";
+ }
+
+ event.invokeid = _invokeId;
+ event.origin = msg->getMeta("um.channel");
+ event.origintype = "umundo";
+ event.type = Event::EXTERNAL;
+
+// if (msg->getMeta().find("um.s11n.type") != msg->getMeta().end())
+// event.compound["class"] = msg->getMeta("um.s11n.type");
+
+ if (object != NULL)
+ protobufToData(event, *(const google::protobuf::Message*)object);
+
+ // get meta fields into event
+ std::map<std::string, std::string>::const_iterator metaIter = msg->getMeta().begin();
+ while(metaIter != msg->getMeta().end()) {
+ if (metaIter->first.substr(0,3).compare("um.") != 0)
+ event.compound[metaIter->first] = Data(metaIter->second, Data::VERBATIM);
+ metaIter++;
+ }
+
+ _interpreter->receive(event);
+}
+
+void UmundoInvoker::added(umundo::ServiceDescription desc) {
+ LOG(ERROR) << "Service found!";
+
+ umundo::ServiceStub* stub = new umundo::ServiceStub(desc);
+ _svcs[desc] = stub;
+
+ Event addedEvent;
+ addedEvent.invokeid = _invokeId;
+ addedEvent.origin = desc.getName();
+ addedEvent.origintype = "umundo";
+ addedEvent.type = Event::EXTERNAL;
+ addedEvent.name = _invokeId + ".added";
+
+ std::map<std::string, std::string>::const_iterator propIter = desc.getProperties().begin();
+ while(propIter != desc.getProperties().end()) {
+ addedEvent.compound[propIter->first] = Data(propIter->second, Data::VERBATIM);
+ propIter++;
+ }
+
+ _interpreter->receive(addedEvent);
+}
+
+void UmundoInvoker::removed(umundo::ServiceDescription desc) {
+ LOG(ERROR) << "Service lost!";
+
+ if (_svcs.find(desc) == _svcs.end()) {
+ return;
+ }
+
+ delete _svcs[desc];
+ _svcs.erase(desc);
+
+ Event addedEvent;
+ addedEvent.invokeid = _invokeId;
+ addedEvent.origin = desc.getName();
+ addedEvent.origintype = "umundo";
+ addedEvent.type = Event::EXTERNAL;
+ addedEvent.name = _invokeId + ".removed";
+
+ std::map<std::string, std::string>::const_iterator propIter = desc.getProperties().begin();
+ while(propIter != desc.getProperties().end()) {
+ addedEvent.compound[propIter->first] = Data(propIter->second, Data::VERBATIM);
+ propIter++;
+ }
+
+ _interpreter->receive(addedEvent);
+}
+
+void UmundoInvoker::changed(umundo::ServiceDescription desc) {
+}
+
+std::map<std::string, umundo::Node> UmundoInvoker::_nodes;
+umundo::Node UmundoInvoker::getNode(Interpreter* interpreter) {
+ if ((_nodes.find(interpreter->getName()) == _nodes.end())) {
+ _nodes[interpreter->getName()] = umundo::Node();
+ }
+ return _nodes[interpreter->getName()];
+}
+
+bool UmundoInvoker::protobufToData(Data& data, const google::protobuf::Message& msg) {
+ const google::protobuf::Descriptor* desc = msg.GetDescriptor();
+ const google::protobuf::Reflection* reflect = msg.GetReflection();
+
+ data.compound["type"] = Data(desc->name(), Data::VERBATIM);
+
+ for (int i = 0; i < desc->field_count(); i++) {
+ const google::protobuf::FieldDescriptor* fieldDesc = desc->field(i);
+ std::string key = fieldDesc->name();
+
+ if (!fieldDesc->is_repeated() && !reflect->HasField(msg, fieldDesc))
+ continue;
+
+ switch(fieldDesc->type()) {
+ case google::protobuf::FieldDescriptor::TYPE_BOOL:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(reflect->GetRepeatedBool(msg, fieldDesc, j) ? "true" : "false"));
+ }
+ } else {
+ data.compound[key].atom = (reflect->GetBool(msg, fieldDesc) ? "true" : "false");
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_BYTES:
+ case google::protobuf::FieldDescriptor::TYPE_STRING:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedString(msg, fieldDesc, j)), Data::VERBATIM));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetString(msg, fieldDesc));
+ data.compound[key].type = Data::VERBATIM;
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_DOUBLE:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedDouble(msg, fieldDesc, j))));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetDouble(msg, fieldDesc));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_ENUM:
+ LOG(ERROR) << "TYPE_ENUM is unimplemented" << std::endl;
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_FIXED32:
+ case google::protobuf::FieldDescriptor::TYPE_UINT32:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt32(msg, fieldDesc, j))));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetUInt32(msg, fieldDesc));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_FIXED64:
+ case google::protobuf::FieldDescriptor::TYPE_UINT64:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt64(msg, fieldDesc, j))));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetUInt64(msg, fieldDesc));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_FLOAT:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedFloat(msg, fieldDesc, j))));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetFloat(msg, fieldDesc));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_GROUP:
+ LOG(ERROR) << "TYPE_GROUP is unimplemented" << std::endl;
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_INT32:
+ case google::protobuf::FieldDescriptor::TYPE_SINT32:
+ case google::protobuf::FieldDescriptor::TYPE_SFIXED32:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt32(msg, fieldDesc, j))));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetInt32(msg, fieldDesc));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_INT64:
+ case google::protobuf::FieldDescriptor::TYPE_SINT64:
+ case google::protobuf::FieldDescriptor::TYPE_SFIXED64:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt64(msg, fieldDesc, j))));
+ }
+ } else {
+ data.compound[key].atom = toStr(reflect->GetInt64(msg, fieldDesc));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_MESSAGE:
+ if (fieldDesc->is_repeated()) {
+ for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
+ data.compound[key].array.push_back(Data());
+ protobufToData(data.compound[key].array.back(), reflect->GetRepeatedMessage(msg, fieldDesc, j));
+ }
+ } else {
+ protobufToData(data.compound[key], reflect->GetMessage(msg, fieldDesc));
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+bool UmundoInvoker::dataToProtobuf(google::protobuf::Message* msg, Data& data) {
+ const google::protobuf::Descriptor* desc = msg->GetDescriptor();
+ const google::protobuf::Reflection* reflect = msg->GetReflection();
+
+ for (int i = 0; i < desc->field_count(); i++) {
+ const google::protobuf::FieldDescriptor* fieldDesc = desc->field(i);
+ std::string key = fieldDesc->name();
+
+ if (data.compound.find(key) == data.compound.end()) {
+ if (fieldDesc->is_required()) {
+ LOG(ERROR) << "required field " << key << " not given in JSON";
+ return false;
+ }
+ continue;
+ }
+
+ std::list<Data>::iterator arrayIter = data.compound[key].array.begin();
+
+ switch(fieldDesc->type()) {
+ case google::protobuf::FieldDescriptor::TYPE_BOOL:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddBool(msg, fieldDesc, arrayIter->atom.compare("false") == 0 ? false : true);
+ arrayIter++;
+ }
+ } else {
+ reflect->SetBool(msg, fieldDesc, (data.compound[key].atom.compare("false") == 0 ? false : true));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_BYTES:
+ case google::protobuf::FieldDescriptor::TYPE_STRING:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddString(msg, fieldDesc, arrayIter->atom);
+ arrayIter++;
+ }
+ } else {
+ reflect->SetString(msg, fieldDesc, data.compound[key].atom);
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_DOUBLE:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddDouble(msg, fieldDesc, strTo<double>(arrayIter->atom));
+ arrayIter++;
+ }
+ } else {
+ reflect->SetDouble(msg, fieldDesc, strTo<double>(data.compound[key].atom));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_ENUM:
+ LOG(ERROR) << "TYPE_ENUM is unimplemented" << std::endl;
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_FIXED32:
+ case google::protobuf::FieldDescriptor::TYPE_UINT32:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddUInt32(msg, fieldDesc, strTo<uint32_t>(arrayIter->atom));
+ arrayIter++;
+ }
+ } else {
+ reflect->SetUInt32(msg, fieldDesc, strTo<uint32_t>(data.compound[key].atom));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_FIXED64:
+ case google::protobuf::FieldDescriptor::TYPE_UINT64:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddUInt64(msg, fieldDesc, strTo<uint64_t>(arrayIter->atom));
+ arrayIter++;
+ }
+ } else {
+ reflect->SetUInt64(msg, fieldDesc, strTo<uint64_t>(data.compound[key].atom));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_FLOAT:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddFloat(msg, fieldDesc, strTo<float>(arrayIter->atom));
+ arrayIter++;
+ }
+ } else {
+ reflect->SetFloat(msg, fieldDesc, strTo<float>(data.compound[key].atom));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_GROUP:
+ LOG(ERROR) << "TYPE_GROUP is unimplemented" << std::endl;
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_INT32:
+ case google::protobuf::FieldDescriptor::TYPE_SINT32:
+ case google::protobuf::FieldDescriptor::TYPE_SFIXED32:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddInt32(msg, fieldDesc, strTo<int32_t>(arrayIter->atom));
+ arrayIter++;
+ }
+ } else {
+ reflect->SetInt32(msg, fieldDesc, strTo<int32_t>(data.compound[key].atom));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_INT64:
+ case google::protobuf::FieldDescriptor::TYPE_SINT64:
+ case google::protobuf::FieldDescriptor::TYPE_SFIXED64:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ reflect->AddInt64(msg, fieldDesc, strTo<int64_t>(arrayIter->atom));
+ arrayIter++;
+ }
+ } else {
+ reflect->SetInt64(msg, fieldDesc, strTo<int64_t>(data.compound[key].atom));
+ }
+ break;
+ case google::protobuf::FieldDescriptor::TYPE_MESSAGE:
+ if (fieldDesc->is_repeated()) {
+ while(arrayIter != data.compound[key].array.end()) {
+ dataToProtobuf(reflect->AddMessage(msg, fieldDesc), *arrayIter);
+ arrayIter++;
+ }
+ } else {
+ dataToProtobuf(reflect->MutableMessage(msg, fieldDesc), data.compound[key]);
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h
new file mode 100644
index 0000000..36a6217
--- /dev/null
+++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h
@@ -0,0 +1,70 @@
+#ifndef UMUNDOINVOKER_H_77YXQGU7
+#define UMUNDOINVOKER_H_77YXQGU7
+
+#include <umundo/core.h>
+#include <umundo/s11n.h>
+#include <umundo/rpc.h>
+#include <umundo/s11n/protobuf/PBSerializer.h>
+#include <google/protobuf/message.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
+namespace uscxml {
+
+class Interpreter;
+
+class UmundoInvoker : public Invoker, public umundo::TypedReceiver, public umundo::ResultSet<umundo::ServiceDescription> {
+public:
+ UmundoInvoker();
+ virtual ~UmundoInvoker();
+ virtual Invoker* create(Interpreter* interpreter);
+
+ virtual std::set<std::string> getNames() {
+ std::set<std::string> names;
+ names.insert("umundo");
+ names.insert("http://umundo.tk.informatik.tu-darmstadt.de/");
+ names.insert("http://umundo.tk.informatik.tu-darmstadt.de");
+ return names;
+ }
+
+ virtual Data getDataModelVariables();
+ virtual void send(SendRequest& req);
+ virtual void cancel(const std::string sendId);
+ virtual void invoke(InvokeRequest& req);
+ virtual void sendToParent(SendRequest& req);
+
+ virtual void receive(void* object, umundo::Message* msg);
+
+ virtual void added(umundo::ServiceDescription);
+ virtual void removed(umundo::ServiceDescription);
+ virtual void changed(umundo::ServiceDescription);
+
+protected:
+ std::string _invokeId;
+ bool _isService;
+
+ bool dataToProtobuf(google::protobuf::Message* msg, Data& data);
+ bool protobufToData(Data& data, const google::protobuf::Message& msg);
+
+ umundo::TypedPublisher _pub;
+ umundo::TypedSubscriber _sub;
+ umundo::Node _node;
+
+ umundo::ServiceFilter _svcFilter;
+ umundo::ServiceManager _svcMgr;
+ std::map<umundo::ServiceDescription, umundo::ServiceStub*> _svcs;
+
+ static std::map<std::string, umundo::Node> _nodes;
+ static umundo::Node getNode(Interpreter* interpreter);
+};
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_INHERIT_PROVIDER(UmundoInvoker, Invoker);
+#endif
+
+}
+
+
+#endif /* end of include guard: UMUNDOINVOKER_H_77YXQGU7 */
diff --git a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp
new file mode 100644
index 0000000..44c89ae
--- /dev/null
+++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp
@@ -0,0 +1,370 @@
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include "uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h"
+#include "uscxml/Message.h"
+#include <iostream>
+#include <event2/dns.h>
+#include <event2/buffer.h>
+#include <event2/keyvalq_struct.h>
+
+#include <string.h>
+
+#include <io/uri.hpp>
+#include <glog/logging.h>
+
+#ifndef _WIN32
+#include <netdb.h>
+#include <arpa/inet.h>
+#endif
+
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host){
+ host.add( new EventIOProcessorProvider() );
+ return true;
+}
+#endif
+
+// see http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor
+
+EventIOProcessor::EventIOProcessor() {
+}
+
+EventIOProcessor::~EventIOProcessor() {
+ _asyncQueue.stop();
+ evdns_base_free(_dns, 1);
+ EventIOServer* httpServer = EventIOServer::getInstance();
+ httpServer->unregisterProcessor(this);
+}
+
+IOProcessor* EventIOProcessor::create(Interpreter* interpreter) {
+ EventIOProcessor* io = new EventIOProcessor();
+ io->_interpreter = interpreter;
+
+ io->_dns = evdns_base_new(io->_asyncQueue._eventLoop, 1);
+ assert(io->_dns);
+ assert(evdns_base_count_nameservers(io->_dns) > 0);
+
+ // register at http server
+ EventIOServer* httpServer = EventIOServer::getInstance();
+ httpServer->registerProcessor(io);
+
+ io->start();
+ return io;
+}
+
+void EventIOProcessor::start() {
+ _asyncQueue.start();
+}
+
+Data EventIOProcessor::getDataModelVariables() {
+ Data data;
+ assert(_url.length() > 0);
+ data.compound["location"] = Data(_url, Data::VERBATIM);
+ return data;
+}
+
+
+void EventIOProcessor::send(SendRequest& req) {
+ // I cant figure out how to copy the reference into the struct :(
+ _sendData[req.sendid].req = req;
+ _sendData[req.sendid].ioProcessor = this;
+
+ int err = 0;
+ char uriBuf[1024];
+
+ struct evhttp_uri* targetURI = evhttp_uri_parse(_sendData[req.sendid].req.target.c_str());
+ if (evhttp_uri_get_port(targetURI) == 0)
+ evhttp_uri_set_port(targetURI, 80);
+ const char* hostName = evhttp_uri_get_host(targetURI);
+
+ // use synchronous dns resolving for multicast dns
+ if(hostName && strlen(hostName) >= strlen(".local")) {
+ if(strcmp(hostName + strlen(hostName) - strlen(".local"), ".local") == 0) {
+ evhttp_uri_set_host(targetURI, EventIOServer::syncResolve(hostName).c_str());
+ }
+ }
+ evhttp_uri_join(targetURI, uriBuf, 1024);
+
+ LOG(INFO) << "URI for send request: " << uriBuf << std::endl;
+
+ std::stringstream ssEndPoint;
+ ssEndPoint << evhttp_uri_get_host(targetURI) << ":" << evhttp_uri_get_port(targetURI);
+ std::string endPoint = ssEndPoint.str();
+
+ std::stringstream ssLocalURI;
+ ssLocalURI << evhttp_uri_get_path(targetURI) << evhttp_uri_get_fragment(targetURI);
+ std::string localURI = ssLocalURI.str();
+
+ if (_httpConnections.find(endPoint) == _httpConnections.end())
+ _httpConnections[endPoint] = evhttp_connection_base_new(_asyncQueue._eventLoop, _dns, evhttp_uri_get_host(targetURI), evhttp_uri_get_port(targetURI));
+
+ struct evhttp_connection* httpConn = _httpConnections[endPoint];
+ struct evhttp_request* httpReq = evhttp_request_new(EventIOProcessor::httpSendReqDone, this);
+
+#if 0
+ // event name
+ if (sendData->req.event.size() > 0) {
+ evhttp_add_header(evhttp_request_get_output_headers(httpReq), "_scxmleventname", evhttp_encode_uri(sendData->req.event.c_str()));
+ }
+
+ // event namelist
+ if (sendData->req.namelist.size() > 0) {
+ std::map<std::string, std::string>::iterator namelistIter = sendData->req.namelist.begin();
+ while (namelistIter != sendData->req.namelist.end()) {
+ evhttp_add_header(evhttp_request_get_output_headers(httpReq),
+ namelistIter->first.c_str(),
+ evhttp_encode_uri(namelistIter->second.c_str()));
+ namelistIter++;
+ }
+ }
+
+ // event params
+ if (sendData->req.params.size() > 0) {
+ std::map<std::string, std::string>::iterator paramIter = sendData->req.params.begin();
+ while (paramIter != sendData->req.params.end()) {
+ evhttp_add_header(evhttp_request_get_output_headers(httpReq),
+ paramIter->first.c_str(),
+ evhttp_encode_uri(paramIter->second.c_str()));
+ paramIter++;
+ }
+ }
+
+ // content
+ if (sendData->req.content.size() > 0)
+ evbuffer_add(evhttp_request_get_output_buffer(httpReq), sendData->req.content.c_str(), sendData->req.content.size());
+#endif
+
+ evhttp_add_header(evhttp_request_get_output_headers(httpReq), "_scxmleventstruct", evhttp_encode_uri(req.toXMLString().c_str()));
+
+
+ _httpRequests[req.sendid] = httpReq;
+ err = evhttp_make_request(httpConn,
+ httpReq,
+ EVHTTP_REQ_POST, localURI.c_str());
+ if (err) {
+ LOG(ERROR) << "Could not make http request to " << req.target;
+ }
+}
+
+void EventIOProcessor::httpRecvReq(struct evhttp_request *req, void *arg) {
+
+ const char *cmdtype;
+ struct evkeyvalq *headers;
+ struct evkeyval *header;
+ struct evbuffer *buf;
+
+ switch (evhttp_request_get_command(req)) {
+ case EVHTTP_REQ_GET: cmdtype = "GET"; break;
+ case EVHTTP_REQ_POST: cmdtype = "POST"; break;
+ case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break;
+ case EVHTTP_REQ_PUT: cmdtype = "PUT"; break;
+ case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break;
+ case EVHTTP_REQ_OPTIONS: cmdtype = "OPTIONS"; break;
+ case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break;
+ case EVHTTP_REQ_CONNECT: cmdtype = "CONNECT"; break;
+ case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break;
+ default: cmdtype = "unknown"; break;
+ }
+
+ Event reqEvent;
+ reqEvent.type = Event::EXTERNAL;
+ bool scxmlStructFound = false;
+
+ // map headers to event structure
+ headers = evhttp_request_get_input_headers(req);
+ for (header = headers->tqh_first; header;
+ header = header->next.tqe_next) {
+// std::cout << "Header: " << header->key << std::endl;
+// std::cout << "Value: " << evhttp_decode_uri(header->value) << std::endl;
+ if (boost::iequals("_scxmleventstruct", header->key)) {
+ reqEvent = Event::fromXML(evhttp_decode_uri(header->value));
+ scxmlStructFound = true;
+ break;
+ } else if (boost::iequals("_scxmleventname", header->key)) {
+ reqEvent.name = evhttp_decode_uri(header->value);
+ } else {
+ reqEvent.compound[header->key] = Data(evhttp_decode_uri(header->value), Data::VERBATIM);
+ }
+ }
+
+ if (!scxmlStructFound) {
+ // get content into event
+ std::string content;
+ buf = evhttp_request_get_input_buffer(req);
+ while (evbuffer_get_length(buf)) {
+ int n;
+ char cbuf[128];
+ n = evbuffer_remove(buf, cbuf, sizeof(buf)-1);
+ if (n > 0) {
+ content.append(cbuf, n);
+ }
+ }
+ reqEvent.compound["content"] = Data(content, Data::VERBATIM);
+ }
+
+ EventIOProcessor* INSTANCE = (EventIOProcessor*)arg;
+ INSTANCE->_interpreter->receive(reqEvent);
+
+ evhttp_send_reply(req, 200, "OK", NULL);
+}
+
+void EventIOProcessor::httpSendReqDone(struct evhttp_request *req, void *cb_arg) {
+ if (req) {
+ LOG(INFO) << "got return code " << evhttp_request_get_response_code(req) << std::endl;
+ }
+}
+
+EventIOServer::EventIOServer(unsigned short port) {
+ _port = port;
+ _base = event_base_new();
+ _http = evhttp_new(_base);
+ _handle = NULL;
+ while((_handle = evhttp_bind_socket_with_handle(_http, INADDR_ANY, _port)) == NULL) {
+ _port++;
+ }
+ determineAddress();
+}
+
+EventIOServer::~EventIOServer() {
+}
+
+EventIOServer* EventIOServer::_instance = NULL;
+tthread::recursive_mutex EventIOServer::_instanceMutex;
+
+EventIOServer* EventIOServer::getInstance() {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_instanceMutex);
+ if (_instance == NULL) {
+ _instance = new EventIOServer(8080);
+ _instance->start();
+ }
+ return _instance;
+}
+
+void EventIOServer::registerProcessor(EventIOProcessor* processor) {
+ EventIOServer* INSTANCE = getInstance();
+ tthread::lock_guard<tthread::recursive_mutex> lock(INSTANCE->_mutex);
+
+ /**
+ * Determine path for interpreter.
+ *
+ * If the interpreter has a name and it is not yet taken, choose it as the path
+ * for requests. If the interpreters name path is already taken, append digits
+ * until we have an available path.
+ *
+ * If the interpreter does not specify a name, take its sessionid.
+ */
+
+ std::string path = processor->_interpreter->getName();
+ if (path.size() == 0) {
+ path = processor->_interpreter->getSessionId();
+ }
+ assert(path.size() > 0);
+
+ std::stringstream actualPath(path);
+ int i = 1;
+ while(INSTANCE->_processors.find(actualPath.str()) != INSTANCE->_processors.end()) {
+ actualPath.str(std::string());
+ actualPath.clear();
+ actualPath << path << ++i;
+ }
+
+ std::stringstream processorURL;
+ processorURL << "http://" << INSTANCE->_address << ":" << INSTANCE->_port << "/" << actualPath.str();
+
+ INSTANCE->_processors[actualPath.str()] = processor;
+ processor->setURL(processorURL.str());
+
+ evhttp_set_cb(INSTANCE->_http, ("/" + actualPath.str()).c_str(), EventIOProcessor::httpRecvReq, processor);
+// evhttp_set_cb(THIS->_http, "/", EventIOProcessor::httpRecvReq, processor);
+// evhttp_set_gencb(THIS->_http, EventIOProcessor::httpRecvReq, NULL);
+}
+
+void EventIOServer::unregisterProcessor(EventIOProcessor* processor) {
+ EventIOServer* INSTANCE = getInstance();
+ tthread::lock_guard<tthread::recursive_mutex> lock(INSTANCE->_mutex);
+ evhttp_del_cb(INSTANCE->_http, processor->_url.c_str());
+}
+
+void EventIOServer::start() {
+ _isRunning = true;
+ _thread = new tthread::thread(EventIOServer::run, this);
+}
+
+void EventIOServer::run(void* instance) {
+ EventIOServer* INSTANCE = (EventIOServer*)instance;
+ while(INSTANCE->_isRunning) {
+ LOG(INFO) << "Dispatching HTTP Server" << std::endl;
+ event_base_dispatch(INSTANCE->_base);
+ }
+ LOG(INFO) << "HTTP Server stopped" << std::endl;
+}
+
+std::string EventIOServer::syncResolve(const std::string& hostname) {
+ struct hostent *he;
+ struct in_addr **addr_list;
+ int i;
+
+ if ( (he = gethostbyname( hostname.c_str() ) ) != NULL) {
+ addr_list = (struct in_addr **) he->h_addr_list;
+ for(i = 0; addr_list[i] != NULL; i++) {
+ return std::string(inet_ntoa(*addr_list[i]));
+ }
+ }
+ return "";
+}
+
+void EventIOServer::determineAddress() {
+
+ char hostname[1024];
+ gethostname(hostname, 1024);
+ _address = std::string(hostname);
+
+#if 0
+ struct sockaddr_storage ss;
+ evutil_socket_t fd;
+ ev_socklen_t socklen = sizeof(ss);
+ char addrbuf[128];
+
+ void *inaddr;
+ const char *addr;
+ int got_port = -1;
+ fd = evhttp_bound_socket_get_fd(_handle);
+ memset(&ss, 0, sizeof(ss));
+ if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) {
+ perror("getsockname() failed");
+ return;
+ }
+
+ if (ss.ss_family == AF_INET) {
+ got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
+ inaddr = &((struct sockaddr_in*)&ss)->sin_addr;
+ } else if (ss.ss_family == AF_INET6) {
+ got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
+ inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr;
+ } else {
+ fprintf(stderr, "Weird address family %d\n",
+ ss.ss_family);
+ return;
+ }
+ addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf,
+ sizeof(addrbuf));
+ if (addr) {
+ _address = std::string(addr);
+ } else {
+ fprintf(stderr, "evutil_inet_ntop failed\n");
+ return;
+ }
+#endif
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h
new file mode 100644
index 0000000..af7aac7
--- /dev/null
+++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h
@@ -0,0 +1,107 @@
+#ifndef EVENTIOPROCESSOR_H_2CUY93KU
+#define EVENTIOPROCESSOR_H_2CUY93KU
+
+#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h"
+#include "uscxml/Interpreter.h"
+#include "uscxml/Factory.h"
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+
+#include <event2/http.h>
+#include <event2/http_struct.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
+namespace uscxml {
+
+class EventIOServer;
+
+class EventIOProcessor : public uscxml::IOProcessor {
+public:
+ struct SendData {
+ EventIOProcessor* ioProcessor;
+ uscxml::SendRequest req;
+ };
+
+ EventIOProcessor();
+ virtual ~EventIOProcessor();
+ virtual IOProcessor* create(uscxml::Interpreter* interpreter);
+
+ virtual std::set<std::string> getNames() {
+ std::set<std::string> names;
+ names.insert("basichttp");
+ names.insert("http://www.w3.org/TR/scxml/#SCXMLEventProcessor");
+ return names;
+ }
+
+ virtual void send(uscxml::SendRequest& req);
+
+ Data getDataModelVariables();
+ void setURL(const std::string& url) { _url = url; }
+
+ void start();
+ static void run(void* instance);
+
+ static void httpMakeSendReq(void* userdata, std::string eventName);
+ static void httpSendReqDone(struct evhttp_request *req, void *cb_arg);
+ static void httpRecvReq(struct evhttp_request *req, void *arg);
+
+protected:
+ std::map<std::string, SendData> _sendData;
+
+ std::string _url;
+
+ uscxml::DelayedEventQueue _asyncQueue;
+ uscxml::Interpreter* _interpreter;
+ std::map<std::string, struct evhttp_connection*> _httpConnections;
+ std::map<std::string, struct evhttp_request*> _httpRequests;
+ struct evdns_base* _dns;
+
+ friend class EventIOServer;
+};
+
+class EventIOServer {
+private:
+ static EventIOServer* getInstance();
+ EventIOServer(unsigned short port);
+ ~EventIOServer();
+
+ void start();
+ void stop();
+ static void run(void* instance);
+
+ void determineAddress();
+ static std::string syncResolve(const std::string& hostname);
+
+ static void registerProcessor(EventIOProcessor* processor);
+ static void unregisterProcessor(EventIOProcessor* processor);
+
+
+ std::map<std::string, EventIOProcessor*> _processors;
+
+ struct event_base* _base;
+ struct evhttp* _http;
+ struct evhttp_bound_socket* _handle;
+
+ unsigned short _port;
+ std::string _address;
+
+ static EventIOServer* _instance;
+ static tthread::recursive_mutex _instanceMutex;
+ tthread::thread* _thread;
+ tthread::recursive_mutex _mutex;
+ bool _isRunning;
+
+ friend class EventIOProcessor;
+};
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_INHERIT_PROVIDER(EventIOProcessor, IOProcessor);
+#endif
+
+}
+
+#endif /* end of include guard: EVENTIOPROCESSOR_H_2CUY93KU */ \ No newline at end of file