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