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