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