Logo Search packages:      
Sourcecode: poco version File versions

ClassLoader.h

//
// ClassLoader.h
//
// $Id: //poco/1.4/Foundation/include/Poco/ClassLoader.h#1 $
//
// Library: Foundation
// Package: SharedLibrary
// Module:  ClassLoader
//
// Definition of the ClassLoader class.
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
// 
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//


#ifndef Foundation_ClassLoader_INCLUDED
#define Foundation_ClassLoader_INCLUDED


#include "Poco/Foundation.h"
#include "Poco/MetaObject.h"
#include "Poco/Manifest.h"
#include "Poco/SharedLibrary.h"
#include "Poco/Mutex.h"
#include "Poco/Exception.h"
#include <map>


namespace Poco {


template <class Base>
00056 class ClassLoader
      /// The ClassLoader loads C++ classes from shared libraries
      /// at runtime. It must be instantiated with a root class
      /// of the loadable classes.
      /// For a class to be loadable from a library, the library
      /// must provide a Manifest of all the classes it contains.
      /// The Manifest for a shared library can be easily built
      /// with the help of the macros in the header file
      /// "Foundation/ClassLibrary.h".
      ///
      /// Starting with POCO release 1.3, a class library can
      /// export multiple manifests. In addition to the default
      /// (unnamed) manifest, multiple named manifests can
      /// be exported, each having a different base class.
      ///
      /// There is one important restriction: one instance of
      /// ClassLoader can only load one manifest from a class
      /// library.
{
public:
      typedef AbstractMetaObject<Base> Meta;
      typedef Manifest<Base> Manif;
      typedef void (*InitializeLibraryFunc)();
      typedef void (*UninitializeLibraryFunc)();
      typedef bool (*BuildManifestFunc)(ManifestBase*);

00082       struct LibraryInfo
      {
            SharedLibrary* pLibrary;
            const Manif*   pManifest;
            int            refCount;
      };
      typedef std::map<std::string, LibraryInfo> LibraryMap;

00090       class Iterator
            /// The ClassLoader's very own iterator class.
      {
      public:
            typedef std::pair<std::string, const Manif*> Pair;

            Iterator(const typename LibraryMap::const_iterator& it)
            {
                  _it = it;
            }
            Iterator(const Iterator& it)
            {
                  _it = it._it;
            }
            ~Iterator()
            {
            }
            Iterator& operator = (const Iterator& it)
            {
                  _it = it._it;
                  return *this;
            }
            inline bool operator == (const Iterator& it) const
            {
                  return _it == it._it;
            }
            inline bool operator != (const Iterator& it) const
            {
                  return _it != it._it;
            }
            Iterator& operator ++ () // prefix
            {
                  ++_it;
                  return *this;
            }
            Iterator operator ++ (int) // postfix
            {
                  Iterator result(_it);
                  ++_it;
                  return result;
            }
            inline const Pair* operator * () const
            {
                  _pair.first  = _it->first;
                  _pair.second = _it->second.pManifest;
                  return &_pair;
            }
            inline const Pair* operator -> () const
            {
                  _pair.first  = _it->first;
                  _pair.second = _it->second.pManifest;
                  return &_pair;
            }

      private:
            typename LibraryMap::const_iterator _it;
            mutable Pair _pair;
      };

00149       ClassLoader()
            /// Creates the ClassLoader.
      {
      }

00154       virtual ~ClassLoader()
            /// Destroys the ClassLoader.
      {
            for (typename LibraryMap::const_iterator it = _map.begin(); it != _map.end(); ++it)
            {
                  delete it->second.pLibrary;
                  delete it->second.pManifest;
            }
      }

00164       void loadLibrary(const std::string& path, const std::string& manifest)
            /// Loads a library from the given path, using the given manifest. 
            /// Does nothing if the library is already loaded.
            /// Throws a LibraryLoadException if the library
            /// cannot be loaded or does not have a Manifest.
            /// If the library exports a function named "pocoInitializeLibrary",
            /// this function is executed.
            /// If called multiple times for the same library,
            /// the number of calls to unloadLibrary() must be the same
            /// for the library to become unloaded.
      {
            FastMutex::ScopedLock lock(_mutex);

            typename LibraryMap::iterator it = _map.find(path);
            if (it == _map.end())
            {
                  LibraryInfo li;
                  li.pLibrary  = new SharedLibrary(path);
                  li.pManifest = new Manif();
                  li.refCount  = 1;
                  try
                  {
                        std::string pocoBuildManifestSymbol("pocoBuildManifest");
                        pocoBuildManifestSymbol.append(manifest);
                        if (li.pLibrary->hasSymbol("pocoInitializeLibrary"))
                        {
                              InitializeLibraryFunc initializeLibrary = (InitializeLibraryFunc) li.pLibrary->getSymbol("pocoInitializeLibrary");
                              initializeLibrary();
                        }
                        if (li.pLibrary->hasSymbol(pocoBuildManifestSymbol))
                        {
                              BuildManifestFunc buildManifest = (BuildManifestFunc) li.pLibrary->getSymbol(pocoBuildManifestSymbol);
                              if (buildManifest(const_cast<Manif*>(li.pManifest)))
                                    _map[path] = li;
                              else
                                    throw LibraryLoadException(std::string("Manifest class mismatch in ") + path, manifest);
                        }
                        else throw LibraryLoadException(std::string("No manifest in ") + path, manifest);
                  }
                  catch (...)
                  {
                        delete li.pLibrary;
                        delete li.pManifest;
                        throw;
                  }
            }
            else
            {
                  ++it->second.refCount;
            }
      }

00216       void loadLibrary(const std::string& path)
            /// Loads a library from the given path. Does nothing
            /// if the library is already loaded.
            /// Throws a LibraryLoadException if the library
            /// cannot be loaded or does not have a Manifest.
            /// If the library exports a function named "pocoInitializeLibrary",
            /// this function is executed.
            /// If called multiple times for the same library,
            /// the number of calls to unloadLibrary() must be the same
            /// for the library to become unloaded.
            ///
            /// Equivalent to loadLibrary(path, "").
      {
            loadLibrary(path, "");
      }
            
00232       void unloadLibrary(const std::string& path)
            /// Unloads the given library. 
            /// Be extremely cautious when unloading shared libraries.
            /// If objects from the library are still referenced somewhere,
            /// a total crash is very likely.
            /// If the library exports a function named "pocoUninitializeLibrary",
            /// this function is executed before it is unloaded.
            /// If loadLibrary() has been called multiple times for the same
            /// library, the number of calls to unloadLibrary() must be the same
            /// for the library to become unloaded.
      {
            FastMutex::ScopedLock lock(_mutex);

            typename LibraryMap::iterator it = _map.find(path);
            if (it != _map.end())
            {
                  if (--it->second.refCount == 0)
                  {
                        if (it->second.pLibrary->hasSymbol("pocoUninitializeLibrary"))
                        {
                              UninitializeLibraryFunc uninitializeLibrary = (UninitializeLibraryFunc) it->second.pLibrary->getSymbol("pocoUninitializeLibrary");
                              uninitializeLibrary();
                        }
                        delete it->second.pManifest;
                        it->second.pLibrary->unload();
                        delete it->second.pLibrary;
                        _map.erase(it);
                  }
            }
            else throw NotFoundException(path);
      }

00264       const Meta* findClass(const std::string& className) const
            /// Returns a pointer to the MetaObject for the given
            /// class, or a null pointer if the class is not known.
      {
            FastMutex::ScopedLock lock(_mutex);

            for (typename LibraryMap::const_iterator it = _map.begin(); it != _map.end(); ++it)
            {
                  const Manif* pManif = it->second.pManifest;
                  typename Manif::Iterator itm = pManif->find(className);
                  if (itm != pManif->end())
                        return *itm;
            }
            return 0;
      }
      
00280       const Meta& classFor(const std::string& className) const
            /// Returns a reference to the MetaObject for the given
            /// class. Throws a NotFoundException if the class
            /// is not known.
      {
            const Meta* pMeta = findClass(className);
            if (pMeta)
                  return *pMeta;
            else
                  throw NotFoundException(className);
      }
      
00292       Base* create(const std::string& className) const
            /// Creates an instance of the given class.
            /// Throws a NotFoundException if the class
            /// is not known.
      {
            return classFor(className).create();
      }
      
00300       Base& instance(const std::string& className) const
            /// Returns a reference to the sole instance of
            /// the given class. The class must be a singleton,
            /// otherwise an InvalidAccessException will be thrown.
            /// Throws a NotFoundException if the class
            /// is not known.
      {
            return classFor(className).instance();
      }
      
00310       bool canCreate(const std::string& className) const
            /// Returns true if create() can create new instances
            /// of the class.
      {
            return classFor(className).canCreate();
      }

00317       void destroy(const std::string& className, Base* pObject) const
            /// Destroys the object pObject points to.
            /// Does nothing if object is not found.
      {
            classFor(className).destroy(pObject);
      }

00324       bool isAutoDelete(const std::string& className, Base* pObject) const
            /// Returns true if the object is automatically
            /// deleted by its meta object.
      {
            return classFor(className).isAutoDelete(pObject);
      }
      
00331       const Manif* findManifest(const std::string& path) const
            /// Returns a pointer to the Manifest for the given
            /// library, or a null pointer if the library has not been loaded.
      {
            FastMutex::ScopedLock lock(_mutex);

            typename LibraryMap::const_iterator it = _map.find(path);
            if (it != _map.end())
                  return it->second.pManifest;
            else
                  return 0;
      }
      
00344       const Manif& manifestFor(const std::string& path) const
            /// Returns a reference to the Manifest for the given library
            /// Throws a NotFoundException if the library has not been loaded.
      {
            const Manif* pManif = findManifest(path);
            if (pManif)
                  return *pManif;
            else
                  throw NotFoundException(path);
      }

00355       bool isLibraryLoaded(const std::string& path) const
            /// Returns true if the library with the given name
            /// has already been loaded.
      {
            return findManifest(path) != 0;
      }

      Iterator begin() const
      {
            FastMutex::ScopedLock lock(_mutex);

            return Iterator(_map.begin());
      }

      Iterator end() const
      {
            FastMutex::ScopedLock lock(_mutex);

            return Iterator(_map.end());
      }

private:
      LibraryMap _map;
      mutable FastMutex _mutex;
};


} // namespace Poco


#endif // Foundation_ClassLoader_INCLUDED

Generated by  Doxygen 1.6.0   Back to index