Fix for Bug 364.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / builder / impl / ChoiceBuilder.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 java.net.URI;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.Date;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Set;
17 import java.util.TreeSet;
18
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
21 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
22 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
23 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
24 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
26 import org.opendaylight.yangtools.yang.model.api.Status;
27 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
28 import org.opendaylight.yangtools.yang.parser.builder.api.AbstractSchemaNodeBuilder;
29 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
30 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
31 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
32 import org.opendaylight.yangtools.yang.parser.util.Comparators;
33 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
34 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
35
36 public final class ChoiceBuilder extends AbstractSchemaNodeBuilder implements DataSchemaNodeBuilder,
37         AugmentationTargetBuilder {
38     private boolean isBuilt;
39     private final ChoiceNodeImpl instance;
40     // DataSchemaNode args
41     private final ConstraintsBuilder constraints;
42     // AugmentationTarget args
43     private final List<AugmentationSchema> augmentations = new ArrayList<>();
44     private final List<AugmentationSchemaBuilder> augmentationBuilders = new ArrayList<>();
45     // ChoiceNode args
46     private Set<ChoiceCaseNode> cases = new TreeSet<>(Comparators.SCHEMA_NODE_COMP);
47     private final Set<ChoiceCaseBuilder> caseBuilders = new HashSet<>();
48     private String defaultCase;
49
50     public ChoiceBuilder(final String moduleName, final int line, final QName qname, final SchemaPath path) {
51         super(moduleName, line, qname);
52         this.schemaPath = path;
53         instance = new ChoiceNodeImpl(qname, path);
54         constraints = new ConstraintsBuilder(moduleName, line);
55     }
56
57     public ChoiceBuilder(final String moduleName, final int line, final QName qname, final SchemaPath path,
58             final ChoiceNode base) {
59         super(moduleName, line, qname);
60         this.schemaPath = path;
61         instance = new ChoiceNodeImpl(qname, path);
62         constraints = new ConstraintsBuilder(moduleName, line, base.getConstraints());
63
64         instance.description = base.getDescription();
65         instance.reference = base.getReference();
66         instance.status = base.getStatus();
67         instance.augmenting = base.isAugmenting();
68         instance.addedByUses = base.isAddedByUses();
69         instance.configuration = base.isConfiguration();
70         instance.constraints = base.getConstraints();
71         instance.augmentations.addAll(base.getAvailableAugmentations());
72
73         URI ns = qname.getNamespace();
74         Date rev = qname.getRevision();
75         String pref = qname.getPrefix();
76         Set<DataSchemaNodeBuilder> wrapped = ParserUtils.wrapChildNodes(moduleName, line, new HashSet<DataSchemaNode>(
77                 base.getCases()), path, ns, rev, pref);
78         for (DataSchemaNodeBuilder wrap : wrapped) {
79             if (wrap instanceof ChoiceCaseBuilder) {
80                 caseBuilders.add((ChoiceCaseBuilder) wrap);
81             }
82         }
83
84         instance.unknownNodes.addAll(base.getUnknownSchemaNodes());
85     }
86
87     @Override
88     public ChoiceNode build() {
89         if (!isBuilt) {
90             instance.setConstraints(constraints.build());
91             instance.setDefaultCase(defaultCase);
92
93             // CASES
94             for (ChoiceCaseBuilder caseBuilder : caseBuilders) {
95                 cases.add(caseBuilder.build());
96             }
97             instance.addCases(cases);
98
99             // AUGMENTATIONS
100             for (AugmentationSchemaBuilder builder : augmentationBuilders) {
101                 augmentations.add(builder.build());
102             }
103             instance.addAvailableAugmentations(new HashSet<>(augmentations));
104
105             // UNKNOWN NODES
106             for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
107                 unknownNodes.add(b.build());
108             }
109             Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
110             instance.addUnknownSchemaNodes(unknownNodes);
111
112             isBuilt = true;
113         }
114         return instance;
115     }
116
117     public Set<ChoiceCaseBuilder> getCases() {
118         return caseBuilders;
119     }
120
121     @Override
122     public SchemaPath getPath() {
123         return instance.path;
124     }
125
126     @Override
127     public void setPath(SchemaPath path) {
128         instance.path = path;
129     }
130
131     /**
132      * Get case by name.
133      *
134      * @param caseName
135      *            name of case to search
136      * @return case with given name if present, null otherwise
137      */
138     public ChoiceCaseBuilder getCaseNodeByName(String caseName) {
139         for (ChoiceCaseBuilder addedCase : caseBuilders) {
140             if (addedCase.getQName().getLocalName().equals(caseName)) {
141                 return addedCase;
142             }
143         }
144         return null;
145     }
146
147     /**
148      * Add case node to this choice.
149      *
150      * If node is not declared with 'case' keyword, create new case builder and
151      * make this node child of newly created case.
152      *
153      * @param caseNode
154      *            case node
155      */
156     public void addCase(DataSchemaNodeBuilder caseNode) {
157         QName caseQName = caseNode.getQName();
158         String caseName = caseQName.getLocalName();
159
160         for (ChoiceCaseBuilder addedCase : caseBuilders) {
161             if (addedCase.getQName().getLocalName().equals(caseName)) {
162                 throw new YangParseException(caseNode.getModuleName(), caseNode.getLine(), "Can not add '" + caseNode
163                         + "' to node '" + qname.getLocalName() + "' in module '" + moduleName
164                         + "': case with same name already declared at line " + addedCase.getLine());
165             }
166         }
167
168         if (caseNode instanceof ChoiceCaseBuilder) {
169             caseBuilders.add((ChoiceCaseBuilder) caseNode);
170         } else {
171             ChoiceCaseBuilder caseBuilder = new ChoiceCaseBuilder(caseNode.getModuleName(), caseNode.getLine(),
172                     caseQName, caseNode.getPath());
173             if (caseNode.isAugmenting()) {
174                 // if node is added by augmentation, set case builder augmenting
175                 // as true and node augmenting as false
176                 caseBuilder.setAugmenting(true);
177                 caseNode.setAugmenting(false);
178             }
179             SchemaPath newPath = ParserUtils.createSchemaPath(caseNode.getPath(), caseQName);
180             caseNode.setPath(newPath);
181             caseBuilder.addChildNode(caseNode);
182             caseBuilders.add(caseBuilder);
183         }
184     }
185
186     @Override
187     public String getDescription() {
188         return instance.description;
189     }
190
191     @Override
192     public void setDescription(final String description) {
193         instance.description = description;
194     }
195
196     @Override
197     public String getReference() {
198         return instance.reference;
199     }
200
201     @Override
202     public void setReference(final String reference) {
203         instance.reference = reference;
204     }
205
206     @Override
207     public Status getStatus() {
208         return instance.status;
209     }
210
211     @Override
212     public void setStatus(Status status) {
213         if (status != null) {
214             instance.status = status;
215         }
216     }
217
218     @Override
219     public boolean isAugmenting() {
220         return instance.augmenting;
221     }
222
223     @Override
224     public void setAugmenting(boolean augmenting) {
225         instance.augmenting = augmenting;
226     }
227
228     @Override
229     public boolean isAddedByUses() {
230         return instance.addedByUses;
231     }
232
233     @Override
234     public void setAddedByUses(final boolean addedByUses) {
235         instance.addedByUses = addedByUses;
236     }
237
238     @Override
239     public boolean isConfiguration() {
240         return instance.configuration;
241     }
242
243     @Override
244     public void setConfiguration(boolean configuration) {
245         instance.configuration = configuration;
246     }
247
248     @Override
249     public ConstraintsBuilder getConstraints() {
250         return constraints;
251     }
252
253     @Override
254     public void addAugmentation(AugmentationSchemaBuilder augment) {
255         augmentationBuilders.add(augment);
256     }
257
258     public List<AugmentationSchemaBuilder> getAugmentationBuilders() {
259         return augmentationBuilders;
260     }
261
262     public String getDefaultCase() {
263         return defaultCase;
264     }
265
266     public void setDefaultCase(String defaultCase) {
267         this.defaultCase = defaultCase;
268     }
269
270     @Override
271     public int hashCode() {
272         final int prime = 31;
273         int result = 1;
274         result = prime * result + ((schemaPath == null) ? 0 : schemaPath.hashCode());
275         return result;
276     }
277
278     @Override
279     public boolean equals(Object obj) {
280         if (this == obj) {
281             return true;
282         }
283         if (obj == null) {
284             return false;
285         }
286         if (getClass() != obj.getClass()) {
287             return false;
288         }
289         ChoiceBuilder other = (ChoiceBuilder) obj;
290         if (schemaPath == null) {
291             if (other.schemaPath != null) {
292                 return false;
293             }
294         } else if (!schemaPath.equals(other.schemaPath)) {
295             return false;
296         }
297         if (parentBuilder == null) {
298             if (other.parentBuilder != null) {
299                 return false;
300             }
301         } else if (!parentBuilder.equals(other.parentBuilder)) {
302             return false;
303         }
304         return true;
305     }
306
307     @Override
308     public String toString() {
309         return "choice " + qname.getLocalName();
310     }
311
312     private static final class ChoiceNodeImpl implements ChoiceNode {
313         private final QName qname;
314         private SchemaPath path;
315         private String description;
316         private String reference;
317         private Status status = Status.CURRENT;
318         private boolean augmenting;
319         private boolean addedByUses;
320         private boolean configuration;
321         private ConstraintDefinition constraints;
322         private final Set<ChoiceCaseNode> cases = new HashSet<>();
323         private final Set<AugmentationSchema> augmentations = new HashSet<>();
324         private final List<UnknownSchemaNode> unknownNodes = new ArrayList<>();
325         private String defaultCase;
326
327         private ChoiceNodeImpl(QName qname, SchemaPath path) {
328             this.qname = qname;
329             this.path = path;
330         }
331
332         @Override
333         public QName getQName() {
334             return qname;
335         }
336
337         @Override
338         public SchemaPath getPath() {
339             return path;
340         }
341
342         @Override
343         public String getDescription() {
344             return description;
345         }
346
347         @Override
348         public String getReference() {
349             return reference;
350         }
351
352         @Override
353         public Status getStatus() {
354             return status;
355         }
356
357         @Override
358         public boolean isAugmenting() {
359             return augmenting;
360         }
361
362         @Override
363         public boolean isAddedByUses() {
364             return addedByUses;
365         }
366
367         @Override
368         public boolean isConfiguration() {
369             return configuration;
370         }
371
372         @Override
373         public ConstraintDefinition getConstraints() {
374             return constraints;
375         }
376
377         private void setConstraints(ConstraintDefinition constraints) {
378             this.constraints = constraints;
379         }
380
381         @Override
382         public Set<AugmentationSchema> getAvailableAugmentations() {
383             return Collections.unmodifiableSet(augmentations);
384         }
385
386         private void addAvailableAugmentations(Set<AugmentationSchema> availableAugmentations) {
387             if (availableAugmentations != null) {
388                 this.augmentations.addAll(availableAugmentations);
389             }
390         }
391
392         @Override
393         public List<UnknownSchemaNode> getUnknownSchemaNodes() {
394             return Collections.unmodifiableList(unknownNodes);
395         }
396
397         private void addUnknownSchemaNodes(List<UnknownSchemaNode> unknownSchemaNodes) {
398             if (unknownSchemaNodes != null) {
399                 this.unknownNodes.addAll(unknownSchemaNodes);
400             }
401         }
402
403         @Override
404         public Set<ChoiceCaseNode> getCases() {
405             return Collections.unmodifiableSet(cases);
406         }
407
408         @Override
409         public ChoiceCaseNode getCaseNodeByName(final QName name) {
410             if (name == null) {
411                 throw new IllegalArgumentException("Choice Case QName cannot be NULL!");
412             }
413             for (final ChoiceCaseNode caseNode : cases) {
414                 if (caseNode != null && name.equals(caseNode.getQName())) {
415                     return caseNode;
416                 }
417             }
418             return null;
419         }
420
421         @Override
422         public ChoiceCaseNode getCaseNodeByName(final String name) {
423             if (name == null) {
424                 throw new IllegalArgumentException("Choice Case string Name cannot be NULL!");
425             }
426             for (final ChoiceCaseNode caseNode : cases) {
427                 if (caseNode != null && (caseNode.getQName() != null)
428                         && name.equals(caseNode.getQName().getLocalName())) {
429                     return caseNode;
430                 }
431             }
432             return null;
433         }
434
435         private void addCases(Set<ChoiceCaseNode> cases) {
436             if (cases != null) {
437                 this.cases.addAll(cases);
438             }
439         }
440
441         @Override
442         public String getDefaultCase() {
443             return defaultCase;
444         }
445
446         private void setDefaultCase(String defaultCase) {
447             this.defaultCase = defaultCase;
448         }
449
450         @Override
451         public int hashCode() {
452             final int prime = 31;
453             int result = 1;
454             result = prime * result + ((qname == null) ? 0 : qname.hashCode());
455             result = prime * result + ((path == null) ? 0 : path.hashCode());
456             return result;
457         }
458
459         @Override
460         public boolean equals(Object obj) {
461             if (this == obj) {
462                 return true;
463             }
464             if (obj == null) {
465                 return false;
466             }
467             if (getClass() != obj.getClass()) {
468                 return false;
469             }
470             ChoiceNodeImpl other = (ChoiceNodeImpl) obj;
471             if (qname == null) {
472                 if (other.qname != null) {
473                     return false;
474                 }
475             } else if (!qname.equals(other.qname)) {
476                 return false;
477             }
478             if (path == null) {
479                 if (other.path != null) {
480                     return false;
481                 }
482             } else if (!path.equals(other.path)) {
483                 return false;
484             }
485             return true;
486         }
487
488         @Override
489         public String toString() {
490             StringBuilder sb = new StringBuilder(ChoiceNodeImpl.class.getSimpleName());
491             sb.append("[");
492             sb.append("qname=" + qname);
493             sb.append("]");
494             return sb.toString();
495         }
496     }
497
498 }