modules.h

Go to the documentation of this file.
00001 /**
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /** @file modules.h Interface for Module Management Subsystem */
00020 
00021 #ifndef __MODULES_H__
00022 #define __MODULES_H__
00023 
00024 #include <hn/osdep.h>                      // For DLLEXPORT
00025 #include <hn/object.h>                     // for Object
00026 #include <string>                          // For std::string
00027 #include <vector>                          // For std::vector
00028 #include <map>                             // For std::map
00029 
00030 //! Typedef HNMODULE (HydraNode Module) depending on platform
00031 #ifdef WIN32
00032         struct HINSTANCE__;
00033         typedef HINSTANCE__* HNMODULE;
00034 #else
00035         typedef void* HNMODULE;
00036 #endif
00037 
00038 //! Forward-declare this for making ModuleBase friends with ModManager
00039 class ModManager;
00040 namespace Detail {
00041         struct InitializerBase;
00042         template<typename T>
00043         struct Initializer;
00044 }
00045 
00046 /**
00047  * Abstract base class for Modules. Plugins must derive their main class
00048  * from this class, and override the pure virtual functions onInit() and
00049  * onExit().
00050  */
00051 class DLLEXPORT ModuleBase : public Object {
00052 public:
00053         ModuleBase(const std::string &name);
00054         virtual ~ModuleBase();
00055 
00056         /**
00057          * Called from main application when the module is loaded.
00058          *
00059          * @return         True if the module initialized successfully.
00060          *                 False otherwise. Note: If you return false from here,
00061          *                 the module will be unloaded immediately, and onExit()
00062          *                 will not be called.
00063          */
00064         virtual bool onInit() = 0;
00065 
00066         /**
00067          * Called from main application when the module is about to be unloaded.
00068          *
00069          * @return         Standard return value indicating module exit status.
00070          *                 Exit status 0 means everything is ok, nonzero means
00071          *                 some kind of an error. Note that the nonzero return
00072          *                 value serves only as informative value - the module
00073          *                 unloading will still proceed even if the return value
00074          *                 is nonzero.
00075          */
00076         virtual int onExit() = 0;
00077 
00078         /**
00079          * Retrieve a descriptive module name.
00080          *
00081          * @return          Descriptive name for the module. The return value
00082          *                  length should not exceed 40 characters. Overriding
00083          *                  this virtual function is purely optional. The base
00084          *                  class implementation of this function returns an
00085          *                  empty string.
00086          */
00087         virtual std::string getDesc();
00088 
00089         /**
00090          * Returns the name of this module, as declared with DECLARE_MODULE
00091          * macro.
00092          */
00093         std::string getName() const { return m_name; }
00094 
00095         /**
00096          * Module priority; this affects network scheduling policy for sockets
00097          * of this module.
00098          */
00099         enum ModulePriority {
00100                 PR_LOW = -1,
00101                 PR_NORMAL = 0,
00102                 PR_HIGH = 1
00103         };
00104 
00105         int8_t getPriority() const { return m_priority; }
00106         void setPriority(ModulePriority pri) { m_priority = pri; }
00107 private:
00108         ModuleBase(); // Default constructor forbidden
00109 
00110         //! Platform-specific handle for the module.
00111         HNMODULE m_handle;
00112 
00113         //! This modules' priority (networking)
00114         int8_t m_priority;
00115 
00116         //! ModManager needs to access the above handle.
00117         friend class ModManager;
00118         friend struct Detail::InitializerBase;
00119 
00120         //! Name of the module, as passed to constructor
00121         std::string m_name;
00122 };
00123 
00124 /**
00125  * Use this macro in your module's entrance class (derived from ModuleBase) to
00126  * initialize Module declaration. This also makes the class a Singleton, which's
00127  * instance may be retrieved using instance() member function from now on.
00128  *
00129  * @param Class      Name of the class being declared.
00130  * @param Name       Short, single-word name of the class, e.g. "ed2k" or "hnsh"
00131  */
00132 #define DECLARE_MODULE(Class, Name)                                          \
00133         public:                                                              \
00134                 static Class& instance() { return *s_instance##Class ; }     \
00135                 Class() : ModuleBase(Name) { s_instance##Class = this; }     \
00136                 static uint8_t getPriority() {                               \
00137                         return s_instance##Class->ModuleBase::getPriority(); \
00138                 }                                                            \
00139                 static void setPriority(ModulePriority pri) {                \
00140                         s_instance##Class->ModuleBase::setPriority(pri);     \
00141                 }                                                            \
00142         private:                                                             \
00143                 static Class *s_instance##Class
00144 
00145 /**
00146  * Use this macro in your module's main implmenetation file to complete the
00147  * module implementation.
00148  *
00149  * @param Class     Name of the module's main class, derived from ModuleBase
00150  */
00151 #ifndef BUILT_IN
00152         #define IMPLEMENT_MODULE(Class)                                       \
00153                 Class* Class::s_instance##Class = 0;                          \
00154                 extern "C" DLLIMPORT ModuleBase* onInit() {                   \
00155                         return new Class();                                   \
00156                 } class Class
00157 #else
00158         #define IMPLEMENT_MODULE(Class) \
00159                 Class* Class::s_instance##Class = 0;                          \
00160                 static Detail::Initializer<Class> s_initializer
00161 #endif
00162 
00163 namespace Detail {
00164         /**
00165          * Base class for built-modules system; not to be used directly.
00166          */
00167         struct InitializerBase {
00168                 InitializerBase();
00169                 virtual ~InitializerBase();
00170                 virtual ModuleBase* doInit() = 0;
00171                 virtual void doExit() = 0;
00172         };
00173 
00174         /**
00175          * Specific initializer class for built-in modules; not to be used
00176          * directly by user code.
00177          */
00178         template<typename T>
00179         struct Initializer : InitializerBase {
00180                 virtual ModuleBase* doInit() { return new T; }
00181                 virtual void doExit() {
00182                         Log::instance().addPreStr(
00183                                 "[exit_" + T::instance().getName() + "] "
00184                         );
00185                         T::instance().onExit();
00186                         Log::instance().remPreStr(
00187                                 "[exit_" + T::instance().getName() + "] "
00188                         );
00189                 }
00190         };
00191 }
00192 
00193 /**
00194  * Central module manager, keeping track of which modules are currently
00195  * loaded, and providing an API for loading/unloading modules.
00196  */
00197 class DLLEXPORT ModManager : public Object {
00198 public:
00199         /**
00200          * Retrives the single instance of this Singleton class.
00201          */
00202         static ModManager& instance();
00203 
00204         /**
00205          * Load a module. The module is searched in standard module directories.
00206          *
00207          * @param name      Name of the module to be loaded.
00208          * @return          True if loading succeeded, false otherwise.
00209          */
00210         bool loadModule(const std::string &name);
00211 
00212         /**
00213          * Unload a module. The module should have been previously loaded with
00214          * loadModule() function.
00215          *
00216          * @param name      Module to be unloaded.
00217          * @return          True if successful, false otherwise.
00218          */
00219         bool unloadModule(const std::string &name);
00220 
00221         /**
00222          * Get the list of loaded modules.
00223          *
00224          * @param ret       Vector which is to be filled with list of all loaded
00225          *                  modules. First element in the vector pair is the
00226          *                  unix name of the module, second is the module
00227          *                  description.
00228          */
00229         void getList(
00230                 std::vector<std::pair<std::string, std::string> > *ret
00231         ) const;
00232 private:
00233         ModManager();
00234         ~ModManager();
00235         ModManager(ModManager &);
00236         ModManager& operator=(const ModManager&);
00237 
00238         //! Map of loaded modules
00239         std::map<std::string, ModuleBase*> m_list;
00240         //! Iterator for the above map
00241         typedef std::map<std::string, ModuleBase*>::iterator Iter;
00242         //! Constant iterator for the above map
00243         typedef std::map<std::string, ModuleBase*>::const_iterator CIter;
00244 
00245         friend class HydraNode;
00246         friend struct Initializer;
00247 
00248         /**
00249          * Initialize ModManager class. Should be called from HydraNode class
00250          * on application startup.
00251          */
00252         void onInit();
00253 
00254         /**
00255          * Shutdown/cleanup this class. Should be called on application
00256          * shutdown from HydraNode class.
00257          */
00258         void onExit();
00259 
00260         /**
00261          * Load a module using os-specific methods.
00262          *
00263          * @param name         Path to the module to be loaded.
00264          * @return             Module handle.
00265          *
00266          * \throws std::runtime_error if module loading fails for any reason.
00267          */
00268         HNMODULE load(const std::string &name);
00269 
00270         /**
00271          * Initialize a module using os-specific methods.
00272          *
00273          * @param plg          Module handle to be initialized, generally
00274          *                     previously returned by load().
00275          * @return             Pointer to abstract ModuleBase class representing
00276          *                     this module.
00277          *
00278          * \throws std::runtime_error if anything goes wrong.
00279          */
00280         ModuleBase* initialize(HNMODULE plg);
00281 };
00282 
00283 
00284 #endif