DCAE-D be initial commit
[sdc/dcae-d/dt-be-main.git] / dcaedt_validator / kwalify / src / main / java / kwalify / MetaValidator.java
1 /*
2  * @(#)MetaValidator.java       $Rev: 4 $ $Release: 0.5.1 $
3  *
4  * copyright(c) 2005 kuwata-lab all rights reserved.
5  */
6
7 package kwalify;
8
9 import org.onap.sdc.common.onaplog.OnapLoggerDebug;
10 import org.onap.sdc.common.onaplog.OnapLoggerError;
11 import org.onap.sdc.common.onaplog.Enums.LogLevel;
12
13 import java.util.Map;
14 import java.util.List;
15 import java.util.Iterator;
16 import java.util.regex.Pattern;
17 import java.util.regex.Matcher;
18 import java.util.regex.PatternSyntaxException;
19
20 /**
21  *  meta validator to validate schema definition
22  *
23  *  @revision    $Rev: 4 $
24  *  @release     $Release: 0.5.1 $
25  */
26 public class MetaValidator extends Validator {
27
28     private static OnapLoggerError errLogger = OnapLoggerError.getInstance();
29     private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance();
30
31     public static final String META_SCHEMA = ""
32         + "name:      MAIN\n"
33         + "type:      map\n"
34         + "required:  yes\n"
35         + "mapping:   &main-rule\n"
36         + " \"name\":\n"
37         + "    type:      str\n"
38         + " \"desc\":\n"
39         + "    type:      str\n"
40         + " \"type\":\n"
41         + "    type:      str\n"
42         + "    #required:  yes\n"
43         + "    enum:\n"
44         + "      - seq\n"
45         + "      #- sequence\n"
46         + "      #- list\n"
47         + "      - map\n"
48         + "      #- mapping\n"
49         + "      #- hash\n"
50         + "      - str\n"
51         + "      #- string\n"
52         + "      - int\n"
53         + "      #- integer\n"
54         + "      - float\n"
55         + "      - number\n"
56         + "      #- numeric\n"
57         + "      - bool\n"
58         + "      #- boolean\n"
59         + "      - text\n"
60         + "      - date\n"
61         + "      - time\n"
62         + "      - timestamp\n"
63         + "      #- object\n"
64         + "      - any\n"
65         + "      - scalar\n"
66         + "      #- collection\n"
67         + " \"required\":\n"
68         + "    type:      bool\n"
69         + " \"enum\":\n"
70         + "    type:      seq\n"
71         + "    sequence:\n"
72         + "      - type:     scalar\n"
73         + "        unique:   yes\n"
74         + " \"pattern\":\n"
75         + "    type:      str\n"
76         + " \"assert\":\n"
77         + "    type:      str\n"
78         + "    pattern:   /\\bval\\b/\n"
79         + " \"range\":\n"
80         + "    type:      map\n"
81         + "    mapping:\n"
82         + "     \"max\":\n"
83         + "        type:     scalar\n"
84         + "     \"min\":\n"
85         + "        type:     scalar\n"
86         + "     \"max-ex\":\n"
87         + "        type:     scalar\n"
88         + "     \"min-ex\":\n"
89         + "        type:     scalar\n"
90         + " \"length\":\n"
91         + "    type:      map\n"
92         + "    mapping:\n"
93         + "     \"max\":\n"
94         + "        type:     int\n"
95         + "     \"min\":\n"
96         + "        type:     int\n"
97         + "     \"max-ex\":\n"
98         + "        type:     int\n"
99         + "     \"min-ex\":\n"
100         + "        type:     int\n"
101         + " \"ident\":\n"
102         + "    type:      bool\n"
103         + " \"unique\":\n"
104         + "    type:      bool\n"
105         + " \"sequence\":\n"
106         + "    name:      SEQUENCE\n"
107         + "    type:      seq\n"
108         + "    sequence:\n"
109         + "      - type:      map\n"
110         + "        mapping:   *main-rule\n"
111         + "        name:      MAIN\n"
112         + "        #required:  yes\n"
113         + " \"mapping\":\n"
114         + "    name:      MAPPING\n"
115         + "    type:      map\n"
116         + "    mapping:\n"
117         + "      =:\n"
118         + "        type:      map\n"
119         + "        mapping:   *main-rule\n"
120         + "        name:      MAIN\n"
121         + "        #required:  yes\n"
122         ;
123
124
125     /**
126      *
127      * ex.
128      * <pre>
129      *  MetaValidator meta_validator = MetaValidator();
130      *  Map schema = YamlUtil.loadFile("schema.yaml");
131      *  List errors = meta_validator.validate(schema);
132      *  if (errors != null && errors.size() > 0) {
133      *    for (Iterator it = errors.iterator(); it.hasNext(); ) {
134      *      ValidationException error = (ValidationException)it.next();
135      *      System.err.println(" - [" + error.getPath() + "] " + error.getMessage());
136      *    }
137      *  }
138      * </pre>
139      */
140
141     private static Validator __instance;
142
143     public static Validator instance() {
144         synchronized (MetaValidator.class) {
145             if (__instance == null) {
146                 try {
147                     Map schema = (Map) YamlUtil.load(META_SCHEMA);
148                     __instance = new MetaValidator(schema);
149                 } catch (SyntaxException ex) {
150                     assert false;
151                 }
152             }
153         }
154
155         return __instance;
156     }
157
158     private MetaValidator(Map schema) {
159         super(schema);
160     }
161
162     public void postValidationHook(Object value, Rule rule, ValidationContext theContext) {
163         if (value == null) {
164             return;   // realy?
165         }
166         if (! "MAIN".equals(rule.getName())) {
167             return;
168         }
169         //
170         assert value instanceof Map;
171         Map map = (Map)value;
172         String type = (String)map.get("type");
173         if (type == null) {
174             type = Types.getDefaultType();
175         }
176         //Class type_class = Types.typeClass(type);
177         //if (type_class == null) {
178         //    theContext.addError(validationError("type.unknown", rule, path + "/type", type, null));
179         //}
180         //
181         //String pattern;
182         //if ((pattern = (String)map.get("pattern")) != null) {
183         if (map.containsKey("pattern")) {
184             String pattern = (String)map.get("pattern");
185             Matcher m = Util.matcher(pattern, "\\A\\/(.*)\\/([mi]?[mi]?)\\z");
186             String pat = m.find() ? m.group(1) : pattern;
187             try {
188                 Pattern.compile(pat);
189             } catch (PatternSyntaxException ex) {
190                 theContext.addError("pattern.syntaxerr", rule, "pattern", pattern, null);
191             }
192         }
193         //
194         //List enum_list;
195         //if ((enum_list = (List)map.get("enum")) != null) {
196         if (map.containsKey("enum")) {
197             List enum_list = (List)map.get("enum");
198             if (Types.isCollectionType(type)) {
199                 theContext.addError("enum.notscalar", rule, "enum:", (Object[])null);
200             } else {
201                 for (Iterator it = enum_list.iterator(); it.hasNext(); ) {
202                     Object elem = it.next();
203                     if (! Types.isCorrectType(elem, type)) {
204                         theContext.addError("enum.type.unmatch", rule,  "enum", elem, new Object[] { Types.typeName(type) });
205                     }
206                 }
207             }
208         }
209         //
210         //String assert_str;
211         //if ((assert_str = (String)map.get("assert")) != null) {
212         if (map.containsKey("assert")) {
213             errLogger.log(LogLevel.ERROR, this.getClass().getName(), "*** warning: sorry, 'assert:' is not supported in current version of Kwalify-java.");
214             //String assert_str = (String)map.get("assert");
215             //if (! Util.matches(assert_str, "\\bval\\b")) {
216             //    theContext.addError(validationError("assert.noval", rule, path + "/assert", assert_str, null);
217             //}
218             //try {
219             //    Expression.parse(assert_str);
220             //} catch (InvalidExpressionException ex) {
221             //    theContext.addError(validationError("assert.syntaxerr", rule, path + "/assert", assert_str, null));
222             //}
223         }
224         //
225         //Map range;
226         //if ((range = (Map)map.get("range")) != null) {
227         if (map.containsKey("range")) {
228             Map range = (Map)map.get("range");
229             //if (! (range instanceof Map)) {
230             //    theContext.addError(validtionError("range.notmap", rule, path + "/range", range, null));
231             //} else
232             if (Types.isCollectionType(type) || type.equals("bool") || type.equals("any")) {
233                 theContext.addError("range.notscalar", rule, "range:", null, null);
234             } else {
235                 for (Iterator it = range.keySet().iterator(); it.hasNext(); ) {
236                     String k = (String)it.next();
237                     Object v = range.get(k);
238                     if (! Types.isCorrectType(v, type)) {
239                         theContext.addError("range.type.unmatch", rule, "range/" + k, v, new Object[] { Types.typeName(type) });
240                     }
241                 }
242             }
243             if (range.containsKey("max") && range.containsKey("max-ex")) {
244                 theContext.addError("range.twomax", rule, "range", null, null);
245             }
246             if (range.containsKey("min") && range.containsKey("min-ex")) {
247                 theContext.addError("range.twomin", rule, "range", null, null);
248             }
249             Object max    = range.get("max");
250             Object min    = range.get("min");
251             Object max_ex = range.get("max-ex");
252             Object min_ex = range.get("min-ex");
253             Object[] args = null;
254             //String error_symbol = null;
255             if (max != null) {
256                 if (min != null && Util.compareValues(max, min) < 0) {
257                     args = new Object[] { max, min };
258                     theContext.addError("range.maxltmin", rule, "range", null, args);
259                 } else if (min_ex != null && Util.compareValues(max, min_ex) <= 0) {
260                     args = new Object[] { max, min_ex };
261                     theContext.addError("range.maxleminex", rule, "range", null, args);
262                 }
263             } else if (max_ex != null) {
264                 if (min != null && Util.compareValues(max_ex, min) <= 0) {
265                     args = new Object[] { max_ex, min };
266                     theContext.addError("range.maxexlemin", rule, "range", null, args);
267                 } else if (min_ex != null && Util.compareValues(max_ex, min_ex) <= 0) {
268                     args = new Object[] { max_ex, min_ex };
269                     theContext.addError("range.maxexleminex", rule, "range", null, args);
270                 }
271             }
272         }
273         //
274         //Map length;
275         //if ((length = (Map)map.get("length")) != null) {
276         if (map.containsKey("length")) {
277             Map length = (Map)map.get("length");
278             //if (! (length instanceof Map)) {
279             //    theContext.addError(validtionError("length.notmap", rule, path + "/length", length, null));
280             //} else
281             if (! (type.equals("str") || type.equals("text"))) {
282                 theContext.addError("length.nottext", rule, "length:", (Object[])null);
283             }
284             //for (Iterator it = length.keySet().iterator(); it.hasNext(); ) {
285             //    String k = (String)it.next();
286             //    Object v = length.get(k);
287             //    if (k == null || ! (k.equals("max") || k.equals("min") || k.equals("max-ex") || k.equals("min-ex"))) {
288             //        theContext.addError(validationError("length.undefined", rule, path + "/length/" + k, "" + k + ":", null));
289             //    } else if (! (v instanceof Integer)) {
290             //        theContext.addError(validationError("length.notint", rule, path + "/length/" + k, v, null));
291             //    }
292             //}
293             if (length.containsKey("max") && length.containsKey("max-ex")) {
294                 theContext.addError("length.twomax", rule, "length", (Object[])null);
295             }
296             if (length.containsKey("min") && length.containsKey("min-ex")) {
297                 theContext.addError("length.twomin", rule, "length", (Object[])null);
298             }
299             Integer max    = (Integer)length.get("max");
300             Integer min    = (Integer)length.get("min");
301             Integer max_ex = (Integer)length.get("max-ex");
302             Integer min_ex = (Integer)length.get("min-ex");
303             Object[] args = null;
304             //String error_symbol = null;
305             if (max != null) {
306                 if (min != null && max.compareTo(min) < 0) {
307                     args = new Object[] { max, min };
308                     theContext.addError("length.maxltmin", rule, "length", null, args);
309                 } else if (min_ex != null && max.compareTo(min_ex) <= 0) {
310                     args = new Object[] { max, min_ex };
311                     theContext.addError("length.maxleminex", rule, "length", null, args);
312                 }
313             } else if (max_ex != null) {
314                 if (min != null && max_ex.compareTo(min) <= 0) {
315                     args = new Object[] { max_ex, min };
316                     theContext.addError("length.maxexlemin", rule, "length", null, args);
317                 } else if (min_ex != null && max_ex.compareTo(min_ex) <= 0) {
318                     args = new Object[] { max_ex, min_ex };
319                     theContext.addError("length.maxexleminex", rule, "length", null, args);
320                 }
321             }
322         }
323         //
324         //Boolean unique;
325         //if ((unique = (Boolean)map.get("unique")) != null) {
326         if (map.containsKey("unique")) {
327             Boolean unique = (Boolean)map.get("unique");
328             if (unique.booleanValue() == true && Types.isCollectionType(type)) {
329                 theContext.addError("unique.notscalar", rule, "unique:", (Object[])null);
330             }
331             if (theContext.getPath().length() == 0) {
332                 theContext.addError("unique.onroot", rule, "", "unique:", null);
333             }
334         }
335         //
336         //Boolean ident;
337         //if ((ident = (Boolean)map.get("ident")) != null) {
338         if (map.containsKey("ident")) {
339             Boolean ident = (Boolean)map.get("ident");
340             if (ident.booleanValue() == true && Types.isCollectionType(type)) {
341                 theContext.addError("ident.notscalar", rule, "ident:", (Object[])null);
342             }
343             if (theContext.getPath().length() == 0) {
344                 theContext.addError("ident.onroot", rule, "/", "ident:", (Object[])null);
345             }
346         }
347         //
348         //List seq;
349         //if ((seq = (List)map.get("sequence")) != null) {
350         if (map.containsKey("sequence")) {
351             List seq = (List)map.get("sequence");
352             //if (! (seq instanceof List)) {
353             //    theContext.addError(validationError("sequence.notseq", rule, path + "/sequence", seq, null));
354             //} else
355             if (seq == null || seq.size() == 0) {
356                 theContext.addError("sequence.noelem", rule, "sequence", seq, null);
357             } else if (seq.size() > 1) {
358                 theContext.addError("sequence.toomany", rule, "sequence", seq, null);
359             } else {
360                 Object item = seq.get(0);
361                 assert item instanceof Map;
362                 Map m = (Map)item;
363                 Boolean ident2 = (Boolean)m.get("ident");
364                 if (ident2 != null && ident2.booleanValue() == true && ! "map".equals(m.get("type"))) {
365                     theContext.addError("ident.notmap", null, "sequence/0", "ident:", null);
366                 }
367             }
368         }
369         //
370         //Map mapping;
371         //if ((mapping = (Map)map.get("mapping")) != null) {
372         if (map.containsKey("mapping")) {
373             Map mapping = (Map)map.get("mapping");
374             //if (mapping != null && ! (mapping instanceof Map)) {
375             //    theContext.addError(validationError("mapping.notmap", rule, path + "/mapping", mapping, null));
376             //} else
377             Object default_value = null;
378             if (mapping != null && mapping instanceof Defaultable) {
379                 default_value = ((Defaultable)mapping).getDefault();
380             }
381             if (mapping == null || (mapping.size() == 0 && default_value == null)) {
382                 theContext.addError("mapping.noelem", rule, "mapping", mapping, null);
383             }
384         }
385         //
386         if (type.equals("seq")) {
387             if (! map.containsKey("sequence")) {
388                 theContext.addError("seq.nosequence", rule, null, (Object[])null);
389             }
390             //if (map.containsKey("enum")) {
391             //    theContext.addError(validationError("seq.conflict", rule, path, "enum:", null));
392             //}
393             if (map.containsKey("pattern")) {
394                 theContext.addError("seq.conflict", rule, "pattern:", (Object[])null);
395             }
396             if (map.containsKey("mapping")) {
397                 theContext.addError("seq.conflict", rule, "mapping:", (Object[])null);
398             }
399             //if (map.containsKey("range")) {
400             //    theContext.addError(validationError("seq.conflict", rule, path, "range:", null));
401             //}
402             //if (map.containsKey("length")) {
403             //    theContext.addError(validationError("seq.conflict", rule, path, "length:", null));
404             //}
405         } else if (type.equals("map")) {
406             if (! map.containsKey("mapping")) {
407                 theContext.addError("map.nomapping", rule, null, (Object[])null);
408             }
409             //if (map.containsKey("enum")) {
410             //    theContext.addError(validationError("map.conflict", rule, path, "enum:", null));
411             //}
412             if (map.containsKey("pattern")) {
413                 theContext.addError("map.conflict", rule, "pattern:", (Object[])null);
414             }
415             if (map.containsKey("sequence")) {
416                 theContext.addError("map.conflict", rule, "sequence:", (Object[])null);
417             }
418             //if (map.containsKey("range")) {
419             //    theContext.addError(validationError("map.conflict", rule, path, "range:", null));
420             //}
421             //if (map.containsKey("length")) {
422             //    theContext.addError(validationError("map.conflict", rule, path, "length:", null));
423             //}
424         } else {
425             if (map.containsKey("sequence")) {
426                 theContext.addError("scalar.conflict", rule, "sequence:", (Object[])null);
427             }
428             if (map.containsKey("mapping")) {
429                 theContext.addError("scalar.conflict", rule, "mapping:", (Object[])null);
430             }
431             if (map.containsKey("enum")) {
432                 if (map.containsKey("range")) {
433                     theContext.addError("enum.conflict", rule, "range:", (Object[])null);
434                 }
435                 if (map.containsKey("length")) {
436                     theContext.addError("enum.conflict", rule, "length:", (Object[])null);
437                 }
438                 if (map.containsKey("pattern")) {
439                     theContext.addError("enum.conflict", rule, "pattern:", (Object[])null);
440                 }
441             }
442         }
443     }
444
445 }