From 9253c31c0b5f89e91f94358895c70dbecfece29e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 15 Apr 2017 11:46:41 -0400 Subject: [PATCH] rework ChannelProviderRegistry Replace interface+impls with a single concrete container which wraps a map. This breaks code which was sub-classing. However, no external code can be found which does this. A build() method is used instead of simple ctor so that the ctor is private, which will cause theoretical external sub-class code to fail to compile. Code using getChannelProviderRegistry() and existing methods will behave as before. Add ChannelProviderRegistry::getFactory() for pass through to ChannelProviderFactory (Registery is just a proxy()...) Remove existing get/create virtual method in favor of getFactory. Update both existing implementations. Add SimpleChannelProviderFactory to cut down on boilerplace for the common case. Add method to clear mapping and release any saved sharedInstance. --- src/client/pv/pvAccess.h | 95 +++++++++++++++++++-- src/factory/ChannelAccessFactory.cpp | 122 ++++++++++++++++----------- testApp/remote/testServerContext.cpp | 34 +------- 3 files changed, 165 insertions(+), 86 deletions(-) diff --git a/src/client/pv/pvAccess.h b/src/client/pv/pvAccess.h index 937c54a..d8430f7 100644 --- a/src/client/pv/pvAccess.h +++ b/src/client/pv/pvAccess.h @@ -958,41 +958,124 @@ public: } }; +//! Simple ChannelProviderFactory which requires the existance of a ctor +//! Provider(const std::tr1::shared_ptr& conf) +//! which is called with a Configuration instance or NULL (use some defaults) +template +struct SimpleChannelProviderFactory : public ChannelProviderFactory +{ + SimpleChannelProviderFactory(const std::string& name) :pname(name) {} + virtual ~SimpleChannelProviderFactory() {} + + virtual std::string getFactoryName() { return pname; } + + virtual ChannelProvider::shared_pointer sharedInstance() + { + epics::pvData::Lock L(sharedM); + if(!shared) { + std::tr1::shared_ptr empty; + shared.reset(new Provider(empty)); + } + return shared; + } + + virtual ChannelProvider::shared_pointer newInstance(const std::tr1::shared_ptr& conf) + { + ChannelProvider::shared_pointer ret(new Provider(conf)); + return ret; + } + +private: + const std::string pname; + epics::pvData::Mutex sharedM; + std::tr1::shared_ptr shared; +}; + /** * Interface for locating channel providers. */ -class epicsShareClass ChannelProviderRegistry : private epics::pvData::NoDefaultMethods { +class epicsShareClass ChannelProviderRegistry { public: POINTER_DEFINITIONS(ChannelProviderRegistry); typedef std::vector stringVector_t; - virtual ~ChannelProviderRegistry() {}; - /** * Get a shared instance of the provider with the specified name. * @param providerName The name of the provider. * @return The interface for the provider or null if the provider is not known. */ - virtual ChannelProvider::shared_pointer getProvider(std::string const & providerName) = 0; + ChannelProvider::shared_pointer getProvider(std::string const & providerName); /** * Creates a new instanceof the provider with the specified name. * @param providerName The name of the provider. * @return The interface for the provider or null if the provider is not known. */ - virtual ChannelProvider::shared_pointer createProvider(std::string const & providerName) = 0; + ChannelProvider::shared_pointer createProvider(std::string const & providerName); + + /** + * Creates a new instanceof the provider with the specified name. + * @param providerName The name of the provider. + * @return The interface for the provider or null if the provider is not known. + */ + ChannelProvider::shared_pointer createProvider(std::string const & providerName, + const std::tr1::shared_ptr& conf); + + /** + * Fetch provider factor with the specified name. + * @param providerName The name of the provider. + * @return The factor or null if the provider is not known. + */ + ChannelProviderFactory::shared_pointer getFactory(std::string const & providerName); /** * Get a array of the names of all the known providers. * @return The names. Be sure to delete vector instance. */ - virtual std::auto_ptr getProviderNames() = 0; + std::auto_ptr getProviderNames(); + + + static ChannelProviderRegistry::shared_pointer build() { + ChannelProviderRegistry::shared_pointer ret(new ChannelProviderRegistry); + return ret; + } + + //! Add new factory. if replace=false and name already in use, return false with no change + //! in other cases insert provided factory and return true. + bool add(const ChannelProviderFactory::shared_pointer& fact, bool replace=true); + + //! Add a new Provider which will be built using SimpleChannelProviderFactory + template + bool add(const std::string& name, bool replace=true) + { + typedef SimpleChannelProviderFactory Factory; + typename Factory::shared_pointer fact(new Factory(name)); + return add(fact, replace); + } + + //! Attempt to remove named factory. Return Factory which was removed, or NULL if not found. + ChannelProviderFactory::shared_pointer remove(const std::string& name); + + //! Drop all factories + void clear() + { + providers.clear(); + } + +private: + ChannelProviderRegistry() {} + + epics::pvData::Mutex mutex; + typedef std::map providers_t; + providers_t providers; }; +//! never returns NULL epicsShareFunc ChannelProviderRegistry::shared_pointer getChannelProviderRegistry(); epicsShareFunc void registerChannelProviderFactory(ChannelProviderFactory::shared_pointer const & channelProviderFactory); epicsShareFunc void unregisterChannelProviderFactory(ChannelProviderFactory::shared_pointer const & channelProviderFactory); +epicsShareFunc void unregisterAllChannelProviderFactory(); /** diff --git a/src/factory/ChannelAccessFactory.cpp b/src/factory/ChannelAccessFactory.cpp index 1c18b51..97f0a8d 100644 --- a/src/factory/ChannelAccessFactory.cpp +++ b/src/factory/ChannelAccessFactory.cpp @@ -21,76 +21,100 @@ using std::string; namespace epics { namespace pvAccess { -static ChannelProviderRegistry::shared_pointer ChannelProviderRegistry; +ChannelProvider::shared_pointer ChannelProviderRegistry::getProvider(std::string const & providerName) { + ChannelProviderFactory::shared_pointer fact(getFactory(providerName)); + if(fact) + return fact->sharedInstance(); + else + return ChannelProvider::shared_pointer(); +} -static Mutex channelProviderMutex; +ChannelProvider::shared_pointer ChannelProviderRegistry::createProvider(std::string const & providerName) { + ChannelProviderFactory::shared_pointer fact(getFactory(providerName)); + if(fact) + return fact->newInstance(); + else + return ChannelProvider::shared_pointer(); +} -typedef std::map ChannelProviderFactoryMap; -static ChannelProviderFactoryMap channelProviders; +ChannelProvider::shared_pointer ChannelProviderRegistry::createProvider(std::string const & providerName, + const std::tr1::shared_ptr& conf) { + ChannelProviderFactory::shared_pointer fact(getFactory(providerName)); + if(fact) + return fact->newInstance(conf); + else + return ChannelProvider::shared_pointer(); +} +ChannelProviderFactory::shared_pointer ChannelProviderRegistry::getFactory(std::string const & providerName) +{ + Lock G(mutex); + providers_t::const_iterator iter = providers.find(providerName); + if (iter == providers.end()) + return ChannelProviderFactory::shared_pointer(); + else + return iter->second; +} -class ChannelProviderRegistryImpl : public ChannelProviderRegistry { -public: +std::auto_ptr ChannelProviderRegistry::getProviderNames() +{ + Lock G(mutex); + std::auto_ptr ret(new stringVector_t); + for (providers_t::const_iterator iter = providers.begin(); + iter != providers.end(); iter++) + ret->push_back(iter->first); - ChannelProvider::shared_pointer getProvider(std::string const & providerName) { + return ret; +} - ChannelProviderFactory::shared_pointer providerFactory; - { - Lock guard(channelProviderMutex); - ChannelProviderFactoryMap::const_iterator iter = channelProviders.find(providerName); - if (iter == channelProviders.end()) - return ChannelProvider::shared_pointer(); - else - providerFactory = iter->second; - } - return providerFactory->sharedInstance(); +bool ChannelProviderRegistry::add(const ChannelProviderFactory::shared_pointer& fact, bool replace) +{ + Lock G(mutex); + std::string name(fact->getFactoryName()); + if(!replace && providers.find(name)!=providers.end()) + throw false; + providers[name] = fact; + return true; +} + +ChannelProviderFactory::shared_pointer ChannelProviderRegistry::remove(const std::string& name) +{ + ChannelProviderFactory::shared_pointer ret; + providers_t::iterator iter(providers.find(name)); + if(iter!=providers.end()) { + ret = iter->second; + providers.erase(iter); } - - ChannelProvider::shared_pointer createProvider(std::string const & providerName) { - - ChannelProviderFactory::shared_pointer providerFactory; - { - Lock guard(channelProviderMutex); - ChannelProviderFactoryMap::const_iterator iter = channelProviders.find(providerName); - if (iter == channelProviders.end()) - return ChannelProvider::shared_pointer(); - else - providerFactory = iter->second; - } - return providerFactory->newInstance(); - } - - std::auto_ptr getProviderNames() { - Lock guard(channelProviderMutex); - std::auto_ptr providers(new stringVector_t()); - for (ChannelProviderFactoryMap::const_iterator i = channelProviders.begin(); - i != channelProviders.end(); i++) - providers->push_back(i->first); - - return providers; - } -}; + return ret; +} ChannelProviderRegistry::shared_pointer getChannelProviderRegistry() { static Mutex mutex; + static ChannelProviderRegistry::shared_pointer global_reg; Lock guard(mutex); - if(ChannelProviderRegistry.get()==0) { - ChannelProviderRegistry.reset(new ChannelProviderRegistryImpl()); + if(!global_reg) { + global_reg = ChannelProviderRegistry::build(); } - return ChannelProviderRegistry; + return global_reg; } void registerChannelProviderFactory(ChannelProviderFactory::shared_pointer const & channelProviderFactory) { - Lock guard(channelProviderMutex); - channelProviders[channelProviderFactory->getFactoryName()] = channelProviderFactory; + assert(channelProviderFactory); + getChannelProviderRegistry()->add(channelProviderFactory); } void unregisterChannelProviderFactory(ChannelProviderFactory::shared_pointer const & channelProviderFactory) { - Lock guard(channelProviderMutex); - channelProviders.erase(channelProviderFactory->getFactoryName()); + assert(channelProviderFactory); + getChannelProviderRegistry()->remove(channelProviderFactory->getFactoryName()); } +epicsShareFunc void unregisterAllChannelProviderFactory() +{ + getChannelProviderRegistry()->clear(); +} + + } } diff --git a/testApp/remote/testServerContext.cpp b/testApp/remote/testServerContext.cpp index 4584fcb..697dee3 100644 --- a/testApp/remote/testServerContext.cpp +++ b/testApp/remote/testServerContext.cpp @@ -17,6 +17,7 @@ public: return "local"; }; + TestChannelProvider(const std::tr1::shared_ptr&) {} ChannelFind::shared_pointer channelFind(std::string const & /*channelName*/, ChannelFindRequester::shared_pointer const & channelFindRequester) @@ -57,41 +58,12 @@ public: } }; - -class TestChannelProviderRegistry : public ChannelProviderRegistry { -public: - - virtual ~TestChannelProviderRegistry() {}; - - ChannelProvider::shared_pointer getProvider(std::string const & providerName) - { - if (providerName == "local") - { - return ChannelProvider::shared_pointer(new TestChannelProvider()); - } - else - return ChannelProvider::shared_pointer(); - } - - ChannelProvider::shared_pointer createProvider(std::string const & providerName) - { - return getProvider(providerName); - } - - std::auto_ptr getProviderNames() - { - std::auto_ptr pn(new stringVector_t()); - pn->push_back("local"); - return pn; - } -}; - void testServerContext() { - ServerContextImpl::shared_pointer ctx = ServerContextImpl::create(); - ChannelProviderRegistry::shared_pointer ca(new TestChannelProviderRegistry()); + ChannelProviderRegistry::shared_pointer ca(ChannelProviderRegistry::build()); + ca->add("local"); ctx->initialize(ca); ctx->printInfo();