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