Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-05-23 03:13:13

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_(std::ostream& os,
0135                    bool optional,
0136                    bool& startWithComma,
0137                    int indentation,
0138                    CfiOptions& options,
0139                    bool& wroteSomething) const final {
0140       if (not defaultType_.empty()) {
0141         if (!edmplugin::PluginManager::isAvailable()) {
0142           auto conf = edmplugin::standard::config();
0143           conf.allowNoCache();
0144           edmplugin::PluginManager::configure(conf);
0145         }
0146         //given each plugin can have very different parameters we should do a full dump
0147         CfiOptions ops = cfi::Typed{};
0148         loadDescription(defaultType_).writeCfi(os, startWithComma, indentation, ops);
0149         wroteSomething = true;
0150       }
0151       if (std::holds_alternative<cfi::ClassFile>(options)) {
0152         std::get<cfi::ClassFile>(options).parameterMustBeTyped();
0153       }
0154     }
0155 
0156     bool hasNestedContent_() const final { return true; }
0157 
0158     void printNestedContent_(std::ostream& os, bool /*optional*/, DocFormatHelper& dfh) const final {
0159       int indentation = dfh.indentation();
0160 
0161       using CreatedType = PluginDescriptionAdaptorBase<typename T::CreatedType>;
0162       using Factory = edmplugin::PluginFactory<CreatedType*()>;
0163 
0164       std::string const& pluginCategory = Factory::get()->category();
0165 
0166       printSpaces(os, indentation);
0167       os << "There are multiple possible different descriptions for this ParameterSet\n";
0168       printSpaces(os, indentation);
0169       os << "because it will be used by a helper plugin object contained inside the top level\n";
0170       printSpaces(os, indentation);
0171       os << "module plugin object and the type of the helper plugin object is configurable.\n";
0172       printSpaces(os, indentation);
0173       os << "Or if it is in a vector of ParameterSets it might be used by multiple\n";
0174       printSpaces(os, indentation);
0175       os << "helper plugin objects and each could be configured with a different plugin type.\n";
0176       printSpaces(os, indentation);
0177       os << "Each plugin type could allow a different set of configuration parameters.\n";
0178       printSpaces(os, indentation);
0179       os << "Each subsection of this section has one of the possible descriptions.\n";
0180       printSpaces(os, indentation);
0181       os << "All of these plugins are from the category \"" << pluginCategory << "\".\n";
0182       printSpaces(os, indentation);
0183       os << "The plugin type is specified by the parameter named \"" << typeLabel_ << "\".\n";
0184 
0185       if (!dfh.brief()) {
0186         os << "\n";
0187       }
0188       std::string section = dfh.sectionOfCategoryAlreadyPrinted(pluginCategory);
0189       if (!section.empty()) {
0190         printSpaces(os, indentation);
0191         os << "*** The descriptions for this plugin category already started printing above (see Section " << section
0192            << ")! ***\n";
0193         printSpaces(os, indentation);
0194         os << "*** We might still be in the middle of that printout at this point because it might be recursive. ***\n";
0195         printSpaces(os, indentation);
0196         os << "*** We'll not duplicate that printout and skip it. ***\n";
0197         printSpaces(os, indentation);
0198         os << "*** (N.B. If we tried to print it again, we might fall into an infinite recursion.) ***\n";
0199 
0200         if (!dfh.brief()) {
0201           os << "\n";
0202         }
0203         return;
0204       }
0205       dfh.addCategory(pluginCategory, dfh.section());
0206 
0207       indentation -= DocFormatHelper::offsetSectionContent();
0208 
0209       //loop over all possible plugins
0210       unsigned int pluginCount = 1;
0211       std::string previousName;
0212       for (auto const& info : edmplugin::PluginManager::get()->categoryToInfos().find(pluginCategory)->second) {
0213         // We only want to print the first instance of each plugin name
0214         if (previousName == info.name_) {
0215           continue;
0216         }
0217 
0218         std::stringstream ss;
0219         ss << dfh.section() << "." << pluginCount;
0220         ++pluginCount;
0221         std::string newSection = ss.str();
0222         printSpaces(os, indentation);
0223         os << "Section " << newSection << " ParameterSet description for plugin named \"" << info.name_ << "\"\n";
0224         if (!dfh.brief())
0225           os << "\n";
0226 
0227         DocFormatHelper new_dfh(dfh);
0228         new_dfh.init();
0229         new_dfh.setSection(newSection);
0230 
0231         loadDescription(info.name_).print(os, new_dfh);
0232 
0233         previousName = info.name_;
0234       }
0235     }
0236 
0237     bool exists_(ParameterSet const& pset) const final {
0238       CMS_SA_ALLOW return pset.existsAs<std::string>(typeLabel_, typeLabelIsTracked_);
0239     }
0240 
0241     bool partiallyExists_(ParameterSet const& pset) const final { return exists_(pset); }
0242 
0243     int howManyXORSubNodesExist_(ParameterSet const& pset) const final { return exists(pset) ? 1 : 0; }
0244 
0245   private:
0246     std::string findType(edm::ParameterSet const& iPSet) const {
0247       if (typeLabelIsTracked_) {
0248         CMS_SA_ALLOW if (iPSet.existsAs<std::string>(typeLabel_) || defaultType_.empty()) {
0249           return iPSet.getParameter<std::string>(typeLabel_);
0250         }
0251         else {
0252           return defaultType_;
0253         }
0254       }
0255       if (defaultType_.empty()) {
0256         return iPSet.getUntrackedParameter<std::string>(typeLabel_);
0257       }
0258       return iPSet.getUntrackedParameter<std::string>(typeLabel_, defaultType_);
0259     }
0260 
0261     ParameterSetDescription loadDescription(std::string const& iName) const {
0262       using CreatedType = PluginDescriptionAdaptorBase<typename T::CreatedType>;
0263       std::unique_ptr<CreatedType> a(edmplugin::PluginFactory<CreatedType*()>::get()->create(iName));
0264 
0265       ParameterSetDescription desc = a->description();
0266 
0267       //There is no way to check to see if a node already wants a label
0268       if (typeLabelIsTracked_) {
0269         if (defaultType_.empty()) {
0270           desc.add<std::string>(typeLabel_);
0271         } else {
0272           desc.add<std::string>(typeLabel_, defaultType_);
0273         }
0274       } else {
0275         if (defaultType_.empty()) {
0276           desc.addUntracked<std::string>(typeLabel_);
0277         } else {
0278           desc.addUntracked<std::string>(typeLabel_, defaultType_);
0279         }
0280       }
0281       return desc;
0282     }
0283 
0284     // ---------- member data --------------------------------
0285     std::string typeLabel_;
0286     std::string defaultType_;
0287     bool typeLabelIsTracked_;
0288   };
0289 }  // namespace edm
0290 
0291 #endif