From a337ec64407978d9466bcc8717b7fb1c21709764 Mon Sep 17 00:00:00 2001 From: Anthony Geay Date: Thu, 27 Oct 2016 15:52:18 +0200 Subject: [PATCH] Issue EDF13739 : Plugin mechanism in driver.exe that allows runtime customization on events sent by YACS engine. --- src/engine/Dispatcher.cxx | 12 +-- src/engine/Dispatcher.hxx | 1 - src/yacsloader/CMakeLists.txt | 7 ++ .../ExampleOfObserversPluginForDriver.cxx | 92 +++++++++++++++++++ src/yacsloader/driver.cxx | 59 +++++++++++- 5 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 src/yacsloader/ExampleOfObserversPluginForDriver.cxx diff --git a/src/engine/Dispatcher.cxx b/src/engine/Dispatcher.cxx index 8ca796b75..c957e915d 100644 --- a/src/engine/Dispatcher.cxx +++ b/src/engine/Dispatcher.cxx @@ -80,11 +80,11 @@ void Dispatcher::printObservers() void Dispatcher::dispatch(Node* object, const std::string& event) { DEBTRACE("Dispatcher::dispatch " << event ); - typedef std::set::iterator jt; std::pair key(object,event); - if(_observers.count(key) != 0) + std::map< std::pair , std::set >::const_iterator it(_observers.find(key)); + if(it!=_observers.end()) { - for(jt iter=_observers[key].begin();iter!=_observers[key].end();iter++) + for(std::set::const_iterator iter=(*it).second.begin();iter!=(*it).second.end();iter++) { (*iter)->notifyObserver(object,event); } @@ -93,11 +93,11 @@ void Dispatcher::dispatch(Node* object, const std::string& event) void Dispatcher::dispatch2(Node* object,const std::string& event, void *something) { - typedef std::set::iterator jt; std::pair key(object,event); - if(_observers.count(key) != 0) + std::map< std::pair , std::set >::const_iterator it(_observers.find(key)); + if(it!=_observers.end()) { - for(jt iter=_observers[key].begin();iter!=_observers[key].end();iter++) + for(std::set::const_iterator iter=(*it).second.begin();iter!=(*it).second.end();iter++) { (*iter)->notifyObserver2(object,event,something); } diff --git a/src/engine/Dispatcher.hxx b/src/engine/Dispatcher.hxx index 26e46e294..dbf270dc4 100644 --- a/src/engine/Dispatcher.hxx +++ b/src/engine/Dispatcher.hxx @@ -82,7 +82,6 @@ namespace YACS virtual ~Dispatcher(); protected: std::map< std::pair , std::set > _observers; - std::map< std::pair , std::set > _observExec; static Dispatcher* _singleton; }; diff --git a/src/yacsloader/CMakeLists.txt b/src/yacsloader/CMakeLists.txt index 77ac92086..20052f372 100644 --- a/src/yacsloader/CMakeLists.txt +++ b/src/yacsloader/CMakeLists.txt @@ -144,6 +144,9 @@ SET(resume_SOURCES SET(debugger_SOURCES debugger.cxx ) +SET(ExampleOfObserversPluginForDriver_SOURCES + ExampleOfObserversPluginForDriver.cxx + ) # --- rules --- @@ -151,6 +154,10 @@ ADD_LIBRARY(YACSloader ${YACSloader_SOURCES}) TARGET_LINK_LIBRARIES(YACSloader ${YACSloader_LIBRARIES}) INSTALL(TARGETS YACSloader EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_LIBS}) +ADD_LIBRARY(ExampleOfObserversPluginForDriver ${ExampleOfObserversPluginForDriver_SOURCES}) +TARGET_LINK_LIBRARIES(ExampleOfObserversPluginForDriver ${_link_LIBRARIES}) +INSTALL(TARGETS ExampleOfObserversPluginForDriver DESTINATION ${SALOME_INSTALL_LIBS}) + ADD_EXECUTABLE(driver ${driver_SOURCES}) TARGET_LINK_LIBRARIES(driver ${_link_LIBRARIES}) diff --git a/src/yacsloader/ExampleOfObserversPluginForDriver.cxx b/src/yacsloader/ExampleOfObserversPluginForDriver.cxx new file mode 100644 index 000000000..e0c0f2fcd --- /dev/null +++ b/src/yacsloader/ExampleOfObserversPluginForDriver.cxx @@ -0,0 +1,92 @@ +// Copyright (C) 2016 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// Author : Anthony Geay (EDF R&D) + + +// This is an example of plugin implementation you can write to intercept events sent by YACS engine during execution +// 1 - Build your shared library with 2 symboles defined : DefineCustomObservers and CleanUpObservers (warning respect the API !). +// 2 - At run time set YACS_DRIVER_PLUGIN_PATH in your environement to the shared library + +#include "Dispatcher.hxx" +#include "ForEachLoop.hxx" + +#include +#include + +class PluginObserver : public YACS::ENGINE::Observer +{ +public: + PluginObserver(YACS::ENGINE::ForEachLoop *fe):_fe(fe) { } +private: + void notifyObserver(YACS::ENGINE::Node* object,const std::string& event); + void notifyObserver2(YACS::ENGINE::Node* object,const std::string& event, void *something); +private: + YACS::ENGINE::ForEachLoop *_fe; +}; + +void PluginObserver::notifyObserver(YACS::ENGINE::Node* object,const std::string& event) +{// Customize here ! + std::cerr << "------------" << event << std::endl; +} + +void PluginObserver::notifyObserver2(YACS::ENGINE::Node* object,const std::string& event, void *something) +{// Customize here ! + std::ostringstream oss; + if(event=="progress_ok") + { + int itemOk(*reinterpret_cast(something)); + oss << event << " " << itemOk; + std::cerr << oss.str() << std::endl; + } +} + +class PluginObserverKeeper +{ +public: + ~PluginObserverKeeper() { clean(); } + void clean() { for(std::vector::iterator it=_observers.begin();it!=_observers.end();it++) delete *it; _observers.clear(); } + void registerObserver(YACS::ENGINE::Observer *newObs) { _observers.push_back(newObs); } +private: + std::vector _observers; +}; + +PluginObserverKeeper pok; + +#include "ForEachLoop.hxx" + +extern "C" +{ + void DefineCustomObservers(YACS::ENGINE::Dispatcher *disp, YACS::ENGINE::ComposedNode *rootNode, YACS::ENGINE::Executor *executor) + {// Customize here ! + YACS::ENGINE::Node *n(rootNode->getChildByName("ForEachLoop_pyobj1")); + YACS::ENGINE::ForEachLoop *nc(dynamic_cast(n)); + if(!nc) + throw YACS::Exception("Expect to have a ForEach node called ForEachLoop_pyobj1 !"); + PluginObserver *myCustomObsever(new PluginObserver(nc)); + pok.registerObserver(myCustomObsever); + disp->addObserver(myCustomObsever,nc,"progress_ok"); + } + + void CleanUpObservers() + {// Customize here ! + pok.clean(); + } +} + diff --git a/src/yacsloader/driver.cxx b/src/yacsloader/driver.cxx index 529cb599f..7d377c8cc 100644 --- a/src/yacsloader/driver.cxx +++ b/src/yacsloader/driver.cxx @@ -101,6 +101,62 @@ typedef struct { string lockFile; } thread_st; +#ifndef WIN32 +#include +#include +#endif + +std::string LoadedDriverPluginLibrary; +void *HandleOnLoadedPlugin=0; +void (*DefineCustomObservers)(YACS::ENGINE::Dispatcher *, YACS::ENGINE::ComposedNode *, YACS::ENGINE::Executor *)=0; +void (*CleanUpObservers) ()=0; + +void LoadObserversPluginIfAny(YACS::ENGINE::ComposedNode *rootNode, YACS::ENGINE::Executor *executor) +{ + static const char SYMBOLE_NAME_1[]="DefineCustomObservers"; + static const char SYMBOLE_NAME_2[]="CleanUpObservers"; +#ifndef WIN32 + Dispatcher *disp(Dispatcher::getDispatcher()); + if(!disp) + throw YACS::Exception("Internal error ! No dispatcher !"); + char *yacsDriverPluginPath(getenv("YACS_DRIVER_PLUGIN_PATH")); + if(!yacsDriverPluginPath) + return ; + void *handle(dlopen(yacsDriverPluginPath, RTLD_LAZY | RTLD_GLOBAL)); + if(!handle) + { + std::string message(dlerror()); + std::ostringstream oss; oss << "Error during load of \"" << yacsDriverPluginPath << "\" defined by the YACS_DRIVER_PLUGIN_PATH env var : " << message; + throw YACS::Exception(oss.str()); + } + DefineCustomObservers=(void (*)(YACS::ENGINE::Dispatcher *, YACS::ENGINE::ComposedNode *, YACS::ENGINE::Executor *))(dlsym(handle,SYMBOLE_NAME_1)); + if(!DefineCustomObservers) + { + std::ostringstream oss; oss << "Error during load of \"" << yacsDriverPluginPath << "\" ! Library has been correctly loaded but symbol " << SYMBOLE_NAME_1 << " does not exists !"; + throw YACS::Exception(oss.str()); + } + CleanUpObservers=(void (*)())(dlsym(handle,SYMBOLE_NAME_2)); + if(!CleanUpObservers) + { + std::ostringstream oss; oss << "Error during load of \"" << yacsDriverPluginPath << "\" ! Library has been correctly loaded but symbol " << SYMBOLE_NAME_2 << " does not exists !"; + throw YACS::Exception(oss.str()); + } + HandleOnLoadedPlugin=handle; + DefineCustomObservers(disp,rootNode,executor); +#endif +} + +void UnLoadObserversPluginIfAny() +{ +#ifndef WIN32 + if(HandleOnLoadedPlugin) + { + CleanUpObservers(); + dlclose(HandleOnLoadedPlugin); + } +#endif +} + #ifdef WIN32 static int #else @@ -509,7 +565,7 @@ int main (int argc, char* argv[]) st->lockFile = rootFile + ".lock"; pthread_create(&th,NULL,&dumpState,(void*)st); } - + LoadObserversPluginIfAny(p,&executor); cerr << "+++++++++++++++++++ start calculation +++++++++++++++++++" << endl; executor.RunW(p,myArgs.display, fromScratch); cerr << "+++++++++++++++++++ end calculation +++++++++++++++++++" << endl; @@ -559,6 +615,7 @@ int main (int argc, char* argv[]) r->fini(); delete r; delete disp; + UnLoadObserversPluginIfAny(); return return_value; } catch (YACS::Exception& e) -- 2.39.2