CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_6_1_2_SLHC4_patch1/src/FWCore/Modules/src/XMLOutputModule.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     Modules
00004 // Class  :     XMLOutputModule
00005 //
00006 // Implementation:
00007 //     <Notes on implementation>
00008 //
00009 // Original Author:  Chris Jones
00010 //         Created:  Fri Aug  4 20:45:44 EDT 2006
00011 //
00012 
00013 // system include files
00014 #include <fstream>
00015 #include <string>
00016 #include <iomanip>
00017 #include <map>
00018 #include <sstream>
00019 #include <algorithm>
00020 
00021 #include "FWCore/Framework/interface/Event.h"
00022 #include "DataFormats/Provenance/interface/BranchDescription.h"
00023 #include "DataFormats/Provenance/interface/Selections.h"
00024 
00025 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00026 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
00027 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
00028 
00029 #include "FWCore/Framework/interface/Frameworkfwd.h"
00030 #include "FWCore/Framework/interface/OutputModule.h"
00031 #include "FWCore/Framework/interface/GenericHandle.h"
00032 #include "FWCore/Framework/interface/MakerMacros.h"
00033 #include "FWCore/Utilities/interface/BaseWithDict.h"
00034 #include "FWCore/Utilities/interface/FunctionWithDict.h"
00035 #include "FWCore/Utilities/interface/MemberWithDict.h"
00036 #include "FWCore/Utilities/interface/ObjectWithDict.h"
00037 #include "FWCore/Utilities/interface/TypeWithDict.h"
00038 
00039 // user include files
00040 
00041 //
00042 // constants, enums and typedefs
00043 //
00044 
00045 namespace edm {
00046   class XMLOutputModule : public OutputModule {
00047 
00048    public:
00049       XMLOutputModule(ParameterSet const&);
00050       virtual ~XMLOutputModule();
00051       static void fillDescriptions(ConfigurationDescriptions& descriptions);
00052 
00053       // ---------- const member functions ---------------------
00054 
00055       // ---------- static member functions --------------------
00056 
00057       // ---------- member functions ---------------------------
00058 
00059    private:
00060       virtual void write(EventPrincipal const& e);
00061       virtual void writeLuminosityBlock(LuminosityBlockPrincipal const&) {}
00062       virtual void writeRun(RunPrincipal const&) {}
00063 
00064       XMLOutputModule(XMLOutputModule const&); // stop default
00065 
00066       XMLOutputModule const& operator=(XMLOutputModule const&); // stop default
00067 
00068       // ---------- member data --------------------------------
00069       std::ofstream stream_;
00070       std::string indentation_;
00071   };
00072 
00073   namespace {
00074     void doNotDelete(void*) {}
00075     void callDestruct(ObjectWithDict* iObj) {
00076       iObj->destruct();
00077     }
00078     //Handle memory for calls to invoke
00079     // We handle Ref's by using an external void* buffer (which we do not delete) while everything else
00080     // we create the proper object (and therefore must delete it)
00081     boost::shared_ptr<ObjectWithDict> initReturnValue(FunctionWithDict const& iMember,
00082                                                       ObjectWithDict* iObj,
00083                                                       void** iRefBuffer) {
00084       TypeWithDict returnType = iMember.returnType();
00085       if(returnType.isReference()) {
00086         *iObj = ObjectWithDict(returnType, iRefBuffer);
00087         return boost::shared_ptr<ObjectWithDict>(iObj, doNotDelete);
00088       }
00089       *iObj = returnType.construct();
00090       return boost::shared_ptr<ObjectWithDict>(iObj, callDestruct);
00091     }
00092 
00093     //remove characters from a string which are not allowed to be used in XML
00094     std::string formatXML(std::string const& iO) {
00095       std::string result(iO);
00096       static std::string const kSubs("<>&");
00097       static std::string const kLeft("&lt;");
00098       static std::string const kRight("&gt;");
00099       static std::string const kAmp("&");
00100 
00101       std::string::size_type i = 0;
00102       while(std::string::npos != (i = result.find_first_of(kSubs, i))) {
00103         switch(result.at(i)) {
00104           case '<':
00105             result.replace(i, 1, kLeft);
00106             break;
00107           case '>':
00108             result.replace(i, 1, kRight);
00109             break;
00110           case '&':
00111             result.replace(i, 1, kAmp);
00112         }
00113         ++i;
00114       }
00115       return result;
00116     }
00117 
00118     char const* kNameValueSep = "\">";
00119     char const* kContainerOpen = "<container size=\"";
00120     char const* kContainerClose = "</container>";
00121     std::string const kObjectOpen = "<object type=\"";
00122     std::string const kObjectClose = "</object>";
00124     #define FILLNAME(_type_) s_toName[typeid(_type_).name()]= #_type_;
00125     std::string const& typeidToName(std::type_info const& iID) {
00126       static std::map<std::string, std::string> s_toName;
00127       if(s_toName.empty()) {
00128         FILLNAME(short);
00129         FILLNAME(int);
00130         FILLNAME(long);
00131         FILLNAME(long long);
00132 
00133         FILLNAME(unsigned short);
00134         FILLNAME(unsigned int);
00135         FILLNAME(unsigned long);
00136         FILLNAME(unsigned long long);
00137 
00138         FILLNAME(double);
00139         FILLNAME(float);
00140       }
00141       return s_toName[iID.name()];
00142     }
00143 
00144     template<typename T>
00145     void doPrint(std::ostream& oStream, std::string const& iPrefix, std::string const& iPostfix, ObjectWithDict const& iObject, std::string const& iIndent) {
00146       oStream << iIndent << iPrefix << typeidToName(typeid(T)) << kNameValueSep
00147         << *reinterpret_cast<T*>(iObject.address()) << iPostfix << "\n";
00148     }
00149 
00150     template<>
00151     void doPrint<char>(std::ostream& oStream, std::string const& iPrefix, std::string const& iPostfix, ObjectWithDict const& iObject, std::string const& iIndent) {
00152       oStream << iIndent << iPrefix << "char" << kNameValueSep
00153         << static_cast<int>(*reinterpret_cast<char*>(iObject.address())) << iPostfix << "\n";
00154     }
00155 
00156     template<>
00157     void doPrint<unsigned char>(std::ostream& oStream, std::string const& iPrefix, std::string const& iPostfix, ObjectWithDict const& iObject, std::string const& iIndent) {
00158       oStream << iIndent << iPrefix << "unsigned char" << kNameValueSep << static_cast<unsigned int>(*reinterpret_cast<unsigned char*>(iObject.address())) << iPostfix << "\n";
00159     }
00160 
00161     template<>
00162     void doPrint<bool>(std::ostream& oStream, std::string const& iPrefix, std::string const& iPostfix, ObjectWithDict const& iObject, std::string const& iIndent) {
00163       oStream << iIndent << iPrefix << "bool" << kNameValueSep
00164         << ((*reinterpret_cast<bool*>(iObject.address()))?"true":"false") << iPostfix << "\n";
00165     }
00166 
00167 
00168     typedef void(*FunctionType)(std::ostream&, std::string const&,
00169                                 std::string const&, ObjectWithDict const&, std::string const&);
00170     typedef std::map<std::string, FunctionType> TypeToPrintMap;
00171 
00172     template<typename T>
00173     void addToMap(TypeToPrintMap& iMap){
00174       iMap[typeid(T).name()]=doPrint<T>;
00175     }
00176 
00177     bool printAsBuiltin(std::ostream& oStream,
00178                                std::string const& iPrefix,
00179                                std::string const& iPostfix,
00180                                ObjectWithDict const iObject,
00181                                std::string const& iIndent){
00182       typedef void(*FunctionType)(std::ostream&, std::string const&, std::string const&, ObjectWithDict const&, std::string const&);
00183       typedef std::map<std::string, FunctionType> TypeToPrintMap;
00184       static TypeToPrintMap s_map;
00185       static bool isFirst = true;
00186       if(isFirst){
00187         addToMap<bool>(s_map);
00188         addToMap<char>(s_map);
00189         addToMap<short>(s_map);
00190         addToMap<int>(s_map);
00191         addToMap<long>(s_map);
00192         addToMap<unsigned char>(s_map);
00193         addToMap<unsigned short>(s_map);
00194         addToMap<unsigned int>(s_map);
00195         addToMap<unsigned long>(s_map);
00196         addToMap<float>(s_map);
00197         addToMap<double>(s_map);
00198         isFirst=false;
00199       }
00200       TypeToPrintMap::iterator itFound =s_map.find(iObject.typeName());
00201       if(itFound == s_map.end()){
00202 
00203         return false;
00204       }
00205       itFound->second(oStream, iPrefix, iPostfix, iObject, iIndent);
00206       return true;
00207     }
00208 
00209     bool printAsContainer(std::ostream& oStream,
00210                           std::string const& iPrefix,
00211                           std::string const& iPostfix,
00212                           ObjectWithDict const& iObject,
00213                           std::string const& iIndent,
00214                           std::string const& iIndentDelta);
00215 
00216     void printDataMembers(std::ostream& oStream,
00217                           ObjectWithDict const& iObject,
00218                           TypeWithDict const& iType,
00219                           std::string const& iIndent,
00220                           std::string const& iIndentDelta);
00221 
00222     void printObject(std::ostream& oStream,
00223                      std::string const& iPrefix,
00224                      std::string const& iPostfix,
00225                      ObjectWithDict const& iObject,
00226                      std::string const& iIndent,
00227                      std::string const& iIndentDelta) {
00228       ObjectWithDict objectToPrint = iObject;
00229       std::string indent(iIndent);
00230       if(iObject.isPointer()) {
00231         oStream << iIndent << iPrefix << formatXML(iObject.typeOf().name(TypeNameHandling::Scoped)) << "\">\n";
00232         indent +=iIndentDelta;
00233         int size = (0!=iObject.address()) ? (0!=*reinterpret_cast<void**>(iObject.address())?1:0) : 0;
00234         oStream << indent << kContainerOpen << size << "\">\n";
00235         if(size) {
00236           std::string indent2 = indent + iIndentDelta;
00237           ObjectWithDict obj(iObject.toType(), *reinterpret_cast<void**>(iObject.address()));
00238           obj = obj.castObject(obj.dynamicType());
00239           printObject(oStream, kObjectOpen, kObjectClose, obj, indent2, iIndentDelta);
00240         }
00241         oStream << indent << kContainerClose << "\n";
00242         oStream << iIndent << iPostfix << "\n";
00243         TypeWithDict pointedType = iObject.toType();
00244         if(TypeWithDict::byName("void") == pointedType || pointedType.isPointer() || iObject.address()==0) {
00245           return;
00246         }
00247         return;
00248         /*
00249         //have the code that follows print the contents of the data to which the pointer points
00250         objectToPrint = ObjectWithDict(pointedType, iObject.address());
00251         //try to convert it to its actual type (assuming the original type was a base class)
00252         objectToPrint = ObjectWithDict(objectToPrint.castObject(objectToPrint.dynamicType()));
00253         indent +=iIndentDelta;
00254         */
00255       }
00256       std::string typeName(objectToPrint.typeOf().name(TypeNameHandling::Scoped));
00257       if(typeName.empty()){
00258         typeName="{unknown}";
00259       }
00260 
00261       //see if we are dealing with a typedef
00262       TypeWithDict objectType = objectToPrint.typeOf();
00263       bool wasTypedef = false;
00264       while(objectType.isTypedef()) {
00265          objectType = objectType.toType();
00266          wasTypedef = true;
00267       }
00268       if(wasTypedef){
00269          ObjectWithDict tmp(objectType, objectToPrint.address());
00270          objectToPrint = tmp;
00271       }
00272       if(printAsBuiltin(oStream, iPrefix, iPostfix, objectToPrint, indent)) {
00273         return;
00274       }
00275       if(printAsContainer(oStream, iPrefix, iPostfix, objectToPrint, indent, iIndentDelta)){
00276         return;
00277       }
00278 
00279       oStream << indent << iPrefix << formatXML(typeName) << "\">\n";
00280       printDataMembers(oStream, objectToPrint, objectType, indent+iIndentDelta, iIndentDelta);
00281       oStream << indent << iPostfix << "\n";
00282 
00283     }
00284 
00285     void printDataMembers(std::ostream& oStream,
00286                           ObjectWithDict const& iObject,
00287                           TypeWithDict const& iType,
00288                           std::string const& iIndent,
00289                           std::string const& iIndentDelta) {
00290       //print all the base class data members
00291       TypeBases bases(iType);
00292       for(auto const& baseMember : bases) {
00293         BaseWithDict base(baseMember);
00294         printDataMembers(oStream, iObject.castObject(base.toType()), base.toType(), iIndent, iIndentDelta);
00295       }
00296       static std::string const kPrefix("<datamember name=\"");
00297       static std::string const ktype("\" type=\"");
00298       static std::string const kPostfix("</datamember>");
00299 
00300       TypeDataMembers dataMembers(iType);
00301       for(auto const& dataMember : dataMembers) {
00302         MemberWithDict member(dataMember);
00303         //std::cout << "     debug " << member.name() << " " << member.typeOf().name() << "\n";
00304         if (member.isTransient()) {
00305           continue;
00306         }
00307         try {
00308           std::string prefix = kPrefix + member.name() + ktype;
00309           printObject(oStream,
00310                       prefix,
00311                       kPostfix,
00312                       member.get(iObject),
00313                       iIndent,
00314                       iIndentDelta);
00315         }catch(std::exception& iEx) {
00316           std::cout << iIndent << member.name() << " <exception caught("
00317           << iEx.what() << ")>\n";
00318         }
00319       }
00320     }
00321 
00322     bool printContentsOfStdContainer(std::ostream& oStream,
00323                                      std::string const& iPrefix,
00324                                      std::string const& iPostfix,
00325                                      ObjectWithDict iBegin,
00326                                      ObjectWithDict const& iEnd,
00327                                      std::string const& iIndent,
00328                                      std::string const& iIndentDelta){
00329       size_t size = 0;
00330       std::ostringstream sStream;
00331       if(iBegin.typeOf() != iEnd.typeOf()) {
00332         std::cerr << " begin (" << iBegin.typeOf().name(TypeNameHandling::Scoped) << ") and end ("
00333           << iEnd.typeOf().name(TypeNameHandling::Scoped) << ") are not the same type" << std::endl;
00334         throw std::exception();
00335       }
00336       try {
00337         FunctionWithDict compare(iBegin.typeOf().functionMemberByName("operator!="));
00338         if(!compare) {
00339           //std::cerr << "no 'operator!=' for " << iBegin.typeOf().name() << std::endl;
00340           return false;
00341         }
00342         FunctionWithDict incr(iBegin.typeOf().functionMemberByName("operator++"));
00343         if(!incr) {
00344           //std::cerr << "no 'operator++' for " << iBegin.typeOf().name() << std::endl;
00345           return false;
00346         }
00347         FunctionWithDict deref(iBegin.typeOf().functionMemberByName("operator*"));
00348         if(!deref) {
00349           //std::cerr << "no 'operator*' for " << iBegin.typeOf().name() << std::endl;
00350           return false;
00351         }
00352 
00353         std::string indexIndent = iIndent+iIndentDelta;
00354         int dummy=0;
00355         //std::cerr << "going to loop using iterator " << iBegin.typeOf().name(NameHAndling::Scoped) << std::endl;
00356 
00357         std::vector<void*> compareArgs;
00358         compareArgs.push_back(iEnd.address());
00359         std::vector<void*> incArgs;
00360         incArgs.push_back(&dummy);
00361         bool compareResult;
00362         ObjectWithDict objCompareResult(TypeWithDict(typeid(bool)), &compareResult);
00363         ObjectWithDict objIncr;
00364         void* objIncrRefBuffer;
00365         boost::shared_ptr<ObjectWithDict> incrMemHolder = initReturnValue(incr, &objIncr, &objIncrRefBuffer);
00366         for(;
00367           compare.invoke(iBegin, &objCompareResult, compareArgs), compareResult;
00368           incr.invoke(iBegin, &objIncr, incArgs), ++size) {
00369           //std::cerr << "going to print" << std::endl;
00370           ObjectWithDict iTemp;
00371           void* derefRefBuffer;
00372           boost::shared_ptr<ObjectWithDict> derefMemHolder = initReturnValue(deref, &iTemp, &derefRefBuffer);
00373           deref.invoke(iBegin, &iTemp);
00374           if(iTemp.isReference()) {
00375             iTemp = ObjectWithDict(iTemp.typeOf(), derefRefBuffer);
00376           }
00377           printObject(sStream, kObjectOpen, kObjectClose, iTemp, indexIndent, iIndentDelta);
00378           //std::cerr << "printed" << std::endl;
00379         }
00380       } catch(std::exception const& iE) {
00381         std::cerr << "while printing std container caught exception " << iE.what() << std::endl;
00382         return false;
00383       }
00384       oStream << iPrefix << iIndent << kContainerOpen << size << "\">\n";
00385       oStream << sStream.str();
00386       oStream << iIndent << kContainerClose << std::endl;
00387       oStream << iPostfix;
00388       //std::cerr << "finished loop" << std::endl;
00389       return true;
00390     }
00391 
00392     bool printAsContainer(std::ostream& oStream,
00393                           std::string const& iPrefix, std::string const& iPostfix,
00394                           ObjectWithDict const& iObject,
00395                           std::string const& iIndent,
00396                           std::string const& iIndentDelta) {
00397       ObjectWithDict sizeObj;
00398       try {
00399         size_t temp; //used to hold the memory for the return value
00400         sizeObj = ObjectWithDict(TypeWithDict(typeid(size_t)), &temp);
00401         iObject.invoke("size", &sizeObj);
00402 
00403         if(sizeObj.typeOf().typeInfo() != typeid(size_t)) {
00404           throw std::exception();
00405         }
00406         size_t size = *reinterpret_cast<size_t*>(sizeObj.address());
00407         FunctionWithDict atMember;
00408         atMember = iObject.typeOf().functionMemberByName("at");
00409         if(!atMember) {
00410           throw std::exception();
00411         }
00412         std::string typeName(iObject.typeOf().name(TypeNameHandling::Scoped));
00413         if(typeName.empty()){
00414           typeName="{unknown}";
00415         }
00416 
00417         oStream << iIndent << iPrefix << formatXML(typeName) << "\">\n"
00418           << iIndent << kContainerOpen << size << "\">\n";
00419         ObjectWithDict contained;
00420         std::string indexIndent=iIndent+iIndentDelta;
00421         for(size_t index = 0; index != size; ++index) {
00422           void* atRefBuffer;
00423           boost::shared_ptr<ObjectWithDict> atMemHolder = initReturnValue(atMember, &contained, &atRefBuffer);
00424 
00425           std::vector<void*> args;
00426           args.push_back(&index);
00427           atMember.invoke(iObject, &contained, args);
00428           if(contained.isReference()) {
00429             contained = ObjectWithDict(contained.typeOf(), atRefBuffer);
00430           }
00431           //std::cout << "invoked 'at'" << std::endl;
00432           try {
00433             printObject(oStream, kObjectOpen, kObjectClose, contained, indexIndent, iIndentDelta);
00434           }catch(std::exception& iEx) {
00435             std::cout << iIndent << " <exception caught("
00436             << iEx.what() << ")>\n";
00437           }
00438         }
00439         oStream << iIndent << kContainerClose << std::endl;
00440         oStream << iIndent << iPostfix << std::endl;
00441         return true;
00442       } catch(std::exception const& x){
00443         //std::cerr << "failed to invoke 'at' because " << x.what() << std::endl;
00444         try {
00445           //oStream << iIndent << iPrefix << formatXML(typeName) << "\">\n";
00446           std::string typeName(iObject.typeOf().name(TypeNameHandling::Scoped));
00447           if(typeName.empty()){
00448             typeName="{unknown}";
00449           }
00450           ObjectWithDict iObjBegin;
00451           void* beginRefBuffer;
00452           FunctionWithDict beginMember = iObject.typeOf().functionMemberByName("begin");
00453           boost::shared_ptr<ObjectWithDict> beginMemHolder = initReturnValue(beginMember, &iObjBegin, &beginRefBuffer);
00454           ObjectWithDict iObjEnd;
00455           void* endRefBuffer;
00456           FunctionWithDict endMember = iObject.typeOf().functionMemberByName("end");
00457           boost::shared_ptr<ObjectWithDict> endMemHolder = initReturnValue(endMember, &iObjEnd, &endRefBuffer);
00458 
00459           beginMember.invoke(iObject, &iObjBegin);
00460           endMember.invoke(iObject, &iObjEnd);
00461           if(printContentsOfStdContainer(oStream,
00462                                          iIndent+iPrefix+formatXML(typeName)+"\">\n",
00463                                          iIndent+iPostfix,
00464                                          iObjBegin,
00465                                          iObjEnd,
00466                                          iIndent,
00467                                          iIndentDelta)) {
00468             if(typeName.empty()){
00469               typeName="{unknown}";
00470             }
00471             return true;
00472           }
00473         } catch(std::exception const& x) {
00474         }
00475         return false;
00476       }
00477       return false;
00478     }
00479 
00480     void printObject(std::ostream& oStream,
00481                      Event const& iEvent,
00482                      std::string const& iClassName,
00483                      std::string const& iModuleLabel,
00484                      std::string const& iInstanceLabel,
00485                      std::string const& iIndent,
00486                      std::string const& iIndentDelta) {
00487       try {
00488         GenericHandle handle(iClassName);
00489       }catch(edm::Exception const&) {
00490         std::cout << iIndent << " \"" << iClassName << "\"" << " is an unknown type" << std::endl;
00491         return;
00492       }
00493       GenericHandle handle(iClassName);
00494       iEvent.getByLabel(iModuleLabel, iInstanceLabel, handle);
00495       std::string className = formatXML(iClassName);
00496       printObject(oStream, kObjectOpen, kObjectClose, *handle, iIndent, iIndentDelta);
00497     }
00498   }
00499 
00500   //
00501   // static data member definitions
00502   //
00503 
00504   //
00505   // constructors and destructor
00506   //
00507   XMLOutputModule::XMLOutputModule(ParameterSet const& iPSet) :
00508       OutputModule(iPSet),
00509       stream_(iPSet.getUntrackedParameter<std::string>("fileName").c_str()),
00510       indentation_("  ") {
00511     if(!stream_){
00512       throw edm::Exception(errors::Configuration) << "failed to open file " << iPSet.getUntrackedParameter<std::string>("fileName");
00513     }
00514     stream_ << "<cmsdata>" << std::endl;
00515   }
00516 
00517   // XMLOutputModule::XMLOutputModule(XMLOutputModule const& rhs)
00518   // {
00519   //    // do actual copying here;
00520   // }
00521 
00522   XMLOutputModule::~XMLOutputModule() {
00523     stream_ << "</cmsdata>" << std::endl;
00524   }
00525 
00526   //
00527   // assignment operators
00528   //
00529   // XMLOutputModule const& XMLOutputModule::operator=(XMLOutputModule const& rhs)
00530   // {
00531   //   //An exception safe implementation is
00532   //   XMLOutputModule temp(rhs);
00533   //   swap(rhs);
00534   //
00535   //   return *this;
00536   // }
00537 
00538   //
00539   // member functions
00540   //
00541   void
00542   XMLOutputModule::write(EventPrincipal const& iEP) {
00543     ModuleDescription desc;
00544     Event event(const_cast<EventPrincipal&>(iEP), desc);
00545     stream_ << "<event run=\"" << event.id().run() << "\" number=\"" << event.id().event() << "\" >\n";
00546     std::string startIndent = indentation_;
00547     for(Selections::const_iterator itBD = keptProducts()[InEvent].begin(), itBDEnd = keptProducts()[InEvent].end();
00548         itBD != itBDEnd;
00549         ++itBD) {
00550       stream_ << "<product type=\"" << (*itBD)->friendlyClassName()
00551              << "\" module=\"" << (*itBD)->moduleLabel()
00552       << "\" productInstance=\"" << (*itBD)->productInstanceName() << "\">\n";
00553       printObject(stream_,
00554                    event,
00555                   (*itBD)->className(),
00556                   (*itBD)->moduleLabel(),
00557                   (*itBD)->productInstanceName(),
00558                   startIndent,
00559                   indentation_);
00560       stream_ << "</product>\n";
00561     }
00562     stream_ << "</event>" << std::endl;
00563   }
00564 
00565   void
00566   XMLOutputModule::fillDescriptions(ConfigurationDescriptions& descriptions) {
00567     ParameterSetDescription desc;
00568     desc.setComment("Prints event information into a file in XML format.");
00569     desc.addUntracked<std::string>("fileName");
00570     OutputModule::fillDescription(desc);
00571     descriptions.add("XMLoutput", desc);
00572   }
00573 }
00574 using edm::XMLOutputModule;
00575 DEFINE_FWK_MODULE(XMLOutputModule);