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