summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
authorBenoit Foucher <benoit@zeroc.com>2015-01-30 16:52:49 +0100
committerBenoit Foucher <benoit@zeroc.com>2015-01-30 16:52:49 +0100
commit94d6c3e457a486b77bef98ccee0537d6e7a757ae (patch)
treeb8e6be293019a4efe90b11a219abe631ac95e69f /cpp
parentRename test::Controller > Test::Controller (diff)
downloadice-94d6c3e457a486b77bef98ccee0537d6e7a757ae.tar.bz2
ice-94d6c3e457a486b77bef98ccee0537d6e7a757ae.tar.xz
ice-94d6c3e457a486b77bef98ccee0537d6e7a757ae.zip
Added support for registration of plugin factories
Diffstat (limited to 'cpp')
-rw-r--r--cpp/include/Ice/Initialize.h3
-rw-r--r--cpp/src/Ice/Initialize.cpp7
-rw-r--r--cpp/src/Ice/PluginManagerI.cpp230
-rw-r--r--cpp/src/Ice/PluginManagerI.h13
-rw-r--r--cpp/test/Ice/plugin/Client.cpp56
5 files changed, 234 insertions, 75 deletions
diff --git a/cpp/include/Ice/Initialize.h b/cpp/include/Ice/Initialize.h
index 5cd0b59d9ac..e90d98803d2 100644
--- a/cpp/include/Ice/Initialize.h
+++ b/cpp/include/Ice/Initialize.h
@@ -120,6 +120,9 @@ ICE_API OutputStreamPtr createOutputStream(const CommunicatorPtr&, const Encodin
ICE_API LoggerPtr getProcessLogger();
ICE_API void setProcessLogger(const LoggerPtr&);
+typedef Ice::Plugin* (*PLUGIN_FACTORY)(const ::Ice::CommunicatorPtr&, const std::string&, const ::Ice::StringSeq&);
+ICE_API void registerPluginFactory(const std::string&, PLUGIN_FACTORY, bool);
+
}
namespace IceInternal
diff --git a/cpp/src/Ice/Initialize.cpp b/cpp/src/Ice/Initialize.cpp
index 21ff3f62c80..e17e405bf7b 100644
--- a/cpp/src/Ice/Initialize.cpp
+++ b/cpp/src/Ice/Initialize.cpp
@@ -16,6 +16,7 @@
#include <Ice/StreamI.h>
#include <Ice/LoggerI.h>
#include <Ice/Instance.h>
+#include <Ice/PluginManagerI.h>
#include <IceUtil/Mutex.h>
#include <IceUtil/MutexPtrLock.h>
#include <IceUtil/StringConverter.h>
@@ -351,6 +352,12 @@ Ice::setProcessLogger(const LoggerPtr& logger)
processLogger = logger;
}
+void
+Ice::registerPluginFactory(const std::string& name, PLUGIN_FACTORY factory, bool loadOnInitialize)
+{
+ PluginManagerI::registerPluginFactory(name, factory, loadOnInitialize);
+}
+
InstancePtr
IceInternal::getInstance(const CommunicatorPtr& communicator)
{
diff --git a/cpp/src/Ice/PluginManagerI.cpp b/cpp/src/Ice/PluginManagerI.cpp
index 77076a13771..e43a8441cc2 100644
--- a/cpp/src/Ice/PluginManagerI.cpp
+++ b/cpp/src/Ice/PluginManagerI.cpp
@@ -13,7 +13,6 @@
#include <Ice/Communicator.h>
#include <Ice/Properties.h>
#include <Ice/LoggerUtil.h>
-#include <Ice/Initialize.h>
#include <Ice/Instance.h>
#include <Ice/LocalException.h>
@@ -23,7 +22,55 @@ using namespace IceInternal;
const char * const Ice::PluginManagerI::_kindOfObject = "plugin";
-typedef Ice::Plugin* (*PLUGIN_FACTORY)(const CommunicatorPtr&, const string&, const StringSeq&);
+namespace
+{
+
+map<string, PLUGIN_FACTORY>* factories = 0;
+vector<string>* loadOnInitialization = 0;
+
+class PluginFactoryDestroy
+{
+public:
+
+ ~PluginFactoryDestroy()
+ {
+ delete factories;
+ factories = 0;
+
+ delete loadOnInitialization;
+ loadOnInitialization = 0;
+ }
+};
+PluginFactoryDestroy destroy;
+
+}
+
+void
+Ice::PluginManagerI::registerPluginFactory(const std::string& name, PLUGIN_FACTORY factory, bool loadOnInit)
+{
+ if(factories == 0)
+ {
+ factories = new map<string, PLUGIN_FACTORY>();
+ }
+ if(loadOnInitialization == 0)
+ {
+ loadOnInitialization = new vector<string>();
+ }
+
+ map<string, PLUGIN_FACTORY>::const_iterator p = factories->find(name);
+ if(p == factories->end())
+ {
+ factories->insert(make_pair(name, factory));
+ if(loadOnInit)
+ {
+ if(loadOnInitialization == 0)
+ {
+ loadOnInitialization = new vector<string>();
+ }
+ loadOnInitialization->push_back(name);
+ }
+ }
+}
void
Ice::PluginManagerI::initializePlugins()
@@ -193,10 +240,48 @@ Ice::PluginManagerI::loadPlugins(int& argc, char* argv[])
StringSeq cmdArgs = argsToStringSeq(argc, argv);
+ const string prefix = "Ice.Plugin.";
+ PropertiesPtr properties = _communicator->getProperties();
+ PropertyDict plugins = properties->getPropertiesForPrefix(prefix);
+
+ //
+ // First, load static plugin factories which were setup to load on
+ // communicator initialization. If a matching plugin property is
+ // set, we load the plugin with the plugin specification. The
+ // entryPoint will be ignored but the rest of the plugin
+ // specification might be used.
+ //
+ if(loadOnInitialization)
+ {
+ for(vector<string>::const_iterator p = loadOnInitialization->begin(); p != loadOnInitialization->end(); ++p)
+ {
+ string property = prefix + *p;
+ PropertyDict::iterator r = plugins.find(property + ".cpp");
+ if(r == plugins.end())
+ {
+ r = plugins.find(property);
+ }
+ else
+ {
+ plugins.erase(property);
+ }
+
+ if(r != plugins.end())
+ {
+ loadPlugin(*p, r->second, cmdArgs);
+ plugins.erase(r);
+ }
+ else
+ {
+ loadPlugin(*p, "", cmdArgs);
+ }
+ }
+ }
+
//
- // Load and initialize the plug-ins defined in the property set
- // with the prefix "Ice.Plugin.". These properties should
- // have the following format:
+ // Next, load and initialize the plug-ins defined in the property
+ // set with the prefix "Ice.Plugin.". These properties should have
+ // the following format:
//
// Ice.Plugin.name[.<language>]=entry_point [args]
//
@@ -204,10 +289,6 @@ Ice::PluginManagerI::loadPlugins(int& argc, char* argv[])
// specified plug-ins in the specified order, then load any
// remaining plug-ins.
//
- const string prefix = "Ice.Plugin.";
- PropertiesPtr properties = _communicator->getProperties();
- PropertyDict plugins = properties->getPropertiesForPrefix(prefix);
-
StringSeq loadOrder = properties->getPropertyAsList("Ice.PluginLoadOrder");
for(StringSeq::const_iterator p = loadOrder.begin(); p != loadOrder.end(); ++p)
{
@@ -220,14 +301,15 @@ Ice::PluginManagerI::loadPlugins(int& argc, char* argv[])
throw ex;
}
- PropertyDict::iterator r = plugins.find("Ice.Plugin." + name + ".cpp");
+ string property = prefix + name;
+ PropertyDict::iterator r = plugins.find(property + ".cpp");
if(r == plugins.end())
{
- r = plugins.find("Ice.Plugin." + name);
+ r = plugins.find(property);
}
else
{
- plugins.erase("Ice.Plugin." + name);
+ plugins.erase(property);
}
if(r != plugins.end())
@@ -270,7 +352,7 @@ Ice::PluginManagerI::loadPlugins(int& argc, char* argv[])
loadPlugin(name, p->second, cmdArgs);
plugins.erase(p);
- plugins.erase("Ice.Plugin." + name);
+ plugins.erase(prefix + name);
}
else
{
@@ -286,7 +368,7 @@ Ice::PluginManagerI::loadPlugins(int& argc, char* argv[])
//
// Is there a .cpp entry?
//
- PropertyDict::iterator q = plugins.find("Ice.Plugin." + name + ".cpp");
+ PropertyDict::iterator q = plugins.find(prefix + name + ".cpp");
if(q != plugins.end())
{
plugins.erase(p);
@@ -305,64 +387,91 @@ void
Ice::PluginManagerI::loadPlugin(const string& name, const string& pluginSpec, StringSeq& cmdArgs)
{
assert(_communicator);
- //
- // Split the entire property value into arguments. An entry point containing spaces
- // must be enclosed in quotes.
- //
+
+ string entryPoint;
StringSeq args;
- try
- {
- args = IceUtilInternal::Options::split(pluginSpec);
- }
- catch(const IceUtilInternal::BadOptException& ex)
+ if(!pluginSpec.empty())
{
- PluginInitializationException e(__FILE__, __LINE__);
- e.reason = "invalid arguments for plug-in `" + name + "':\n" + ex.reason;
- throw e;
- }
+ //
+ // Split the entire property value into arguments. An entry point containing spaces
+ // must be enclosed in quotes.
+ //
+ try
+ {
+ args = IceUtilInternal::Options::split(pluginSpec);
+ }
+ catch(const IceUtilInternal::BadOptException& ex)
+ {
+ PluginInitializationException e(__FILE__, __LINE__);
+ e.reason = "invalid arguments for plug-in `" + name + "':\n" + ex.reason;
+ throw e;
+ }
- assert(!args.empty());
+ assert(!args.empty());
- //
- // Shift the arguments.
- //
- const string entryPoint = args[0];
- args.erase(args.begin());
+ //
+ // Shift the arguments.
+ //
+ entryPoint = args[0];
+ args.erase(args.begin());
+
+ //
+ // Convert command-line options into properties. First we
+ // convert the options from the plug-in configuration, then
+ // we convert the options from the application command-line.
+ //
+ PropertiesPtr properties = _communicator->getProperties();
+ args = properties->parseCommandLineOptions(name, args);
+ cmdArgs = properties->parseCommandLineOptions(name, cmdArgs);
+ }
+
+ PluginPtr plugin;
+ PLUGIN_FACTORY factory = 0;
+ DynamicLibraryPtr library;
//
- // Convert command-line options into properties. First we
- // convert the options from the plug-in configuration, then
- // we convert the options from the application command-line.
+ // Always check the static plugin factory table first, it takes
+ // precedence over the the entryPoint specified in the plugin
+ // property value.
//
- PropertiesPtr properties = _communicator->getProperties();
- args = properties->parseCommandLineOptions(name, args);
- cmdArgs = properties->parseCommandLineOptions(name, cmdArgs);
+ if(factories)
+ {
+ map<string, PLUGIN_FACTORY>::const_iterator p = factories->find(name);
+ if(p != factories->end())
+ {
+ factory = p->second;
+ }
+ }
//
- // Load the entry point symbol.
+ // If we didn't find the factory, get the factory using the entry
+ // point symbol.
//
- PluginPtr plugin;
- DynamicLibraryPtr library = new DynamicLibrary();
- DynamicLibrary::symbol_type sym = library->loadEntryPoint(entryPoint);
- if(sym == 0)
+ if(!factory)
{
- ostringstream out;
- string msg = library->getErrorMessage();
- out << "unable to load entry point `" << entryPoint << "'";
- if(!msg.empty())
+ assert(!entryPoint.empty());
+ library = new DynamicLibrary();
+ DynamicLibrary::symbol_type sym = library->loadEntryPoint(entryPoint);
+ if(sym == 0)
{
- out << ": " + msg;
+ ostringstream out;
+ string msg = library->getErrorMessage();
+ out << "unable to load entry point `" << entryPoint << "'";
+ if(!msg.empty())
+ {
+ out << ": " + msg;
+ }
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = out.str();
+ throw ex;
}
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = out.str();
- throw ex;
+ factory = reinterpret_cast<PLUGIN_FACTORY>(sym);
}
//
// Invoke the factory function. No exceptions can be raised
// by the factory function because it's declared extern "C".
//
- PLUGIN_FACTORY factory = reinterpret_cast<PLUGIN_FACTORY>(sym);
plugin = factory(_communicator, name, args);
if(!plugin)
{
@@ -378,7 +487,10 @@ Ice::PluginManagerI::loadPlugin(const string& name, const string& pluginSpec, St
info.plugin = plugin;
_plugins.push_back(info);
- _libraries->add(library);
+ if(library)
+ {
+ _libraries->add(library);
+ }
}
Ice::PluginPtr
@@ -393,13 +505,3 @@ Ice::PluginManagerI::findPlugin(const string& name) const
}
return 0;
}
-
-void
-IceInternal::loadPlugin(const Ice::CommunicatorPtr& communicator,
- const string& name,
- const string& pluginSpec,
- Ice::StringSeq& cmdArgs)
-{
- PluginManagerIPtr pluginManager = PluginManagerIPtr::dynamicCast(getInstance(communicator)->pluginManager());
- pluginManager->loadPlugin(name, pluginSpec, cmdArgs);
-}
diff --git a/cpp/src/Ice/PluginManagerI.h b/cpp/src/Ice/PluginManagerI.h
index d70783e3cb4..ef9a1dd9275 100644
--- a/cpp/src/Ice/PluginManagerI.h
+++ b/cpp/src/Ice/PluginManagerI.h
@@ -18,20 +18,17 @@
#include <IceUtil/Mutex.h>
#include <map>
-namespace IceInternal
-{
-
-ICE_API void loadPlugin(const ::Ice::CommunicatorPtr&, const std::string&, const std::string&, Ice::StringSeq&);
-
-}
-
namespace Ice
{
+typedef Ice::Plugin* (*PLUGIN_FACTORY)(const ::Ice::CommunicatorPtr&, const std::string&, const ::Ice::StringSeq&);
+
class PluginManagerI : public PluginManager, public IceUtil::Mutex
{
public:
+ static void registerPluginFactory(const std::string&, PLUGIN_FACTORY, bool);
+
virtual void initializePlugins();
virtual StringSeq getPlugins();
virtual PluginPtr getPlugin(const std::string&);
@@ -42,8 +39,6 @@ private:
PluginManagerI(const CommunicatorPtr&, const IceInternal::DynamicLibraryListPtr&);
friend class IceInternal::Instance;
- friend void IceInternal::loadPlugin(const Ice::CommunicatorPtr&, const std::string&, const std::string&,
- Ice::StringSeq&);
void loadPlugins(int&, char*[]);
void loadPlugin(const std::string&, const std::string&, StringSeq&);
diff --git a/cpp/test/Ice/plugin/Client.cpp b/cpp/test/Ice/plugin/Client.cpp
index 77747547e2e..a767e1814dc 100644
--- a/cpp/test/Ice/plugin/Client.cpp
+++ b/cpp/test/Ice/plugin/Client.cpp
@@ -54,8 +54,7 @@ public:
~MyPlugin()
{
- test(_initialized);
- test(_destroyed);
+ test(!_initialized || _destroyed); // If initialized, we must be destroyed too.
}
private:
@@ -68,12 +67,65 @@ typedef IceUtil::Handle<MyPlugin> MyPluginPtr;
}
+extern "C"
+{
+
+Ice::Plugin*
+createMyPlugin(const ::Ice::CommunicatorPtr&, const std::string&, const ::Ice::StringSeq&)
+{
+ return new MyPlugin();
+}
+
+}
+
int
main(int argc, char* argv[])
{
int status = EXIT_SUCCESS;
Ice::CommunicatorPtr communicator;
+ Ice::registerPluginFactory("Static1", createMyPlugin, true); // true = Load on communicator initialization
+ Ice::registerPluginFactory("Static2", createMyPlugin, false);
+
+ cout << "testing static plugin factory... " << flush;
+ try
+ {
+ communicator = Ice::initialize(argc, argv);
+ MyPluginPtr plugin = MyPluginPtr::dynamicCast(communicator->getPluginManager()->getPlugin("Static1"));
+ test(plugin && plugin->isInitialized());
+ try
+ {
+ communicator->getPluginManager()->getPlugin("Static2");
+ }
+ catch(const Ice::NotRegisteredException&)
+ {
+ }
+ communicator->destroy();
+ }
+ catch(const Ice::Exception& ex)
+ {
+ cerr << ex << endl;
+ test(false);
+ }
+ try
+ {
+ Ice::InitializationData initData;
+ initData.properties = Ice::createProperties(argc, argv);
+ initData.properties->setProperty("Ice.Plugin.Static2", "1");
+ communicator = Ice::initialize(argc, argv, initData);
+ MyPluginPtr plugin = MyPluginPtr::dynamicCast(communicator->getPluginManager()->getPlugin("Static1"));
+ test(plugin && plugin->isInitialized());
+ plugin = MyPluginPtr::dynamicCast(communicator->getPluginManager()->getPlugin("Static2"));
+ test(plugin && plugin->isInitialized());
+ communicator->destroy();
+ }
+ catch(const Ice::Exception& ex)
+ {
+ cerr << ex << endl;
+ test(false);
+ }
+ cout << "ok" << endl;
+
cout << "testing a simple plug-in... " << flush;
try
{