Update the API generation code and code generation sample
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / yang / model / parser / util / YangModelBuilderUtil.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/eplv10.html\r
7  */\r
8 package org.opendaylight.controller.yang.model.parser.util;\r
9 \r
10 import java.net.URI;\r
11 import java.util.ArrayList;\r
12 import java.util.Collections;\r
13 import java.util.Date;\r
14 import java.util.List;\r
15 import java.util.Stack;\r
16 \r
17 import org.antlr.v4.runtime.tree.ParseTree;\r
18 import org.opendaylight.controller.antlrv4.code.gen.YangParser;\r
19 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Bit_stmtContext;\r
20 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Bits_specificationContext;\r
21 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_argContext;\r
22 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_stmtContext;\r
23 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Decimal64_specificationContext;\r
24 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Description_stmtContext;\r
25 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Enum_specificationContext;\r
26 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Enum_stmtContext;\r
27 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Fraction_digits_stmtContext;\r
28 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leafref_specificationContext;\r
29 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Length_stmtContext;\r
30 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_argContext;\r
31 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_stmtContext;\r
32 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Max_elements_stmtContext;\r
33 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Min_elements_stmtContext;\r
34 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Must_stmtContext;\r
35 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Numerical_restrictionsContext;\r
36 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_argContext;\r
37 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_stmtContext;\r
38 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Path_stmtContext;\r
39 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Pattern_stmtContext;\r
40 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Position_stmtContext;\r
41 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Range_stmtContext;\r
42 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Reference_stmtContext;\r
43 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Require_instance_argContext;\r
44 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Require_instance_stmtContext;\r
45 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_argContext;\r
46 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_stmtContext;\r
47 import org.opendaylight.controller.antlrv4.code.gen.YangParser.StringContext;\r
48 import org.opendaylight.controller.antlrv4.code.gen.YangParser.String_restrictionsContext;\r
49 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_body_stmtsContext;\r
50 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Units_stmtContext;\r
51 import org.opendaylight.controller.antlrv4.code.gen.YangParser.When_stmtContext;\r
52 import org.opendaylight.controller.yang.common.QName;\r
53 import org.opendaylight.controller.yang.model.api.RevisionAwareXPath;\r
54 import org.opendaylight.controller.yang.model.api.SchemaPath;\r
55 import org.opendaylight.controller.yang.model.api.Status;\r
56 import org.opendaylight.controller.yang.model.api.TypeDefinition;\r
57 import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;\r
58 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition;\r
59 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition;\r
60 import org.opendaylight.controller.yang.model.api.type.LengthConstraint;\r
61 import org.opendaylight.controller.yang.model.api.type.PatternConstraint;\r
62 import org.opendaylight.controller.yang.model.api.type.RangeConstraint;\r
63 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;\r
64 import org.opendaylight.controller.yang.model.parser.builder.api.SchemaNodeBuilder;\r
65 import org.opendaylight.controller.yang.model.parser.builder.impl.ConstraintsBuilder;\r
66 import org.opendaylight.controller.yang.model.util.BaseConstraints;\r
67 import org.opendaylight.controller.yang.model.util.BinaryType;\r
68 import org.opendaylight.controller.yang.model.util.BitsType;\r
69 import org.opendaylight.controller.yang.model.util.EnumerationType;\r
70 import org.opendaylight.controller.yang.model.util.InstanceIdentifier;\r
71 import org.opendaylight.controller.yang.model.util.Leafref;\r
72 import org.opendaylight.controller.yang.model.util.RevisionAwareXPathImpl;\r
73 import org.opendaylight.controller.yang.model.util.StringType;\r
74 import org.opendaylight.controller.yang.model.util.UnknownType;\r
75 import org.opendaylight.controller.yang.model.util.YangTypesConverter;\r
76 import org.slf4j.Logger;\r
77 import org.slf4j.LoggerFactory;\r
78 \r
79 public class YangModelBuilderUtil {\r
80 \r
81     private static final Logger logger = LoggerFactory\r
82             .getLogger(YangModelBuilderUtil.class);\r
83 \r
84     /**\r
85      * Parse given tree and get first string value.\r
86      *\r
87      * @param treeNode\r
88      *            tree to parse\r
89      * @return first string value from given tree\r
90      */\r
91     public static String stringFromNode(final ParseTree treeNode) {\r
92         final String result = "";\r
93         for (int i = 0; i < treeNode.getChildCount(); ++i) {\r
94             if (treeNode.getChild(i) instanceof StringContext) {\r
95                 final StringContext context = (StringContext) treeNode\r
96                         .getChild(i);\r
97                 if (context != null) {\r
98                     return context.getChild(0).getText().replace("\"", "");\r
99                 }\r
100             }\r
101         }\r
102         return result;\r
103     }\r
104 \r
105     /**\r
106      * Parse 'description', 'reference' and 'status' statements and fill in\r
107      * given builder.\r
108      *\r
109      * @param ctx\r
110      *            context to parse\r
111      * @param builder\r
112      *            builder to fill in with parsed statements\r
113      */\r
114     public static void parseSchemaNodeArgs(ParseTree ctx,\r
115             SchemaNodeBuilder builder) {\r
116         for (int i = 0; i < ctx.getChildCount(); i++) {\r
117             ParseTree child = ctx.getChild(i);\r
118             if (child instanceof Description_stmtContext) {\r
119                 String desc = stringFromNode(child);\r
120                 builder.setDescription(desc);\r
121             } else if (child instanceof Reference_stmtContext) {\r
122                 String ref = stringFromNode(child);\r
123                 builder.setReference(ref);\r
124             } else if (child instanceof Status_stmtContext) {\r
125                 Status status = parseStatus((Status_stmtContext) child);\r
126                 builder.setStatus(status);\r
127             }\r
128         }\r
129     }\r
130 \r
131     /**\r
132      * Parse given context and return its value;\r
133      *\r
134      * @param ctx\r
135      *            status context\r
136      * @return value parsed from context\r
137      */\r
138     public static Status parseStatus(Status_stmtContext ctx) {\r
139         for (int i = 0; i < ctx.getChildCount(); i++) {\r
140             ParseTree statusArg = ctx.getChild(i);\r
141             if (statusArg instanceof Status_argContext) {\r
142                 String statusArgStr = stringFromNode(statusArg);\r
143                 if (statusArgStr.equals("current")) {\r
144                     return Status.CURRENT;\r
145                 } else if (statusArgStr.equals("deprecated")) {\r
146                     return Status.DEPRECATED;\r
147                 } else if (statusArgStr.equals("obsolete")) {\r
148                     return Status.OBSOLETE;\r
149                 } else {\r
150                     logger.warn("Invalid 'status' statement: " + statusArgStr);\r
151                 }\r
152             }\r
153         }\r
154         return null;\r
155     }\r
156 \r
157     /**\r
158      * Parse given tree and returns units statement as string.\r
159      *\r
160      * @param ctx\r
161      *            context to parse\r
162      * @return value of units statement as string or null if there is no units\r
163      *         statement\r
164      */\r
165     public static String parseUnits(ParseTree ctx) {\r
166         String units = null;\r
167         for (int i = 0; i < ctx.getChildCount(); i++) {\r
168             ParseTree child = ctx.getChild(i);\r
169             if (child instanceof Units_stmtContext) {\r
170                 units = stringFromNode(child);\r
171                 break;\r
172             }\r
173         }\r
174         return units;\r
175     }\r
176 \r
177     /**\r
178      * Create SchemaPath object from given path list with namespace, revision\r
179      * and prefix based on given values.\r
180      *\r
181      * @param actualPath\r
182      * @param namespace\r
183      * @param revision\r
184      * @param prefix\r
185      * @return SchemaPath object.\r
186      */\r
187     public static SchemaPath createActualSchemaPath(List<String> actualPath,\r
188             URI namespace, Date revision, String prefix) {\r
189         final List<QName> path = new ArrayList<QName>();\r
190         QName qname;\r
191         for (String pathElement : actualPath) {\r
192             qname = new QName(namespace, revision, prefix, pathElement);\r
193             path.add(qname);\r
194         }\r
195         return new SchemaPath(path, true);\r
196     }\r
197 \r
198     /**\r
199      * Create SchemaPath from given string.\r
200      *\r
201      * @param augmentPath\r
202      *            string representation of path\r
203      * @return SchemaPath object\r
204      */\r
205     public static SchemaPath parseAugmentPath(String augmentPath) {\r
206         boolean absolute = augmentPath.startsWith("/");\r
207         String[] splittedPath = augmentPath.split("/");\r
208         List<QName> path = new ArrayList<QName>();\r
209         QName name;\r
210         for (String pathElement : splittedPath) {\r
211             if (pathElement.length() > 0) {\r
212                 String[] splittedElement = pathElement.split(":");\r
213                 if (splittedElement.length == 1) {\r
214                     name = new QName(null, null, null, splittedElement[0]);\r
215                 } else {\r
216                     name = new QName(null, null, splittedElement[0],\r
217                             splittedElement[1]);\r
218                 }\r
219                 path.add(name);\r
220             }\r
221         }\r
222         return new SchemaPath(path, absolute);\r
223     }\r
224 \r
225     /**\r
226      * Create java.util.List of QName objects from given key definition as\r
227      * string.\r
228      *\r
229      * @param keyDefinition\r
230      *            key definition as string\r
231      * @param namespace\r
232      *            current namespace\r
233      * @param revision\r
234      *            current revision\r
235      * @param prefix\r
236      *            current prefix\r
237      * @return YANG list key as java.util.List of QName objects\r
238      */\r
239     public static List<QName> createListKey(String keyDefinition,\r
240             URI namespace, Date revision, String prefix) {\r
241         List<QName> key = new ArrayList<QName>();\r
242         String[] splittedKey = keyDefinition.split(" ");\r
243 \r
244         QName qname = null;\r
245         for (String keyElement : splittedKey) {\r
246             if (keyElement.length() != 0) {\r
247                 qname = new QName(namespace, revision, prefix, keyElement);\r
248                 key.add(qname);\r
249             }\r
250         }\r
251         return key;\r
252     }\r
253 \r
254     private static List<EnumTypeDefinition.EnumPair> getEnumConstants(\r
255             Type_body_stmtsContext ctx, List<String> path, URI namespace,\r
256             Date revision, String prefix) {\r
257         List<EnumTypeDefinition.EnumPair> enumConstants = new ArrayList<EnumTypeDefinition.EnumPair>();\r
258 \r
259         out: for (int j = 0; j < ctx.getChildCount(); j++) {\r
260             ParseTree enumSpecChild = ctx.getChild(j);\r
261             if (enumSpecChild instanceof Enum_specificationContext) {\r
262                 for (int k = 0; k < enumSpecChild.getChildCount(); k++) {\r
263                     ParseTree enumChild = enumSpecChild.getChild(k);\r
264                     if (enumChild instanceof Enum_stmtContext) {\r
265                         enumConstants.add(createEnumPair(\r
266                                 (Enum_stmtContext) enumChild, k, path,\r
267                                 namespace, revision, prefix));\r
268                         if (k == enumSpecChild.getChildCount() - 1) {\r
269                             break out;\r
270                         }\r
271                     }\r
272                 }\r
273             }\r
274         }\r
275         return enumConstants;\r
276     }\r
277 \r
278     private static EnumTypeDefinition.EnumPair createEnumPair(\r
279             Enum_stmtContext ctx, final int value, List<String> path,\r
280             final URI namespace, final Date revision, final String prefix) {\r
281         final String name = stringFromNode(ctx);\r
282         final QName qname = new QName(namespace, revision, prefix, name);\r
283         String description = null;\r
284         String reference = null;\r
285         Status status = null;\r
286         List<String> enumPairPath = new ArrayList<String>(path);\r
287         enumPairPath.add(name);\r
288 \r
289         for (int i = 0; i < ctx.getChildCount(); i++) {\r
290             ParseTree child = ctx.getChild(i);\r
291             if (child instanceof Description_stmtContext) {\r
292                 description = stringFromNode(child);\r
293             } else if (child instanceof Reference_stmtContext) {\r
294                 reference = stringFromNode(child);\r
295             } else if (child instanceof Status_stmtContext) {\r
296                 status = parseStatus((Status_stmtContext) child);\r
297             }\r
298         }\r
299 \r
300         EnumPairImpl result = new EnumPairImpl();\r
301         result.qname = qname;\r
302         result.path = createActualSchemaPath(enumPairPath, namespace, revision,\r
303                 prefix);\r
304         result.description = description;\r
305         result.reference = reference;\r
306         result.status = status;\r
307         // TODO: extensionSchemaNodes\r
308         result.name = name;\r
309         result.value = value;\r
310         return result;\r
311     }\r
312 \r
313     private static class EnumPairImpl implements EnumTypeDefinition.EnumPair {\r
314 \r
315         private QName qname;\r
316         private SchemaPath path;\r
317         private String description;\r
318         private String reference;\r
319         private Status status;\r
320         private List<UnknownSchemaNode> extensionSchemaNodes = Collections\r
321                 .emptyList();\r
322         private String name;\r
323         private Integer value;\r
324 \r
325         @Override\r
326         public QName getQName() {\r
327             return qname;\r
328         }\r
329 \r
330         @Override\r
331         public SchemaPath getPath() {\r
332             return path;\r
333         }\r
334 \r
335         @Override\r
336         public String getDescription() {\r
337             return description;\r
338         }\r
339 \r
340         @Override\r
341         public String getReference() {\r
342             return reference;\r
343         }\r
344 \r
345         @Override\r
346         public Status getStatus() {\r
347             return status;\r
348         }\r
349 \r
350         @Override\r
351         public List<UnknownSchemaNode> getUnknownSchemaNodes() {\r
352             return extensionSchemaNodes;\r
353         }\r
354 \r
355         @Override\r
356         public String getName() {\r
357             return name;\r
358         }\r
359 \r
360         @Override\r
361         public Integer getValue() {\r
362             return value;\r
363         }\r
364 \r
365         @Override\r
366         public int hashCode() {\r
367             final int prime = 31;\r
368             int result = 1;\r
369             result = prime * result + ((qname == null) ? 0 : qname.hashCode());\r
370             result = prime * result + ((path == null) ? 0 : path.hashCode());\r
371             result = prime * result\r
372                     + ((description == null) ? 0 : description.hashCode());\r
373             result = prime * result\r
374                     + ((reference == null) ? 0 : reference.hashCode());\r
375             result = prime * result\r
376                     + ((status == null) ? 0 : status.hashCode());\r
377             result = prime\r
378                     * result\r
379                     + ((extensionSchemaNodes == null) ? 0\r
380                             : extensionSchemaNodes.hashCode());\r
381             result = prime * result + ((name == null) ? 0 : name.hashCode());\r
382             result = prime * result + ((value == null) ? 0 : value.hashCode());\r
383             return result;\r
384         }\r
385 \r
386         @Override\r
387         public boolean equals(Object obj) {\r
388             if (this == obj) {\r
389                 return true;\r
390             }\r
391             if (obj == null) {\r
392                 return false;\r
393             }\r
394             if (getClass() != obj.getClass()) {\r
395                 return false;\r
396             }\r
397             EnumPairImpl other = (EnumPairImpl) obj;\r
398             if (qname == null) {\r
399                 if (other.qname != null) {\r
400                     return false;\r
401                 }\r
402             } else if (!qname.equals(other.qname)) {\r
403                 return false;\r
404             }\r
405             if (path == null) {\r
406                 if (other.path != null) {\r
407                     return false;\r
408                 }\r
409             } else if (!path.equals(other.path)) {\r
410                 return false;\r
411             }\r
412             if (description == null) {\r
413                 if (other.description != null) {\r
414                     return false;\r
415                 }\r
416             } else if (!description.equals(other.description)) {\r
417                 return false;\r
418             }\r
419             if (reference == null) {\r
420                 if (other.reference != null) {\r
421                     return false;\r
422                 }\r
423             } else if (!reference.equals(other.reference)) {\r
424                 return false;\r
425             }\r
426             if (status == null) {\r
427                 if (other.status != null) {\r
428                     return false;\r
429                 }\r
430             } else if (!status.equals(other.status)) {\r
431                 return false;\r
432             }\r
433             if (extensionSchemaNodes == null) {\r
434                 if (other.extensionSchemaNodes != null) {\r
435                     return false;\r
436                 }\r
437             } else if (!extensionSchemaNodes.equals(other.extensionSchemaNodes)) {\r
438                 return false;\r
439             }\r
440             if (name == null) {\r
441                 if (other.name != null) {\r
442                     return false;\r
443                 }\r
444             } else if (!name.equals(other.name)) {\r
445                 return false;\r
446             }\r
447             if (value == null) {\r
448                 if (other.value != null) {\r
449                     return false;\r
450                 }\r
451             } else if (!value.equals(other.value)) {\r
452                 return false;\r
453             }\r
454             return true;\r
455         }\r
456 \r
457         @Override\r
458         public String toString() {\r
459             return EnumTypeDefinition.EnumPair.class.getSimpleName() + "[name="\r
460                     + name + ", value=" + value + "]";\r
461         }\r
462     };\r
463 \r
464     private static List<RangeConstraint> getRangeConstraints(\r
465             Type_body_stmtsContext ctx) {\r
466         final List<RangeConstraint> rangeConstraints = new ArrayList<RangeConstraint>();\r
467         for (int j = 0; j < ctx.getChildCount(); j++) {\r
468             ParseTree numRestrChild = ctx.getChild(j);\r
469             if (numRestrChild instanceof Numerical_restrictionsContext) {\r
470                 for (int k = 0; k < numRestrChild.getChildCount(); k++) {\r
471                     ParseTree rangeChild = numRestrChild.getChild(k);\r
472                     if (rangeChild instanceof Range_stmtContext) {\r
473                         rangeConstraints\r
474                                 .addAll(parseRangeConstraints((Range_stmtContext) rangeChild));\r
475                         break;\r
476                     }\r
477                 }\r
478             }\r
479         }\r
480         return rangeConstraints;\r
481     }\r
482 \r
483     private static List<RangeConstraint> parseRangeConstraints(\r
484             Range_stmtContext ctx) {\r
485         List<RangeConstraint> rangeConstraints = new ArrayList<RangeConstraint>();\r
486         String description = null;\r
487         String reference = null;\r
488 \r
489         for (int i = 0; i < ctx.getChildCount(); i++) {\r
490             ParseTree child = ctx.getChild(i);\r
491             if (child instanceof Description_stmtContext) {\r
492                 description = stringFromNode(child);\r
493             } else if (child instanceof Reference_stmtContext) {\r
494                 reference = stringFromNode(child);\r
495             }\r
496         }\r
497 \r
498         String rangeStr = stringFromNode(ctx);\r
499         String trimmed = rangeStr.replace(" ", "");\r
500         String[] splittedRange = trimmed.split("\\|");\r
501         for (String rangeDef : splittedRange) {\r
502             String[] splittedRangeDef = rangeDef.split("\\.\\.");\r
503             Long min;\r
504             Long max;\r
505             if (splittedRangeDef.length == 1) {\r
506                 min = max = parseRangeValue(splittedRangeDef[0]);\r
507             } else {\r
508                 min = parseRangeValue(splittedRangeDef[0]);\r
509                 max = parseRangeValue(splittedRangeDef[1]);\r
510             }\r
511             RangeConstraint range = BaseConstraints.rangeConstraint(min, max,\r
512                     description, reference);\r
513             rangeConstraints.add(range);\r
514         }\r
515 \r
516         return rangeConstraints;\r
517     }\r
518 \r
519     private static List<LengthConstraint> getLengthConstraints(\r
520             Type_body_stmtsContext ctx) {\r
521         List<LengthConstraint> lengthConstraints = new ArrayList<LengthConstraint>();\r
522         for (int j = 0; j < ctx.getChildCount(); j++) {\r
523             ParseTree stringRestrChild = ctx.getChild(j);\r
524             if (stringRestrChild instanceof String_restrictionsContext) {\r
525                 for (int k = 0; k < stringRestrChild.getChildCount(); k++) {\r
526                     ParseTree lengthChild = stringRestrChild.getChild(k);\r
527                     if (lengthChild instanceof Length_stmtContext) {\r
528                         lengthConstraints\r
529                                 .addAll(parseLengthConstraints((Length_stmtContext) lengthChild));\r
530                     }\r
531                 }\r
532             }\r
533         }\r
534         return lengthConstraints;\r
535     }\r
536 \r
537     private static List<LengthConstraint> parseLengthConstraints(\r
538             Length_stmtContext ctx) {\r
539         List<LengthConstraint> lengthConstraints = new ArrayList<LengthConstraint>();\r
540         String description = null;\r
541         String reference = null;\r
542 \r
543         for (int i = 0; i < ctx.getChildCount(); i++) {\r
544             ParseTree child = ctx.getChild(i);\r
545             if (child instanceof Description_stmtContext) {\r
546                 description = stringFromNode(child);\r
547             } else if (child instanceof Reference_stmtContext) {\r
548                 reference = stringFromNode(child);\r
549             }\r
550         }\r
551 \r
552         String lengthStr = stringFromNode(ctx);\r
553         String trimmed = lengthStr.replace(" ", "");\r
554         String[] splittedRange = trimmed.split("\\|");\r
555         for (String rangeDef : splittedRange) {\r
556             String[] splittedRangeDef = rangeDef.split("\\.\\.");\r
557             Long min;\r
558             Long max;\r
559             if (splittedRangeDef.length == 1) {\r
560                 min = max = parseRangeValue(splittedRangeDef[0]);\r
561             } else {\r
562                 min = parseRangeValue(splittedRangeDef[0]);\r
563                 max = parseRangeValue(splittedRangeDef[1]);\r
564             }\r
565             LengthConstraint range = BaseConstraints.lengthConstraint(min, max,\r
566                     description, reference);\r
567             lengthConstraints.add(range);\r
568         }\r
569 \r
570         return lengthConstraints;\r
571     }\r
572 \r
573     private static Long parseRangeValue(String value) {\r
574         Long result = null;\r
575         if (value.equals("min")) {\r
576             result = Long.MIN_VALUE;\r
577         } else if (value.equals("max")) {\r
578             result = Long.MAX_VALUE;\r
579         } else {\r
580             result = Long.valueOf(value);\r
581         }\r
582         return result;\r
583     }\r
584 \r
585     private static List<PatternConstraint> getPatternConstraint(\r
586             Type_body_stmtsContext ctx) {\r
587         List<PatternConstraint> patterns = new ArrayList<PatternConstraint>();\r
588 \r
589         out: for (int j = 0; j < ctx.getChildCount(); j++) {\r
590             ParseTree stringRestrChild = ctx.getChild(j);\r
591             if (stringRestrChild instanceof String_restrictionsContext) {\r
592                 for (int k = 0; k < stringRestrChild.getChildCount(); k++) {\r
593                     ParseTree lengthChild = stringRestrChild.getChild(k);\r
594                     if (lengthChild instanceof Pattern_stmtContext) {\r
595                         patterns.add(parsePatternConstraint((Pattern_stmtContext) lengthChild));\r
596                         if (k == lengthChild.getChildCount() - 1) {\r
597                             break out;\r
598                         }\r
599                     }\r
600                 }\r
601             }\r
602         }\r
603         return patterns;\r
604     }\r
605 \r
606     /**\r
607      * Internal helper method.\r
608      *\r
609      * @param ctx\r
610      *            pattern context\r
611      * @return PatternConstraint object\r
612      */\r
613     private static PatternConstraint parsePatternConstraint(\r
614             Pattern_stmtContext ctx) {\r
615         String description = null;\r
616         String reference = null;\r
617         for (int i = 0; i < ctx.getChildCount(); i++) {\r
618             ParseTree child = ctx.getChild(i);\r
619             if (child instanceof Description_stmtContext) {\r
620                 description = stringFromNode(child);\r
621             } else if (child instanceof Reference_stmtContext) {\r
622                 reference = stringFromNode(child);\r
623             }\r
624         }\r
625         String pattern = patternStringFromNode(ctx);\r
626         return BaseConstraints.patternConstraint(pattern, description,\r
627                 reference);\r
628     }\r
629 \r
630     public static String patternStringFromNode(final Pattern_stmtContext treeNode) {\r
631         String result = "";\r
632         for (int i = 0; i < treeNode.getChildCount(); ++i) {\r
633             ParseTree child = treeNode.getChild(i);\r
634             if (child instanceof StringContext) {\r
635                 for(int j = 0; j < child.getChildCount(); j++) {\r
636                     if(j % 2 == 0) {\r
637                         String patternToken = child.getChild(j).getText();\r
638                         result += patternToken.substring(1, patternToken.length()-1);\r
639                     }\r
640                 }\r
641             }\r
642         }\r
643         return result;\r
644     }\r
645 \r
646     private static Integer getFractionDigits(Type_body_stmtsContext ctx) {\r
647         for (int j = 0; j < ctx.getChildCount(); j++) {\r
648             ParseTree dec64specChild = ctx.getChild(j);\r
649             if (dec64specChild instanceof Decimal64_specificationContext) {\r
650                 return parseFractionDigits((Decimal64_specificationContext) dec64specChild);\r
651             }\r
652         }\r
653         return null;\r
654     }\r
655 \r
656     private static Integer parseFractionDigits(\r
657             Decimal64_specificationContext ctx) {\r
658         for (int k = 0; k < ctx.getChildCount(); k++) {\r
659             ParseTree fdChild = ctx.getChild(k);\r
660             if (fdChild instanceof Fraction_digits_stmtContext) {\r
661                 return Integer.valueOf(stringFromNode(fdChild));\r
662             }\r
663         }\r
664         return null;\r
665     }\r
666 \r
667     private static List<BitsTypeDefinition.Bit> getBits(\r
668             Type_body_stmtsContext ctx, List<String> actualPath, URI namespace,\r
669             Date revision, String prefix) {\r
670         List<BitsTypeDefinition.Bit> bits = new ArrayList<BitsTypeDefinition.Bit>();\r
671         for (int j = 0; j < ctx.getChildCount(); j++) {\r
672             ParseTree bitsSpecChild = ctx.getChild(j);\r
673             if (bitsSpecChild instanceof Bits_specificationContext) {\r
674                 for (int k = 0; k < bitsSpecChild.getChildCount(); k++) {\r
675                     ParseTree bitChild = bitsSpecChild.getChild(k);\r
676                     if (bitChild instanceof Bit_stmtContext) {\r
677                         bits.add(parseBit((Bit_stmtContext) bitChild,\r
678                                 actualPath, namespace, revision, prefix));\r
679                     }\r
680                 }\r
681             }\r
682         }\r
683         return bits;\r
684     }\r
685 \r
686     private static boolean isRequireInstance(Type_body_stmtsContext ctx) {\r
687         for (int i = 0; i < ctx.getChildCount(); i++) {\r
688             ParseTree child = ctx.getChild(i);\r
689             if (child instanceof Require_instance_stmtContext) {\r
690                 for (int j = 0; j < child.getChildCount(); j++) {\r
691                     ParseTree reqArg = child.getChild(j);\r
692                     if (reqArg instanceof Require_instance_argContext) {\r
693                         return Boolean.valueOf(stringFromNode(reqArg));\r
694                     }\r
695                 }\r
696             }\r
697         }\r
698         return false;\r
699     }\r
700 \r
701     private static BitsTypeDefinition.Bit parseBit(final Bit_stmtContext ctx,\r
702             List<String> actualPath, final URI namespace, final Date revision,\r
703             final String prefix) {\r
704         String name = stringFromNode(ctx);\r
705         final QName qname = new QName(namespace, revision, prefix, name);\r
706         Long position = null;\r
707 \r
708         String description = null;\r
709         String reference = null;\r
710         Status status = Status.CURRENT;\r
711 \r
712         Stack<String> bitPath = new Stack<String>();\r
713         bitPath.addAll(actualPath);\r
714         bitPath.add(name);\r
715 \r
716         SchemaPath schemaPath = createActualSchemaPath(bitPath, namespace,\r
717                 revision, prefix);\r
718 \r
719         for (int i = 0; i < ctx.getChildCount(); i++) {\r
720             ParseTree child = ctx.getChild(i);\r
721             if (child instanceof Position_stmtContext) {\r
722                 String positionStr = stringFromNode(child);\r
723                 position = Long.valueOf(positionStr);\r
724                 if (position < 0 || position > 4294967295L) {\r
725                     throw new IllegalArgumentException(\r
726                             "position value MUST be in the range 0 to 4294967295, but was: "\r
727                                     + position);\r
728                 }\r
729             } else if (child instanceof Description_stmtContext) {\r
730                 description = stringFromNode(child);\r
731             } else if (child instanceof Reference_stmtContext) {\r
732                 reference = stringFromNode(child);\r
733             } else if (child instanceof Status_stmtContext) {\r
734                 status = parseStatus((Status_stmtContext) child);\r
735             }\r
736         }\r
737 \r
738         // TODO: extensionDefinitions\r
739         return createBit(qname, schemaPath, description, reference, status,\r
740                 null, position);\r
741     }\r
742 \r
743     private static BitsTypeDefinition.Bit createBit(final QName qname,\r
744             final SchemaPath schemaPath, final String description,\r
745             final String reference, final Status status,\r
746             final List<UnknownSchemaNode> extensionDefinitions,\r
747             final Long position) {\r
748         return new BitsTypeDefinition.Bit() {\r
749 \r
750             @Override\r
751             public QName getQName() {\r
752                 return qname;\r
753             }\r
754 \r
755             @Override\r
756             public SchemaPath getPath() {\r
757                 return schemaPath;\r
758             }\r
759 \r
760             @Override\r
761             public String getDescription() {\r
762                 return description;\r
763             }\r
764 \r
765             @Override\r
766             public String getReference() {\r
767                 return reference;\r
768             }\r
769 \r
770             @Override\r
771             public Status getStatus() {\r
772                 return status;\r
773             }\r
774 \r
775             @Override\r
776             public List<UnknownSchemaNode> getUnknownSchemaNodes() {\r
777                 return extensionDefinitions;\r
778             }\r
779 \r
780             @Override\r
781             public Long getPosition() {\r
782                 return position;\r
783             }\r
784 \r
785             @Override\r
786             public String getName() {\r
787                 return qname.getLocalName();\r
788             }\r
789 \r
790             @Override\r
791             public int hashCode() {\r
792                 final int prime = 31;\r
793                 int result = 1;\r
794                 result = prime * result\r
795                         + ((qname == null) ? 0 : qname.hashCode());\r
796                 result = prime * result\r
797                         + ((schemaPath == null) ? 0 : schemaPath.hashCode());\r
798                 result = prime * result\r
799                         + ((description == null) ? 0 : description.hashCode());\r
800                 result = prime * result\r
801                         + ((reference == null) ? 0 : reference.hashCode());\r
802                 result = prime * result\r
803                         + ((status == null) ? 0 : status.hashCode());\r
804                 result = prime * result\r
805                         + ((position == null) ? 0 : position.hashCode());\r
806                 result = prime\r
807                         * result\r
808                         + ((extensionDefinitions == null) ? 0\r
809                                 : extensionDefinitions.hashCode());\r
810                 return result;\r
811             }\r
812 \r
813             @Override\r
814             public boolean equals(Object obj) {\r
815                 if (this == obj) {\r
816                     return true;\r
817                 }\r
818                 if (obj == null) {\r
819                     return false;\r
820                 }\r
821                 if (getClass() != obj.getClass()) {\r
822                     return false;\r
823                 }\r
824                 Bit other = (Bit) obj;\r
825                 if (qname == null) {\r
826                     if (other.getQName() != null) {\r
827                         return false;\r
828                     }\r
829                 } else if (!qname.equals(other.getQName())) {\r
830                     return false;\r
831                 }\r
832                 if (schemaPath == null) {\r
833                     if (other.getPath() != null) {\r
834                         return false;\r
835                     }\r
836                 } else if (!schemaPath.equals(other.getPath())) {\r
837                     return false;\r
838                 }\r
839                 if (description == null) {\r
840                     if (other.getDescription() != null) {\r
841                         return false;\r
842                     }\r
843                 } else if (!description.equals(other.getDescription())) {\r
844                     return false;\r
845                 }\r
846                 if (reference == null) {\r
847                     if (other.getReference() != null) {\r
848                         return false;\r
849                     }\r
850                 } else if (!reference.equals(other.getReference())) {\r
851                     return false;\r
852                 }\r
853                 if (status == null) {\r
854                     if (other.getStatus() != null) {\r
855                         return false;\r
856                     }\r
857                 } else if (!status.equals(other.getStatus())) {\r
858                     return false;\r
859                 }\r
860                 if (extensionDefinitions == null) {\r
861                     if (other.getUnknownSchemaNodes() != null) {\r
862                         return false;\r
863                     }\r
864                 } else if (!extensionDefinitions.equals(other\r
865                         .getUnknownSchemaNodes())) {\r
866                     return false;\r
867                 }\r
868                 if (position == null) {\r
869                     if (other.getPosition() != null) {\r
870                         return false;\r
871                     }\r
872                 } else if (!position.equals(other.getPosition())) {\r
873                     return false;\r
874                 }\r
875                 return true;\r
876             }\r
877 \r
878             @Override\r
879             public String toString() {\r
880                 return Bit.class.getSimpleName() + "[name="\r
881                         + qname.getLocalName() + ", position=" + position + "]";\r
882             }\r
883         };\r
884     }\r
885 \r
886     /**\r
887      * Parse orderedby statement.\r
888      *\r
889      * @param childNode\r
890      *            Ordered_by_stmtContext\r
891      * @return true, if orderedby contains value 'user' or false otherwise\r
892      */\r
893     public static boolean parseUserOrdered(Ordered_by_stmtContext childNode) {\r
894         boolean result = false;\r
895         for (int j = 0; j < childNode.getChildCount(); j++) {\r
896             ParseTree orderArg = childNode.getChild(j);\r
897             if (orderArg instanceof Ordered_by_argContext) {\r
898                 String orderStr = stringFromNode(orderArg);\r
899                 if (orderStr.equals("system")) {\r
900                     result = false;\r
901                 } else if (orderStr.equals("user")) {\r
902                     result = true;\r
903                 } else {\r
904                     logger.warn("Invalid 'orderedby' statement.");\r
905                 }\r
906             }\r
907         }\r
908         return result;\r
909     }\r
910 \r
911     /**\r
912      * Parse given config context and return true if it contains string 'true',\r
913      * false otherwise.\r
914      *\r
915      * @param ctx\r
916      *            config context to parse.\r
917      * @return true if given context contains string 'true', false otherwise\r
918      */\r
919     public static boolean parseConfig(final Config_stmtContext ctx) {\r
920         if (ctx != null) {\r
921             for (int i = 0; i < ctx.getChildCount(); ++i) {\r
922                 final ParseTree configContext = ctx.getChild(i);\r
923                 if (configContext instanceof Config_argContext) {\r
924                     final String value = stringFromNode(configContext);\r
925                     if (value.equals("true")) {\r
926                         return true;\r
927                     }\r
928                 }\r
929             }\r
930         }\r
931         return false;\r
932     }\r
933 \r
934     /**\r
935      * Parse given type body and creates UnknownType definition.\r
936      *\r
937      * @param typedefQName\r
938      *            qname of current type\r
939      * @param ctx\r
940      *            type body\r
941      * @return UnknownType object with constraints from parsed type body\r
942      */\r
943     public static TypeDefinition<?> parseUnknownTypeBody(QName typedefQName,\r
944             Type_body_stmtsContext ctx) {\r
945         UnknownType.Builder ut = new UnknownType.Builder(typedefQName);\r
946 \r
947         if (ctx != null) {\r
948             List<RangeConstraint> rangeStatements = getRangeConstraints(ctx);\r
949             List<LengthConstraint> lengthStatements = getLengthConstraints(ctx);\r
950             List<PatternConstraint> patternStatements = getPatternConstraint(ctx);\r
951             Integer fractionDigits = getFractionDigits(ctx);\r
952 \r
953             ut.rangeStatements(rangeStatements);\r
954             ut.lengthStatements(lengthStatements);\r
955             ut.patterns(patternStatements);\r
956             ut.fractionDigits(fractionDigits);\r
957         }\r
958 \r
959         return ut.build();\r
960     }\r
961 \r
962     /**\r
963      * Create TypeDefinition object based on given type name and type body.\r
964      *\r
965      * @param typeName\r
966      *            name of type\r
967      * @param typeBody\r
968      *            type body\r
969      * @param actualPath\r
970      *            current path in schema\r
971      * @param namespace\r
972      *            current namespace\r
973      * @param revision\r
974      *            current revision\r
975      * @param prefix\r
976      *            current prefix\r
977      * @return TypeDefinition object based on parsed values.\r
978      */\r
979     public static TypeDefinition<?> parseTypeBody(String typeName,\r
980             Type_body_stmtsContext typeBody, List<String> actualPath,\r
981             URI namespace, Date revision, String prefix) {\r
982         TypeDefinition<?> type = null;\r
983 \r
984         List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody);\r
985         Integer fractionDigits = getFractionDigits(typeBody);\r
986         List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody);\r
987         List<PatternConstraint> patternStatements = getPatternConstraint(typeBody);\r
988         List<EnumTypeDefinition.EnumPair> enumConstants = getEnumConstants(typeBody, actualPath, namespace, revision, prefix);\r
989 \r
990         if (typeName.equals("decimal64")) {\r
991             type = YangTypesConverter.javaTypeForBaseYangDecimal64Type(\r
992                     rangeStatements, fractionDigits);\r
993         } else if (typeName.startsWith("int")) {\r
994             type = YangTypesConverter.javaTypeForBaseYangSignedIntegerType(typeName,\r
995                     rangeStatements);\r
996         } else if(typeName.startsWith("uint")) {\r
997             type = YangTypesConverter.javaTypeForBaseYangUnsignedIntegerType(typeName,\r
998                     rangeStatements);\r
999         } else if (typeName.equals("enumeration")) {\r
1000             type = new EnumerationType(enumConstants);\r
1001         } else if (typeName.equals("string")) {\r
1002             type = new StringType(lengthStatements, patternStatements);\r
1003         } else if (typeName.equals("bits")) {\r
1004             type = new BitsType(getBits(typeBody, actualPath, namespace,\r
1005                     revision, prefix));\r
1006         } else if (typeName.equals("leafref")) {\r
1007             final String path = parseLeafrefPath(typeBody);\r
1008             final boolean absolute = path.startsWith("/");\r
1009             RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path,\r
1010                     absolute);\r
1011             type = new Leafref(actualPath, namespace, revision, xpath);\r
1012         } else if (typeName.equals("binary")) {\r
1013             type = new BinaryType(null, lengthStatements, null);\r
1014         } else if (typeName.equals("instance-identifier")) {\r
1015             boolean requireInstance = isRequireInstance(typeBody);\r
1016             type = new InstanceIdentifier(null, requireInstance);\r
1017         }\r
1018         return type;\r
1019     }\r
1020 \r
1021     private static String parseLeafrefPath(Type_body_stmtsContext ctx) {\r
1022         for (int i = 0; i < ctx.getChildCount(); i++) {\r
1023             ParseTree child = ctx.getChild(i);\r
1024             if (child instanceof Leafref_specificationContext) {\r
1025                 for (int j = 0; j < child.getChildCount(); j++) {\r
1026                     ParseTree leafRefSpec = child.getChild(j);\r
1027                     if (leafRefSpec instanceof Path_stmtContext) {\r
1028                         return stringFromNode(leafRefSpec);\r
1029                     }\r
1030                 }\r
1031             }\r
1032         }\r
1033         return null;\r
1034     }\r
1035 \r
1036     /**\r
1037      * Internal helper method for parsing Must_stmtContext.\r
1038      *\r
1039      * @param ctx\r
1040      *            Must_stmtContext\r
1041      * @return an array of strings with following fields: [0] must text [1]\r
1042      *         description [2] reference\r
1043      */\r
1044     public static String[] parseMust(YangParser.Must_stmtContext ctx) {\r
1045         String[] params = new String[3];\r
1046 \r
1047         String mustText = "";\r
1048         String description = null;\r
1049         String reference = null;\r
1050         for (int i = 0; i < ctx.getChildCount(); ++i) {\r
1051             ParseTree child = ctx.getChild(i);\r
1052             if (child instanceof StringContext) {\r
1053                 final StringContext context = (StringContext) child;\r
1054                 for (int j = 0; j < context.getChildCount(); j++) {\r
1055                     String mustPart = context.getChild(j).getText();\r
1056                     if (j == 0) {\r
1057                         mustText += mustPart\r
1058                                 .substring(0, mustPart.length() - 1);\r
1059                         continue;\r
1060                     }\r
1061                     if (j % 2 == 0) {\r
1062                         mustText += mustPart.substring(1);\r
1063                     }\r
1064                 }\r
1065             } else if (child instanceof Description_stmtContext) {\r
1066                 description = stringFromNode(child);\r
1067             } else if (child instanceof Reference_stmtContext) {\r
1068                 reference = stringFromNode(child);\r
1069             }\r
1070         }\r
1071         params[0] = mustText;\r
1072         params[1] = description;\r
1073         params[2] = reference;\r
1074 \r
1075         return params;\r
1076     }\r
1077 \r
1078     /**\r
1079      * Parse given tree and set constraints to given builder.\r
1080      *\r
1081      * @param ctx\r
1082      *            Context to search.\r
1083      * @param constraintsBuilder\r
1084      *            ConstraintsBuilder to fill.\r
1085      */\r
1086     public static void parseConstraints(ParseTree ctx,\r
1087             ConstraintsBuilder constraintsBuilder) {\r
1088         for (int i = 0; i < ctx.getChildCount(); ++i) {\r
1089             final ParseTree childNode = ctx.getChild(i);\r
1090             if (childNode instanceof Max_elements_stmtContext) {\r
1091                 Integer max = Integer.valueOf(stringFromNode(childNode));\r
1092                 constraintsBuilder.setMinElements(max);\r
1093             } else if (childNode instanceof Min_elements_stmtContext) {\r
1094                 Integer min = Integer.valueOf(stringFromNode(childNode));\r
1095                 constraintsBuilder.setMinElements(min);\r
1096             } else if (childNode instanceof Must_stmtContext) {\r
1097                 String[] mustParams = parseMust((Must_stmtContext) childNode);\r
1098                 constraintsBuilder.addMustDefinition(mustParams[0],\r
1099                         mustParams[1], mustParams[2]);\r
1100             } else if (childNode instanceof Mandatory_stmtContext) {\r
1101                 for (int j = 0; j < childNode.getChildCount(); j++) {\r
1102                     ParseTree mandatoryTree = ctx.getChild(j);\r
1103                     if (mandatoryTree instanceof Mandatory_argContext) {\r
1104                         Boolean mandatory = Boolean\r
1105                                 .valueOf(stringFromNode(mandatoryTree));\r
1106                         constraintsBuilder.setMandatory(mandatory);\r
1107                     }\r
1108                 }\r
1109             } else if (childNode instanceof When_stmtContext) {\r
1110                 constraintsBuilder.addWhenCondition(stringFromNode(childNode));\r
1111             }\r
1112         }\r
1113     }\r
1114 \r
1115 }\r