diff options
Diffstat (limited to 'src/uscxml')
49 files changed, 4331 insertions, 741 deletions
diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp index 553e886..fdbbbc3 100644 --- a/src/uscxml/Factory.cpp +++ b/src/uscxml/Factory.cpp @@ -2,61 +2,121 @@ #include "uscxml/config.h" #include "uscxml/Factory.h" -#include "uscxml/datamodel/ecmascript/v8/V8DataModel.h" -#include "uscxml/ioprocessor/basichttp/libevent/EventIOProcessor.h" -#include "uscxml/invoker/scxml/USCXMLInvoker.h" +#include "uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h" +#include "uscxml/plugins/invoker/scxml/USCXMLInvoker.h" #ifdef UMUNDO_FOUND -#include "uscxml/invoker/umundo/UmundoInvoker.h" +#include "uscxml/plugins/invoker/umundo/UmundoInvoker.h" #endif #ifdef MILES_FOUND -#include "uscxml/invoker/modality/miles/SpatialAudio.h" +#include "uscxml/plugins/invoker/modality/miles/SpatialAudio.h" +#endif + +#ifdef V8_FOUND +#include "uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h" #endif namespace uscxml { Factory::Factory() { - _dataModels["ecmascript"] = new V8DataModel(); +#ifdef BUILD_AS_PLUGINS + pluma.acceptProviderType<InvokerProvider>(); + pluma.acceptProviderType<IOProcessorProvider>(); + pluma.acceptProviderType<DataModelProvider>(); + pluma.loadFromFolder("/Users/sradomski/Documents/TK/Code/uscxml/build/xcode/lib"); - // use basichttp for transporting to/from scxml sessions as well - _ioProcessors["basichttp"] = new EventIOProcessor(); - _ioProcessors["http://www.w3.org/TR/scxml/#SCXMLEventProcessor"] = _ioProcessors["basichttp"]; + std::vector<InvokerProvider*> invokerProviders; + pluma.getProviders(invokerProviders); + for (std::vector<InvokerProvider*>::iterator it = invokerProviders.begin() ; it != invokerProviders.end() ; ++it) { + Invoker* invoker = (*it)->create(); + registerInvoker(invoker); + } - _invoker["scxml"] = new USCXMLInvoker(); - _invoker["http://www.w3.org/TR/scxml/"] = _invoker["scxml"]; + std::vector<IOProcessorProvider*> ioProcessorProviders; + pluma.getProviders(ioProcessorProviders); + for (std::vector<IOProcessorProvider*>::iterator it = ioProcessorProviders.begin() ; it != ioProcessorProviders.end() ; ++it) { + IOProcessor* ioProcessor = (*it)->create(); + registerIOProcessor(ioProcessor); + } + std::vector<DataModelProvider*> dataModelProviders; + pluma.getProviders(dataModelProviders); + for (std::vector<DataModelProvider*>::iterator it = dataModelProviders.begin() ; it != dataModelProviders.end() ; ++it) { + DataModel* dataModel = (*it)->create(); + registerDataModel(dataModel); + } + + pluma.unloadAll(); + +#else #ifdef UMUNDO_FOUND - _invoker["umundo"] = new UmundoInvoker(); - _invoker["http://umundo.tk.informatik.tu-darmstadt.de/"] = _invoker["umundo"]; + { + UmundoInvoker* invoker = new UmundoInvoker(); + registerInvoker(invoker); + } #endif #ifdef MILES_FOUND - _invoker["spatial-audio"] = new SpatialAudio(); - _invoker["audio"] = _invoker["spatial-audio"]; - _invoker["http://www.smartvortex.eu/mmi/spatial-audio/"] = _invoker["spatial-audio"]; + { + SpatialAudio* invoker = new SpatialAudio(); + registerInvoker(invoker); + } #endif + +#ifdef V8_FOUND + { + V8DataModel* dataModel = new V8DataModel(); + registerDataModel(dataModel); + } +#endif + + // these are always available + { + USCXMLInvoker* invoker = new USCXMLInvoker(); + registerInvoker(invoker); + } + { + EventIOProcessor* ioProcessor = new EventIOProcessor(); + registerIOProcessor(ioProcessor); + } +#endif } - void Factory::registerIOProcessor(const std::string type, IOProcessor* ioProcessor) { - getInstance()->_ioProcessors[type] = ioProcessor; + void Factory::registerIOProcessor(IOProcessor* ioProcessor) { + std::set<std::string> names = ioProcessor->getNames(); + std::set<std::string>::iterator nameIter = names.begin(); + while(nameIter != names.end()) { + _ioProcessors[*nameIter] = ioProcessor; + nameIter++; + } } - void Factory::registerDataModel(const std::string type, DataModel* dataModel) { - getInstance()->_dataModels[type] = dataModel; + void Factory::registerDataModel(DataModel* dataModel) { + std::set<std::string> names = dataModel->getNames(); + std::set<std::string>::iterator nameIter = names.begin(); + while(nameIter != names.end()) { + _dataModels[*nameIter] = dataModel; + nameIter++; + } } + void Factory::registerInvoker(Invoker* invoker) { + std::set<std::string> names = invoker->getNames(); + std::set<std::string>::iterator nameIter = names.begin(); + while(nameIter != names.end()) { + _invokers[*nameIter] = invoker; + nameIter++; + } + } + void Factory::registerExecutableContent(const std::string tag, ExecutableContent* executableContent) { - getInstance()->_executableContent[tag] = executableContent; + _executableContent[tag] = executableContent; } - void Factory::registerInvoker(const std::string type, Invoker* invoker) { - getInstance()->_invoker[type] = invoker; - } - Invoker* Factory::getInvoker(const std::string type, Interpreter* interpreter) { - if (Factory::getInstance()->_invoker.find(type) != getInstance()->_invoker.end()) { - return (Invoker*)getInstance()->_invoker[type]->create(interpreter); + if (Factory::getInstance()->_invokers.find(type) != getInstance()->_invokers.end()) { + return (Invoker*)getInstance()->_invokers[type]->create(interpreter); } return NULL; } diff --git a/src/uscxml/Factory.h b/src/uscxml/Factory.h index e2418f0..24d74e3 100644 --- a/src/uscxml/Factory.h +++ b/src/uscxml/Factory.h @@ -3,10 +3,16 @@ #include "uscxml/Message.h" +#ifdef BUILD_AS_PLUGINS +#include "Pluma/Pluma.hpp" +#endif + #include <string> +#include <set> namespace uscxml { + // see http://stackoverflow.com/questions/228005/alternative-to-itoa-for-converting-integer-to-string-c template <typename T> std::string toStr(T tmp) { std::ostringstream out; out << tmp; @@ -33,9 +39,13 @@ namespace uscxml { IOProcessor() {}; virtual ~IOProcessor() {}; virtual IOProcessor* create(Interpreter* interpreter) = 0; + virtual std::set<std::string> getNames() = 0; + virtual void setInterpreter(Interpreter* interpreter) { _interpreter = interpreter; } virtual Data getDataModelVariables() = 0; virtual void send(SendRequest& req) = 0; + protected: + Interpreter* _interpreter; }; class Invoker : public IOProcessor { @@ -46,8 +56,9 @@ namespace uscxml { class DataModel { public: - virtual DataModel* create(Interpreter* interpreter) = 0; virtual ~DataModel() {} + virtual DataModel* create(Interpreter* interpreter) = 0; + virtual std::set<std::string> getNames() = 0; virtual bool validate(const std::string& location, const std::string& schema) = 0; virtual void setEvent(const Event& event) = 0; @@ -67,10 +78,10 @@ namespace uscxml { class Factory { public: - static void registerIOProcessor(const std::string type, IOProcessor* ioProcessor); - static void registerDataModel(const std::string type, DataModel* dataModel); - static void registerExecutableContent(const std::string tag, ExecutableContent* executableContent); - static void registerInvoker(const std::string type, Invoker* invoker); + void registerIOProcessor(IOProcessor* ioProcessor); + void registerDataModel(DataModel* dataModel); + void registerInvoker(Invoker* invoker); + void registerExecutableContent(const std::string tag, ExecutableContent* executableContent); static DataModel* getDataModel(const std::string type, Interpreter* interpreter); static IOProcessor* getIOProcessor(const std::string type, Interpreter* interpreter); @@ -81,10 +92,14 @@ namespace uscxml { std::map<std::string, DataModel*> _dataModels; std::map<std::string, IOProcessor*> _ioProcessors; - std::map<std::string, Invoker*> _invoker; + std::map<std::string, Invoker*> _invokers; std::map<std::string, ExecutableContent*> _executableContent; protected: +#ifdef BUILD_AS_PLUGINS + pluma::Pluma pluma; +#endif + Factory(); static Factory* _instance; diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 773516e..6890baf 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -18,7 +18,7 @@ #include <SAX/helpers/CatchErrorHandler.hpp> #include "uscxml/concurrency/tinythread.h" -#include "uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h" +#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h" #include "uscxml/concurrency/BlockingQueue.h" #include "uscxml/Message.h" #include "uscxml/Factory.h" diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp index 722352d..991c875 100644 --- a/src/uscxml/URL.cpp +++ b/src/uscxml/URL.cpp @@ -1,7 +1,17 @@ -#include "URL.h" #include <glog/logging.h> #include <algorithm> +#include <stdio.h> +#include <string.h> +#ifndef WIN32 +#include <sys/time.h> +#endif +#include <stdlib.h> +#include <errno.h> + +#include "uscxml/Common.h" +#include "URL.h" + namespace uscxml { std::ostream & operator<<(std::ostream & stream, const URL& url) { @@ -37,5 +47,349 @@ std::ostream & operator<<(std::ostream & stream, const URL& url) { return stream; } - +/* we use a global one for convenience */ +CURLM *multi_handle; + +/* curl calls this routine to get more data */ +static size_t write_callback(char *buffer, + size_t size, + size_t nitems, + void *userp) +{ + char *newbuff; + size_t rembuff; + + URL_FILE *url = (URL_FILE *)userp; + size *= nitems; + + rembuff=url->buffer_len - url->buffer_pos; /* remaining space in buffer */ + + if(size > rembuff) { + /* not enough space in buffer */ + newbuff=(char*)realloc(url->buffer,url->buffer_len + (size - rembuff)); + if(newbuff==NULL) { + fprintf(stderr,"callback buffer grow failed\n"); + size=rembuff; + } + else { + /* realloc suceeded increase buffer size*/ + url->buffer_len+=size - rembuff; + url->buffer=newbuff; + } + } + + memcpy(&url->buffer[url->buffer_pos], buffer, size); + url->buffer_pos += size; + + return size; +} + +/* use to attempt to fill the read buffer up to requested number of bytes */ +static int fill_buffer(URL_FILE *file, size_t want) +{ + fd_set fdread; + fd_set fdwrite; + fd_set fdexcep; + struct timeval timeout; + int rc; + + /* only attempt to fill buffer if transactions still running and buffer + * doesnt exceed required size already + */ + if((!file->still_running) || (file->buffer_pos > want)) + return 0; + + /* attempt to fill buffer */ + do { + int maxfd = -1; + long curl_timeo = -1; + + FD_ZERO(&fdread); + FD_ZERO(&fdwrite); + FD_ZERO(&fdexcep); + + /* set a suitable timeout to fail on */ + timeout.tv_sec = 60; /* 1 minute */ + timeout.tv_usec = 0; + + curl_multi_timeout(multi_handle, &curl_timeo); + if(curl_timeo >= 0) { + timeout.tv_sec = curl_timeo / 1000; + if(timeout.tv_sec > 1) + timeout.tv_sec = 1; + else + timeout.tv_usec = (curl_timeo % 1000) * 1000; + } + + /* get file descriptors from the transfers */ + curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); + + /* In a real-world program you OF COURSE check the return code of the + function calls. On success, the value of maxfd is guaranteed to be + greater or equal than -1. We call select(maxfd + 1, ...), specially + in case of (maxfd == -1), we call select(0, ...), which is basically + equal to sleep. */ + + rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); + + switch(rc) { + case -1: + /* select error */ + break; + + case 0: + default: + /* timeout or readable/writable sockets */ + curl_multi_perform(multi_handle, &file->still_running); + break; + } + } while(file->still_running && (file->buffer_pos < want)); + return 1; +} + +/* use to remove want bytes from the front of a files buffer */ +static int use_buffer(URL_FILE *file,int want) +{ + /* sort out buffer */ + if((file->buffer_pos - want) <=0) { + /* ditch buffer - write will recreate */ + if(file->buffer) + free(file->buffer); + + file->buffer=NULL; + file->buffer_pos=0; + file->buffer_len=0; + } + else { + /* move rest down make it available for later */ + memmove(file->buffer, + &file->buffer[want], + (file->buffer_pos - want)); + + file->buffer_pos -= want; + } + return 0; +} + +URL_FILE *url_fopen(const char *url,const char *operation) +{ + /* this code could check for URLs or types in the 'url' and + basicly use the real fopen() for standard files */ + + URL_FILE *file; + (void)operation; + + file = (URL_FILE*)malloc(sizeof(URL_FILE)); + if(!file) + return NULL; + + memset(file, 0, sizeof(URL_FILE)); + + if((file->handle.file=fopen(url,operation))) + file->type = CFTYPE_FILE; /* marked as URL */ + + else { + file->type = CFTYPE_CURL; /* marked as URL */ + file->handle.curl = curl_easy_init(); + + curl_easy_setopt(file->handle.curl, CURLOPT_URL, url); + curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file); + curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback); + + if(!multi_handle) + multi_handle = curl_multi_init(); + + curl_multi_add_handle(multi_handle, file->handle.curl); + + /* lets start the fetch */ + curl_multi_perform(multi_handle, &file->still_running); + + if((file->buffer_pos == 0) && (!file->still_running)) { + /* if still_running is 0 now, we should return NULL */ + + /* make sure the easy handle is not in the multi handle anymore */ + curl_multi_remove_handle(multi_handle, file->handle.curl); + + /* cleanup */ + curl_easy_cleanup(file->handle.curl); + + free(file); + + file = NULL; + } + } + return file; +} + +int url_fclose(URL_FILE *file) +{ + int ret=0;/* default is good return */ + + switch(file->type) { + case CFTYPE_FILE: + ret=fclose(file->handle.file); /* passthrough */ + break; + + case CFTYPE_CURL: + /* make sure the easy handle is not in the multi handle anymore */ + curl_multi_remove_handle(multi_handle, file->handle.curl); + + /* cleanup */ + curl_easy_cleanup(file->handle.curl); + break; + + default: /* unknown or supported type - oh dear */ + ret=EOF; + errno=EBADF; + break; + } + + if(file->buffer) + free(file->buffer);/* free any allocated buffer space */ + + free(file); + + return ret; +} + +int url_feof(URL_FILE *file) +{ + int ret=0; + + switch(file->type) { + case CFTYPE_FILE: + ret=feof(file->handle.file); + break; + + case CFTYPE_CURL: + if((file->buffer_pos == 0) && (!file->still_running)) + ret = 1; + break; + + default: /* unknown or supported type - oh dear */ + ret=-1; + errno=EBADF; + break; + } + return ret; +} + +size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file) +{ + size_t want; + + switch(file->type) { + case CFTYPE_FILE: + want=fread(ptr,size,nmemb,file->handle.file); + break; + + case CFTYPE_CURL: + want = nmemb * size; + + fill_buffer(file,want); + + /* check if theres data in the buffer - if not fill_buffer() + * either errored or EOF */ + if(!file->buffer_pos) + return 0; + + /* ensure only available data is considered */ + if(file->buffer_pos < want) + want = file->buffer_pos; + + /* xfer data to caller */ + memcpy(ptr, file->buffer, want); + + use_buffer(file,want); + + want = want / size; /* number of items */ + break; + + default: /* unknown or supported type - oh dear */ + want=0; + errno=EBADF; + break; + + } + return want; +} + +char *url_fgets(char *ptr, size_t size, URL_FILE *file) +{ + size_t want = size - 1;/* always need to leave room for zero termination */ + size_t loop; + + switch(file->type) { + case CFTYPE_FILE: + ptr = fgets(ptr,size,file->handle.file); + break; + + case CFTYPE_CURL: + fill_buffer(file,want); + + /* check if theres data in the buffer - if not fill either errored or + * EOF */ + if(!file->buffer_pos) + return NULL; + + /* ensure only available data is considered */ + if(file->buffer_pos < want) + want = file->buffer_pos; + + /*buffer contains data */ + /* look for newline or eof */ + for(loop=0;loop < want;loop++) { + if(file->buffer[loop] == '\n') { + want=loop+1;/* include newline */ + break; + } + } + + /* xfer data to caller */ + memcpy(ptr, file->buffer, want); + ptr[want]=0;/* allways null terminate */ + + use_buffer(file,want); + + break; + + default: /* unknown or supported type - oh dear */ + ptr=NULL; + errno=EBADF; + break; + } + + return ptr;/*success */ +} + +void url_rewind(URL_FILE *file) +{ + switch(file->type) { + case CFTYPE_FILE: + rewind(file->handle.file); /* passthrough */ + break; + + case CFTYPE_CURL: + /* halt transaction */ + curl_multi_remove_handle(multi_handle, file->handle.curl); + + /* restart */ + curl_multi_add_handle(multi_handle, file->handle.curl); + + /* ditch buffer - write will recreate - resets stream pos*/ + if(file->buffer) + free(file->buffer); + + file->buffer=NULL; + file->buffer_pos=0; + file->buffer_len=0; + + break; + + default: /* unknown or supported type - oh dear */ + break; + } +} + }
\ No newline at end of file diff --git a/src/uscxml/URL.h b/src/uscxml/URL.h index d6fc9ed..8438d3a 100644 --- a/src/uscxml/URL.h +++ b/src/uscxml/URL.h @@ -1,10 +1,41 @@ #ifndef URL_H_27HPRH76 #define URL_H_27HPRH76 -#include "Utilities.h" +#include <string> +#include <sstream> +#include <curl/curl.h> namespace uscxml { +enum fcurl_type_e { + CFTYPE_NONE=0, + CFTYPE_FILE=1, + CFTYPE_CURL=2 +}; + +struct fcurl_data +{ + enum fcurl_type_e type; /* type of handle */ + union { + CURL *curl; + FILE *file; + } handle; /* handle */ + + char *buffer; /* buffer to store cached data*/ + size_t buffer_len; /* currently allocated buffers length */ + size_t buffer_pos; /* end of data in buffer*/ + int still_running; /* Is background url fetch still in progress */ +}; + +typedef struct fcurl_data URL_FILE; + +URL_FILE *url_fopen(const char *url,const char *operation); +int url_fclose(URL_FILE *file); +int url_feof(URL_FILE *file); +size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file); +char * url_fgets(char *ptr, size_t size, URL_FILE *file); +void url_rewind(URL_FILE *file); + class URL { public: URL(const std::string urlString) : _urlString(urlString) {} diff --git a/src/uscxml/Utilities.cpp b/src/uscxml/Utilities.cpp deleted file mode 100644 index 846d3fa..0000000 --- a/src/uscxml/Utilities.cpp +++ /dev/null @@ -1,403 +0,0 @@ -/***************************************************************************** - * - * Taken in its entirety from http://curl.haxx.se/libcurl/c/fopen.html - * - * This example source code introduces a c library buffered I/O interface to - * URL reads it supports fopen(), fread(), fgets(), feof(), fclose(), - * rewind(). Supported functions have identical prototypes to their normal c - * lib namesakes and are preceaded by url_ . - * - * Using this code you can replace your program's fopen() with url_fopen() - * and fread() with url_fread() and it become possible to read remote streams - * instead of (only) local files. Local files (ie those that can be directly - * fopened) will drop back to using the underlying clib implementations - * - * See the main() function at the bottom that shows an app that retrives from a - * specified url using fgets() and fread() and saves as two output files. - * - * Copyright (c) 2003 Simtec Electronics - * - * Re-implemented by Vincent Sanders <vince@kyllikki.org> with extensive - * reference to original curl example code - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * This example requires libcurl 7.9.7 or later. - */ - -#include <stdio.h> -#include <string.h> -#ifndef WIN32 -#include <sys/time.h> -#endif -#include <stdlib.h> -#include <errno.h> - -#include "uscxml/Common.h" -#include "uscxml/Utilities.h" - -/* we use a global one for convenience */ -CURLM *multi_handle; - -/* curl calls this routine to get more data */ -static size_t write_callback(char *buffer, - size_t size, - size_t nitems, - void *userp) -{ - char *newbuff; - size_t rembuff; - - URL_FILE *url = (URL_FILE *)userp; - size *= nitems; - - rembuff=url->buffer_len - url->buffer_pos; /* remaining space in buffer */ - - if(size > rembuff) { - /* not enough space in buffer */ - newbuff=(char*)realloc(url->buffer,url->buffer_len + (size - rembuff)); - if(newbuff==NULL) { - fprintf(stderr,"callback buffer grow failed\n"); - size=rembuff; - } - else { - /* realloc suceeded increase buffer size*/ - url->buffer_len+=size - rembuff; - url->buffer=newbuff; - } - } - - memcpy(&url->buffer[url->buffer_pos], buffer, size); - url->buffer_pos += size; - - return size; -} - -/* use to attempt to fill the read buffer up to requested number of bytes */ -static int fill_buffer(URL_FILE *file, size_t want) -{ - fd_set fdread; - fd_set fdwrite; - fd_set fdexcep; - struct timeval timeout; - int rc; - - /* only attempt to fill buffer if transactions still running and buffer - * doesnt exceed required size already - */ - if((!file->still_running) || (file->buffer_pos > want)) - return 0; - - /* attempt to fill buffer */ - do { - int maxfd = -1; - long curl_timeo = -1; - - FD_ZERO(&fdread); - FD_ZERO(&fdwrite); - FD_ZERO(&fdexcep); - - /* set a suitable timeout to fail on */ - timeout.tv_sec = 60; /* 1 minute */ - timeout.tv_usec = 0; - - curl_multi_timeout(multi_handle, &curl_timeo); - if(curl_timeo >= 0) { - timeout.tv_sec = curl_timeo / 1000; - if(timeout.tv_sec > 1) - timeout.tv_sec = 1; - else - timeout.tv_usec = (curl_timeo % 1000) * 1000; - } - - /* get file descriptors from the transfers */ - curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); - - /* In a real-world program you OF COURSE check the return code of the - function calls. On success, the value of maxfd is guaranteed to be - greater or equal than -1. We call select(maxfd + 1, ...), specially - in case of (maxfd == -1), we call select(0, ...), which is basically - equal to sleep. */ - - rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); - - switch(rc) { - case -1: - /* select error */ - break; - - case 0: - default: - /* timeout or readable/writable sockets */ - curl_multi_perform(multi_handle, &file->still_running); - break; - } - } while(file->still_running && (file->buffer_pos < want)); - return 1; -} - -/* use to remove want bytes from the front of a files buffer */ -static int use_buffer(URL_FILE *file,int want) -{ - /* sort out buffer */ - if((file->buffer_pos - want) <=0) { - /* ditch buffer - write will recreate */ - if(file->buffer) - free(file->buffer); - - file->buffer=NULL; - file->buffer_pos=0; - file->buffer_len=0; - } - else { - /* move rest down make it available for later */ - memmove(file->buffer, - &file->buffer[want], - (file->buffer_pos - want)); - - file->buffer_pos -= want; - } - return 0; -} - -URL_FILE *url_fopen(const char *url,const char *operation) -{ - /* this code could check for URLs or types in the 'url' and - basicly use the real fopen() for standard files */ - - URL_FILE *file; - (void)operation; - - file = (URL_FILE*)malloc(sizeof(URL_FILE)); - if(!file) - return NULL; - - memset(file, 0, sizeof(URL_FILE)); - - if((file->handle.file=fopen(url,operation))) - file->type = CFTYPE_FILE; /* marked as URL */ - - else { - file->type = CFTYPE_CURL; /* marked as URL */ - file->handle.curl = curl_easy_init(); - - curl_easy_setopt(file->handle.curl, CURLOPT_URL, url); - curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file); - curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0L); - curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback); - - if(!multi_handle) - multi_handle = curl_multi_init(); - - curl_multi_add_handle(multi_handle, file->handle.curl); - - /* lets start the fetch */ - curl_multi_perform(multi_handle, &file->still_running); - - if((file->buffer_pos == 0) && (!file->still_running)) { - /* if still_running is 0 now, we should return NULL */ - - /* make sure the easy handle is not in the multi handle anymore */ - curl_multi_remove_handle(multi_handle, file->handle.curl); - - /* cleanup */ - curl_easy_cleanup(file->handle.curl); - - free(file); - - file = NULL; - } - } - return file; -} - -int url_fclose(URL_FILE *file) -{ - int ret=0;/* default is good return */ - - switch(file->type) { - case CFTYPE_FILE: - ret=fclose(file->handle.file); /* passthrough */ - break; - - case CFTYPE_CURL: - /* make sure the easy handle is not in the multi handle anymore */ - curl_multi_remove_handle(multi_handle, file->handle.curl); - - /* cleanup */ - curl_easy_cleanup(file->handle.curl); - break; - - default: /* unknown or supported type - oh dear */ - ret=EOF; - errno=EBADF; - break; - } - - if(file->buffer) - free(file->buffer);/* free any allocated buffer space */ - - free(file); - - return ret; -} - -int url_feof(URL_FILE *file) -{ - int ret=0; - - switch(file->type) { - case CFTYPE_FILE: - ret=feof(file->handle.file); - break; - - case CFTYPE_CURL: - if((file->buffer_pos == 0) && (!file->still_running)) - ret = 1; - break; - - default: /* unknown or supported type - oh dear */ - ret=-1; - errno=EBADF; - break; - } - return ret; -} - -size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file) -{ - size_t want; - - switch(file->type) { - case CFTYPE_FILE: - want=fread(ptr,size,nmemb,file->handle.file); - break; - - case CFTYPE_CURL: - want = nmemb * size; - - fill_buffer(file,want); - - /* check if theres data in the buffer - if not fill_buffer() - * either errored or EOF */ - if(!file->buffer_pos) - return 0; - - /* ensure only available data is considered */ - if(file->buffer_pos < want) - want = file->buffer_pos; - - /* xfer data to caller */ - memcpy(ptr, file->buffer, want); - - use_buffer(file,want); - - want = want / size; /* number of items */ - break; - - default: /* unknown or supported type - oh dear */ - want=0; - errno=EBADF; - break; - - } - return want; -} - -char *url_fgets(char *ptr, size_t size, URL_FILE *file) -{ - size_t want = size - 1;/* always need to leave room for zero termination */ - size_t loop; - - switch(file->type) { - case CFTYPE_FILE: - ptr = fgets(ptr,size,file->handle.file); - break; - - case CFTYPE_CURL: - fill_buffer(file,want); - - /* check if theres data in the buffer - if not fill either errored or - * EOF */ - if(!file->buffer_pos) - return NULL; - - /* ensure only available data is considered */ - if(file->buffer_pos < want) - want = file->buffer_pos; - - /*buffer contains data */ - /* look for newline or eof */ - for(loop=0;loop < want;loop++) { - if(file->buffer[loop] == '\n') { - want=loop+1;/* include newline */ - break; - } - } - - /* xfer data to caller */ - memcpy(ptr, file->buffer, want); - ptr[want]=0;/* allways null terminate */ - - use_buffer(file,want); - - break; - - default: /* unknown or supported type - oh dear */ - ptr=NULL; - errno=EBADF; - break; - } - - return ptr;/*success */ -} - -void url_rewind(URL_FILE *file) -{ - switch(file->type) { - case CFTYPE_FILE: - rewind(file->handle.file); /* passthrough */ - break; - - case CFTYPE_CURL: - /* halt transaction */ - curl_multi_remove_handle(multi_handle, file->handle.curl); - - /* restart */ - curl_multi_add_handle(multi_handle, file->handle.curl); - - /* ditch buffer - write will recreate - resets stream pos*/ - if(file->buffer) - free(file->buffer); - - file->buffer=NULL; - file->buffer_pos=0; - file->buffer_len=0; - - break; - - default: /* unknown or supported type - oh dear */ - break; - } -} -
\ No newline at end of file diff --git a/src/uscxml/Utilities.h b/src/uscxml/Utilities.h deleted file mode 100644 index 8816c72..0000000 --- a/src/uscxml/Utilities.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef UTILITIES_H_A89E99LI -#define UTILITIES_H_A89E99LI - -#include <string> -#include <sstream> -#include <curl/curl.h> - -// see http://stackoverflow.com/questions/228005/alternative-to-itoa-for-converting-integer-to-string-c -template <typename T> std::string toStr(T tmp) { - std::ostringstream out; - out << tmp; - return out.str(); -} - -template <typename T> T strTo(std::string tmp) { - T output; - std::istringstream in(tmp); - in >> output; - return output; -} - -enum fcurl_type_e { - CFTYPE_NONE=0, - CFTYPE_FILE=1, - CFTYPE_CURL=2 -}; - -struct fcurl_data -{ - enum fcurl_type_e type; /* type of handle */ - union { - CURL *curl; - FILE *file; - } handle; /* handle */ - - char *buffer; /* buffer to store cached data*/ - size_t buffer_len; /* currently allocated buffers length */ - size_t buffer_pos; /* end of data in buffer*/ - int still_running; /* Is background url fetch still in progress */ -}; - -typedef struct fcurl_data URL_FILE; - -URL_FILE *url_fopen(const char *url,const char *operation); -int url_fclose(URL_FILE *file); -int url_feof(URL_FILE *file); -size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file); -char * url_fgets(char *ptr, size_t size, URL_FILE *file); -void url_rewind(URL_FILE *file); - -#endif /* end of include guard: UTILITIES_H_A89E99LI */ diff --git a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp index 170e5d9..e2a89b2 100644 --- a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.cpp +++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.cpp @@ -1,4 +1,4 @@ -#include "uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h" +#include "DelayedEventQueue.h" #include <assert.h> #include <event2/event.h> diff --git a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h index 024e353..024e353 100644 --- a/src/uscxml/concurrency/eventqueue/libevent/DelayedEventQueue.h +++ b/src/uscxml/concurrency/eventqueue/DelayedEventQueue.h diff --git a/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.cpp b/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.cpp deleted file mode 100644 index a93b14a..0000000 --- a/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "uscxml/concurrency/DelayedEventQueue.h" -#include <assert.h> - -namespace uscxml { - - DelayedEventQueue::DelayedEventQueue() { - _eventLoop = EV_DEFAULT; - _thread = NULL; - } - - DelayedEventQueue::~DelayedEventQueue() { - ev_break(_eventLoop); - if (_thread) - _thread->join(); - } - - void DelayedEventQueue::addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData) { - if(_timeoutWatcher.find(eventId) != _timeoutWatcher.end()) { - cancelEvent(eventId); - } - - _timeoutWatcher[eventId].eventId = eventId; - _timeoutWatcher[eventId].userData = userData; - _timeoutWatcher[eventId].eventQueue = this; - _timeoutWatcher[eventId].callback = callback; - - ev_timer_init (&_timeoutWatcher[eventId].io, DelayedEventQueue::timerCallback, ((float)delayMs)/1000.0f, 0.); - ev_timer_start (_eventLoop, &_timeoutWatcher[eventId].io); - - } - - void DelayedEventQueue::cancelEvent(std::string eventId) { - if(_timeoutWatcher.find(eventId) != _timeoutWatcher.end()) { - ev_timer_stop(_eventLoop, &_timeoutWatcher[eventId].io); - _timeoutWatcher.erase(eventId); - } - } - - void DelayedEventQueue::start() { - _thread = new tthread::thread(DelayedEventQueue::run, this); - } - - void DelayedEventQueue::stop() { - } - - void DelayedEventQueue::run(void* instance) { - ev_run (((DelayedEventQueue*)instance)->_eventLoop, 0); - } - - void DelayedEventQueue::timerCallback(EV_P_ ev_timer *w, int revents) { - struct callbackData *data = (struct callbackData*)w; - std::string eventId = data->eventId; // copy eventId - data->eventQueue->_timeoutWatcher.erase(data->eventId); - data->callback(data->userData, eventId); - } - -}
\ No newline at end of file diff --git a/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.h b/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.h deleted file mode 100644 index 2bc71b2..0000000 --- a/src/uscxml/concurrency/eventqueue/libev/DelayedEventQueue.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef DELAYEDEVENTQUEUE_H_JA6WRBVP -#define DELAYEDEVENTQUEUE_H_JA6WRBVP - -#include "tinythread.h" -#include <ev.h> - -#include <map> -#include <string> -#include <iostream> - -namespace uscxml { - -class DelayedEventQueue { -public: - - struct callbackData - { - ev_timer io; - void *userData; - void (*callback)(void*, const std::string eventId); - std::string eventId; - DelayedEventQueue* eventQueue; - }; - - DelayedEventQueue(); - virtual ~DelayedEventQueue(); - - void addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData); - void cancelEvent(std::string eventId); - - void start(); - void stop(); - static void run(void*); - - static void timerCallback(EV_P_ ev_timer *w, int revents); - - tthread::thread* _thread; - std::map<std::string, callbackData> _timeoutWatcher; - struct ev_loop* _eventLoop; -}; - -} - - -#endif /* end of include guard: DELAYEDEVENTQUEUE_H_JA6WRBVP */ diff --git a/src/uscxml/ioprocessor/basichttp/README.md b/src/uscxml/ioprocessor/basichttp/README.md deleted file mode 100644 index de89944..0000000 --- a/src/uscxml/ioprocessor/basichttp/README.md +++ /dev/null @@ -1,2 +0,0 @@ -Only the libevent basichttp ioprocessor is supported. Mongoose seemed somewhat -unmaintained and pion comes with too many dependencies.
\ No newline at end of file diff --git a/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.cpp b/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.cpp deleted file mode 100644 index a62fefc..0000000 --- a/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.h" -#include "uscxml/Message.h" - diff --git a/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.h b/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.h deleted file mode 100644 index bb7a0fc..0000000 --- a/src/uscxml/ioprocessor/basichttp/mongoose/MongooseIOProcessor.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef MONGOOSEIOPROCESSOR_H_JS0GMSFO -#define MONGOOSEIOPROCESSOR_H_JS0GMSFO - -#include "uscxml/Interpreter.h" -#include "uscxml/Factory.h" - -namespace uscxml { - -class MongooseIOProcessor : public IOProcessor { - -}; - -} - -#endif /* end of include guard: MONGOOSEIOPROCESSOR_H_JS0GMSFO */ diff --git a/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.cpp b/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.cpp deleted file mode 100644 index 7aa9169..0000000 --- a/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "uscxml/ioprocessor/basichttp/pion/PionIOProcessor.h" -#include "uscxml/Message.h" - -#include <pion/http/request.hpp> -#include <pion/http/message.hpp> - -namespace uscxml { - -using namespace pion; - -PionIOProcessor::PionIOProcessor() { -} - -PionIOProcessor::~PionIOProcessor() { - -} - -IOProcessor* PionIOProcessor::create(Interpreter* interpreter) { - PionIOProcessor* io = new PionIOProcessor(); - io->_interpreter = interpreter; - io->_ioServer = PionIOServer::getInstance(); - return io; -} - -void handle_connection(pion::tcp::connection_ptr& tcp_conn) { -} - -void PionIOProcessor::send(SendRequest& req) { - - boost::system::error_code error_code; - boost::asio::io_service io_service; - - pion::tcp::connection tcp_conn(io_service, 0); - error_code = tcp_conn.connect("localhost", 8080); - if (error_code) throw error_code; // connection failed - - - - http::request httpReq; - httpReq.set_method("POST"); - if (req.event.size() > 0) - httpReq.add_header("_scxmleventname", req.event); - - httpReq.send(tcp_conn, error_code); - -// http::request_writer writer; -// writer. - -} -void PionIOProcessor::invoke(InvokeRequest& req) { - -} -void PionIOProcessor::cancel(const std::string sendId) { - -} - -PionIOServer::PionIOServer() : pion::tcp::server(0) { -} - -PionIOServer::~PionIOServer() { -} - -void PionIOServer::handle_connection(pion::tcp::connection_ptr& tcp_conn) { -} - -PionIOServer* PionIOServer::_instance = NULL; -PionIOServer* PionIOServer::getInstance() { - if (_instance == NULL) { - _instance = new PionIOServer(); - } - return _instance; -} - -}
\ No newline at end of file diff --git a/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.h b/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.h deleted file mode 100644 index 154acdb..0000000 --- a/src/uscxml/ioprocessor/basichttp/pion/PionIOProcessor.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef PIONIOPROCESSOR_H_VAITDNCN -#define PIONIOPROCESSOR_H_VAITDNCN - -#include "uscxml/Interpreter.h" -#include "uscxml/Factory.h" -#include "uscxml/concurrency/DelayedEventQueue.h" - -#include <pion/http/request_writer.hpp> -#include <pion/http/request_writer.hpp> -#include <pion/tcp/server.hpp> - -namespace uscxml { - -class PionIOServer : public pion::tcp::server { -public: - PionIOServer(); - virtual ~PionIOServer(); - DelayedEventQueue _eventQueue; - - virtual void handle_connection(pion::tcp::connection_ptr& tcp_conn); - - static PionIOServer* getInstance(); - static PionIOServer* _instance; - - pion::http::request_writer_ptr _writer; - pion::tcp::connection_ptr _conn; - -}; - -class PionIOProcessor : public IOProcessor { -public: - PionIOProcessor(); - virtual ~PionIOProcessor(); - virtual IOProcessor* create(Interpreter* interpreter); - - virtual void send(SendRequest& req); - virtual void invoke(InvokeRequest& req); - virtual void cancel(const std::string sendId); - -protected: - Interpreter* _interpreter; - PionIOServer* _ioServer; -}; - -} - -#endif /* end of include guard: PIONIOPROCESSOR_H_VAITDNCN */ diff --git a/src/uscxml/plugins/Plugins.cpp b/src/uscxml/plugins/Plugins.cpp new file mode 100644 index 0000000..4e819bb --- /dev/null +++ b/src/uscxml/plugins/Plugins.cpp @@ -0,0 +1,11 @@ +#include "Plugins.h" + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_PROVIDER_SOURCE(DataModel, 1, 1); +PLUMA_PROVIDER_SOURCE(IOProcessor, 1, 1); +PLUMA_PROVIDER_SOURCE(Invoker, 1, 1); +#endif + +}
\ No newline at end of file diff --git a/src/uscxml/plugins/Plugins.h b/src/uscxml/plugins/Plugins.h new file mode 100644 index 0000000..56dd1e2 --- /dev/null +++ b/src/uscxml/plugins/Plugins.h @@ -0,0 +1,17 @@ +#ifndef PLUGINS_H_M6G1NF1E +#define PLUGINS_H_M6G1NF1E + +#include <Pluma/Pluma.hpp> +#include "uscxml/Factory.h" + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_PROVIDER_HEADER(IOProcessor); +PLUMA_PROVIDER_HEADER(Invoker); +PLUMA_PROVIDER_HEADER(DataModel); +#endif + +} + +#endif /* end of include guard: PLUGINS_H_M6G1NF1E */ diff --git a/src/uscxml/plugins/Pluma/Config.hpp b/src/uscxml/plugins/Pluma/Config.hpp new file mode 100755 index 0000000..efd98c9 --- /dev/null +++ b/src/uscxml/plugins/Pluma/Config.hpp @@ -0,0 +1,141 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+//
+// Based on SFML configuration header
+// SFML Config.hpp:
+// http://www.sfml-dev.org/documentation/2.0/Config_8hpp-source.htm
+//
+// Acknowledgements to Simple and Fast Multimedia Library
+// http://www.sfml-dev.org/
+//
+////////////////////////////////////////////////////////////
+
+
+#ifndef PLUMA_CONFIG_HPP
+#define PLUMA_CONFIG_HPP
+
+
+////////////////////////////////////////////////////////////
+// Identify the operating system
+////////////////////////////////////////////////////////////
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+
+ // Windows
+ #define PLUMA_SYS_WINDOWS
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+ #ifndef NOMINMAX
+ #define NOMINMAX
+ #endif
+
+#elif defined(linux) || defined(__linux)
+
+ // Linux
+ #define PLUMA_SYS_LINUX
+
+#elif defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh)
+
+ // MacOS
+ #define PLUMA_SYS_MACOS
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+
+ // FreeBSD
+ #define PLUMA_SYS_FREEBSD
+
+#else
+
+ // Unsupported system
+ #error This operating system is not supported by this library
+
+#endif
+
+
+
+////////////////////////////////////////////////////////////
+// Define library file extension based on OS
+////////////////////////////////////////////////////////////
+#ifdef PLUMA_SYS_WINDOWS
+ #define PLUMA_LIB_EXTENSION "dll"
+#elif defined(PLUMA_SYS_MACOS)
+ #define PLUMA_LIB_EXTENSION "dylib"
+#elif defined(PLUMA_SYS_LINUX) || defined(PLUMA_SYS_FREEBSD)
+ #define PLUMA_LIB_EXTENSION "so"
+#else
+ // unknown library file type
+ #error Unknown library file extension for this operating system
+#endif
+
+
+////////////////////////////////////////////////////////////
+// Define portable import / export macros
+////////////////////////////////////////////////////////////
+#if defined(PLUMA_SYS_WINDOWS)
+
+ #ifndef PLUMA_STATIC
+
+ // Windows platforms
+ #ifdef PLUMA_EXPORTS
+
+ // From DLL side, we must export
+ #define PLUMA_API __declspec(dllexport)
+
+ #else
+
+ // From client application side, we must import
+ #define PLUMA_API __declspec(dllimport)
+
+ #endif
+
+ // For Visual C++ compilers, we also need to turn off this annoying C4251 warning.
+ // You can read lots ot different things about it, but the point is the code will
+ // just work fine, and so the simplest way to get rid of this warning is to disable it
+ #ifdef _MSC_VER
+
+ #pragma warning(disable : 4251)
+
+ #endif
+
+ #else
+
+ // No specific directive needed for static build
+ #define PLUMA_API
+
+ #endif
+
+#else
+
+ // Other platforms don't need to define anything
+ #define PLUMA_API
+
+#endif
+
+
+
+
+#endif // PLUMA_CONFIG_HPP
diff --git a/src/uscxml/plugins/Pluma/Connector.hpp b/src/uscxml/plugins/Pluma/Connector.hpp new file mode 100755 index 0000000..3c227e7 --- /dev/null +++ b/src/uscxml/plugins/Pluma/Connector.hpp @@ -0,0 +1,86 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_CONNECTOR_HPP
+#define PLUMA_CONNECTOR_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Pluma.hpp>
+
+
+/////////////////////////////////////////////////////////////////
+// Define portable import/export macros for Plugin registration
+/////////////////////////////////////////////////////////////////
+#if defined(PLUMA_SYS_WINDOWS)
+
+ #ifndef PLUMA_STATIC_PLUGIN
+
+ // Windows platforms
+ #ifndef PLUGIN_IMPORTS
+
+ // From DLL side, we must export
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C" __declspec(dllexport)
+ #else
+ #define PLUMA_CONNECTOR __declspec(dllexport)
+ #endif
+
+ #else
+
+ // From client application side, we must import
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C" __declspec(dllimport)
+ #else
+ #define PLUMA_CONNECTOR __declspec(dllimport)
+ #endif
+
+ #endif
+
+ #else
+
+ // Only define the extern "C" for static build
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C"
+ #else
+ #define PLUMA_CONNECTOR
+ #endif
+
+ #endif
+
+#else
+
+ // Only define the extern "C" for other platforms
+ #ifdef __cplusplus
+ #define PLUMA_CONNECTOR extern "C"
+ #else
+ #define PLUMA_CONNECTOR
+ #endif
+
+#endif
+
+
+#endif // PLUMA_CONNECTOR_HPP
diff --git a/src/uscxml/plugins/Pluma/DLibrary.cpp b/src/uscxml/plugins/Pluma/DLibrary.cpp new file mode 100755 index 0000000..9b617db --- /dev/null +++ b/src/uscxml/plugins/Pluma/DLibrary.cpp @@ -0,0 +1,106 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/DLibrary.hpp>
+#include <cstdio>
+#include <string>
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+DLibrary* DLibrary::load(const std::string& path){
+ if ( path.empty() ){
+ fprintf(stderr, "Failed to load library: Empty path\n");
+ return NULL;
+ }
+ void* handle = NULL;
+
+ // load library - OS dependent operation
+ #ifdef PLUMA_SYS_WINDOWS
+ handle = ::LoadLibraryA(path.c_str());
+ if (!handle){
+ fprintf(stderr, "Failed to load library \"%s\".\n", path.c_str());
+ return NULL;
+ }
+ #else
+ handle = ::dlopen(path.c_str(), RTLD_NOW);
+ if (!handle){
+ const char* errorString = ::dlerror();
+ fprintf(stderr, "Failed to load library \"%s\".", path.c_str());
+ if(errorString) fprintf(stderr, " OS returned error: \"%s\".", errorString);
+ fprintf(stderr, "\n");
+ return NULL;
+ }
+ #endif
+ // return a DLibrary with the DLL handle
+ return new DLibrary(handle);
+}
+
+
+////////////////////////////////////////////////////////////
+DLibrary::~DLibrary(){
+ if (handle){
+ #ifdef PLUMA_SYS_WINDOWS
+ ::FreeLibrary( (HMODULE)handle );
+ #else
+ ::dlclose(handle);
+ #endif
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void* DLibrary::getSymbol(const std::string& symbol){
+ if (!handle){
+ fprintf(stderr, "Cannot inspect library symbols, library isn't loaded.\n");
+ return NULL;
+ }
+ void* res;
+ #ifdef PLUMA_SYS_WINDOWS
+ res = (void*)(::GetProcAddress((HMODULE)handle, symbol.c_str()));
+ #else
+ res = (void*)(::dlsym(handle, symbol.c_str()));
+ #endif
+ if (!res){
+ fprintf(stderr, "Library symbol \"%s\" not found.\n", symbol.c_str());
+ return NULL;
+ }
+ return res;
+}
+
+
+////////////////////////////////////////////////////////////
+DLibrary::DLibrary(void* handle):
+ handle(handle)
+{
+ // Nothing to do
+}
+
+} // namespace pluma
+
diff --git a/src/uscxml/plugins/Pluma/DLibrary.hpp b/src/uscxml/plugins/Pluma/DLibrary.hpp new file mode 100755 index 0000000..1bb9bac --- /dev/null +++ b/src/uscxml/plugins/Pluma/DLibrary.hpp @@ -0,0 +1,123 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_DYNAMIC_LIBRARY_HPP
+#define PLUMA_DYNAMIC_LIBRARY_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <string>
+
+// include OS dependent support for DLL
+#ifdef PLUMA_SYS_WINDOWS
+ #include <Windows.h>
+#else
+ #include <dlfcn.h>
+#endif
+
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+/// \brief Manages a Dynamic Linking Library.
+///
+////////////////////////////////////////////////////////////
+class DLibrary{
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load a library.
+ ///
+ /// \param path Path to the library.
+ ///
+ /// \return Pointer to the loaded library, or NULL if failed.
+ ///
+ ////////////////////////////////////////////////////////////
+ static DLibrary* load(const std::string& path);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ /// Close and free the opened library (if any).
+ ///
+ ////////////////////////////////////////////////////////////
+ ~DLibrary();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get a symbol from the library.
+ ///
+ /// \param symbol Symbol that we're looking for.
+ ///
+ /// \return Pointer to what the symbol refers to, or NULL if
+ /// the symbol is not found.
+ ///
+ ////////////////////////////////////////////////////////////
+ void* getSymbol(const std::string& symbol);
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor.
+ ///
+ /// Library instances cannot be created, use load instead.
+ ///
+ /// \see load
+ ///
+ ////////////////////////////////////////////////////////////
+ DLibrary();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Constructor via library handle.
+ ///
+ /// Used on load function.
+ ///
+ /// \see load
+ ///
+ ////////////////////////////////////////////////////////////
+ DLibrary(void* handle);
+
+
+
+////////////////////////////////////////////////////////////
+// Member data
+////////////////////////////////////////////////////////////
+
+
+private:
+
+ void* handle; ///< Library handle.
+
+};
+
+
+} // namespace pluma
+
+
+#endif // PLUMA_DYNAMIC_LIBRARY_HPP
diff --git a/src/uscxml/plugins/Pluma/Dir.cpp b/src/uscxml/plugins/Pluma/Dir.cpp new file mode 100755 index 0000000..860220e --- /dev/null +++ b/src/uscxml/plugins/Pluma/Dir.cpp @@ -0,0 +1,103 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Dir.hpp>
+#include <Pluma/uce-dirent.h>
+#include <cstdio>
+#include <queue>
+
+
+namespace pluma{
+
+namespace dir{
+
+
+////////////////////////////////////////////////////////////
+void listFiles(std::list<std::string>& list, const std::string& folder, const std::string& extension, bool recursive){
+ DIR* dir;
+ DIR* subDir;
+ struct dirent *ent;
+ // try to open top folder
+ dir = opendir(folder.c_str());
+ if (dir == NULL){
+ // could not open directory
+ fprintf(stderr, "Could not open \"%s\" directory.\n", folder.c_str());
+ return;
+ }else{
+ // close, we'll process it next
+ closedir(dir);
+ }
+ // enqueue top folder
+ std::queue<std::string> folders;
+ folders.push(folder);
+
+ // run while has queued folders
+ while (!folders.empty()){
+ std::string currFolder = folders.front();
+ folders.pop();
+ dir = opendir(currFolder.c_str());
+ if (dir == NULL) continue;
+ // iterate through all the files and directories
+ while ((ent = readdir (dir)) != NULL) {
+ std::string name(ent->d_name);
+ // ignore "." and ".." directories
+ if ( name.compare(".") == 0 || name.compare("..") == 0) continue;
+ // add path to the file name
+ std::string path = currFolder;
+ path.append("/");
+ path.append(name);
+ // check if it's a folder by trying to open it
+ subDir = opendir(path.c_str());
+ if (subDir != NULL){
+ // it's a folder: close, we can process it later
+ closedir(subDir);
+ if (recursive) folders.push(path);
+ }else{
+ // it's a file
+ if (extension.empty()){
+ list.push_back(path);
+ }else{
+ // check file extension
+ size_t lastDot = name.find_last_of('.');
+ std::string ext = name.substr(lastDot+1);
+ if (ext.compare(extension) == 0){
+ // match
+ list.push_back(path);
+ }
+ } // endif (extension test)
+ } // endif (folder test)
+ } // endwhile (nextFile)
+ closedir(dir);
+ } // endwhile (queued folders)
+
+} // end listFiles
+
+
+} // namespace dir
+
+} // namespace pluma
diff --git a/src/uscxml/plugins/Pluma/Dir.hpp b/src/uscxml/plugins/Pluma/Dir.hpp new file mode 100755 index 0000000..a94c477 --- /dev/null +++ b/src/uscxml/plugins/Pluma/Dir.hpp @@ -0,0 +1,64 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_DIRECTORY_HPP
+#define PLUMA_DIRECTORY_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <string>
+#include <list>
+
+
+namespace pluma{
+
+namespace dir{
+
+////////////////////////////////////////////////////////////
+/// \brief List files of a directory.
+///
+/// \param list The output files list.
+/// \param folder The folder where to search in
+/// \param extension A file extension filter,
+/// empty extension will match all files.
+/// \param recursive If true it will list files in
+/// sub directories as well.
+///
+////////////////////////////////////////////////////////////
+void listFiles(
+ std::list<std::string>& list,
+ const std::string& folder,
+ const std::string& extension = "",
+ bool recursive = false
+);
+
+
+} // namespace dir
+
+} // namespace pluma
+
+
+#endif // PLUMA_DIRECTORY_HPP
diff --git a/src/uscxml/plugins/Pluma/Host.cpp b/src/uscxml/plugins/Pluma/Host.cpp new file mode 100755 index 0000000..eb37c33 --- /dev/null +++ b/src/uscxml/plugins/Pluma/Host.cpp @@ -0,0 +1,179 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Host.hpp>
+#include <cstdio>
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+Host::Host(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::add(Provider* provider){
+ if (provider == NULL){
+ fprintf(stderr, "Trying to add a null provider.\n");
+ return false;
+ }
+ if (!validateProvider(provider)){
+ delete provider;
+ return false;
+ }
+ addRequests[ provider->plumaGetType() ].push_back(provider);
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+Host::~Host(){
+ clearProviders();
+ // map frees itself
+}
+
+
+////////////////////////////////////////////////////////////
+void Host::clearProviders(){
+ ProvidersMap::iterator it;
+ for (it = knownTypes.begin() ; it != knownTypes.end() ; ++it){
+ std::list<Provider*>& providers = it->second.providers;
+ std::list<Provider*>::iterator provIt;
+ for (provIt = providers.begin() ; provIt != providers.end() ; ++provIt){
+ delete *provIt;
+ }
+ std::list<Provider*>().swap(providers);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::knows(const std::string& type) const{
+ return knownTypes.find(type) != knownTypes.end();
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Host::getVersion(const std::string& type) const{
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return it->second.version;
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+unsigned int Host::getLowestVersion(const std::string& type) const{
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return it->second.lowestVersion;
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////
+void Host::registerType(const std::string& type, unsigned int version, unsigned int lowestVersion){
+ if (!knows(type)){
+ ProviderInfo pi;
+ pi.version = version;
+ pi.lowestVersion = lowestVersion;
+ knownTypes[type] = pi;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+const std::list<Provider*>* Host::getProviders(const std::string& type) const{
+ ProvidersMap::const_iterator it = knownTypes.find(type);
+ if (it != knownTypes.end())
+ return &it->second.providers;
+ return NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::validateProvider(Provider* provider) const{
+ const std::string& type = provider->plumaGetType();
+ if ( !knows(type) ){
+ fprintf(stderr, "%s provider type isn't registered.\n", type.c_str());
+ return false;
+ }
+ if (!provider->isCompatible(*this)){
+ fprintf(stderr, "Incompatible %s provider version.\n", type.c_str());
+ return false;
+ }
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::registerProvider(Provider* provider){
+ if (!validateProvider(provider)){
+ delete provider;
+ return false;
+ }
+ knownTypes[ provider->plumaGetType() ].providers.push_back(provider);
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+void Host::cancelAddictions(){
+ TempProvidersMap::iterator it;
+ for( it = addRequests.begin() ; it != addRequests.end() ; ++it){
+ std::list<Provider*> lst = it->second;
+ std::list<Provider*>::iterator providerIt;
+ for (providerIt = lst.begin() ; providerIt != lst.end() ; ++providerIt){
+ delete *providerIt;
+ }
+ }
+ // clear map
+ TempProvidersMap().swap(addRequests);
+}
+
+
+////////////////////////////////////////////////////////////
+bool Host::confirmAddictions(){
+ if (addRequests.empty()) return false;
+ TempProvidersMap::iterator it;
+ for( it = addRequests.begin() ; it != addRequests.end() ; ++it){
+ std::list<Provider*> lst = it->second;
+ std::list<Provider*>::iterator providerIt;
+ for (providerIt = lst.begin() ; providerIt != lst.end() ; ++providerIt){
+ knownTypes[it->first].providers.push_back(*providerIt);
+ }
+ }
+ // clear map
+ TempProvidersMap().swap(addRequests);
+ return true;
+}
+
+
+} //namespace pluma
diff --git a/src/uscxml/plugins/Pluma/Host.hpp b/src/uscxml/plugins/Pluma/Host.hpp new file mode 100755 index 0000000..cf049f5 --- /dev/null +++ b/src/uscxml/plugins/Pluma/Host.hpp @@ -0,0 +1,212 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_HOST_HPP
+#define PLUMA_HOST_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Provider.hpp>
+
+#include <vector>
+#include <list>
+#include <map>
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+/// \brief Manages providers.
+///
+////////////////////////////////////////////////////////////
+class PLUMA_API Host{
+friend class PluginManager;
+friend class Provider;
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Add provider.
+ ///
+ /// Provider type and version are checked. Only known and
+ /// valid provider types are accepted.
+ ///
+ /// \param provider Provider to be added.
+ ///
+ /// \return True if the provider is accepted.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool add(Provider* provider);
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor.
+ ///
+ /// New Host instances are not publicly allowed.
+ ///
+ ////////////////////////////////////////////////////////////
+ Host();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ /// Clears all hosted providers
+ ///
+ ////////////////////////////////////////////////////////////
+ ~Host();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Ckeck if a provider type is registered.
+ ///
+ /// \param type Provider type id.
+ ///
+ /// \return True if the type is registered
+ ///
+ ////////////////////////////////////////////////////////////
+ bool knows(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get version of a type of providers.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return The version of the provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ unsigned int getVersion(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get lowest compatible version of a type of providers.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return The lowest compatible version of the provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ unsigned int getLowestVersion(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Register a type of providers.
+ ///
+ /// \param type Provider type.
+ /// \param version Current version of that provider type.
+ /// \param lowestVersion Lowest compatible version of that provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ void registerType(const std::string& type, unsigned int version, unsigned int lowestVersion);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get providers of a certain type.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return Pointer to the list of providers of that \a type,
+ /// or NULL if \a type is not registered.
+ ///
+ ////////////////////////////////////////////////////////////
+ const std::list<Provider*>* getProviders(const std::string& type) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Clears all hosted providers.
+ ///
+ ////////////////////////////////////////////////////////////
+ void clearProviders();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Validate provider type and version.
+ ///
+ /// \return True if the provider is acceptable.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool validateProvider(Provider* provider) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Clearly add a provider.
+ ///
+ /// Provider type and version are checked. Only known and
+ /// valid provider types are accepted.
+ /// If acepted, provider is directly stored.
+ ///
+ /// \param provider Provider to be added.
+ ///
+ /// \return True if the provider is accepted.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool registerProvider(Provider* provider);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Previous add calls are canceled.
+ ///
+ /// Added providers are not stored.
+ ///
+ /// \see add
+ ///
+ ////////////////////////////////////////////////////////////
+ void cancelAddictions();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Previous add calls are confirmed.
+ ///
+ /// Added providers are finally stored.
+ ///
+ /// \return True if something was stored.
+ ///
+ /// \see add
+ ///
+ ////////////////////////////////////////////////////////////
+ bool confirmAddictions();
+
+
+
+////////////////////////////////////////////////////////////
+// Member data
+////////////////////////////////////////////////////////////
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Structure with information about a provider type.
+ ///
+ ////////////////////////////////////////////////////////////
+ struct ProviderInfo{
+ unsigned int version;
+ unsigned int lowestVersion;
+ std::list<Provider*> providers;
+ };
+
+ typedef std::map<std::string, ProviderInfo > ProvidersMap;
+ typedef std::map<std::string, std::list<Provider*> > TempProvidersMap;
+
+ ProvidersMap knownTypes; ///< Map of registered types.
+ TempProvidersMap addRequests; ///< Temporarily added providers
+
+};
+
+} // namespace pluma
+
+#endif // PLUMA_HOST_HPP
diff --git a/src/uscxml/plugins/Pluma/PluginManager.cpp b/src/uscxml/plugins/Pluma/PluginManager.cpp new file mode 100755 index 0000000..1124505 --- /dev/null +++ b/src/uscxml/plugins/Pluma/PluginManager.cpp @@ -0,0 +1,201 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/PluginManager.hpp>
+#include <Pluma/DLibrary.hpp>
+#include <Pluma/Dir.hpp>
+#include <cstdio>
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+PluginManager::PluginManager(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+PluginManager::~PluginManager(){
+ unloadAll();
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::load(const std::string& path){
+ std::string plugName = getPluginName(path);
+ std::string realPath = resolvePathExtension(path);
+ DLibrary* lib = DLibrary::load(realPath);
+ if (!lib) return false;
+
+ fnRegisterPlugin* registerFunction;
+ registerFunction = reinterpret_cast<fnRegisterPlugin*>(lib->getSymbol("connect"));
+
+ if(!registerFunction){
+ fprintf(stderr, "Failed to initialize plugin \"%s\": connect function not found\n", plugName.c_str());
+ delete lib;
+ return false;
+ }
+ // try to initialize plugin:
+ if (!registerFunction(host)){
+ // plugin decided to fail
+ fprintf(stderr, "Self registry failed on plugin \"%s\".\n", plugName.c_str());
+ host.cancelAddictions();
+ delete lib;
+ return false;
+ }
+ // Store the library if addictions are confirmed
+ if (host.confirmAddictions())
+ libraries[plugName] = lib;
+ else{
+ // otherwise nothing was registered
+ fprintf(stderr, "Nothing registered by plugin \"%s\".\n", plugName.c_str());
+ delete lib;
+ return false;
+ }
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::load(const std::string& folder, const std::string& pluginName){
+ if (folder.empty())
+ return load(pluginName);
+ else if (folder[folder.size()-1] == '/' || folder[folder.size()-1] == '\\')
+ return load(folder + pluginName);
+ return load(folder + '/' + pluginName);
+}
+
+
+////////////////////////////////////////////////////////////
+int PluginManager::loadFromFolder(const std::string& folder, bool recursive){
+ std::list<std::string> files;
+ dir::listFiles(files, folder, PLUMA_LIB_EXTENSION, recursive);
+ // try to load every library
+ int res = 0;
+ std::list<std::string>::const_iterator it;
+ for (it = files.begin() ; it != files.end() ; ++it){
+ if ( load(*it) ) ++res;
+ }
+ return res;
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::unload(const std::string& pluginName){
+ std::string plugName = getPluginName(pluginName);
+ LibMap::iterator it = libraries.find(plugName);
+ if( it != libraries.end() ) {
+ delete it->second;
+ libraries.erase(it);
+ return true;
+ }
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void PluginManager::unloadAll(){
+
+ host.clearProviders();
+ LibMap::iterator it;
+ for (it = libraries.begin() ; it != libraries.end() ; ++it){
+ delete it->second;
+ }
+ libraries.clear();
+}
+
+
+////////////////////////////////////////////////////////////
+std::string PluginManager::getPluginName(const std::string& path){
+ size_t lastDash = path.find_last_of("/\\");
+ size_t lastDot = path.find_last_of('.');
+ if (lastDash == std::string::npos) lastDash = 0;
+ else ++lastDash;
+ if (lastDot < lastDash || lastDot == std::string::npos){
+ // path without extension
+ lastDot = path.length();
+ }
+ return path.substr(lastDash, lastDot-lastDash);
+}
+
+
+////////////////////////////////////////////////////////////
+std::string PluginManager::resolvePathExtension(const std::string& path){
+ size_t lastDash = path.find_last_of("/\\");
+ size_t lastDot = path.find_last_of('.');
+ if (lastDash == std::string::npos) lastDash = 0;
+ else ++lastDash;
+ if (lastDot < lastDash || lastDot == std::string::npos){
+ // path without extension, add it
+ return path + "." + PLUMA_LIB_EXTENSION;
+ }
+ return path;
+}
+
+
+////////////////////////////////////////////////////////////
+void PluginManager::registerType(const std::string& type, unsigned int version, unsigned int lowestVersion){
+ host.registerType(type, version, lowestVersion);
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::addProvider(Provider* provider){
+ if (provider == NULL){
+ fprintf(stderr, "Trying to add null provider\n");
+ return false;
+ }
+ return host.registerProvider(provider);
+}
+
+
+////////////////////////////////////////////////////////////
+void PluginManager::getLoadedPlugins(std::vector<const std::string*>& pluginNames) const{
+ pluginNames.reserve(pluginNames.size()+libraries.size());
+ LibMap::const_iterator it;
+ for(it = libraries.begin() ; it != libraries.end() ; ++it){
+ pluginNames.push_back(&(it->first));
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool PluginManager::isLoaded(const std::string& pluginName) const{
+ return libraries.find(getPluginName(pluginName)) != libraries.end();
+}
+
+
+////////////////////////////////////////////////////////////
+const std::list<Provider*>* PluginManager::getProviders(const std::string& type) const{
+ return host.getProviders(type);
+}
+
+
+
+} // namespace pluma
+
diff --git a/src/uscxml/plugins/Pluma/PluginManager.hpp b/src/uscxml/plugins/Pluma/PluginManager.hpp new file mode 100755 index 0000000..e5ddf06 --- /dev/null +++ b/src/uscxml/plugins/Pluma/PluginManager.hpp @@ -0,0 +1,245 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_PLUGIN_MANAGER_HPP
+#define PLUMA_PLUGIN_MANAGER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Host.hpp>
+
+#include <string>
+#include <map>
+
+namespace pluma{
+class DLibrary;
+
+////////////////////////////////////////////////////////////
+/// \brief Manages loaded plugins.
+///
+////////////////////////////////////////////////////////////
+class PLUMA_API PluginManager{
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ ////////////////////////////////////////////////////////////
+ ~PluginManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load a plugin given it's path
+ ///
+ /// \param path Path for the plugin, including plugin name. File extension
+ /// may be included, but is discouraged for better cross platform code.
+ /// If file extension isn't present on the path, Pluma will deduce it
+ /// from the operating system.
+ ///
+ /// \return True if the plugin is successfully loaded.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see loadFromFolder
+ /// \see unload
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ bool load(const std::string& path);
+
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load a plugin from a given folder
+ ///
+ /// \param folder The folder path.
+ /// \param pluginName Name of the plugin. File extension
+ /// may be included, but is discouraged for better cross platform code.
+ /// If file extension is omitted, Pluma will deduce it
+ /// from the operating system.
+ ///
+ /// \return True if the plugin is successfully loaded.
+ ///
+ /// \see load(const std::string&)
+ /// \see loadFromFolder
+ /// \see unload
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ bool load(const std::string& folder, const std::string& pluginName);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Load all plugins from a given folder
+ ///
+ /// \param folder Path for the folder where the plug-ins are.
+ /// \param recursive If true it will search on sub-folders as well
+ ///
+ /// \return Number of successfully loaded plug-ins.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see unload
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ int loadFromFolder(const std::string& folder, bool recursive = false);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Unload a plugin.
+ ///
+ /// \param pluginName Name or path of the plugin.
+ ///
+ /// \return True if the plugin is successfully unloaded,
+ /// false if no such plugin exists on the manager.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see loadFromFolder
+ /// \see unloadAll
+ ///
+ ////////////////////////////////////////////////////////////
+ bool unload(const std::string& pluginName);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Unload all loaded plugins.
+ ///
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see loadFromFolder
+ /// \see unload
+ ///
+ ////////////////////////////////////////////////////////////
+ void unloadAll();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Directly add a new provider.
+ ///
+ /// \param provider Provider.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool addProvider(Provider* provider);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the name of all loaded plugins.
+ ///
+ /// \param pluginNames A vector to fill with the plugins names.
+ ///
+ ////////////////////////////////////////////////////////////
+ void getLoadedPlugins(std::vector<const std::string*>& pluginNames) const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a plug-in is loaded.
+ ///
+ /// \param pluginName the plug-in tname o check.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool isLoaded(const std::string& pluginName) const;
+
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Default constructor.
+ ///
+ /// PluginManager cannot be publicly instantiated.
+ ///
+ ////////////////////////////////////////////////////////////
+ PluginManager();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Register a provider type
+ ///
+ /// \param type Provider type.
+ /// \param version Current version of that provider type.
+ /// \param lowestVersion Lowest compatible version of that provider type.
+ ///
+ /// \see Host::registerType
+ ///
+ ////////////////////////////////////////////////////////////
+ void registerType(const std::string& type, unsigned int version, unsigned int lowestVersion);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get providers of a certain type.
+ ///
+ /// \param type Provider type.
+ ///
+ /// \return Pointer to the list of providers of that \a type,
+ /// or NULL if \a type is not registered.
+ ///
+ /// \see Host::getProviders
+ ///
+ ////////////////////////////////////////////////////////////
+ const std::list<Provider*>* getProviders(const std::string& type) const;
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the plugin name (without extension) from its path
+ ///
+ /// \param path Plugin path.
+ ///
+ /// \return Name of the plugin.
+ ///
+ /// \see resolvePathExtension
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see unload
+ ///
+ ////////////////////////////////////////////////////////////
+ static std::string getPluginName(const std::string& path);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief If the plugin path omits it's extension, this method returns
+ /// the path plus the OS specific dll extension.
+ /// Return a copy of the path otherwise.
+ ///
+ /// \param path Plugin path.
+ ///
+ /// \return Path with extension.
+ ///
+ /// \see getPluginName
+ /// \see load(const std::string&, const std::string&)
+ /// \see load(const std::string&)
+ /// \see unload
+ ///
+ ////////////////////////////////////////////////////////////
+ static std::string resolvePathExtension(const std::string& path);
+
+
+private:
+
+ /// Signature for the plugin's registration function
+ typedef bool fnRegisterPlugin(Host&);
+ typedef std::map<std::string,DLibrary*> LibMap;
+
+ LibMap libraries; ///< Map containing the loaded libraries
+ Host host; ///< Host app proxy, holding all providers
+
+};
+
+} // namespace pluma
+
+#endif // PLUMA_PLUGIN_MANAGER_HPP
diff --git a/src/uscxml/plugins/Pluma/Pluma.hpp b/src/uscxml/plugins/Pluma/Pluma.hpp new file mode 100755 index 0000000..a9d614e --- /dev/null +++ b/src/uscxml/plugins/Pluma/Pluma.hpp @@ -0,0 +1,171 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_PLUMA_HPP
+#define PLUMA_PLUMA_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <Pluma/Provider.hpp>
+#include <Pluma/PluginManager.hpp>
+
+////////////////////////////////////////////////////////////
+// Andy macro to convert parameter to string
+////////////////////////////////////////////////////////////
+#define PLUMA_2STRING(X) #X
+
+////////////////////////////////////////////////////////////
+// Macro that helps host applications defining
+// their provider classes
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_HEADER(TYPE)\
+PLUMA_PROVIDER_HEADER_BEGIN(TYPE)\
+virtual TYPE* create() const = 0;\
+PLUMA_PROVIDER_HEADER_END
+
+////////////////////////////////////////////////////////////
+// Macro that generate first part of the provider definition
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_HEADER_BEGIN(TYPE)\
+class TYPE##Provider: public pluma::Provider{\
+private:\
+ friend class pluma::Pluma;\
+ static const unsigned int PLUMA_INTERFACE_VERSION;\
+ static const unsigned int PLUMA_INTERFACE_LOWEST_VERSION;\
+ static const std::string PLUMA_PROVIDER_TYPE;\
+ std::string plumaGetType() const{ return PLUMA_PROVIDER_TYPE; }\
+public:\
+ unsigned int getVersion() const{ return PLUMA_INTERFACE_VERSION; }
+
+////////////////////////////////////////////////////////////
+// Macro that generate last part of the provider definition
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_HEADER_END };
+
+////////////////////////////////////////////////////////////
+// Macro that generate the provider declaration
+////////////////////////////////////////////////////////////
+#define PLUMA_PROVIDER_SOURCE(TYPE, Version, LowestVersion)\
+const std::string TYPE##Provider::PLUMA_PROVIDER_TYPE = PLUMA_2STRING( TYPE );\
+const unsigned int TYPE##Provider::PLUMA_INTERFACE_VERSION = Version;\
+const unsigned int TYPE##Provider::PLUMA_INTERFACE_LOWEST_VERSION = LowestVersion;
+
+
+////////////////////////////////////////////////////////////
+// Macro that helps plugins generating their provider implementations
+// PRE: SPECIALIZED_TYPE must inherit from BASE_TYPE
+////////////////////////////////////////////////////////////
+#define PLUMA_INHERIT_PROVIDER(SPECIALIZED_TYPE, BASE_TYPE)\
+class SPECIALIZED_TYPE##Provider: public BASE_TYPE##Provider{\
+public:\
+ BASE_TYPE * create() const{ return new SPECIALIZED_TYPE (); }\
+};
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+/// \brief Pluma plugins management
+///
+////////////////////////////////////////////////////////////
+class Pluma: public PluginManager{
+
+public:
+ ////////////////////////////////////////////////////////////
+ /// \brief Default Constructor
+ ///
+ ////////////////////////////////////////////////////////////
+ Pluma();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Tell Pluma to accept a certain type of providers
+ ///
+ /// A Pluma object is able to accept multiple types of providers.
+ /// When a plugin is loaded, it tries to register it's providers
+ /// implementations. Those are only accepted by the host
+ /// application if it's accepting providers of that kind.
+ ///
+ /// \tparam ProviderType type of provider.
+ ///
+ ////////////////////////////////////////////////////////////
+ template<typename ProviderType>
+ void acceptProviderType();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the stored providers of a certain type.
+ ///
+ /// Providers are added at the end of the \a providers vector.
+ ///
+ /// \tparam ProviderType type of provider to be returned.
+ /// \param[out] providers Vector to fill with the existing
+ /// providers.
+ ///
+ ////////////////////////////////////////////////////////////
+ template<typename ProviderType>
+ void getProviders(std::vector<ProviderType*>& providers);
+};
+
+#include <Pluma/Pluma.inl>
+
+}
+
+
+#endif // PLUMA_PLUMA_HPP
+
+
+////////////////////////////////////////////////////////////
+/// \class pluma::Pluma
+///
+/// Pluma is the main class of Pluma library. Allows hosting
+/// applications to load/unload dlls in runtime (plugins), and
+/// to get providers of shared interface objects.
+///
+/// Example:
+/// \code
+/// pluma::Pluma pluma;
+/// // Tell it to accept providers of the type DeviceProvider
+/// pluma.acceptProviderType<DeviceProvider>();
+/// // Load some dll
+/// pluma.load("plugins/standard_devices");
+/// // Get device providers into a vector
+/// std::vector<DeviceProvider*> providers;
+/// pluma.getProviders(providers);
+/// // create a Device from the first provider
+/// if (!providers.empty()){
+/// Device* myDevice = providers.first()->create();
+/// // do something with myDevice
+/// std::cout << device->getDescription() << std::endl;
+/// // (...)
+/// delete myDevice;
+/// }
+/// \endcode
+///
+/// It is also possible to add local providers, providers that
+/// are defined directly on the host application. That can
+/// be useful to provide and use default implementations of certain
+/// interfaces, along with plugin implementations.
+///
+////////////////////////////////////////////////////////////
diff --git a/src/uscxml/plugins/Pluma/Pluma.inl b/src/uscxml/plugins/Pluma/Pluma.inl new file mode 100755 index 0000000..c3b6ce7 --- /dev/null +++ b/src/uscxml/plugins/Pluma/Pluma.inl @@ -0,0 +1,52 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+inline Pluma::Pluma(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+template<typename ProviderType>
+void Pluma::acceptProviderType(){
+ PluginManager::registerType(
+ ProviderType::PLUMA_PROVIDER_TYPE,
+ ProviderType::PLUMA_INTERFACE_VERSION,
+ ProviderType::PLUMA_INTERFACE_LOWEST_VERSION
+ );
+}
+
+
+////////////////////////////////////////////////////////////
+template<typename ProviderType>
+void Pluma::getProviders(std::vector<ProviderType*>& providers){
+ const std::list<Provider*>* lst = PluginManager::getProviders(ProviderType::PLUMA_PROVIDER_TYPE);
+ if (!lst) return;
+ providers.reserve(providers.size() + lst->size());
+ std::list<Provider*>::const_iterator it;
+ for (it = lst->begin() ; it != lst->end() ; ++it)
+ providers.push_back(static_cast<ProviderType*>(*it));
+}
diff --git a/src/uscxml/plugins/Pluma/Provider.cpp b/src/uscxml/plugins/Pluma/Provider.cpp new file mode 100755 index 0000000..36d4da3 --- /dev/null +++ b/src/uscxml/plugins/Pluma/Provider.cpp @@ -0,0 +1,52 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Provider.hpp>
+#include <Pluma/Host.hpp>
+
+
+namespace pluma{
+
+////////////////////////////////////////////////////////////
+Provider::~Provider(){
+ // Nothing to do
+}
+
+
+////////////////////////////////////////////////////////////
+bool Provider::isCompatible(const Host& host) const{
+ // check compatibility with host
+ const std::string& type = this->plumaGetType();
+ if (!host.knows(type)) return false;
+ unsigned int lowest = host.getLowestVersion(type);
+ unsigned int current = host.getVersion(type);
+ unsigned int myVersion = this->getVersion();
+ return lowest <= myVersion && myVersion <= current;
+}
+
+} // namespace pluma
diff --git a/src/uscxml/plugins/Pluma/Provider.hpp b/src/uscxml/plugins/Pluma/Provider.hpp new file mode 100755 index 0000000..ea06497 --- /dev/null +++ b/src/uscxml/plugins/Pluma/Provider.hpp @@ -0,0 +1,204 @@ +////////////////////////////////////////////////////////////
+//
+// Pluma - Plug-in Management Framework
+// Copyright (C) 2010-2012 Gil Costa (gsaurus@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef PLUMA_PROVIDER_HPP
+#define PLUMA_PROVIDER_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <Pluma/Config.hpp>
+#include <string>
+
+
+namespace pluma{
+class Host;
+
+////////////////////////////////////////////////////////////
+/// \brief Interface to provide applications with objects from plugins.
+///
+////////////////////////////////////////////////////////////
+class PLUMA_API Provider{
+friend class Host;
+
+
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor.
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual ~Provider();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get provider version.
+ ///
+ /// \return Version number.
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual unsigned int getVersion() const = 0;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check compatibility with host.
+ ///
+ /// The same provider may be compiled with different versions
+ /// on host side and on plugins side. This function checks if
+ /// a plugin provider is compatible with the current version of
+ /// the same provider type on the host side.
+ ///
+ /// \param host Host, proxy of host application.
+ ///
+ /// \return True if it's compatible with \a host.
+ ///
+ ////////////////////////////////////////////////////////////
+ bool isCompatible(const Host& host) const;
+
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get provider type.
+ ///
+ /// Each provider defined on the host application is identified by
+ /// a unique type. Those types are automatically managed internally by
+ /// pluma.
+ ///
+ /// \return Provider type id.
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual std::string plumaGetType() const = 0;
+
+};
+
+} // namespace pluma
+
+
+#endif // PLUMA_PROVIDER_HPP
+
+
+////////////////////////////////////////////////////////////
+/// \class pluma::Provider
+/// The plugin specific implementations are unknown at the host side,
+/// only their shared interfaces are known. Then, host app needs a generic
+/// way of create interface objects. That's what provider classes are for.
+/// It is the factory design pattern
+/// (http://www.oodesign.com/factory-pattern.html)
+///
+/// Shared interfaces define their provider types (by inheriting from
+/// pluma::Provider). Hosts then use those tipes to get objects from the
+/// plugins.
+/// Plugins derive the shared interface providers so that they can provide
+/// host with specific implementations of the shared interface.
+/// Those specific providers are given to the host through a connect function.
+///
+///
+/// Example: A host app uses objects of type Device. A certain plugin
+/// defines a Keyboard, witch is a Device.
+/// The Host will use DeviceProviders to create objects of type Device.
+/// The plugin will provide host specifically with a KeyboardProvider.
+/// Other plugins may provide host with other derived DeviceProvider types.
+///
+/// Device hpp (shared):
+/// \code
+/// #include <Pluma/Pluma.hpp>
+/// class Device{
+/// public:
+/// virtual std::string getDescription() const = 0;
+/// };
+/// // create DevicedProvider class
+/// PLUMA_PROVIDER_HEADER(Device);
+/// \endcode
+///
+/// Device cpp (shared):
+/// \code
+/// #include "Device.hpp"
+/// generate DevicedProvider with version 6, and compatible with at least v.3
+/// PLUMA_PROVIDER_SOURCE(Device, 6, 3);
+/// \endcode
+///
+///
+/// <br>
+/// Keyboard code on the plugin side:
+/// \code
+/// #include <Pluma/Pluma.hpp>
+/// #include "Device.hpp"
+///
+/// class Keyboard: public Device{
+/// public:
+/// std::string getDescription() const{
+/// return "keyboard";
+/// }
+/// };
+///
+/// // create KeyboardProvider, it implements DeviceProvider
+/// PLUMA_INHERIT_PROVIDER(Keyboard, Device);
+/// \endcode
+///
+/// plugin connector:
+/// \code
+/// #include <Pluma/Connector.hpp>
+/// #include "Keyboard.hpp"
+///
+/// PLUMA_CONNECTOR
+/// bool connect(pluma::Host& host){
+/// // add a keyboard provider to host
+/// host.add( new KeyboardProvider() );
+/// return true;
+/// }
+/// \endcode
+///
+///
+/// Host application code:
+/// \code
+/// #include <Pluma/Pluma.hpp>
+///
+/// #include "Device.hpp"
+/// #include <iostream>
+/// #include <vector>
+///
+/// int main(){
+///
+/// pluma::Pluma plugins;
+/// // Tell plugins manager to accept providers of the type DeviceProvider
+/// plugins.acceptProviderType<DeviceProvider>();
+/// // Load library "standard_devices" from folder "plugins"
+/// plugins.load("plugins", "standard_devices");
+///
+/// // Get device providers into a vector
+/// std::vector<DeviceProvider*> providers;
+/// plugins.getProviders(providers);
+///
+/// // create a Device from the first provider
+/// if (!providers.empty()){
+/// Device* myDevice = providers.first()->create();
+/// // do something with myDevice
+/// std::cout << device->getDescription() << std::endl;
+/// // and delete it in the end
+/// delete myDevice;
+/// }
+/// return 0;
+/// }
+/// \endcode
+///
+////////////////////////////////////////////////////////////
diff --git a/src/uscxml/plugins/Pluma/uce-dirent.h b/src/uscxml/plugins/Pluma/uce-dirent.h new file mode 100755 index 0000000..ecf78eb --- /dev/null +++ b/src/uscxml/plugins/Pluma/uce-dirent.h @@ -0,0 +1,679 @@ +/* + * uce-dirent.h - operating system independent dirent implementation + * + * Copyright (C) 1998-2002 Toni Ronkko + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * ``Software''), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * May 28 1998, Toni Ronkko <tronkko@messi.uku.fi> + * + * $Id: uce-dirent.h,v 1.7 2002/05/13 10:48:35 tr Exp $ + * + * $Log: uce-dirent.h,v $ + * Revision 1.7 2002/05/13 10:48:35 tr + * embedded some source code directly to the header so that no source + * modules need to be included in the MS Visual C project using the + * interface, removed all the dependencies to other headers of the `uce' + * library so that the header can be made public + * + * Revision 1.6 2002/04/12 16:22:04 tr + * Unified Compiling Environment (UCE) replaced `std' library + * + * Revision 1.5 2001/07/20 16:33:40 tr + * moved to `std' library and re-named defines accordingly + * + * Revision 1.4 2001/07/10 16:47:18 tronkko + * revised comments + * + * Revision 1.3 2001/01/11 13:16:43 tr + * using ``uce-machine.h'' for finding out defines such as `FREEBSD' + * + * Revision 1.2 2000/10/08 16:00:41 tr + * copy of FreeBSD man page + * + * Revision 1.1 2000/07/10 05:53:16 tr + * Initial revision + * + * Revision 1.2 1998/07/19 18:29:14 tr + * Added error reporting capabilities and some asserts. + * + * Revision 1.1 1998/07/04 16:27:51 tr + * Initial revision + * + * + * MSVC 1.0 scans automatic dependencies incorrectly when your project + * contains this very header. The problem is that MSVC cannot handle + * include directives inside #if..#endif block those are never entered. + * Since this header ought to compile in many different operating systems, + * there had to be several conditional blocks that are compiled only in + * operating systems for what they were designed for. MSVC 1.0 cannot + * handle inclusion of sys/dir.h in a part that is compiled only in Apollo + * operating system. To fix the problem you need to insert DIR.H into + * SYSINCL.DAT located in MSVC\BIN directory and restart visual C++. + * Consult manuals for more informaton about the problem. + * + * Since many UNIX systems have dirent.h we assume to have one also. + * However, if your UNIX system does not have dirent.h you can download one + * for example at: http://ftp.uni-mannheim.de/ftp/GNU/dirent/dirent.tar.gz. + * You can also see if you have one of dirent.h, direct.h, dir.h, ndir.h, + * sys/dir.h and sys/ndir.h somewhere. Try defining HAVE_DIRENT_H, + * HAVE_DIRECT_H, HAVE_DIR_H, HAVE_NDIR_H, HAVE_SYS_DIR_H and + * HAVE_SYS_NDIR_H according to the files found. + */ +#ifndef DIRENT_H +#define DIRENT_H +#define DIRENT_H_INCLUDED + +/* find out platform */ +#if defined(MSDOS) /* MS-DOS */ +#elif defined(__MSDOS__) /* Turbo C/Borland */ +# define MSDOS +#elif defined(__DOS__) /* Watcom */ +# define MSDOS +#endif + +#if defined(WIN32) /* MS-Windows */ +#elif defined(__NT__) /* Watcom */ +# define WIN32 +#elif defined(_WIN32) /* Microsoft */ +# define WIN32 +#elif defined(__WIN32__) /* Borland */ +# define WIN32 +#endif + +/* + * See what kind of dirent interface we have unless autoconf has already + * determinated that. + */ +#if !defined(HAVE_DIRENT_H) && !defined(HAVE_DIRECT_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_NDIR_H) && !defined(HAVE_DIR_H) +# if defined(_MSC_VER) /* Microsoft C/C++ */ + /* no dirent.h */ +# elif defined(__BORLANDC__) /* Borland C/C++ */ +# define HAVE_DIRENT_H +# define VOID_CLOSEDIR +# elif defined(__TURBOC__) /* Borland Turbo C */ + /* no dirent.h */ +# elif defined(__WATCOMC__) /* Watcom C/C++ */ +# define HAVE_DIRECT_H +# elif defined(__apollo) /* Apollo */ +# define HAVE_SYS_DIR_H +# elif defined(__hpux) /* HP-UX */ +# define HAVE_DIRENT_H +# elif defined(__alpha) || defined(__alpha__) /* Alpha OSF1 */ +# error "not implemented" +# elif defined(__sgi) /* Silicon Graphics */ +# define HAVE_DIRENT_H +# elif defined(sun) || defined(_sun) /* Sun Solaris */ +# define HAVE_DIRENT_H +# elif defined(__FreeBSD__) /* FreeBSD */ +# define HAVE_DIRENT_H +# elif defined(__linux__) /* Linux */ +# define HAVE_DIRENT_H +# elif defined(__GNUC__) /* GNU C/C++ */ +# define HAVE_DIRENT_H +# else +# error "not implemented" +# endif +#endif + +/* include proper interface headers */ +#if defined(HAVE_DIRENT_H) +# include <dirent.h> +# ifdef FREEBSD +# define NAMLEN(dp) ((int)((dp)->d_namlen)) +# else +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) +# endif + +#elif defined(HAVE_NDIR_H) +# include <ndir.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_NDIR_H) +# include <sys/ndir.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIRECT_H) +# include <direct.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIR_H) +# include <dir.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_DIR_H) +# include <sys/types.h> +# include <sys/dir.h> +# ifndef dirent +# define dirent direct +# endif +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(MSDOS) || defined(WIN32) + + /* figure out type of underlaying directory interface to be used */ +# if defined(WIN32) +# define DIRENT_WIN32_INTERFACE +# elif defined(MSDOS) +# define DIRENT_MSDOS_INTERFACE +# else +# error "missing native dirent interface" +# endif + + /*** WIN32 specifics ***/ +# if defined(DIRENT_WIN32_INTERFACE) +# include <windows.h> +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (MAX_PATH) +# endif + + + /*** MS-DOS specifics ***/ +# elif defined(DIRENT_MSDOS_INTERFACE) +# include <dos.h> + + /* Borland defines file length macros in dir.h */ +# if defined(__BORLANDC__) +# include <dir.h> +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# if !defined(_find_t) +# define _find_t find_t +# endif + + /* Turbo C defines ffblk structure in dir.h */ +# elif defined(__TURBOC__) +# include <dir.h> +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# define DIRENT_USE_FFBLK + + /* MSVC */ +# elif defined(_MSC_VER) +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (12) +# endif + + /* Watcom */ +# elif defined(__WATCOMC__) +# if !defined(DIRENT_MAXNAMLEN) +# if defined(__OS2__) || defined(__NT__) +# define DIRENT_MAXNAMLEN (255) +# else +# define DIRENT_MAXNAMLEN (12) +# endif +# endif + +# endif +# endif + + /*** generic MS-DOS and MS-Windows stuff ***/ +# if !defined(NAME_MAX) && defined(DIRENT_MAXNAMLEN) +# define NAME_MAX DIRENT_MAXNAMLEN +# endif +# if NAME_MAX < DIRENT_MAXNAMLEN +# error "assertion failed: NAME_MAX >= DIRENT_MAXNAMLEN" +# endif + + + /* + * Substitute for real dirent structure. Note that `d_name' field is a + * true character array although we have it copied in the implementation + * dependent data. We could save some memory if we had declared `d_name' + * as a pointer refering the name within implementation dependent data. + * We have not done that since some code may rely on sizeof(d_name) to be + * something other than four. Besides, directory entries are typically so + * small that it takes virtually no time to copy them from place to place. + */ + typedef struct dirent { + char d_name[NAME_MAX + 1]; + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) /*WIN32*/ + WIN32_FIND_DATA data; +# elif defined(DIRENT_MSDOS_INTERFACE) /*MSDOS*/ +# if defined(DIRENT_USE_FFBLK) + struct ffblk data; +# else + struct _find_t data; +# endif +# endif + } dirent; + + /* DIR substitute structure containing directory name. The name is + * essential for the operation of ``rewinndir'' function. */ + typedef struct DIR { + char *dirname; /* directory being scanned */ + dirent current; /* current entry */ + int dirent_filled; /* is current un-processed? */ + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) + HANDLE search_handle; +# elif defined(DIRENT_MSDOS_INTERFACE) +# endif + } DIR; + +# ifdef __cplusplus +extern "C" { +# endif + +/* supply prototypes for dirent functions */ +static DIR *opendir (const char *dirname); +static struct dirent *readdir (DIR *dirp); +static int closedir (DIR *dirp); +static void rewinddir (DIR *dirp); + +/* + * Implement dirent interface as static functions so that the user does not + * need to change his project in any way to use dirent function. With this + * it is sufficient to include this very header from source modules using + * dirent functions and the functions will be pulled in automatically. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +/* use ffblk instead of _find_t if requested */ +#if defined(DIRENT_USE_FFBLK) +# define _A_ARCH (FA_ARCH) +# define _A_HIDDEN (FA_HIDDEN) +# define _A_NORMAL (0) +# define _A_RDONLY (FA_RDONLY) +# define _A_SUBDIR (FA_DIREC) +# define _A_SYSTEM (FA_SYSTEM) +# define _A_VOLID (FA_LABEL) +# define _dos_findnext(dest) findnext(dest) +# define _dos_findfirst(name,flags,dest) findfirst(name,dest,flags) +#endif + +static int _initdir (DIR *p); +static const char *_getdirname (const struct dirent *dp); +static void _setdirname (struct DIR *dirp); + +/* + * <function name="opendir"> + * <intro>open directory stream for reading + * <syntax>DIR *opendir (const char *dirname); + * + * <desc>Open named directory stream for read and return pointer to the + * internal working area that is used for retrieving individual directory + * entries. The internal working area has no fields of your interest. + * + * <ret>Returns a pointer to the internal working area or NULL in case the + * directory stream could not be opened. Global `errno' variable will set + * in case of error as follows: + * + * <table> + * [EACESS |Permission denied. + * [EMFILE |Too many open files used by the process. + * [ENFILE |Too many open files in system. + * [ENOENT |Directory does not exist. + * [ENOMEM |Insufficient memory. + * [ENOTDIR |dirname does not refer to directory. This value is not + * reliable on MS-DOS and MS-Windows platforms. Many + * implementations return ENOENT even when the name refers to a + * file.] + * </table> + * </function> + */ +static DIR * +opendir( + const char *dirname) +{ + DIR *dirp; + assert (dirname != NULL); + + dirp = (DIR*)malloc (sizeof (struct DIR)); + if (dirp != NULL) { + char *p; + + /* allocate room for directory name */ + dirp->dirname = (char*) malloc (strlen (dirname) + 1 + strlen ("\\*.*")); + if (dirp->dirname == NULL) { + /* failed to duplicate directory name. errno set by malloc() */ + free (dirp); + return NULL; + } + /* Copy directory name while appending directory separator and "*.*". + * Directory separator is not appended if the name already ends with + * drive or directory separator. Directory separator is assumed to be + * '/' or '\' and drive separator is assumed to be ':'. */ + strcpy (dirp->dirname, dirname); + p = strchr (dirp->dirname, '\0'); + if (dirp->dirname < p && + *(p - 1) != '\\' && *(p - 1) != '/' && *(p - 1) != ':') + { + strcpy (p++, "/"); + } +# ifdef DIRENT_WIN32_INTERFACE + strcpy (p, "*"); /*scan files with and without extension in win32*/ +# else + strcpy (p, "*.*"); /*scan files with and without extension in DOS*/ +# endif + + /* open stream */ + if (_initdir (dirp) == 0) { + /* initialization failed */ + free (dirp->dirname); + free (dirp); + return NULL; + } + } + return dirp; +} + + +/* + * <function name="readdir"> + * <intro>read a directory entry + * <syntax>struct dirent *readdir (DIR *dirp); + * + * <desc>Read individual directory entry and return pointer to a structure + * containing the name of the entry. Individual directory entries returned + * include normal files, sub-directories, pseudo-directories "." and ".." + * and also volume labels, hidden files and system files in MS-DOS and + * MS-Windows. You might want to use stat(2) function to determinate which + * one are you dealing with. Many dirent implementations already contain + * equivalent information in dirent structure but you cannot depend on + * this. + * + * The dirent structure contains several system dependent fields that + * generally have no interest to you. The only interesting one is char + * d_name[] that is also portable across different systems. The d_name + * field contains the name of the directory entry without leading path. + * While d_name is portable across different systems the actual storage + * capacity of d_name varies from system to system and there is no portable + * way to find out it at compile time as different systems define the + * capacity of d_name with different macros and some systems do not define + * capacity at all (besides actual declaration of the field). If you really + * need to find out storage capacity of d_name then you might want to try + * NAME_MAX macro. The NAME_MAX is defined in POSIX standard althought + * there are many MS-DOS and MS-Windows implementations those do not define + * it. There are also systems that declare d_name as "char d_name[1]" and + * then allocate suitable amount of memory at run-time. Thanks to Alain + * Decamps (Alain.Decamps@advalvas.be) for pointing it out to me. + * + * This all leads to the fact that it is difficult to allocate space + * for the directory names when the very same program is being compiled on + * number of operating systems. Therefore I suggest that you always + * allocate space for directory names dynamically. + * + * <ret> + * Returns a pointer to a structure containing name of the directory entry + * in `d_name' field or NULL if there was an error. In case of an error the + * global `errno' variable will set as follows: + * + * <table> + * [EBADF |dir parameter refers to an invalid directory stream. This value + * is not set reliably on all implementations.] + * </table> + * </function> + */ +static struct dirent * +readdir (DIR *dirp) +{ + assert (dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return NULL; + } + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* directory stream was opened/rewound incorrectly or it ended normally */ + errno = EBADF; + return NULL; + } +#endif + + if (dirp->dirent_filled != 0) { + /* + * Directory entry has already been retrieved and there is no need to + * retrieve a new one. Directory entry will be retrieved in advance + * when the user calls readdir function for the first time. This is so + * because real dirent has separate functions for opening and reading + * the stream whereas Win32 and DOS dirents open the stream + * automatically when we retrieve the first file. Therefore, we have to + * save the first file when opening the stream and later we have to + * return the saved entry when the user tries to read the first entry. + */ + dirp->dirent_filled = 0; + } else { + /* fill in entry and return that */ +#if defined(DIRENT_WIN32_INTERFACE) + if (FindNextFile (dirp->search_handle, &dirp->current.data) == FALSE) { + /* Last file has been processed or an error occured */ + FindClose (dirp->search_handle); + dirp->search_handle = INVALID_HANDLE_VALUE; + errno = ENOENT; + return NULL; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findnext (&dirp->current.data) != 0) { + /* _dos_findnext and findnext will set errno to ENOENT when no + * more entries could be retrieved. */ + return NULL; + } +# endif + + _setdirname (dirp); + assert (dirp->dirent_filled == 0); + } + return &dirp->current; +} + + +/* + * <function name="closedir"> + * <intro>close directory stream. + * <syntax>int closedir (DIR *dirp); + * + * <desc>Close directory stream opened by the `opendir' function. Close of + * directory stream invalidates the DIR structure as well as previously read + * dirent entry. + * + * <ret>The function typically returns 0 on success and -1 on failure but + * the function may be declared to return void on same systems. At least + * Borland C/C++ and some UNIX implementations use void as a return type. + * The dirent wrapper tries to define VOID_CLOSEDIR whenever closedir is + * known to return nothing. The very same definition is made by the GNU + * autoconf if you happen to use it. + * + * The global `errno' variable will set to EBADF in case of error. + * </function> + */ +static int +closedir (DIR *dirp) +{ + int retcode = 0; + + /* make sure that dirp points to legal structure */ + assert (dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return -1; + } + + /* free directory name and search handles */ + if (dirp->dirname != NULL) free (dirp->dirname); + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose (dirp->search_handle) == FALSE) { + /* Unknown error */ + retcode = -1; + errno = EBADF; + } + } +#endif + + /* clear dirp structure to make sure that it cannot be used anymore*/ + memset (dirp, 0, sizeof (*dirp)); +# if defined(DIRENT_WIN32_INTERFACE) + dirp->search_handle = INVALID_HANDLE_VALUE; +# endif + + free (dirp); + return retcode; +} + + +/* + * <function name="rewinddir"> + * <intro>rewind directory stream to the beginning + * <syntax>void rewinddir (DIR *dirp); + * + * <desc>Rewind directory stream to the beginning so that the next call of + * readdir() returns the very first directory entry again. However, note + * that next call of readdir() may not return the same directory entry as it + * did in first time. The directory stream may have been affected by newly + * created files. + * + * Almost every dirent implementation ensure that rewinddir will update + * the directory stream to reflect any changes made to the directory entries + * since the previous ``opendir'' or ``rewinddir'' call. Keep an eye on + * this if your program depends on the feature. I know at least one dirent + * implementation where you are required to close and re-open the stream to + * see the changes. + * + * <ret>Returns nothing. If something went wrong while rewinding, you will + * notice it later when you try to retrieve the first directory entry. + */ +static void +rewinddir (DIR *dirp) +{ + /* make sure that dirp is legal */ + assert (dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return; + } + assert (dirp->dirname != NULL); + + /* close previous stream */ +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose (dirp->search_handle) == FALSE) { + /* Unknown error */ + errno = EBADF; + } + } +#endif + + /* re-open previous stream */ + if (_initdir (dirp) == 0) { + /* initialization failed but we cannot deal with error. User will notice + * error later when she tries to retrieve first directory enty. */ + /*EMPTY*/; + } +} + + +/* + * Open native directory stream object and retrieve first file. + * Be sure to close previous stream before opening new one. + */ +static int +_initdir (DIR *dirp) +{ + assert (dirp != NULL); + assert (dirp->dirname != NULL); + dirp->dirent_filled = 0; + +# if defined(DIRENT_WIN32_INTERFACE) + /* Open stream and retrieve first file */ + dirp->search_handle = FindFirstFile (dirp->dirname, &dirp->current.data); + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* something went wrong but we don't know what. GetLastError() could + * give us more information about the error, but then we should map + * the error code into errno. */ + errno = ENOENT; + return 0; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findfirst (dirp->dirname, + _A_SUBDIR | _A_RDONLY | _A_ARCH | _A_SYSTEM | _A_HIDDEN, + &dirp->current.data) != 0) + { + /* _dos_findfirst and findfirst will set errno to ENOENT when no + * more entries could be retrieved. */ + return 0; + } +# endif + + /* initialize DIR and it's first entry */ + _setdirname (dirp); + dirp->dirent_filled = 1; + return 1; +} + + +/* + * Return implementation dependent name of the current directory entry. + */ +static const char * +_getdirname (const struct dirent *dp) +{ +#if defined(DIRENT_WIN32_INTERFACE) + return dp->data.cFileName; + +#elif defined(DIRENT_USE_FFBLK) + return dp->data.ff_name; + +#else + return dp->data.name; +#endif +} + + +/* + * Copy name of implementation dependent directory entry to the d_name field. + */ +static void +_setdirname (struct DIR *dirp) { + /* make sure that d_name is long enough */ + assert (strlen (_getdirname (&dirp->current)) <= NAME_MAX); + + strncpy (dirp->current.d_name, + _getdirname (&dirp->current), + NAME_MAX); + dirp->current.d_name[NAME_MAX] = '\0'; /*char d_name[NAME_MAX+1]*/ +} + +# ifdef __cplusplus +} +# endif +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) + +#else +# error "missing dirent interface" +#endif + + +#endif /*DIRENT_H*/ + diff --git a/src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index 7bdc34b..e25ece4 100644 --- a/src/uscxml/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -1,11 +1,23 @@ #include "uscxml/Common.h" -#include "uscxml/datamodel/ecmascript/v8/V8DataModel.h" +#include "V8DataModel.h" #include "dom/V8SCXMLDOM.h" #include "uscxml/Message.h" #include <glog/logging.h> +#ifdef BUILD_AS_PLUGINS +#include <Pluma/Connector.hpp> +#endif + namespace uscxml { +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host){ + host.add( new V8DataModelProvider() ); + return true; +} +#endif + V8DataModel::V8DataModel() { // _contexts.push_back(v8::Context::New()); } diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h new file mode 100644 index 0000000..994ed18 --- /dev/null +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h @@ -0,0 +1,92 @@ +#ifndef V8DATAMODEL_H_KN8TWG0V +#define V8DATAMODEL_H_KN8TWG0V + +#include "uscxml/Interpreter.h" +#include <list> +#include <v8.h> + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + class Event; + class Data; + class V8SCXMLDOM; +} + +namespace uscxml { + +class V8DataModel : public DataModel { +public: + V8DataModel(); + virtual ~V8DataModel(); + virtual DataModel* create(Interpreter* interpreter); + + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("ecmascript"); + return names; + } + + virtual void initialize(); + virtual void setSessionId(const std::string& sessionId); + virtual void setName(const std::string& name); + virtual void setEvent(const Event& event); + + virtual bool validate(const std::string& location, const std::string& schema); + + virtual uint32_t getLength(const std::string& expr); + virtual void pushContext(); + virtual void popContext(); + + virtual void eval(const std::string& expr); + virtual void assign(const std::string& location, const std::string& expr); + virtual void assign(const std::string& location, const Data& data); + + virtual Data getStringAsData(const std::string& content); + virtual Data getValueAsData(const v8::Handle<v8::Value>& value); + + virtual std::string evalAsString(const std::string& expr); + virtual bool evalAsBool(const std::string& expr); + + static v8::Handle<v8::Value> jsGetEventName(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventType(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventSendId(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventOrigin(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventOriginType(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventInvokeId(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + + static v8::Handle<v8::Value> jsIn(const v8::Arguments& args); + static v8::Handle<v8::Value> jsPrint(const v8::Arguments& args); + + +protected: + std::list<v8::Persistent<v8::Context> > _contexts; + Interpreter* _interpreter; + + std::string _sessionId; + std::string _name; + + Event _event; + v8::Persistent<v8::ObjectTemplate> _globalTemplate; + v8::Persistent<v8::ObjectTemplate> _eventTemplate; + + v8::Handle<v8::Value> evalAsValue(const std::string& expr); + virtual v8::Handle<v8::Value> getDataAsValue(const Data& data); + +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(V8DataModel, DataModel); +#endif + +} + +#endif /* end of include guard: V8DATAMODEL_H_KN8TWG0V */ diff --git a/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp index 6452330..6452330 100644 --- a/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp diff --git a/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h index c513e48..c513e48 100644 --- a/src/uscxml/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h diff --git a/src/uscxml/invoker/modality/MMIComponent.cpp b/src/uscxml/plugins/invoker/modality/MMIComponent.cpp index 0655806..0655806 100644 --- a/src/uscxml/invoker/modality/MMIComponent.cpp +++ b/src/uscxml/plugins/invoker/modality/MMIComponent.cpp diff --git a/src/uscxml/invoker/modality/MMIComponent.h b/src/uscxml/plugins/invoker/modality/MMIComponent.h index a83775f..a83775f 100644 --- a/src/uscxml/invoker/modality/MMIComponent.h +++ b/src/uscxml/plugins/invoker/modality/MMIComponent.h diff --git a/src/uscxml/invoker/modality/UmundoComponent.cpp b/src/uscxml/plugins/invoker/modality/UmundoComponent.cpp index 22dd279..22dd279 100644 --- a/src/uscxml/invoker/modality/UmundoComponent.cpp +++ b/src/uscxml/plugins/invoker/modality/UmundoComponent.cpp diff --git a/src/uscxml/invoker/modality/UmundoComponent.h b/src/uscxml/plugins/invoker/modality/UmundoComponent.h index f2c76c4..f2c76c4 100644 --- a/src/uscxml/invoker/modality/UmundoComponent.h +++ b/src/uscxml/plugins/invoker/modality/UmundoComponent.h diff --git a/src/uscxml/invoker/modality/miles/SpatialAudio.cpp b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp index 5e394bd..13091ae 100644 --- a/src/uscxml/invoker/modality/miles/SpatialAudio.cpp +++ b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.cpp @@ -11,7 +11,15 @@ #include <math.h> namespace uscxml { - + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host){ + host.add( new SpatialAudioProvider() ); + return true; +} +#endif + SpatialAudio::SpatialAudio() { _audioDevOpen = false; _audioDev = NULL; diff --git a/src/uscxml/invoker/modality/miles/SpatialAudio.h b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h index f86e2ff..bbbf478 100644 --- a/src/uscxml/invoker/modality/miles/SpatialAudio.h +++ b/src/uscxml/plugins/invoker/modality/miles/SpatialAudio.h @@ -3,7 +3,6 @@ #include <map> -#include "uscxml/Utilities.h" #include "../MMIComponent.h" extern "C" { @@ -22,6 +21,15 @@ public: virtual ~SpatialAudio(); virtual Invoker* create(Interpreter* interpreter); + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("spatial-audio"); + names.insert("audio"); + names.insert("http://www.smartvortex.eu/mmi/spatial-audio"); + names.insert("http://www.smartvortex.eu/mmi/spatial-audio/"); + return names; + } + virtual Data getDataModelVariables(); virtual void send(SendRequest& req); virtual void cancel(const std::string sendId); diff --git a/src/uscxml/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp index 70c2474..0e617b9 100644 --- a/src/uscxml/invoker/scxml/USCXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp @@ -2,8 +2,20 @@ #include "USCXMLInvoker.h" #include "uscxml/Interpreter.h" +#ifdef BUILD_AS_PLUGINS +#include <Pluma/Connector.hpp> +#endif + namespace uscxml { - + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host){ + host.add( new USCXMLInvokerProvider() ); + return true; +} +#endif + USCXMLInvoker::USCXMLInvoker() { } diff --git a/src/uscxml/invoker/scxml/USCXMLInvoker.h b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h index 76657d8..9068a24 100644 --- a/src/uscxml/invoker/scxml/USCXMLInvoker.h +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h @@ -3,6 +3,10 @@ #include "uscxml/Factory.h" +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + namespace uscxml { class Interpreter; @@ -12,7 +16,14 @@ public: USCXMLInvoker(); virtual ~USCXMLInvoker(); virtual Invoker* create(Interpreter* interpreter); - + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("uscxml"); + names.insert("http://www.w3.org/TR/scxml"); + names.insert("http://www.w3.org/TR/scxml/"); + return names; + } + virtual Data getDataModelVariables(); virtual void send(SendRequest& req); virtual void cancel(const std::string sendId); @@ -24,7 +35,11 @@ protected: Interpreter* _invokedInterpreter; Interpreter* _parentInterpreter; }; - + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(USCXMLInvoker, Invoker); +#endif + } #endif /* end of include guard: USCXMLINVOKER_H_OQFA21IO */ diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp new file mode 100644 index 0000000..68ffe5a --- /dev/null +++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp @@ -0,0 +1,487 @@ +#include "uscxml/config.h" +#include "uscxml/Common.h" +#include "UmundoInvoker.h" +#include "uscxml/Interpreter.h" +#include <glog/logging.h> + +#ifdef BUILD_AS_PLUGINS +#include <Pluma/Connector.hpp> +#endif + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host){ + host.add( new UmundoInvokerProvider() ); + return true; +} +#endif + +UmundoInvoker::UmundoInvoker() { +} + +UmundoInvoker::~UmundoInvoker() { + _node.removeSubscriber(_sub); + _node.removePublisher(_pub); +}; + +Invoker* UmundoInvoker::create(Interpreter* interpreter) { + UmundoInvoker* invoker = new UmundoInvoker(); + invoker->_interpreter = interpreter; + return invoker; +} + +Data UmundoInvoker::getDataModelVariables() { + Data data; + return data; +} + +void UmundoInvoker::send(SendRequest& req) { + umundo::Message* msg = new umundo::Message(); + + if (req.name.length() > 0) { + msg->putMeta("event", req.name); + } else { + msg->putMeta("event", "umundo"); + } + + if (req.params.find("type") != req.params.end()) { + // assume JSON in content to transform to protobuf object + if (req.content.length() > 0 && _interpreter->getDataModel() != NULL) { + std::string type = req.params["type"].front(); + const google::protobuf::Message* protoMsg = umundo::PBSerializer::getProto(type); + if (protoMsg == NULL) { + LOG(ERROR) << "No type " << type << " is known, pass a directory with proto .desc files via types param when invoking"; + return; + } + try { + Data data = _interpreter->getDataModel()->getStringAsData(req.content); + google::protobuf::Message* pbMsg = protoMsg->New(); + if (!dataToProtobuf(pbMsg, data)) { + LOG(ERROR) << "Cannot create message from JSON - not sending"; + } else { + // add all s11n properties + if (!_isService) { + _pub.prepareMsg(msg, type, pbMsg); + _pub.send(msg); + } else { + std::map<umundo::ServiceDescription, umundo::ServiceStub*>::iterator svcIter = _svcs.begin(); + while(svcIter != _svcs.end()) { + umundo::ServiceStub* stub = svcIter->second; + Event event; + void* rv = NULL; + stub->callStubMethod(req.name, pbMsg, type, rv, ""); + protobufToData(event, *(const google::protobuf::Message*)rv); + + event.name = _invokeId + ".reply." + req.name; + event.invokeid = _invokeId; + event.origin = msg->getMeta("um.channel"); + event.origintype = "umundo"; + event.type = Event::EXTERNAL; + + _interpreter->receive(event); + svcIter++; + } + } + } + } catch (Event e) { + LOG(ERROR) << "Syntax error when invoking umundo:" << std::endl << e << std::endl; + return; + } + } else { + LOG(ERROR) << "Required JSON object in content" << std::endl; + return; + } + } +} + +void UmundoInvoker::cancel(const std::string sendId) { + assert(false); +} + +void UmundoInvoker::sendToParent(SendRequest& req) { + assert(false); +} + +void UmundoInvoker::invoke(InvokeRequest& req) { + _invokeId = req.invokeid; + + std::string channelName; + std::string serviceName; + + if (req.params.find("channel") != req.params.end()) { + channelName = req.params["channel"].front(); + _isService = false; + } else if (req.params.find("service") != req.params.end()) { + serviceName = req.params["service"].front(); + _isService = true; + } else { + LOG(ERROR) << "Invoking umundo needs a service or a channel param"; + return; + } + + _node = getNode(_interpreter); + + // add types from .proto or .desc files + if (req.params.find("types") != req.params.end()) { + std::list<std::string>::iterator typeIter = req.params["types"].begin(); + while(typeIter != req.params["types"].end()) { + Arabica::io::URI srcURI(*typeIter); + // if (!_interpreter->makeAbsolute(srcURI)) { + // LOG(ERROR) << "Relative URI for types in umundo invoker " << *typeIter << " with no base URI set for interpreter"; + // return; + // } + umundo::PBSerializer::addProto(srcURI.path()); + typeIter++; + } + } + + if (!_isService) { + // use umundo to publish objects on a channel + _pub = umundo::TypedPublisher(channelName); + _sub = umundo::TypedSubscriber(channelName, this); + + _node.addPublisher(_pub); + _node.addSubscriber(_sub); + + } else if (serviceName.length() > 0) { + // use umundo to access services + _svcFilter = umundo::ServiceFilter(serviceName); + _node.connect(&_svcMgr); + _svcMgr.startQuery(_svcFilter, this); + } +} + +void UmundoInvoker::receive(void* object, umundo::Message* msg) { + uscxml::Event event; + if (msg->getMeta().find("event") != msg->getMeta().end()) { + event.name = msg->getMeta("event"); + } else { + event.name = "umundo.rcvd"; + } + + event.invokeid = _invokeId; + event.origin = msg->getMeta("um.channel"); + event.origintype = "umundo"; + event.type = Event::EXTERNAL; + +// if (msg->getMeta().find("um.s11n.type") != msg->getMeta().end()) +// event.compound["class"] = msg->getMeta("um.s11n.type"); + + if (object != NULL) + protobufToData(event, *(const google::protobuf::Message*)object); + + // get meta fields into event + std::map<std::string, std::string>::const_iterator metaIter = msg->getMeta().begin(); + while(metaIter != msg->getMeta().end()) { + if (metaIter->first.substr(0,3).compare("um.") != 0) + event.compound[metaIter->first] = Data(metaIter->second, Data::VERBATIM); + metaIter++; + } + + _interpreter->receive(event); +} + +void UmundoInvoker::added(umundo::ServiceDescription desc) { + LOG(ERROR) << "Service found!"; + + umundo::ServiceStub* stub = new umundo::ServiceStub(desc); + _svcs[desc] = stub; + + Event addedEvent; + addedEvent.invokeid = _invokeId; + addedEvent.origin = desc.getName(); + addedEvent.origintype = "umundo"; + addedEvent.type = Event::EXTERNAL; + addedEvent.name = _invokeId + ".added"; + + std::map<std::string, std::string>::const_iterator propIter = desc.getProperties().begin(); + while(propIter != desc.getProperties().end()) { + addedEvent.compound[propIter->first] = Data(propIter->second, Data::VERBATIM); + propIter++; + } + + _interpreter->receive(addedEvent); +} + +void UmundoInvoker::removed(umundo::ServiceDescription desc) { + LOG(ERROR) << "Service lost!"; + + if (_svcs.find(desc) == _svcs.end()) { + return; + } + + delete _svcs[desc]; + _svcs.erase(desc); + + Event addedEvent; + addedEvent.invokeid = _invokeId; + addedEvent.origin = desc.getName(); + addedEvent.origintype = "umundo"; + addedEvent.type = Event::EXTERNAL; + addedEvent.name = _invokeId + ".removed"; + + std::map<std::string, std::string>::const_iterator propIter = desc.getProperties().begin(); + while(propIter != desc.getProperties().end()) { + addedEvent.compound[propIter->first] = Data(propIter->second, Data::VERBATIM); + propIter++; + } + + _interpreter->receive(addedEvent); +} + +void UmundoInvoker::changed(umundo::ServiceDescription desc) { +} + +std::map<std::string, umundo::Node> UmundoInvoker::_nodes; +umundo::Node UmundoInvoker::getNode(Interpreter* interpreter) { + if ((_nodes.find(interpreter->getName()) == _nodes.end())) { + _nodes[interpreter->getName()] = umundo::Node(); + } + return _nodes[interpreter->getName()]; +} + +bool UmundoInvoker::protobufToData(Data& data, const google::protobuf::Message& msg) { + const google::protobuf::Descriptor* desc = msg.GetDescriptor(); + const google::protobuf::Reflection* reflect = msg.GetReflection(); + + data.compound["type"] = Data(desc->name(), Data::VERBATIM); + + for (int i = 0; i < desc->field_count(); i++) { + const google::protobuf::FieldDescriptor* fieldDesc = desc->field(i); + std::string key = fieldDesc->name(); + + if (!fieldDesc->is_repeated() && !reflect->HasField(msg, fieldDesc)) + continue; + + switch(fieldDesc->type()) { + case google::protobuf::FieldDescriptor::TYPE_BOOL: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(reflect->GetRepeatedBool(msg, fieldDesc, j) ? "true" : "false")); + } + } else { + data.compound[key].atom = (reflect->GetBool(msg, fieldDesc) ? "true" : "false"); + } + break; + case google::protobuf::FieldDescriptor::TYPE_BYTES: + case google::protobuf::FieldDescriptor::TYPE_STRING: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedString(msg, fieldDesc, j)), Data::VERBATIM)); + } + } else { + data.compound[key].atom = toStr(reflect->GetString(msg, fieldDesc)); + data.compound[key].type = Data::VERBATIM; + } + break; + case google::protobuf::FieldDescriptor::TYPE_DOUBLE: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedDouble(msg, fieldDesc, j)))); + } + } else { + data.compound[key].atom = toStr(reflect->GetDouble(msg, fieldDesc)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_ENUM: + LOG(ERROR) << "TYPE_ENUM is unimplemented" << std::endl; + break; + case google::protobuf::FieldDescriptor::TYPE_FIXED32: + case google::protobuf::FieldDescriptor::TYPE_UINT32: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt32(msg, fieldDesc, j)))); + } + } else { + data.compound[key].atom = toStr(reflect->GetUInt32(msg, fieldDesc)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_FIXED64: + case google::protobuf::FieldDescriptor::TYPE_UINT64: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt64(msg, fieldDesc, j)))); + } + } else { + data.compound[key].atom = toStr(reflect->GetUInt64(msg, fieldDesc)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_FLOAT: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedFloat(msg, fieldDesc, j)))); + } + } else { + data.compound[key].atom = toStr(reflect->GetFloat(msg, fieldDesc)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_GROUP: + LOG(ERROR) << "TYPE_GROUP is unimplemented" << std::endl; + break; + case google::protobuf::FieldDescriptor::TYPE_INT32: + case google::protobuf::FieldDescriptor::TYPE_SINT32: + case google::protobuf::FieldDescriptor::TYPE_SFIXED32: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt32(msg, fieldDesc, j)))); + } + } else { + data.compound[key].atom = toStr(reflect->GetInt32(msg, fieldDesc)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_INT64: + case google::protobuf::FieldDescriptor::TYPE_SINT64: + case google::protobuf::FieldDescriptor::TYPE_SFIXED64: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt64(msg, fieldDesc, j)))); + } + } else { + data.compound[key].atom = toStr(reflect->GetInt64(msg, fieldDesc)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_MESSAGE: + if (fieldDesc->is_repeated()) { + for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) { + data.compound[key].array.push_back(Data()); + protobufToData(data.compound[key].array.back(), reflect->GetRepeatedMessage(msg, fieldDesc, j)); + } + } else { + protobufToData(data.compound[key], reflect->GetMessage(msg, fieldDesc)); + } + break; + } + } + return true; +} + +bool UmundoInvoker::dataToProtobuf(google::protobuf::Message* msg, Data& data) { + const google::protobuf::Descriptor* desc = msg->GetDescriptor(); + const google::protobuf::Reflection* reflect = msg->GetReflection(); + + for (int i = 0; i < desc->field_count(); i++) { + const google::protobuf::FieldDescriptor* fieldDesc = desc->field(i); + std::string key = fieldDesc->name(); + + if (data.compound.find(key) == data.compound.end()) { + if (fieldDesc->is_required()) { + LOG(ERROR) << "required field " << key << " not given in JSON"; + return false; + } + continue; + } + + std::list<Data>::iterator arrayIter = data.compound[key].array.begin(); + + switch(fieldDesc->type()) { + case google::protobuf::FieldDescriptor::TYPE_BOOL: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddBool(msg, fieldDesc, arrayIter->atom.compare("false") == 0 ? false : true); + arrayIter++; + } + } else { + reflect->SetBool(msg, fieldDesc, (data.compound[key].atom.compare("false") == 0 ? false : true)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_BYTES: + case google::protobuf::FieldDescriptor::TYPE_STRING: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddString(msg, fieldDesc, arrayIter->atom); + arrayIter++; + } + } else { + reflect->SetString(msg, fieldDesc, data.compound[key].atom); + } + break; + case google::protobuf::FieldDescriptor::TYPE_DOUBLE: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddDouble(msg, fieldDesc, strTo<double>(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetDouble(msg, fieldDesc, strTo<double>(data.compound[key].atom)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_ENUM: + LOG(ERROR) << "TYPE_ENUM is unimplemented" << std::endl; + break; + case google::protobuf::FieldDescriptor::TYPE_FIXED32: + case google::protobuf::FieldDescriptor::TYPE_UINT32: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddUInt32(msg, fieldDesc, strTo<uint32_t>(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetUInt32(msg, fieldDesc, strTo<uint32_t>(data.compound[key].atom)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_FIXED64: + case google::protobuf::FieldDescriptor::TYPE_UINT64: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddUInt64(msg, fieldDesc, strTo<uint64_t>(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetUInt64(msg, fieldDesc, strTo<uint64_t>(data.compound[key].atom)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_FLOAT: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddFloat(msg, fieldDesc, strTo<float>(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetFloat(msg, fieldDesc, strTo<float>(data.compound[key].atom)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_GROUP: + LOG(ERROR) << "TYPE_GROUP is unimplemented" << std::endl; + break; + case google::protobuf::FieldDescriptor::TYPE_INT32: + case google::protobuf::FieldDescriptor::TYPE_SINT32: + case google::protobuf::FieldDescriptor::TYPE_SFIXED32: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddInt32(msg, fieldDesc, strTo<int32_t>(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetInt32(msg, fieldDesc, strTo<int32_t>(data.compound[key].atom)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_INT64: + case google::protobuf::FieldDescriptor::TYPE_SINT64: + case google::protobuf::FieldDescriptor::TYPE_SFIXED64: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + reflect->AddInt64(msg, fieldDesc, strTo<int64_t>(arrayIter->atom)); + arrayIter++; + } + } else { + reflect->SetInt64(msg, fieldDesc, strTo<int64_t>(data.compound[key].atom)); + } + break; + case google::protobuf::FieldDescriptor::TYPE_MESSAGE: + if (fieldDesc->is_repeated()) { + while(arrayIter != data.compound[key].array.end()) { + dataToProtobuf(reflect->AddMessage(msg, fieldDesc), *arrayIter); + arrayIter++; + } + } else { + dataToProtobuf(reflect->MutableMessage(msg, fieldDesc), data.compound[key]); + } + break; + } + } + return true; +} + +}
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h new file mode 100644 index 0000000..36a6217 --- /dev/null +++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h @@ -0,0 +1,70 @@ +#ifndef UMUNDOINVOKER_H_77YXQGU7 +#define UMUNDOINVOKER_H_77YXQGU7 + +#include <umundo/core.h> +#include <umundo/s11n.h> +#include <umundo/rpc.h> +#include <umundo/s11n/protobuf/PBSerializer.h> +#include <google/protobuf/message.h> + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class Interpreter; + +class UmundoInvoker : public Invoker, public umundo::TypedReceiver, public umundo::ResultSet<umundo::ServiceDescription> { +public: + UmundoInvoker(); + virtual ~UmundoInvoker(); + virtual Invoker* create(Interpreter* interpreter); + + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("umundo"); + names.insert("http://umundo.tk.informatik.tu-darmstadt.de/"); + names.insert("http://umundo.tk.informatik.tu-darmstadt.de"); + return names; + } + + virtual Data getDataModelVariables(); + virtual void send(SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(InvokeRequest& req); + virtual void sendToParent(SendRequest& req); + + virtual void receive(void* object, umundo::Message* msg); + + virtual void added(umundo::ServiceDescription); + virtual void removed(umundo::ServiceDescription); + virtual void changed(umundo::ServiceDescription); + +protected: + std::string _invokeId; + bool _isService; + + bool dataToProtobuf(google::protobuf::Message* msg, Data& data); + bool protobufToData(Data& data, const google::protobuf::Message& msg); + + umundo::TypedPublisher _pub; + umundo::TypedSubscriber _sub; + umundo::Node _node; + + umundo::ServiceFilter _svcFilter; + umundo::ServiceManager _svcMgr; + std::map<umundo::ServiceDescription, umundo::ServiceStub*> _svcs; + + static std::map<std::string, umundo::Node> _nodes; + static umundo::Node getNode(Interpreter* interpreter); +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(UmundoInvoker, Invoker); +#endif + +} + + +#endif /* end of include guard: UMUNDOINVOKER_H_77YXQGU7 */ diff --git a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp new file mode 100644 index 0000000..44c89ae --- /dev/null +++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp @@ -0,0 +1,370 @@ +#ifdef _WIN32 +#include <winsock2.h> +#include <windows.h> +#endif + +#include "uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h" +#include "uscxml/Message.h" +#include <iostream> +#include <event2/dns.h> +#include <event2/buffer.h> +#include <event2/keyvalq_struct.h> + +#include <string.h> + +#include <io/uri.hpp> +#include <glog/logging.h> + +#ifndef _WIN32 +#include <netdb.h> +#include <arpa/inet.h> +#endif + +#ifdef BUILD_AS_PLUGINS +#include <Pluma/Connector.hpp> +#endif + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host){ + host.add( new EventIOProcessorProvider() ); + return true; +} +#endif + +// see http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor + +EventIOProcessor::EventIOProcessor() { +} + +EventIOProcessor::~EventIOProcessor() { + _asyncQueue.stop(); + evdns_base_free(_dns, 1); + EventIOServer* httpServer = EventIOServer::getInstance(); + httpServer->unregisterProcessor(this); +} + +IOProcessor* EventIOProcessor::create(Interpreter* interpreter) { + EventIOProcessor* io = new EventIOProcessor(); + io->_interpreter = interpreter; + + io->_dns = evdns_base_new(io->_asyncQueue._eventLoop, 1); + assert(io->_dns); + assert(evdns_base_count_nameservers(io->_dns) > 0); + + // register at http server + EventIOServer* httpServer = EventIOServer::getInstance(); + httpServer->registerProcessor(io); + + io->start(); + return io; +} + +void EventIOProcessor::start() { + _asyncQueue.start(); +} + +Data EventIOProcessor::getDataModelVariables() { + Data data; + assert(_url.length() > 0); + data.compound["location"] = Data(_url, Data::VERBATIM); + return data; +} + + +void EventIOProcessor::send(SendRequest& req) { + // I cant figure out how to copy the reference into the struct :( + _sendData[req.sendid].req = req; + _sendData[req.sendid].ioProcessor = this; + + int err = 0; + char uriBuf[1024]; + + struct evhttp_uri* targetURI = evhttp_uri_parse(_sendData[req.sendid].req.target.c_str()); + if (evhttp_uri_get_port(targetURI) == 0) + evhttp_uri_set_port(targetURI, 80); + const char* hostName = evhttp_uri_get_host(targetURI); + + // use synchronous dns resolving for multicast dns + if(hostName && strlen(hostName) >= strlen(".local")) { + if(strcmp(hostName + strlen(hostName) - strlen(".local"), ".local") == 0) { + evhttp_uri_set_host(targetURI, EventIOServer::syncResolve(hostName).c_str()); + } + } + evhttp_uri_join(targetURI, uriBuf, 1024); + + LOG(INFO) << "URI for send request: " << uriBuf << std::endl; + + std::stringstream ssEndPoint; + ssEndPoint << evhttp_uri_get_host(targetURI) << ":" << evhttp_uri_get_port(targetURI); + std::string endPoint = ssEndPoint.str(); + + std::stringstream ssLocalURI; + ssLocalURI << evhttp_uri_get_path(targetURI) << evhttp_uri_get_fragment(targetURI); + std::string localURI = ssLocalURI.str(); + + if (_httpConnections.find(endPoint) == _httpConnections.end()) + _httpConnections[endPoint] = evhttp_connection_base_new(_asyncQueue._eventLoop, _dns, evhttp_uri_get_host(targetURI), evhttp_uri_get_port(targetURI)); + + struct evhttp_connection* httpConn = _httpConnections[endPoint]; + struct evhttp_request* httpReq = evhttp_request_new(EventIOProcessor::httpSendReqDone, this); + +#if 0 + // event name + if (sendData->req.event.size() > 0) { + evhttp_add_header(evhttp_request_get_output_headers(httpReq), "_scxmleventname", evhttp_encode_uri(sendData->req.event.c_str())); + } + + // event namelist + if (sendData->req.namelist.size() > 0) { + std::map<std::string, std::string>::iterator namelistIter = sendData->req.namelist.begin(); + while (namelistIter != sendData->req.namelist.end()) { + evhttp_add_header(evhttp_request_get_output_headers(httpReq), + namelistIter->first.c_str(), + evhttp_encode_uri(namelistIter->second.c_str())); + namelistIter++; + } + } + + // event params + if (sendData->req.params.size() > 0) { + std::map<std::string, std::string>::iterator paramIter = sendData->req.params.begin(); + while (paramIter != sendData->req.params.end()) { + evhttp_add_header(evhttp_request_get_output_headers(httpReq), + paramIter->first.c_str(), + evhttp_encode_uri(paramIter->second.c_str())); + paramIter++; + } + } + + // content + if (sendData->req.content.size() > 0) + evbuffer_add(evhttp_request_get_output_buffer(httpReq), sendData->req.content.c_str(), sendData->req.content.size()); +#endif + + evhttp_add_header(evhttp_request_get_output_headers(httpReq), "_scxmleventstruct", evhttp_encode_uri(req.toXMLString().c_str())); + + + _httpRequests[req.sendid] = httpReq; + err = evhttp_make_request(httpConn, + httpReq, + EVHTTP_REQ_POST, localURI.c_str()); + if (err) { + LOG(ERROR) << "Could not make http request to " << req.target; + } +} + +void EventIOProcessor::httpRecvReq(struct evhttp_request *req, void *arg) { + + const char *cmdtype; + struct evkeyvalq *headers; + struct evkeyval *header; + struct evbuffer *buf; + + switch (evhttp_request_get_command(req)) { + case EVHTTP_REQ_GET: cmdtype = "GET"; break; + case EVHTTP_REQ_POST: cmdtype = "POST"; break; + case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break; + case EVHTTP_REQ_PUT: cmdtype = "PUT"; break; + case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break; + case EVHTTP_REQ_OPTIONS: cmdtype = "OPTIONS"; break; + case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break; + case EVHTTP_REQ_CONNECT: cmdtype = "CONNECT"; break; + case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break; + default: cmdtype = "unknown"; break; + } + + Event reqEvent; + reqEvent.type = Event::EXTERNAL; + bool scxmlStructFound = false; + + // map headers to event structure + headers = evhttp_request_get_input_headers(req); + for (header = headers->tqh_first; header; + header = header->next.tqe_next) { +// std::cout << "Header: " << header->key << std::endl; +// std::cout << "Value: " << evhttp_decode_uri(header->value) << std::endl; + if (boost::iequals("_scxmleventstruct", header->key)) { + reqEvent = Event::fromXML(evhttp_decode_uri(header->value)); + scxmlStructFound = true; + break; + } else if (boost::iequals("_scxmleventname", header->key)) { + reqEvent.name = evhttp_decode_uri(header->value); + } else { + reqEvent.compound[header->key] = Data(evhttp_decode_uri(header->value), Data::VERBATIM); + } + } + + if (!scxmlStructFound) { + // get content into event + std::string content; + buf = evhttp_request_get_input_buffer(req); + while (evbuffer_get_length(buf)) { + int n; + char cbuf[128]; + n = evbuffer_remove(buf, cbuf, sizeof(buf)-1); + if (n > 0) { + content.append(cbuf, n); + } + } + reqEvent.compound["content"] = Data(content, Data::VERBATIM); + } + + EventIOProcessor* INSTANCE = (EventIOProcessor*)arg; + INSTANCE->_interpreter->receive(reqEvent); + + evhttp_send_reply(req, 200, "OK", NULL); +} + +void EventIOProcessor::httpSendReqDone(struct evhttp_request *req, void *cb_arg) { + if (req) { + LOG(INFO) << "got return code " << evhttp_request_get_response_code(req) << std::endl; + } +} + +EventIOServer::EventIOServer(unsigned short port) { + _port = port; + _base = event_base_new(); + _http = evhttp_new(_base); + _handle = NULL; + while((_handle = evhttp_bind_socket_with_handle(_http, INADDR_ANY, _port)) == NULL) { + _port++; + } + determineAddress(); +} + +EventIOServer::~EventIOServer() { +} + +EventIOServer* EventIOServer::_instance = NULL; +tthread::recursive_mutex EventIOServer::_instanceMutex; + +EventIOServer* EventIOServer::getInstance() { + tthread::lock_guard<tthread::recursive_mutex> lock(_instanceMutex); + if (_instance == NULL) { + _instance = new EventIOServer(8080); + _instance->start(); + } + return _instance; +} + +void EventIOServer::registerProcessor(EventIOProcessor* processor) { + EventIOServer* INSTANCE = getInstance(); + tthread::lock_guard<tthread::recursive_mutex> lock(INSTANCE->_mutex); + + /** + * Determine path for interpreter. + * + * If the interpreter has a name and it is not yet taken, choose it as the path + * for requests. If the interpreters name path is already taken, append digits + * until we have an available path. + * + * If the interpreter does not specify a name, take its sessionid. + */ + + std::string path = processor->_interpreter->getName(); + if (path.size() == 0) { + path = processor->_interpreter->getSessionId(); + } + assert(path.size() > 0); + + std::stringstream actualPath(path); + int i = 1; + while(INSTANCE->_processors.find(actualPath.str()) != INSTANCE->_processors.end()) { + actualPath.str(std::string()); + actualPath.clear(); + actualPath << path << ++i; + } + + std::stringstream processorURL; + processorURL << "http://" << INSTANCE->_address << ":" << INSTANCE->_port << "/" << actualPath.str(); + + INSTANCE->_processors[actualPath.str()] = processor; + processor->setURL(processorURL.str()); + + evhttp_set_cb(INSTANCE->_http, ("/" + actualPath.str()).c_str(), EventIOProcessor::httpRecvReq, processor); +// evhttp_set_cb(THIS->_http, "/", EventIOProcessor::httpRecvReq, processor); +// evhttp_set_gencb(THIS->_http, EventIOProcessor::httpRecvReq, NULL); +} + +void EventIOServer::unregisterProcessor(EventIOProcessor* processor) { + EventIOServer* INSTANCE = getInstance(); + tthread::lock_guard<tthread::recursive_mutex> lock(INSTANCE->_mutex); + evhttp_del_cb(INSTANCE->_http, processor->_url.c_str()); +} + +void EventIOServer::start() { + _isRunning = true; + _thread = new tthread::thread(EventIOServer::run, this); +} + +void EventIOServer::run(void* instance) { + EventIOServer* INSTANCE = (EventIOServer*)instance; + while(INSTANCE->_isRunning) { + LOG(INFO) << "Dispatching HTTP Server" << std::endl; + event_base_dispatch(INSTANCE->_base); + } + LOG(INFO) << "HTTP Server stopped" << std::endl; +} + +std::string EventIOServer::syncResolve(const std::string& hostname) { + struct hostent *he; + struct in_addr **addr_list; + int i; + + if ( (he = gethostbyname( hostname.c_str() ) ) != NULL) { + addr_list = (struct in_addr **) he->h_addr_list; + for(i = 0; addr_list[i] != NULL; i++) { + return std::string(inet_ntoa(*addr_list[i])); + } + } + return ""; +} + +void EventIOServer::determineAddress() { + + char hostname[1024]; + gethostname(hostname, 1024); + _address = std::string(hostname); + +#if 0 + struct sockaddr_storage ss; + evutil_socket_t fd; + ev_socklen_t socklen = sizeof(ss); + char addrbuf[128]; + + void *inaddr; + const char *addr; + int got_port = -1; + fd = evhttp_bound_socket_get_fd(_handle); + memset(&ss, 0, sizeof(ss)); + if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) { + perror("getsockname() failed"); + return; + } + + if (ss.ss_family == AF_INET) { + got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port); + inaddr = &((struct sockaddr_in*)&ss)->sin_addr; + } else if (ss.ss_family == AF_INET6) { + got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port); + inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr; + } else { + fprintf(stderr, "Weird address family %d\n", + ss.ss_family); + return; + } + addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf, + sizeof(addrbuf)); + if (addr) { + _address = std::string(addr); + } else { + fprintf(stderr, "evutil_inet_ntop failed\n"); + return; + } +#endif +} + +}
\ No newline at end of file diff --git a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h new file mode 100644 index 0000000..af7aac7 --- /dev/null +++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.h @@ -0,0 +1,107 @@ +#ifndef EVENTIOPROCESSOR_H_2CUY93KU +#define EVENTIOPROCESSOR_H_2CUY93KU + +#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h" +#include "uscxml/Interpreter.h" +#include "uscxml/Factory.h" +#ifndef _WIN32 +#include <sys/time.h> +#endif + +#include <event2/http.h> +#include <event2/http_struct.h> + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class EventIOServer; + +class EventIOProcessor : public uscxml::IOProcessor { +public: + struct SendData { + EventIOProcessor* ioProcessor; + uscxml::SendRequest req; + }; + + EventIOProcessor(); + virtual ~EventIOProcessor(); + virtual IOProcessor* create(uscxml::Interpreter* interpreter); + + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("basichttp"); + names.insert("http://www.w3.org/TR/scxml/#SCXMLEventProcessor"); + return names; + } + + virtual void send(uscxml::SendRequest& req); + + Data getDataModelVariables(); + void setURL(const std::string& url) { _url = url; } + + void start(); + static void run(void* instance); + + static void httpMakeSendReq(void* userdata, std::string eventName); + static void httpSendReqDone(struct evhttp_request *req, void *cb_arg); + static void httpRecvReq(struct evhttp_request *req, void *arg); + +protected: + std::map<std::string, SendData> _sendData; + + std::string _url; + + uscxml::DelayedEventQueue _asyncQueue; + uscxml::Interpreter* _interpreter; + std::map<std::string, struct evhttp_connection*> _httpConnections; + std::map<std::string, struct evhttp_request*> _httpRequests; + struct evdns_base* _dns; + + friend class EventIOServer; +}; + +class EventIOServer { +private: + static EventIOServer* getInstance(); + EventIOServer(unsigned short port); + ~EventIOServer(); + + void start(); + void stop(); + static void run(void* instance); + + void determineAddress(); + static std::string syncResolve(const std::string& hostname); + + static void registerProcessor(EventIOProcessor* processor); + static void unregisterProcessor(EventIOProcessor* processor); + + + std::map<std::string, EventIOProcessor*> _processors; + + struct event_base* _base; + struct evhttp* _http; + struct evhttp_bound_socket* _handle; + + unsigned short _port; + std::string _address; + + static EventIOServer* _instance; + static tthread::recursive_mutex _instanceMutex; + tthread::thread* _thread; + tthread::recursive_mutex _mutex; + bool _isRunning; + + friend class EventIOProcessor; +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(EventIOProcessor, IOProcessor); +#endif + +} + +#endif /* end of include guard: EVENTIOPROCESSOR_H_2CUY93KU */
\ No newline at end of file |