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