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