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