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