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