// // Copyright (c) ZeroC, Inc. All rights reserved. // #include #include #include #include #include #include #include #include using namespace std; using namespace Ice; using namespace IceInternal; const char * const Ice::PluginManagerI::_kindOfObject = "plugin"; namespace { map* factories = 0; vector* loadOnInitialization = 0; class PluginFactoryDestroy { public: ~PluginFactoryDestroy() { delete factories; factories = 0; delete loadOnInitialization; loadOnInitialization = 0; } }; PluginFactoryDestroy destroy; } void Ice::PluginManagerI::registerPluginFactory(const std::string& name, PluginFactory factory, bool loadOnInit) { if(factories == 0) { factories = new map(); } map::const_iterator p = factories->find(name); if(p == factories->end()) { factories->insert(make_pair(name, factory)); if(loadOnInit) { if(loadOnInitialization == 0) { loadOnInitialization = new vector(); } loadOnInitialization->push_back(name); } } } void Ice::PluginManagerI::initializePlugins() { if(_initialized) { throw InitializationException(__FILE__, __LINE__, "plug-ins already initialized"); } // // Invoke initialize() on the plug-ins, in the order they were loaded. // vector initializedPlugins; try { for(PluginInfoList::iterator p = _plugins.begin(); p != _plugins.end(); ++p) { try { p->plugin->initialize(); } catch(const Ice::PluginInitializationException&) { throw; } catch(const std::exception& ex) { ostringstream os; os << "plugin `" << p->name << "' initialization failed:\n" << ex.what(); throw PluginInitializationException(__FILE__, __LINE__, os.str()); } catch(...) { ostringstream os; os << "plugin `" << p->name << "' initialization failed:\nunknown exception"; throw PluginInitializationException(__FILE__, __LINE__, os.str()); } initializedPlugins.push_back(p->plugin); } } catch(...) { // // Destroy the plug-ins that have been successfully initialized, in the // reverse order. // for(vector::reverse_iterator p = initializedPlugins.rbegin(); p != initializedPlugins.rend(); ++p) { try { (*p)->destroy(); } catch(...) { // Ignore. } } throw; } _initialized = true; } StringSeq Ice::PluginManagerI::getPlugins() ICE_NOEXCEPT { IceUtil::Mutex::Lock sync(*this); StringSeq names; for(PluginInfoList::iterator p = _plugins.begin(); p != _plugins.end(); ++p) { names.push_back(p->name); } return names; } PluginPtr Ice::PluginManagerI::getPlugin(const string& name) { IceUtil::Mutex::Lock sync(*this); if(!_communicator) { throw CommunicatorDestroyedException(__FILE__, __LINE__); } PluginPtr p = findPlugin(name); if(p) { return p; } throw NotRegisteredException(__FILE__, __LINE__, _kindOfObject, name); } void Ice::PluginManagerI::addPlugin(const string& name, const PluginPtr& plugin) { IceUtil::Mutex::Lock sync(*this); if(!_communicator) { throw CommunicatorDestroyedException(__FILE__, __LINE__); } if(findPlugin(name)) { throw AlreadyRegisteredException(__FILE__, __LINE__, _kindOfObject, name); } PluginInfo info; info.name = name; info.plugin = plugin; _plugins.push_back(info); } void Ice::PluginManagerI::destroy() ICE_NOEXCEPT { IceUtil::Mutex::Lock sync(*this); if(_communicator) { if(_initialized) { // // Destroy the plug-ins that have been successfully initialized, in the // reverse order. // for(PluginInfoList::reverse_iterator p = _plugins.rbegin(); p != _plugins.rend(); ++p) { try { p->plugin->destroy(); } catch(const std::exception& ex) { Warning out(getProcessLogger()); out << "unexpected exception raised by plug-in `" << p->name << "' destruction:\n" << ex.what(); } catch(const std::string& str) { Warning out(getProcessLogger()); out << "unexpected exception raised by plug-in `" << p->name << "' destruction:\n" << str; } catch(const char* msg) { Warning out(getProcessLogger()); out << "unexpected exception raised by plug-in `" << p->name << "' destruction:\n" << msg; } catch(...) { Warning out(getProcessLogger()); out << "unexpected exception raised by plug-in `" << p->name << "' destruction"; } } } _communicator = 0; } _plugins.clear(); _libraries = 0; } Ice::PluginManagerI::PluginManagerI(const CommunicatorPtr& communicator, const DynamicLibraryListPtr& libraries) : _communicator(communicator), _libraries(libraries), _initialized(false) { } void Ice::PluginManagerI::loadPlugins(int& argc, const char* argv[]) { assert(_communicator); 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::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); } } } // // 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[.]=entry_point [args] // // If the Ice.PluginLoadOrder property is defined, load the // specified plug-ins in the specified order, then load any // remaining plug-ins. // StringSeq loadOrder = properties->getPropertyAsList("Ice.PluginLoadOrder"); for(StringSeq::const_iterator p = loadOrder.begin(); p != loadOrder.end(); ++p) { string name = *p; if(findPlugin(name)) { throw PluginInitializationException(__FILE__, __LINE__, "plug-in `" + name + "' already loaded"); } string property = prefix + name; PropertyDict::iterator r = plugins.find(property + ".cpp"); if(r == plugins.end()) { r = plugins.find(property); } else { plugins.erase(property); } if(r != plugins.end()) { loadPlugin(name, r->second, cmdArgs); plugins.erase(r); } else { throw PluginInitializationException(__FILE__, __LINE__, "plug-in `" + name + "' not defined"); } } // // Load any remaining plug-ins that weren't specified in PluginLoadOrder. // while(!plugins.empty()) { PropertyDict::iterator p = plugins.begin(); string name = p->first.substr(prefix.size()); size_t dotPos = name.find_last_of('.'); if(dotPos != string::npos) { string suffix = name.substr(dotPos + 1); if(suffix == "java" || suffix == "clr") { // // Ignored // plugins.erase(p); } else if(suffix == "cpp") { name = name.substr(0, dotPos); loadPlugin(name, p->second, cmdArgs); plugins.erase(p); plugins.erase(prefix + name); } else { // // Name is just a regular name that happens to contain a dot // dotPos = string::npos; } } if(dotPos == string::npos) { // // Is there a .cpp entry? // PropertyDict::iterator q = plugins.find(prefix + name + ".cpp"); if(q != plugins.end()) { plugins.erase(p); p = q; } loadPlugin(name, p->second, cmdArgs); plugins.erase(p); } } stringSeqToArgs(cmdArgs, argc, argv); } void Ice::PluginManagerI::loadPlugin(const string& name, const string& pluginSpec, StringSeq& cmdArgs) { assert(_communicator); string entryPoint; StringSeq args; if(!pluginSpec.empty()) { // // 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) { throw PluginInitializationException(__FILE__, __LINE__, "invalid arguments for plug-in `" + name + "':\n" + ex.reason); } assert(!args.empty()); // // 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); } PluginFactory factory = 0; DynamicLibraryPtr library; // // Always check the static plugin factory table first, it takes // precedence over the the entryPoint specified in the plugin // property value. // if(factories) { map::const_iterator p = factories->find(name); if(p != factories->end()) { factory = p->second; } } // // If we didn't find the factory, get the factory using the entry // point symbol. // if(!factory) { assert(!entryPoint.empty()); library = new DynamicLibrary(); DynamicLibrary::symbol_type sym = library->loadEntryPoint(entryPoint); if(sym == 0) { ostringstream os; string msg = library->getErrorMessage(); os << "unable to load entry point `" << entryPoint << "'"; if(!msg.empty()) { os << ": " + msg; } throw PluginInitializationException(__FILE__, __LINE__, os.str()); } #ifdef __IBMCPP__ // xlC warns when casting a void* to function pointer # pragma report(disable, "1540-0216") #endif factory = reinterpret_cast(sym); } // // Invoke the factory function. No exceptions can be raised // by the factory function because it's declared extern "C". // PluginPtr plugin(factory(_communicator, name, args)); if(!plugin) { throw PluginInitializationException(__FILE__, __LINE__, "failure in entry point `" + entryPoint + "'"); } PluginInfo info; info.name = name; info.plugin = plugin; _plugins.push_back(info); if(library) { _libraries->add(library); } } Ice::PluginPtr Ice::PluginManagerI::findPlugin(const string& name) const { for(PluginInfoList::const_iterator p = _plugins.begin(); p != _plugins.end(); ++p) { if(name == p->name) { return p->plugin; } } return 0; }