Initial opendaylight infrastructure commit!!
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / model / parser / impl / YangModelParserImpl.java
1 /*\r
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
3  *\r
4  * This program and the accompanying materials are made available under the\r
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
6  * and is available at http://www.eclipse.org/legal/epl-v10.html\r
7  */\r
8 package org.opendaylight.controller.model.parser.impl;\r
9 \r
10 import static org.opendaylight.controller.model.parser.util.YangModelBuilderHelper.*;\r
11 \r
12 import java.net.URI;\r
13 import java.net.URISyntaxException;\r
14 import java.text.DateFormat;\r
15 import java.text.ParseException;\r
16 import java.text.SimpleDateFormat;\r
17 import java.util.Date;\r
18 import java.util.List;\r
19 import java.util.Stack;\r
20 \r
21 import org.antlr.v4.runtime.tree.ParseTree;\r
22 import org.opendaylight.controller.antlrv4.code.gen.YangParser;\r
23 import org.opendaylight.controller.antlrv4.code.gen.YangParserBaseListener;\r
24 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_argContext;\r
25 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_stmtContext;\r
26 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Container_stmtContext;\r
27 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Description_stmtContext;\r
28 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;\r
29 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_delete_stmtContext;\r
30 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_not_supported_stmtContext;\r
31 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_replace_stmtContext;\r
32 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Import_stmtContext;\r
33 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Key_stmtContext;\r
34 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_list_stmtContext;\r
35 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_stmtContext;\r
36 import org.opendaylight.controller.antlrv4.code.gen.YangParser.List_stmtContext;\r
37 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_header_stmtsContext;\r
38 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;\r
39 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_argContext;\r
40 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_stmtContext;\r
41 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Prefix_stmtContext;\r
42 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Presence_stmtContext;\r
43 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Reference_stmtContext;\r
44 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_date_stmtContext;\r
45 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtContext;\r
46 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtsContext;\r
47 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_stmtContext;\r
48 import org.opendaylight.controller.antlrv4.code.gen.YangParser.StringContext;\r
49 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_body_stmtsContext;\r
50 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext;\r
51 import org.opendaylight.controller.model.api.type.EnumTypeDefinition;\r
52 import org.opendaylight.controller.model.api.type.LengthConstraint;\r
53 import org.opendaylight.controller.model.api.type.PatternConstraint;\r
54 import org.opendaylight.controller.model.api.type.RangeConstraint;\r
55 import org.opendaylight.controller.model.parser.api.AugmentationSchemaBuilder;\r
56 import org.opendaylight.controller.model.parser.api.GroupingBuilder;\r
57 import org.opendaylight.controller.model.parser.builder.ContainerSchemaNodeBuilder;\r
58 import org.opendaylight.controller.model.parser.builder.DeviationBuilder;\r
59 import org.opendaylight.controller.model.parser.builder.FeatureBuilder;\r
60 import org.opendaylight.controller.model.parser.builder.LeafListSchemaNodeBuilder;\r
61 import org.opendaylight.controller.model.parser.builder.LeafSchemaNodeBuilder;\r
62 import org.opendaylight.controller.model.parser.builder.ListSchemaNodeBuilder;\r
63 import org.opendaylight.controller.model.parser.builder.ModuleBuilder;\r
64 import org.opendaylight.controller.model.parser.builder.MustDefinitionBuilder;\r
65 import org.opendaylight.controller.model.parser.builder.NotificationBuilder;\r
66 import org.opendaylight.controller.model.parser.builder.RpcDefinitionBuilder;\r
67 import org.opendaylight.controller.model.parser.builder.TypedefBuilder;\r
68 import org.opendaylight.controller.model.parser.util.YangModelBuilderHelper;\r
69 import org.opendaylight.controller.model.util.BitsType;\r
70 import org.opendaylight.controller.model.util.EnumerationType;\r
71 import org.opendaylight.controller.model.util.Leafref;\r
72 import org.opendaylight.controller.model.util.StringType;\r
73 import org.opendaylight.controller.model.util.YangTypesConverter;\r
74 import org.opendaylight.controller.yang.common.QName;\r
75 import org.opendaylight.controller.yang.model.api.RevisionAwareXPath;\r
76 import org.opendaylight.controller.yang.model.api.Status;\r
77 import org.opendaylight.controller.yang.model.api.TypeDefinition;\r
78 import org.slf4j.Logger;\r
79 import org.slf4j.LoggerFactory;\r
80 \r
81 public class YangModelParserImpl extends YangParserBaseListener {\r
82 \r
83     private static final Logger logger = LoggerFactory\r
84             .getLogger(YangModelParserImpl.class);\r
85 \r
86     private ModuleBuilder moduleBuilder;\r
87 \r
88     private String moduleName;\r
89     private URI namespace;\r
90     private String yangModelPrefix;\r
91     private Date revision;\r
92 \r
93     private final DateFormat simpleDateFormat = new SimpleDateFormat(\r
94             "yyyy-mm-dd");\r
95     private final Stack<String> actualPath = new Stack<String>();\r
96 \r
97     @Override\r
98     public void enterModule_stmt(YangParser.Module_stmtContext ctx) {\r
99         moduleName = stringFromNode(ctx);\r
100         actualPath.push(moduleName);\r
101         moduleBuilder = new ModuleBuilder(moduleName);\r
102     }\r
103 \r
104     @Override\r
105     public void exitModule_stmt(YangParser.Module_stmtContext ctx) {\r
106         final String moduleName = actualPath.pop();\r
107         logger.debug("Exiting module " + moduleName);\r
108     }\r
109 \r
110     @Override\r
111     public void enterModule_header_stmts(final Module_header_stmtsContext ctx) {\r
112         super.enterModule_header_stmts(ctx);\r
113 \r
114         for (int i = 0; i < ctx.getChildCount(); ++i) {\r
115             final ParseTree treeNode = ctx.getChild(i);\r
116             if (treeNode instanceof Namespace_stmtContext) {\r
117                 String namespaceStr = stringFromNode(treeNode);\r
118                 try {\r
119                     this.namespace = new URI(namespaceStr);\r
120                     moduleBuilder.setNamespace(namespace);\r
121                 } catch (URISyntaxException e) {\r
122                     logger.warn("Failed to parse module namespace", e);\r
123                 }\r
124             } else if (treeNode instanceof Prefix_stmtContext) {\r
125                 yangModelPrefix = stringFromNode(treeNode);\r
126                 moduleBuilder.setPrefix(yangModelPrefix);\r
127             } else if (treeNode instanceof Yang_version_stmtContext) {\r
128                 final String yangVersion = stringFromNode(treeNode);\r
129                 moduleBuilder.setYangVersion(yangVersion);\r
130             }\r
131         }\r
132     }\r
133 \r
134     // TODO: resolve submodule parsing\r
135     @Override\r
136     public void enterSubmodule_header_stmts(\r
137             YangParser.Submodule_header_stmtsContext ctx) {\r
138         String submoduleName = stringFromNode(ctx);\r
139         QName submoduleQName = new QName(namespace, revision, yangModelPrefix,\r
140                 submoduleName);\r
141         moduleBuilder.addSubmodule(submoduleQName);\r
142         updatePath(submoduleName);\r
143     }\r
144 \r
145     @Override\r
146     public void exitSubmodule_header_stmts(\r
147             YangParser.Submodule_header_stmtsContext ctx) {\r
148         final String submodule = actualPath.pop();\r
149         logger.debug("exiting submodule " + submodule);\r
150     }\r
151 \r
152     @Override\r
153     public void enterOrganization_stmt(YangParser.Organization_stmtContext ctx) {\r
154         final String organization = stringFromNode(ctx);\r
155         moduleBuilder.setOrganization(organization);\r
156     }\r
157 \r
158     @Override\r
159     public void enterContact_stmt(YangParser.Contact_stmtContext ctx) {\r
160         String contact = stringFromNode(ctx);\r
161         moduleBuilder.setContact(contact);\r
162     }\r
163 \r
164     @Override\r
165     public void enterRevision_stmts(Revision_stmtsContext ctx) {\r
166         for (int i = 0; i < ctx.getChildCount(); ++i) {\r
167             final ParseTree treeNode = ctx.getChild(i);\r
168             if (treeNode instanceof Revision_stmtContext) {\r
169                 final String revisionDateStr = stringFromNode(treeNode);\r
170                 try {\r
171                     revision = simpleDateFormat.parse(revisionDateStr);\r
172                 } catch (ParseException e) {\r
173                     logger.warn("Failed to parse revision string: "\r
174                             + revisionDateStr);\r
175                 }\r
176             }\r
177         }\r
178     }\r
179 \r
180     @Override\r
181     public void enterDescription_stmt(YangParser.Description_stmtContext ctx) {\r
182         // if this is module description...\r
183         if (actualPath.size() == 1) {\r
184             moduleBuilder.setDescription(stringFromNode(ctx));\r
185         }\r
186     }\r
187 \r
188     @Override\r
189     public void enterImport_stmt(Import_stmtContext ctx) {\r
190         super.enterImport_stmt(ctx);\r
191 \r
192         final String importName = stringFromNode(ctx);\r
193         String importPrefix = null;\r
194         Date importRevision = null;\r
195 \r
196         for (int i = 0; i < ctx.getChildCount(); ++i) {\r
197             final ParseTree treeNode = ctx.getChild(i);\r
198             if (treeNode instanceof Prefix_stmtContext) {\r
199                 importPrefix = stringFromNode(treeNode);\r
200             }\r
201             if (treeNode instanceof Revision_date_stmtContext) {\r
202                 String importRevisionStr = stringFromNode(treeNode);\r
203                 try {\r
204                     importRevision = simpleDateFormat.parse(importRevisionStr);\r
205                 } catch (Exception e) {\r
206                     logger.warn("Failed to parse import revision-date.", e);\r
207                 }\r
208             }\r
209         }\r
210         moduleBuilder.addModuleImport(importName, importRevision, importPrefix);\r
211     }\r
212 \r
213     @Override\r
214     public void enterAugment_stmt(YangParser.Augment_stmtContext ctx) {\r
215         final String augmentPath = stringFromNode(ctx);\r
216         AugmentationSchemaBuilder builder = moduleBuilder.addAugment(\r
217                 augmentPath, actualPath);\r
218         updatePath(augmentPath);\r
219 \r
220         for (int i = 0; i < ctx.getChildCount(); i++) {\r
221             ParseTree child = ctx.getChild(i);\r
222             if (child instanceof Description_stmtContext) {\r
223                 String desc = stringFromNode(child);\r
224                 builder.setDescription(desc);\r
225             } else if (child instanceof Reference_stmtContext) {\r
226                 String ref = stringFromNode(child);\r
227                 builder.setReference(ref);\r
228             } else if (child instanceof Status_stmtContext) {\r
229                 Status status = getStatus((Status_stmtContext) child);\r
230                 builder.setStatus(status);\r
231             }\r
232         }\r
233     }\r
234 \r
235     @Override\r
236     public void exitAugment_stmt(YangParser.Augment_stmtContext ctx) {\r
237         final String augment = actualPath.pop();\r
238         logger.debug("exiting augment " + augment);\r
239     }\r
240 \r
241     @Override\r
242     public void enterMust_stmt(YangParser.Must_stmtContext ctx) {\r
243         String mustText = "";\r
244         String description = null;\r
245         String reference = null;\r
246         for (int i = 0; i < ctx.getChildCount(); ++i) {\r
247             ParseTree child = ctx.getChild(i);\r
248             if (child instanceof StringContext) {\r
249                 final StringContext context = (StringContext) child;\r
250                 for (int j = 0; j < context.getChildCount(); j++) {\r
251                     String mustPart = context.getChild(j).getText();\r
252                     if (j == 0) {\r
253                         mustText += mustPart\r
254                                 .substring(0, mustPart.length() - 1);\r
255                         continue;\r
256                     }\r
257                     if (j % 2 == 0) {\r
258                         mustText += mustPart.substring(1);\r
259                     }\r
260                 }\r
261             } else if (child instanceof Description_stmtContext) {\r
262                 description = stringFromNode(child);\r
263             } else if (child instanceof Reference_stmtContext) {\r
264                 reference = stringFromNode(child);\r
265             }\r
266         }\r
267         MustDefinitionBuilder builder = moduleBuilder.addMustDefinition(\r
268                 mustText, actualPath);\r
269         builder.setDescription(description);\r
270         builder.setReference(reference);\r
271     }\r
272 \r
273     @Override\r
274     public void enterTypedef_stmt(YangParser.Typedef_stmtContext ctx) {\r
275         String typedefName = stringFromNode(ctx);\r
276         QName typedefQName = new QName(namespace, revision, yangModelPrefix,\r
277                 typedefName);\r
278         TypedefBuilder builder = moduleBuilder.addTypedef(typedefQName,\r
279                 actualPath);\r
280         updatePath(typedefName);\r
281 \r
282         builder.setPath(getActualSchemaPath(actualPath, namespace, revision,\r
283                 yangModelPrefix));\r
284         parseSchemaNodeArgs(ctx, builder);\r
285     }\r
286 \r
287     @Override\r
288     public void exitTypedef_stmt(YangParser.Typedef_stmtContext ctx) {\r
289         final String actContainer = actualPath.pop();\r
290         logger.debug("exiting " + actContainer);\r
291     }\r
292 \r
293     @Override\r
294     public void enterType_stmt(YangParser.Type_stmtContext ctx) {\r
295         String typeName = stringFromNode(ctx);\r
296         QName typeQName;\r
297         if (typeName.contains(":")) {\r
298             String[] splittedName = typeName.split(":");\r
299             // if this type contains prefix, it means that it point to type in\r
300             // external module\r
301             typeQName = new QName(null, null, splittedName[0], splittedName[1]);\r
302         } else {\r
303             typeQName = new QName(namespace, revision, yangModelPrefix,\r
304                     typeName);\r
305         }\r
306 \r
307         TypeDefinition<?> type = null;\r
308 \r
309         if (!YangTypesConverter.isBaseYangType(typeName)) {\r
310             if (typeName.equals("leafref")) {\r
311                 // TODO: RevisionAwareXPath implementation\r
312                 type = new Leafref(new RevisionAwareXPath() {\r
313                 });\r
314             } else {\r
315                 type = parseUnknownType(typeQName, ctx);\r
316                 // mark parent node of this type statement as dirty\r
317                 moduleBuilder.addDirtyNode(actualPath);\r
318             }\r
319         } else {\r
320 \r
321             Type_body_stmtsContext typeBody = null;\r
322             for (int i = 0; i < ctx.getChildCount(); i++) {\r
323                 if (ctx.getChild(i) instanceof Type_body_stmtsContext) {\r
324                     typeBody = (Type_body_stmtsContext) ctx.getChild(i);\r
325                     break;\r
326                 }\r
327             }\r
328 \r
329             if (typeBody == null) {\r
330                 // if there are no constraints, just grab default base yang type\r
331                 type = YangTypesConverter.javaTypeForBaseYangType(typeName);\r
332             } else {\r
333                 List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody);\r
334                 Integer fractionDigits = getFractionDigits(typeBody);\r
335                 List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody);\r
336                 List<PatternConstraint> patternStatements = getPatternConstraint(typeBody);\r
337                 List<EnumTypeDefinition.EnumPair> enumConstants = YangModelBuilderHelper\r
338                         .getEnumConstants(typeBody);\r
339 \r
340                 if (typeName.equals("decimal64")) {\r
341                     type = YangTypesConverter.javaTypeForBaseYangDecimal64Type(\r
342                             rangeStatements, fractionDigits);\r
343                 } else if (typeName.startsWith("int")\r
344                         || typeName.startsWith("uint")) {\r
345                     type = YangTypesConverter.javaTypeForBaseYangIntegerType(\r
346                             typeName, rangeStatements);\r
347                 } else if (typeName.equals("enumeration")) {\r
348                     type = new EnumerationType(enumConstants);\r
349                 } else if (typeName.equals("string")) {\r
350                     type = new StringType(lengthStatements, patternStatements);\r
351                 } else if (typeName.equals("bits")) {\r
352                     type = new BitsType(getBits(typeBody, actualPath,\r
353                             namespace, revision, yangModelPrefix));\r
354                 } else {\r
355                     // TODO: implement binary + instance-identifier types\r
356                 }\r
357             }\r
358 \r
359         }\r
360 \r
361         moduleBuilder.setType(type, actualPath);\r
362         updatePath(typeName);\r
363     }\r
364 \r
365     @Override\r
366     public void exitType_stmt(YangParser.Type_stmtContext ctx) {\r
367         final String actContainer = actualPath.pop();\r
368         logger.debug("exiting " + actContainer);\r
369     }\r
370 \r
371     @Override\r
372     public void enterGrouping_stmt(YangParser.Grouping_stmtContext ctx) {\r
373         final String groupName = stringFromNode(ctx);\r
374         QName groupQName = new QName(namespace, revision, yangModelPrefix,\r
375                 groupName);\r
376         GroupingBuilder groupBuilder = moduleBuilder.addGrouping(groupQName,\r
377                 actualPath);\r
378         updatePath("grouping");\r
379         updatePath(groupName);\r
380         parseSchemaNodeArgs(ctx, groupBuilder);\r
381     }\r
382 \r
383     @Override\r
384     public void exitGrouping_stmt(YangParser.Grouping_stmtContext ctx) {\r
385         String actContainer = actualPath.pop();\r
386         actContainer += "-" + actualPath.pop();\r
387         logger.debug("exiting " + actContainer);\r
388     }\r
389 \r
390     @Override\r
391     public void enterContainer_stmt(Container_stmtContext ctx) {\r
392         super.enterContainer_stmt(ctx);\r
393         String containerName = stringFromNode(ctx);\r
394         QName containerQName = new QName(namespace, revision, yangModelPrefix,\r
395                 containerName);\r
396         ContainerSchemaNodeBuilder containerBuilder = moduleBuilder\r
397                 .addContainerNode(containerQName, actualPath);\r
398         updatePath(containerName);\r
399 \r
400         containerBuilder.setPath(getActualSchemaPath(actualPath, namespace,\r
401                 revision, yangModelPrefix));\r
402         parseSchemaNodeArgs(ctx, containerBuilder);\r
403 \r
404         for (int i = 0; i < ctx.getChildCount(); ++i) {\r
405             final ParseTree childNode = ctx.getChild(i);\r
406             if (childNode instanceof Presence_stmtContext) {\r
407                 containerBuilder.setPresenceContainer(true);\r
408             } else if (childNode instanceof Config_stmtContext) {\r
409                 for (int j = 0; j < childNode.getChildCount(); j++) {\r
410                     ParseTree configArg = childNode.getChild(j);\r
411                     if (configArg instanceof Config_argContext) {\r
412                         String config = stringFromNode(configArg);\r
413                         if (config.equals("true")) {\r
414                             containerBuilder.setConfiguration(true);\r
415                         } else {\r
416                             containerBuilder.setConfiguration(false);\r
417                         }\r
418                     }\r
419                 }\r
420             }\r
421         }\r
422     }\r
423 \r
424     @Override\r
425     public void exitContainer_stmt(Container_stmtContext ctx) {\r
426         super.exitContainer_stmt(ctx);\r
427         final String actContainer = actualPath.pop();\r
428         logger.debug("exiting " + actContainer);\r
429     }\r
430 \r
431     private boolean isLeafReadOnly(final ParseTree leaf) {\r
432         if (leaf != null) {\r
433             for (int i = 0; i < leaf.getChildCount(); ++i) {\r
434                 final ParseTree configContext = leaf.getChild(i);\r
435                 if (configContext instanceof Config_argContext) {\r
436                     final String value = stringFromNode(configContext);\r
437                     if (value.equals("true")) {\r
438                         return true;\r
439                     }\r
440                 }\r
441             }\r
442         }\r
443         return false;\r
444     }\r
445 \r
446     @Override\r
447     public void enterLeaf_stmt(Leaf_stmtContext ctx) {\r
448         super.enterLeaf_stmt(ctx);\r
449 \r
450         final String leafName = stringFromNode(ctx);\r
451         QName leafQName = new QName(namespace, revision, yangModelPrefix,\r
452                 leafName);\r
453         LeafSchemaNodeBuilder leafBuilder = moduleBuilder.addLeafNode(\r
454                 leafQName, actualPath);\r
455         updatePath(leafName);\r
456 \r
457         leafBuilder.setPath(getActualSchemaPath(actualPath, namespace,\r
458                 revision, yangModelPrefix));\r
459         parseSchemaNodeArgs(ctx, leafBuilder);\r
460 \r
461         for (int i = 0; i < ctx.getChildCount(); i++) {\r
462             ParseTree child = ctx.getChild(i);\r
463             if (child instanceof Config_stmtContext) {\r
464                 leafBuilder.setConfiguration(isLeafReadOnly(child));\r
465             }\r
466         }\r
467     }\r
468 \r
469     @Override\r
470     public void exitLeaf_stmt(YangParser.Leaf_stmtContext ctx) {\r
471         final String actLeaf = actualPath.pop();\r
472         logger.debug("exiting " + actLeaf);\r
473     }\r
474 \r
475     @Override\r
476     public void enterUses_stmt(YangParser.Uses_stmtContext ctx) {\r
477         final String groupingPathStr = stringFromNode(ctx);\r
478         moduleBuilder.addUsesNode(groupingPathStr, actualPath);\r
479         updatePath(groupingPathStr);\r
480     }\r
481 \r
482     @Override\r
483     public void exitUses_stmt(YangParser.Uses_stmtContext ctx) {\r
484         final String actContainer = actualPath.pop();\r
485         logger.debug("exiting " + actContainer);\r
486     }\r
487 \r
488     @Override\r
489     public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) {\r
490         super.enterLeaf_list_stmt(ctx);\r
491 \r
492         final String leafListName = stringFromNode(ctx);\r
493         QName leafListQName = new QName(namespace, revision, yangModelPrefix,\r
494                 leafListName);\r
495         LeafListSchemaNodeBuilder leafListBuilder = moduleBuilder\r
496                 .addLeafListNode(leafListQName, actualPath);\r
497         updatePath(leafListName);\r
498 \r
499         parseSchemaNodeArgs(ctx, leafListBuilder);\r
500 \r
501         for (int i = 0; i < ctx.getChildCount(); ++i) {\r
502             final ParseTree childNode = ctx.getChild(i);\r
503             if (childNode instanceof Config_stmtContext) {\r
504                 leafListBuilder.setConfiguration(isLeafReadOnly(childNode));\r
505             } else if (childNode instanceof Ordered_by_stmtContext) {\r
506                 final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;\r
507                 final boolean userOrdered = parseUserOrdered(orderedBy);\r
508                 leafListBuilder.setUserOrdered(userOrdered);\r
509             }\r
510         }\r
511     }\r
512 \r
513     @Override\r
514     public void exitLeaf_list_stmt(YangParser.Leaf_list_stmtContext ctx) {\r
515         final String actContainer = actualPath.pop();\r
516         logger.debug("exiting " + actContainer);\r
517     }\r
518 \r
519     @Override\r
520     public void enterList_stmt(List_stmtContext ctx) {\r
521         super.enterList_stmt(ctx);\r
522 \r
523         final String containerName = stringFromNode(ctx);\r
524         QName containerQName = new QName(namespace, revision, yangModelPrefix,\r
525                 containerName);\r
526         ListSchemaNodeBuilder listBuilder = moduleBuilder.addListNode(\r
527                 containerQName, actualPath);\r
528         updatePath(containerName);\r
529 \r
530         listBuilder.setPath(getActualSchemaPath(actualPath, namespace,\r
531                 revision, yangModelPrefix));\r
532         parseSchemaNodeArgs(ctx, listBuilder);\r
533 \r
534         String keyDefinition = "";\r
535         for (int i = 0; i < ctx.getChildCount(); ++i) {\r
536             ParseTree childNode = ctx.getChild(i);\r
537 \r
538             if (childNode instanceof Ordered_by_stmtContext) {\r
539                 final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;\r
540                 final boolean userOrdered = parseUserOrdered(orderedBy);\r
541                 listBuilder.setUserOrdered(userOrdered);\r
542             } else if (childNode instanceof Key_stmtContext) {\r
543                 List<QName> key = createListKey(keyDefinition, namespace,\r
544                         revision, keyDefinition);\r
545                 listBuilder.setKeyDefinition(key);\r
546             }\r
547         }\r
548     }\r
549 \r
550     @Override\r
551     public void exitList_stmt(List_stmtContext ctx) {\r
552         final String actContainer = actualPath.pop();\r
553         logger.debug("exiting " + actContainer);\r
554     }\r
555 \r
556     @Override\r
557     public void enterNotification_stmt(YangParser.Notification_stmtContext ctx) {\r
558         final String notificationName = stringFromNode(ctx);\r
559         QName notificationQName = new QName(namespace, revision,\r
560                 yangModelPrefix, notificationName);\r
561         NotificationBuilder notificationBuilder = moduleBuilder\r
562                 .addNotification(notificationQName, actualPath);\r
563         updatePath(notificationName);\r
564 \r
565         notificationBuilder.setPath(getActualSchemaPath(actualPath, namespace,\r
566                 revision, yangModelPrefix));\r
567         parseSchemaNodeArgs(ctx, notificationBuilder);\r
568     }\r
569 \r
570     @Override\r
571     public void exitNotification_stmt(YangParser.Notification_stmtContext ctx) {\r
572         final String actContainer = actualPath.pop();\r
573         logger.debug("exiting " + actContainer);\r
574     }\r
575 \r
576     @Override\r
577     public void enterRpc_stmt(YangParser.Rpc_stmtContext ctx) {\r
578         final String rpcName = stringFromNode(ctx);\r
579         QName rpcQName = new QName(namespace, revision, yangModelPrefix,\r
580                 rpcName);\r
581         RpcDefinitionBuilder rpcBuilder = moduleBuilder.addRpc(rpcQName,\r
582                 actualPath);\r
583         updatePath(rpcName);\r
584 \r
585         rpcBuilder.setPath(getActualSchemaPath(actualPath, namespace, revision,\r
586                 yangModelPrefix));\r
587         parseSchemaNodeArgs(ctx, rpcBuilder);\r
588     }\r
589 \r
590     @Override\r
591     public void exitRpc_stmt(YangParser.Rpc_stmtContext ctx) {\r
592         final String actContainer = actualPath.pop();\r
593         logger.debug("exiting " + actContainer);\r
594     }\r
595 \r
596     @Override\r
597     public void enterInput_stmt(YangParser.Input_stmtContext ctx) {\r
598         updatePath("input");\r
599     }\r
600 \r
601     @Override\r
602     public void exitInput_stmt(YangParser.Input_stmtContext ctx) {\r
603         final String actContainer = actualPath.pop();\r
604         logger.debug("exiting " + actContainer);\r
605     }\r
606 \r
607     @Override\r
608     public void enterOutput_stmt(YangParser.Output_stmtContext ctx) {\r
609         updatePath("output");\r
610     }\r
611 \r
612     @Override\r
613     public void exitOutput_stmt(YangParser.Output_stmtContext ctx) {\r
614         final String actContainer = actualPath.pop();\r
615         logger.debug("exiting " + actContainer);\r
616     }\r
617 \r
618     @Override\r
619     public void enterFeature_stmt(YangParser.Feature_stmtContext ctx) {\r
620         final String featureName = stringFromNode(ctx);\r
621         QName featureQName = new QName(namespace, revision, yangModelPrefix,\r
622                 featureName);\r
623         FeatureBuilder featureBuilder = moduleBuilder.addFeature(featureQName,\r
624                 actualPath);\r
625         updatePath(featureName);\r
626 \r
627         featureBuilder.setPath(getActualSchemaPath(actualPath, namespace,\r
628                 revision, yangModelPrefix));\r
629         parseSchemaNodeArgs(ctx, featureBuilder);\r
630     }\r
631 \r
632     @Override\r
633     public void exitFeature_stmt(YangParser.Feature_stmtContext ctx) {\r
634         final String actContainer = actualPath.pop();\r
635         logger.debug("exiting " + actContainer);\r
636     }\r
637 \r
638     @Override\r
639     public void enterDeviation_stmt(YangParser.Deviation_stmtContext ctx) {\r
640         final String targetPath = stringFromNode(ctx);\r
641         String reference = null;\r
642         String deviate = null;\r
643         DeviationBuilder builder = moduleBuilder.addDeviation(targetPath);\r
644         updatePath(targetPath);\r
645 \r
646         for (int i = 0; i < ctx.getChildCount(); i++) {\r
647             ParseTree child = ctx.getChild(i);\r
648             if (child instanceof Reference_stmtContext) {\r
649                 reference = stringFromNode(child);\r
650             } else if (child instanceof Deviate_not_supported_stmtContext) {\r
651                 deviate = stringFromNode(child);\r
652             } else if (child instanceof Deviate_add_stmtContext) {\r
653                 deviate = stringFromNode(child);\r
654             } else if (child instanceof Deviate_replace_stmtContext) {\r
655                 deviate = stringFromNode(child);\r
656             } else if (child instanceof Deviate_delete_stmtContext) {\r
657                 deviate = stringFromNode(child);\r
658             }\r
659         }\r
660         builder.setReference(reference);\r
661         builder.setDeviate(deviate);\r
662     }\r
663 \r
664     @Override\r
665     public void exitDeviation_stmt(YangParser.Deviation_stmtContext ctx) {\r
666         final String actContainer = actualPath.pop();\r
667         logger.debug("exiting " + actContainer);\r
668     }\r
669 \r
670     public ModuleBuilder getModuleBuilder() {\r
671         return moduleBuilder;\r
672     }\r
673 \r
674     private void updatePath(String containerName) {\r
675         actualPath.push(containerName);\r
676     }\r
677 \r
678     /**\r
679      * Parse ordered-by statement.\r
680      * \r
681      * @param childNode\r
682      *            Ordered_by_stmtContext\r
683      * @return true, if ordered-by contains value 'user' or false otherwise\r
684      */\r
685     private boolean parseUserOrdered(Ordered_by_stmtContext childNode) {\r
686         boolean result = false;\r
687         for (int j = 0; j < childNode.getChildCount(); j++) {\r
688             ParseTree orderArg = childNode.getChild(j);\r
689             if (orderArg instanceof Ordered_by_argContext) {\r
690                 String orderStr = stringFromNode(orderArg);\r
691                 if (orderStr.equals("system")) {\r
692                     result = false;\r
693                 } else if (orderStr.equals("user")) {\r
694                     result = true;\r
695                 } else {\r
696                     logger.warn("Invalid 'ordered-by' statement.");\r
697                 }\r
698             }\r
699         }\r
700         return result;\r
701     }\r
702 \r
703 }\r