Bug 5884: Augmenting a choice without a case results in no getter
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / effective / AbstractEffectiveDocumentedDataNodeContainer.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.collect.ImmutableMap;
11 import com.google.common.collect.ImmutableSet;
12 import java.util.Collection;
13 import java.util.HashSet;
14 import java.util.LinkedHashMap;
15 import java.util.LinkedHashSet;
16 import java.util.Map;
17 import java.util.Objects;
18 import java.util.Set;
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.ChoiceSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
24 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
26 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.UsesNode;
28 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
29 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
30 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
31 import org.opendaylight.yangtools.yang.parser.spi.source.AugmentToChoiceNamespace;
32 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangValidationBundles;
33
34 abstract class AbstractEffectiveDocumentedDataNodeContainer<A, D extends DeclaredStatement<A>>
35         extends AbstractEffectiveDocumentedNode<A, D> implements
36         DataNodeContainer {
37
38     private final Map<QName, DataSchemaNode> childNodes;
39     private final Set<GroupingDefinition> groupings;
40     private final Set<UsesNode> uses;
41     private final Set<TypeDefinition<?>> typeDefinitions;
42     private final Set<DataSchemaNode> publicChildNodes;
43
44     protected AbstractEffectiveDocumentedDataNodeContainer(
45             final StmtContext<A, D, ?> ctx) {
46         super(ctx);
47
48         Collection<? extends EffectiveStatement<?, ?>> effectiveSubstatements = effectiveSubstatements();
49
50         Map<QName, DataSchemaNode> mutableChildNodes = new LinkedHashMap<>();
51         Set<GroupingDefinition> mutableGroupings = new HashSet<>();
52         Set<UsesNode> mutableUses = new HashSet<>();
53         Set<TypeDefinition<?>> mutableTypeDefinitions = new LinkedHashSet<>();
54         Set<DataSchemaNode> mutablePublicChildNodes = new LinkedHashSet<>();
55
56         for (EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements) {
57             if (effectiveStatement instanceof DataSchemaNode) {
58                 final DataSchemaNode dataSchemaNode = (DataSchemaNode) effectiveStatement;
59                 if (!mutableChildNodes.containsKey(dataSchemaNode.getQName())) {
60                     /**
61                      * Add case short hand when augmenting choice with short hand
62                      **/
63                     if (this instanceof AugmentationSchema && !(effectiveStatement instanceof ChoiceCaseNode ||
64                             effectiveStatement instanceof ChoiceSchemaNode) &&
65                             (YangValidationBundles.SUPPORTED_CASE_SHORTHANDS.contains(effectiveStatement.statementDefinition())) &&
66                             Boolean.TRUE.equals(ctx.getFromNamespace(AugmentToChoiceNamespace.class, ctx))) {
67                         final CaseShorthandImpl caseShorthand = new CaseShorthandImpl(dataSchemaNode);
68                         mutableChildNodes.put(caseShorthand.getQName(), caseShorthand);
69                         mutablePublicChildNodes.add(caseShorthand);
70                     } else {
71                         mutableChildNodes.put(dataSchemaNode.getQName(), dataSchemaNode);
72                         mutablePublicChildNodes.add(dataSchemaNode);
73                     }
74                 } else {
75                     throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, effectiveStatement);
76                 }
77             }
78             if (effectiveStatement instanceof UsesNode) {
79                 UsesNode usesNode = (UsesNode) effectiveStatement;
80                 if (!mutableUses.contains(usesNode)) {
81                     mutableUses.add(usesNode);
82                 } else {
83                     throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, effectiveStatement);
84                 }
85             }
86             if (effectiveStatement instanceof TypeDefEffectiveStatementImpl) {
87                 TypeDefEffectiveStatementImpl typeDef = (TypeDefEffectiveStatementImpl) effectiveStatement;
88                 TypeDefinition<?> type = typeDef.getTypeDefinition();
89                 if (!mutableTypeDefinitions.contains(type)) {
90                     mutableTypeDefinitions.add(type);
91                 } else {
92                     throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, effectiveStatement);
93                 }
94             }
95             if (effectiveStatement instanceof GroupingDefinition) {
96                 GroupingDefinition grp = (GroupingDefinition) effectiveStatement;
97                 if (!mutableGroupings.contains(grp)) {
98                     mutableGroupings.add(grp);
99                 } else {
100                     throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, effectiveStatement);
101                 }
102             }
103         }
104
105         this.childNodes = ImmutableMap.copyOf(mutableChildNodes);
106         this.groupings = ImmutableSet.copyOf(mutableGroupings);
107         this.publicChildNodes = ImmutableSet.copyOf(mutablePublicChildNodes);
108         this.typeDefinitions = ImmutableSet.copyOf(mutableTypeDefinitions);
109         this.uses = ImmutableSet.copyOf(mutableUses);
110     }
111
112     @Override
113     public final Set<TypeDefinition<?>> getTypeDefinitions() {
114         return typeDefinitions;
115     }
116
117     @Override
118     public final Set<DataSchemaNode> getChildNodes() {
119         return publicChildNodes;
120     }
121
122     @Override
123     public final Set<GroupingDefinition> getGroupings() {
124         return groupings;
125     }
126
127     @Override
128     public final DataSchemaNode getDataChildByName(final QName name) {
129         // Child nodes are keyed by their container name, so we can do a direct
130         // lookup
131         return childNodes.get(name);
132     }
133
134     @Override
135     public final DataSchemaNode getDataChildByName(final String name) {
136         for (DataSchemaNode node : childNodes.values()) {
137             if (node.getQName().getLocalName().equals(name)) {
138                 return node;
139             }
140         }
141         return null;
142     }
143
144     @Override
145     public Set<UsesNode> getUses() {
146         return uses;
147     }
148
149 }