2 * copyright(c) 2005 kuwata-lab all rights reserved.
7 import java.io.Serializable;
9 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.IdentityHashMap;
13 import java.util.Iterator;
14 import java.util.regex.Pattern;
15 import java.util.regex.Matcher;
16 import java.util.regex.PatternSyntaxException;
18 import org.onap.sdc.common.onaplog.Enums.LogLevel;
19 import org.onap.sdc.common.onaplog.OnapLoggerDebug;
22 * rule for validation.
23 * Validator class generates rule instances.
26 public class Rule implements Serializable{
27 private static final String RANGE1 = "/range";
28 private static final String RANGE2 = "range:";
29 private static final String ENUM_CONFLICT = "enum.conflict";
30 private static final String MAP_CONFLICT = "map.conflict";
31 private static final String LENGTH1 = "/length";
32 private static final String LENGTH2 = "length:";
33 private static final String LENGTH3 = "/length/";
34 private static final String SEQ_CONFLICT = "seq.conflict";
35 private static final String PATTERN1 = "pattern:";
36 private static final String MAPPING1 = "mapping:";
37 private static final String SEQUENCE1 = "/sequence";
38 private static final String MAX_EX = "max-ex";
39 private static final String MIN_EX = "min-ex";
40 private static final String TYPE1 = "/type";
41 private static final String TYPE_NOTSTR = "type.notstr";
42 private static final String TYPE_UNKNOWN = "type.unknown";
43 private static final String IDENT1 = "ident:";
44 private static final String UNIQUE1 = "unique:";
45 private static final String MAPPING2 = "/mapping";
46 private static final String MAPPING3 = "/mapping/=";
47 private static final String MAPPING4 = "/mapping/";
48 private static final String SEQUENCE2 = "sequence:";
49 private static final String SCALAR_CONFLICT = "scalar.conflict";
50 private static final String UNIQUE_NOTBOOL = "unique.notbool";
51 private static final String UNIQUE_NOTSCALAR = "unique.notscalar";
52 private static final String UNIQUE_ONROOT = "unique.onroot";
53 private static final String UNIQUE2 = "/unique";
54 private static final String IDENT_ONROOT = "ident.onroot";
55 private static final String IDENT_NOTSCALAR = "ident.notscalar";
56 private static final String IDENT_NOTMAP = "ident.notmap";
57 private static final String MAP = "map";
58 private static final String EMPTY_STRING = "";
59 private static final String SLASH = "/";
60 private static final String SCHEMA_NOTMAP = "schema.notmap";
61 private static final String SCHEMA_NOTMAP1 = "schema.notmap: {}";
62 private static final String PATTERN2 = "/pattern";
63 private static final String PATTERN_NOTSTR = "pattern.notstr";
64 private static final String PATTERN_NOTMATCH = "pattern.notmatch";
65 private static final String REQUIRED_NOTBOOL = "required.notbool";
66 private static final String REQUIRED1 = "/required";
67 private static final String PATTERN_SYNTAXERR = "pattern.syntaxerr";
68 private static final String PATTERN_SYNTAX_EXCEPTION = "PatternSyntaxException: {}";
69 private static final String SEQUENCE_NOTSEQ = "sequence.notseq";
70 private static final String SEQUENCE_NOELEM = "sequence.noelem";
71 private static final String SEQUENCE_TOOMANY = "sequence.toomany";
72 private static final String SEQUENCE3 = "/sequence/";
73 private static final String MAPPING_NOTMAP = "mapping.notmap";
74 private static final String MAPPING_NOELEM = "mapping.noelem";
75 private static final String IDENT2 = "/ident";
76 private static final String IDENT_NOTBOOL = "ident.notbool";
77 private static final String LENGTH_MAXEXLEMINEX = "length.maxexleminex";
78 private static final String LENGTH_MAXEXLEMIN = "length.maxexlemin";
79 private static final String TWO_SPACES = " ";
80 private static final String NAME1 = "name: ";
81 private static final String DESC1 = "desc: ";
82 private static final String TYPE2 = "type: ";
83 private static final String REQUIRED2 = "required: ";
84 private static final String PATTERN3 = "pattern: ";
85 private static final String REGEXP = "regexp: ";
86 private static final String ASSERT1 = "assert: ";
87 private static final String IDENT3 = "ident: ";
88 private static final String UNIQUE3 = "unique: ";
89 private static final String ENUM2 = "enum:\n";
90 private static final String RANGE3 = "range: { ";
91 private static final String NAME = "name";
92 private static final String DESC = "desc";
93 private static final String SHORT = "short";
94 private static final String REQUIRED = "required";
95 private static final String TYPE = "type";
96 private static final String PATTERN = "pattern";
97 private static final String SEQUENCE = "sequence";
98 private static final String MAPPING = "mapping";
99 private static final String ASSERT = "assert";
100 private static final String RANGE = "range";
101 private static final String LENGTH = "length";
102 private static final String IDENT = "ident";
103 private static final String UNIQUE = "unique";
104 private static final String ENUM = "enum:";
105 private static final String ENUM1 = "/enum";
106 public static final String MAX = "max";
107 public static final String MIN = "min";
109 private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance();
112 private String name = null;
113 private String desc = null;
114 private String _short = null; //added by jora: only used for map types
115 private boolean required = false;
116 private String _type = null;
117 private Class typeClass = null;
118 private String pattern = null;
119 private Pattern patternRegexp = null;
120 private List enumList = null;
121 private List sequence = null;
122 private DefaultableHashMap _mapping = null;
123 private String _assert = null;
124 private Map<String,Object> range = null;
125 private Map<String,Integer> length = null;
126 private boolean ident = false;
127 private boolean unique = false;
129 private static final int CODE_NAME = NAME.hashCode();
130 private static final int CODE_DESC = DESC.hashCode();
131 private static final int CODE_SHORT = SHORT.hashCode();
132 private static final int CODE_REQUIRED = REQUIRED.hashCode();
133 private static final int CODE_TYPE = TYPE.hashCode();
134 private static final int CODE_PATTERN = PATTERN.hashCode();
135 private static final int CODE_LENGTH = LENGTH.hashCode();
136 private static final int CODE_RANGE = RANGE.hashCode();
137 private static final int CODE_ASSERT = ASSERT.hashCode();
138 private static final int CODE_IDENT = IDENT.hashCode();
139 private static final int CODE_UNIQUE = UNIQUE.hashCode();
140 private static final int CODE_ENUM = ENUM.hashCode();
141 private static final int CODE_MAPPING = MAPPING.hashCode();
142 private static final int CODE_SEQUENCE = SEQUENCE.hashCode();
144 public Rule(Object schema, Rule parent) {
145 if (schema != null) {
146 if (! (schema instanceof Map)) {
147 throw schemaError(SCHEMA_NOTMAP, null, SLASH, null, null);
149 Map ruleTable = new IdentityHashMap();
150 init((Map)schema, EMPTY_STRING, ruleTable);
152 this.parent = parent;
155 public Rule(Object schema) {
159 public Rule(Map schema, Rule parent) {
160 if (schema != null) {
161 Map ruleTable = new IdentityHashMap();
162 init(schema, EMPTY_STRING, ruleTable);
164 this.parent = parent;
167 public Rule(Map schema) {
175 public String getName() { return name; }
176 public void setName(String name) { this.name = name; }
178 public String getShort() { return _short; }
179 public void setShort(String key) { _short = key; }
181 public boolean isRequired() { return required; }
182 public void setRequired(boolean required) { this.required = required; }
184 public String getType() { return _type; }
185 public void setType(String type) { this._type = type; }
187 public String getPattern() { return pattern; }
188 public void setPattern(String pattern) { this.pattern = pattern; }
190 public Pattern getPatternRegexp() { return patternRegexp; }
192 public List getEnum() { return enumList; }
193 public void setEnum(List enumList) { this.enumList = enumList; }
195 public List getSequence() { return sequence; }
196 public void setSequence(List sequence) { this.sequence = sequence; }
198 public DefaultableHashMap getMapping() { return _mapping; }
199 public void setMapping(DefaultableHashMap mapping) { _mapping = mapping; }
201 public String getAssert() { return _assert; }
202 public void setAssert(String assertString) { _assert = assertString; }
204 public Map getRange() { return range; }
205 public void setRange(Map range) { this.range = range; }
207 public Map getLength() { return length; }
208 public void setLength(Map length) { this.length = length; }
210 public boolean isIdent() { return ident; }
212 public boolean isUnique() { return unique; }
213 public void setUnique(boolean unique) { this.unique = unique; }
215 private static SchemaException schemaError(String errorSymbol, Rule rule, String path, Object value, Object[] args) {
216 String msg = Messages.buildMessage(errorSymbol, value, args);
217 return new SchemaException(msg, path, value, rule);
220 private void init(Object elem, String path, Map ruleTable) {
222 if (! (elem instanceof Map)) {
223 if (path == null || path.isEmpty()) {
226 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), SCHEMA_NOTMAP1, elem);
227 throw schemaError(SCHEMA_NOTMAP, null, path, null, null);
229 init((Map)elem, path, ruleTable);
232 private void init(Map hash, String path, Map ruleTable) {
234 ruleTable.put(hash, rule);
237 Object type = hash.get(TYPE);
238 initTypeValue(type, rule, path);
241 for (Iterator it = hash.keySet().iterator(); it.hasNext(); ) {
242 Object key = it.next();
243 Object value = hash.get(key);
244 int code = key.hashCode();
246 if (code == CODE_TYPE && key.equals(TYPE)) {
248 } else if (code == CODE_NAME && key.equals(NAME)) {
249 initNameValue(value);
250 } else if (code == CODE_DESC && key.equals(DESC)) {
251 initDescValue(value);
252 } else if (code == CODE_SHORT && key.equals(SHORT)) {
253 initShortValue(value, rule, path);
254 } else if (code == CODE_REQUIRED && key.equals(REQUIRED)) {
255 initRequiredValue(value, rule, path);
256 } else if (code == CODE_PATTERN && key.equals(PATTERN)) {
257 initPatternValue(value, rule, path);
258 } else if (code == CODE_ENUM && key.equals(ENUM)) {
259 initEnumValue(value, rule, path);
260 } else if (code == CODE_ASSERT && key.equals(ASSERT)) {
261 initAssertValue(value, rule, path);
262 } else if (code == CODE_RANGE && key.equals(RANGE)) {
263 initRangeValue(value, rule, path);
264 } else if (code == CODE_LENGTH && key.equals(LENGTH)) {
265 initLengthValue(value, rule, path);
266 } else if (code == CODE_IDENT && key.equals(IDENT)) {
267 initIdentValue(value, rule, path);
268 } else if (code == CODE_UNIQUE && key.equals(UNIQUE)) {
269 initUniqueValue(value, rule, path);
270 } else if (code == CODE_SEQUENCE && key.equals(SEQUENCE)) {
271 rule = initSequenceValue(value, rule, path, ruleTable);
272 } else if (code == CODE_MAPPING && key.equals(MAPPING)) {
273 rule = initMappingValue(value, rule, path, ruleTable);
277 checkConfliction(hash, rule, path);
280 private void initTypeValue(Object value, Rule rule, String path) {
282 value = Types.getDefaultType();
284 if (! (value instanceof String)) {
285 throw schemaError(TYPE_NOTSTR, rule, path + TYPE1, _type, null);
287 _type = (String)value;
288 typeClass = Types.typeClass(_type);
289 if (! Types.isBuiltinType(_type)) {
290 throw schemaError(TYPE_UNKNOWN, rule, path + TYPE1, _type, null);
295 private void initNameValue(Object value) {
296 name = value.toString();
300 private void initDescValue(Object value) {
301 desc = value.toString();
304 private void initShortValue(Object value, Rule rule, String path) {
306 //the short form specification is to be interpreted as key if the type is a map or as an
307 //index if the target is a sequence (as index 0 actually)
308 if (!Types.isCollectionType(_type)) {
309 throw schemaError("range.notcollection", rule, path + "/short", value, null);
311 //we should also verify that it points to a declared key of the mapping .. not really, as it would
312 //fail the overall grammar
313 _short = value.toString();
316 private void initRequiredValue(Object value, Rule rule, String path) {
317 if (! (value instanceof Boolean)) {
318 throw schemaError(REQUIRED_NOTBOOL, rule, path + REQUIRED1, value, null);
320 required = (Boolean) value;
324 private void initPatternValue(Object value, Rule rule, String path) {
325 if (! (value instanceof String)) {
326 throw schemaError(PATTERN_NOTSTR, rule, path + PATTERN2, value, null);
328 pattern = (String)value;
329 Matcher m = Util.matcher(pattern, "\\A/(.*)/([mi]?[mi]?)\\z");
331 throw schemaError(PATTERN_NOTMATCH, rule, path + PATTERN2, value, null);
333 String pat = m.group(1);
334 String opt = m.group(2);
336 if (opt.indexOf('i') >= 0) {
337 flag += Pattern.CASE_INSENSITIVE;
339 if (opt.indexOf('m') >= 0) {
340 flag += Pattern.DOTALL; // not MULTILINE
343 patternRegexp = Pattern.compile(pat, flag);
344 } catch (PatternSyntaxException ex) {
345 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), PATTERN_SYNTAX_EXCEPTION, ex);
346 throw schemaError(PATTERN_SYNTAXERR, rule, path + PATTERN2, value, null);
351 private void initEnumValue(Object value, Rule rule, String path) {
352 if (! (value instanceof List)) {
353 throw schemaError("enum.notseq", rule, path + ENUM1, value, null);
355 enumList = (List)value;
356 if (Types.isCollectionType(_type)) {
357 throw schemaError("enum.notscalar", rule, path, ENUM, null);
359 Map elemTable = new HashMap();
360 for (Iterator it = enumList.iterator(); it.hasNext(); ) {
361 Object elem = it.next();
362 if (! Util.isInstanceOf(elem, typeClass)) {
363 throw schemaError("enum.type.unmatch", rule, path + ENUM1, elem, new Object[] { Types.typeName(_type) });
365 if (elemTable.containsKey(elem)) {
366 throw schemaError("enum.duplicate", rule, path + ENUM1, elem, null);
368 elemTable.put(elem, Boolean.TRUE);
373 private void initAssertValue(Object value, Rule rule, String path) {
374 if (! (value instanceof String)) {
375 throw schemaError("assert.notstr", rule, path + "/assert", value, null);
377 _assert = (String)value;
378 if (! Util.matches(_assert, "\\bval\\b")) {
379 throw schemaError("assert.noval", rule, path + "/assert", value, null);
384 private void initRangeValue(Object value, Rule rule, String path) {
385 if (! (value instanceof Map)) {
386 throw schemaError("range.notmap", rule, path + RANGE1, value, null);
388 if (Types.isCollectionType(_type) || "bool".equals(_type)) {
389 throw schemaError("range.notscalar", rule, path, RANGE2, null);
392 for (Iterator it = range.keySet().iterator(); it.hasNext(); ) {
393 Object rkey = it.next();
394 Object rval = range.get(rkey);
395 if (MAX.equals(rkey) || MIN.equals(rkey) || rkey.equals(MAX_EX) || rkey.equals(MIN_EX)) {
396 if (! Util.isInstanceOf(rval, typeClass)) {
397 String typename = Types.typeName(_type);
398 throw schemaError("range.type.unmatch", rule, path + "/range/" + rkey, rval, new Object[] { typename });
401 throw schemaError("range.undefined", rule, path + "/range/" + rkey, rkey.toString() + ":", null);
404 if (range.containsKey(MAX) && range.containsKey(MAX_EX)) {
405 throw schemaError("range.twomax", rule, path + RANGE1, null, null);
407 if (range.containsKey(MIN) && range.containsKey(MIN_EX)) {
408 throw schemaError("range.twomin", rule, path + RANGE1, null, null);
411 Object max = range.get(MAX);
412 Object min = range.get(MIN);
413 Object maxEx = range.get(MAX_EX);
414 Object minEx = range.get(MIN_EX);
418 if (min != null && Util.compareValues(max, min) < 0) {
419 args = new Object[] { max, min };
420 throw schemaError("range.maxltmin", rule, path + RANGE1, null, args);
421 } else if (minEx != null && Util.compareValues(max, minEx) <= 0) {
422 args = new Object[] { max, minEx };
423 throw schemaError("range.maxleminex", rule, path + RANGE1, null, args);
425 } else if (maxEx != null) {
426 if (min != null && Util.compareValues(maxEx, min) <= 0) {
427 args = new Object[] { maxEx, min };
428 throw schemaError("range.maxexlemin", rule, path + RANGE1, null, args);
429 } else if (minEx != null && Util.compareValues(maxEx, minEx) <= 0) {
430 args = new Object[] { maxEx, minEx };
431 throw schemaError("range.maxexleminex", rule, path + RANGE1, null, args);
437 private void initLengthValue(Object value, Rule rule, String path) {
438 if (! (value instanceof Map)) {
439 throw schemaError("length.notmap", rule, path + LENGTH1, value, null);
442 if (! ("str".equals(_type) || "text".equals(_type))) {
443 throw schemaError("length.nottext", rule, path, LENGTH2, null);
445 for (String k : length.keySet()) {
446 Integer v = length.get(k);
447 if (MAX.equals(k) || MIN.equals(k) || k.equals(MAX_EX) || k.equals(MIN_EX)) {
449 throw schemaError("length.notint", rule, path + LENGTH3 + k, v, null);
452 throw schemaError("length.undefined", rule, path + LENGTH3 + k, k + ":", null);
455 if (length.containsKey(MAX) && length.containsKey(MAX_EX)) {
456 throw schemaError("length.twomax", rule, path + LENGTH1, null, null);
458 if (length.containsKey(MIN) && length.containsKey(MIN_EX)) {
459 throw schemaError("length.twomin", rule, path + LENGTH1, null, null);
462 Integer max = length.get(MAX);
463 Integer min = length.get(MIN);
464 Integer maxEx = length.get(MAX_EX);
465 Integer minEx = length.get(MIN_EX);
469 if (min != null && max.compareTo(min) < 0) {
470 args = new Object[] { max, min };
471 throw schemaError("length.maxltmin", rule, path + LENGTH1, null, args);
472 } else if (minEx != null && max.compareTo(minEx) <= 0) {
473 args = new Object[] { max, minEx };
474 throw schemaError("length.maxleminex", rule, path + LENGTH1, null, args);
476 } else if (maxEx != null) {
477 if (min != null && maxEx.compareTo(min) <= 0) {
478 args = new Object[] { maxEx, min };
479 throw schemaError(LENGTH_MAXEXLEMIN, rule, path + LENGTH1, null, args);
480 } else if (minEx != null && maxEx.compareTo(minEx) <= 0) {
481 args = new Object[] { maxEx, minEx };
482 throw schemaError(LENGTH_MAXEXLEMINEX, rule, path + LENGTH1, null, args);
487 private void initIdentValue(Object value, Rule rule, String path) {
488 if (value == null || ! (value instanceof Boolean)) {
489 throw schemaError(IDENT_NOTBOOL, rule, path + IDENT2, value, null);
491 ident = (Boolean) value;
493 if (Types.isCollectionType(_type)) {
494 throw schemaError(IDENT_NOTSCALAR, rule, path, IDENT1, null);
496 if (EMPTY_STRING.equals(path)) {
497 throw schemaError(IDENT_ONROOT, rule, SLASH, IDENT1, null);
499 if (parent == null || ! MAP.equals(parent.getType())) {
500 throw schemaError(IDENT_NOTMAP, rule, path, IDENT1, null);
505 private void initUniqueValue(Object value, Rule rule, String path) {
506 if (! (value instanceof Boolean)) {
507 throw schemaError(UNIQUE_NOTBOOL, rule, path + UNIQUE2, value, null);
509 unique = (Boolean) value;
510 if (Types.isCollectionType(_type)) {
511 throw schemaError(UNIQUE_NOTSCALAR, rule, path, UNIQUE1, null);
513 if (path.equals(EMPTY_STRING)) {
514 throw schemaError(UNIQUE_ONROOT, rule, SLASH, UNIQUE1, null);
519 private Rule initSequenceValue(Object value, Rule rule, String path, Map ruleTable) {
520 if (value != null && ! (value instanceof List)) {
521 throw schemaError(SEQUENCE_NOTSEQ, rule, path + SEQUENCE1, value.toString(), null);
523 sequence = (List)value;
524 if (sequence == null || sequence.isEmpty()) {
525 throw schemaError(SEQUENCE_NOELEM, rule, path + SEQUENCE1, value, null);
527 if (sequence.size() > 1) {
528 throw schemaError(SEQUENCE_TOOMANY, rule, path + SEQUENCE1, value, null);
530 Object elem = sequence.get(0);
532 elem = new HashMap();
535 rule = (Rule)ruleTable.get(elem);
537 rule = new Rule(null, this);
538 rule.init(elem, path + SEQUENCE3 + i, ruleTable);
540 sequence = new ArrayList();
546 private Rule initMappingValue(Object value, Rule rule, String path, Map ruleTable) {
548 if (value != null && !(value instanceof Map)) {
549 throw schemaError(MAPPING_NOTMAP, rule, path + MAPPING2, value.toString(), null);
551 Object defaultValue = null;
552 if (value instanceof Defaultable) {
553 defaultValue = ((Defaultable)value).getDefault();
555 if (value == null || ((Map)value).size() == 0 && defaultValue == null) {
556 throw schemaError(MAPPING_NOELEM, rule, path + MAPPING2, value, null);
558 // create hash of rule
559 _mapping = new DefaultableHashMap();
560 if (defaultValue != null) {
561 rule = (Rule)ruleTable.get(defaultValue);
563 rule = new Rule(null, this);
564 rule.init(defaultValue, path + MAPPING3, ruleTable);
566 _mapping.setDefault(rule);
568 // put rules into _mapping
569 Map map = (Map)value;
570 for (Iterator it = map.keySet().iterator(); it.hasNext(); ) {
571 Object k = it.next();
572 Object v = map.get(k); // DefaultableHashMap
574 v = new DefaultableHashMap();
576 rule = (Rule)ruleTable.get(v);
578 rule = new Rule(null, this);
579 rule.init(v, path + MAPPING4 + k, ruleTable);
582 _mapping.setDefault(rule);
584 _mapping.put(k, rule);
591 private void checkConfliction(Map hash, Rule rule, String path) {
592 if ("seq".equals(_type)) {
593 if (! hash.containsKey(SEQUENCE)) {
594 throw schemaError("seq.nosequence", rule, path, null, null);
596 if (enumList != null) {
597 throw schemaError(SEQ_CONFLICT, rule, path, ENUM, null);
599 if (pattern != null) {
600 throw schemaError(SEQ_CONFLICT, rule, path, PATTERN1, null);
602 if (_mapping != null) {
603 throw schemaError(SEQ_CONFLICT, rule, path, MAPPING1, null);
606 throw schemaError(SEQ_CONFLICT, rule, path, RANGE2, null);
608 if (length != null) {
609 throw schemaError(SEQ_CONFLICT, rule, path, LENGTH2, null);
611 } else if (_type.equals(MAP)) {
612 if (! hash.containsKey(MAPPING)) {
613 throw schemaError("map.nomapping", rule, path, null, null);
615 if (enumList != null) {
616 throw schemaError(MAP_CONFLICT, rule, path, ENUM, null);
618 if (pattern != null) {
619 throw schemaError(MAP_CONFLICT, rule, path, PATTERN1, null);
621 if (sequence != null) {
622 throw schemaError(MAP_CONFLICT, rule, path, SEQUENCE2, null);
625 throw schemaError(MAP_CONFLICT, rule, path, RANGE2, null);
627 if (length != null) {
628 throw schemaError(MAP_CONFLICT, rule, path, LENGTH2, null);
631 if (sequence != null) {
632 throw schemaError(SCALAR_CONFLICT, rule, path, SEQUENCE2, null);
634 if (_mapping != null) {
635 throw schemaError(SCALAR_CONFLICT, rule, path, MAPPING1, null);
637 if (enumList != null) {
639 throw schemaError(ENUM_CONFLICT, rule, path, RANGE2, null);
641 if (length != null) {
642 throw schemaError(ENUM_CONFLICT, rule, path, LENGTH2, null);
644 if (pattern != null) {
645 throw schemaError(ENUM_CONFLICT, rule, path, PATTERN1, null);
651 public String inspect() {
652 StringBuilder sb = new StringBuilder();
654 Map done = new IdentityHashMap();
655 inspect(sb, level, done);
656 return sb.toString();
659 private void inspect(StringBuilder sb, int level, Map done) {
660 done.put(this, Boolean.TRUE);
661 String indent = Util.repeatString(TWO_SPACES, level);
663 sb.append(indent).append(NAME1).append(name).append("\n");
666 sb.append(indent).append(DESC1).append(desc).append("\n");
669 sb.append(indent).append(TYPE2).append(_type).append("\n");
672 sb.append(indent).append(REQUIRED2).append(required).append("\n");
674 if (pattern != null) {
675 sb.append(indent).append(PATTERN3).append(pattern).append("\n");
677 if (patternRegexp != null) {
678 sb.append(indent).append(REGEXP).append(patternRegexp).append("\n");
680 if (_assert != null) {
681 sb.append(indent).append(ASSERT1).append(_assert).append("\n");
684 sb.append(indent).append(IDENT3).append(ident).append("\n");
687 sb.append(indent).append(UNIQUE3).append(unique).append("\n");
689 if (enumList != null) {
690 appendEnums(sb, indent);
693 appendRange(sb, indent);
695 if (sequence != null) {
696 appendSequence(sb, level, done, indent);
698 if (_mapping != null) {
699 appendMapping(sb, level, done, indent);
703 private void appendEnums(StringBuilder sb, String indent) {
704 sb.append(indent).append(ENUM2);
705 for (Object anEnumList : enumList) {
706 sb.append(indent).append(" - ").append(anEnumList.toString()).append("\n");
710 private void appendMapping(StringBuilder sb, int level, Map done, String indent) {
711 for (Object o : _mapping.entrySet()) {
712 Map.Entry entry = (Map.Entry) o;
713 Object key = entry.getKey();
714 Rule rule = (Rule) entry.getValue();
715 sb.append(indent).append(" ").append(Util.inspect(key));
716 if (done.containsKey(rule)) {
717 sb.append(": ...\n");
720 rule.inspect(sb, level + 2, done);
725 private void appendSequence(StringBuilder sb, int level, Map done, String indent) {
726 for (Object aSequence : sequence) {
727 Rule rule = (Rule) aSequence;
728 if (done.containsKey(rule)) {
729 sb.append(indent).append(" ").append("- ...\n");
731 sb.append(indent).append(" ").append("- \n");
732 rule.inspect(sb, level + 2, done);
737 private void appendRange(StringBuilder sb, String indent) {
738 sb.append(indent).append(RANGE3);
739 String[] keys = new String[] {MAX, MAX_EX, MIN, MIN_EX, };
740 String colon = EMPTY_STRING;
741 for (String key : keys) {
742 Object val = range.get(key);
744 sb.append(colon).append(key).append(": ").append(val);