Introduce TypeDefinitionAware
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / effective / TypeDefEffectiveStatementImpl.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;
9
10 import com.google.common.base.Optional;
11 import com.google.common.collect.ImmutableList;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
15 import org.opendaylight.yangtools.yang.common.QName;
16 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
17 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
18 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
19 import org.opendaylight.yangtools.yang.model.api.stmt.TypeDefinitionAware;
20 import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement;
21 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
22 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement;
23 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
24 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
25 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
26 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
27 import org.opendaylight.yangtools.yang.model.util.ExtendedType.Builder;
28 import org.opendaylight.yangtools.yang.parser.spi.TypeNamespace;
29 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
30 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
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.type.Decimal64SpecificationEffectiveStatementImpl;
34 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.LengthEffectiveStatementImpl;
35 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.PatternEffectiveStatementImpl;
36 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.RangeEffectiveStatementImpl;
37
38 public final class TypeDefEffectiveStatementImpl extends AbstractEffectiveSchemaNode<TypedefStatement> implements
39         TypeDefinition<TypeDefinition<?>>, TypedefEffectiveStatement {
40     private final TypeDefinition<?> baseType;
41     private final String defaultValue;
42     private final String units;
43     private final List<RangeConstraint> ranges;
44     private final List<LengthConstraint> lengths;
45     private final List<PatternConstraint> patterns;
46     private final Integer fractionDigits;
47     private ExtendedType extendedType = null;
48
49     public TypeDefEffectiveStatementImpl(final StmtContext<QName, TypedefStatement, ?> ctx) {
50         super(ctx);
51         baseType = parseBaseTypeFromCtx(ctx);
52
53         UnitsEffectiveStatementImpl unitsStmt = firstEffective(UnitsEffectiveStatementImpl.class);
54         this.units = (unitsStmt == null) ? null : unitsStmt.argument();
55         DefaultEffectiveStatementImpl defaultStmt = firstEffective(DefaultEffectiveStatementImpl.class);
56         this.defaultValue = (defaultStmt == null) ? null : defaultStmt.argument();
57
58         EffectiveStatementBase<?, ?> typeEffectiveStmt = firstSubstatementOfType(TypeDefinition.class,
59                 EffectiveStatementBase.class);
60         ranges = initRanges(typeEffectiveStmt);
61         lengths = initLengths(typeEffectiveStmt);
62         patterns = initPatterns(typeEffectiveStmt);
63
64         // due to compatibility problems with original yang parser
65         // :FIXME try to find out better solution
66         if (typeEffectiveStmt.argument().equals(TypeUtils.DECIMAL64) && ranges.isEmpty()) {
67             fractionDigits = null;
68         } else {
69             fractionDigits = initFractionDigits(typeEffectiveStmt);
70         }
71     }
72
73     private TypeDefinition<?> parseBaseTypeFromCtx(final StmtContext<QName, TypedefStatement, ?> ctx) {
74
75         TypeDefinition<?> baseTypeInit;
76
77         QName baseTypeQName = Utils.qNameFromArgument(ctx,
78                 StmtContextUtils.firstAttributeOf(ctx.declaredSubstatements(), TypeStatement.class));
79
80         if (TypeUtils.isYangBuiltInTypeString(baseTypeQName.getLocalName())) {
81             baseTypeInit = TypeUtils.getYangPrimitiveTypeFromString(baseTypeQName.getLocalName());
82             if (baseTypeInit == null) {
83                 baseTypeInit = firstSubstatementOfType(TypeDefinition.class);
84
85                 // due to compatibility problems with original yang parser
86                 // :FIXME try to find out better solution
87                 if (baseTypeInit instanceof Decimal64SpecificationEffectiveStatementImpl) {
88                     Decimal64SpecificationEffectiveStatementImpl decimal64 = (Decimal64SpecificationEffectiveStatementImpl) baseTypeInit;
89                     if (decimal64.isExtended()) {
90                         baseTypeInit = decimal64.getBaseType();
91                     }
92                 }
93             }
94         } else {
95             StmtContext<?, TypedefStatement, TypedefEffectiveStatement> baseTypeCtx = ctx
96                     .getParentContext().getFromNamespace(TypeNamespace.class, baseTypeQName);
97             baseTypeInit = (TypeDefEffectiveStatementImpl) baseTypeCtx.buildEffective();
98         }
99
100         return baseTypeInit;
101     }
102
103     private static Integer initFractionDigits(final EffectiveStatementBase<?, ?> typeEffectiveStmt) {
104         final FractionDigitsEffectiveStatementImpl fractionDigitsEffStmt = typeEffectiveStmt
105                 .firstEffective(FractionDigitsEffectiveStatementImpl.class);
106         return fractionDigitsEffStmt != null ? fractionDigitsEffStmt.argument() : null;
107     }
108
109     private static List<RangeConstraint> initRanges(final EffectiveStatementBase<?, ?> typeEffectiveStmt) {
110         final RangeEffectiveStatementImpl rangeConstraints = typeEffectiveStmt
111                 .firstEffective(RangeEffectiveStatementImpl.class);
112         return rangeConstraints != null ? rangeConstraints.argument() : Collections.<RangeConstraint> emptyList();
113     }
114
115     private static List<LengthConstraint> initLengths(final EffectiveStatementBase<?, ?> typeEffectiveStmt) {
116         final LengthEffectiveStatementImpl lengthConstraints = typeEffectiveStmt
117                 .firstEffective(LengthEffectiveStatementImpl.class);
118         return lengthConstraints != null ? lengthConstraints.argument() : Collections.<LengthConstraint> emptyList();
119     }
120
121     private static List<PatternConstraint> initPatterns(final EffectiveStatementBase<?, ?> typeEffectiveStmt) {
122         final List<PatternConstraint> patternConstraints = new ArrayList<>();
123
124         for (final EffectiveStatement<?, ?> effectiveStatement : typeEffectiveStmt.effectiveSubstatements()) {
125             if (effectiveStatement instanceof PatternEffectiveStatementImpl) {
126                 final PatternConstraint pattern = ((PatternEffectiveStatementImpl) effectiveStatement).argument();
127                 if (pattern != null) {
128                     patternConstraints.add(pattern);
129                 }
130             }
131         }
132
133         return ImmutableList.copyOf(patternConstraints);
134     }
135
136     @Override
137     public TypeDefinition<?> getBaseType() {
138         return baseType;
139     }
140
141     @Override
142     public String getUnits() {
143         return units;
144     }
145
146     @Override
147     public Object getDefaultValue() {
148         return defaultValue;
149     }
150
151     @Override
152     public List<UnknownSchemaNode> getUnknownSchemaNodes() {
153         return Collections.emptyList();
154     }
155
156     public List<RangeConstraint> getRangeConstraints() {
157         return ranges;
158     }
159
160     public List<LengthConstraint> getLengthConstraints() {
161         return lengths;
162     }
163
164     public List<PatternConstraint> getPatternConstraints() {
165         return patterns;
166     }
167
168     public Integer getFractionDigits() {
169         return fractionDigits;
170     }
171
172     @Override
173     public TypeDefinition<?> getTypeDefinition() {
174         if (extendedType != null) {
175             return extendedType;
176         }
177
178         Builder extendedTypeBuilder;
179         if (baseType instanceof TypeDefinitionAware) {
180             TypeDefinitionAware typeDefBaseType = (TypeDefinitionAware) baseType;
181             extendedTypeBuilder = ExtendedType.builder(getQName(), typeDefBaseType.getTypeDefinition(),
182                     Optional.fromNullable(getDescription()), Optional.fromNullable(getReference()), getPath());
183         } else {
184             extendedTypeBuilder = ExtendedType.builder(getQName(), baseType, Optional.fromNullable(getDescription()),
185                     Optional.fromNullable(getReference()), getPath());
186         }
187
188         extendedTypeBuilder.defaultValue(defaultValue);
189         extendedTypeBuilder.units(units);
190
191         extendedTypeBuilder.fractionDigits(fractionDigits);
192         extendedTypeBuilder.ranges(ranges);
193         extendedTypeBuilder.lengths(lengths);
194         extendedTypeBuilder.patterns(patterns);
195
196         extendedType = extendedTypeBuilder.build();
197
198         return extendedType;
199     }
200 }