Open Babel  3.0
Classes | Namespaces | Macros | Functions
plugin.h File Reference
#include <openbabel/babelconfig.h>
#include <openbabel/dlhandler.h>
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <sstream>
#include <cstring>

Go to the source code of this file.

Classes

struct  CharPtrLess
 
class  OBPlugin
 

Namespaces

 OpenBabel
 

Macros

#define MAKE_PLUGIN(BaseClass)
 
#define OB_STATIC_PLUGIN(className, instanceName)
 

Functions

std::vector< std::string > EnableStaticPlugins ()
 

Detailed Description

Simplify 'plugin' classes to be discovered and/or loaded at runtime.

The code in this file makes it easy to make 'plugin' classes. These classes are derived from a base class, like OBFingerprint. The derived classes ('sub-types' like fingerprint2) usually have a single instance. Plugin classes are only discovered at runtime, so no existing code needs to be changed when adding a new derived class. In some builds the new code can be added or removed by just moving a DLL or so file. The plugin classes derived from any base class (including new ones) type can be listed from the commandline.

Step-by-Step Instructions

1) In the header file for YourBaseClass (which handles whatsits). Make sure to include the plugin.h header , derive the class from OBPlugin and in its definition add the MAKE_PLUGIN macro and a function TypeID() containing a simple descriptor of the type

class YourBaseClass : public OBPlugin
{
MAKE_PLUGIN(YourBaseClass)
const char* TypeID()
{ return "whatsits"; };
...rest of implementation, probably involving virtual functions redefined
in the sub-type classes
};

See below for what the macro contains.

2) Declare each sub-type in a class derived from the base class and give it a constructor which calls OBPlugin constructor as shown:

class YourSubType1 : public YourBaseClass
{
public:
YourSubtype1(const char* ID, bool IsDefault=false)
: YourBaseClass(ID, IsDefault){}
virtual string Description()
{ return "A description with one or more lines";};
...rest of implementation
};

Only the first line of the description is used when the subclasses are listed.

3) Declare a global instance of the sub-type class which specifies its ID. and, optionally, whether it is to be regarded as the default type of YourBaseClass.

YourSubType1 theType1("whatsit2",true);

4) The following functions are available:

YourBaseClass* YourBaseClass::FindType(const char* ID); This returns the default type when ID is NULL or empty.

To list the sub-types of any plugin class use the List which sends to cout by default (or any other ostream if specified).

OBPlugin::List("whatsits")

The ListAsString and ListAsVector functions are alternatives, usable with scripting.

It is also possible to iterate through each sub-type by the following code:

OBPlugin::PluginIterator itr;
for(itr=OBPlugin::Begin("whatsits");itr!=OBPlugin::End("whatsits");++itr)
{
itr is a std::map::const_iterator
itr->first is the ID of the subtype;
itr->second is The OBPlugin* which you will have to cast to your type
}

Since this is not the most beautiful code, it is probably better to use the List methods if possible.

YourBaseClass* MakeNewInstance();

How it works

MAKE_PLUGIN(YourBaseClass) inserts the following code into YourBaseClass:

protected:
//The collection of sub-types is in a local static variable to avoid
//any difficulties with the order of initialization of static objects.
static PluginMapType& Map()
{
static PluginMapType m;
return m;
}
//Making the map accessible to the base class (Cannot be used during construction)
virtual PluginMapType& GetMap()const
{
return Map();
}
public:
static YourBaseClass*& Default()
{
static YourBaseClass* d;
return d;
}
//Constructor registers the sub-type
YourBaseClass(const char* ID, bool IsDefault=false)
{
_id = ID;
if(ID && *ID && *ID!=' ') //do not register if ID is empty or starts with a space
{
if(IsDefault || Map().empty())
Default() = this;
Map()[ID]=this;
//Ensure YourBaseClass is registered in OBPlugin so it can be accessed from the commandline
PluginMap()[TypeID()] =this;
}
}
static YourBaseClass* FindType(const char* ID)
{
if(!ID || *ID==0)
return Default();
return static_cast<YourBaseClass*>(BaseFindType(Map(),ID));
}