30 #include <boost/regex.hpp> 47 const string ValidationError::EMPTY;
49 ValidationError::MsgLookup ValidationError::_errmsgs;
53 void ValidationError::_loadMessages() {
55 _errmsgs[WRONG_TYPE] =
"value has the incorrect type";
56 _errmsgs[MISSING_REQUIRED] =
"no value available for required parameter";
57 _errmsgs[NOT_AN_ARRAY] =
"value is not an array as required";
58 _errmsgs[ARRAY_TOO_SHORT] =
"insufficient number of array values";
59 _errmsgs[TOO_FEW_VALUES] =
"not enough values for parameter";
60 _errmsgs[TOO_MANY_VALUES] =
"too many values provided for parameter";
61 _errmsgs[WRONG_OCCURRENCE_COUNT]=
"incorrect number of values for parameter";
62 _errmsgs[VALUE_DISALLOWED] =
"value is not among defined set";
63 _errmsgs[VALUE_OUT_OF_RANGE] =
"value is out of range";
64 _errmsgs[BAD_VALUE] =
"illegal value";
65 _errmsgs[UNKNOWN_NAME] =
"parameter name is unknown";
66 _errmsgs[BAD_DEFINITION] =
"malformed definition";
67 _errmsgs[NOT_LOADED] =
"file not loaded" 68 " -- call Policy.loadPolicyFiles() before validating";
69 _errmsgs[UNKNOWN_ERROR] =
"unknown error";
74 ParamLookup::const_iterator i;
75 for (i = _errors.begin(); i != _errors.end(); ++i)
80 string ValidationError::describe(
string prefix)
const {
85 os << prefix << *i <<
": " 86 << getErrorMessageFor((ErrorType)getErrors(*i)) << endl;
90 char const* ValidationError::what(
void)
const throw() {
95 int n = getParamCount();
96 os <<
"Validation error";
97 if (n == 1) os <<
" (1 error)";
98 else if (n > 1) os <<
" (" << getParamCount() <<
" errors)";
99 if (getParamCount() == 0)
100 os <<
": no errors" <<
"\n";
102 os <<
": \n" << describe(
" * ");
105 return buffer.
c_str();
108 ValidationError::~ValidationError() throw() { }
114 Definition::~Definition() { }
117 if (_policy->isString(Dictionary::KW_TYPE)) {
118 const string&
type = _policy->getString(Dictionary::KW_TYPE);
122 }
catch(BadNameError&) {
124 (DictionaryError,
string(
"Unknown type: \"") + type +
"\".");
127 throw LSST_EXCEPT(DictionaryError,
string(
"Illegal type: \"") + type
132 else if (_policy->exists(Dictionary::KW_TYPE)) {
134 (DictionaryError,
string(
"Expected string for \"type\"; found ")
135 + _policy->getTypeName(Dictionary::KW_TYPE) +
" instead.");
145 const string Definition::getDescription()
const {
146 if (_policy->exists(Dictionary::KW_DESCRIPTION))
147 return _policy->getString(Dictionary::KW_DESCRIPTION);
155 const int Definition::getMaxOccurs()
const {
156 if (_policy->exists(Dictionary::KW_MAX_OCCUR))
157 return _policy->getInt(Dictionary::KW_MAX_OCCUR);
165 const int Definition::getMinOccurs()
const {
166 if (_policy->exists(Dictionary::KW_MIN_OCCUR))
167 return _policy->getInt(Dictionary::KW_MIN_OCCUR);
179 void Definition::setDefaultIn(Policy& policy,
const string& withName,
180 ValidationError* errs)
const 182 if (! _policy->exists(
"default"))
return;
191 setDefaultIn<bool>(policy, withName, errs);
193 setDefaultIn<int>(policy, withName, errs);
195 setDefaultIn<double>(policy, withName, errs);
197 setDefaultIn<string>(policy, withName, errs);
199 setDefaultIn<Policy::Ptr>(policy, withName, errs);
201 string(
"Programmer Error: Unknown type for \"")
202 + getPrefix() + withName +
"\": " 215 ValidationError *errs)
const 218 ValidationError *use = &ve;
219 if (errs != 0) use = errs;
221 if (! policy.exists(name)) {
222 if (getMinOccurs() > 0)
223 use->addError(getPrefix() + name, ValidationError::MISSING_REQUIRED);
232 validateBasic<bool>(
name, policy, use);
236 validateBasic<int>(
name, policy, use);
240 validateBasic<double>(
name, policy, use);
244 validateBasic<string>(
name, policy, use);
248 validateBasic<Policy::ConstPtr>(
name, policy, use);
249 validateRecurse(name, policy.getConstPolicyArray(name), use);
253 use->addError(getPrefix() + name, ValidationError::NOT_LOADED);
258 string(
"Unknown type for \"") + getPrefix() + name
259 +
"\": \"" + policy.getTypeName(name) +
"\"");
262 if (errs == 0 && ve.getParamCount() > 0)
throw ve;
272 void Definition::validateCount(
const string& name,
int count,
273 ValidationError *errs)
const {
274 int max = getMaxOccurs();
275 if (max >= 0 && count > max)
276 errs->addError(getPrefix() + name, ValidationError::TOO_MANY_VALUES);
277 if (count < getMinOccurs()) {
279 errs->addError(getPrefix() + name, ValidationError::MISSING_REQUIRED);
281 errs->addError(getPrefix() + name, ValidationError::NOT_AN_ARRAY);
283 errs->addError(getPrefix() + name, ValidationError::ARRAY_TOO_SHORT);
292 bool operator<(
const Policy&
a,
const Policy&
b) {
return true; }
296 void Definition::validateRecurse(
const string& name,
298 ValidationError *errs)
const 300 for (Policy::ConstPolicyPtrArray::const_iterator i = value.begin();
301 i != value.end(); ++i) {
303 validateRecurse(name, *p, errs);
308 void Definition::validateRecurse(
const string& name,
const Policy& value,
309 ValidationError *errs)
const 311 if (_policy->exists(Dictionary::KW_DICT)) {
312 if (!_policy->isPolicy(Dictionary::KW_DICT))
314 (DictionaryError,
string(
"Wrong type for ") + getPrefix() + name
315 +
" \"" + Dictionary::KW_DICT +
"\": expected Policy, but found " 316 + _policy->getTypeName(Dictionary::KW_DICT) +
".");
318 Dictionary subdict(*(_policy->getPolicy(Dictionary::KW_DICT)));
319 subdict.setPrefix(_prefix + name +
".");
320 subdict.validate(value, errs);
324 else if (_policy->exists(Dictionary::KW_DICT_FILE)) {
327 +
"." + Dictionary::KW_DICT_FILE +
" needs to be loaded with " 328 "Dictionary.loadPolicyFiles() before validating.");
337 void Definition::validateBasic(
const string& name,
const T& value,
338 int curcount, ValidationError *errs)
const 341 ValidationError *use = &ve;
342 if (errs != 0) use = errs;
346 int maxOccurs = getMaxOccurs();
347 if (maxOccurs >= 0 && curcount + 1 > maxOccurs)
348 use->addError(getPrefix() + name, ValidationError::TOO_MANY_VALUES);
351 if (getType() !=
Policy::UNDEF && getType() != Policy::getValueType<T>()) {
352 use->addError(getPrefix() + name, ValidationError::WRONG_TYPE);
354 else if (_policy->isPolicy(Dictionary::KW_ALLOWED)) {
356 = _policy->getPolicyArray(Dictionary::KW_ALLOWED);
359 bool minFound =
false, maxFound =
false;
362 for (Policy::PolicyPtrArray::const_iterator it = allowed.begin();
363 it != allowed.end(); ++it)
366 if (a->exists(Dictionary::KW_MIN)) {
372 string(
"Min value for ") + getPrefix() + name
373 +
" already specified; additional value not allowed.");
376 min = a->getValue<T>(Dictionary::KW_MIN);
378 }
catch(TypeError& e) {
381 string(
"Wrong type for ") + getPrefix() + name
382 +
" min value: expected " + getTypeName() +
", found " 383 + a->getTypeName(Dictionary::KW_MIN) +
".");
388 if (a->exists(Dictionary::KW_MAX)) {
392 string(
"Max value for ") + getPrefix() + name
393 +
" already specified; additional value not allowed.");
395 max = a->getValue<T>(Dictionary::KW_MAX);
397 }
catch(TypeError& e) {
400 string(
"Wrong type for ") + getPrefix() + name
401 +
" max value: expected " + getTypeName() +
", found " 402 + a->getTypeName(Dictionary::KW_MAX) +
".");
405 if (a->exists(Dictionary::KW_VALUE)) {
406 const T& value = a->getValue<T>(Dictionary::KW_VALUE);
410 vector<T> values = a->getValueArray<T>(Dictionary::KW_VALUE);
412 vi != values.
end(); ++vi)
417 if ((minFound && value < min) || (maxFound && max < value))
418 use->addError(getPrefix() + name, ValidationError::VALUE_OUT_OF_RANGE);
420 if (allvals.
size() > 0 && allvals.
count(value) == 0)
421 use->addError(getPrefix() + name, ValidationError::VALUE_DISALLOWED);
423 if (errs == 0 && ve.getParamCount() > 0)
throw ve;
428 template void Definition::validateBasic<Policy::Ptr>
440 ValidationError *errs)
const 442 validateBasic<bool>(
name, value, curcount, errs);
446 ValidationError *errs)
const 448 validateBasic<int>(
name, value, curcount, errs);
452 ValidationError *errs)
const 454 validateBasic<double>(
name, value, curcount, errs);
458 ValidationError *errs)
const 460 validateBasic<string>(
name, value, curcount, errs);
464 int curcount, ValidationError *errs)
const 466 validateBasic<Policy>(
name, value, curcount, errs);
467 validateRecurse(name, value, errs);
480 ValidationError *errs)
const 482 validateBasic<bool>(
name, value, errs);
486 ValidationError *errs)
const 488 validateBasic<int>(
name, value, errs);
492 ValidationError *errs)
const 494 validateBasic<double>(
name, value, errs);
497 ValidationError *errs)
const 499 validateBasic<string>(
name, value, errs);
503 ValidationError *errs)
const 505 validateBasic<Policy::ConstPtr>(
name, value, errs);
506 validateRecurse(name, value, errs);
509 void Definition::check()
const {
511 if (okayKeywords.
size() == 0) {
512 okayKeywords.
insert(Dictionary::KW_TYPE);
513 okayKeywords.
insert(Dictionary::KW_DICT);
514 okayKeywords.
insert(Dictionary::KW_DICT_FILE);
516 okayKeywords.
insert(Dictionary::KW_MIN_OCCUR);
517 okayKeywords.
insert(Dictionary::KW_MAX_OCCUR);
518 okayKeywords.
insert(Dictionary::KW_MIN);
519 okayKeywords.
insert(Dictionary::KW_MAX);
520 okayKeywords.
insert(Dictionary::KW_ALLOWED);
521 okayKeywords.
insert(Dictionary::KW_DESCRIPTION);
522 okayKeywords.
insert(Dictionary::KW_DEFAULT);
525 for (Policy::StringArray::const_iterator i = terms.begin();
526 i != terms.end(); ++i)
528 if (okayKeywords.
count(*i) == 1)
continue;
530 (DictionaryError,
string(
"Unknown Dictionary property found at ")
531 + _prefix + _name +
": " + *i);
539 const char* Dictionary::KW_DICT =
"dictionary";
540 const char* Dictionary::KW_DICT_FILE =
"dictionaryFile";
541 const char* Dictionary::KW_TYPE =
"type";
542 const char* Dictionary::KW_DESCRIPTION =
"description";
543 const char* Dictionary::KW_DEFAULT =
"default";
544 const char* Dictionary::KW_DEFINITIONS =
"definitions";
545 const char* Dictionary::KW_CHILD_DEF =
"childDefinition";
546 const char* Dictionary::KW_ALLOWED =
"allowed";
547 const char* Dictionary::KW_MIN_OCCUR =
"minOccurs";
548 const char* Dictionary::KW_MAX_OCCUR =
"maxOccurs";
549 const char* Dictionary::KW_MIN =
"min";
550 const char* Dictionary::KW_MAX =
"max";
551 const char* Dictionary::KW_VALUE =
"value";
553 const boost::regex Dictionary::FIELDSEP_RE(
"\\.");
558 Dictionary::Dictionary(
const char *filePath) : Policy(filePath) {
559 if (!exists(KW_DEFINITIONS))
561 +
": does not contain a Dictionary");
564 Dictionary::Dictionary(
const string& filePath) : Policy(filePath) {
565 if (!exists(KW_DEFINITIONS))
567 +
": does not contain a Dictionary");
570 Dictionary::Dictionary(
const PolicyFile& filePath) : Policy(filePath) {
571 if (!exists(KW_DEFINITIONS))
573 +
": does not contain a Dictionary");
583 Definition* Dictionary::makeDef(
const string& name)
const {
584 Policy *p =
const_cast<Dictionary*
>(
this);
588 boost::sregex_token_iterator it = boost::make_regex_token_iterator(name, FIELDSEP_RE, -1);
589 boost::sregex_token_iterator
end;
591 bool isWildcard =
false;
594 if (! p->isPolicy(KW_DEFINITIONS))
595 throw LSST_EXCEPT(DictionaryError,
"Definition for " + find
597 sp = p->getPolicy(KW_DEFINITIONS);
598 if (sp->isPolicy(find)) {
599 sp = sp->getPolicy(find);
602 else if (sp->isPolicy(Dictionary::KW_CHILD_DEF)) {
603 if (sp->valueCount(Dictionary::KW_CHILD_DEF) > 1)
605 (DictionaryError,
string(
"Multiple ") + KW_CHILD_DEF
606 +
"s found " +
"that match " + getPrefix() + name +
".");
607 sp = sp->getPolicy(Dictionary::KW_CHILD_DEF);
613 if (! sp->isPolicy(Dictionary::KW_DICT))
615 find +
"." + KW_DICT +
" not found.");
616 sp = sp->getPolicy(Dictionary::KW_DICT);
620 Definition* result =
new Definition(name, sp);
621 result->setWildcard(isWildcard);
622 result->setPrefix(getPrefix());
631 Policy::DictPtr Dictionary::getSubDictionary(
const string& name)
const {
632 string subname =
string(KW_DEFINITIONS) +
"." + name +
".dictionary";
635 string(
"sub-policy \"") + subname +
"\" not found.");
637 (DictionaryError, subname +
" is a " + getTypeName(subname)
639 ConstPtr subpol = getPolicy(subname);
641 result->setPrefix(_prefix + name +
".");
645 int Dictionary::loadPolicyFiles(
const boost::filesystem::path& repository,
bool strict) {
649 for (
int level = 0; level < maxLevel; ++level) {
652 paramNames(params,
false);
656 static string endswith =
string(
".") + KW_DICT_FILE;
657 size_t p = ni->
rfind(endswith);
658 if (p == ni->length()-endswith.
length()) {
659 string parent = ni->substr(0, p);
660 Policy::Ptr defin = getPolicy(parent);
664 defin->set(Dictionary::KW_DICT, getFile(*ni));
666 defin->set(Dictionary::KW_DICT,
667 std::make_shared<PolicyFile>(getString(*ni)));
684 else result += newLoads;
687 (DictionaryError,
string(
"Exceeded recursion limit (")
689 +
") loading policy files; does this dictionary contain a circular" 697 void Dictionary::check()
const {
698 PolicyPtrArray defs = getValueArray<Policy::Ptr>(KW_DEFINITIONS);
699 if (defs.size() == 0)
701 string(
"no \"") + KW_DEFINITIONS +
"\" section found");
704 (DictionaryError,
string(
"expected a single \"") + KW_DEFINITIONS
708 for (Policy::StringArray::const_iterator i = names.begin();
709 i != names.end(); ++i)
714 if (hasSubDictionary(*i)) {
717 ConstPtr subPol = defs[0]->getPolicy(*i);
719 getSubDictionary(*i)->check();
730 ValidationError *use = &ve;
731 if (errs != 0) use = errs;
735 for (Policy::StringArray::const_iterator i = params.begin();
736 i != params.end(); ++i)
740 def->validate(pol, *i, use);
742 catch (NameNotFound& e) {
743 use->addError(getPrefix() + *i, ValidationError::UNKNOWN_NAME);
750 for (Policy::StringArray::const_iterator i = dn.begin(); i != dn.end(); ++i) {
751 const string& name = *i;
752 if (!pol.exists(name)) {
754 if (name != Dictionary::KW_CHILD_DEF && def->getMinOccurs() > 0)
755 use->addError(getPrefix() + name,
756 ValidationError::MISSING_REQUIRED);
760 if (errs == 0 && ve.getParamCount() > 0)
throw ve;
definition of the PolicyFile class
std::vector< bool > BoolArray
std::shared_ptr< Dictionary > DictPtr
std::vector< std::string > StringArray
std::vector< double > DoubleArray
#define LSST_EXCEPT_HERE
For internal use; gathers the file, line, and function for a tracepoint.
std::vector< Ptr > PolicyPtrArray
std::shared_ptr< PolicyFile > FilePtr
std::vector< ConstPtr > ConstPolicyPtrArray
std::shared_ptr< const Policy > ConstPtr
A base class for image defects.
int loadPolicyFiles(bool strict=true)
Recursively replace all PolicyFile values with the contents of the files they refer to...
std::shared_ptr< Policy > Ptr
Reports errors in the logical structure of the program.
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
static const char *const typeName[]
c-string forms for the supported value types.
definition of the Dictionary class
std::vector< int > IntArray
static ValueType getTypeByName(const std::string &name)
Given the human-readable name of a type ("bool", "int", "policy", etc), what is its ValueType (BOOL...
#define POL_EXCEPT_VIRTFUNCS(etn)
Reports errors that are due to events beyond the control of the program.
ValueType
an enumeration for the supported policy types