Merge "Bug 584 - Milestone : Increasing unit test coverage, from 44.9% to 60%"
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / builder / util / AbstractDocumentedDataNodeContainerBuilder.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
3  * This program and the accompanying materials are made available under the
4  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
5  * and is available at http://www.eclipse.org/legal/epl-v10.html
6  */
7 package org.opendaylight.yangtools.yang.parser.builder.util;
8
9 import java.util.ArrayList;
10 import java.util.HashSet;
11 import java.util.LinkedHashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Set;
15 import java.util.TreeSet;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
18 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
19 import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
20 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
21 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
22 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
23 import org.opendaylight.yangtools.yang.model.api.UsesNode;
24 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
25 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
26 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
27 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
28 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
29 import org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils;
30 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
31
32 /**
33  * Basic implementation of DataNodeContainerBuilder.
34  */
35 public abstract class AbstractDocumentedDataNodeContainerBuilder extends AbstractDocumentedNodeBuilder implements DataNodeContainerBuilder {
36     protected final QName qname;
37
38     private final Map<QName, DataSchemaNode> childNodes = new LinkedHashMap<>();
39     private final List<DataSchemaNodeBuilder> addedChildNodes = new ArrayList<>();
40
41     private final Set<GroupingDefinition> groupings = new TreeSet<>(Comparators.SCHEMA_NODE_COMP);
42     private final Set<GroupingBuilder> addedGroupings = new HashSet<>();
43
44     private final Set<TypeDefinition<?>> typedefs = new TreeSet<>(Comparators.SCHEMA_NODE_COMP);
45     private final Set<TypeDefinitionBuilder> addedTypedefs = new HashSet<>();
46
47     private final Set<UsesNode> usesNodes = new HashSet<>();
48     private final List<UsesNodeBuilder> addedUsesNodes = new ArrayList<>();
49
50     protected AbstractDocumentedDataNodeContainerBuilder(final String moduleName, final int line, final QName qname) {
51         super(moduleName, line);
52         this.qname = qname;
53     }
54
55     protected AbstractDocumentedDataNodeContainerBuilder(final String moduleName, final int line, final QName qname, final SchemaPath path, final DataNodeContainer base) {
56         super(moduleName, line);
57         this.qname = qname;
58
59         // We do copy of child nodes with namespace change
60         // FIXME: Copy should be part of builder API so impl we prevent
61         // cyclic dependencies and each builder carries its own semantic for copy.
62         addedChildNodes.addAll(BuilderUtils.wrapChildNodes(moduleName, line, base.getChildNodes(), path, qname));
63         addedGroupings.addAll(BuilderUtils.wrapGroupings(moduleName, line, base.getGroupings(), path, qname));
64         addedTypedefs.addAll(BuilderUtils.wrapTypedefs(moduleName, line, base, path, qname));
65         // FIXME: unkownSchemaNodes should be available in DataNodeContainer
66         // addedUnknownNodes.addAll(BuilderUtils.wrapUnknownNodes(moduleName,
67         // line, base.getUnknownSchemaNodes(), path, qname));
68         usesNodes.addAll(base.getUses());
69
70         if (base instanceof DocumentedNode) {
71             DocumentedNode node = (DocumentedNode) base;
72             setDescription(node.getDescription());
73             setReference(node.getReference());
74             setStatus(node.getStatus());
75         }
76     }
77
78     @Override
79     public final QName getQName() {
80         return qname;
81     }
82
83     @Override
84     public final Map<QName, DataSchemaNode> getChildNodes() {
85         return childNodes;
86     }
87
88     @Override
89     public final List<DataSchemaNodeBuilder> getChildNodeBuilders() {
90         return addedChildNodes;
91     }
92
93     @Override
94     public final DataSchemaNodeBuilder getDataChildByName(final String name) {
95         for (DataSchemaNodeBuilder child : addedChildNodes) {
96             if (child.getQName().getLocalName().equals(name)) {
97                 return child;
98             }
99         }
100         return null;
101     }
102
103     @Override
104     public final void addChildNode(final DataSchemaNodeBuilder child) {
105         checkIsPresent(child);
106         addedChildNodes.add(child);
107     }
108
109     @Override
110     public final void addChildNode(final int index, final DataSchemaNodeBuilder child) {
111         checkIsPresent(child);
112         if (index > addedChildNodes.size()) {
113             addedChildNodes.add(child);
114         } else {
115             addedChildNodes.add(index, child);
116         }
117     }
118
119     private void checkIsPresent(final DataSchemaNodeBuilder child) {
120         for (DataSchemaNodeBuilder addedChildNode : addedChildNodes) {
121             if (addedChildNode.getQName().equals(child.getQName())) {
122                 throw new YangParseException(child.getModuleName(), child.getLine(), String.format(
123                         "Can not add '%s' to '%s' in module '%s': node with same name already declared at line %d",
124                         child, this, getModuleName(), addedChildNode.getLine()));
125             }
126         }
127     }
128
129     @Override
130     public final void addChildNodeToContext(final DataSchemaNodeBuilder child) {
131         addedChildNodes.add(child);
132     }
133
134     @Override
135     public final void addChildNode(final DataSchemaNode child) {
136         checkNotSealed();
137         QName childName = child.getQName();
138         if (childNodes.containsKey(childName)) {
139             throw new YangParseException(getModuleName(), getLine(), String.format(
140                     "Can not add '%s' to '%s' in module '%s': node with same name already declared", child, this,
141                     getModuleName()));
142         }
143         childNodes.put(childName, child);
144     }
145
146     @Override
147     public final Set<GroupingDefinition> getGroupings() {
148         return groupings;
149     }
150
151     @Override
152     public final Set<GroupingBuilder> getGroupingBuilders() {
153         return addedGroupings;
154     }
155
156     @Override
157     public void addGrouping(final GroupingBuilder grouping) {
158         checkNotSealed();
159         QName groupingName = grouping.getQName();
160         for (GroupingBuilder addedGrouping : addedGroupings) {
161             if (addedGrouping.getQName().equals(groupingName)) {
162                 throw new YangParseException(grouping.getModuleName(), grouping.getLine(), String.format(
163                         "Can not add '%s': grouping with same name already declared in module '%s' at line %d",
164                         grouping, getModuleName(), addedGrouping.getLine()));
165             }
166         }
167         addedGroupings.add(grouping);
168     }
169
170     @Override
171     public final Set<TypeDefinition<?>> getTypeDefinitions() {
172         return typedefs;
173     }
174
175     public final Set<UsesNode> getUsesNodes() {
176         return usesNodes;
177     }
178
179     @Override
180     public final List<UsesNodeBuilder> getUsesNodeBuilders() {
181         return addedUsesNodes;
182     }
183
184     @Override
185     public final void addUsesNode(final UsesNodeBuilder usesNode) {
186         checkNotSealed();
187         addedUsesNodes.add(usesNode);
188     }
189
190
191     @Override
192     public final Set<TypeDefinitionBuilder> getTypeDefinitionBuilders() {
193         return addedTypedefs;
194     }
195
196     @Override
197     public void addTypedef(final TypeDefinitionBuilder type) {
198         checkNotSealed();
199         String typeName = type.getQName().getLocalName();
200         for (TypeDefinitionBuilder addedTypedef : addedTypedefs) {
201             if (addedTypedef.getQName().getLocalName().equals(typeName)) {
202                 throw new YangParseException(getModuleName(), type.getLine(), "Can not add typedef '" + typeName
203                         + "': typedef with same name already declared at line " + addedTypedef.getLine());
204             }
205         }
206         addedTypedefs.add(type);
207     }
208
209     protected abstract String getStatementName();
210
211     protected void buildChildren() {
212         checkNotSealed();
213         seal();
214
215         for (DataSchemaNodeBuilder node : addedChildNodes) {
216             childNodes.put(node.getQName(), node.build());
217         }
218
219         for (GroupingBuilder builder : addedGroupings) {
220             groupings.add(builder.build());
221         }
222
223         for (TypeDefinitionBuilder entry : addedTypedefs) {
224             typedefs.add(entry.build());
225         }
226
227         for (UsesNodeBuilder builder : addedUsesNodes) {
228             usesNodes.add(builder.build());
229         }
230     }
231
232 }