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