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;
#define POL_EXCEPT_VIRTFUNCS(etn)
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...
Reports errors that are due to events beyond the control of the program.
ValueType
an enumeration for the supported policy types