Salome HOME
Issue EDF13739 : Plugin mechanism in driver.exe that allows runtime customization...
authorAnthony Geay <anthony.geay@edf.fr>
Thu, 27 Oct 2016 13:52:18 +0000 (15:52 +0200)
committerAnthony Geay <anthony.geay@edf.fr>
Thu, 27 Oct 2016 13:52:18 +0000 (15:52 +0200)
src/engine/Dispatcher.cxx
src/engine/Dispatcher.hxx
src/yacsloader/CMakeLists.txt
src/yacsloader/ExampleOfObserversPluginForDriver.cxx [new file with mode: 0644]
src/yacsloader/driver.cxx

index 8ca796b751824cff41ebac4c01b29a5a84002246..c957e915d67a745b778b65030f569182014b110a 100644 (file)
@@ -80,11 +80,11 @@ void Dispatcher::printObservers()
 void Dispatcher::dispatch(Node* object, const std::string& event)
 {
   DEBTRACE("Dispatcher::dispatch " << event );
-  typedef std::set<Observer*>::iterator jt;
   std::pair<Node*,std::string> key(object,event);
-  if(_observers.count(key) != 0)
+  std::map< std::pair<Node*,std::string> , std::set<Observer*> >::const_iterator it(_observers.find(key));
+  if(it!=_observers.end())
     {
-      for(jt iter=_observers[key].begin();iter!=_observers[key].end();iter++)
+      for(std::set<Observer*>::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<Observer*>::iterator jt;
   std::pair<Node*,std::string> key(object,event);
-  if(_observers.count(key) != 0)
+  std::map< std::pair<Node*,std::string> , std::set<Observer*> >::const_iterator it(_observers.find(key));
+  if(it!=_observers.end())
     {
-      for(jt iter=_observers[key].begin();iter!=_observers[key].end();iter++)
+      for(std::set<Observer*>::const_iterator iter=(*it).second.begin();iter!=(*it).second.end();iter++)
         {
           (*iter)->notifyObserver2(object,event,something);
         }
index 26e46e2941ebed18c73a29b951121457bf0d74c9..dbf270dc4520d772abaa9a3eb478e83a32a3e839 100644 (file)
@@ -82,7 +82,6 @@ namespace YACS
       virtual ~Dispatcher();
     protected:
       std::map< std::pair<Node*,std::string> , std::set<Observer*> > _observers;
-      std::map< std::pair<Executor*,std::string> , std::set<Observer*> > _observExec;
       static Dispatcher* _singleton;
     };
 
index 77ac92086a29364c781bd71ac931b49ea1ceeff4..20052f3721d0c1a7544e13ca1baa66ca60fe6019 100644 (file)
@@ -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 (file)
index 0000000..e0c0f2f
--- /dev/null
@@ -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 <iostream>
+#include <sstream>
+
+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<int *>(something));
+      oss << event << " " << itemOk;
+      std::cerr << oss.str() << std::endl;
+    }
+}
+
+class PluginObserverKeeper
+{
+public:
+  ~PluginObserverKeeper() { clean(); }
+  void clean() { for(std::vector<YACS::ENGINE::Observer *>::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<YACS::ENGINE::Observer *> _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<YACS::ENGINE::ForEachLoop *>(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();
+  }
+}
+
index 529cb599f705019aacca303123b979fbdfb1e6d7..7d377c8cc3fff7d6bf9749a0cc37539b9cafe3c9 100644 (file)
@@ -101,6 +101,62 @@ typedef struct {
   string lockFile;
 } thread_st;
 
+#ifndef WIN32
+#include <dlfcn.h>
+#include <stdlib.h>
+#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)