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