Bug 3670 (part 1/5): Use of new statement parser in yang-maven-plugin
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / effective / type / Decimal64SpecificationEffectiveStatementImpl.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type;
9
10 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
11 import org.opendaylight.yangtools.yang.model.util.ExtendedType.Builder;
12 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
13 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.EffectiveStatementBase;
14 import org.opendaylight.yangtools.yang.model.util.Decimal64;
15 import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement;
16 import com.google.common.base.Optional;
17 import com.google.common.collect.ImmutableList;
18 import java.math.BigDecimal;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import org.opendaylight.yangtools.yang.common.QName;
23 import org.opendaylight.yangtools.yang.common.YangConstants;
24 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
25 import org.opendaylight.yangtools.yang.model.api.Status;
26 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
28 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
29 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
30 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
31 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.TypeUtils;
32 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils;
33 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.FractionDigitsEffectiveStatementImpl;
34
35 public class Decimal64SpecificationEffectiveStatementImpl extends
36         EffectiveStatementBase<String, TypeStatement.Decimal64Specification>
37         implements DecimalTypeDefinition, TypeDefinitionEffectiveBuilder {
38
39     private static final String UNITS = "";
40     private static final BigDecimal DEFAULT_VALUE = null;
41     private static final QName QNAME = QName.create(
42             YangConstants.RFC6020_YANG_MODULE, TypeUtils.DECIMAL64);
43
44     private static final String DESCRIPTION = "The decimal64 type represents a subset of the real numbers, which can "
45             + "be represented by decimal numerals. The value space of decimal64 is the set of numbers that can "
46             + "be obtained by multiplying a 64-bit signed integer by a negative power of ten, i.e., expressible as "
47             + "'i x 10^-n' where i is an integer64 and n is an integer between 1 and 18, inclusively.";
48
49     private static final String REFERENCE = "https://tools.ietf.org/html/rfc6020#section-9.3";
50     private static final BigDecimal MIN_VALUE = new BigDecimal(
51             "-922337203685477580.8");
52     private static final BigDecimal MAX_VALUE = new BigDecimal(
53             "922337203685477580.7");
54
55     private List<RangeConstraint> rangeConstraints;
56     private Integer fractionDigits;
57     private SchemaPath path;
58     private QName extendedTypeQName;
59
60     private ExtendedType extendedType;
61     private final boolean isExtended;
62
63     public Decimal64SpecificationEffectiveStatementImpl(
64             StmtContext<String, TypeStatement.Decimal64Specification, EffectiveStatement<String, TypeStatement.Decimal64Specification>> ctx) {
65         super(ctx);
66
67         for (final EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
68             if (effectiveStatement instanceof FractionDigitsEffectiveStatementImpl) {
69                 fractionDigits = ((FractionDigitsEffectiveStatementImpl) effectiveStatement)
70                         .argument();
71             }
72         }
73
74         List<RangeConstraint> initRanges = initRanges();
75
76         if (!initRanges.isEmpty() && validateRanges(initRanges)) {
77             isExtended = true;
78             rangeConstraints = ImmutableList.copyOf(initRanges);
79             SchemaPath parentPath = Utils.getSchemaPath(ctx.getParentContext());
80             extendedTypeQName = QName.create(parentPath.getLastComponent().getModule(), QNAME.getLocalName());
81             path = parentPath.createChild(extendedTypeQName);
82         } else {
83             isExtended = false;
84             rangeConstraints = defaultRangeStatements();
85             path = Utils.getSchemaPath(ctx.getParentContext()).createChild(QNAME);
86         }
87     }
88
89     private boolean validateRanges(List<RangeConstraint> initRanges) {
90         for (RangeConstraint rangeConstraint : initRanges) {
91
92             String maxValueString = rangeConstraint.getMax().toString();
93             String minValueString = rangeConstraint.getMin().toString();
94
95             if ((!maxValueString.equals("max") && new BigDecimal(maxValueString)
96                     .compareTo(MAX_VALUE) > 0)
97                     || (!minValueString.equals("min") && new BigDecimal(
98                             minValueString).compareTo(MIN_VALUE) < 0)) {
99                 return false;
100             }
101         }
102         return true;
103     }
104
105     protected List<RangeConstraint> initRanges() {
106         final RangeEffectiveStatementImpl rangeConstraints = firstEffective(RangeEffectiveStatementImpl.class);
107         return rangeConstraints != null ? rangeConstraints.argument()
108                 : Collections.<RangeConstraint> emptyList();
109     }
110
111     private List<RangeConstraint> defaultRangeStatements() {
112
113         final List<RangeConstraint> rangeStmts = new ArrayList<>();
114         final String rangeDescription = "Integer values between " + MIN_VALUE
115                 + " and " + MAX_VALUE + ", inclusively.";
116         final String rangeReference = RangeConstraintEffectiveImpl.DEFAULT_REFERENCE;
117
118         rangeStmts.add(new RangeConstraintEffectiveImpl(MIN_VALUE, MAX_VALUE,
119                 Optional.of(rangeDescription), Optional.of(rangeReference)));
120
121         return ImmutableList.copyOf(rangeStmts);
122     }
123
124     public boolean isExtended() {
125         return isExtended;
126     }
127
128     @Override
129     public List<RangeConstraint> getRangeConstraints() {
130         return rangeConstraints;
131     }
132
133     @Override
134     public Integer getFractionDigits() {
135         return fractionDigits;
136     }
137
138     @Override
139     public DecimalTypeDefinition getBaseType() {
140         if(isExtended) {
141             if (decimal64Instance == null) {
142                 decimal64Instance = Decimal64.create(path, fractionDigits);
143             }
144             return decimal64Instance;
145         } else {
146             return null;
147         }
148     }
149
150     @Override
151     public String getUnits() {
152         return UNITS;
153     }
154
155     @Override
156     public Object getDefaultValue() {
157         return DEFAULT_VALUE;
158     }
159
160     @Override
161     public QName getQName() {
162         return QNAME;
163     }
164
165     @Override
166     public SchemaPath getPath() {
167         return path;
168     }
169
170     @Override
171     public List<UnknownSchemaNode> getUnknownSchemaNodes() {
172         return Collections.emptyList();
173     }
174
175     @Override
176     public String getDescription() {
177         return DESCRIPTION;
178     }
179
180     @Override
181     public String getReference() {
182         return REFERENCE;
183     }
184
185     @Override
186     public Status getStatus() {
187         return Status.CURRENT;
188     }
189
190     @Override
191     public int hashCode() {
192         final int prime = 31;
193         int result = 1;
194         result = prime * result + ((QNAME == null) ? 0 : QNAME.hashCode());
195         result = prime * result + ((path == null) ? 0 : path.hashCode());
196         return result;
197     }
198
199     @Override
200     public boolean equals(final Object obj) {
201         if (this == obj) {
202             return true;
203         }
204         if (obj == null) {
205             return false;
206         }
207         if (getClass() != obj.getClass()) {
208             return false;
209         }
210         Decimal64SpecificationEffectiveStatementImpl other = (Decimal64SpecificationEffectiveStatementImpl) obj;
211         if (path == null) {
212             if (other.path != null) {
213                 return false;
214             }
215         } else if (!path.equals(other.path)) {
216             return false;
217         }
218         return true;
219     }
220
221     @Override
222     public String toString() {
223         return Decimal64SpecificationEffectiveStatementImpl.class
224                 .getSimpleName()
225                 + "[qName="
226                 + QNAME
227                 + ", fractionDigits="
228                 + fractionDigits + "]";
229     }
230
231     private Decimal64 decimal64Instance = null;
232
233     @Override
234     public TypeDefinition<?> buildType() {
235
236         if (decimal64Instance == null) {
237             decimal64Instance = Decimal64.create(path, fractionDigits);
238         }
239
240         if(!isExtended) {
241             return decimal64Instance;
242         }
243
244         if (extendedType != null) {
245             return extendedType;
246         }
247
248         Builder extendedTypeBuilder = ExtendedType.builder(path.getLastComponent(), decimal64Instance, Optional.<String>absent(),
249                 Optional.<String>absent(), path);
250
251         extendedTypeBuilder.fractionDigits(fractionDigits);
252         extendedTypeBuilder.ranges(rangeConstraints);
253
254         extendedType = extendedTypeBuilder.build();
255
256         return extendedType;
257     }
258 }