00001
00019 #include "config.h"
00020 #include "libnebular.hpp"
00021 #include "libnebular-plugin.hpp"
00022 #include "utils.hpp"
00023
00024 #include <list>
00025
00026 #include <loki/Singleton.h>
00027
00028 #if __GNUC__
00029
00030
00031 #include <dlfcn.h>
00032
00033 #include <dirent.h>
00034
00035 #include <sys/types.h>
00036
00037 #else
00038 #error Some code needs to be ported
00039 #endif // __GNUC__
00040
00041 namespace libnebular{
00042 using namespace std;
00043
00054 class DLLibWrapper{
00055 #ifdef __GNUC__
00056 private:
00057 struct Impl_;
00058 boost::shared_ptr<Impl_> pimpl_;
00059
00060 public:
00062 DLLibWrapper(const string &newUrl):
00063 pimpl_(
00064 new Impl_(
00065 newUrl
00066 )
00067 )
00068 {
00071 }
00073 ~DLLibWrapper() {}
00074
00078 void open(){
00079 pimpl_->open();
00080 }
00084 void close(){
00085 pimpl_->close();
00086 }
00087
00089 template<typename F> F get(const string &symbolName){
00090 return pimpl_->get<F>(symbolName);
00091 }
00092
00093 private:
00094
00095 struct Impl_{
00096 string url;
00097 void *dlHandle;
00098
00099 Impl_(const string &newUrl):
00100 url(newUrl),
00101 dlHandle(NULL)
00102 {}
00103
00104 ~Impl_() {
00105 if(dlHandle){
00106 close();
00107 }
00108 }
00109
00113 void open(){
00114 if(dlHandle != NULL){
00116 return;
00117 }
00118
00119 dlHandle = dlopen(
00120 url.c_str(),
00122 RTLD_NOW |
00123 RTLD_GLOBAL
00124 );
00125 if(!( dlHandle != NULL )){
00126 throw LIBNEBULAR_ERROR(
00127 string("Error loading library from \"") + url +"\": " +
00128 string(dlerror())
00129 );
00130 }
00131 }
00135 void close(){
00136 bool ok;
00137 ok = (dlclose(
00138 dlHandle
00139 ) == 0);
00140 if(!( ok )){
00141 Log::warning(
00142 string("Error closing library \"") + url +"\": " +
00143 string(dlerror())
00144 );
00145 }
00146 }
00147
00149 template<typename F> F get(const string &symbolName){
00150
00151 if(dlHandle == NULL){
00152 open();
00153 }
00154
00155 F symbol = reinterpret_cast<F>(
00156 dlsym(dlHandle, symbolName.c_str())
00157 );
00158
00160 char *errorStr;
00161 if ((errorStr = dlerror()) != NULL) {
00162 throw LIBNEBULAR_ERROR(
00163 string("Error loading library from \"") + url +"\": " +
00164 string(errorStr)
00165 );
00166 }
00167
00168 return symbol;
00169 }
00170
00171 };
00172 #else // __GNUC__
00173
00174 #error Please provide appropriate DL Library wrapper
00175
00176 #endif
00177 };
00178
00179
00180
00181
00182 class PicHandlerMgr;
00183
00185 class Core::Impl_{
00186 public:
00187 typedef list< DLLibWrapper > PluginFileList;
00188 typedef list< boost::shared_ptr<PicHandlerMgr> > PluginList;
00189
00190 private:
00191
00192 friend class Core;
00193 Impl_():
00194 isPluginRegDone_(false),
00195 pluginDir(".")
00196 {}
00197
00199 typedef Loki::SingletonHolder<
00200 Core
00201 > CoreHolder;
00202
00203 bool isPluginRegDone_;
00204 std::string pluginDir;
00205
00206 PluginFileList pluginFiles;
00207 PluginList plugins;
00208
00209 public:
00210 ~Impl_() {}
00211
00212 PluginList::iterator pluginBegin(){
00213 return plugins.begin();
00214 }
00215 PluginList::iterator pluginEnd(){
00216 return plugins.end();
00217 }
00218 };
00219
00220
00221 Core::Core():
00222 pimpl_(new Impl_)
00223 {}
00224
00225 Core::~Core() {}
00226
00227 void Core::registerPlugins(){
00231 struct PluginFileEnum{
00232 string dirName;
00233
00234 int numFiles;
00235
00236 static int isPluginFile(const struct ::dirent *aDirEnt){
00237 const string fileName = aDirEnt->d_name;
00238 const string prefix = "libnebular-plugin-";
00239 const string suffix = ".so";
00240
00241 if(
00242 fileName.length() > prefix.length() + suffix.length() &&
00243 fileName.substr(0, prefix.length()) == prefix &&
00244 fileName.substr(fileName.length() - suffix.length()) == suffix
00245 ){
00246 return int(true);
00247 }
00248 return int(false);
00249 }
00250
00251 void enumerate(list<string> &newList){
00252 #if __GNUC__
00253
00254 newList = list<string>();
00255
00256 struct ::dirent **dirEntriesRaw;
00257 numFiles = ::scandir(
00258 dirName.c_str(),
00259 &dirEntriesRaw,
00260 isPluginFile,
00261 ::alphasort
00262 );
00263 boost::shared_ptr<
00264 struct ::dirent *
00265 > dirEntries(
00266 dirEntriesRaw,
00267 CArrayOfArrayDeleter(numFiles)
00268 );
00269
00270 const string dirFileSep = "/";
00271 if(numFiles >= 0){
00272 for(int idxFile = 0; idxFile < numFiles; idxFile++){
00273 newList.push_back(
00274 dirName + dirFileSep + dirEntries.get()[idxFile]->d_name
00275 );
00276 }
00277 }else{
00278 throw LIBNEBULAR_ERROR("At plugin directory file enumeration");
00279 }
00280 #endif // __GNUC__
00281 }
00282
00283 PluginFileEnum(const string &newDirName):
00284 dirName(newDirName)
00285 {}
00286
00287 ~PluginFileEnum() {}
00288 } pluginFileEnum(
00289 pimpl_->pluginDir
00290 );
00291
00292 list<string> pluginFile;
00293 pluginFileEnum.enumerate(pluginFile);
00294
00295
00296 pimpl_->plugins = Impl_::PluginList();
00297 pimpl_->pluginFiles = Impl_::PluginFileList();
00298
00299 for(
00300 list<string>::iterator curPluginFile = pluginFile.begin();
00301 curPluginFile != pluginFile.end();
00302 curPluginFile++
00303 ){
00304 DLLibWrapper pluginLib(*curPluginFile);
00305
00306 pimpl_->pluginFiles.push_back(
00307 pluginLib
00308 );
00309
00310 pluginLib.open();
00311 typedef boost::shared_ptr<PicHandlerMgr> (*GetPicHandlerMgrPtr)();
00312 GetPicHandlerMgrPtr getNewCurrPicHandlerMgr =
00313 pluginLib.get<GetPicHandlerMgrPtr>(
00314 "getNewCurrPicHandlerMgr"
00315 );
00316
00317 pimpl_->plugins.push_back(
00318 getNewCurrPicHandlerMgr()
00319 );
00320 }
00321
00322 if(pimpl_->pluginFiles.empty()){
00323 Log::warning("No plugins found");
00324 }
00325
00326 pimpl_->isPluginRegDone_ = true;
00327 }
00328
00329 void Core::makePluginsRegistered(){
00330 if(!isPluginRegDone()){
00331 registerPlugins();
00332 }
00333 }
00334
00335 bool Core::isPluginRegDone() const{
00336 return pimpl_->isPluginRegDone_;
00337 }
00338
00339 void Core::setPluginDir(const std::string &newPluginDir){
00340 pimpl_->pluginDir = newPluginDir;
00341 }
00342
00343 Core &Core::get(){
00344 return Impl_::CoreHolder::Instance();
00345 }
00346
00347
00348
00349
00350 class PluginIteratorImpl_{
00351 private:
00352 friend class PluginIterator;
00353
00354 typedef Core::Impl_::PluginList::iterator BaseIterator;
00355 BaseIterator i;
00356
00357 public:
00359
00360 static PluginIterator toPluginIterator(
00361 BaseIterator newPluginListI
00362 ){
00363 PluginIterator newPluginI;
00364 newPluginI.pimpl_->i = newPluginListI;
00365 return newPluginI;
00366 }
00367 };
00368
00369
00370 PluginIterator::PluginIterator():
00371 pimpl_(new Impl_)
00372 {}
00373 PluginIterator::~PluginIterator() {}
00374
00375 PluginIterator::PluginIterator(
00376 const PluginIterator &src
00377 ):
00378 pimpl_(new Impl_)
00379 {
00380 (*this) = src;
00381 }
00382 PluginIterator& PluginIterator::operator=(
00383 const PluginIterator &src
00384 ){
00385 (pimpl_->i) = (src.pimpl_->i);
00386 return *this;
00387 }
00388
00389 PluginIterator &PluginIterator::operator++(){
00390 ++( pimpl_->i );
00391 return *this;
00392 }
00393 PluginIterator PluginIterator::operator++(int){
00394 PluginIterator prev = *this;
00395 ( pimpl_->i++ );
00396 return prev;
00397 }
00398 bool PluginIterator::operator!=(const PluginIterator &b) const{
00399 return ( pimpl_->i != b.pimpl_->i );
00400 }
00401 bool PluginIterator::operator==(const PluginIterator &b) const{
00402 return ( pimpl_->i == b.pimpl_->i );
00403 }
00404 PluginIterator::value_type& PluginIterator::operator*(){
00405 return *( *( pimpl_->i ) );
00406 }
00407 PluginIterator::value_type* PluginIterator::operator->(){
00408 return ( *( pimpl_->i ) ).get();
00409 }
00410
00411
00412 PluginIterator pluginBegin(){
00413 return PluginIteratorImpl_::toPluginIterator(
00414 Core::get().pimpl_->pluginBegin()
00415 );
00416 }
00417 PluginIterator pluginEnd(){
00418 return PluginIteratorImpl_::toPluginIterator(
00419 Core::get().pimpl_->pluginEnd()
00420 );
00421 }
00422
00423
00424
00425 }
00426