Use Objects.hashCode()
[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(
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     private static final List<RangeConstraint> DEFAULT_RANGE_STATEMENTS;
55     static {
56         final String rangeDescription = "Integer values between " + MIN_VALUE
57                 + " and " + MAX_VALUE + ", inclusively.";
58         final String rangeReference = RangeConstraintEffectiveImpl.DEFAULT_REFERENCE;
59
60         DEFAULT_RANGE_STATEMENTS = ImmutableList.<RangeConstraint>of(
61                 new RangeConstraintEffectiveImpl(MIN_VALUE, MAX_VALUE, Optional.of(rangeDescription),
62                 Optional.of(rangeReference)));
63     }
64
65     private List<RangeConstraint> rangeConstraints;
66     private Integer fractionDigits;
67     private SchemaPath path;
68     private QName extendedTypeQName;
69
70     private ExtendedType extendedType;
71     private final boolean isExtended;
72
73     public Decimal64SpecificationEffectiveStatementImpl(
74             final StmtContext<String, TypeStatement.Decimal64Specification, EffectiveStatement<String, TypeStatement.Decimal64Specification>> ctx) {
75         super(ctx);
76
77         for (final EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
78             if (effectiveStatement instanceof FractionDigitsEffectiveStatementImpl) {
79                 fractionDigits = ((FractionDigitsEffectiveStatementImpl) effectiveStatement)
80                         .argument();
81             }
82         }
83
84         List<RangeConstraint> initRanges = initRanges();
85
86         if (!initRanges.isEmpty() && validateRanges(initRanges)) {
87             isExtended = true;
88             rangeConstraints = ImmutableList.copyOf(initRanges);
89             SchemaPath parentPath = Utils.getSchemaPath(ctx.getParentContext());
90             extendedTypeQName = QName.create(parentPath.getLastComponent().getModule(), QNAME.getLocalName());
91             path = parentPath.createChild(extendedTypeQName);
92         } else {
93             isExtended = false;
94             rangeConstraints = DEFAULT_RANGE_STATEMENTS;
95             path = Utils.getSchemaPath(ctx.getParentContext()).createChild(QNAME);
96         }
97     }
98
99     private static boolean validateRanges(final List<RangeConstraint> initRanges) {
100         for (RangeConstraint rangeConstraint : initRanges) {
101
102             String maxValueString = rangeConstraint.getMax().toString();
103             String minValueString = rangeConstraint.getMin().toString();
104
105             if ((!maxValueString.equals("max") && new BigDecimal(maxValueString)
106                     .compareTo(MAX_VALUE) > 0)
107                     || (!minValueString.equals("min") && new BigDecimal(
108                             minValueString).compareTo(MIN_VALUE) < 0)) {
109                 return false;
110             }
111         }
112         return true;
113     }
114
115     protected List<RangeConstraint> initRanges() {
116         final RangeEffectiveStatementImpl rangeConstraints = firstEffective(RangeEffectiveStatementImpl.class);
117         return rangeConstraints != null ? rangeConstraints.argument()
118                 : Collections.<RangeConstraint> emptyList();
119     }
120
121     public boolean isExtended() {
122         return isExtended;
123     }
124
125     @Override
126     public List<RangeConstraint> getRangeConstraints() {
127         return rangeConstraints;
128     }
129
130     @Override
131     public Integer getFractionDigits() {
132         return fractionDigits;
133     }
134
135     @Override
136     public DecimalTypeDefinition getBaseType() {
137         if(isExtended) {
138             if (decimal64Instance == null) {
139                 decimal64Instance = Decimal64.create(path, fractionDigits);
140             }
141             return decimal64Instance;
142         } else {
143             return null;
144         }
145     }
146
147     @Override
148     public String getUnits() {
149         return UNITS;
150     }
151
152     @Override
153     public Object getDefaultValue() {
154         return DEFAULT_VALUE;
155     }
156
157     @Override
158     public QName getQName() {
159         return QNAME;
160     }
161
162     @Override
163     public SchemaPath getPath() {
164         return path;
165     }
166
167     @Override
168     public List<UnknownSchemaNode> getUnknownSchemaNodes() {
169         return Collections.emptyList();
170     }
171
172     @Override
173     public String getDescription() {
174         return DESCRIPTION;
175     }
176
177     @Override
178     public String getReference() {
179         return REFERENCE;
180     }
181
182     @Override
183     public Status getStatus() {
184         return Status.CURRENT;
185     }
186
187     @Override
188     public int hashCode() {
189         final int prime = 31;
190         int result = 1;
191         result = prime * result + Objects.hashCode(QNAME);
192         result = prime * result + Objects.hashCode(path);
193         return result;
194     }
195
196     @Override
197     public boolean equals(final Object obj) {
198         if (this == obj) {
199             return true;
200         }
201         if (obj == null) {
202             return false;
203         }
204         if (getClass() != obj.getClass()) {
205             return false;
206         }
207         Decimal64SpecificationEffectiveStatementImpl other = (Decimal64SpecificationEffectiveStatementImpl) obj;
208         if (path == null) {
209             if (other.path != null) {
210                 return false;
211             }
212         } else if (!path.equals(other.path)) {
213             return false;
214         }
215         return true;
216     }
217
218     @Override
219     public String toString() {
220         return Decimal64SpecificationEffectiveStatementImpl.class
221                 .getSimpleName()
222                 + "[qName="
223                 + QNAME
224                 + ", fractionDigits="
225                 + fractionDigits + "]";
226     }
227
228     private Decimal64 decimal64Instance = null;
229
230     @Override
231     public TypeDefinition<?> buildType() {
232
233         if (decimal64Instance == null) {
234             decimal64Instance = Decimal64.create(path, fractionDigits);
235         }
236
237         if(!isExtended) {
238             return decimal64Instance;
239         }
240
241         if (extendedType != null) {
242             return extendedType;
243         }
244
245         Builder extendedTypeBuilder = ExtendedType.builder(path.getLastComponent(), decimal64Instance, Optional.<String>absent(),
246                 Optional.<String>absent(), path);
247
248         extendedTypeBuilder.fractionDigits(fractionDigits);
249         extendedTypeBuilder.ranges(rangeConstraints);
250
251         extendedType = extendedTypeBuilder.build();
252
253         return extendedType;
254     }
255 }