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;