// @(#)root/base:$Id$
// Author: Fons Rademakers   26/1/2002

/*************************************************************************
 * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TPluginManager
#define ROOT_TPluginManager


//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TPluginManager                                                       //
//                                                                      //
// This class implements a plugin library manager. It keeps track of    //
// a list of plugin handlers. A plugin handler knows which plugin       //
// library to load to get a specific class that is used to extend the   //
// functionality of a specific base class and how to create an object   //
// of this class. For example, to extend the base class TFile to be     //
// able to read RFIO files one needs to load the plugin library         //
// libRFIO.so which defines the TRFIOFile class. This loading should    //
// be triggered when a given URI contains a regular expression defined  //
// by the handler.                                                      //
// Plugin handlers can be defined via macros in a list of plugin        //
// directories. With $ROOTSYS/etc/plugins the default top plugin        //
// directory specified in $ROOTSYS/etc/system.rootrc. Additional        //
// directories can be specified by adding them to the end of the list.  //
// Macros for identical plugin handlers in later directories will       //
// override previous ones (the inverse of normal search path behavior). //
// The macros must have names like <BaseClass>/PX0_<PluginClass>.C,     //
// e.g.:                                                                //
//    TFile/P10_TRFIOFile.C, TSQLServer/P20_TMySQLServer.C, etc.        //
// to allow easy sorting and grouping. If the BaseClass is in a         //
// namespace the directory must have the name NameSpace@@BaseClass as   //
// : is a reserved pathname character on some operating systems.        //
// Macros not beginning with 'P' and ending with ".C" are ignored.      //
// These macros typically look like:                                    //
//                                                                      //
//   void P10_TDCacheFile()                                             //
//   {                                                                  //
//       gPluginMgr->AddHandler("TFile", "^dcache", "TDCacheFile",      //
//          "DCache", "TDCacheFile(const char*,Option_t*)");            //
//   }                                                                  //
//                                                                      //
// Plugin handlers can also be defined via resources in the .rootrc     //
// file. Although now deprecated this method still works for backward   //
// compatibility, e.g.:                                                 //
//                                                                      //
//   Plugin.TFile:       ^rfio:   TRFIOFile    RFIO   "<constructor>"   //
//   Plugin.TSQLServer:  ^mysql:  TMySQLServer MySQL  "<constructor>"   //
//   +Plugin.TSQLServer: ^pgsql:  TPgSQLServer PgSQL  "<constructor>"   //
//   Plugin.TVirtualFitter: *     TFitter      Minuit "TFitter(Int_t)"  //
//                                                                      //
// Where the + in front of Plugin.TSQLServer says that it extends the   //
// existing definition of TSQLServer, useful when there is more than    //
// one plugin that can extend the same base class. The "<constructor>"  //
// should be the constructor or a static method that generates an       //
// instance of the specified class. Global methods should start with    //
// "::" in their name, like "::CreateFitter()".                         //
// Instead of being a shared library a plugin can also be a CINT        //
// script, so instead of libDialog.so one can have Dialog.C.            //
// The * is a placeholder in case there is no need for a URI to         //
// differentiate between different plugins for the same base class.     //
// For the default plugins see $ROOTSYS/etc/system.rootrc.              //
//                                                                      //
// Plugin handlers can also be registered at run time, e.g.:            //
//                                                                      //
//   gPluginMgr->AddHandler("TSQLServer", "^sapdb:",                    //
//                          "TSapDBServer", "SapDB",                    //
//             "TSapDBServer(const char*,const char*, const char*)");   //
//                                                                      //
// A list of currently defined handlers can be printed using:           //
//                                                                      //
//   gPluginMgr->Print(); // use option="a" to see ctors                //
//                                                                      //
// The use of the plugin library manager removes all textual references //
// to hard-coded class and library names and the resulting dependencies //
// in the base classes. The plugin manager is used to extend a.o.       //
// TFile, TSQLServer, TGrid, etc. functionality.                        //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#ifndef ROOT_TObject
#include "TObject.h"
#endif
#ifndef ROOT_TString
#include "TString.h"
#endif
#ifndef ROOT_TMethodCall
#include "TMethodCall.h"
#endif
#ifndef ROOT_TVirtualMutex
#include "TVirtualMutex.h"
#endif
#ifndef ROOT_TInterpreter
#include "TInterpreter.h"
#endif

class TEnv;
class TList;
class THashTable;
class TFunction;
class TMethodCall;
class TPluginManager;


class TPluginHandler : public TObject {

friend class TPluginManager;

private:
   TString      fBase;      // base class which will be extended by plugin
   TString      fRegexp;    // regular expression which must be matched in URI
   TString      fClass;     // class to be loaded from plugin library
   TString      fPlugin;    // plugin library which should contain fClass
   TString      fCtor;      // ctor used to instantiate object of fClass
   TString      fOrigin;    // origin of plugin handler definition
   TMethodCall *fCallEnv;   //!ctor method call environment
   TFunction   *fMethod;    //!ctor method or global function
   Int_t        fCanCall;   //!if 1 fCallEnv is ok, -1 fCallEnv is not ok
   Bool_t       fIsMacro;   // plugin is a macro and not a library
   Bool_t       fIsGlobal;  // plugin ctor is a global function

   TPluginHandler() :
      fBase(), fRegexp(), fClass(), fPlugin(), fCtor(), fOrigin(),
      fCallEnv(0), fMethod(0), fCanCall(0), fIsMacro(kTRUE), fIsGlobal(kTRUE) { }
   TPluginHandler(const char *base, const char *regexp,
                  const char *className, const char *pluginName,
                  const char *ctor, const char *origin);
   TPluginHandler(const TPluginHandler&);            // not implemented
   TPluginHandler& operator=(const TPluginHandler&); // not implemented

   ~TPluginHandler();

   const char *GetBase() const { return fBase; }
   const char *GetRegexp() const { return fRegexp; }
   const char *GetPlugin() const { return fPlugin; }
   const char *GetCtor() const { return fCtor; }
   const char *GetOrigin() const { return fOrigin; }

   Bool_t CanHandle(const char *base, const char *uri);
   void   SetupCallEnv();

   Bool_t CheckForExecPlugin(Int_t nargs);

public:
   const char *GetClass() const { return fClass; }
   Int_t       CheckPlugin() const;
   Int_t       LoadPlugin();

   template <typename... T> Long_t ExecPluginImpl(const T&... params)
   {
      auto nargs = sizeof...(params);
      if (!CheckForExecPlugin(nargs)) return 0;

      fCallEnv->SetParams(params...);

      Long_t ret;
      fCallEnv->Execute(ret);

      return ret;
   }

   template <typename... T> Long_t ExecPlugin(int nargs, const T&... params)
   {
      // For backward compatibility.
      if ((gDebug > 1) && (nargs != (int)sizeof...(params))) {
         Warning("ExecPlugin","Announced number of args different from the real number of argument passed %d vs %lu",
                 nargs, (unsigned long)sizeof...(params) );
      }
      return ExecPluginImpl(params...);
   }

   void        Print(Option_t *opt = "") const;

   ClassDef(TPluginHandler,3)  // Handler for plugin libraries
};


class TPluginManager : public TObject {

private:
   TList      *fHandlers;     // list of plugin handlers
   THashTable *fBasesLoaded;  //! table of base classes already checked or loaded
   Bool_t      fReadingDirs;  //! true if we are running LoadHandlersFromPluginDirs

   TPluginManager(const TPluginManager& pm);              // not implemented
   TPluginManager& operator=(const TPluginManager& pm);   // not implemented
   void   LoadHandlerMacros(const char *path);

public:
   TPluginManager() : fHandlers(0), fBasesLoaded(0), fReadingDirs(kFALSE) { }
   ~TPluginManager();

   void   LoadHandlersFromEnv(TEnv *env);
   void   LoadHandlersFromPluginDirs(const char *base = 0);
   void   AddHandler(const char *base, const char *regexp,
                     const char *className, const char *pluginName,
                     const char *ctor = 0, const char *origin = 0);
   void   RemoveHandler(const char *base, const char *regexp = 0);

   TPluginHandler *FindHandler(const char *base, const char *uri = 0);

   void   Print(Option_t *opt = "") const;
   Int_t  WritePluginMacros(const char *dir, const char *plugin = 0) const;
   Int_t  WritePluginRecords(const char *envFile, const char *plugin = 0) const;

   ClassDef(TPluginManager,1)  // Manager for plugin handlers
};

R__EXTERN TPluginManager *gPluginMgr;

#endif
 TPluginManager.h:1
 TPluginManager.h:2
 TPluginManager.h:3
 TPluginManager.h:4
 TPluginManager.h:5
 TPluginManager.h:6
 TPluginManager.h:7
 TPluginManager.h:8
 TPluginManager.h:9
 TPluginManager.h:10
 TPluginManager.h:11
 TPluginManager.h:12
 TPluginManager.h:13
 TPluginManager.h:14
 TPluginManager.h:15
 TPluginManager.h:16
 TPluginManager.h:17
 TPluginManager.h:18
 TPluginManager.h:19
 TPluginManager.h:20
 TPluginManager.h:21
 TPluginManager.h:22
 TPluginManager.h:23
 TPluginManager.h:24
 TPluginManager.h:25
 TPluginManager.h:26
 TPluginManager.h:27
 TPluginManager.h:28
 TPluginManager.h:29
 TPluginManager.h:30
 TPluginManager.h:31
 TPluginManager.h:32
 TPluginManager.h:33
 TPluginManager.h:34
 TPluginManager.h:35
 TPluginManager.h:36
 TPluginManager.h:37
 TPluginManager.h:38
 TPluginManager.h:39
 TPluginManager.h:40
 TPluginManager.h:41
 TPluginManager.h:42
 TPluginManager.h:43
 TPluginManager.h:44
 TPluginManager.h:45
 TPluginManager.h:46
 TPluginManager.h:47
 TPluginManager.h:48
 TPluginManager.h:49
 TPluginManager.h:50
 TPluginManager.h:51
 TPluginManager.h:52
 TPluginManager.h:53
 TPluginManager.h:54
 TPluginManager.h:55
 TPluginManager.h:56
 TPluginManager.h:57
 TPluginManager.h:58
 TPluginManager.h:59
 TPluginManager.h:60
 TPluginManager.h:61
 TPluginManager.h:62
 TPluginManager.h:63
 TPluginManager.h:64
 TPluginManager.h:65
 TPluginManager.h:66
 TPluginManager.h:67
 TPluginManager.h:68
 TPluginManager.h:69
 TPluginManager.h:70
 TPluginManager.h:71
 TPluginManager.h:72
 TPluginManager.h:73
 TPluginManager.h:74
 TPluginManager.h:75
 TPluginManager.h:76
 TPluginManager.h:77
 TPluginManager.h:78
 TPluginManager.h:79
 TPluginManager.h:80
 TPluginManager.h:81
 TPluginManager.h:82
 TPluginManager.h:83
 TPluginManager.h:84
 TPluginManager.h:85
 TPluginManager.h:86
 TPluginManager.h:87
 TPluginManager.h:88
 TPluginManager.h:89
 TPluginManager.h:90
 TPluginManager.h:91
 TPluginManager.h:92
 TPluginManager.h:93
 TPluginManager.h:94
 TPluginManager.h:95
 TPluginManager.h:96
 TPluginManager.h:97
 TPluginManager.h:98
 TPluginManager.h:99
 TPluginManager.h:100
 TPluginManager.h:101
 TPluginManager.h:102
 TPluginManager.h:103
 TPluginManager.h:104
 TPluginManager.h:105
 TPluginManager.h:106
 TPluginManager.h:107
 TPluginManager.h:108
 TPluginManager.h:109
 TPluginManager.h:110
 TPluginManager.h:111
 TPluginManager.h:112
 TPluginManager.h:113
 TPluginManager.h:114
 TPluginManager.h:115
 TPluginManager.h:116
 TPluginManager.h:117
 TPluginManager.h:118
 TPluginManager.h:119
 TPluginManager.h:120
 TPluginManager.h:121
 TPluginManager.h:122
 TPluginManager.h:123
 TPluginManager.h:124
 TPluginManager.h:125
 TPluginManager.h:126
 TPluginManager.h:127
 TPluginManager.h:128
 TPluginManager.h:129
 TPluginManager.h:130
 TPluginManager.h:131
 TPluginManager.h:132
 TPluginManager.h:133
 TPluginManager.h:134
 TPluginManager.h:135
 TPluginManager.h:136
 TPluginManager.h:137
 TPluginManager.h:138
 TPluginManager.h:139
 TPluginManager.h:140
 TPluginManager.h:141
 TPluginManager.h:142
 TPluginManager.h:143
 TPluginManager.h:144
 TPluginManager.h:145
 TPluginManager.h:146
 TPluginManager.h:147
 TPluginManager.h:148
 TPluginManager.h:149
 TPluginManager.h:150
 TPluginManager.h:151
 TPluginManager.h:152
 TPluginManager.h:153
 TPluginManager.h:154
 TPluginManager.h:155
 TPluginManager.h:156
 TPluginManager.h:157
 TPluginManager.h:158
 TPluginManager.h:159
 TPluginManager.h:160
 TPluginManager.h:161
 TPluginManager.h:162
 TPluginManager.h:163
 TPluginManager.h:164
 TPluginManager.h:165
 TPluginManager.h:166
 TPluginManager.h:167
 TPluginManager.h:168
 TPluginManager.h:169
 TPluginManager.h:170
 TPluginManager.h:171
 TPluginManager.h:172
 TPluginManager.h:173
 TPluginManager.h:174
 TPluginManager.h:175
 TPluginManager.h:176
 TPluginManager.h:177
 TPluginManager.h:178
 TPluginManager.h:179
 TPluginManager.h:180
 TPluginManager.h:181
 TPluginManager.h:182
 TPluginManager.h:183
 TPluginManager.h:184
 TPluginManager.h:185
 TPluginManager.h:186
 TPluginManager.h:187
 TPluginManager.h:188
 TPluginManager.h:189
 TPluginManager.h:190
 TPluginManager.h:191
 TPluginManager.h:192
 TPluginManager.h:193
 TPluginManager.h:194
 TPluginManager.h:195
 TPluginManager.h:196
 TPluginManager.h:197
 TPluginManager.h:198
 TPluginManager.h:199
 TPluginManager.h:200
 TPluginManager.h:201
 TPluginManager.h:202
 TPluginManager.h:203
 TPluginManager.h:204
 TPluginManager.h:205
 TPluginManager.h:206
 TPluginManager.h:207
 TPluginManager.h:208
 TPluginManager.h:209
 TPluginManager.h:210
 TPluginManager.h:211
 TPluginManager.h:212
 TPluginManager.h:213
 TPluginManager.h:214
 TPluginManager.h:215
 TPluginManager.h:216
 TPluginManager.h:217
 TPluginManager.h:218