Bug 1131 - yang-parser-impl cleanup
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / YangModelBasicValidationListener.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.parser.impl;
9
10 import com.google.common.collect.Sets;
11 import java.net.URI;
12 import java.net.URISyntaxException;
13 import java.util.HashSet;
14 import java.util.Set;
15 import org.antlr.v4.runtime.tree.ParseTree;
16 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
17 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Anyxml_stmtContext;
18 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext;
19 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Augment_stmtContext;
20 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext;
21 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
22 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Case_stmtContext;
23 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Choice_stmtContext;
24 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Config_argContext;
25 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Container_stmtContext;
26 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Default_stmtContext;
27 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
28 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviation_stmtContext;
29 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Extension_stmtContext;
30 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Feature_stmtContext;
31 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Grouping_stmtContext;
32 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Identity_stmtContext;
33 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.If_feature_stmtContext;
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Import_stmtContext;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Include_stmtContext;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Key_stmtContext;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leaf_list_stmtContext;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leaf_stmtContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.List_stmtContext;
40 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_argContext;
41 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
42 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
43 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
44 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
45 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Notification_stmtContext;
46 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_argContext;
47 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Prefix_stmtContext;
48 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_stmtContext;
49 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
50 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtContext;
51 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Rpc_stmtContext;
52 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_argContext;
53 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
54 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_stmtContext;
55 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Type_stmtContext;
56 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Typedef_stmtContext;
57 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Unique_stmtContext;
58 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Uses_stmtContext;
59 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yin_element_argContext;
60 import org.opendaylight.yangtools.antlrv4.code.gen.YangParserBaseListener;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 /**
65  * Validation listener that validates yang statements according to RFC-6020.
66  * This validator expects only one module or submodule per file and performs
67  * only basic validation where context from all yang models is not present.
68  */
69 final class YangModelBasicValidationListener extends YangParserBaseListener {
70     private static final Logger LOGGER = LoggerFactory.getLogger(YangModelBasicValidationListener.class);
71     private final Set<String> uniquePrefixes = new HashSet<>();
72     private final Set<String> uniqueImports = new HashSet<>();
73     private final Set<String> uniqueIncludes = new HashSet<>();
74
75     private String globalModuleId;
76
77     /**
78      * Constraints:
79      * <ol>
80      * <li>Identifier is in required format</li>
81      * <li>Header statements present(mandatory prefix and namespace statements
82      * are in header)</li>
83      * <li>Only one module or submodule per file</li>
84      * </ol>
85      */
86     @Override
87     public void enterModule_stmt(final Module_stmtContext ctx) {
88
89         BasicValidations.checkIdentifier(ctx);
90
91         BasicValidations.checkPresentChildOfType(ctx, Module_header_stmtsContext.class, true);
92
93         String moduleName = ValidationUtil.getName(ctx);
94         BasicValidations.checkIsModuleIdNull(globalModuleId);
95         globalModuleId = moduleName;
96     }
97
98     /**
99      * Constraints:
100      * <ol>
101      * <li>Identifier is in required format</li>
102      * <li>Header statements present(mandatory belongs-to statement is in
103      * header)</li>
104      * <li>Only one module or submodule per file</li>
105      * </ol>
106      */
107     @Override
108     public void enterSubmodule_stmt(final Submodule_stmtContext ctx) {
109
110         BasicValidations.checkIdentifier(ctx);
111
112         BasicValidations.checkPresentChildOfType(ctx, Submodule_header_stmtsContext.class, true);
113
114         String submoduleName = ValidationUtil.getName(ctx);
115         BasicValidations.checkIsModuleIdNull(globalModuleId);
116         globalModuleId = submoduleName;
117
118     }
119
120     /**
121      * Constraints:
122      * <ol>
123      * <li>One Belongs-to statement present</li>
124      * </ol>
125      */
126     @Override
127     public void enterSubmodule_header_stmts(final Submodule_header_stmtsContext ctx) {
128         BasicValidations.checkPresentChildOfType(ctx, Belongs_to_stmtContext.class, true);
129
130         // check Yang version present, if not log
131         try {
132             BasicValidations.checkPresentYangVersion(ctx, ValidationUtil.getRootParentName(ctx));
133         } catch (Exception e) {
134             LOGGER.debug(e.getMessage());
135         }
136     }
137
138     /**
139      * Constraints:
140      * <ol>
141      * <li>One Namespace statement present</li>
142      * <li>One Prefix statement present</li>
143      * </ol>
144      */
145     @Override
146     public void enterModule_header_stmts(final Module_header_stmtsContext ctx) {
147         String moduleName = ValidationUtil.getRootParentName(ctx);
148
149         BasicValidations.checkPresentChildOfType(ctx, Namespace_stmtContext.class, true);
150         BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, true);
151
152         // check Yang version present, if not log
153         try {
154             BasicValidations.checkPresentYangVersion(ctx, moduleName);
155         } catch (Exception e) {
156             LOGGER.debug(e.getMessage());
157         }
158     }
159
160     /**
161      * Constraints:
162      * <ol>
163      * <li>Date is in valid format</li>
164      * </ol>
165      */
166     @Override
167     public void enterRevision_stmt(final Revision_stmtContext ctx) {
168         BasicValidations.checkDateFormat(ctx);
169
170     }
171
172     /**
173      * Constraints:
174      * <ol>
175      * <li>Identifier is in required format</li>
176      * <li>One Prefix statement child</li>
177      * </ol>
178      */
179     @Override
180     public void enterBelongs_to_stmt(final Belongs_to_stmtContext ctx) {
181         BasicValidations.checkIdentifier(ctx);
182
183         BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, true);
184     }
185
186     /**
187      * Constraints:
188      * <ol>
189      * <li>Namespace string can be parsed as URI</li>
190      * </ol>
191      */
192     @Override
193     public void enterNamespace_stmt(final Namespace_stmtContext ctx) {
194         String namespaceName = ValidationUtil.getName(ctx);
195         String rootParentName = ValidationUtil.getRootParentName(ctx);
196
197         try {
198             new URI(namespaceName);
199         } catch (URISyntaxException e) {
200             ValidationUtil.ex(ValidationUtil.f("(In module:%s) Namespace:%s cannot be parsed as URI", rootParentName,
201                     namespaceName));
202         }
203     }
204
205     /**
206      * Constraints:
207      * <ol>
208      * <li>Identifier is in required format</li>
209      * <li>Every import(identified by identifier) within a module/submodule is
210      * present only once</li>
211      * <li>One prefix statement child</li>
212      * </ol>
213      */
214     @Override
215     public void enterImport_stmt(final Import_stmtContext ctx) {
216
217         BasicValidations.checkIdentifier(ctx);
218
219         BasicValidations.checkUniquenessInNamespace(ctx, uniqueImports);
220
221         BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, true);
222
223     }
224
225     /**
226      * Constraints:
227      * <ol>
228      * <li>Date is in valid format</li>
229      * </ol>
230      */
231     @Override
232     public void enterRevision_date_stmt(final Revision_date_stmtContext ctx) {
233         BasicValidations.checkDateFormat(ctx);
234     }
235
236     /**
237      * Constraints:
238      * <ol>
239      * <li>Identifier is in required format</li>
240      * <li>Every include(identified by identifier) within a module/submodule is
241      * present only once</li>
242      * </ol>
243      */
244     @Override
245     public void enterInclude_stmt(final Include_stmtContext ctx) {
246
247         BasicValidations.checkIdentifier(ctx);
248
249         BasicValidations.checkUniquenessInNamespace(ctx, uniqueIncludes);
250     }
251
252     /**
253      * Constraints:
254      * <ol>
255      * <li>Yang-version is specified as 1</li>
256      * </ol>
257      */
258     @Override
259     public void enterYang_version_stmt(final YangParser.Yang_version_stmtContext ctx) {
260         String version = ValidationUtil.getName(ctx);
261         String rootParentName = ValidationUtil.getRootParentName(ctx);
262         if (!version.equals(BasicValidations.SUPPORTED_YANG_VERSION)) {
263             ValidationUtil.ex(ValidationUtil.f("(In (sub)module:%s) Unsupported yang version:%s, supported version:%s",
264                     rootParentName, version, BasicValidations.SUPPORTED_YANG_VERSION));
265         }
266     }
267
268     /**
269      * Constraints:
270      * <ol>
271      * <li>Identifier is in required format</li>
272      * <li>Every prefix(identified by identifier) within a module/submodule is
273      * presented only once</li>
274      * </ol>
275      */
276     @Override
277     public void enterPrefix_stmt(final Prefix_stmtContext ctx) {
278
279         BasicValidations.checkIdentifier(ctx);
280
281         BasicValidations.checkUniquenessInNamespace(ctx, uniquePrefixes);
282     }
283
284     /**
285      * Constraints:
286      * <ol>
287      * <li>Identifier is in required format</li>
288      * <li>One type statement child</li>
289      * </ol>
290      */
291     @Override
292     public void enterTypedef_stmt(final Typedef_stmtContext ctx) {
293
294         BasicValidations.checkIdentifier(ctx);
295
296         BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, true);
297     }
298
299     /**
300      * Constraints:
301      * <ol>
302      * <li>(Prefix):Identifier is in required format</li>
303      * </ol>
304      */
305     @Override
306     public void enterType_stmt(final Type_stmtContext ctx) {
307         BasicValidations.checkPrefixedIdentifier(ctx);
308     }
309
310     /**
311      * Constraints:
312      * <ol>
313      * <li>Identifier is in required format</li>
314      * </ol>
315      */
316     @Override
317     public void enterContainer_stmt(final Container_stmtContext ctx) {
318         BasicValidations.checkIdentifier(ctx);
319     }
320
321     /**
322      * Constraints:
323      * <ol>
324      * <li>Identifier is in required format</li>
325      * <li>One type statement child</li>
326      * <li>Default statement must not be present if mandatory statement is</li>
327      * </ol>
328      */
329     @Override
330     public void enterLeaf_stmt(final Leaf_stmtContext ctx) {
331         BasicValidations.checkIdentifier(ctx);
332
333         BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, true);
334
335         BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class, Default_stmtContext.class);
336     }
337
338     /**
339      * Constraints:
340      * <ol>
341      * <li>Identifier is in required format</li>
342      * <li>One type statement child</li>
343      * </ol>
344      */
345     @Override
346     public void enterLeaf_list_stmt(final Leaf_list_stmtContext ctx) {
347
348         BasicValidations.checkIdentifier(ctx);
349
350         BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, true);
351     }
352
353     private static final Set<String> PERMITTED_ORDER_BY_ARGS = Sets.newHashSet("system", "user");
354
355     /**
356      * Constraints:
357      * <ol>
358      * <li>Value must be one of: system, user</li>
359      * </ol>
360      */
361     @Override
362     public void enterOrdered_by_arg(final Ordered_by_argContext ctx) {
363         BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_ORDER_BY_ARGS);
364     }
365
366     /**
367      * Constraints:
368      * <ol>
369      * <li>Identifier is in required format</li>
370      * </ol>
371      */
372     @Override
373     public void enterList_stmt(final List_stmtContext ctx) {
374         BasicValidations.checkIdentifier(ctx);
375         // TODO check: "if config==true then key must be present" could be
376         // performed
377     }
378
379     /**
380      * Constraints:
381      * <ol>
382      * <li>No duplicate keys</li>
383      * </ol>
384      */
385     @Override
386     public void enterKey_stmt(final Key_stmtContext ctx) {
387         BasicValidations.getAndCheckUniqueKeys(ctx);
388     }
389
390     /**
391      * Constraints:
392      * <ol>
393      * <liNo duplicate uniques</li>
394      * </ol>
395      */
396     @Override
397     public void enterUnique_stmt(final Unique_stmtContext ctx) {
398         BasicValidations.getAndCheckUniqueKeys(ctx);
399     }
400
401     /**
402      * Constraints:
403      * <ol>
404      * <li>Identifier is in required format</li>
405      * <li>Default statement must not be present if mandatory statement is</li>
406      * </ol>
407      */
408     @Override
409     public void enterChoice_stmt(final Choice_stmtContext ctx) {
410         BasicValidations.checkIdentifier(ctx);
411
412         BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class, Default_stmtContext.class);
413
414     }
415
416     /**
417      * Constraints:
418      * <ol>
419      * <li>Identifier is in required format</li>
420      * </ol>
421      */
422     @Override
423     public void enterCase_stmt(final Case_stmtContext ctx) {
424         BasicValidations.checkIdentifier(ctx);
425     }
426
427     private static final Set<String> PERMITTED_BOOLEAN_ARGS = Sets.newHashSet("true", "false");
428
429     /**
430      * Constraints:
431      * <ol>
432      * <li>Value must be one of: true, false</li>
433      * </ol>
434      */
435     @Override
436     public void enterMandatory_arg(final Mandatory_argContext ctx) {
437         BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_BOOLEAN_ARGS);
438     }
439
440     /**
441      * Constraints:
442      * <ol>
443      * <li>Identifier is in required format</li>
444      * </ol>
445      */
446     @Override
447     public void enterAnyxml_stmt(final Anyxml_stmtContext ctx) {
448         BasicValidations.checkIdentifier(ctx);
449     }
450
451     /**
452      * Constraints:
453      * <ol>
454      * <li>Identifier is in required format</li>
455      * </ol>
456      */
457     @Override
458     public void enterGrouping_stmt(final Grouping_stmtContext ctx) {
459         BasicValidations.checkIdentifier(ctx);
460     }
461
462     /**
463      * Constraints:
464      * <ol>
465      * <li>(Prefix):Identifier is in required format</li>
466      * </ol>
467      */
468     @Override
469     public void enterUses_stmt(final Uses_stmtContext ctx) {
470         BasicValidations.checkPrefixedIdentifier(ctx);
471     }
472
473     /**
474      * Constraints:
475      * <ol>
476      * <li>Identifier is in required format</li>
477      * </ol>
478      */
479     @Override
480     public void enterRefine_stmt(final Refine_stmtContext ctx) {
481         BasicValidations.checkSchemaNodeIdentifier(ctx);
482     }
483
484     /**
485      * Constraints:
486      * <ol>
487      * <li>Identifier is in required format</li>
488      * </ol>
489      */
490     @Override
491     public void enterRpc_stmt(final Rpc_stmtContext ctx) {
492         BasicValidations.checkIdentifier(ctx);
493     }
494
495     /**
496      * Constraints:
497      * <ol>
498      * <li>Identifier is in required format</li>
499      * </ol>
500      */
501     @Override
502     public void enterNotification_stmt(final Notification_stmtContext ctx) {
503         BasicValidations.checkIdentifier(ctx);
504     }
505
506     /**
507      * Constraints:
508      * <ol>
509      * <li>Schema Node Identifier is in required format</li>
510      * </ol>
511      */
512     @Override
513     public void enterAugment_stmt(final Augment_stmtContext ctx) {
514         BasicValidations.checkSchemaNodeIdentifier(ctx);
515     }
516
517     /**
518      * Constraints:
519      * <ol>
520      * <li>Identifier is in required format</li>
521      * </ol>
522      */
523     @Override
524     public void enterIdentity_stmt(final Identity_stmtContext ctx) {
525         BasicValidations.checkIdentifier(ctx);
526     }
527
528     /**
529      * Constraints:
530      * <ol>
531      * <li>(Prefix):Identifier is in required format</li>
532      * </ol>
533      */
534     @Override
535     public void enterBase_stmt(final Base_stmtContext ctx) {
536         BasicValidations.checkPrefixedIdentifier(ctx);
537
538     }
539
540     /**
541      * Constraints:
542      * <ol>
543      * <li>Value must be one of: true, false</li>
544      * </ol>
545      */
546     @Override
547     public void enterYin_element_arg(final Yin_element_argContext ctx) {
548         BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_BOOLEAN_ARGS);
549     }
550
551     /**
552      * Constraints:
553      * <ol>
554      * <li>Identifier is in required format</li>
555      * </ol>
556      */
557     @Override
558     public void enterExtension_stmt(final Extension_stmtContext ctx) {
559         BasicValidations.checkIdentifier(ctx);
560     }
561
562     /**
563      * Constraints:
564      * <ol>
565      * <li>Identifier is in required format</li>
566      * </ol>
567      */
568     @Override
569     public void enterArgument_stmt(final Argument_stmtContext ctx) {
570         BasicValidations.checkIdentifier(ctx);
571     }
572
573     /**
574      * Constraints:
575      * <ol>
576      * <li>Identifier is in required format</li>
577      * </ol>
578      */
579     @Override
580     public void enterFeature_stmt(final Feature_stmtContext ctx) {
581         BasicValidations.checkIdentifier(ctx);
582
583     }
584
585     /**
586      * Constraints:
587      * <ol>
588      * <li>(Prefix):Identifier is in required format</li>
589      * </ol>
590      */
591     @Override
592     public void enterIf_feature_stmt(final If_feature_stmtContext ctx) {
593         BasicValidations.checkPrefixedIdentifier(ctx);
594     }
595
596     /**
597      * Constraints:
598      * <ol>
599      * <li>Schema Node Identifier is in required format</li>
600      * <li>At least one deviate-* statement child</li>
601      * </ol>
602      */
603     @Override
604     public void enterDeviation_stmt(final Deviation_stmtContext ctx) {
605         BasicValidations.checkSchemaNodeIdentifier(ctx);
606
607         Set<Class<? extends ParseTree>> types = Sets.newHashSet();
608         types.add(Deviate_add_stmtContext.class);
609         types.add(Deviate_add_stmtContext.class);
610         BasicValidations.checkPresentChildOfTypes(ctx, types, false);
611     }
612
613     /**
614      * Constraints:
615      * <ol>
616      * <li>Value must be one of: true, false</li>
617      * </ol>
618      */
619     @Override
620     public void enterConfig_arg(final Config_argContext ctx) {
621         BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_BOOLEAN_ARGS);
622     }
623
624     private static final Set<String> PERMITTED_STATUS_ARGS = Sets.newHashSet("current", "deprecated", "obsolete");
625
626     /**
627      * Constraints:
628      * <ol>
629      * <li>Value must be one of: "current", "deprecated", "obsolete"</li>
630      * </ol>
631      */
632     @Override
633     public void enterStatus_arg(final Status_argContext ctx) {
634         BasicValidations.checkOnlyPermittedValues(ctx, PERMITTED_STATUS_ARGS);
635     }
636
637 }