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] =
69 " -- call Policy.loadPolicyFiles() before validating";
70 _errmsgs[UNKNOWN_ERROR] =
"unknown error";
75 ParamLookup::const_iterator i;
76 for (i = _errors.begin(); i != _errors.end(); ++i)
result.push_back(i->first);
80 string ValidationError::describe(
string prefix)
const {
85 os <<
prefix << *i <<
": " << getErrorMessageFor((ErrorType)getErrors(*i)) <<
endl;
89 char const* ValidationError::what(
void)
const throw() {
94 int n = getParamCount();
95 os <<
"Validation error";
99 os <<
" (" << getParamCount() <<
" errors)";
100 if (getParamCount() == 0)
104 os <<
": \n" << describe(
" * ");
107 return buffer.
c_str();
110 ValidationError::~ValidationError() throw() {}
116 Definition::~Definition() {}
119 if (_policy->isString(Dictionary::KW_TYPE)) {
120 const string&
type = _policy->getString(Dictionary::KW_TYPE);
124 }
catch (BadNameError&) {
125 throw LSST_EXCEPT(DictionaryError,
string(
"Unknown type: \"") +
type +
"\".");
128 throw LSST_EXCEPT(DictionaryError,
string(
"Illegal type: \"") +
type +
"\"; use \"" +
132 }
else if (_policy->exists(Dictionary::KW_TYPE)) {
133 throw LSST_EXCEPT(DictionaryError,
string(
"Expected string for \"type\"; found ") +
134 _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);
156 const int Definition::getMaxOccurs()
const {
157 if (_policy->exists(Dictionary::KW_MAX_OCCUR))
158 return _policy->getInt(Dictionary::KW_MAX_OCCUR);
167 const int Definition::getMinOccurs()
const {
168 if (_policy->exists(Dictionary::KW_MIN_OCCUR))
169 return _policy->getInt(Dictionary::KW_MIN_OCCUR);
181 void Definition::setDefaultIn(Policy& policy,
const string& withName, 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);
202 getPrefix() + withName +
216 ValidationError* use = &ve;
217 if (errs != 0) use = errs;
219 if (!policy.exists(
name)) {
220 if (getMinOccurs() > 0) use->addError(getPrefix() +
name, ValidationError::MISSING_REQUIRED);
229 validateBasic<bool>(
name, policy, use);
233 validateBasic<int>(
name, policy, use);
237 validateBasic<double>(
name, policy, use);
241 validateBasic<string>(
name, policy, use);
245 validateBasic<Policy::ConstPtr>(
name, policy, use);
246 validateRecurse(
name, policy.getConstPolicyArray(
name), use);
250 use->addError(getPrefix() +
name, ValidationError::NOT_LOADED);
255 "\": \"" + policy.getTypeName(
name) +
"\"");
258 if (errs == 0 && ve.getParamCount() > 0)
throw ve;
268 void Definition::validateCount(
const string&
name,
int count, ValidationError* errs)
const {
269 int max = getMaxOccurs();
270 if (
max >= 0 && count >
max) errs->addError(getPrefix() +
name, ValidationError::TOO_MANY_VALUES);
271 if (count < getMinOccurs()) {
273 errs->addError(getPrefix() +
name, ValidationError::MISSING_REQUIRED);
275 errs->addError(getPrefix() +
name, ValidationError::NOT_AN_ARRAY);
277 errs->addError(getPrefix() +
name, ValidationError::ARRAY_TOO_SHORT);
286 bool operator<(
const Policy&
a,
const Policy&
b) {
return true; }
291 ValidationError* errs)
const {
292 for (Policy::ConstPolicyPtrArray::const_iterator i = value.begin(); i != value.end(); ++i) {
294 validateRecurse(
name, *p, errs);
299 void Definition::validateRecurse(
const string&
name,
const Policy& value, ValidationError* errs)
const {
300 if (_policy->exists(Dictionary::KW_DICT)) {
301 if (!_policy->isPolicy(Dictionary::KW_DICT))
302 throw LSST_EXCEPT(DictionaryError,
string(
"Wrong type for ") + getPrefix() +
name +
" \"" +
303 Dictionary::KW_DICT +
304 "\": expected Policy, but found " +
305 _policy->getTypeName(Dictionary::KW_DICT) +
".");
307 Dictionary subdict(*(_policy->getPolicy(Dictionary::KW_DICT)));
308 subdict.setPrefix(_prefix +
name +
".");
309 subdict.validate(value, errs);
313 else if (_policy->exists(Dictionary::KW_DICT_FILE)) {
315 " needs to be loaded with "
316 "Dictionary.loadPolicyFiles() before validating.");
326 void Definition::validateBasic(
const string&
name,
const T& value,
int curcount,
327 ValidationError* errs)
const {
329 ValidationError* use = &ve;
330 if (errs != 0) use = errs;
334 int maxOccurs = getMaxOccurs();
335 if (maxOccurs >= 0 && curcount + 1 > maxOccurs)
336 use->addError(getPrefix() +
name, ValidationError::TOO_MANY_VALUES);
339 if (getType() !=
Policy::UNDEF && getType() != Policy::getValueType<T>()) {
340 use->addError(getPrefix() +
name, ValidationError::WRONG_TYPE);
341 }
else if (_policy->isPolicy(Dictionary::KW_ALLOWED)) {
345 bool minFound =
false, maxFound =
false;
348 for (Policy::PolicyPtrArray::const_iterator it = allowed.begin(); it != allowed.end(); ++it) {
350 if (
a->exists(Dictionary::KW_MIN)) {
355 string(
"Min value for ") + getPrefix() +
name +
356 " already specified; additional value not allowed.");
359 min =
a->getValue<T>(Dictionary::KW_MIN);
361 }
catch (TypeError& e) {
362 throw LSST_EXCEPT(DictionaryError,
string(
"Wrong type for ") + getPrefix() +
name +
363 " min value: expected " + getTypeName() +
365 a->getTypeName(Dictionary::KW_MIN) +
".");
370 if (
a->exists(Dictionary::KW_MAX)) {
373 string(
"Max value for ") + getPrefix() +
name +
374 " already specified; additional value not allowed.");
376 max =
a->getValue<T>(Dictionary::KW_MAX);
378 }
catch (TypeError& e) {
379 throw LSST_EXCEPT(DictionaryError,
string(
"Wrong type for ") + getPrefix() +
name +
380 " max value: expected " + getTypeName() +
382 a->getTypeName(Dictionary::KW_MAX) +
".");
385 if (
a->exists(Dictionary::KW_VALUE)) {
386 const T& value =
a->getValue<T>(Dictionary::KW_VALUE);
390 vector<T> values =
a->getValueArray<T>(Dictionary::KW_VALUE);
396 if ((minFound && value <
min) || (maxFound &&
max < value))
397 use->addError(getPrefix() +
name, ValidationError::VALUE_OUT_OF_RANGE);
399 if (allvals.
size() > 0 && allvals.
count(value) == 0)
400 use->addError(getPrefix() +
name, ValidationError::VALUE_DISALLOWED);
402 if (errs == 0 && ve.getParamCount() > 0)
throw ve;
408 ValidationError*)
const;
419 validateBasic<bool>(
name, value, curcount, errs);
423 validateBasic<int>(
name, value, curcount, errs);
427 validateBasic<double>(
name, value, curcount, errs);
431 validateBasic<string>(
name, value, curcount, errs);
435 ValidationError* errs)
const {
436 validateBasic<Policy>(
name, value, curcount, errs);
437 validateRecurse(
name, value, errs);
450 validateBasic<bool>(
name, value, errs);
454 validateBasic<int>(
name, value, errs);
458 validateBasic<double>(
name, value, errs);
461 validateBasic<string>(
name, value, errs);
465 ValidationError* errs)
const {
466 validateBasic<Policy::ConstPtr>(
name, value, errs);
467 validateRecurse(
name, value, errs);
470 void Definition::check()
const {
472 if (okayKeywords.
size() == 0) {
473 okayKeywords.
insert(Dictionary::KW_TYPE);
474 okayKeywords.
insert(Dictionary::KW_DICT);
475 okayKeywords.
insert(Dictionary::KW_DICT_FILE);
477 okayKeywords.
insert(Dictionary::KW_MIN_OCCUR);
478 okayKeywords.
insert(Dictionary::KW_MAX_OCCUR);
479 okayKeywords.
insert(Dictionary::KW_MIN);
480 okayKeywords.
insert(Dictionary::KW_MAX);
481 okayKeywords.
insert(Dictionary::KW_ALLOWED);
482 okayKeywords.
insert(Dictionary::KW_DESCRIPTION);
483 okayKeywords.
insert(Dictionary::KW_DEFAULT);
486 for (Policy::StringArray::const_iterator i = terms.begin(); i != terms.end(); ++i) {
487 if (okayKeywords.
count(*i) == 1)
491 string(
"Unknown Dictionary property found at ") + _prefix + _name +
": " + *i);
499 const char* Dictionary::KW_DICT =
"dictionary";
500 const char* Dictionary::KW_DICT_FILE =
"dictionaryFile";
501 const char* Dictionary::KW_TYPE =
"type";
502 const char* Dictionary::KW_DESCRIPTION =
"description";
503 const char* Dictionary::KW_DEFAULT =
"default";
504 const char* Dictionary::KW_DEFINITIONS =
"definitions";
505 const char* Dictionary::KW_CHILD_DEF =
"childDefinition";
506 const char* Dictionary::KW_ALLOWED =
"allowed";
507 const char* Dictionary::KW_MIN_OCCUR =
"minOccurs";
508 const char* Dictionary::KW_MAX_OCCUR =
"maxOccurs";
509 const char* Dictionary::KW_MIN =
"min";
510 const char* Dictionary::KW_MAX =
"max";
511 const char* Dictionary::KW_VALUE =
"value";
513 const boost::regex Dictionary::FIELDSEP_RE(
"\\.");
518 Dictionary::Dictionary(
const char* filePath) : Policy(filePath) {
519 if (!
exists(KW_DEFINITIONS))
523 Dictionary::Dictionary(
const string& filePath) : Policy(filePath) {
524 if (!
exists(KW_DEFINITIONS))
528 Dictionary::Dictionary(
const PolicyFile& filePath) : Policy(filePath) {
529 if (!
exists(KW_DEFINITIONS))
540 Definition* Dictionary::makeDef(
const string&
name)
const {
541 Policy* p =
const_cast<Dictionary*
>(
this);
545 boost::sregex_token_iterator it = boost::make_regex_token_iterator(
name, FIELDSEP_RE, -1);
546 boost::sregex_token_iterator
end;
548 bool isWildcard =
false;
551 if (!p->isPolicy(KW_DEFINITIONS))
552 throw LSST_EXCEPT(DictionaryError,
"Definition for " + find +
" not found.");
553 sp = p->getPolicy(KW_DEFINITIONS);
554 if (sp->isPolicy(find)) {
555 sp = sp->getPolicy(find);
557 }
else if (sp->isPolicy(Dictionary::KW_CHILD_DEF)) {
558 if (sp->valueCount(Dictionary::KW_CHILD_DEF) > 1)
559 throw LSST_EXCEPT(DictionaryError,
string(
"Multiple ") + KW_CHILD_DEF +
"s found " +
560 "that match " + getPrefix() +
name +
".");
561 sp = sp->getPolicy(Dictionary::KW_CHILD_DEF);
567 if (!sp->isPolicy(Dictionary::KW_DICT))
568 throw LSST_EXCEPT(DictionaryError, find +
"." + KW_DICT +
" not found.");
569 sp = sp->getPolicy(Dictionary::KW_DICT);
573 Definition*
result =
new Definition(
name, sp);
574 result->setWildcard(isWildcard);
575 result->setPrefix(getPrefix());
585 string subname =
string(KW_DEFINITIONS) +
"." +
name +
".dictionary";
586 if (!exists(subname))
588 if (!isPolicy(subname))
589 throw LSST_EXCEPT(DictionaryError, subname +
" is a " + getTypeName(subname) +
" instead of a " +
591 ConstPtr subpol = getPolicy(subname);
597 int Dictionary::loadPolicyFiles(
const boost::filesystem::path& repository,
bool strict) {
601 for (
int level = 0; level < maxLevel; ++level) {
604 paramNames(params,
false);
608 static string endswith =
string(
".") + KW_DICT_FILE;
609 size_t p = ni->
rfind(endswith);
610 if (p == ni->length() - endswith.
length()) {
611 string parent = ni->substr(0, p);
616 defin->set(Dictionary::KW_DICT, getFile(*ni));
618 defin->set(Dictionary::KW_DICT, std::make_shared<PolicyFile>(getString(*ni)));
638 ") loading policy files; does this dictionary contain a circular"
646 void Dictionary::check()
const {
647 PolicyPtrArray defs = getValueArray<Policy::Ptr>(KW_DEFINITIONS);
648 if (defs.size() == 0)
649 throw LSST_EXCEPT(DictionaryError,
string(
"no \"") + KW_DEFINITIONS +
"\" section found");
651 throw LSST_EXCEPT(DictionaryError,
string(
"expected a single \"") + KW_DEFINITIONS +
655 for (Policy::StringArray::const_iterator i = names.begin(); i != names.end(); ++i) {
659 if (hasSubDictionary(*i)) {
662 ConstPtr subPol = defs[0]->getPolicy(*i);
663 if (subPol->getValueType(KW_DICT) !=
Policy::FILE) getSubDictionary(*i)->check();
674 ValidationError* use = &ve;
675 if (errs != 0) use = errs;
679 for (Policy::StringArray::const_iterator i = params.begin(); i != params.end(); ++i) {
682 def->validate(pol, *i, use);
683 }
catch (NameNotFound& e) {
684 use->addError(getPrefix() + *i, ValidationError::UNKNOWN_NAME);
691 for (Policy::StringArray::const_iterator i = dn.begin(); i != dn.end(); ++i) {
692 const string&
name = *i;
693 if (!pol.exists(
name)) {
695 if (
name != Dictionary::KW_CHILD_DEF && def->getMinOccurs() > 0)
696 use->addError(getPrefix() +
name, ValidationError::MISSING_REQUIRED);
700 if (errs == 0 && ve.getParamCount() > 0)
throw ve;