00001 #include "DataFormats/Provenance/interface/BranchDescription.h"
00002 #include "DataFormats/Provenance/interface/ModuleDescription.h"
00003 #include "FWCore/Utilities/interface/Exception.h"
00004 #include "FWCore/Utilities/interface/EDMException.h"
00005 #include "FWCore/Utilities/interface/FriendlyName.h"
00006 #include "FWCore/Utilities/interface/WrappedClassName.h"
00007
00008 #include "Reflex/Member.h"
00009
00010 #include <ostream>
00011 #include <sstream>
00012 #include <stdlib.h>
00013
00014 class TClass;
00015
00016
00017
00018
00019
00020 namespace edm {
00021 BranchDescription::Transients::Transients() :
00022 parameterSetID_(),
00023 branchName_(),
00024 wrappedName_(),
00025 produced_(false),
00026 onDemand_(false),
00027 dropped_(false),
00028 parameterSetIDs_(),
00029 moduleNames_(),
00030 transient_(false),
00031 type_(),
00032 typeID_(),
00033 wrapperInterfaceBase_(0),
00034 splitLevel_(),
00035 basketSize_() {
00036 }
00037
00038 BranchDescription::BranchDescription() :
00039 branchType_(InEvent),
00040 moduleLabel_(),
00041 processName_(),
00042 branchID_(),
00043 productID_(),
00044 fullClassName_(),
00045 friendlyClassName_(),
00046 productInstanceName_(),
00047 branchAliases_(),
00048 transients_() {
00049
00050 }
00051
00052 BranchDescription::BranchDescription(
00053 BranchType const& branchType,
00054 std::string const& mdLabel,
00055 std::string const& procName,
00056 std::string const& name,
00057 std::string const& fName,
00058 std::string const& pin,
00059 ModuleDescription const& modDesc,
00060 TypeID const& theTypeID,
00061 std::set<std::string> const& aliases) :
00062 branchType_(branchType),
00063 moduleLabel_(mdLabel),
00064 processName_(procName),
00065 branchID_(),
00066 productID_(),
00067 fullClassName_(name),
00068 friendlyClassName_(fName),
00069 productInstanceName_(pin),
00070 branchAliases_(aliases),
00071 transients_() {
00072 dropped() = false;
00073 produced() = true;
00074 onDemand() = false;
00075 typeID() = theTypeID;
00076 transients_.get().parameterSetID_ = modDesc.parameterSetID();
00077 transients_.get().moduleName_ = modDesc.moduleName();
00078 init();
00079 }
00080
00081 void
00082 BranchDescription::initBranchName() const {
00083 if(!branchName().empty()) {
00084 return;
00085 }
00086 throwIfInvalid_();
00087
00088 char const underscore('_');
00089 char const period('.');
00090
00091 if(friendlyClassName_.find(underscore) != std::string::npos) {
00092 throw cms::Exception("IllegalCharacter") << "Class name '" << friendlyClassName()
00093 << "' contains an underscore ('_'), which is illegal in the name of a product.\n";
00094 }
00095
00096 if(moduleLabel_.find(underscore) != std::string::npos) {
00097 throw cms::Exception("IllegalCharacter") << "Module label '" << moduleLabel()
00098 << "' contains an underscore ('_'), which is illegal in a module label.\n";
00099 }
00100
00101 if(productInstanceName_.find(underscore) != std::string::npos) {
00102 throw cms::Exception("IllegalCharacter") << "Product instance name '" << productInstanceName()
00103 << "' contains an underscore ('_'), which is illegal in a product instance name.\n";
00104 }
00105
00106 if(processName_.find(underscore) != std::string::npos) {
00107 throw cms::Exception("IllegalCharacter") << "Process name '" << processName()
00108 << "' contains an underscore ('_'), which is illegal in a process name.\n";
00109 }
00110
00111 branchName().reserve(friendlyClassName().size() +
00112 moduleLabel().size() +
00113 productInstanceName().size() +
00114 processName().size() + 4);
00115 branchName() += friendlyClassName();
00116 branchName() += underscore;
00117 branchName() += moduleLabel();
00118 branchName() += underscore;
00119 branchName() += productInstanceName();
00120 branchName() += underscore;
00121 branchName() += processName();
00122 branchName() += period;
00123
00124 if(!branchID_.isValid()) {
00125 branchID_.setID(branchName());
00126 }
00127 }
00128
00129 void
00130 BranchDescription::initFromDictionary() const {
00131 Reflex::Type null;
00132
00133 if(type() != null) {
00134 return;
00135 }
00136
00137 throwIfInvalid_();
00138
00139 wrappedName() = wrappedClassName(fullClassName());
00140
00141 Reflex::Type t = Reflex::Type::ByName(fullClassName());
00142 if(t == null) {
00143 splitLevel() = invalidSplitLevel;
00144 basketSize() = invalidBasketSize;
00145 transient() = false;
00146 return;
00147 }
00148 typeID() = TypeID(t.TypeInfo());
00149 type() = Reflex::Type::ByName(wrappedName());
00150 if(type() == null) {
00151 splitLevel() = invalidSplitLevel;
00152 basketSize() = invalidBasketSize;
00153 return;
00154 }
00155 Reflex::PropertyList wp = type().Properties();
00156 transient() = (wp.HasProperty("persistent") ? wp.PropertyAsString("persistent") == std::string("false") : false);
00157 if(transient()) {
00158 splitLevel() = invalidSplitLevel;
00159 basketSize() = invalidBasketSize;
00160 return;
00161 }
00162 if(wp.HasProperty("splitLevel")) {
00163 splitLevel() = strtol(wp.PropertyAsString("splitLevel").c_str(), 0, 0);
00164 if(splitLevel() < 0) {
00165 throw cms::Exception("IllegalSplitLevel") << "' An illegal ROOT split level of " <<
00166 splitLevel() << " is specified for class " << wrappedName() << ".'\n";
00167 }
00168 ++splitLevel();
00169 } else {
00170 splitLevel() = invalidSplitLevel;
00171 }
00172 if(wp.HasProperty("basketSize")) {
00173 basketSize() = strtol(wp.PropertyAsString("basketSize").c_str(), 0, 0);
00174 if(basketSize() <= 0) {
00175 throw cms::Exception("IllegalBasketSize") << "' An illegal ROOT basket size of " <<
00176 basketSize() << " is specified for class " << wrappedName() << "'.\n";
00177 }
00178 } else {
00179 basketSize() = invalidBasketSize;
00180 }
00181 }
00182
00183 ParameterSetID const&
00184 BranchDescription::psetID() const {
00185 assert(!parameterSetIDs().empty());
00186 if(parameterSetIDs().size() != 1) {
00187 throw cms::Exception("Ambiguous")
00188 << "Your application requires all events on Branch '" << branchName()
00189 << "'\n to have the same provenance. This file has events with mixed provenance\n"
00190 << "on this branch. Use a different input file.\n";
00191 }
00192 return parameterSetIDs().begin()->second;
00193 }
00194
00195 void
00196 BranchDescription::merge(BranchDescription const& other) {
00197 parameterSetIDs().insert(other.parameterSetIDs().begin(), other.parameterSetIDs().end());
00198 moduleNames().insert(other.moduleNames().begin(), other.moduleNames().end());
00199 branchAliases_.insert(other.branchAliases().begin(), other.branchAliases().end());
00200 if(splitLevel() == invalidSplitLevel) splitLevel() = other.splitLevel();
00201 if(basketSize() == invalidBasketSize) basketSize() = other.basketSize();
00202 }
00203
00204 void
00205 BranchDescription::write(std::ostream& os) const {
00206 os << "Branch Type = " << branchType() << std::endl;
00207 os << "Process Name = " << processName() << std::endl;
00208 os << "ModuleLabel = " << moduleLabel() << std::endl;
00209 os << "Branch ID = " << branchID() << '\n';
00210 os << "Class Name = " << fullClassName() << '\n';
00211 os << "Friendly Class Name = " << friendlyClassName() << '\n';
00212 os << "Product Instance Name = " << productInstanceName() << std::endl;
00213 }
00214
00215 void throwExceptionWithText(char const* txt) {
00216 Exception e(errors::LogicError);
00217 e << "Problem using an incomplete BranchDescription\n"
00218 << txt
00219 << "\nPlease report this error to the FWCore developers";
00220 throw e;
00221 }
00222
00223 void
00224 BranchDescription::throwIfInvalid_() const {
00225 if(branchType_ >= NumBranchTypes)
00226 throwExceptionWithText("Illegal BranchType detected");
00227
00228 if(moduleLabel_.empty())
00229 throwExceptionWithText("Module label is not allowed to be empty");
00230
00231 if(processName_.empty())
00232 throwExceptionWithText("Process name is not allowed to be empty");
00233
00234 if(fullClassName_.empty())
00235 throwExceptionWithText("Full class name is not allowed to be empty");
00236
00237 if(friendlyClassName_.empty())
00238 throwExceptionWithText("Friendly class name is not allowed to be empty");
00239
00240 if(produced() && !parameterSetID().isValid())
00241 throwExceptionWithText("Invalid ParameterSetID detected");
00242 }
00243
00244 void
00245 BranchDescription::updateFriendlyClassName() {
00246 friendlyClassName_ = friendlyname::friendlyName(fullClassName());
00247 branchName().clear();
00248 initBranchName();
00249 }
00250
00251 bool
00252 operator<(BranchDescription const& a, BranchDescription const& b) {
00253 if(a.processName() < b.processName()) return true;
00254 if(b.processName() < a.processName()) return false;
00255 if(a.fullClassName() < b.fullClassName()) return true;
00256 if(b.fullClassName() < a.fullClassName()) return false;
00257 if(a.friendlyClassName() < b.friendlyClassName()) return true;
00258 if(b.friendlyClassName() < a.friendlyClassName()) return false;
00259 if(a.productInstanceName() < b.productInstanceName()) return true;
00260 if(b.productInstanceName() < a.productInstanceName()) return false;
00261 if(a.moduleLabel() < b.moduleLabel()) return true;
00262 if(b.moduleLabel() < a.moduleLabel()) return false;
00263 if(a.branchType() < b.branchType()) return true;
00264 if(b.branchType() < a.branchType()) return false;
00265 if(a.branchID() < b.branchID()) return true;
00266 if(b.branchID() < a.branchID()) return false;
00267 if(a.parameterSetIDs() < b.parameterSetIDs()) return true;
00268 if(b.parameterSetIDs() < a.parameterSetIDs()) return false;
00269 if(a.moduleNames() < b.moduleNames()) return true;
00270 if(b.moduleNames() < a.moduleNames()) return false;
00271 if(a.branchAliases() < b.branchAliases()) return true;
00272 if(b.branchAliases() < a.branchAliases()) return false;
00273 if(a.present() < b.present()) return true;
00274 if(b.present() < a.present()) return false;
00275 return false;
00276 }
00277
00278 bool
00279 combinable(BranchDescription const& a, BranchDescription const& b) {
00280 return
00281 (a.branchType() == b.branchType()) &&
00282 (a.processName() == b.processName()) &&
00283 (a.fullClassName() == b.fullClassName()) &&
00284 (a.friendlyClassName() == b.friendlyClassName()) &&
00285 (a.productInstanceName() == b.productInstanceName()) &&
00286 (a.moduleLabel() == b.moduleLabel()) &&
00287 (a.branchID() == b.branchID());
00288 }
00289
00290 bool
00291 operator==(BranchDescription const& a, BranchDescription const& b) {
00292 return combinable(a, b) &&
00293 (a.dropped() == b.dropped()) &&
00294 (a.moduleNames() == b.moduleNames()) &&
00295 (a.parameterSetIDs() == b.parameterSetIDs()) &&
00296 (a.branchAliases() == b.branchAliases());
00297 }
00298
00299 std::string
00300 match(BranchDescription const& a, BranchDescription const& b,
00301 std::string const& fileName,
00302 BranchDescription::MatchMode m) {
00303 std::ostringstream differences;
00304 if(a.branchName() != b.branchName()) {
00305 differences << "Branch name '" << b.branchName() << "' does not match '" << a.branchName() << "'.\n";
00306
00307
00308
00309
00310
00311 }
00312 if(a.branchType() != b.branchType()) {
00313 differences << "Branch '" << b.branchName() << "' is a(n) '" << b.branchType() << "' branch\n";
00314 differences << " in file '" << fileName << "', but a(n) '" << a.branchType() << "' branch in previous files.\n";
00315 }
00316 if(a.branchID() != b.branchID()) {
00317 differences << "Branch '" << b.branchName() << "' has a branch ID of '" << b.branchID() << "'\n";
00318 differences << " in file '" << fileName << "', but '" << a.branchID() << "' in previous files.\n";
00319 }
00320 if(a.fullClassName() != b.fullClassName()) {
00321 differences << "Products on branch '" << b.branchName() << "' have type '" << b.fullClassName() << "'\n";
00322 differences << " in file '" << fileName << "', but '" << a.fullClassName() << "' in previous files.\n";
00323 }
00324 if(!b.dropped() && a.dropped()) {
00325 differences << "Branch '" << a.branchName() << "' was dropped in the first input file but is present in '" << fileName << "'.\n";
00326 }
00327 if(m == BranchDescription::Strict) {
00328 if(b.parameterSetIDs().size() > 1) {
00329 differences << "Branch '" << b.branchName() << "' uses more than one parameter set in file '" << fileName << "'.\n";
00330 } else if(a.parameterSetIDs().size() > 1) {
00331 differences << "Branch '" << a.branchName() << "' uses more than one parameter set in previous files.\n";
00332 } else if(a.parameterSetIDs() != b.parameterSetIDs()) {
00333 differences << "Branch '" << b.branchName() << "' uses different parameter sets in file '" << fileName << "'.\n";
00334 differences << " than in previous files.\n";
00335 }
00336 }
00337 return differences.str();
00338 }
00339
00340 WrapperInterfaceBase const*
00341 BranchDescription::getInterface() const {
00342 if(wrapperInterfaceBase() == 0) {
00343
00344 Reflex::Type type = Reflex::Type::ByName(wrappedName());
00345 Reflex::Member getTheInterface = type.FunctionMemberByName(std::string("getInterface"));
00346 getTheInterface.Invoke(wrapperInterfaceBase());
00347 assert(wrapperInterfaceBase() != 0);
00348 }
00349 return wrapperInterfaceBase();
00350 }
00351 }