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