2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
\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
8 package org.opendaylight.controller.model.parser.util;
\r
10 import java.net.URI;
\r
11 import java.util.ArrayList;
\r
12 import java.util.Date;
\r
13 import java.util.List;
\r
14 import java.util.Stack;
\r
16 import org.antlr.v4.runtime.tree.ParseTree;
\r
17 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Bit_stmtContext;
\r
18 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Bits_specificationContext;
\r
19 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Decimal64_specificationContext;
\r
20 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Description_stmtContext;
\r
21 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Enum_specificationContext;
\r
22 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Enum_stmtContext;
\r
23 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Fraction_digits_stmtContext;
\r
24 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Length_stmtContext;
\r
25 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Numerical_restrictionsContext;
\r
26 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Pattern_stmtContext;
\r
27 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Position_stmtContext;
\r
28 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Range_stmtContext;
\r
29 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Reference_stmtContext;
\r
30 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_argContext;
\r
31 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_stmtContext;
\r
32 import org.opendaylight.controller.antlrv4.code.gen.YangParser.StringContext;
\r
33 import org.opendaylight.controller.antlrv4.code.gen.YangParser.String_restrictionsContext;
\r
34 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_body_stmtsContext;
\r
35 import org.opendaylight.controller.model.api.type.BitsTypeDefinition;
\r
36 import org.opendaylight.controller.model.api.type.EnumTypeDefinition;
\r
37 import org.opendaylight.controller.model.api.type.LengthConstraint;
\r
38 import org.opendaylight.controller.model.api.type.PatternConstraint;
\r
39 import org.opendaylight.controller.model.api.type.RangeConstraint;
\r
40 import org.opendaylight.controller.model.api.type.BitsTypeDefinition.Bit;
\r
41 import org.opendaylight.controller.model.parser.api.SchemaNodeBuilder;
\r
42 import org.opendaylight.controller.model.util.BaseConstraints;
\r
43 import org.opendaylight.controller.model.util.UnknownType;
\r
44 import org.opendaylight.controller.yang.common.QName;
\r
45 import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
\r
46 import org.opendaylight.controller.yang.model.api.SchemaPath;
\r
47 import org.opendaylight.controller.yang.model.api.Status;
\r
48 import org.opendaylight.controller.yang.model.api.TypeDefinition;
\r
49 import org.slf4j.Logger;
\r
50 import org.slf4j.LoggerFactory;
\r
52 public class YangModelBuilderHelper {
\r
54 private static final Logger logger = LoggerFactory
\r
55 .getLogger(YangModelBuilderHelper.class);
\r
58 * Get 'description', 'reference' and 'status' statements and fill in
\r
64 * builder to fill in with parsed statements
\r
66 public static void parseSchemaNodeArgs(ParseTree ctx,
\r
67 SchemaNodeBuilder builder) {
\r
68 for (int i = 0; i < ctx.getChildCount(); i++) {
\r
69 ParseTree child = ctx.getChild(i);
\r
70 if (child instanceof Description_stmtContext) {
\r
71 String desc = stringFromNode(child);
\r
72 builder.setDescription(desc);
\r
73 } else if (child instanceof Reference_stmtContext) {
\r
74 String ref = stringFromNode(child);
\r
75 builder.setReference(ref);
\r
76 } else if (child instanceof Status_stmtContext) {
\r
77 Status status = getStatus((Status_stmtContext) child);
\r
78 builder.setStatus(status);
\r
83 public static SchemaPath getActualSchemaPath(Stack<String> actualPath,
\r
84 URI namespace, Date revision, String prefix) {
\r
85 final List<QName> path = new ArrayList<QName>();
\r
87 for (String pathElement : actualPath) {
\r
88 qname = new QName(namespace, revision, prefix, pathElement);
\r
91 return new SchemaPath(path, true);
\r
94 public static Status getStatus(Status_stmtContext ctx) {
\r
95 for (int i = 0; i < ctx.getChildCount(); i++) {
\r
96 ParseTree statusArg = ctx.getChild(i);
\r
97 if (statusArg instanceof Status_argContext) {
\r
98 String statusArgStr = stringFromNode(statusArg);
\r
99 if (statusArgStr.equals("current")) {
\r
100 return Status.CURRENT;
\r
101 } else if (statusArgStr.equals("deprecated")) {
\r
102 return Status.DEPRECATED;
\r
103 } else if (statusArgStr.equals("obsolete")) {
\r
104 return Status.OBSOLOTE;
\r
106 logger.warn("Invalid 'status' statement: " + statusArgStr);
\r
113 public static String stringFromNode(final ParseTree treeNode) {
\r
114 final String result = "";
\r
115 for (int j = 0; j < treeNode.getChildCount(); ++j) {
\r
116 if (treeNode.getChild(j) instanceof StringContext) {
\r
117 final StringContext context = (StringContext) treeNode
\r
120 if (context != null) {
\r
121 return context.getChild(0).getText().replace("\"", "");
\r
128 public static SchemaPath parsePath(String augmentPath) {
\r
129 boolean absolute = augmentPath.startsWith("/");
\r
130 String[] splittedPath = augmentPath.split("/");
\r
131 List<QName> path = new ArrayList<QName>();
\r
133 for (String pathElement : splittedPath) {
\r
134 if (pathElement.length() > 0) {
\r
135 String[] splittedElement = pathElement.split(":");
\r
136 if (splittedElement.length == 1) {
\r
137 name = new QName(null, null, null, splittedElement[0]);
\r
139 name = new QName(null, null, splittedElement[0],
\r
140 splittedElement[1]);
\r
145 return new SchemaPath(path, absolute);
\r
148 public static List<QName> createListKey(String keyDefinition,
\r
149 URI namespace, Date revision, String prefix) {
\r
150 List<QName> key = new ArrayList<QName>();
\r
151 String[] splittedKey = keyDefinition.split(" ");
\r
153 QName qname = null;
\r
154 for (String keyElement : splittedKey) {
\r
155 if (keyElement.length() != 0) {
\r
156 qname = new QName(namespace, revision, prefix, keyElement);
\r
163 public static TypeDefinition<?> parseUnknownType(QName typedefQName,
\r
165 UnknownType.Builder ut = new UnknownType.Builder(typedefQName);
\r
166 for (int i = 0; i < ctx.getChildCount(); i++) {
\r
167 ParseTree child = ctx.getChild(i);
\r
168 if (child instanceof Type_body_stmtsContext) {
\r
169 for (int j = 0; j < child.getChildCount(); j++) {
\r
170 ParseTree typeBodyChild = child.getChild(j);
\r
171 // NUMERICAL RESTRICTIONS
\r
172 if (typeBodyChild instanceof Numerical_restrictionsContext) {
\r
173 for (int k = 0; k < typeBodyChild.getChildCount(); k++) {
\r
174 ParseTree numRestrictionsChild = typeBodyChild
\r
176 if (numRestrictionsChild instanceof Range_stmtContext) {
\r
177 List<RangeConstraint> ranges = parseRangeConstraints((Range_stmtContext) numRestrictionsChild);
\r
178 ut.rangeStatements(ranges);
\r
181 // STRING RESTRICTIONS
\r
182 } else if (typeBodyChild instanceof String_restrictionsContext) {
\r
183 List<PatternConstraint> patterns = new ArrayList<PatternConstraint>();
\r
184 List<LengthConstraint> lengths = new ArrayList<LengthConstraint>();
\r
185 for (int k = 0; k < typeBodyChild.getChildCount(); k++) {
\r
186 ParseTree stringRestrictionsChild = typeBodyChild
\r
188 if (stringRestrictionsChild instanceof Pattern_stmtContext) {
\r
189 patterns.add(parsePatternConstraint((Pattern_stmtContext) stringRestrictionsChild));
\r
190 } else if (stringRestrictionsChild instanceof Length_stmtContext) {
\r
191 lengths = parseLengthConstraints((Length_stmtContext) stringRestrictionsChild);
\r
194 ut.patterns(patterns);
\r
195 ut.lengthStatements(lengths);
\r
197 } else if (typeBodyChild instanceof Decimal64_specificationContext) {
\r
198 for (int k = 0; k < typeBodyChild.getChildCount(); k++) {
\r
199 ParseTree fdChild = typeBodyChild.getChild(k);
\r
200 if (fdChild instanceof Fraction_digits_stmtContext) {
\r
201 // TODO: implement fraction digits
\r
203 // Integer.valueOf(stringFromNode(fdChild));
\r
214 public static List<RangeConstraint> getRangeConstraints(
\r
215 Type_body_stmtsContext ctx) {
\r
216 List<RangeConstraint> rangeConstraints = new ArrayList<RangeConstraint>();
\r
217 for (int j = 0; j < ctx.getChildCount(); j++) {
\r
218 ParseTree numRestrChild = ctx.getChild(j);
\r
219 if (numRestrChild instanceof Numerical_restrictionsContext) {
\r
220 for (int k = 0; k < numRestrChild.getChildCount(); k++) {
\r
221 ParseTree rangeChild = numRestrChild.getChild(k);
\r
222 if (rangeChild instanceof Range_stmtContext) {
\r
224 .addAll(parseRangeConstraints((Range_stmtContext) rangeChild));
\r
229 return rangeConstraints;
\r
232 private static List<RangeConstraint> parseRangeConstraints(
\r
233 Range_stmtContext ctx) {
\r
234 List<RangeConstraint> rangeConstraints = new ArrayList<RangeConstraint>();
\r
235 String description = null;
\r
236 String reference = null;
\r
238 for (int i = 0; i < ctx.getChildCount(); i++) {
\r
239 ParseTree child = ctx.getChild(i);
\r
240 if (child instanceof Description_stmtContext) {
\r
241 description = stringFromNode(child);
\r
242 } else if (child instanceof Reference_stmtContext) {
\r
243 reference = stringFromNode(child);
\r
247 String rangeStr = stringFromNode(ctx);
\r
248 String trimmed = rangeStr.replace(" ", "");
\r
249 String[] splittedRange = trimmed.split("\\|");
\r
250 for (String rangeDef : splittedRange) {
\r
251 // TODO: this needs to be refactored, because valid range can be
\r
252 // also defined as "1..max"
\r
253 String[] splittedRangeDef = rangeDef.split("\\.\\.");
\r
254 Long min = Long.valueOf(splittedRangeDef[0]);
\r
255 Long max = Long.valueOf(splittedRangeDef[1]);
\r
256 RangeConstraint range = BaseConstraints.rangeConstraint(min, max,
\r
257 description, reference);
\r
258 rangeConstraints.add(range);
\r
261 return rangeConstraints;
\r
264 public static Integer getFractionDigits(Type_body_stmtsContext ctx) {
\r
265 for (int j = 0; j < ctx.getChildCount(); j++) {
\r
266 ParseTree dec64specChild = ctx.getChild(j);
\r
267 if (dec64specChild instanceof Decimal64_specificationContext) {
\r
268 for (int k = 0; k < dec64specChild.getChildCount(); k++) {
\r
269 ParseTree fdChild = dec64specChild.getChild(k);
\r
270 if (fdChild instanceof Fraction_digits_stmtContext) {
\r
271 return Integer.valueOf(stringFromNode(fdChild));
\r
279 public static List<EnumTypeDefinition.EnumPair> getEnumConstants(
\r
280 Type_body_stmtsContext ctx) {
\r
281 List<EnumTypeDefinition.EnumPair> enumConstants = new ArrayList<EnumTypeDefinition.EnumPair>();
\r
283 out: for (int j = 0; j < ctx.getChildCount(); j++) {
\r
284 ParseTree enumSpecChild = ctx.getChild(j);
\r
285 if (enumSpecChild instanceof Enum_specificationContext) {
\r
286 for (int k = 0; k < enumSpecChild.getChildCount(); k++) {
\r
287 ParseTree enumChild = enumSpecChild.getChild(k);
\r
288 if (enumChild instanceof Enum_stmtContext) {
\r
289 enumConstants.add(createEnumPair(
\r
290 (Enum_stmtContext) enumChild, k));
\r
291 if (k == enumSpecChild.getChildCount() - 1) {
\r
298 return enumConstants;
\r
301 private static EnumTypeDefinition.EnumPair createEnumPair(
\r
302 Enum_stmtContext ctx, final int value) {
\r
303 final String name = stringFromNode(ctx);
\r
304 return new EnumTypeDefinition.EnumPair() {
\r
307 public QName getQName() {
\r
308 // TODO Auto-generated method stub
\r
313 public SchemaPath getPath() {
\r
314 // TODO Auto-generated method stub
\r
319 public String getDescription() {
\r
320 // TODO Auto-generated method stub
\r
325 public String getReference() {
\r
326 // TODO Auto-generated method stub
\r
331 public Status getStatus() {
\r
332 // TODO Auto-generated method stub
\r
337 public List<ExtensionDefinition> getExtensionSchemaNodes() {
\r
338 // TODO Auto-generated method stub
\r
343 public String getName() {
\r
348 public Integer getValue() {
\r
353 public String toString() {
\r
354 return EnumTypeDefinition.EnumPair.class.getSimpleName()
\r
355 + "[name=" + name + ", value=" + value + "]";
\r
360 public static List<LengthConstraint> getLengthConstraints(
\r
361 Type_body_stmtsContext ctx) {
\r
362 List<LengthConstraint> lengthConstraints = new ArrayList<LengthConstraint>();
\r
363 for (int j = 0; j < ctx.getChildCount(); j++) {
\r
364 ParseTree stringRestrChild = ctx.getChild(j);
\r
365 if (stringRestrChild instanceof String_restrictionsContext) {
\r
366 for (int k = 0; k < stringRestrChild.getChildCount(); k++) {
\r
367 ParseTree lengthChild = stringRestrChild.getChild(k);
\r
368 if (lengthChild instanceof Length_stmtContext) {
\r
370 .addAll(parseLengthConstraints((Length_stmtContext) lengthChild));
\r
375 return lengthConstraints;
\r
378 private static List<LengthConstraint> parseLengthConstraints(
\r
379 Length_stmtContext ctx) {
\r
380 List<LengthConstraint> lengthConstraints = new ArrayList<LengthConstraint>();
\r
381 String description = null;
\r
382 String reference = null;
\r
384 for (int i = 0; i < ctx.getChildCount(); i++) {
\r
385 ParseTree child = ctx.getChild(i);
\r
386 if (child instanceof Description_stmtContext) {
\r
387 description = stringFromNode(child);
\r
388 } else if (child instanceof Reference_stmtContext) {
\r
389 reference = stringFromNode(child);
\r
393 String lengthStr = stringFromNode(ctx);
\r
394 String trimmed = lengthStr.replace(" ", "");
\r
395 String[] splittedRange = trimmed.split("\\|");
\r
396 for (String rangeDef : splittedRange) {
\r
397 // TODO: this needs to be refactored, because valid length can be
\r
398 // also defined as "1"
\r
399 String[] splittedRangeDef = rangeDef.split("\\.\\.");
\r
400 Long min = Long.valueOf(splittedRangeDef[0]);
\r
401 Long max = Long.valueOf(splittedRangeDef[1]);
\r
402 LengthConstraint range = BaseConstraints.lengthConstraint(min, max,
\r
403 description, reference);
\r
404 lengthConstraints.add(range);
\r
407 return lengthConstraints;
\r
410 public static List<PatternConstraint> getPatternConstraint(
\r
411 Type_body_stmtsContext ctx) {
\r
412 List<PatternConstraint> patterns = new ArrayList<PatternConstraint>();
\r
414 out: for (int j = 0; j < ctx.getChildCount(); j++) {
\r
415 ParseTree stringRestrChild = ctx.getChild(j);
\r
416 if (stringRestrChild instanceof String_restrictionsContext) {
\r
417 for (int k = 0; k < stringRestrChild.getChildCount(); k++) {
\r
418 ParseTree lengthChild = stringRestrChild.getChild(k);
\r
419 if (lengthChild instanceof Pattern_stmtContext) {
\r
420 patterns.add(parsePatternConstraint((Pattern_stmtContext) lengthChild));
\r
421 if (k == lengthChild.getChildCount() - 1) {
\r
432 * Internal helper method.
\r
436 * @return PatternConstraint object
\r
438 private static PatternConstraint parsePatternConstraint(
\r
439 Pattern_stmtContext ctx) {
\r
440 String description = null;
\r
441 String reference = null;
\r
442 for (int i = 0; i < ctx.getChildCount(); i++) {
\r
443 ParseTree child = ctx.getChild(i);
\r
444 if (child instanceof Description_stmtContext) {
\r
445 description = stringFromNode(child);
\r
446 } else if (child instanceof Reference_stmtContext) {
\r
447 reference = stringFromNode(child);
\r
450 String pattern = stringFromNode(ctx);
\r
451 return BaseConstraints.patternConstraint(pattern, description,
\r
455 public static List<BitsTypeDefinition.Bit> getBits(
\r
456 Type_body_stmtsContext ctx, Stack<String> actualPath,
\r
457 URI namespace, Date revision, String prefix) {
\r
458 List<BitsTypeDefinition.Bit> bits = new ArrayList<BitsTypeDefinition.Bit>();
\r
459 for (int j = 0; j < ctx.getChildCount(); j++) {
\r
460 ParseTree bitsSpecChild = ctx.getChild(j);
\r
461 if (bitsSpecChild instanceof Bits_specificationContext) {
\r
462 for (int k = 0; k < bitsSpecChild.getChildCount(); k++) {
\r
463 ParseTree bitChild = bitsSpecChild.getChild(k);
\r
464 if (bitChild instanceof Bit_stmtContext) {
\r
465 bits.add(parseBit((Bit_stmtContext) bitChild,
\r
466 actualPath, namespace, revision, prefix));
\r
474 private static BitsTypeDefinition.Bit parseBit(final Bit_stmtContext ctx,
\r
475 Stack<String> actualPath, final URI namespace, final Date revision,
\r
476 final String prefix) {
\r
477 String name = stringFromNode(ctx);
\r
478 final QName qname = new QName(namespace, revision, prefix, name);
\r
479 Long position = null;
\r
481 String description = null;
\r
482 String reference = null;
\r
483 Status status = Status.CURRENT;
\r
485 Stack<String> bitPath = new Stack<String>();
\r
486 bitPath.addAll(actualPath);
\r
489 SchemaPath schemaPath = getActualSchemaPath(bitPath, namespace,
\r
492 for (int i = 0; i < ctx.getChildCount(); i++) {
\r
493 ParseTree child = ctx.getChild(i);
\r
494 if (child instanceof Position_stmtContext) {
\r
495 String positionStr = stringFromNode(child);
\r
496 position = Long.valueOf(positionStr);
\r
497 if (position < 0 || position > 4294967295L) {
\r
498 throw new IllegalArgumentException(
\r
499 "position value MUST be in the range 0 to 4294967295, but was: "
\r
502 } else if (child instanceof Description_stmtContext) {
\r
503 description = stringFromNode(child);
\r
504 } else if (child instanceof Reference_stmtContext) {
\r
505 reference = stringFromNode(child);
\r
506 } else if (child instanceof Status_stmtContext) {
\r
507 status = getStatus((Status_stmtContext) child);
\r
511 // TODO: extensionDefinitions
\r
512 return createBit(qname, schemaPath, description, reference, status,
\r
516 private static BitsTypeDefinition.Bit createBit(final QName qname,
\r
517 final SchemaPath schemaPath, final String description,
\r
518 final String reference, final Status status,
\r
519 final List<ExtensionDefinition> extensionDefinitions,
\r
520 final Long position) {
\r
521 return new BitsTypeDefinition.Bit() {
\r
524 public QName getQName() {
\r
529 public SchemaPath getPath() {
\r
534 public String getDescription() {
\r
535 return description;
\r
539 public String getReference() {
\r
544 public Status getStatus() {
\r
549 public List<ExtensionDefinition> getExtensionSchemaNodes() {
\r
550 return extensionDefinitions;
\r
554 public Long getPosition() {
\r
559 public String getName() {
\r
560 return qname.getLocalName();
\r
564 public int hashCode() {
\r
565 final int prime = 31;
\r
567 result = prime * result
\r
568 + ((qname == null) ? 0 : qname.hashCode());
\r
569 result = prime * result
\r
570 + ((schemaPath == null) ? 0 : schemaPath.hashCode());
\r
571 result = prime * result
\r
572 + ((description == null) ? 0 : description.hashCode());
\r
573 result = prime * result
\r
574 + ((reference == null) ? 0 : reference.hashCode());
\r
575 result = prime * result
\r
576 + ((status == null) ? 0 : status.hashCode());
\r
577 result = prime * result
\r
578 + ((position == null) ? 0 : position.hashCode());
\r
581 + ((extensionDefinitions == null) ? 0
\r
582 : extensionDefinitions.hashCode());
\r
587 public boolean equals(Object obj) {
\r
594 if (getClass() != obj.getClass()) {
\r
597 Bit other = (Bit) obj;
\r
598 if (qname == null) {
\r
599 if (other.getQName() != null) {
\r
602 } else if (!qname.equals(other.getQName())) {
\r
605 if (schemaPath == null) {
\r
606 if (other.getPath() != null) {
\r
609 } else if (!schemaPath.equals(other.getPath())) {
\r
612 if (description == null) {
\r
613 if (other.getDescription() != null) {
\r
616 } else if (!description.equals(other.getDescription())) {
\r
619 if (reference == null) {
\r
620 if (other.getReference() != null) {
\r
623 } else if (!reference.equals(other.getReference())) {
\r
626 if (status == null) {
\r
627 if (other.getStatus() != null) {
\r
630 } else if (!status.equals(other.getStatus())) {
\r
633 if (extensionDefinitions == null) {
\r
634 if (other.getExtensionSchemaNodes() != null) {
\r
637 } else if (!extensionDefinitions.equals(other
\r
638 .getExtensionSchemaNodes())) {
\r
641 if (position == null) {
\r
642 if (other.getPosition() != null) {
\r
645 } else if (!position.equals(other.getPosition())) {
\r
652 public String toString() {
\r
653 return Bit.class.getSimpleName() + "[name="
\r
654 + qname.getLocalName() + ", position=" + position + "]";
\r