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 / ExtendedTypeEffectiveStatementImpl.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.base.Splitter;
12 import com.google.common.collect.ImmutableList;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
18 import org.opendaylight.yangtools.yang.model.api.Status;
19 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
20 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
22 import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement;
23 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement;
24 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
27 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
28 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
29 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
30 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
31 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
32 import org.opendaylight.yangtools.yang.model.util.ExtendedType.Builder;
33 import org.opendaylight.yangtools.yang.parser.spi.TypeNamespace;
34 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
35 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.TypeUtils;
36 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils;
37 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.LengthEffectiveStatementImpl;
38 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.PatternEffectiveStatementImpl;
39 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.RangeEffectiveStatementImpl;
40 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.TypeDefinitionEffectiveBuilder;
41 import org.opendaylight.yangtools.yang.parser.util.TypeConstraints;
42
43 public class ExtendedTypeEffectiveStatementImpl extends EffectiveStatementBase<String, TypeStatement> implements
44         TypeDefinition<TypeDefinition<?>>, TypeDefinitionEffectiveBuilder {
45
46     private static final Splitter COLON_SPLITTER = Splitter.on(':').trimResults();
47
48     private final QName qName;
49     private final SchemaPath path;
50
51     private final TypeDefinition<?> baseType;
52
53     private final String defaultValue = null;
54     private final String units = null;
55
56     private final String description = null;
57     private final String reference = null;
58
59     private final Status status = null;
60
61     private final List<RangeConstraint> ranges;
62     private final List<LengthConstraint> lengths;
63     private final List<PatternConstraint> patterns;
64     private final Integer fractionDigits;
65
66     private ExtendedType extendedType = null;
67     private final boolean isExtended;
68
69     public ExtendedTypeEffectiveStatementImpl(
70             StmtContext<String, TypeStatement, EffectiveStatement<String, TypeStatement>> ctx, boolean isExtended) {
71         super(ctx);
72
73         this.isExtended = isExtended;
74         qName = initQName(ctx, isExtended);
75
76         final StmtContext<?, TypedefStatement, EffectiveStatement<QName, TypedefStatement>> typeStmt = ctx
77                 .getFromNamespace(TypeNamespace.class, qName);
78         if (typeStmt == null) {
79             path = Utils.getSchemaPath(ctx);
80         } else {
81             path = Utils.getSchemaPath(ctx.getFromNamespace(TypeNamespace.class, qName));
82         }
83
84         ranges = initRanges();
85         lengths = initLengths();
86         patterns = initPatterns();
87         fractionDigits = initFractionDigits();
88
89         baseType = parseBaseTypeFromCtx(ctx);
90         validateTypeConstraints(ctx);
91     }
92
93     private QName initQName(final StmtContext<String, TypeStatement, EffectiveStatement<String, TypeStatement>> ctx,
94             final boolean isExtended) {
95
96         QName qName;
97
98         if (isExtended) {
99             final Splitter colonSplitter = Splitter.on(":").trimResults();
100             final List<String> nameTokens = colonSplitter.splitToList(ctx.getStatementArgument());
101
102             switch (nameTokens.size()) {
103             case 1:
104                 qName = QName.create(Utils.getRootModuleQName(ctx), nameTokens.get(0));
105                 break;
106             case 2:
107                 qName = QName.create(Utils.getRootModuleQName(ctx), nameTokens.get(1));
108                 break;
109             default:
110                 throw new IllegalArgumentException(String.format(
111                         "Bad colon separated parts number (%d) of QName '%s'.", nameTokens.size(),
112                         ctx.getStatementArgument()));
113             }
114         } else {
115             qName = Utils.qNameFromArgument(ctx, ctx.getStatementArgument());
116         }
117         return qName;
118     }
119
120     private TypeDefinition<?> parseBaseTypeFromCtx(
121             final StmtContext<String, TypeStatement, EffectiveStatement<String, TypeStatement>> ctx) {
122
123         TypeDefinition<?> baseType;
124
125         final QName baseTypeQName = Utils.qNameFromArgument(ctx, ctx.getStatementArgument());
126         if (TypeUtils.isYangPrimitiveTypeString(baseTypeQName.getLocalName())) {
127             baseType = TypeUtils.getYangPrimitiveTypeFromString(baseTypeQName.getLocalName());
128         } else {
129             StmtContext<?, TypedefStatement, EffectiveStatement<QName, TypedefStatement>> baseTypeCtx = ctx
130                     .getParentContext().getFromNamespace(TypeNamespace.class, baseTypeQName);
131
132             if (baseTypeCtx == null) {
133                 throw new IllegalStateException(String.format("Type '%s' was not found in %s.", baseTypeQName,
134                         ctx.getStatementSourceReference()));
135             }
136
137             baseType = (TypeDefEffectiveStatementImpl) baseTypeCtx.buildEffective();
138         }
139
140         return baseType;
141     }
142
143     private void validateTypeConstraints(
144             final StmtContext<String, TypeStatement, EffectiveStatement<String, TypeStatement>> ctx) {
145
146         final List<String> sourceParts = COLON_SPLITTER.splitToList(ctx.getStatementSourceReference().toString());
147         TypeConstraints typeConstraints = new TypeConstraints(sourceParts.get(0), Integer.parseInt(sourceParts.get(1)));
148
149         typeConstraints.addRanges(ranges);
150         typeConstraints.addLengths(lengths);
151         typeConstraints.addPatterns(patterns);
152         typeConstraints.addFractionDigits(fractionDigits);
153
154         typeConstraints = addConstraintsFromBaseType(typeConstraints, baseType);
155         typeConstraints.validateConstraints();
156     }
157
158     private TypeConstraints addConstraintsFromBaseType(final TypeConstraints typeConstraints,
159             final TypeDefinition<?> baseType) {
160
161         final String baseTypeName = baseType.getQName().getLocalName();
162
163         if (baseType instanceof IntegerTypeDefinition) {
164             final IntegerTypeDefinition intType = (IntegerTypeDefinition) TypeUtils
165                     .getYangPrimitiveTypeFromString(baseTypeName);
166             typeConstraints.addRanges(intType.getRangeConstraints());
167         } else if (baseType instanceof UnsignedIntegerTypeDefinition) {
168             final UnsignedIntegerTypeDefinition uintType = (UnsignedIntegerTypeDefinition) TypeUtils
169                     .getYangPrimitiveTypeFromString(baseTypeName);
170             typeConstraints.addRanges(uintType.getRangeConstraints());
171         } else if (baseType instanceof StringTypeDefinition) {
172             final StringTypeDefinition stringType = (StringTypeDefinition) TypeUtils
173                     .getYangPrimitiveTypeFromString(baseTypeName);
174             typeConstraints.addLengths(stringType.getLengthConstraints());
175             typeConstraints.addPatterns(stringType.getPatternConstraints());
176         } else if (baseType instanceof BinaryTypeDefinition) {
177             final BinaryTypeDefinition binaryType = (BinaryTypeDefinition) TypeUtils
178                     .getYangPrimitiveTypeFromString(baseTypeName);
179             typeConstraints.addLengths(binaryType.getLengthConstraints());
180         } else if (baseType instanceof TypeDefEffectiveStatementImpl) {
181             typeConstraints.addRanges(((TypeDefEffectiveStatementImpl) baseType).getRangeConstraints());
182             typeConstraints.addLengths(((TypeDefEffectiveStatementImpl) baseType).getLengthConstraints());
183             typeConstraints.addPatterns(((TypeDefEffectiveStatementImpl) baseType).getPatternConstraints());
184             typeConstraints.addFractionDigits(((TypeDefEffectiveStatementImpl) baseType).getFractionDigits());
185         }
186 //        else if (baseType instanceof DecimalTypeDefinition) {
187 //            final DecimalTypeDefinition decimalType = (DecimalTypeDefinition) TypeUtils
188 //                    .getYangBaseTypeFromString(baseTypeName);
189 //            typeConstraints.addRanges(decimalType.getRangeConstraints());
190 //            typeConstraints.addFractionDigits(decimalType.getFractionDigits());
191 //        }
192 //        else if (baseType instanceof ExtendedTypeEffectiveStatementImpl) {
193 //            typeConstraints.addRanges(((ExtendedTypeEffectiveStatementImpl) baseType).getRangeConstraints());
194 //            typeConstraints.addLengths(((ExtendedTypeEffectiveStatementImpl) baseType).getLengthConstraints());
195 //            typeConstraints.addPatterns(((ExtendedTypeEffectiveStatementImpl) baseType).getPatternConstraints());
196 //            typeConstraints.addFractionDigits(((ExtendedTypeEffectiveStatementImpl) baseType).getFractionDigits());
197 //        }
198
199         return typeConstraints;
200     }
201
202     protected Integer initFractionDigits() {
203         final FractionDigitsEffectiveStatementImpl fractionDigitsEffStmt = firstEffective(FractionDigitsEffectiveStatementImpl.class);
204         return fractionDigitsEffStmt != null ? fractionDigitsEffStmt.argument() : null;
205     }
206
207     protected List<RangeConstraint> initRanges() {
208         final RangeEffectiveStatementImpl rangeConstraints = firstEffective(RangeEffectiveStatementImpl.class);
209         return rangeConstraints != null ? rangeConstraints.argument() : Collections.<RangeConstraint> emptyList();
210     }
211
212     protected List<LengthConstraint> initLengths() {
213         final LengthEffectiveStatementImpl lengthConstraints = firstEffective(LengthEffectiveStatementImpl.class);
214         return lengthConstraints != null ? lengthConstraints.argument() : Collections.<LengthConstraint> emptyList();
215     }
216
217     protected List<PatternConstraint> initPatterns() {
218         final List<PatternConstraint> patternConstraints = new ArrayList<>();
219
220         for (final EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
221             if (effectiveStatement instanceof PatternEffectiveStatementImpl) {
222                 final PatternConstraint pattern = ((PatternEffectiveStatementImpl) effectiveStatement).argument();
223
224                 if (pattern != null) {
225                     patternConstraints.add(pattern);
226                 }
227             }
228         }
229
230         return !patternConstraints.isEmpty() ? ImmutableList.copyOf(patternConstraints) : Collections
231                 .<PatternConstraint> emptyList();
232     }
233
234     @Override
235     public TypeDefinition<?> getBaseType() {
236         return baseType;
237     }
238
239     @Override
240     public String getUnits() {
241         return units;
242     }
243
244     @Override
245     public Object getDefaultValue() {
246         return defaultValue;
247     }
248
249     @Override
250     public QName getQName() {
251         return qName;
252     }
253
254     @Override
255     public SchemaPath getPath() {
256         return path;
257     }
258
259     @Override
260     public List<UnknownSchemaNode> getUnknownSchemaNodes() {
261         return Collections.emptyList();
262     }
263
264     @Override
265     public String getDescription() {
266         return description;
267     }
268
269     @Override
270     public String getReference() {
271         return reference;
272     }
273
274     @Override
275     public Status getStatus() {
276         return status;
277     }
278
279     public List<RangeConstraint> getRangeConstraints() {
280         return ranges;
281     }
282
283     public List<LengthConstraint> getLengthConstraints() {
284         return lengths;
285     }
286
287     public List<PatternConstraint> getPatternConstraints() {
288         return patterns;
289     }
290
291     public Integer getFractionDigits() {
292         return fractionDigits;
293     }
294
295     @Override
296     public ExtendedType buildType() {
297
298         if (extendedType != null) {
299             return extendedType;
300         }
301
302         if (!isExtended && baseType instanceof TypeDefEffectiveStatementImpl) {
303             TypeDefEffectiveStatementImpl originalTypeDef = (TypeDefEffectiveStatementImpl) baseType;
304             return originalTypeDef.buildType();
305         }
306
307         Builder extendedTypeBuilder;
308         if (baseType instanceof TypeDefEffectiveStatementImpl) {
309             TypeDefEffectiveStatementImpl typeDefBaseType = (TypeDefEffectiveStatementImpl) baseType;
310             extendedTypeBuilder = ExtendedType.builder(qName, typeDefBaseType.buildType(),
311                     Optional.fromNullable(description), Optional.fromNullable(reference), path);
312         } else {
313             extendedTypeBuilder = ExtendedType.builder(qName, baseType, Optional.fromNullable(description),
314                     Optional.fromNullable(reference), path);
315         }
316
317         extendedTypeBuilder.fractionDigits(fractionDigits);
318         extendedTypeBuilder.ranges(ranges);
319         extendedTypeBuilder.lengths(lengths);
320         extendedTypeBuilder.patterns(patterns);
321
322         extendedType = extendedTypeBuilder.build();
323
324         return extendedType;
325     }
326 }