Fixed resolving of schema path and qname for nodes added by augmentation.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / builder / impl / ModuleBuilder.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.Deque;
15 import java.util.HashSet;
16 import java.util.LinkedHashSet;
17 import java.util.LinkedList;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.TreeMap;
22 import java.util.TreeSet;
23
24 import org.opendaylight.yangtools.yang.common.QName;
25 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
26 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.Deviation;
28 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
29 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
30 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
31 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.Module;
33 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
34 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
35 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
36 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
37 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
38 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.UsesNode;
40 import org.opendaylight.yangtools.yang.parser.builder.api.AbstractDataNodeContainerBuilder;
41 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
42 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
43 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
44 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
45 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
46 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
47 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
48 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
49 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
50 import org.opendaylight.yangtools.yang.parser.util.Comparators;
51 import org.opendaylight.yangtools.yang.parser.util.RefineHolder;
52 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
53
54 /**
55  * Builder of Module object. If this module is dependent on external
56  * module/modules, these dependencies must be resolved before module is built,
57  * otherwise result may not be valid.
58  */
59 public class ModuleBuilder extends AbstractDataNodeContainerBuilder {
60
61     private final ModuleImpl instance;
62     private final String name;
63     private final SchemaPath schemaPath;
64     private URI namespace;
65     private String prefix;
66     private Date revision;
67
68     private final Deque<Builder> actualPath = new LinkedList<Builder>();
69     private final Set<TypeAwareBuilder> dirtyNodes = new HashSet<TypeAwareBuilder>();
70
71     private final Set<ModuleImport> imports = new HashSet<ModuleImport>();
72     private final List<AugmentationSchemaBuilder> addedAugments = new ArrayList<AugmentationSchemaBuilder>();
73     private final List<AugmentationSchemaBuilder> allAugments = new ArrayList<AugmentationSchemaBuilder>();
74     private final Set<UsesNodeBuilder> addedUsesNodes = new HashSet<UsesNodeBuilder>();
75     private final List<UsesNodeBuilder> allUsesNodes = new ArrayList<UsesNodeBuilder>();
76     private final Set<RpcDefinitionBuilder> addedRpcs = new HashSet<RpcDefinitionBuilder>();
77     private final Set<NotificationBuilder> addedNotifications = new HashSet<NotificationBuilder>();
78     private final Set<IdentitySchemaNodeBuilder> addedIdentities = new HashSet<IdentitySchemaNodeBuilder>();
79     private final Set<FeatureBuilder> addedFeatures = new HashSet<FeatureBuilder>();
80     private final Set<DeviationBuilder> addedDeviations = new HashSet<DeviationBuilder>();
81     private final Set<TypeDefinitionBuilder> addedTypedefs = new HashSet<TypeDefinitionBuilder>();
82     private final List<ExtensionBuilder> addedExtensions = new ArrayList<ExtensionBuilder>();
83     private final List<UnknownSchemaNodeBuilder> allUnknownNodes = new ArrayList<UnknownSchemaNodeBuilder>();
84
85     public ModuleBuilder(final String name) {
86         super(name, 0, null);
87         this.name = name;
88         schemaPath = new SchemaPath(Collections.<QName> emptyList(), true);
89         instance = new ModuleImpl(name);
90         actualPath.push(this);
91     }
92
93     /**
94      * Build new Module object based on this builder.
95      */
96     @Override
97     public Module build() {
98         instance.setPrefix(prefix);
99         instance.setRevision(revision);
100         instance.setImports(imports);
101         instance.setNamespace(namespace);
102
103         // TYPEDEFS
104         final Set<TypeDefinition<?>> typedefs = new TreeSet<TypeDefinition<?>>(Comparators.SCHEMA_NODE_COMP);
105         for (TypeDefinitionBuilder tdb : addedTypedefs) {
106             typedefs.add(tdb.build());
107         }
108         instance.setTypeDefinitions(typedefs);
109
110         // CHILD NODES
111         final Map<QName, DataSchemaNode> children = new TreeMap<QName, DataSchemaNode>(Comparators.QNAME_COMP);
112         for (DataSchemaNodeBuilder child : addedChildNodes) {
113             children.put(child.getQName(), child.build());
114         }
115         instance.setChildNodes(children);
116
117         // GROUPINGS
118         final Set<GroupingDefinition> groupings = new TreeSet<GroupingDefinition>(Comparators.SCHEMA_NODE_COMP);
119         for (GroupingBuilder gb : addedGroupings) {
120             groupings.add(gb.build());
121         }
122         instance.setGroupings(groupings);
123
124         // USES
125         final Set<UsesNode> usesDefinitions = new HashSet<UsesNode>();
126         for (UsesNodeBuilder unb : addedUsesNodes) {
127             usesDefinitions.add(unb.build());
128         }
129         instance.setUses(usesDefinitions);
130
131         // FEATURES
132         final Set<FeatureDefinition> features = new TreeSet<FeatureDefinition>(Comparators.SCHEMA_NODE_COMP);
133         for (FeatureBuilder fb : addedFeatures) {
134             features.add(fb.build());
135         }
136         instance.setFeatures(features);
137
138         // NOTIFICATIONS
139         final Set<NotificationDefinition> notifications = new TreeSet<NotificationDefinition>(
140                 Comparators.SCHEMA_NODE_COMP);
141         for (NotificationBuilder entry : addedNotifications) {
142             notifications.add(entry.build());
143         }
144         instance.setNotifications(notifications);
145
146         // AUGMENTATIONS
147         final Set<AugmentationSchema> augmentations = new HashSet<AugmentationSchema>();
148         for (AugmentationSchemaBuilder builder : addedAugments) {
149             augmentations.add(builder.build());
150         }
151         instance.setAugmentations(augmentations);
152
153         // RPCs
154         final Set<RpcDefinition> rpcs = new TreeSet<RpcDefinition>(Comparators.SCHEMA_NODE_COMP);
155         for (RpcDefinitionBuilder rpc : addedRpcs) {
156             rpcs.add(rpc.build());
157         }
158         instance.setRpcs(rpcs);
159
160         // DEVIATIONS
161         final Set<Deviation> deviations = new HashSet<Deviation>();
162         for (DeviationBuilder entry : addedDeviations) {
163             deviations.add(entry.build());
164         }
165         instance.setDeviations(deviations);
166
167         // EXTENSIONS
168         final List<ExtensionDefinition> extensions = new ArrayList<ExtensionDefinition>();
169         for (ExtensionBuilder eb : addedExtensions) {
170             extensions.add(eb.build());
171         }
172         Collections.sort(extensions, Comparators.SCHEMA_NODE_COMP);
173         instance.setExtensionSchemaNodes(extensions);
174
175         // IDENTITIES
176         final Set<IdentitySchemaNode> identities = new TreeSet<IdentitySchemaNode>(Comparators.SCHEMA_NODE_COMP);
177         for (IdentitySchemaNodeBuilder id : addedIdentities) {
178             identities.add(id.build());
179         }
180         instance.setIdentities(identities);
181
182         // UNKNOWN NODES
183         final List<UnknownSchemaNode> unknownNodes = new ArrayList<UnknownSchemaNode>();
184         for (UnknownSchemaNodeBuilder unb : addedUnknownNodes) {
185             unknownNodes.add(unb.build());
186         }
187         instance.setUnknownSchemaNodes(unknownNodes);
188
189         return instance;
190     }
191
192     public boolean isAllUsesDataCollected() {
193         for (UsesNodeBuilder usesNode : allUsesNodes) {
194             if (!usesNode.isDataCollected()) {
195                 return false;
196             }
197         }
198         return true;
199     }
200
201     @Override
202     public void setParent(Builder parent) {
203         throw new YangParseException(name, 0, "Can not set parent to module");
204     }
205
206     @Override
207     public SchemaPath getPath() {
208         return schemaPath;
209     }
210
211     @Override
212     public Set<TypeDefinitionBuilder> getTypeDefinitionBuilders() {
213         return addedTypedefs;
214     }
215
216     public void enterNode(final Builder node) {
217         actualPath.push(node);
218     }
219
220     public void exitNode() {
221         actualPath.pop();
222     }
223
224     public Builder getActualNode() {
225         if (actualPath.isEmpty()) {
226             return null;
227         } else {
228             return actualPath.peekFirst();
229         }
230     }
231
232     public Builder getActualParent() {
233         if (actualPath.size() < 2) {
234             return null;
235         } else {
236             Builder builderChild = actualPath.removeFirst();
237             Builder builderParent = actualPath.peekFirst();
238             actualPath.addFirst(builderChild);
239             return builderParent;
240         }
241     }
242
243     public Set<TypeAwareBuilder> getDirtyNodes() {
244         return dirtyNodes;
245     }
246
247     public List<AugmentationSchemaBuilder> getAllAugments() {
248         return allAugments;
249     }
250
251     public Set<IdentitySchemaNodeBuilder> getIdentities() {
252         return addedIdentities;
253     }
254
255     public List<UsesNodeBuilder> getAllUsesNodes() {
256         return allUsesNodes;
257     }
258
259     public Set<DeviationBuilder> getDeviations() {
260         return addedDeviations;
261     }
262
263     public List<ExtensionBuilder> getExtensions() {
264         return addedExtensions;
265     }
266
267     public List<UnknownSchemaNodeBuilder> getAllUnknownNodes() {
268         return allUnknownNodes;
269     }
270
271     public String getName() {
272         return name;
273     }
274
275     public URI getNamespace() {
276         return namespace;
277     }
278
279     public void setNamespace(final URI namespace) {
280         this.namespace = namespace;
281     }
282
283     public String getPrefix() {
284         return prefix;
285     }
286
287     public Date getRevision() {
288         return revision;
289     }
290
291     public void markActualNodeDirty() {
292         final TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) getActualNode();
293         dirtyNodes.add(nodeBuilder);
294     }
295
296     public void setRevision(final Date revision) {
297         this.revision = revision;
298     }
299
300     public void setPrefix(final String prefix) {
301         this.prefix = prefix;
302     }
303
304     public void setYangVersion(final String yangVersion) {
305         instance.setYangVersion(yangVersion);
306     }
307
308     public void setDescription(final String description) {
309         instance.setDescription(description);
310     }
311
312     public void setReference(final String reference) {
313         instance.setReference(reference);
314     }
315
316     public void setOrganization(final String organization) {
317         instance.setOrganization(organization);
318     }
319
320     public void setContact(final String contact) {
321         instance.setContact(contact);
322     }
323
324     public boolean addModuleImport(final String moduleName, final Date revision, final String prefix) {
325         final ModuleImport moduleImport = createModuleImport(moduleName, revision, prefix);
326         return imports.add(moduleImport);
327     }
328
329     public Set<ModuleImport> getModuleImports() {
330         return imports;
331     }
332
333     public ExtensionBuilder addExtension(final QName qname, final int line) {
334         final String extName = qname.getLocalName();
335         for (ExtensionBuilder addedExtension : addedExtensions) {
336             if (addedExtension.getQName().getLocalName().equals(extName)) {
337                 raiseYangParserException("extension", "node", extName, line, addedExtension.getLine());
338             }
339         }
340         final ExtensionBuilder builder = new ExtensionBuilder(name, line, qname);
341         addedExtensions.add(builder);
342         return builder;
343     }
344
345     public ContainerSchemaNodeBuilder addContainerNode(final int line, final QName qname, final SchemaPath schemaPath) {
346         final ContainerSchemaNodeBuilder builder = new ContainerSchemaNodeBuilder(name, line, qname, schemaPath);
347
348         Builder parent = getActualNode();
349         builder.setParent(parent);
350         addChildToParent(parent, builder, qname.getLocalName());
351
352         return builder;
353     }
354
355     public ListSchemaNodeBuilder addListNode(final int line, final QName qname, final SchemaPath schemaPath) {
356         final ListSchemaNodeBuilder builder = new ListSchemaNodeBuilder(name, line, qname, schemaPath);
357
358         Builder parent = getActualNode();
359         builder.setParent(parent);
360         addChildToParent(parent, builder, qname.getLocalName());
361
362         return builder;
363     }
364
365     public LeafSchemaNodeBuilder addLeafNode(final int line, final QName qname, final SchemaPath schemaPath) {
366         final LeafSchemaNodeBuilder builder = new LeafSchemaNodeBuilder(name, line, qname, schemaPath);
367
368         Builder parent = getActualNode();
369         builder.setParent(parent);
370         addChildToParent(parent, builder, qname.getLocalName());
371
372         return builder;
373     }
374
375     public LeafListSchemaNodeBuilder addLeafListNode(final int line, final QName qname, final SchemaPath schemaPath) {
376         final LeafListSchemaNodeBuilder builder = new LeafListSchemaNodeBuilder(name, line, qname, schemaPath);
377
378         Builder parent = getActualNode();
379         builder.setParent(parent);
380         addChildToParent(parent, builder, qname.getLocalName());
381
382         return builder;
383     }
384
385     public GroupingBuilder addGrouping(final int line, final QName qname) {
386         final GroupingBuilder builder = new GroupingBuilderImpl(name, line, qname);
387
388         Builder parent = getActualNode();
389         builder.setParent(parent);
390
391         String groupingName = qname.getLocalName();
392         if (parent.equals(this)) {
393             for (GroupingBuilder addedGrouping : addedGroupings) {
394                 if (addedGrouping.getQName().getLocalName().equals(groupingName)) {
395                     raiseYangParserException("", "Grouping", groupingName, line, addedGrouping.getLine());
396                 }
397             }
398             addedGroupings.add(builder);
399         } else {
400             if (parent instanceof DataNodeContainerBuilder) {
401                 DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parent;
402                 for (GroupingBuilder addedGrouping : parentNode.getGroupingBuilders()) {
403                     if (addedGrouping.getQName().getLocalName().equals(groupingName)) {
404                         raiseYangParserException("", "Grouping", groupingName, line, addedGrouping.getLine());
405                     }
406                 }
407                 parentNode.addGrouping(builder);
408             } else if (parent instanceof RpcDefinitionBuilder) {
409                 RpcDefinitionBuilder parentNode = (RpcDefinitionBuilder) parent;
410                 for (GroupingBuilder child : parentNode.getGroupings()) {
411                     if (child.getQName().getLocalName().equals(groupingName)) {
412                         raiseYangParserException("", "Grouping", groupingName, line, child.getLine());
413                     }
414                 }
415                 parentNode.addGrouping(builder);
416             } else {
417                 throw new YangParseException(name, line, "Unresolved parent of grouping " + groupingName);
418             }
419         }
420
421         return builder;
422     }
423
424     public AugmentationSchemaBuilder addAugment(final int line, final String augmentTargetStr) {
425         final AugmentationSchemaBuilder builder = new AugmentationSchemaBuilderImpl(name, line, augmentTargetStr);
426
427         Builder parent = getActualNode();
428         builder.setParent(parent);
429
430         if (parent.equals(this)) {
431             // augment can be declared only under 'module' ...
432             addedAugments.add(builder);
433         } else {
434             // ... or 'uses' statement
435             if (parent instanceof UsesNodeBuilder) {
436                 ((UsesNodeBuilder) parent).addAugment(builder);
437             } else {
438                 throw new YangParseException(name, line, "Augment can be declared only under module or uses statement.");
439             }
440         }
441         allAugments.add(builder);
442
443         return builder;
444     }
445
446     @Override
447     public Set<UsesNodeBuilder> getUsesNodes() {
448         return addedUsesNodes;
449     }
450
451     @Override
452     public void addUsesNode(UsesNodeBuilder usesBuilder) {
453         addedUsesNodes.add(usesBuilder);
454         allUsesNodes.add(usesBuilder);
455     }
456
457     public UsesNodeBuilder addUsesNode(final int line, final String groupingPathStr) {
458         final UsesNodeBuilder usesBuilder = new UsesNodeBuilderImpl(name, line, groupingPathStr);
459
460         Builder parent = getActualNode();
461         usesBuilder.setParent(parent);
462
463         if (parent.equals(this)) {
464             addedUsesNodes.add(usesBuilder);
465         } else {
466             if (!(parent instanceof DataNodeContainerBuilder)) {
467                 throw new YangParseException(name, line, "Unresolved parent of uses '" + groupingPathStr + "'.");
468             }
469             ((DataNodeContainerBuilder) parent).addUsesNode(usesBuilder);
470         }
471         if(parent instanceof AugmentationSchemaBuilder) {
472             usesBuilder.setAugmenting(true);
473             usesBuilder.setParentAugment((AugmentationSchemaBuilder)parent);
474         }
475
476         allUsesNodes.add(usesBuilder);
477         return usesBuilder;
478     }
479
480     public void addRefine(final RefineHolder refine) {
481         final Builder parent = getActualNode();
482         if (!(parent instanceof UsesNodeBuilder)) {
483             throw new YangParseException(name, refine.getLine(), "refine can be defined only in uses statement");
484         }
485         ((UsesNodeBuilder) parent).addRefine(refine);
486         refine.setParent(parent);
487     }
488
489     public RpcDefinitionBuilder addRpc(final int line, final QName qname) {
490         Builder parent = getActualNode();
491         if (!(parent.equals(this))) {
492             throw new YangParseException(name, line, "rpc can be defined only in module or submodule");
493         }
494
495         final RpcDefinitionBuilder rpcBuilder = new RpcDefinitionBuilder(name, line, qname);
496         rpcBuilder.setParent(parent);
497
498         String rpcName = qname.getLocalName();
499         for (RpcDefinitionBuilder rpc : addedRpcs) {
500             if (rpc.getQName().getLocalName().equals(rpcName)) {
501                 raiseYangParserException("", "rpc", rpcName, line, rpc.getLine());
502             }
503         }
504         for (DataSchemaNodeBuilder addedChild : addedChildNodes) {
505             if (addedChild.getQName().getLocalName().equals(rpcName)) {
506                 raiseYangParserException("rpc", "node", rpcName, line, addedChild.getLine());
507             }
508         }
509         for (NotificationBuilder addedNotification : addedNotifications) {
510             if (addedNotification.getQName().getLocalName().equals(rpcName)) {
511                 raiseYangParserException("rpc", "notification", rpcName, line, addedNotification.getLine());
512             }
513         }
514         addedRpcs.add(rpcBuilder);
515         return rpcBuilder;
516     }
517
518     public ContainerSchemaNodeBuilder addRpcInput(final int line, final QName qname, final SchemaPath schemaPath) {
519         final Builder parent = getActualNode();
520         if (!(parent instanceof RpcDefinitionBuilder)) {
521             throw new YangParseException(name, line, "input can be defined only in rpc statement");
522         }
523         final RpcDefinitionBuilder rpc = (RpcDefinitionBuilder) parent;
524
525         final ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(name, line, qname, schemaPath);
526         inputBuilder.setParent(rpc);
527
528         rpc.setInput(inputBuilder);
529         return inputBuilder;
530     }
531
532     public ContainerSchemaNodeBuilder addRpcOutput(final SchemaPath schemaPath, final QName qname, final int line) {
533         final Builder parent = getActualNode();
534         if (!(parent instanceof RpcDefinitionBuilder)) {
535             throw new YangParseException(name, line, "output can be defined only in rpc statement");
536         }
537         final RpcDefinitionBuilder rpc = (RpcDefinitionBuilder) parent;
538
539         final ContainerSchemaNodeBuilder outputBuilder = new ContainerSchemaNodeBuilder(name, line, qname, schemaPath);
540         outputBuilder.setParent(rpc);
541
542         rpc.setOutput(outputBuilder);
543         return outputBuilder;
544     }
545
546     public NotificationBuilder addNotification(final int line, final QName qname) {
547         final Builder parent = getActualNode();
548         if (!(parent.equals(this))) {
549             throw new YangParseException(name, line, "notification can be defined only in module or submodule");
550         }
551
552         String notificationName = qname.getLocalName();
553         for (NotificationBuilder nb : addedNotifications) {
554             if (nb.getQName().equals(qname)) {
555                 raiseYangParserException("", "notification", notificationName, line, nb.getLine());
556             }
557         }
558         for (RpcDefinitionBuilder rpc : addedRpcs) {
559             if (rpc.getQName().getLocalName().equals(notificationName)) {
560                 raiseYangParserException("notification", "rpc", notificationName, line, rpc.getLine());
561             }
562         }
563         for (DataSchemaNodeBuilder addedChild : addedChildNodes) {
564             if (addedChild.getQName().getLocalName().equals(notificationName)) {
565                 raiseYangParserException("notification", "node", notificationName, line, addedChild.getLine());
566             }
567         }
568
569         final NotificationBuilder builder = new NotificationBuilder(name, line, qname);
570         builder.setParent(parent);
571         addedNotifications.add(builder);
572
573         return builder;
574     }
575
576     public FeatureBuilder addFeature(final int line, final QName qname) {
577         Builder parent = getActualNode();
578         if (!(parent.equals(this))) {
579             throw new YangParseException(name, line, "feature can be defined only in module or submodule");
580         }
581
582         final FeatureBuilder builder = new FeatureBuilder(name, line, qname);
583         builder.setParent(parent);
584
585         String featureName = qname.getLocalName();
586         for (FeatureBuilder addedFeature : addedFeatures) {
587             if (addedFeature.getQName().getLocalName().equals(featureName)) {
588                 raiseYangParserException("", "feature", featureName, line, addedFeature.getLine());
589             }
590         }
591         addedFeatures.add(builder);
592         return builder;
593     }
594
595     public ChoiceBuilder addChoice(final int line, final QName qname) {
596         final ChoiceBuilder builder = new ChoiceBuilder(name, line, qname);
597
598         Builder parent = getActualNode();
599         builder.setParent(parent);
600         addChildToParent(parent, builder, qname.getLocalName());
601
602         return builder;
603     }
604
605     public ChoiceCaseBuilder addCase(final int line, final QName qname) {
606         Builder parent = getActualNode();
607         if (parent == null || parent.equals(this)) {
608             throw new YangParseException(name, line, "'case' parent not found");
609         }
610
611         final ChoiceCaseBuilder builder = new ChoiceCaseBuilder(name, line, qname);
612         builder.setParent(parent);
613
614         if (parent instanceof ChoiceBuilder) {
615             ((ChoiceBuilder) parent).addCase(builder);
616         } else if (parent instanceof AugmentationSchemaBuilder) {
617             ((AugmentationSchemaBuilder) parent).addChildNode(builder);
618         } else {
619             throw new YangParseException(name, line, "Unresolved parent of 'case' " + qname.getLocalName());
620         }
621
622         return builder;
623     }
624
625     public AnyXmlBuilder addAnyXml(final int line, final QName qname, final SchemaPath schemaPath) {
626         final AnyXmlBuilder builder = new AnyXmlBuilder(name, line, qname, schemaPath);
627
628         Builder parent = getActualNode();
629         builder.setParent(parent);
630         addChildToParent(parent, builder, qname.getLocalName());
631
632         return builder;
633     }
634
635     @Override
636     public void addTypedef(TypeDefinitionBuilder typedefBuilder) {
637         String nodeName = typedefBuilder.getQName().getLocalName();
638         for (TypeDefinitionBuilder tdb : addedTypedefs) {
639             if (tdb.getQName().getLocalName().equals(nodeName)) {
640                 raiseYangParserException("", "typedef", nodeName, typedefBuilder.getLine(), tdb.getLine());
641             }
642         }
643         addedTypedefs.add(typedefBuilder);
644     }
645
646     public TypeDefinitionBuilderImpl addTypedef(final int line, final QName qname) {
647         final TypeDefinitionBuilderImpl builder = new TypeDefinitionBuilderImpl(name, line, qname);
648
649         Builder parent = getActualNode();
650         builder.setParent(parent);
651
652         String typedefName = qname.getLocalName();
653         if (parent.equals(this)) {
654             for (TypeDefinitionBuilder tdb : addedTypedefs) {
655                 if (tdb.getQName().getLocalName().equals(typedefName)) {
656                     raiseYangParserException("", "typedef", typedefName, line, tdb.getLine());
657                 }
658             }
659             addedTypedefs.add(builder);
660         } else {
661             if (parent instanceof DataNodeContainerBuilder) {
662                 DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parent;
663                 for (TypeDefinitionBuilder child : parentNode.getTypeDefinitionBuilders()) {
664                     if (child.getQName().getLocalName().equals(typedefName)) {
665                         raiseYangParserException("", "typedef", typedefName, line, child.getLine());
666                     }
667                 }
668                 parentNode.addTypedef(builder);
669             } else if (parent instanceof RpcDefinitionBuilder) {
670                 RpcDefinitionBuilder rpcParent = (RpcDefinitionBuilder) parent;
671                 for (TypeDefinitionBuilder tdb : rpcParent.getTypeDefinitions()) {
672                     if (tdb.getQName().getLocalName().equals(builder.getQName().getLocalName())) {
673                         raiseYangParserException("", "typedef", typedefName, line, tdb.getLine());
674                     }
675                 }
676                 rpcParent.addTypedef(builder);
677             } else {
678                 throw new YangParseException(name, line, "Unresolved parent of typedef " + typedefName);
679             }
680         }
681
682         return builder;
683     }
684
685     public void setType(final TypeDefinition<?> type) {
686         Builder parent = getActualNode();
687         if (!(parent instanceof TypeAwareBuilder)) {
688             throw new YangParseException("Failed to set type '" + type.getQName().getLocalName()
689                     + "'. Invalid parent node: " + parent);
690         }
691         ((TypeAwareBuilder) parent).setType(type);
692     }
693
694     public UnionTypeBuilder addUnionType(final int line, final URI namespace, final Date revision) {
695         final Builder parent = getActualNode();
696         if (parent == null) {
697             throw new YangParseException(name, line, "Unresolved parent of union type");
698         } else {
699             final UnionTypeBuilder union = new UnionTypeBuilder(name, line);
700             if (parent instanceof TypeAwareBuilder) {
701                 ((TypeAwareBuilder) parent).setTypedef(union);
702                 return union;
703             } else {
704                 throw new YangParseException(name, line, "Invalid parent of union type.");
705             }
706         }
707     }
708
709     public void addIdentityrefType(final int line, final SchemaPath schemaPath, final String baseString) {
710         final IdentityrefTypeBuilder identityref = new IdentityrefTypeBuilder(name, line, baseString, schemaPath);
711
712         final Builder parent = getActualNode();
713         if (parent == null) {
714             throw new YangParseException(name, line, "Unresolved parent of identityref type.");
715         } else {
716             if (parent instanceof TypeAwareBuilder) {
717                 final TypeAwareBuilder typeParent = (TypeAwareBuilder) parent;
718                 typeParent.setTypedef(identityref);
719                 dirtyNodes.add(typeParent);
720             } else {
721                 throw new YangParseException(name, line, "Invalid parent of identityref type.");
722             }
723         }
724     }
725
726     public DeviationBuilder addDeviation(final int line, final String targetPath) {
727         Builder parent = getActualNode();
728         if (!(parent.equals(this))) {
729             throw new YangParseException(name, line, "deviation can be defined only in module or submodule");
730         }
731
732         final DeviationBuilder builder = new DeviationBuilder(name, line, targetPath);
733         builder.setParent(parent);
734         addedDeviations.add(builder);
735         return builder;
736     }
737
738     public IdentitySchemaNodeBuilder addIdentity(final QName qname, final int line) {
739         Builder parent = getActualNode();
740         if (!(parent.equals(this))) {
741             throw new YangParseException(name, line, "identity can be defined only in module or submodule");
742         }
743         String identityName = qname.getLocalName();
744         for (IdentitySchemaNodeBuilder idBuilder : addedIdentities) {
745             if (idBuilder.getQName().equals(qname)) {
746                 raiseYangParserException("", "identity", identityName, line, idBuilder.getLine());
747             }
748         }
749
750         final IdentitySchemaNodeBuilder builder = new IdentitySchemaNodeBuilder(name, line, qname);
751         builder.setParent(parent);
752         addedIdentities.add(builder);
753         return builder;
754     }
755
756     @Override
757     public void addUnknownNodeBuilder(final UnknownSchemaNodeBuilder builder) {
758         addedUnknownNodes.add(builder);
759         allUnknownNodes.add(builder);
760     }
761
762     public UnknownSchemaNodeBuilder addUnknownSchemaNode(final int line, final QName qname) {
763         final Builder parent = getActualNode();
764         final UnknownSchemaNodeBuilder builder = new UnknownSchemaNodeBuilder(name, line, qname);
765         builder.setParent(parent);
766         allUnknownNodes.add(builder);
767
768         if (parent.equals(this)) {
769             addedUnknownNodes.add(builder);
770         } else {
771             if (parent instanceof SchemaNodeBuilder) {
772                 ((SchemaNodeBuilder) parent).addUnknownNodeBuilder(builder);
773             } else if (parent instanceof DataNodeContainerBuilder) {
774                 ((DataNodeContainerBuilder) parent).addUnknownNodeBuilder(builder);
775             } else if (parent instanceof RefineHolder) {
776                 ((RefineHolder) parent).addUnknownNodeBuilder(builder);
777             } else {
778                 throw new YangParseException(name, line, "Unresolved parent of unknown node '" + qname.getLocalName()
779                         + "'");
780             }
781         }
782
783         return builder;
784     }
785
786     public Set<RpcDefinitionBuilder> getRpcs() {
787         return addedRpcs;
788     }
789
790     public Set<NotificationBuilder> getNotifications() {
791         return addedNotifications;
792     }
793
794     @Override
795     public String toString() {
796         return "module " + name;
797     }
798
799     private final class ModuleImpl implements Module {
800         private URI namespace;
801         private final String name;
802         private Date revision;
803         private String prefix;
804         private String yangVersion;
805         private String description;
806         private String reference;
807         private String organization;
808         private String contact;
809         private Set<ModuleImport> imports = Collections.emptySet();
810         private Set<FeatureDefinition> features = Collections.emptySet();
811         private Set<TypeDefinition<?>> typeDefinitions = Collections.emptySet();
812         private Set<NotificationDefinition> notifications = Collections.emptySet();
813         private Set<AugmentationSchema> augmentations = Collections.emptySet();
814         private Set<RpcDefinition> rpcs = Collections.emptySet();
815         private Set<Deviation> deviations = Collections.emptySet();
816         private Map<QName, DataSchemaNode> childNodes = Collections.emptyMap();
817         private Set<GroupingDefinition> groupings = Collections.emptySet();
818         private Set<UsesNode> uses = Collections.emptySet();
819         private List<ExtensionDefinition> extensionNodes = Collections.emptyList();
820         private Set<IdentitySchemaNode> identities = Collections.emptySet();
821         private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
822
823         private ModuleImpl(String name) {
824             this.name = name;
825         }
826
827         @Override
828         public URI getNamespace() {
829             return namespace;
830         }
831
832         private void setNamespace(URI namespace) {
833             this.namespace = namespace;
834         }
835
836         @Override
837         public String getName() {
838             return name;
839         }
840
841         @Override
842         public Date getRevision() {
843             return revision;
844         }
845
846         private void setRevision(Date revision) {
847             this.revision = revision;
848         }
849
850         @Override
851         public String getPrefix() {
852             return prefix;
853         }
854
855         private void setPrefix(String prefix) {
856             this.prefix = prefix;
857         }
858
859         @Override
860         public String getYangVersion() {
861             return yangVersion;
862         }
863
864         private void setYangVersion(String yangVersion) {
865             this.yangVersion = yangVersion;
866         }
867
868         @Override
869         public String getDescription() {
870             return description;
871         }
872
873         private void setDescription(String description) {
874             this.description = description;
875         }
876
877         @Override
878         public String getReference() {
879             return reference;
880         }
881
882         private void setReference(String reference) {
883             this.reference = reference;
884         }
885
886         @Override
887         public String getOrganization() {
888             return organization;
889         }
890
891         private void setOrganization(String organization) {
892             this.organization = organization;
893         }
894
895         @Override
896         public String getContact() {
897             return contact;
898         }
899
900         private void setContact(String contact) {
901             this.contact = contact;
902         }
903
904         @Override
905         public Set<ModuleImport> getImports() {
906             return imports;
907         }
908
909         private void setImports(Set<ModuleImport> imports) {
910             if (imports != null) {
911                 this.imports = imports;
912             }
913         }
914
915         @Override
916         public Set<FeatureDefinition> getFeatures() {
917             return features;
918         }
919
920         private void setFeatures(Set<FeatureDefinition> features) {
921             if (features != null) {
922                 this.features = features;
923             }
924         }
925
926         @Override
927         public Set<TypeDefinition<?>> getTypeDefinitions() {
928             return typeDefinitions;
929         }
930
931         private void setTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
932             if (typeDefinitions != null) {
933                 this.typeDefinitions = typeDefinitions;
934             }
935         }
936
937         @Override
938         public Set<NotificationDefinition> getNotifications() {
939             return notifications;
940         }
941
942         private void setNotifications(Set<NotificationDefinition> notifications) {
943             if (notifications != null) {
944                 this.notifications = notifications;
945             }
946         }
947
948         @Override
949         public Set<AugmentationSchema> getAugmentations() {
950             return augmentations;
951         }
952
953         private void setAugmentations(Set<AugmentationSchema> augmentations) {
954             if (augmentations != null) {
955                 this.augmentations = augmentations;
956             }
957         }
958
959         @Override
960         public Set<RpcDefinition> getRpcs() {
961             return rpcs;
962         }
963
964         private void setRpcs(Set<RpcDefinition> rpcs) {
965             if (rpcs != null) {
966                 this.rpcs = rpcs;
967             }
968         }
969
970         @Override
971         public Set<Deviation> getDeviations() {
972             return deviations;
973         }
974
975         private void setDeviations(Set<Deviation> deviations) {
976             if (deviations != null) {
977                 this.deviations = deviations;
978             }
979         }
980
981         @Override
982         public Set<DataSchemaNode> getChildNodes() {
983             return new LinkedHashSet<DataSchemaNode>(childNodes.values());
984         }
985
986         private void setChildNodes(Map<QName, DataSchemaNode> childNodes) {
987             if (childNodes != null) {
988                 this.childNodes = childNodes;
989             }
990         }
991
992         @Override
993         public Set<GroupingDefinition> getGroupings() {
994             return groupings;
995         }
996
997         private void setGroupings(Set<GroupingDefinition> groupings) {
998             if (groupings != null) {
999                 this.groupings = groupings;
1000             }
1001         }
1002
1003         @Override
1004         public Set<UsesNode> getUses() {
1005             return uses;
1006         }
1007
1008         private void setUses(Set<UsesNode> uses) {
1009             if (uses != null) {
1010                 this.uses = uses;
1011             }
1012         }
1013
1014         @Override
1015         public List<ExtensionDefinition> getExtensionSchemaNodes() {
1016             return extensionNodes;
1017         }
1018
1019         private void setExtensionSchemaNodes(final List<ExtensionDefinition> extensionNodes) {
1020             if (extensionNodes != null) {
1021                 this.extensionNodes = extensionNodes;
1022             }
1023         }
1024
1025         @Override
1026         public Set<IdentitySchemaNode> getIdentities() {
1027             return identities;
1028         }
1029
1030         private void setIdentities(final Set<IdentitySchemaNode> identities) {
1031             if (identities != null) {
1032                 this.identities = identities;
1033             }
1034         }
1035
1036         @Override
1037         public List<UnknownSchemaNode> getUnknownSchemaNodes() {
1038             return unknownNodes;
1039         }
1040
1041         private void setUnknownSchemaNodes(final List<UnknownSchemaNode> unknownNodes) {
1042             if (unknownNodes != null) {
1043                 this.unknownNodes = unknownNodes;
1044             }
1045         }
1046
1047         @Override
1048         public DataSchemaNode getDataChildByName(QName name) {
1049             return childNodes.get(name);
1050         }
1051
1052         @Override
1053         public DataSchemaNode getDataChildByName(String name) {
1054             DataSchemaNode result = null;
1055             for (Map.Entry<QName, DataSchemaNode> entry : childNodes.entrySet()) {
1056                 if (entry.getKey().getLocalName().equals(name)) {
1057                     result = entry.getValue();
1058                     break;
1059                 }
1060             }
1061             return result;
1062         }
1063
1064         @Override
1065         public int hashCode() {
1066             final int prime = 31;
1067             int result = 1;
1068             result = prime * result + ((namespace == null) ? 0 : namespace.hashCode());
1069             result = prime * result + ((name == null) ? 0 : name.hashCode());
1070             result = prime * result + ((revision == null) ? 0 : revision.hashCode());
1071             result = prime * result + ((prefix == null) ? 0 : prefix.hashCode());
1072             result = prime * result + ((yangVersion == null) ? 0 : yangVersion.hashCode());
1073             return result;
1074         }
1075
1076         @Override
1077         public boolean equals(Object obj) {
1078             if (this == obj) {
1079                 return true;
1080             }
1081             if (obj == null) {
1082                 return false;
1083             }
1084             if (getClass() != obj.getClass()) {
1085                 return false;
1086             }
1087             ModuleImpl other = (ModuleImpl) obj;
1088             if (namespace == null) {
1089                 if (other.namespace != null) {
1090                     return false;
1091                 }
1092             } else if (!namespace.equals(other.namespace)) {
1093                 return false;
1094             }
1095             if (name == null) {
1096                 if (other.name != null) {
1097                     return false;
1098                 }
1099             } else if (!name.equals(other.name)) {
1100                 return false;
1101             }
1102             if (revision == null) {
1103                 if (other.revision != null) {
1104                     return false;
1105                 }
1106             } else if (!revision.equals(other.revision)) {
1107                 return false;
1108             }
1109             if (prefix == null) {
1110                 if (other.prefix != null) {
1111                     return false;
1112                 }
1113             } else if (!prefix.equals(other.prefix)) {
1114                 return false;
1115             }
1116             if (yangVersion == null) {
1117                 if (other.yangVersion != null) {
1118                     return false;
1119                 }
1120             } else if (!yangVersion.equals(other.yangVersion)) {
1121                 return false;
1122             }
1123             return true;
1124         }
1125
1126         @Override
1127         public String toString() {
1128             StringBuilder sb = new StringBuilder(ModuleImpl.class.getSimpleName());
1129             sb.append("[");
1130             sb.append("name=" + name);
1131             sb.append(", namespace=" + namespace);
1132             sb.append(", revision=" + revision);
1133             sb.append(", prefix=" + prefix);
1134             sb.append(", yangVersion=" + yangVersion);
1135             sb.append("]");
1136             return sb.toString();
1137         }
1138     }
1139
1140     /**
1141      * Add child to parent. Method checks for duplicates and add given child
1142      * node to parent. If node with same name is found, throws exception. If
1143      * parent is null, child node will be added directly to module.
1144      *
1145      * @param parent
1146      * @param child
1147      * @param childName
1148      */
1149     private void addChildToParent(final Builder parent, final DataSchemaNodeBuilder child, final String childName) {
1150         final int lineNum = child.getLine();
1151         if (parent.equals(this)) {
1152             addChildToModule(child, childName, lineNum);
1153         } else {
1154             addChildToSubnodeOfModule(parent, child, childName, lineNum);
1155         }
1156     }
1157
1158     /**
1159      * Adds child node <code>child</code> to the set of nodes child nodes.
1160      *
1161      * The method reduces the complexity of the method
1162      * {@link #addChildToParent(Builder, DataSchemaNodeBuilder, String)
1163      * addChildToParent}.
1164      *
1165      * @param child
1166      *            data schema node builder for child node
1167      * @param childName
1168      *            string with name of child node
1169      * @param lineNum
1170      *            line number in YANG file where is the node with the name equal
1171      *            to <code>childName</code> is defined
1172      */
1173     private void addChildToModule(final DataSchemaNodeBuilder child, final String childName, final int lineNum) {
1174         // if parent == null => node is defined under module
1175         // All leafs, leaf-lists, lists, containers, choices, rpcs,
1176         // notifications, and anyxmls defined within a parent node or at the
1177         // top level of the module or its submodules share the same
1178         // identifier namespace.
1179         for (DataSchemaNodeBuilder childNode : addedChildNodes) {
1180             if (childNode.getQName().getLocalName().equals(childName)) {
1181                 raiseYangParserException("'"+child+"'", "node", childName, lineNum, childNode.getLine());
1182             }
1183         }
1184         for (RpcDefinitionBuilder rpc : addedRpcs) {
1185             if (rpc.getQName().getLocalName().equals(childName)) {
1186                 raiseYangParserException("'"+child+"'", "rpc", childName, lineNum, rpc.getLine());
1187             }
1188         }
1189         for (NotificationBuilder notification : addedNotifications) {
1190             if (notification.getQName().getLocalName().equals(childName)) {
1191                 raiseYangParserException("'"+child+"'", "notification", childName, lineNum, notification.getLine());
1192             }
1193         }
1194         addedChildNodes.add(child);
1195     }
1196
1197     /**
1198      * Adds child node <code>child</code> to the group of child nodes of the
1199      * <code>parent</code>
1200      *
1201      * The method reduces the complexity of the method
1202      * {@link #addChildToParent(Builder, DataSchemaNodeBuilder, String)
1203      * addChildToParent}. *
1204      *
1205      * @param parent
1206      *            builder of node which is parent for <code>child</code>
1207      * @param child
1208      *            data schema node builder for child node
1209      * @param childName
1210      *            string with name of child node
1211      * @param lineNum
1212      *            line number in YANG file where is the node with the name equal
1213      *            to <code>childName</code> is defined
1214      */
1215     private void addChildToSubnodeOfModule(final Builder parent, final DataSchemaNodeBuilder child,
1216             final String childName, final int lineNum) {
1217         if (parent instanceof AugmentationSchemaBuilder) {
1218             child.setAugmenting(true);
1219         }
1220         // no need for checking rpc and notification because they can be
1221         // defined only under module or submodule
1222         if (parent instanceof DataNodeContainerBuilder) {
1223             DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parent;
1224             for (DataSchemaNodeBuilder childNode : parentNode.getChildNodeBuilders()) {
1225                 if (childNode.getQName().getLocalName().equals(childName)) {
1226                     raiseYangParserException("'"+child+"'", "node", childName, lineNum, childNode.getLine());
1227                 }
1228             }
1229             parentNode.addChildNode(child);
1230         } else if (parent instanceof ChoiceBuilder) {
1231             ChoiceBuilder parentNode = (ChoiceBuilder) parent;
1232             for (ChoiceCaseBuilder caseBuilder : parentNode.getCases()) {
1233                 if (caseBuilder.getQName().getLocalName().equals(childName)) {
1234                     raiseYangParserException("'"+child+"'", "node", childName, lineNum, caseBuilder.getLine());
1235                 }
1236             }
1237             parentNode.addCase(child);
1238         } else {
1239             throw new YangParseException(name, lineNum, "Unresolved parent of node '" + childName + "'.");
1240         }
1241     }
1242
1243     /**
1244      *
1245      * Implementation of <code>ModuleImport</code> interface only for the method
1246      * {@link ModuleBuilder#createModuleImport(String, Date, String)
1247      * createModuleImport}.
1248      *
1249      */
1250     private class ModuleImportImpl implements ModuleImport {
1251         final String moduleName;
1252         final Date revision;
1253         final String prefix;
1254
1255         private ModuleImportImpl(final String moduleName, final Date revision, final String prefix) {
1256             this.moduleName = moduleName;
1257             this.revision = revision;
1258             this.prefix = prefix;
1259         }
1260
1261         @Override
1262         public String getModuleName() {
1263             return moduleName;
1264         }
1265
1266         @Override
1267         public Date getRevision() {
1268             return revision;
1269         }
1270
1271         @Override
1272         public String getPrefix() {
1273             return prefix;
1274         }
1275
1276         @Override
1277         public int hashCode() {
1278             final int prime = 31;
1279             int result = 1;
1280             result = prime * result + ((moduleName == null) ? 0 : moduleName.hashCode());
1281             result = prime * result + ((revision == null) ? 0 : revision.hashCode());
1282             result = prime * result + ((prefix == null) ? 0 : prefix.hashCode());
1283             return result;
1284         }
1285
1286         @Override
1287         public boolean equals(Object obj) {
1288             if (this == obj) {
1289                 return true;
1290             }
1291             if (obj == null) {
1292                 return false;
1293             }
1294             if (getClass() != obj.getClass()) {
1295                 return false;
1296             }
1297             ModuleImport other = (ModuleImport) obj;
1298             if (getModuleName() == null) {
1299                 if (other.getModuleName() != null) {
1300                     return false;
1301                 }
1302             } else if (!getModuleName().equals(other.getModuleName())) {
1303                 return false;
1304             }
1305             if (getRevision() == null) {
1306                 if (other.getRevision() != null) {
1307                     return false;
1308                 }
1309             } else if (!getRevision().equals(other.getRevision())) {
1310                 return false;
1311             }
1312             if (getPrefix() == null) {
1313                 if (other.getPrefix() != null) {
1314                     return false;
1315                 }
1316             } else if (!getPrefix().equals(other.getPrefix())) {
1317                 return false;
1318             }
1319             return true;
1320         }
1321
1322         @Override
1323         public String toString() {
1324             return "ModuleImport[moduleName=" + moduleName + ", revision=" + revision + ", prefix=" + prefix + "]";
1325         }
1326     }
1327
1328     private ModuleImport createModuleImport(final String moduleName, final Date revision, final String prefix) {
1329         final ModuleImport moduleImport = new ModuleImportImpl(moduleName, revision, prefix);
1330         return moduleImport;
1331     }
1332
1333     private void raiseYangParserException(final String cantAddType, final String type, final String name,
1334             final int currentLine, final int duplicateLine) {
1335
1336         StringBuilder msgPrefix = new StringBuilder("");
1337         if (cantAddType != null && !cantAddType.isEmpty()) {
1338             msgPrefix.append("Can not add ");
1339             msgPrefix.append(cantAddType);
1340             msgPrefix.append(": ");
1341         }
1342
1343         String msg = String.format("%s%s with same name '%s' already declared at line %d.", msgPrefix, type, name,
1344                 duplicateLine);
1345         throw new YangParseException(moduleName, currentLine, msg);
1346     }
1347 }