30 #include <boost/scoped_ptr.hpp>
31 #include <boost/make_shared.hpp>
32 #include <boost/lexical_cast.hpp>
39 namespace pexExcept = lsst::pex::exceptions;
40 namespace fs = boost::filesystem;
49 using namespace boost;
51 const string ValidationError::EMPTY;
53 ValidationError::MsgLookup ValidationError::_errmsgs;
57 void ValidationError::_loadMessages() {
59 _errmsgs[WRONG_TYPE] =
"value has the incorrect type";
60 _errmsgs[MISSING_REQUIRED] =
"no value available for required parameter";
61 _errmsgs[NOT_AN_ARRAY] =
"value is not an array as required";
62 _errmsgs[ARRAY_TOO_SHORT] =
"insufficient number of array values";
63 _errmsgs[TOO_FEW_VALUES] =
"not enough values for parameter";
64 _errmsgs[TOO_MANY_VALUES] =
"too many values provided for parameter";
65 _errmsgs[WRONG_OCCURRENCE_COUNT]=
"incorrect number of values for parameter";
66 _errmsgs[VALUE_DISALLOWED] =
"value is not among defined set";
67 _errmsgs[VALUE_OUT_OF_RANGE] =
"value is out of range";
68 _errmsgs[BAD_VALUE] =
"illegal value";
69 _errmsgs[UNKNOWN_NAME] =
"parameter name is unknown";
70 _errmsgs[BAD_DEFINITION] =
"malformed definition";
71 _errmsgs[NOT_LOADED] =
"file not loaded"
72 " -- call Policy.loadPolicyFiles() before validating";
73 _errmsgs[UNKNOWN_ERROR] =
"unknown error";
76 vector<string> ValidationError::getParamNames()
const {
77 vector<string> result;
78 ParamLookup::const_iterator i;
79 for (i = _errors.begin(); i != _errors.end(); ++i)
80 result.push_back(i->first);
84 string ValidationError::describe(
string prefix)
const {
88 for (list<string>::const_iterator i = names.begin(); i != names.end(); ++i)
89 os << prefix << *i <<
": "
90 << getErrorMessageFor((ErrorType)getErrors(*i)) << endl;
94 char const* ValidationError::what(
void)
const throw() {
99 int n = getParamCount();
100 os <<
"Validation error";
101 if (n == 1) os <<
" (1 error)";
102 else if (n > 1) os <<
" (" << getParamCount() <<
" errors)";
103 if (getParamCount() == 0)
104 os <<
": no errors" <<
"\n";
106 os <<
": \n" << describe(
" * ");
109 return buffer.c_str();
112 ValidationError::~ValidationError() throw() { }
118 Definition::~Definition() { }
121 if (_policy->isString(Dictionary::KW_TYPE)) {
122 const string& type = _policy->getString(Dictionary::KW_TYPE);
126 }
catch(BadNameError&) {
128 (DictionaryError,
string(
"Unknown type: \"") + type +
"\".");
131 throw LSST_EXCEPT(DictionaryError,
string(
"Illegal type: \"") + type
136 else if (_policy->exists(Dictionary::KW_TYPE)) {
138 (DictionaryError,
string(
"Expected string for \"type\"; found ")
139 + _policy->getTypeName(Dictionary::KW_TYPE) +
" instead.");
149 const string Definition::getDescription()
const {
150 if (_policy->exists(Dictionary::KW_DESCRIPTION))
151 return _policy->getString(Dictionary::KW_DESCRIPTION);
159 const int Definition::getMaxOccurs()
const {
160 if (_policy->exists(Dictionary::KW_MAX_OCCUR))
161 return _policy->getInt(Dictionary::KW_MAX_OCCUR);
169 const int Definition::getMinOccurs()
const {
170 if (_policy->exists(Dictionary::KW_MIN_OCCUR))
171 return _policy->getInt(Dictionary::KW_MIN_OCCUR);
183 void Definition::setDefaultIn(Policy& policy,
const string& withName,
184 ValidationError* errs)
const
186 if (! _policy->exists(
"default"))
return;
195 setDefaultIn<bool>(policy, withName, errs);
197 setDefaultIn<int>(policy, withName, errs);
199 setDefaultIn<double>(policy, withName, errs);
201 setDefaultIn<string>(policy, withName, errs);
203 setDefaultIn<Policy::Ptr>(policy, withName, errs);
205 string(
"Programmer Error: Unknown type for \"")
206 + getPrefix() + withName +
"\": "
218 void Definition::validate(
const Policy& policy,
const string& name,
219 ValidationError *errs)
const
222 ValidationError *use = &ve;
223 if (errs != 0) use = errs;
225 if (! policy.exists(name)) {
226 if (getMinOccurs() > 0)
227 use->addError(getPrefix() + name, ValidationError::MISSING_REQUIRED);
236 validateBasic<bool>(name, policy, use);
240 validateBasic<int>(name, policy, use);
244 validateBasic<double>(name, policy, use);
248 validateBasic<string>(name, policy, use);
252 validateBasic<Policy::ConstPtr>(name, policy, use);
253 validateRecurse(name, policy.getConstPolicyArray(name), use);
257 use->addError(getPrefix() + name, ValidationError::NOT_LOADED);
262 string(
"Unknown type for \"") + getPrefix() + name
263 +
"\": \"" + policy.getTypeName(name) +
"\"");
266 if (errs == 0 && ve.getParamCount() > 0)
throw ve;
276 void Definition::validateCount(
const string& name,
int count,
277 ValidationError *errs)
const {
278 int max = getMaxOccurs();
279 if (max >= 0 && count > max)
280 errs->addError(getPrefix() + name, ValidationError::TOO_MANY_VALUES);
281 if (count < getMinOccurs()) {
283 errs->addError(getPrefix() + name, ValidationError::MISSING_REQUIRED);
285 errs->addError(getPrefix() + name, ValidationError::NOT_AN_ARRAY);
287 errs->addError(getPrefix() + name, ValidationError::ARRAY_TOO_SHORT);
296 bool operator<(
const Policy& a,
const Policy&
b) {
return true; }
300 void Definition::validateRecurse(
const string& name,
302 ValidationError *errs)
const
304 for (Policy::ConstPolicyPtrArray::const_iterator i = value.begin();
305 i != value.end(); ++i) {
307 validateRecurse(name, *p, errs);
312 void Definition::validateRecurse(
const string& name,
const Policy& value,
313 ValidationError *errs)
const
317 (pexExcept::LogicError,
string(
"Wrong type: expected ")
319 +
" but found " + getTypeName() +
". // recurse if we have a sub-definition");
321 else if (_policy->exists(Dictionary::KW_DICT)) {
322 if (!_policy->isPolicy(Dictionary::KW_DICT))
324 (DictionaryError,
string(
"Wrong type for ") + getPrefix() + name
325 +
" \"" + Dictionary::KW_DICT +
"\": expected Policy, but found "
326 + _policy->getTypeName(Dictionary::KW_DICT) +
".");
328 Dictionary subdict(*(_policy->getPolicy(Dictionary::KW_DICT)));
329 subdict.setPrefix(_prefix + name +
".");
330 subdict.validate(value, errs);
334 else if (_policy->exists(Dictionary::KW_DICT_FILE)) {
336 (pexExcept::LogicError, _prefix + name
337 +
"." + Dictionary::KW_DICT_FILE +
" needs to be loaded with "
338 "Dictionary.loadPolicyFiles() before validating.");
347 void Definition::validateBasic(
const string& name,
const T& value,
348 int curcount, ValidationError *errs)
const
351 ValidationError *use = &ve;
352 if (errs != 0) use = errs;
356 int maxOccurs = getMaxOccurs();
357 if (maxOccurs >= 0 && curcount + 1 > maxOccurs)
358 use->addError(getPrefix() + name, ValidationError::TOO_MANY_VALUES);
361 if (getType() !=
Policy::UNDEF && getType() != Policy::getValueType<T>()) {
362 use->addError(getPrefix() + name, ValidationError::WRONG_TYPE);
364 else if (_policy->isPolicy(Dictionary::KW_ALLOWED)) {
366 = _policy->getPolicyArray(Dictionary::KW_ALLOWED);
369 bool minFound =
false, maxFound =
false;
372 for (Policy::PolicyPtrArray::const_iterator it = allowed.begin();
373 it != allowed.end(); ++it)
376 if (a->exists(Dictionary::KW_MIN)) {
382 string(
"Min value for ") + getPrefix() + name
383 +
" (" + lexical_cast<string>(min)
384 +
") already specified; additional value not allowed.");
387 min = a->getValue<T>(Dictionary::KW_MIN);
389 }
catch(TypeError& e) {
392 string(
"Wrong type for ") + getPrefix() + name
393 +
" min value: expected " + getTypeName() +
", found "
394 + a->getTypeName(Dictionary::KW_MIN) +
".");
399 if (a->exists(Dictionary::KW_MAX)) {
403 string(
"Max value for ") + getPrefix() + name
404 +
" (" + lexical_cast<string>(max)
405 +
") already specified; additional value not allowed.");
407 max = a->getValue<T>(Dictionary::KW_MAX);
409 }
catch(TypeError& e) {
412 string(
"Wrong type for ") + getPrefix() + name
413 +
" max value: expected " + getTypeName() +
", found "
414 + a->getTypeName(Dictionary::KW_MAX) +
".");
417 if (a->exists(Dictionary::KW_VALUE)) {
418 const T& value = a->getValue<T>(Dictionary::KW_VALUE);
420 allvals.insert(value);
422 vector<T> values = a->getValueArray<T>(Dictionary::KW_VALUE);
423 for (
typename vector<T>::const_iterator vi = values.begin();
424 vi != values.end(); ++vi)
429 if ((minFound && value < min) || (maxFound && max < value))
430 use->addError(getPrefix() + name, ValidationError::VALUE_OUT_OF_RANGE);
432 if (allvals.size() > 0 && allvals.count(value) == 0)
433 use->addError(getPrefix() + name, ValidationError::VALUE_DISALLOWED);
435 if (errs == 0 && ve.getParamCount() > 0)
throw ve;
440 template void Definition::validateBasic<Policy::Ptr>
441 (std::string
const &,
Policy::Ptr const &, int, ValidationError*)
const;
451 void Definition::validate(
const string& name,
bool value,
int curcount,
452 ValidationError *errs)
const
454 validateBasic<bool>(name, value, curcount, errs);
457 void Definition::validate(
const string& name,
int value,
int curcount,
458 ValidationError *errs)
const
460 validateBasic<int>(name, value, curcount, errs);
463 void Definition::validate(
const string& name,
double value,
int curcount,
464 ValidationError *errs)
const
466 validateBasic<double>(name, value, curcount, errs);
469 void Definition::validate(
const string& name,
string value,
int curcount,
470 ValidationError *errs)
const
472 validateBasic<string>(name, value, curcount, errs);
475 void Definition::validate(
const string& name,
const Policy& value,
476 int curcount, ValidationError *errs)
const
478 validateBasic<Policy>(name, value, curcount, errs);
479 validateRecurse(name, value, errs);
492 ValidationError *errs)
const
494 validateBasic<bool>(name, value, errs);
497 void Definition::validate(
const string& name,
const Policy::IntArray& value,
498 ValidationError *errs)
const
500 validateBasic<int>(name, value, errs);
504 ValidationError *errs)
const
506 validateBasic<double>(name, value, errs);
509 ValidationError *errs)
const
511 validateBasic<string>(name, value, errs);
515 ValidationError *errs)
const
517 validateBasic<Policy::ConstPtr>(name, value, errs);
518 validateRecurse(name, value, errs);
521 void Definition::check()
const {
522 static set<string> okayKeywords;
523 if (okayKeywords.size() == 0) {
524 okayKeywords.insert(Dictionary::KW_TYPE);
525 okayKeywords.insert(Dictionary::KW_DICT);
526 okayKeywords.insert(Dictionary::KW_DICT_FILE);
528 okayKeywords.insert(Dictionary::KW_MIN_OCCUR);
529 okayKeywords.insert(Dictionary::KW_MAX_OCCUR);
530 okayKeywords.insert(Dictionary::KW_MIN);
531 okayKeywords.insert(Dictionary::KW_MAX);
532 okayKeywords.insert(Dictionary::KW_ALLOWED);
533 okayKeywords.insert(Dictionary::KW_DESCRIPTION);
534 okayKeywords.insert(Dictionary::KW_DEFAULT);
537 for (Policy::StringArray::const_iterator i = terms.begin();
538 i != terms.end(); ++i)
540 if (okayKeywords.count(*i) == 1)
continue;
542 (DictionaryError,
string(
"Unknown Dictionary property found at ")
543 + _prefix +
_name +
": " + *i);
551 const char* Dictionary::KW_DICT =
"dictionary";
552 const char* Dictionary::KW_DICT_FILE =
"dictionaryFile";
553 const char* Dictionary::KW_TYPE =
"type";
554 const char* Dictionary::KW_DESCRIPTION =
"description";
555 const char* Dictionary::KW_DEFAULT =
"default";
556 const char* Dictionary::KW_DEFINITIONS =
"definitions";
557 const char* Dictionary::KW_CHILD_DEF =
"childDefinition";
558 const char* Dictionary::KW_ALLOWED =
"allowed";
559 const char* Dictionary::KW_MIN_OCCUR =
"minOccurs";
560 const char* Dictionary::KW_MAX_OCCUR =
"maxOccurs";
561 const char* Dictionary::KW_MIN =
"min";
562 const char* Dictionary::KW_MAX =
"max";
563 const char* Dictionary::KW_VALUE =
"value";
565 const regex Dictionary::FIELDSEP_RE(
"\\.");
570 Dictionary::Dictionary(
const char *filePath) : Policy(filePath) {
571 if (!
exists(KW_DEFINITIONS))
572 throw LSST_EXCEPT(pexExcept::RuntimeError,
string(filePath)
573 +
": does not contain a Dictionary");
576 Dictionary::Dictionary(
const string& filePath) : Policy(filePath) {
577 if (!
exists(KW_DEFINITIONS))
578 throw LSST_EXCEPT(pexExcept::RuntimeError,
string(filePath)
579 +
": does not contain a Dictionary");
582 Dictionary::Dictionary(
const PolicyFile& filePath) : Policy(filePath) {
583 if (!
exists(KW_DEFINITIONS))
584 throw LSST_EXCEPT(pexExcept::RuntimeError, filePath.getPath()
585 +
": does not contain a Dictionary");
595 Definition* Dictionary::makeDef(
const string& name)
const {
596 Policy *p =
const_cast<Dictionary*
>(
this);
600 sregex_token_iterator it = make_regex_token_iterator(name, FIELDSEP_RE, -1);
601 sregex_token_iterator end;
603 bool isWildcard =
false;
606 if (! p->isPolicy(KW_DEFINITIONS))
607 throw LSST_EXCEPT(DictionaryError,
"Definition for " + find
609 sp = p->getPolicy(KW_DEFINITIONS);
610 if (sp->isPolicy(find)) {
611 sp = sp->getPolicy(find);
614 else if (sp->isPolicy(Dictionary::KW_CHILD_DEF)) {
615 if (sp->valueCount(Dictionary::KW_CHILD_DEF) > 1)
617 (DictionaryError,
string(
"Multiple ") + KW_CHILD_DEF
618 +
"s found " +
"that match " + getPrefix() + name +
".");
619 sp = sp->getPolicy(Dictionary::KW_CHILD_DEF);
625 if (! sp->isPolicy(Dictionary::KW_DICT))
627 find +
"." + KW_DICT +
" not found.");
628 sp = sp->getPolicy(Dictionary::KW_DICT);
632 Definition* result =
new Definition(name, sp);
633 result->setWildcard(isWildcard);
634 result->setPrefix(getPrefix());
643 Policy::DictPtr Dictionary::getSubDictionary(
const string& name)
const {
644 string subname = string(KW_DEFINITIONS) +
"." + name +
".dictionary";
646 (pexExcept::LogicError,
647 string(
"sub-policy \"") + subname +
"\" not found.");
649 (DictionaryError, subname +
" is a " + getTypeName(subname)
651 ConstPtr subpol = getPolicy(subname);
653 result->setPrefix(_prefix + name +
".");
657 int Dictionary::loadPolicyFiles(
const fs::path& repository,
bool strict) {
661 for (
int level = 0; level < maxLevel; ++level) {
664 paramNames(params,
false);
665 list<string> toRemove;
666 for (list<string>::const_iterator ni=params.begin(); ni != params.end(); ++ni) {
668 static string endswith = string(
".") + KW_DICT_FILE;
669 size_t p = ni->rfind(endswith);
670 if (p == ni->length()-endswith.length()) {
671 string parent = ni->substr(0, p);
676 defin->set(Dictionary::KW_DICT, getFile(*ni));
678 defin->set(Dictionary::KW_DICT,
679 make_shared<PolicyFile>(getString(*ni)));
681 toRemove.push_back(*ni);
689 for (list<string>::iterator i = toRemove.begin(); i != toRemove.end(); ++i)
696 else result += newLoads;
699 (DictionaryError,
string(
"Exceeded recursion limit (")
700 + lexical_cast<string>(maxLevel)
701 +
") loading policy files; does this dictionary contain a circular"
709 void Dictionary::check()
const {
710 PolicyPtrArray defs = getValueArray<Policy::Ptr>(KW_DEFINITIONS);
711 if (defs.size() == 0)
713 string(
"no \"") + KW_DEFINITIONS +
"\" section found");
716 (DictionaryError,
string(
"expected a single \"") + KW_DEFINITIONS
717 +
"\" section; found " + lexical_cast<
string>(defs.size()));
720 for (Policy::StringArray::const_iterator i = names.begin();
721 i != names.end(); ++i)
723 scoped_ptr<Definition> def(makeDef(*i));
726 if (hasSubDictionary(*i)) {
729 ConstPtr subPol = defs[0]->getPolicy(*i);
731 getSubDictionary(*i)->check();
740 void Dictionary::validate(
const Policy& pol, ValidationError *errs)
const {
742 ValidationError *use = &ve;
743 if (errs != 0) use = errs;
747 for (Policy::StringArray::const_iterator i = params.begin();
748 i != params.end(); ++i)
751 scoped_ptr<Definition> def(makeDef(*i));
752 def->validate(pol, *i, use);
754 catch (NameNotFound& e) {
755 use->addError(getPrefix() + *i, ValidationError::UNKNOWN_NAME);
762 for (Policy::StringArray::const_iterator i = dn.begin(); i != dn.end(); ++i) {
763 const string& name = *i;
764 if (!pol.exists(name)) {
765 scoped_ptr<Definition> def(makeDef(name));
766 if (name != Dictionary::KW_CHILD_DEF && def->getMinOccurs() > 0)
767 use->addError(getPrefix() + name,
768 ValidationError::MISSING_REQUIRED);
772 if (errs == 0 && ve.getParamCount() > 0)
throw ve;
std::vector< int > IntArray
std::vector< Ptr > PolicyPtrArray
definition of the PolicyFile class
boost::shared_ptr< PolicyFile > FilePtr
std::string const & _name
boost::shared_ptr< const Policy > ConstPtr
boost::shared_ptr< Policy > Ptr
boost::shared_ptr< Dictionary > DictPtr
static const char *const typeName[]
std::vector< std::string > StringArray
#define POL_EXCEPT_VIRTFUNCS(etn)
#define LSST_EXCEPT(type,...)
std::vector< double > DoubleArray
static ValueType getTypeByName(const std::string &name)
definition of the Dictionary class
afw::table::Key< double > b
int loadPolicyFiles(bool strict=true)
std::vector< bool > BoolArray
bool operator<(Ellipse< DataT > const &a, Ellipse< DataT > const &b)
std::vector< ConstPtr > ConstPolicyPtrArray