BUG-1371: improved parser handling of invalid yang list key.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / builder / impl / ListSchemaNodeBuilder.java
1 /*
2  * Copyright (c) 2013 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.builder.impl;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.ImmutableList;
13 import com.google.common.collect.ImmutableSet;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Set;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
19 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
20 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
24 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
25 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
26 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
27 import org.opendaylight.yangtools.yang.parser.builder.api.ConstraintsBuilder;
28 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
29 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
30 import org.opendaylight.yangtools.yang.parser.builder.api.UnknownSchemaNodeBuilder;
31 import org.opendaylight.yangtools.yang.parser.builder.util.AbstractDocumentedDataNodeContainer;
32 import org.opendaylight.yangtools.yang.parser.builder.util.AbstractDocumentedDataNodeContainerBuilder;
33 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
34
35 public final class ListSchemaNodeBuilder extends AbstractDocumentedDataNodeContainerBuilder implements
36         DataSchemaNodeBuilder, AugmentationTargetBuilder {
37     private ListSchemaNodeImpl instance;
38     private boolean userOrdered;
39     private List<String> keys;
40     private List<QName> keyDefinition;
41     // SchemaNode args
42     private SchemaPath schemaPath;
43     // DataSchemaNode args
44     private boolean augmenting;
45     private boolean addedByUses;
46     private ListSchemaNodeBuilder originalBuilder;
47     private ListSchemaNode originalNode;
48     private boolean configuration;
49     private final ConstraintsBuilder constraints;
50     // AugmentationTarget args
51     private final List<AugmentationSchema> augmentations = new ArrayList<>();
52     private final List<AugmentationSchemaBuilder> augmentationBuilders = new ArrayList<>();
53
54     public ListSchemaNodeBuilder(final String moduleName, final int line, final QName qname, final SchemaPath path) {
55         super(moduleName, line, qname);
56         this.schemaPath = Preconditions.checkNotNull(path, "Schema Path must not be null");
57         constraints = new ConstraintsBuilderImpl(moduleName, line);
58     }
59
60     public ListSchemaNodeBuilder(final String moduleName, final int line, final QName qname, final SchemaPath path,
61             final ListSchemaNode base) {
62         super(moduleName, line, qname, path, base);
63         this.schemaPath = Preconditions.checkNotNull(path, "Schema Path must not be null");
64         constraints = new ConstraintsBuilderImpl(moduleName, line, base.getConstraints());
65
66         keyDefinition = ImmutableList.copyOf(base.getKeyDefinition());
67         userOrdered = base.isUserOrdered();
68
69         augmenting = base.isAugmenting();
70         addedByUses = base.isAddedByUses();
71         originalNode = base;
72         configuration = base.isConfiguration();
73
74         addedUnknownNodes.addAll(BuilderUtils.wrapUnknownNodes(moduleName, line, base.getUnknownSchemaNodes(), path,
75                 qname));
76         augmentations.addAll(base.getAvailableAugmentations());
77     }
78
79     @Override
80     public ListSchemaNode build() {
81         if (instance != null) {
82             return instance;
83         }
84         buildChildren();
85         instance = new ListSchemaNodeImpl(qname, schemaPath, this);
86
87         instance.augmenting = augmenting;
88         instance.addedByUses = addedByUses;
89         instance.configuration = configuration;
90         instance.constraints = constraints.toInstance();
91         instance.userOrdered = userOrdered;
92
93         // KEY
94         if (keys == null) {
95             instance.keyDefinition = ImmutableList.of();
96         } else {
97             keyDefinition = new ArrayList<>();
98             for (String key : keys) {
99                 DataSchemaNode keyPart = instance.getDataChildByName(key);
100                 if (keyPart == null) {
101                     throw new YangParseException(getModuleName(), getLine(), "Failed to resolve list key for name "
102                             + key);
103                 }
104                 keyDefinition.add(keyPart.getQName());
105             }
106             instance.keyDefinition = ImmutableList.copyOf(keyDefinition);
107         }
108
109         // ORIGINAL NODE
110         if (originalNode == null && originalBuilder != null) {
111             originalNode = originalBuilder.build();
112         }
113         instance.original = originalNode;
114
115         // AUGMENTATIONS
116         for (AugmentationSchemaBuilder builder : augmentationBuilders) {
117             augmentations.add(builder.build());
118         }
119         instance.augmentations = ImmutableSet.copyOf(augmentations);
120
121         // UNKNOWN NODES
122         for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
123             unknownNodes.add(b.build());
124         }
125         instance.unknownNodes = ImmutableList.copyOf(unknownNodes);
126
127         return instance;
128     }
129
130     @Override
131     protected String getStatementName() {
132         return "list";
133     }
134
135     @Override
136     public SchemaPath getPath() {
137         return schemaPath;
138     }
139
140     @Override
141     public void setPath(final SchemaPath path) {
142         this.schemaPath = path;
143     }
144
145     @Override
146     public void addAugmentation(final AugmentationSchemaBuilder augment) {
147         augmentationBuilders.add(augment);
148     }
149
150     public List<AugmentationSchemaBuilder> getAugmentationBuilders() {
151         return augmentationBuilders;
152     }
153
154     public List<String> getKeys() {
155         return keys;
156     }
157
158     public void setKeys(final List<String> keys) {
159         this.keys = keys;
160     }
161
162     @Override
163     public boolean isAugmenting() {
164         return augmenting;
165     }
166
167     @Override
168     public void setAugmenting(final boolean augmenting) {
169         this.augmenting = augmenting;
170     }
171
172     @Override
173     public boolean isAddedByUses() {
174         return addedByUses;
175     }
176
177     @Override
178     public void setAddedByUses(final boolean addedByUses) {
179         this.addedByUses = addedByUses;
180     }
181
182     @Override
183     public ListSchemaNodeBuilder getOriginal() {
184         return originalBuilder;
185     }
186
187     @Override
188     public void setOriginal(final SchemaNodeBuilder builder) {
189         Preconditions.checkArgument(builder instanceof ListSchemaNodeBuilder, "Original of list cannot be " + builder);
190         this.originalBuilder = (ListSchemaNodeBuilder) builder;
191     }
192
193     @Override
194     public boolean isConfiguration() {
195         return configuration;
196     }
197
198     @Override
199     public void setConfiguration(final boolean configuration) {
200         this.configuration = configuration;
201     }
202
203     @Override
204     public ConstraintsBuilder getConstraints() {
205         return constraints;
206     }
207
208     public boolean isUserOrdered() {
209         return userOrdered;
210     }
211
212     public void setUserOrdered(final boolean userOrdered) {
213         this.userOrdered = userOrdered;
214     }
215
216     @Override
217     public int hashCode() {
218         final int prime = 31;
219         int result = 1;
220         result = prime * result + ((schemaPath == null) ? 0 : schemaPath.hashCode());
221         return result;
222     }
223
224     @Override
225     public boolean equals(final Object obj) {
226         if (this == obj) {
227             return true;
228         }
229         if (obj == null) {
230             return false;
231         }
232         if (getClass() != obj.getClass()) {
233             return false;
234         }
235         ListSchemaNodeBuilder other = (ListSchemaNodeBuilder) obj;
236         if (schemaPath == null) {
237             if (other.schemaPath != null) {
238                 return false;
239             }
240         } else if (!schemaPath.equals(other.schemaPath)) {
241             return false;
242         }
243         if (getParent() == null) {
244             if (other.getParent() != null) {
245                 return false;
246             }
247         } else if (!getParent().equals(other.getParent())) {
248             return false;
249         }
250         return true;
251     }
252
253     @Override
254     public String toString() {
255         return "list " + qname.getLocalName();
256     }
257
258     private static final class ListSchemaNodeImpl extends AbstractDocumentedDataNodeContainer implements
259             ListSchemaNode, DerivableSchemaNode {
260         private final QName qname;
261         private final SchemaPath path;
262         private ImmutableList<QName> keyDefinition;
263         private boolean augmenting;
264         private boolean addedByUses;
265         private ListSchemaNode original;
266         private boolean configuration;
267         private ConstraintDefinition constraints;
268         private ImmutableSet<AugmentationSchema> augmentations;
269         private ImmutableList<UnknownSchemaNode> unknownNodes;
270         private boolean userOrdered;
271
272         private ListSchemaNodeImpl(final QName qname, final SchemaPath path, final ListSchemaNodeBuilder builder) {
273             super(builder);
274             this.qname = qname;
275             this.path = path;
276         }
277
278         @Override
279         public QName getQName() {
280             return qname;
281         }
282
283         @Override
284         public SchemaPath getPath() {
285             return path;
286         }
287
288         @Override
289         public List<QName> getKeyDefinition() {
290             return keyDefinition;
291         }
292
293         @Override
294         public boolean isAugmenting() {
295             return augmenting;
296         }
297
298         @Override
299         public boolean isAddedByUses() {
300             return addedByUses;
301         }
302
303         @Override
304         public Optional<ListSchemaNode> getOriginal() {
305             return Optional.fromNullable(original);
306         }
307
308         @Override
309         public boolean isConfiguration() {
310             return configuration;
311         }
312
313         @Override
314         public ConstraintDefinition getConstraints() {
315             return constraints;
316         }
317
318         @Override
319         public Set<AugmentationSchema> getAvailableAugmentations() {
320             return augmentations;
321         }
322
323         @Override
324         public boolean isUserOrdered() {
325             return userOrdered;
326         }
327
328         @Override
329         public List<UnknownSchemaNode> getUnknownSchemaNodes() {
330             return unknownNodes;
331         }
332
333         @Override
334         public int hashCode() {
335             final int prime = 31;
336             int result = 1;
337             result = prime * result + ((qname == null) ? 0 : qname.hashCode());
338             result = prime * result + ((path == null) ? 0 : path.hashCode());
339             return result;
340         }
341
342         @Override
343         public boolean equals(final Object obj) {
344             if (this == obj) {
345                 return true;
346             }
347             if (obj == null) {
348                 return false;
349             }
350             if (getClass() != obj.getClass()) {
351                 return false;
352             }
353             final ListSchemaNodeImpl other = (ListSchemaNodeImpl) obj;
354             if (qname == null) {
355                 if (other.qname != null) {
356                     return false;
357                 }
358             } else if (!qname.equals(other.qname)) {
359                 return false;
360             }
361             if (path == null) {
362                 if (other.path != null) {
363                     return false;
364                 }
365             } else if (!path.equals(other.path)) {
366                 return false;
367             }
368             return true;
369         }
370
371         @Override
372         public String toString() {
373             return "list " + qname.getLocalName();
374         }
375     }
376
377 }