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