summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2015-09-18 02:35:30 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2015-09-18 02:35:30 +0100
commitb99a435f52de826327ea3e4cc8cc8aaf348d5b53 (patch)
tree90fd3bf144108aa0a9d27856b3f5eb65ab6d0020
parentSupport addition and removal of plugin resolver functions (diff)
downloadlibadhocutil-b99a435f52de826327ea3e4cc8cc8aaf348d5b53.tar.bz2
libadhocutil-b99a435f52de826327ea3e4cc8cc8aaf348d5b53.tar.xz
libadhocutil-b99a435f52de826327ea3e4cc8cc8aaf348d5b53.zip
Use resolvers to load libraries automagically on demand
-rw-r--r--libadhocutil/Jamfile.jam2
-rw-r--r--libadhocutil/plugins.cpp24
-rw-r--r--libadhocutil/plugins.h9
-rw-r--r--libadhocutil/unittests/testPluginsRuntime.cpp50
4 files changed, 80 insertions, 5 deletions
diff --git a/libadhocutil/Jamfile.jam b/libadhocutil/Jamfile.jam
index 45bbeec..861509a 100644
--- a/libadhocutil/Jamfile.jam
+++ b/libadhocutil/Jamfile.jam
@@ -6,6 +6,7 @@ lib Ice : ;
lib IceUtil ;
lib pthread ;
lib curl ;
+lib dl ;
alias iceall : : : : <library>Ice <library>IceUtil <library>pthread ;
@@ -15,6 +16,7 @@ lib adhocutil :
<include>.
<library>iceall
<library>curl
+ <library>dl
<cflags>-fvisibility=hidden
<variant>release:<cflags>-flto
: :
diff --git a/libadhocutil/plugins.cpp b/libadhocutil/plugins.cpp
index 6caf34f..a1eef70 100644
--- a/libadhocutil/plugins.cpp
+++ b/libadhocutil/plugins.cpp
@@ -1,5 +1,6 @@
#include "plugins.h"
#include <string.h>
+#include <dlfcn.h>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include "buffer.h"
@@ -73,6 +74,11 @@ namespace AdHoc {
{
}
+ LoadLibraryException::LoadLibraryException(const std::string & f, const char * msg) :
+ std::runtime_error(stringbf("Failed to load library [%s]; %s", f, msg))
+ {
+ }
+
PluginManager::PluginManager() :
plugins(new PluginStore()),
resolvers(new TypePluginResolvers())
@@ -111,12 +117,30 @@ namespace AdHoc {
PluginManager::get(const std::string & n, const std::type_info & t) const
{
auto r = plugins->get<2>().equal_range(boost::make_tuple(n, std::cref(t)));
+ if (r.first == r.second) {
+ auto tr = resolvers->find(t.hash_code());
+ if (tr != resolvers->end()) {
+ if (auto lib = tr->second(t, n)) {
+ loadLibrary(*lib);
+ }
+ }
+ r = plugins->get<2>().equal_range(boost::make_tuple(n, std::cref(t)));
+ }
if (r.first != r.second) {
return (*r.first);
}
throw NoSuchPluginException(n, t);
}
+ void
+ PluginManager::loadLibrary(const std::string & f)
+ {
+ void * handle = dlopen(f.c_str(), RTLD_NOW);
+ if (!handle) {
+ throw LoadLibraryException(f, dlerror());
+ }
+ }
+
std::set<PluginPtr>
PluginManager::getAll() const
{
diff --git a/libadhocutil/plugins.h b/libadhocutil/plugins.h
index 8b8efac..03d59fb 100644
--- a/libadhocutil/plugins.h
+++ b/libadhocutil/plugins.h
@@ -63,6 +63,13 @@ namespace AdHoc {
DuplicateResolverException(const std::type_info &);
};
+ /// Thrown when an attempt to load a library fails.
+ class LoadLibraryException : public std::runtime_error {
+ public:
+ /// Constuctor taking syscall error details.
+ LoadLibraryException(const std::string & f, const char * msg);
+ };
+
template <typename T>
/// Typed plugin and handle to implementation.
class DLL_PUBLIC PluginOf : public Plugin {
@@ -171,6 +178,8 @@ namespace AdHoc {
static PluginManager * getDefault();
private:
+ static void loadLibrary(const std::string &);
+
typedef boost::multi_index_container<PluginPtr,
boost::multi_index::indexed_by<
boost::multi_index::ordered_non_unique<boost::multi_index::member<Plugin, const std::string, &Plugin::name>>,
diff --git a/libadhocutil/unittests/testPluginsRuntime.cpp b/libadhocutil/unittests/testPluginsRuntime.cpp
index 2b13913..aa1dcf1 100644
--- a/libadhocutil/unittests/testPluginsRuntime.cpp
+++ b/libadhocutil/unittests/testPluginsRuntime.cpp
@@ -13,7 +13,9 @@ auto variant = selfExe.parent_path().leaf();
auto toolset = selfExe.parent_path().parent_path().leaf();
auto lib = rootDir / "bin" / toolset / variant / "libutilTestClasses.so";
-static boost::optional<std::string> resolver(const std::type_info &, const std::string &);
+static boost::optional<std::string> nullResolver(const std::type_info &, const std::string &);
+static boost::optional<std::string> badResolver(const std::type_info &, const std::string &);
+static boost::optional<std::string> goodResolver(const std::type_info &, const std::string &);
BOOST_AUTO_TEST_CASE( ready )
{
@@ -36,20 +38,58 @@ BOOST_AUTO_TEST_CASE( loadAndUnloadlib )
}
boost::optional<std::string>
-resolver(const std::type_info &, const std::string &)
+nullResolver(const std::type_info &, const std::string &)
{
- return std::string();
+ return nullptr;
+}
+
+boost::optional<std::string>
+badResolver(const std::type_info &, const std::string &)
+{
+ return std::string("dontexist");
+}
+
+boost::optional<std::string>
+goodResolver(const std::type_info & t, const std::string & n)
+{
+ BOOST_REQUIRE_EQUAL(typeid(BaseThing), t);
+ BOOST_REQUIRE_EQUAL("ImplOfThing", n);
+ return lib.string();
}
BOOST_AUTO_TEST_CASE( addAndRemoveResolver )
{
auto pm = AdHoc::PluginManager::getDefault();
BOOST_REQUIRE_EQUAL(0, pm->countResolvers());
- pm->addResolver<BaseThing>(resolver);
+ pm->addResolver<BaseThing>(nullResolver);
BOOST_REQUIRE_EQUAL(1, pm->countResolvers());
- BOOST_REQUIRE_THROW(pm->addResolver<BaseThing>(resolver), DuplicateResolverException);
+ BOOST_REQUIRE_THROW(pm->addResolver<BaseThing>(nullResolver), DuplicateResolverException);
BOOST_REQUIRE_EQUAL(1, pm->countResolvers());
pm->removeResolver<BaseThing>();
BOOST_REQUIRE_EQUAL(0, pm->countResolvers());
}
+BOOST_AUTO_TEST_CASE( null )
+{
+ auto pm = AdHoc::PluginManager::getDefault();
+ pm->addResolver<BaseThing>(nullResolver);
+ BOOST_REQUIRE_THROW(pm->get<BaseThing>("ImplOfThing"), AdHoc::NoSuchPluginException);
+ pm->removeResolver<BaseThing>();
+}
+
+BOOST_AUTO_TEST_CASE( bad )
+{
+ auto pm = AdHoc::PluginManager::getDefault();
+ pm->addResolver<BaseThing>(badResolver);
+ BOOST_REQUIRE_THROW(pm->get<BaseThing>("ImplOfThing"), AdHoc::LoadLibraryException);
+ pm->removeResolver<BaseThing>();
+}
+
+BOOST_AUTO_TEST_CASE( good )
+{
+ auto pm = AdHoc::PluginManager::getDefault();
+ pm->addResolver<BaseThing>(goodResolver);
+ BOOST_REQUIRE(pm->get<BaseThing>("ImplOfThing"));
+ pm->removeResolver<BaseThing>();
+}
+