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