Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-11-02 03:11:08

0001 #ifndef FWCore_ParameterSet_PluginDescription_h
0002 #define FWCore_ParameterSet_PluginDescription_h
0003 // -*- C++ -*-
0004 //
0005 // Package:     FWCore/ParameterSet
0006 // Class  :     PluginDescription
0007 //
0008 /**\class PluginDescription PluginDescription.h "PluginDescription.h"
0009 
0010  Description: Use to describe how to validate a plugin that will be loaded
0011 
0012  Usage:
0013  User defined plugins which are constructed by passing a edm::ParameterSet can
0014  have their parameters validated using the \c edm::PluginDescription. For this to
0015  work, one must
0016  
0017  1) Plugin configuration
0018  All the parameters used by the Plugin must be contained within one PSet, this
0019  also includes an cms.string parameter containing the name of the actual plugin
0020  type to be loaded. E.g. if a module \c FooProd loaded a plugin of specific type
0021  \c BarHelper and \c BarHelper uses the parameter named \c value :
0022  \code{.py}
0023  foo = cms.EDProducer("FooProd",
0024                       pluginDescription = cms.PSet(type = cms.string("BarHelper"),
0025                                                    value = cms.int32(5) ) )
0026  \endcode
0027 
0028 2) Plugin fillPSetDescription
0029 Each user plugin must define a static member function:
0030  \code{.cpp}
0031  static void fillPSetDescription(edm::ParameterSetDescription const&);
0032  \endcode
0033 
0034  The function fills the \c edm::ParameterSetDescription with the descriptions of
0035  the parameters necessary for that particular plugin. Note that the parameter
0036  used by the module to find the type of the plugin should NOT be declared in
0037  the \c edm::ParameterSetDescription since it will be added by the
0038  \c edm::PluginDescription itself. E.g.
0039  
0040  \code{.cpp}
0041  void BarHelper::fillPSetDescription(edm::ParameterSetDescription& iPSD) {
0042     iPSD.add<int>("value", 5);
0043  }
0044  \endcode
0045  
0046  3) Module's fillDescriptions
0047  The module which uses the plugins must use the \c edm::PluginDescription within its
0048  \c fillDescriptions static member function.
0049  The \c edm::PluginDescription object is attached to the \c edm::ParameterSetDescription
0050  object which is being used to represent the PSet for the plugin. In turn, that
0051  \c edm::ParamterSetDescription is attached to the module's top level \edm::ParameterSetDescription.
0052  This exactly mimics what would be done if the plugin's parameters were directly known to
0053  the module.
0054  
0055  \code{.cpp}
0056  void FooProd::fillDescriptions(ConfigurationDescriptions& oDesc) {
0057    //specify how to get the plugin validation
0058    ParameterSetDescription pluginDesc;
0059    //'type' is the label to the string containing which plugin to load
0060    pluginDesc.addNode(edm::PluginDescription<HelperFactory>("type") );
0061  
0062    ParameterSetDescription desc;
0063    desc.add<ParameterSetDescription>("pluginDescription", pluginDesc);
0064  
0065    oDesc.addDefault(desc);
0066  }
0067  \endcode
0068  
0069  4) Factory registration
0070  Use \c EDM_REGISTER_VALIDATED_PLUGINFACTORY rather than
0071  \c EDM_REGISTER_PLUGINFACTORY. This new macro can be found in
0072  FWCore/ParameterSet/interface/ValidatedPluginFactoryMacros.h
0073  
0074  5) Plugin registration
0075  Use \c DEFINE_EDM_VALIDATED_PLUGIN rather than \c DEFINE_EDM_PLUGIN.
0076  This new macro can be found in FWCore/Framework/interface/ValidatedPluginMacros.h
0077  
0078  */
0079 //
0080 // Original Author:  Chris Jones
0081 //         Created:  Wed, 19 Sep 2018 19:23:27 GMT
0082 //
0083 
0084 // system include files
0085 #include "FWCore/ParameterSet/interface/ParameterDescriptionNode.h"
0086 #include "FWCore/ParameterSet/interface/PluginDescriptionAdaptorBase.h"
0087 #include "FWCore/PluginManager/interface/PluginFactory.h"
0088 #include "FWCore/PluginManager/interface/PluginManager.h"
0089 #include "FWCore/PluginManager/interface/standard.h"
0090 #include "FWCore/Utilities/interface/thread_safety_macros.h"
0091 
0092 // user include files
0093 #include <ostream>
0094 #include <sstream>
0095 #include <string>
0096 
0097 // forward declarations
0098 namespace edm {
0099   template <typename T>
0100   class PluginDescription : public ParameterDescriptionNode {
0101   public:
0102     /**Constructor without a default for typeLabel
0103    @param[in] typeLabel the label for the std::string parameter which holds the plugin type to be loaded
0104    @param[in] typeLabelIsTracked 'true' if the parameter `typeLabel` is tracked, else should be false
0105    */
0106     PluginDescription(std::string typeLabel, bool typeLabelIsTracked)
0107         : typeLabel_{std::move(typeLabel)}, typeLabelIsTracked_{typeLabelIsTracked} {}
0108 
0109     /**Constructor with a default for typeLabel
0110    @param[in] typeLabel the label for the std::string parameter which holds the plugin type to be loaded
0111    @param[in] defaultType the default plugin type that should be loaded if no type is given
0112    @param[in] typeLabelIsTracked 'true' if the parameter `typeLabel` is tracked, else should be false
0113    */
0114     PluginDescription(std::string typeLabel, std::string defaultType, bool typeLabelIsTracked)
0115         : typeLabel_{std::move(typeLabel)},
0116           defaultType_{std::move(defaultType)},
0117           typeLabelIsTracked_{typeLabelIsTracked} {}
0118 
0119     // ---------- const member functions ---------------------
0120     ParameterDescriptionNode* clone() const final { return new PluginDescription<T>(*this); }
0121 
0122   protected:
0123     void checkAndGetLabelsAndTypes_(std::set<std::string>& usedLabels,
0124                                     std::set<ParameterTypes>& parameterTypes,
0125                                     std::set<ParameterTypes>& wildcardTypes) const final {}
0126 
0127     void validate_(ParameterSet& pset, std::set<std::string>& validatedLabels, bool optional) const final {
0128       loadDescription(findType(pset)).validate(pset);
0129       //all names are good
0130       auto n = pset.getParameterNames();
0131       validatedLabels.insert(n.begin(), n.end());
0132     }
0133 
0134     void writeCfi_(
0135         std::ostream& os, bool optional, bool& startWithComma, int indentation, bool& wroteSomething) const final {
0136       if (not defaultType_.empty()) {
0137         if (!edmplugin::PluginManager::isAvailable()) {
0138           auto conf = edmplugin::standard::config();
0139           conf.allowNoCache();
0140           edmplugin::PluginManager::configure(conf);
0141         }
0142         loadDescription(defaultType_).writeCfi(os, startWithComma, indentation);
0143         wroteSomething = true;
0144       }
0145     }
0146 
0147     bool hasNestedContent_() const final { return true; }
0148 
0149     void printNestedContent_(std::ostream& os, bool /*optional*/, DocFormatHelper& dfh) const final {
0150       int indentation = dfh.indentation();
0151 
0152       using CreatedType = PluginDescriptionAdaptorBase<typename T::CreatedType>;
0153       using Factory = edmplugin::PluginFactory<CreatedType*()>;
0154 
0155       std::string const& pluginCategory = Factory::get()->category();
0156 
0157       printSpaces(os, indentation);
0158       os << "There are multiple possible different descriptions for this ParameterSet\n";
0159       printSpaces(os, indentation);
0160       os << "because it will be used by a helper plugin object contained inside the top level\n";
0161       printSpaces(os, indentation);
0162       os << "module plugin object and the type of the helper plugin object is configurable.\n";
0163       printSpaces(os, indentation);
0164       os << "Or if it is in a vector of ParameterSets it might be used by multiple\n";
0165       printSpaces(os, indentation);
0166       os << "helper plugin objects and each could be configured with a different plugin type.\n";
0167       printSpaces(os, indentation);
0168       os << "Each plugin type could allow a different set of configuration parameters.\n";
0169       printSpaces(os, indentation);
0170       os << "Each subsection of this section has one of the possible descriptions.\n";
0171       printSpaces(os, indentation);
0172       os << "All of these plugins are from the category \"" << pluginCategory << "\".\n";
0173       printSpaces(os, indentation);
0174       os << "The plugin type is specified by the parameter named \"" << typeLabel_ << "\".\n";
0175 
0176       if (!dfh.brief()) {
0177         os << "\n";
0178       }
0179       std::string section = dfh.sectionOfCategoryAlreadyPrinted(pluginCategory);
0180       if (!section.empty()) {
0181         printSpaces(os, indentation);
0182         os << "*** The descriptions for this plugin category already started printing above (see Section " << section
0183            << ")! ***\n";
0184         printSpaces(os, indentation);
0185         os << "*** We might still be in the middle of that printout at this point because it might be recursive. ***\n";
0186         printSpaces(os, indentation);
0187         os << "*** We'll not duplicate that printout and skip it. ***\n";
0188         printSpaces(os, indentation);
0189         os << "*** (N.B. If we tried to print it again, we might fall into an infinite recursion.) ***\n";
0190 
0191         if (!dfh.brief()) {
0192           os << "\n";
0193         }
0194         return;
0195       }
0196       dfh.addCategory(pluginCategory, dfh.section());
0197 
0198       indentation -= DocFormatHelper::offsetSectionContent();
0199 
0200       //loop over all possible plugins
0201       unsigned int pluginCount = 1;
0202       std::string previousName;
0203       for (auto const& info : edmplugin::PluginManager::get()->categoryToInfos().find(pluginCategory)->second) {
0204         // We only want to print the first instance of each plugin name
0205         if (previousName == info.name_) {
0206           continue;
0207         }
0208 
0209         std::stringstream ss;
0210         ss << dfh.section() << "." << pluginCount;
0211         ++pluginCount;
0212         std::string newSection = ss.str();
0213         printSpaces(os, indentation);
0214         os << "Section " << newSection << " ParameterSet description for plugin named \"" << info.name_ << "\"\n";
0215         if (!dfh.brief())
0216           os << "\n";
0217 
0218         DocFormatHelper new_dfh(dfh);
0219         new_dfh.init();
0220         new_dfh.setSection(newSection);
0221 
0222         loadDescription(info.name_).print(os, new_dfh);
0223 
0224         previousName = info.name_;
0225       }
0226     }
0227 
0228     bool exists_(ParameterSet const& pset) const final {
0229       CMS_SA_ALLOW return pset.existsAs<std::string>(typeLabel_, typeLabelIsTracked_);
0230     }
0231 
0232     bool partiallyExists_(ParameterSet const& pset) const final { return exists_(pset); }
0233 
0234     int howManyXORSubNodesExist_(ParameterSet const& pset) const final { return exists(pset) ? 1 : 0; }
0235 
0236   private:
0237     std::string findType(edm::ParameterSet const& iPSet) const {
0238       if (typeLabelIsTracked_) {
0239         CMS_SA_ALLOW if (iPSet.existsAs<std::string>(typeLabel_) || defaultType_.empty()) {
0240           return iPSet.getParameter<std::string>(typeLabel_);
0241         }
0242         else {
0243           return defaultType_;
0244         }
0245       }
0246       if (defaultType_.empty()) {
0247         return iPSet.getUntrackedParameter<std::string>(typeLabel_);
0248       }
0249       return iPSet.getUntrackedParameter<std::string>(typeLabel_, defaultType_);
0250     }
0251 
0252     ParameterSetDescription loadDescription(std::string const& iName) const {
0253       using CreatedType = PluginDescriptionAdaptorBase<typename T::CreatedType>;
0254       std::unique_ptr<CreatedType> a(edmplugin::PluginFactory<CreatedType*()>::get()->create(iName));
0255 
0256       ParameterSetDescription desc = a->description();
0257 
0258       //There is no way to check to see if a node already wants a label
0259       if (typeLabelIsTracked_) {
0260         if (defaultType_.empty()) {
0261           desc.add<std::string>(typeLabel_);
0262         } else {
0263           desc.add<std::string>(typeLabel_, defaultType_);
0264         }
0265       } else {
0266         if (defaultType_.empty()) {
0267           desc.addUntracked<std::string>(typeLabel_);
0268         } else {
0269           desc.addUntracked<std::string>(typeLabel_, defaultType_);
0270         }
0271       }
0272       return desc;
0273     }
0274 
0275     // ---------- member data --------------------------------
0276     std::string typeLabel_;
0277     std::string defaultType_;
0278     bool typeLabelIsTracked_;
0279   };
0280 }  // namespace edm
0281 
0282 #endif