LSSTApplications  10.0-2-g4f67435,11.0.rc2+1,11.0.rc2+12,11.0.rc2+3,11.0.rc2+4,11.0.rc2+5,11.0.rc2+6,11.0.rc2+7,11.0.rc2+8
LSSTDataManagementBasePackage
Dictionary.cc
Go to the documentation of this file.
1 /*
2  * LSST Data Management System
3  * Copyright 2008, 2009, 2010 LSST Corporation.
4  *
5  * This product includes software developed by the
6  * LSST Project (http://www.lsst.org/).
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the LSST License Statement and
19  * the GNU General Public License along with this program. If not,
20  * see <http://www.lsstcorp.org/LegalNotices/>.
21  */
22 
23 /*
24  * Dictionary
25  */
28 // #include "lsst/pex/utils/Trace.h"
29 
30 #include <boost/scoped_ptr.hpp>
31 #include <boost/make_shared.hpp>
32 #include <boost/lexical_cast.hpp>
33 #include <boost/regex.hpp>
34 
35 #include <stdexcept>
36 #include <memory>
37 #include <string>
38 #include <set>
39 
40 namespace pexExcept = lsst::pex::exceptions;
41 
42 namespace lsst {
43 namespace pex {
44 namespace policy {
45 
46 //@cond
47 
48 using namespace std;
49 
50 const string ValidationError::EMPTY;
51 
52 ValidationError::MsgLookup ValidationError::_errmsgs;
53 
54 POL_EXCEPT_VIRTFUNCS(lsst::pex::policy::ValidationError)
55 
56 void ValidationError::_loadMessages() {
57  _errmsgs[OK] = EMPTY;
58  _errmsgs[WRONG_TYPE] = "value has the incorrect type";
59  _errmsgs[MISSING_REQUIRED] = "no value available for required parameter";
60  _errmsgs[NOT_AN_ARRAY] = "value is not an array as required";
61  _errmsgs[ARRAY_TOO_SHORT] = "insufficient number of array values";
62  _errmsgs[TOO_FEW_VALUES] = "not enough values for parameter";
63  _errmsgs[TOO_MANY_VALUES] = "too many values provided for parameter";
64  _errmsgs[WRONG_OCCURRENCE_COUNT]="incorrect number of values for parameter";
65  _errmsgs[VALUE_DISALLOWED] = "value is not among defined set";
66  _errmsgs[VALUE_OUT_OF_RANGE] = "value is out of range";
67  _errmsgs[BAD_VALUE] = "illegal value";
68  _errmsgs[UNKNOWN_NAME] = "parameter name is unknown";
69  _errmsgs[BAD_DEFINITION] = "malformed definition";
70  _errmsgs[NOT_LOADED] = "file not loaded"
71  " -- call Policy.loadPolicyFiles() before validating";
72  _errmsgs[UNKNOWN_ERROR] = "unknown error";
73 }
74 
75 vector<string> ValidationError::getParamNames() const {
76  vector<string> result;
77  ParamLookup::const_iterator i;
78  for (i = _errors.begin(); i != _errors.end(); ++i)
79  result.push_back(i->first);
80  return result;
81 }
82 
83 string ValidationError::describe(string prefix) const {
84  ostringstream os;
85  list<string> names;
86  paramNames(names);
87  for (list<string>::const_iterator i = names.begin(); i != names.end(); ++i)
88  os << prefix << *i << ": "
89  << getErrorMessageFor((ErrorType)getErrors(*i)) << endl;
90  return os.str();
91 }
92 
93 char const* ValidationError::what(void) const throw() {
94  // static to avoid memory issue -- but a concurrency problem?
95  // copied from pex/exceptions/src/Exception.cc
96  static string buffer;
97  ostringstream os;
98  int n = getParamCount();
99  os << "Validation error";
100  if (n == 1) os << " (1 error)";
101  else if (n > 1) os << " (" << getParamCount() << " errors)";
102  if (getParamCount() == 0)
103  os << ": no errors" << "\n";
104  else {
105  os << ": \n" << describe(" * ");
106  }
107  buffer = os.str();
108  return buffer.c_str();
109 }
110 
111 ValidationError::~ValidationError() throw() { }
112 
114 // Definition
116 
117 Definition::~Definition() { }
118 
119 Policy::ValueType Definition::_determineType() const {
120  if (_policy->isString(Dictionary::KW_TYPE)) {
121  const string& type = _policy->getString(Dictionary::KW_TYPE);
122  Policy::ValueType result;
123  try {
124  result = Policy::getTypeByName(type);
125  } catch(BadNameError&) {
126  throw LSST_EXCEPT
127  (DictionaryError, string("Unknown type: \"") + type + "\".");
128  }
129  if (result == Policy::FILE)
130  throw LSST_EXCEPT(DictionaryError, string("Illegal type: \"") + type
131  + "\"; use \"" + Policy::typeName[Policy::POLICY]
132  + "\" instead.");
133  else return result;
134  }
135  else if (_policy->exists(Dictionary::KW_TYPE)) {
136  throw LSST_EXCEPT
137  (DictionaryError, string("Expected string for \"type\"; found ")
138  + _policy->getTypeName(Dictionary::KW_TYPE) + " instead.");
139  }
140 
141  else return Policy::UNDEF;
142 }
143 
148 const string Definition::getDescription() const {
149  if (_policy->exists(Dictionary::KW_DESCRIPTION))
150  return _policy->getString(Dictionary::KW_DESCRIPTION);
151  else return "";
152 }
153 
158 const int Definition::getMaxOccurs() const {
159  if (_policy->exists(Dictionary::KW_MAX_OCCUR))
160  return _policy->getInt(Dictionary::KW_MAX_OCCUR);
161  else return -1;
162 }
163 
168 const int Definition::getMinOccurs() const {
169  if (_policy->exists(Dictionary::KW_MIN_OCCUR))
170  return _policy->getInt(Dictionary::KW_MIN_OCCUR);
171  else return 0;
172 }
173 
174 
175 /*
176  * the default value into the given policy
177  * @param policy the policy object update
178  * @param withName the name to look for the value under. This must be
179  * a non-hierarchical name.
180  * @exception ValidationError if the value does not conform to this definition.
181  */
182 void Definition::setDefaultIn(Policy& policy, const string& withName,
183  ValidationError* errs) const
184 {
185  if (! _policy->exists("default")) return;
186 /*
187  Policy::ValueType type = getType();
188  if (type == Policy::UNDEF)
189  type = _policy->getValueType("default");
190 */
191  Policy::ValueType type = _policy->getValueType("default");
192 
193  if (type == Policy::BOOL)
194  setDefaultIn<bool>(policy, withName, errs);
195  else if (type == Policy::INT)
196  setDefaultIn<int>(policy, withName, errs);
197  else if (type == Policy::DOUBLE)
198  setDefaultIn<double>(policy, withName, errs);
199  else if (type == Policy::STRING)
200  setDefaultIn<string>(policy, withName, errs);
201  else if (type == Policy::POLICY)
202  setDefaultIn<Policy::Ptr>(policy, withName, errs);
203  else throw LSST_EXCEPT(pexExcept::LogicError,
204  string("Programmer Error: Unknown type for \"")
205  + getPrefix() + withName + "\": "
206  + Policy::typeName[getType()]);
207 }
208 
209 /*
210  * confirm that a Policy parameter conforms to this definition
211  * @param policy the policy object to inspect
212  * @param name the name to look for the value under. If not given
213  * the name set in this definition will be used.
214  * @exception ValidationError if the value does not conform. The message
215  * should explain why.
216  */
217 void Definition::validate(const Policy& policy, const string& name,
218  ValidationError *errs) const
219 {
220  ValidationError ve(LSST_EXCEPT_HERE);
221  ValidationError *use = &ve;
222  if (errs != 0) use = errs;
223 
224  if (! policy.exists(name)) {
225  if (getMinOccurs() > 0)
226  use->addError(getPrefix() + name, ValidationError::MISSING_REQUIRED);
227  return;
228  }
229 
230  // What type is actually present in the policy?
231  Policy::ValueType type = policy.getValueType(name);
232 
233  switch (type) {
234  case Policy::BOOL:
235  validateBasic<bool>(name, policy, use);
236  break;
237 
238  case Policy::INT:
239  validateBasic<int>(name, policy, use);
240  break;
241 
242  case Policy::DOUBLE:
243  validateBasic<double>(name, policy, use);
244  break;
245 
246  case Policy::STRING:
247  validateBasic<string>(name, policy, use);
248  break;
249 
250  case Policy::POLICY:
251  validateBasic<Policy::ConstPtr>(name, policy, use);
252  validateRecurse(name, policy.getConstPolicyArray(name), use);
253  break;
254 
255  case Policy::FILE:
256  use->addError(getPrefix() + name, ValidationError::NOT_LOADED);
257  break;
258 
259  default:
260  throw LSST_EXCEPT(pexExcept::LogicError,
261  string("Unknown type for \"") + getPrefix() + name
262  + "\": \"" + policy.getTypeName(name) + "\"");
263  }
264 
265  if (errs == 0 && ve.getParamCount() > 0) throw ve;
266 }
267 
275 void Definition::validateCount(const string& name, int count,
276  ValidationError *errs) const {
277  int max = getMaxOccurs(); // -1 means no limit / undefined
278  if (max >= 0 && count > max)
279  errs->addError(getPrefix() + name, ValidationError::TOO_MANY_VALUES);
280  if (count < getMinOccurs()) {
281  if (count == 0)
282  errs->addError(getPrefix() + name, ValidationError::MISSING_REQUIRED);
283  else if (count == 1)
284  errs->addError(getPrefix() + name, ValidationError::NOT_AN_ARRAY);
285  else
286  errs->addError(getPrefix() + name, ValidationError::ARRAY_TOO_SHORT);
287  }
288 }
289 
295 bool operator<(const Policy& a, const Policy& b) { return true; }
296 bool operator<(const Policy::ConstPtr& a, const Policy::ConstPtr& b) { return true; }
297 bool operator<(const Policy::FilePtr& a, const Policy::FilePtr& b) { return true; }
298 
299 void Definition::validateRecurse(const string& name,
301  ValidationError *errs) const
302 {
303  for (Policy::ConstPolicyPtrArray::const_iterator i = value.begin();
304  i != value.end(); ++i) {
305  Policy::ConstPtr p = *i;
306  validateRecurse(name, *p, errs);
307  }
308 }
309 
310 /* Validate a sub-policy using a sub-dictionary. */
311 void Definition::validateRecurse(const string& name, const Policy& value,
312  ValidationError *errs) const
313 {
314  if (!getType() == Policy::POLICY) // should have checked this at a higher level
315  throw LSST_EXCEPT
316  (pexExcept::LogicError, string("Wrong type: expected ")
317  + Policy::typeName[Policy::POLICY] + " for " + getPrefix() + name
318  + " but found " + getTypeName() + ". // recurse if we have a sub-definition");
319  // recurse if we have a sub-definition
320  else if (_policy->exists(Dictionary::KW_DICT)) {
321  if (!_policy->isPolicy(Dictionary::KW_DICT))
322  throw LSST_EXCEPT
323  (DictionaryError, string("Wrong type for ") + getPrefix() + name
324  + " \"" + Dictionary::KW_DICT + "\": expected Policy, but found "
325  + _policy->getTypeName(Dictionary::KW_DICT) + ".");
326  else {
327  Dictionary subdict(*(_policy->getPolicy(Dictionary::KW_DICT)));
328  subdict.setPrefix(_prefix + name + ".");
329  subdict.validate(value, errs);
330  }
331  }
332  // is there an unresolved link here?
333  else if (_policy->exists(Dictionary::KW_DICT_FILE)) {
334  throw LSST_EXCEPT
335  (pexExcept::LogicError, _prefix + name
336  + "." + Dictionary::KW_DICT_FILE + " needs to be loaded with "
337  "Dictionary.loadPolicyFiles() before validating.");
338  }
339  // there's a policy type defined here, but no sub-definition (that is, no
340  // constraints -- it could be any policy), so anything is okay.
341  else { }
342 }
343 
344 // TODO: integrate all checks into check() rather than having them in validate()
345 template <class T>
346 void Definition::validateBasic(const string& name, const T& value,
347  int curcount, ValidationError *errs) const
348 {
349  ValidationError ve(LSST_EXCEPT_HERE);
350  ValidationError *use = &ve;
351  if (errs != 0) use = errs;
352 
353  // check if we're going to get too many
354  if (curcount >= 0) {
355  int maxOccurs = getMaxOccurs();
356  if (maxOccurs >= 0 && curcount + 1 > maxOccurs)
357  use->addError(getPrefix() + name, ValidationError::TOO_MANY_VALUES);
358  }
359 
360  if (getType() != Policy::UNDEF && getType() != Policy::getValueType<T>()) {
361  use->addError(getPrefix() + name, ValidationError::WRONG_TYPE);
362  }
363  else if (_policy->isPolicy(Dictionary::KW_ALLOWED)) {
364  Policy::PolicyPtrArray allowed
365  = _policy->getPolicyArray(Dictionary::KW_ALLOWED);
366 
367  T min, max;
368  bool minFound = false, maxFound = false;
369  set<T> allvals;
370  // iterate over the keys inside the "allowed" sub-policy
371  for (Policy::PolicyPtrArray::const_iterator it = allowed.begin();
372  it != allowed.end(); ++it)
373  {
374  Policy::Ptr a = *it;
375  if (a->exists(Dictionary::KW_MIN)) {
376  if (minFound) {
377  // Would like to catch this in Dictionary::check(), but that
378  // would require some fancy type-based logic.
379  throw LSST_EXCEPT
380  (DictionaryError,
381  string("Min value for ") + getPrefix() + name
382  + " (" + boost::lexical_cast<string>(min)
383  + ") already specified; additional value not allowed.");
384  }
385  try {
386  min = a->getValue<T>(Dictionary::KW_MIN);
387  minFound = true; // after min assign, in case of exceptions
388  } catch(TypeError& e) {
389  throw LSST_EXCEPT
390  (DictionaryError,
391  string("Wrong type for ") + getPrefix() + name
392  + " min value: expected " + getTypeName() + ", found "
393  + a->getTypeName(Dictionary::KW_MIN) + ".");
394  } catch(...) {
395  throw;
396  }
397  }
398  if (a->exists(Dictionary::KW_MAX)) {
399  if (maxFound)
400  throw LSST_EXCEPT
401  (DictionaryError,
402  string("Max value for ") + getPrefix() + name
403  + " (" + boost::lexical_cast<string>(max)
404  + ") already specified; additional value not allowed.");
405  try {
406  max = a->getValue<T>(Dictionary::KW_MAX);
407  maxFound = true; // after max assign, in case of exceptions
408  } catch(TypeError& e) {
409  throw LSST_EXCEPT
410  (DictionaryError,
411  string("Wrong type for ") + getPrefix() + name
412  + " max value: expected " + getTypeName() + ", found "
413  + a->getTypeName(Dictionary::KW_MAX) + ".");
414  }
415  }
416  if (a->exists(Dictionary::KW_VALUE)) {
417  const T& value = a->getValue<T>(Dictionary::KW_VALUE);
418 
419  allvals.insert(value);
420  // allvals.insert(a->getValue<T>(Dictionary::KW_VALUE));
421  vector<T> values = a->getValueArray<T>(Dictionary::KW_VALUE);
422  for (typename vector<T>::const_iterator vi = values.begin();
423  vi != values.end(); ++vi)
424  allvals.insert(*vi);
425  }
426  }
427 
428  if ((minFound && value < min) || (maxFound && max < value))
429  use->addError(getPrefix() + name, ValidationError::VALUE_OUT_OF_RANGE);
430 
431  if (allvals.size() > 0 && allvals.count(value) == 0)
432  use->addError(getPrefix() + name, ValidationError::VALUE_DISALLOWED);
433  }
434  if (errs == 0 && ve.getParamCount() > 0) throw ve;
435 }
436 
437 // instantiate to keep gcc 4.4 happy when compiling with opt=2
438 // (why? -- see LSST Trac ticket #1253)
439 template void Definition::validateBasic<Policy::Ptr>
440 (std::string const &, Policy::Ptr const &, int, ValidationError*) const;
441 
442 /*
443  * confirm that a Policy parameter name-value combination is consistent
444  * with this dictionary. This does not check occurrence compliance
445  * @param name the name of the parameter being checked
446  * @param value the value of the parameter to check.
447  * @exception ValidationError if the value does not conform. The message
448  * should explain why.
449  */
450 void Definition::validate(const string& name, bool value, int curcount,
451  ValidationError *errs) const
452 {
453  validateBasic<bool>(name, value, curcount, errs);
454 }
455 
456 void Definition::validate(const string& name, int value, int curcount,
457  ValidationError *errs) const
458 {
459  validateBasic<int>(name, value, curcount, errs);
460 }
461 
462 void Definition::validate(const string& name, double value, int curcount,
463  ValidationError *errs) const
464 {
465  validateBasic<double>(name, value, curcount, errs);
466 }
467 
468 void Definition::validate(const string& name, string value, int curcount,
469  ValidationError *errs) const
470 {
471  validateBasic<string>(name, value, curcount, errs);
472 }
473 
474 void Definition::validate(const string& name, const Policy& value,
475  int curcount, ValidationError *errs) const
476 {
477  validateBasic<Policy>(name, value, curcount, errs);
478  validateRecurse(name, value, errs);
479 }
480 
481 /*
482  * confirm that a Policy parameter name-array value combination is
483  * consistent with this dictionary. Unlike the scalar version,
484  * this does check occurrence compliance.
485  * @param name the name of the parameter being checked
486  * @param value the value of the parameter to check.
487  * @exception ValidationError if the value does not conform. The message
488  * should explain why.
489  */
490 void Definition::validate(const string& name, const Policy::BoolArray& value,
491  ValidationError *errs) const
492 {
493  validateBasic<bool>(name, value, errs);
494 }
495 
496 void Definition::validate(const string& name, const Policy::IntArray& value,
497  ValidationError *errs) const
498 {
499  validateBasic<int>(name, value, errs);
500 }
501 
502 void Definition::validate(const string& name, const Policy::DoubleArray& value,
503  ValidationError *errs) const
504 {
505  validateBasic<double>(name, value, errs);
506 }
507 void Definition::validate(const string& name, const Policy::StringArray& value,
508  ValidationError *errs) const
509 {
510  validateBasic<string>(name, value, errs);
511 }
512 
513 void Definition::validate(const string& name, const Policy::ConstPolicyPtrArray& value,
514  ValidationError *errs) const
515 {
516  validateBasic<Policy::ConstPtr>(name, value, errs);
517  validateRecurse(name, value, errs);
518 }
519 
520 void Definition::check() const {
521  static set<string> okayKeywords;
522  if (okayKeywords.size() == 0) {
523  okayKeywords.insert(Dictionary::KW_TYPE);
524  okayKeywords.insert(Dictionary::KW_DICT);
525  okayKeywords.insert(Dictionary::KW_DICT_FILE);
526  okayKeywords.insert(Policy::typeName[Policy::FILE]);
527  okayKeywords.insert(Dictionary::KW_MIN_OCCUR);
528  okayKeywords.insert(Dictionary::KW_MAX_OCCUR);
529  okayKeywords.insert(Dictionary::KW_MIN);
530  okayKeywords.insert(Dictionary::KW_MAX);
531  okayKeywords.insert(Dictionary::KW_ALLOWED);
532  okayKeywords.insert(Dictionary::KW_DESCRIPTION);
533  okayKeywords.insert(Dictionary::KW_DEFAULT);
534  }
535  Policy::StringArray terms = _policy->names(true);
536  for (Policy::StringArray::const_iterator i = terms.begin();
537  i != terms.end(); ++i)
538  {
539  if (okayKeywords.count(*i) == 1) continue;
540  else throw LSST_EXCEPT
541  (DictionaryError, string("Unknown Dictionary property found at ")
542  + _prefix + _name + ": " + *i);
543  }
544 }
545 
547 // Dictionary
549 
550 const char* Dictionary::KW_DICT = "dictionary";
551 const char* Dictionary::KW_DICT_FILE = "dictionaryFile";
552 const char* Dictionary::KW_TYPE = "type";
553 const char* Dictionary::KW_DESCRIPTION = "description";
554 const char* Dictionary::KW_DEFAULT = "default";
555 const char* Dictionary::KW_DEFINITIONS = "definitions";
556 const char* Dictionary::KW_CHILD_DEF = "childDefinition";
557 const char* Dictionary::KW_ALLOWED = "allowed";
558 const char* Dictionary::KW_MIN_OCCUR = "minOccurs";
559 const char* Dictionary::KW_MAX_OCCUR = "maxOccurs";
560 const char* Dictionary::KW_MIN = "min";
561 const char* Dictionary::KW_MAX = "max";
562 const char* Dictionary::KW_VALUE = "value";
563 
564 const boost::regex Dictionary::FIELDSEP_RE("\\.");
565 
566 /*
567  * load a dictionary from a file
568  */
569 Dictionary::Dictionary(const char *filePath) : Policy(filePath) {
570  if (!exists(KW_DEFINITIONS))
571  throw LSST_EXCEPT(pexExcept::RuntimeError, string(filePath)
572  + ": does not contain a Dictionary");
573  check();
574 }
575 Dictionary::Dictionary(const string& filePath) : Policy(filePath) {
576  if (!exists(KW_DEFINITIONS))
577  throw LSST_EXCEPT(pexExcept::RuntimeError, string(filePath)
578  + ": does not contain a Dictionary");
579  check();
580 }
581 Dictionary::Dictionary(const PolicyFile& filePath) : Policy(filePath) {
582  if (!exists(KW_DEFINITIONS))
583  throw LSST_EXCEPT(pexExcept::RuntimeError, filePath.getPath()
584  + ": does not contain a Dictionary");
585  check();
586 }
587 
588 /*
589  * return a definition for the named parameter. The caller is responsible
590  * for deleting the returned object. This is slightly more efficient than
591  * getDef().
592  * @param name the hierarchical name for the parameter
593  */
594 Definition* Dictionary::makeDef(const string& name) const {
595  Policy *p = const_cast<Dictionary*>(this);
596  Policy::Ptr sp; // sub-policy
597 
598  // split the name
599  boost::sregex_token_iterator it = boost::make_regex_token_iterator(name, FIELDSEP_RE, -1);
600  boost::sregex_token_iterator end;
601  string find;
602  bool isWildcard = false; // was the immediate parent a wildcard childDefinition?
603  while (it != end) {
604  find = *it;
605  if (! p->isPolicy(KW_DEFINITIONS))
606  throw LSST_EXCEPT(DictionaryError, "Definition for " + find
607  + " not found.");
608  sp = p->getPolicy(KW_DEFINITIONS);
609  if (sp->isPolicy(find)) {
610  sp = sp->getPolicy(find);
611  isWildcard = false; // update each time, to get only immediate parent
612  }
613  else if (sp->isPolicy(Dictionary::KW_CHILD_DEF)) {
614  if (sp->valueCount(Dictionary::KW_CHILD_DEF) > 1)
615  throw LSST_EXCEPT
616  (DictionaryError, string("Multiple ") + KW_CHILD_DEF
617  + "s found " + "that match " + getPrefix() + name + ".");
618  sp = sp->getPolicy(Dictionary::KW_CHILD_DEF);
619  isWildcard = true;
620  }
621  else throw LSST_EXCEPT(NameNotFound, find);
622  p = sp.get();
623  if (++it != end) {
624  if (! sp->isPolicy(Dictionary::KW_DICT))
625  throw LSST_EXCEPT(DictionaryError,
626  find + "." + KW_DICT + " not found.");
627  sp = sp->getPolicy(Dictionary::KW_DICT);
628  p = sp.get();
629  }
630  }
631  Definition* result = new Definition(name, sp);
632  result->setWildcard(isWildcard);
633  result->setPrefix(getPrefix());
634  return result;
635 }
636 
642 Policy::DictPtr Dictionary::getSubDictionary(const string& name) const {
643  string subname = string(KW_DEFINITIONS) + "." + name + ".dictionary";
644  if (!exists(subname)) throw LSST_EXCEPT
645  (pexExcept::LogicError,
646  string("sub-policy \"") + subname + "\" not found.");
647  if (!isPolicy(subname)) throw LSST_EXCEPT
648  (DictionaryError, subname + " is a " + getTypeName(subname)
649  + " instead of a " + Policy::typeName[Policy::POLICY] + ".");
650  ConstPtr subpol = getPolicy(subname);
651  Policy::DictPtr result = boost::make_shared<Dictionary>(*subpol);
652  result->setPrefix(_prefix + name + ".");
653  return result;
654 }
655 
656 int Dictionary::loadPolicyFiles(const boost::filesystem::path& repository, bool strict) {
657  int maxLevel = 16;
658  int result = 0;
659  // loop until we reach the leaves
660  for (int level = 0; level < maxLevel; ++level) {
661  // find the "dictionaryFile" parameters
662  list<string> params;
663  paramNames(params, false);
664  list<string> toRemove;
665  for (list<string>::const_iterator ni=params.begin(); ni != params.end(); ++ni) {
666  // loop over the keys that end with ".dictionaryFile"
667  static string endswith = string(".") + KW_DICT_FILE;
668  size_t p = ni->rfind(endswith);
669  if (p == ni->length()-endswith.length()) {
670  string parent = ni->substr(0, p);
671  Policy::Ptr defin = getPolicy(parent);
672 
673  // these will get dereferenced with the call to super method
674  if (isFile(*ni))
675  defin->set(Dictionary::KW_DICT, getFile(*ni));
676  else
677  defin->set(Dictionary::KW_DICT,
678  boost::make_shared<PolicyFile>(getString(*ni)));
679 
680  toRemove.push_back(*ni);
681  }
682  }
683 
684  // if no new loads, then we've loaded everything
685  int newLoads = Policy::loadPolicyFiles(repository, strict);
686 
687  // remove obsolete dictionaryFile references, to prevent re-loading
688  for (list<string>::iterator i = toRemove.begin(); i != toRemove.end(); ++i)
689  remove(*i);
690 
691  if (newLoads == 0) {
692  check(); // validate self after everything is loaded
693  return result;
694  }
695  else result += newLoads;
696  }
697  throw LSST_EXCEPT
698  (DictionaryError, string("Exceeded recursion limit (")
699  + boost::lexical_cast<string>(maxLevel)
700  + ") loading policy files; does this dictionary contain a circular"
701  " definition?");
702 }
703 
708 void Dictionary::check() const {
709  PolicyPtrArray defs = getValueArray<Policy::Ptr>(KW_DEFINITIONS);
710  if (defs.size() == 0)
711  throw LSST_EXCEPT(DictionaryError,
712  string("no \"") + KW_DEFINITIONS + "\" section found");
713  if (defs.size() > 1)
714  throw LSST_EXCEPT
715  (DictionaryError, string("expected a single \"") + KW_DEFINITIONS
716  + "\" section; found " + boost::lexical_cast<string>(defs.size()));
717 
718  Policy::StringArray names = defs[0]->names(false);
719  for (Policy::StringArray::const_iterator i = names.begin();
720  i != names.end(); ++i)
721  {
722  boost::scoped_ptr<Definition> def(makeDef(*i));
723  def->check();
724 
725  if (hasSubDictionary(*i)) {
726  // if the subdict is a policy file, skip it -- it will have to be
727  // checked later, when it is loaded
728  ConstPtr subPol = defs[0]->getPolicy(*i);
729  if (subPol->getValueType(KW_DICT) != Policy::FILE)
730  getSubDictionary(*i)->check();
731  // TODO: test that loading a subdict from a reference gets re-checked
732  }
733  }
734 }
735 
736 /*
737  * validate a Policy against this Dictionary
738  */
739 void Dictionary::validate(const Policy& pol, ValidationError *errs) const {
740  ValidationError ve(LSST_EXCEPT_HERE);
741  ValidationError *use = &ve;
742  if (errs != 0) use = errs;
743  Policy::StringArray params = pol.names(true);
744 
745  // validate each item in policy
746  for (Policy::StringArray::const_iterator i = params.begin();
747  i != params.end(); ++i)
748  {
749  try {
750  boost::scoped_ptr<Definition> def(makeDef(*i));
751  def->validate(pol, *i, use);
752  }
753  catch (NameNotFound& e) {
754  use->addError(getPrefix() + *i, ValidationError::UNKNOWN_NAME);
755  }
756  }
757 
758  // check definitions of missing elements for required elements
759  Policy::ConstPtr defs = getDefinitions();
760  Policy::StringArray dn = defs->names(false);
761  for (Policy::StringArray::const_iterator i = dn.begin(); i != dn.end(); ++i) {
762  const string& name = *i;
763  if (!pol.exists(name)) { // item in dictionary, but not in policy
764  boost::scoped_ptr<Definition> def(makeDef(name));
765  if (name != Dictionary::KW_CHILD_DEF && def->getMinOccurs() > 0)
766  use->addError(getPrefix() + name,
767  ValidationError::MISSING_REQUIRED);
768  }
769  }
770 
771  if (errs == 0 && ve.getParamCount() > 0) throw ve;
772 }
773 
774 //@endcond
775 
776 } // namespace policy
777 } // namespace pex
778 } // namespace lsst
#define POL_EXCEPT_VIRTFUNCS(etn)
Definition: exceptions.h:39
std::vector< bool > BoolArray
Definition: Policy.h:178
definition of the PolicyFile class
table::Key< std::string > name
Definition: ApCorrMap.cc:71
boost::shared_ptr< PolicyFile > FilePtr
Definition: Policy.h:176
std::vector< std::string > StringArray
Definition: Policy.h:181
std::string const & _name
Definition: Mask.cc:678
boost::shared_ptr< Policy > Ptr
Definition: Policy.h:172
#define LSST_EXCEPT_HERE
Definition: Exception.h:40
static ValueType getTypeByName(const std::string &name)
std::vector< Ptr > PolicyPtrArray
Definition: Policy.h:182
std::vector< int > IntArray
Definition: Policy.h:179
static const char *const typeName[]
Definition: Policy.h:205
std::vector< double > DoubleArray
Definition: Policy.h:180
std::vector< ConstPtr > ConstPolicyPtrArray
Definition: Policy.h:184
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
boost::shared_ptr< const Policy > ConstPtr
Definition: Policy.h:173
boost::shared_ptr< Dictionary > DictPtr
Definition: Policy.h:174
def exists
Definition: cuda.py:53
definition of the Dictionary class
afw::table::Key< double > b
int loadPolicyFiles(bool strict=true)
Definition: Policy.h:775