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