Cleanup use of Guava library
[yangtools.git] / yang / yang-model-export / src / main / java / org / opendaylight / yangtools / yang / model / export / SchemaContextEmitter.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.model.export;
9
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Preconditions;
12 import com.google.common.base.Predicates;
13 import com.google.common.base.Strings;
14 import com.google.common.collect.Collections2;
15 import com.google.common.primitives.UnsignedInteger;
16 import java.net.URI;
17 import java.util.Collection;
18 import java.util.Date;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Map.Entry;
23 import java.util.Objects;
24 import java.util.Optional;
25 import java.util.Set;
26 import javax.annotation.Nonnull;
27 import javax.annotation.Nullable;
28 import javax.annotation.concurrent.NotThreadSafe;
29 import org.opendaylight.yangtools.yang.common.QName;
30 import org.opendaylight.yangtools.yang.common.YangVersion;
31 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
32 import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
35 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
36 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
38 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
40 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.Deviation;
42 import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
43 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
44 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
45 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
46 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
47 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
48 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.Module;
51 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
52 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
53 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
54 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
55 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
56 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
57 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
58 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
59 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
60 import org.opendaylight.yangtools.yang.model.api.Status;
61 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
62 import org.opendaylight.yangtools.yang.model.api.UniqueConstraint;
63 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
64 import org.opendaylight.yangtools.yang.model.api.UsesNode;
65 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
66 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
67 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
68 import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
69 import org.opendaylight.yangtools.yang.model.api.stmt.ActionStatement;
70 import org.opendaylight.yangtools.yang.model.api.stmt.AnydataStatement;
71 import org.opendaylight.yangtools.yang.model.api.stmt.AnyxmlStatement;
72 import org.opendaylight.yangtools.yang.model.api.stmt.ArgumentStatement;
73 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement;
74 import org.opendaylight.yangtools.yang.model.api.stmt.BaseStatement;
75 import org.opendaylight.yangtools.yang.model.api.stmt.BelongsToStatement;
76 import org.opendaylight.yangtools.yang.model.api.stmt.BitStatement;
77 import org.opendaylight.yangtools.yang.model.api.stmt.BodyGroup;
78 import org.opendaylight.yangtools.yang.model.api.stmt.CaseStatement;
79 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceStatement;
80 import org.opendaylight.yangtools.yang.model.api.stmt.ConfigStatement;
81 import org.opendaylight.yangtools.yang.model.api.stmt.ContactStatement;
82 import org.opendaylight.yangtools.yang.model.api.stmt.ContainerStatement;
83 import org.opendaylight.yangtools.yang.model.api.stmt.DataDefinitionContainer;
84 import org.opendaylight.yangtools.yang.model.api.stmt.DataDefinitionStatement;
85 import org.opendaylight.yangtools.yang.model.api.stmt.DefaultStatement;
86 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement;
87 import org.opendaylight.yangtools.yang.model.api.stmt.DeviateStatement;
88 import org.opendaylight.yangtools.yang.model.api.stmt.DeviationStatement;
89 import org.opendaylight.yangtools.yang.model.api.stmt.DocumentationGroup;
90 import org.opendaylight.yangtools.yang.model.api.stmt.DocumentedConstraintGroup;
91 import org.opendaylight.yangtools.yang.model.api.stmt.EnumStatement;
92 import org.opendaylight.yangtools.yang.model.api.stmt.ErrorAppTagStatement;
93 import org.opendaylight.yangtools.yang.model.api.stmt.ErrorMessageStatement;
94 import org.opendaylight.yangtools.yang.model.api.stmt.FeatureStatement;
95 import org.opendaylight.yangtools.yang.model.api.stmt.FractionDigitsStatement;
96 import org.opendaylight.yangtools.yang.model.api.stmt.GroupingStatement;
97 import org.opendaylight.yangtools.yang.model.api.stmt.IdentityStatement;
98 import org.opendaylight.yangtools.yang.model.api.stmt.IfFeatureStatement;
99 import org.opendaylight.yangtools.yang.model.api.stmt.ImportStatement;
100 import org.opendaylight.yangtools.yang.model.api.stmt.IncludeStatement;
101 import org.opendaylight.yangtools.yang.model.api.stmt.InputStatement;
102 import org.opendaylight.yangtools.yang.model.api.stmt.KeyStatement;
103 import org.opendaylight.yangtools.yang.model.api.stmt.LeafListStatement;
104 import org.opendaylight.yangtools.yang.model.api.stmt.LeafStatement;
105 import org.opendaylight.yangtools.yang.model.api.stmt.LengthStatement;
106 import org.opendaylight.yangtools.yang.model.api.stmt.LinkageGroup;
107 import org.opendaylight.yangtools.yang.model.api.stmt.ListStatement;
108 import org.opendaylight.yangtools.yang.model.api.stmt.MandatoryStatement;
109 import org.opendaylight.yangtools.yang.model.api.stmt.MaxElementsStatement;
110 import org.opendaylight.yangtools.yang.model.api.stmt.MetaGroup;
111 import org.opendaylight.yangtools.yang.model.api.stmt.MinElementsStatement;
112 import org.opendaylight.yangtools.yang.model.api.stmt.ModifierStatement;
113 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
114 import org.opendaylight.yangtools.yang.model.api.stmt.MustStatement;
115 import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement;
116 import org.opendaylight.yangtools.yang.model.api.stmt.NotificationStatement;
117 import org.opendaylight.yangtools.yang.model.api.stmt.OperationGroup;
118 import org.opendaylight.yangtools.yang.model.api.stmt.OrderedByStatement;
119 import org.opendaylight.yangtools.yang.model.api.stmt.OrganizationStatement;
120 import org.opendaylight.yangtools.yang.model.api.stmt.OutputStatement;
121 import org.opendaylight.yangtools.yang.model.api.stmt.PathStatement;
122 import org.opendaylight.yangtools.yang.model.api.stmt.PatternStatement;
123 import org.opendaylight.yangtools.yang.model.api.stmt.PositionStatement;
124 import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
125 import org.opendaylight.yangtools.yang.model.api.stmt.PresenceStatement;
126 import org.opendaylight.yangtools.yang.model.api.stmt.RangeStatement;
127 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement;
128 import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement;
129 import org.opendaylight.yangtools.yang.model.api.stmt.RequireInstanceStatement;
130 import org.opendaylight.yangtools.yang.model.api.stmt.RevisionDateStatement;
131 import org.opendaylight.yangtools.yang.model.api.stmt.RevisionGroup;
132 import org.opendaylight.yangtools.yang.model.api.stmt.RevisionStatement;
133 import org.opendaylight.yangtools.yang.model.api.stmt.RpcStatement;
134 import org.opendaylight.yangtools.yang.model.api.stmt.StatusStatement;
135 import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement;
136 import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement;
137 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement;
138 import org.opendaylight.yangtools.yang.model.api.stmt.UniqueStatement;
139 import org.opendaylight.yangtools.yang.model.api.stmt.UnitsStatement;
140 import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement;
141 import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
142 import org.opendaylight.yangtools.yang.model.api.stmt.ValueStatement;
143 import org.opendaylight.yangtools.yang.model.api.stmt.WhenStatement;
144 import org.opendaylight.yangtools.yang.model.api.stmt.YangVersionStatement;
145 import org.opendaylight.yangtools.yang.model.api.stmt.YinElementStatement;
146 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
147 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
148 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
149 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
150 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
151 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
152 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
153 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
154 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
155 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
156 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
157 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
158 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
159 import org.opendaylight.yangtools.yang.model.api.type.ModifierKind;
160 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
161 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
162 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
163 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
164 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
165 import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
166
167 @Beta
168 @NotThreadSafe
169 abstract class SchemaContextEmitter {
170
171     final YangModuleWriter writer;
172     final boolean emitInstantiated;
173     final boolean emitUses;
174     final Map<QName, StatementDefinition> extensions;
175     final YangVersion yangVersion;
176
177     SchemaContextEmitter(final YangModuleWriter writer, final Map<QName, StatementDefinition> extensions,
178             final YangVersion yangVersion) {
179         this(writer, extensions, yangVersion, false, true);
180     }
181
182     SchemaContextEmitter(final YangModuleWriter writer, final Map<QName, StatementDefinition> extensions,
183             final YangVersion yangVersion, final boolean emitInstantiated, final boolean emitUses) {
184         this.writer = Preconditions.checkNotNull(writer);
185         this.emitInstantiated = emitInstantiated;
186         this.emitUses = emitUses;
187         this.extensions = Preconditions.checkNotNull(extensions);
188         this.yangVersion = yangVersion;
189     }
190
191     static void writeToStatementWriter(final Module module, final SchemaContext ctx,
192             final StatementTextWriter statementWriter, final boolean emitInstantiated) {
193         final YangModuleWriter yangSchemaWriter = SchemaToStatementWriterAdaptor.from(statementWriter);
194         final Map<QName, StatementDefinition> extensions = ExtensionStatement.mapFrom(ctx.getExtensions());
195         if (module instanceof EffectiveStatement && !emitInstantiated) {
196             /*
197              * if module is an effective statement and we don't want to export
198              * instantiated statements (e.g. statements added by uses or
199              * augment) we can get declared form i.e. ModuleStatement and then
200              * use DeclaredSchemaContextEmitter
201              */
202             new DeclaredSchemaContextEmitter(yangSchemaWriter, extensions,
203                     YangVersion.parse(module.getYangVersion()).orElse(null))
204                             .emitModule(((EffectiveStatement<?, ?>) module).getDeclared());
205         } else {
206             /*
207              * if we don't have access to declared form of supplied module or we
208              * want to emit also instantiated statements (e.g. statements added
209              * by uses or augment), we use EffectiveSchemaContextEmitter.
210              */
211             new EffectiveSchemaContextEmitter(yangSchemaWriter, extensions,
212                     YangVersion.parse(module.getYangVersion()).orElse(null), emitInstantiated).emitModule(module);
213         }
214     }
215
216     // FIXME: Probably should be moved to utils bundle.
217     static <T> boolean isPrefix(final Iterable<T> prefix, final Iterable<T> other) {
218         final Iterator<T> prefixIt = prefix.iterator();
219         final Iterator<T> otherIt = other.iterator();
220         while (prefixIt.hasNext()) {
221             if (!otherIt.hasNext()) {
222                 return false;
223             }
224             if (!Objects.deepEquals(prefixIt.next(), otherIt.next())) {
225                 return false;
226             }
227         }
228         return true;
229     }
230
231     static class DeclaredSchemaContextEmitter extends SchemaContextEmitter {
232
233         DeclaredSchemaContextEmitter(final YangModuleWriter writer, final Map<QName, StatementDefinition> extensions,
234                 final YangVersion yangVersion) {
235             super(writer, extensions, yangVersion);
236         }
237
238         void emitModule(final DeclaredStatement<?> declaredRootStmt) {
239             if (declaredRootStmt instanceof ModuleStatement) {
240                 emitModule((ModuleStatement) declaredRootStmt);
241             } else if (declaredRootStmt instanceof SubmoduleStatement) {
242                 emitSubmodule((SubmoduleStatement) declaredRootStmt);
243             } else {
244                 throw new UnsupportedOperationException(
245                         String.format("Yin export: unsupported declared statement %s", declaredRootStmt));
246             }
247         }
248
249         private void emitModule(final ModuleStatement module) {
250             super.writer.startModuleNode(module.rawArgument());
251             emitModuleHeader(module);
252             emitLinkageNodes(module);
253             emitMetaNodes(module);
254             emitRevisionNodes(module);
255             emitBodyNodes(module);
256             emitUnknownStatementNodes(module);
257             super.writer.endNode();
258         }
259
260         private void emitModuleHeader(final ModuleStatement input) {
261             emitYangVersionNode(input.getYangVersion());
262             emitNamespace(input.getNamespace());
263             emitPrefixNode(input.getPrefix());
264         }
265
266         private void emitSubmodule(final SubmoduleStatement submodule) {
267             super.writer.startSubmoduleNode(submodule.rawArgument());
268             emitSubmoduleHeaderNodes(submodule);
269             emitLinkageNodes(submodule);
270             emitMetaNodes(submodule);
271             emitRevisionNodes(submodule);
272             emitBodyNodes(submodule);
273             emitUnknownStatementNodes(submodule);
274             super.writer.endNode();
275         }
276
277         private void emitSubmoduleHeaderNodes(final SubmoduleStatement input) {
278             emitYangVersionNode(input.getYangVersion());
279             emitBelongsTo(input.getBelongsTo());
280         }
281
282         private void emitBelongsTo(final BelongsToStatement belongsTo) {
283             super.writer.startBelongsToNode(belongsTo.rawArgument());
284             emitPrefixNode(belongsTo.getPrefix());
285             super.writer.endNode();
286         }
287
288         private void emitMetaNodes(final MetaGroup input) {
289             emitOrganizationNode(input.getOrganization());
290             emitContact(input.getContact());
291             emitDescriptionNode(input.getDescription());
292             emitReferenceNode(input.getReference());
293         }
294
295         private void emitLinkageNodes(final LinkageGroup input) {
296             for (final ImportStatement importNode : input.getImports()) {
297                 emitImport(importNode);
298             }
299             for (final IncludeStatement importNode : input.getIncludes()) {
300                 emitInclude(importNode);
301             }
302         }
303
304         private void emitRevisionNodes(final RevisionGroup input) {
305             emitRevisions(input.getRevisions());
306         }
307
308         private void emitBodyNodes(final BodyGroup input) {
309
310             for (final org.opendaylight.yangtools.yang.model.api.stmt.ExtensionStatement extension : input
311                     .getExtensions()) {
312                 emitExtension(extension);
313             }
314             for (final FeatureStatement definition : input.getFeatures()) {
315                 emitFeature(definition);
316             }
317             for (final IdentityStatement identity : input.getIdentities()) {
318                 emitIdentity(identity);
319             }
320             for (final DeviationStatement deviation : input.getDeviations()) {
321                 emitDeviation(deviation);
322             }
323
324             emitDataNodeContainer(input);
325
326             for (final AugmentStatement augmentation : input.getAugments()) {
327                 emitAugment(augmentation);
328             }
329             for (final RpcStatement rpc : input.getRpcs()) {
330                 emitRpc(rpc);
331             }
332
333             emitNotifications(input.getNotifications());
334         }
335
336         private void emitDataNodeContainer(final DataDefinitionContainer input) {
337             for (final DataDefinitionStatement child : input.getDataDefinitions()) {
338                 emitDataSchemaNode(child);
339             }
340         }
341
342         private void emitDataNodeContainer(final DataDefinitionContainer.WithReusableDefinitions input) {
343             for (final TypedefStatement typedef : input.getTypedefs()) {
344                 emitTypedefNode(typedef);
345             }
346             for (final GroupingStatement grouping : input.getGroupings()) {
347                 emitGrouping(grouping);
348             }
349             for (final DataDefinitionStatement child : input.getDataDefinitions()) {
350                 emitDataSchemaNode(child);
351             }
352         }
353
354         private void emitDataSchemaNode(final DataDefinitionStatement child) {
355             if (child instanceof ContainerStatement) {
356                 emitContainer((ContainerStatement) child);
357             } else if (child instanceof LeafStatement) {
358                 emitLeaf((LeafStatement) child);
359             } else if (child instanceof LeafListStatement) {
360                 emitLeafList((LeafListStatement) child);
361             } else if (child instanceof ListStatement) {
362                 emitList((ListStatement) child);
363             } else if (child instanceof ChoiceStatement) {
364                 emitChoice((ChoiceStatement) child);
365             } else if (child instanceof AnyxmlStatement) {
366                 emitAnyxml((AnyxmlStatement) child);
367             } else if (child instanceof AnydataStatement) {
368                 emitAnydata((AnydataStatement) child);
369             } else if (child instanceof UsesStatement) {
370                 emitUsesNode((UsesStatement) child);
371             } else {
372                 throw new UnsupportedOperationException("Not supported DataStatement type " + child.getClass());
373             }
374         }
375
376         private void emitYangVersionNode(@Nullable final YangVersionStatement yangVersionStatement) {
377             if (yangVersionStatement != null) {
378                 super.writer.startYangVersionNode(yangVersionStatement.rawArgument());
379                 super.writer.endNode();
380             }
381         }
382
383         private void emitImport(final ImportStatement importNode) {
384             super.writer.startImportNode(importNode.rawArgument());
385             emitDocumentedNode(importNode);
386             emitPrefixNode(importNode.getPrefix());
387             emitRevisionDateNode(importNode.getRevisionDate());
388             super.writer.endNode();
389         }
390
391         private void emitInclude(final IncludeStatement include) {
392             super.writer.startIncludeNode(include.rawArgument());
393             emitDocumentedNode(include);
394             emitRevisionDateNode(include.getRevisionDate());
395             super.writer.endNode();
396         }
397
398         private void emitNamespace(final NamespaceStatement namespaceStatement) {
399             Preconditions.checkNotNull(namespaceStatement, "Namespace must not be null");
400             super.writer.startNamespaceNode(namespaceStatement.getUri());
401             super.writer.endNode();
402         }
403
404         private void emitPrefixNode(final PrefixStatement prefixStatement) {
405             Preconditions.checkNotNull(prefixStatement, "Prefix must not be null");
406             super.writer.startPrefixNode(prefixStatement.rawArgument());
407             super.writer.endNode();
408         }
409
410         private void emitOrganizationNode(@Nullable final OrganizationStatement organizationStatement) {
411             if (organizationStatement != null) {
412                 super.writer.startOrganizationNode(organizationStatement.rawArgument());
413                 super.writer.endNode();
414             }
415         }
416
417         private void emitContact(@Nullable final ContactStatement contactStatement) {
418             if (contactStatement != null) {
419                 super.writer.startContactNode(contactStatement.rawArgument());
420                 super.writer.endNode();
421             }
422         }
423
424         private void emitDescriptionNode(@Nullable final DescriptionStatement descriptionStatement) {
425             if (descriptionStatement != null) {
426                 super.writer.startDescriptionNode(descriptionStatement.rawArgument());
427                 super.writer.endNode();
428             }
429         }
430
431         private void emitReferenceNode(@Nullable final ReferenceStatement referenceStatement) {
432             if (referenceStatement != null) {
433                 super.writer.startReferenceNode(referenceStatement.rawArgument());
434                 super.writer.endNode();
435             }
436         }
437
438         private void emitUnitsNode(@Nullable final UnitsStatement unitsStatement) {
439             if (unitsStatement != null) {
440                 super.writer.startUnitsNode(unitsStatement.rawArgument());
441                 super.writer.endNode();
442             }
443         }
444
445         private void emitRevisions(final Collection<? extends RevisionStatement> revisions) {
446             for (final RevisionStatement revisionStatement : revisions) {
447                 emitRevision(revisionStatement);
448             }
449         }
450
451         private void emitRevision(final RevisionStatement revision) {
452             super.writer.startRevisionNode(revision.rawArgument());
453             emitDocumentedNode(revision);
454             super.writer.endNode();
455         }
456
457         private void emitRevisionDateNode(@Nullable final RevisionDateStatement revisionDateStatement) {
458             if (revisionDateStatement != null) {
459                 super.writer.startRevisionDateNode(revisionDateStatement.rawArgument());
460                 super.writer.endNode();
461             }
462         }
463
464         private void emitExtension(final org.opendaylight.yangtools.yang.model.api.stmt.ExtensionStatement extension) {
465             super.writer.startExtensionNode(extension.rawArgument());
466             emitArgument(extension.getArgument());
467             emitDocumentedNodeWithStatus(extension);
468             emitUnknownStatementNodes(extension);
469             super.writer.endNode();
470         }
471
472         private void emitArgument(@Nullable final ArgumentStatement input) {
473             if (input != null) {
474                 super.writer.startArgumentNode(input.rawArgument());
475                 emitYinElement(input.getYinElement());
476                 super.writer.endNode();
477             }
478         }
479
480         private void emitYinElement(@Nullable final YinElementStatement yinElementStatement) {
481             if (yinElementStatement != null) {
482                 super.writer.startYinElementNode(yinElementStatement.rawArgument());
483                 super.writer.endNode();
484             }
485         }
486
487         private void emitIdentity(final IdentityStatement identity) {
488             super.writer.startIdentityNode(identity.rawArgument());
489             emitBaseIdentities(identity.getBases());
490             emitStatusNode(identity.getStatus());
491             emitDescriptionNode(identity.getDescription());
492             emitReferenceNode(identity.getReference());
493             super.writer.endNode();
494         }
495
496         private void emitBaseIdentities(final Collection<? extends BaseStatement> collection) {
497             for (final BaseStatement baseStmt : collection) {
498                 emitBase(baseStmt);
499             }
500         }
501
502         private void emitBase(final BaseStatement baseStmt) {
503             super.writer.startBaseNode(baseStmt.rawArgument());
504             super.writer.endNode();
505         }
506
507         private void emitFeature(final FeatureStatement feature) {
508             super.writer.startFeatureNode(feature.rawArgument());
509             emitIfFeatures(feature.getIfFeatures());
510             emitDocumentedNodeWithStatus(feature);
511             super.writer.endNode();
512         }
513
514         private void emitIfFeatures(final Collection<? extends IfFeatureStatement> ifFeatures) {
515             for (final IfFeatureStatement ifFeatureStatement : ifFeatures) {
516                 emitIfFeature(ifFeatureStatement);
517             }
518         }
519
520         private void emitIfFeature(final IfFeatureStatement ifFeature) {
521             super.writer.startIfFeatureNode(ifFeature.rawArgument());
522             super.writer.endNode();
523         }
524
525         private void emitTypedefNode(final TypedefStatement typedef) {
526             super.writer.startTypedefNode(typedef.rawArgument());
527             emitType(typedef.getType());
528             emitUnitsNode(typedef.getUnits());
529             emitDefaultNode(typedef.getDefault());
530             emitStatusNode(typedef.getStatus());
531             emitDescriptionNode(typedef.getDescription());
532             emitReferenceNode(typedef.getReference());
533             emitUnknownStatementNodes(typedef);
534             super.writer.endNode();
535         }
536
537         private void emitType(final TypeStatement typeStatement) {
538             super.writer.startTypeNode(typeStatement.rawArgument());
539             for (final DeclaredStatement<?> typeSubstmt : typeStatement.declaredSubstatements()) {
540                 if (typeSubstmt instanceof RangeStatement) {
541                     emitRange((RangeStatement) typeSubstmt);
542                 } else if (typeSubstmt instanceof LengthStatement) {
543                     emitLength((LengthStatement) typeSubstmt);
544                 } else if (typeSubstmt instanceof PatternStatement) {
545                     emitPattern((PatternStatement) typeSubstmt);
546                 } else if (typeSubstmt instanceof FractionDigitsStatement) {
547                     emitFractionDigits((FractionDigitsStatement) typeSubstmt);
548                 } else if (typeSubstmt instanceof EnumStatement) {
549                     emitEnum((EnumStatement) typeSubstmt);
550                 } else if (typeSubstmt instanceof PathStatement) {
551                     emitPath((PathStatement) typeSubstmt);
552                 } else if (typeSubstmt instanceof RequireInstanceStatement) {
553                     emitRequireInstance((RequireInstanceStatement) typeSubstmt);
554                 } else if (typeSubstmt instanceof BaseStatement) {
555                     emitBase((BaseStatement) typeSubstmt);
556                 } else if (typeSubstmt instanceof BitStatement) {
557                     emitBit((BitStatement) typeSubstmt);
558                 } else if (typeSubstmt instanceof TypeStatement) {
559                     emitType((TypeStatement) typeSubstmt);
560                 }
561             }
562             super.writer.endNode();
563         }
564
565         private void emitRange(final RangeStatement range) {
566             super.writer.startRangeNode(range.rawArgument());
567             emitDocumentedConstraint(range);
568             super.writer.endNode();
569         }
570
571         private void emitFractionDigits(final FractionDigitsStatement fractionDigits) {
572             super.writer.startFractionDigitsNode(fractionDigits.rawArgument());
573             super.writer.endNode();
574         }
575
576         private void emitLength(final LengthStatement lengthStatement) {
577             super.writer.startLengthNode(lengthStatement.rawArgument());
578             emitDocumentedConstraint(lengthStatement);
579             super.writer.endNode();
580         }
581
582         private void emitPattern(final PatternStatement pattern) {
583             super.writer.startPatternNode(pattern.rawArgument());
584             emitModifier(pattern.getModifierStatement());
585             emitDocumentedConstraint(pattern);
586             super.writer.endNode();
587         }
588
589         private void emitModifier(final ModifierStatement modifierStatement) {
590             if (modifierStatement != null) {
591                 super.writer.startModifierNode(modifierStatement.rawArgument());
592                 super.writer.endNode();
593             }
594         }
595
596         private void emitDefaultNodes(final Collection<? extends DefaultStatement> collection) {
597             for (final DefaultStatement defaultValue : collection) {
598                 emitDefaultNode(defaultValue);
599             }
600         }
601
602         private void emitDefaultNode(@Nullable final DefaultStatement defaultStmt) {
603             if (defaultStmt != null) {
604                 super.writer.startDefaultNode(defaultStmt.rawArgument());
605                 super.writer.endNode();
606             }
607         }
608
609         private void emitEnum(final EnumStatement enumStmt) {
610             super.writer.startEnumNode(enumStmt.rawArgument());
611             emitDocumentedNodeWithStatus(enumStmt);
612             emitValueNode(enumStmt.getValue());
613             super.writer.endNode();
614         }
615
616         private void emitPath(final PathStatement path) {
617             super.writer.startPathNode(path.rawArgument());
618             super.writer.endNode();
619         }
620
621         private void emitRequireInstance(final RequireInstanceStatement require) {
622             super.writer.startRequireInstanceNode(require.rawArgument());
623             super.writer.endNode();
624         }
625
626         private void emitBit(final BitStatement bit) {
627             super.writer.startBitNode(bit.rawArgument());
628             emitPositionNode(bit.getPosition());
629             emitDocumentedNodeWithStatus(bit);
630             super.writer.endNode();
631         }
632
633         private void emitPositionNode(@Nullable final PositionStatement positionStatement) {
634             if (positionStatement != null) {
635                 super.writer.startPositionNode(positionStatement.rawArgument());
636                 super.writer.endNode();
637             }
638         }
639
640         private void emitStatusNode(@Nullable final StatusStatement statusStatement) {
641             if (statusStatement != null) {
642                 super.writer.startStatusNode(statusStatement.rawArgument());
643                 super.writer.endNode();
644             }
645         }
646
647         private void emitConfigNode(@Nullable final ConfigStatement configStatement) {
648             if (configStatement != null) {
649                 super.writer.startConfigNode(configStatement.rawArgument());
650                 super.writer.endNode();
651             }
652         }
653
654         private void emitMandatoryNode(@Nullable final MandatoryStatement mandatoryStatement) {
655             if (mandatoryStatement != null) {
656                 super.writer.startMandatoryNode(mandatoryStatement.rawArgument());
657                 super.writer.endNode();
658             }
659         }
660
661         private void emitPresenceNode(@Nullable final PresenceStatement presenceStatement) {
662             if (presenceStatement != null) {
663                 super.writer.startPresenceNode(presenceStatement.rawArgument());
664                 super.writer.endNode();
665             }
666         }
667
668         private void emitOrderedBy(@Nullable final OrderedByStatement orderedByStatement) {
669             if (orderedByStatement != null) {
670                 super.writer.startOrderedByNode(orderedByStatement.rawArgument());
671                 super.writer.endNode();
672             }
673         }
674
675         private void emitMust(@Nullable final MustStatement must) {
676             if (must != null) {
677                 super.writer.startMustNode(must.rawArgument());
678                 emitErrorMessageNode(must.getErrorMessageStatement());
679                 emitErrorAppTagNode(must.getErrorAppTagStatement());
680                 emitDescriptionNode(must.getDescription());
681                 emitReferenceNode(must.getReference());
682                 super.writer.endNode();
683             }
684         }
685
686         private void emitErrorMessageNode(@Nullable final ErrorMessageStatement errorMessageStatement) {
687             if (errorMessageStatement != null) {
688                 super.writer.startErrorMessageNode(errorMessageStatement.rawArgument());
689                 super.writer.endNode();
690             }
691         }
692
693         private void emitErrorAppTagNode(@Nullable final ErrorAppTagStatement errorAppTagStatement) {
694             if (errorAppTagStatement != null) {
695                 super.writer.startErrorAppTagNode(errorAppTagStatement.rawArgument());
696                 super.writer.endNode();
697             }
698         }
699
700         private void emitMinElementsNode(@Nullable final MinElementsStatement minElementsStatement) {
701             if (minElementsStatement != null) {
702                 super.writer.startMinElementsNode(minElementsStatement.rawArgument());
703                 super.writer.endNode();
704             }
705         }
706
707         private void emitMaxElementsNode(@Nullable final MaxElementsStatement maxElementsStatement) {
708             if (maxElementsStatement != null) {
709                 super.writer.startMaxElementsNode(maxElementsStatement.rawArgument());
710                 super.writer.endNode();
711             }
712         }
713
714         private void emitValueNode(@Nullable final ValueStatement valueStatement) {
715             if (valueStatement != null) {
716                 super.writer.startValueNode(valueStatement.rawArgument());
717                 super.writer.endNode();
718             }
719         }
720
721         private void emitDocumentedNodeWithStatus(final DocumentationGroup.WithStatus input) {
722             emitStatusNode(input.getStatus());
723             emitDocumentedNode(input);
724         }
725
726         private void emitDocumentedNode(final DocumentationGroup input) {
727             emitDescriptionNode(input.getDescription());
728             emitReferenceNode(input.getReference());
729         }
730
731         private void emitDocumentedConstraint(final DocumentedConstraintGroup input) {
732             emitDescriptionNode(input.getDescription());
733             emitReferenceNode(input.getReference());
734             emitErrorMessageNode(input.getErrorMessageStatement());
735             emitErrorAppTagNode(input.getErrorAppTagStatement());
736         }
737
738         private void emitGrouping(final GroupingStatement grouping) {
739             super.writer.startGroupingNode(grouping.rawArgument());
740             emitDocumentedNodeWithStatus(grouping);
741             emitDataNodeContainer(grouping);
742             emitUnknownStatementNodes(grouping);
743             emitNotifications(grouping.getNotifications());
744             emitActions(grouping.getActions());
745             super.writer.endNode();
746
747         }
748
749         private void emitContainer(final ContainerStatement container) {
750             super.writer.startContainerNode(container.rawArgument());
751             emitWhen(container.getWhenStatement());
752             emitMustNodes(container.getMusts());
753             emitIfFeatures(container.getIfFeatures());
754             emitPresenceNode(container.getPresence());
755             emitConfigNode(container.getConfig());
756             emitDocumentedNodeWithStatus(container);
757             emitDataNodeContainer(container);
758             emitUnknownStatementNodes(container);
759             emitNotifications(container.getNotifications());
760             emitActions(container.getActions());
761             super.writer.endNode();
762
763         }
764
765         private void emitLeaf(final LeafStatement leaf) {
766             super.writer.startLeafNode(leaf.rawArgument());
767             emitWhen(leaf.getWhenStatement());
768             emitIfFeatures(leaf.getIfFeatures());
769             emitType(leaf.getType());
770             emitUnitsNode(leaf.getUnits());
771             emitMustNodes(leaf.getMusts());
772             emitDefaultNode(leaf.getDefault());
773             emitConfigNode(leaf.getConfig());
774             emitMandatoryNode(leaf.getMandatory());
775             emitDocumentedNodeWithStatus(leaf);
776             emitUnknownStatementNodes(leaf);
777             super.writer.endNode();
778         }
779
780         private void emitLeafList(final LeafListStatement leafList) {
781             super.writer.startLeafListNode(leafList.rawArgument());
782             emitWhen(leafList.getWhenStatement());
783             emitIfFeatures(leafList.getIfFeatures());
784             emitType(leafList.getType());
785             emitUnitsNode(leafList.getUnits());
786             emitMustNodes(leafList.getMusts());
787             emitConfigNode(leafList.getConfig());
788             emitDefaultNodes(leafList.getDefaults());
789             emitMinElementsNode(leafList.getMinElements());
790             emitMaxElementsNode(leafList.getMaxElements());
791             emitOrderedBy(leafList.getOrderedBy());
792             emitDocumentedNodeWithStatus(leafList);
793             emitUnknownStatementNodes(leafList);
794             super.writer.endNode();
795         }
796
797         private void emitList(final ListStatement list) {
798             super.writer.startListNode(list.rawArgument());
799             emitWhen(list.getWhenStatement());
800             emitIfFeatures(list.getIfFeatures());
801             emitMustNodes(list.getMusts());
802             emitKey(list.getKey());
803             emitUniqueConstraints(list.getUnique());
804             emitConfigNode(list.getConfig());
805             emitMinElementsNode(list.getMinElements());
806             emitMaxElementsNode(list.getMaxElements());
807             emitOrderedBy(list.getOrderedBy());
808             emitDocumentedNodeWithStatus(list);
809             emitDataNodeContainer(list);
810             emitUnknownStatementNodes(list);
811             emitNotifications(list.getNotifications());
812             emitActions(list.getActions());
813             super.writer.endNode();
814         }
815
816         private void emitMustNodes(final Collection<? extends MustStatement> collection) {
817             for (final MustStatement must : collection) {
818                 emitMust(must);
819             }
820         }
821
822         private void emitKey(final KeyStatement keyStatement) {
823             if (keyStatement != null) {
824                 super.writer.startKeyNode(keyStatement.rawArgument());
825                 super.writer.endNode();
826             }
827         }
828
829         private void emitUniqueConstraints(final Collection<? extends UniqueStatement> collection) {
830             for (final UniqueStatement uniqueConstraint : collection) {
831                 emitUnique(uniqueConstraint);
832             }
833         }
834
835         private void emitUnique(final UniqueStatement uniqueConstraint) {
836             if (uniqueConstraint != null) {
837                 super.writer.startUniqueNode(uniqueConstraint.rawArgument());
838                 super.writer.endNode();
839             }
840         }
841
842         private void emitChoice(final ChoiceStatement choice) {
843             super.writer.startChoiceNode(choice.rawArgument());
844             emitWhen(choice.getWhenStatement());
845             emitIfFeatures(choice.getIfFeatures());
846             emitDefaultNode(choice.getDefault());
847             emitConfigNode(choice.getConfig());
848             emitMandatoryNode(choice.getMandatory());
849             emitDocumentedNodeWithStatus(choice);
850             emitCases(choice.getCases());
851             emitUnknownStatementNodes(choice);
852             super.writer.endNode();
853         }
854
855         private void emitShortCases(final Collection<? extends DeclaredStatement<?>> declaredSubstatements) {
856             for (final DeclaredStatement<?> child : declaredSubstatements) {
857                 if (child instanceof ContainerStatement) {
858                     emitContainer((ContainerStatement) child);
859                 } else if (child instanceof LeafStatement) {
860                     emitLeaf((LeafStatement) child);
861                 } else if (child instanceof LeafListStatement) {
862                     emitLeafList((LeafListStatement) child);
863                 } else if (child instanceof ListStatement) {
864                     emitList((ListStatement) child);
865                 } else if (child instanceof ChoiceStatement) {
866                     emitChoice((ChoiceStatement) child);
867                 } else if (child instanceof AnyxmlStatement) {
868                     emitAnyxml((AnyxmlStatement) child);
869                 } else if (child instanceof AnydataStatement) {
870                     emitAnydata((AnydataStatement) child);
871                 }
872             }
873         }
874
875         private void emitCases(final Collection<? extends CaseStatement> cases) {
876             for (final CaseStatement caze : cases) {
877                 if (isExplicitStatement(caze)) {
878                     emitCaseNode(caze);
879                 } else {
880                     final Collection<? extends DeclaredStatement<?>> shortCaseChilds = caze.declaredSubstatements();
881                     Preconditions.checkState(shortCaseChilds.size() == 1,
882                             "Only one child is allowed for each short case node");
883                     emitShortCases(shortCaseChilds);
884                 }
885             }
886         }
887
888         private void emitCaseNode(final CaseStatement caze) {
889             super.writer.startCaseNode(caze.rawArgument());
890             emitWhen(caze.getWhenStatement());
891             emitIfFeatures(caze.getIfFeatures());
892             emitDocumentedNodeWithStatus(caze);
893             emitDataNodeContainer(caze);
894             emitUnknownStatementNodes(caze);
895             super.writer.endNode();
896         }
897
898         private void emitAnyxml(final AnyxmlStatement anyxml) {
899             super.writer.startAnyxmlNode(anyxml.rawArgument());
900             emitDocumentedNodeWithStatus(anyxml);
901             emitWhen(anyxml.getWhenStatement());
902             emitIfFeatures(anyxml.getIfFeatures());
903             emitMustNodes(anyxml.getMusts());
904             emitConfigNode(anyxml.getConfig());
905             emitMandatoryNode(anyxml.getMandatory());
906             emitDocumentedNodeWithStatus(anyxml);
907             emitUnknownStatementNodes(anyxml);
908             super.writer.endNode();
909         }
910
911         private void emitAnydata(final AnydataStatement anydata) {
912             super.writer.startAnydataNode(anydata.rawArgument());
913             emitWhen(anydata.getWhenStatement());
914             emitIfFeatures(anydata.getIfFeatures());
915             emitMustNodes(anydata.getMusts());
916             emitConfigNode(anydata.getConfig());
917             emitMandatoryNode(anydata.getMandatory());
918             emitDocumentedNodeWithStatus(anydata);
919             emitUnknownStatementNodes(anydata);
920             super.writer.endNode();
921         }
922
923         private void emitUsesNode(final UsesStatement uses) {
924             super.writer.startUsesNode(uses.rawArgument());
925             emitWhen(uses.getWhenStatement());
926             emitIfFeatures(uses.getIfFeatures());
927             emitDocumentedNodeWithStatus(uses);
928             for (final RefineStatement refine : uses.getRefines()) {
929                 emitRefine(refine);
930             }
931             for (final AugmentStatement aug : uses.getAugments()) {
932                 emitUsesAugmentNode(aug);
933             }
934             super.writer.endNode();
935         }
936
937         private void emitRefine(final RefineStatement refine) {
938             super.writer.startRefineNode(refine.rawArgument());
939             emitDocumentedNode(refine);
940             emitIfFeatures(refine.getIfFeatures());
941             emitMustNodes(refine.getMusts());
942             emitPresenceNode(refine.getPresence());
943             emitDefaultNodes(refine.getDefaults());
944             emitConfigNode(refine.getConfig());
945             emitMandatoryNode(refine.getMandatory());
946             emitMinElementsNode(refine.getMinElements());
947             emitMaxElementsNode(refine.getMaxElements());
948             super.writer.endNode();
949         }
950
951         private void emitUsesAugmentNode(final AugmentStatement aug) {
952             /**
953              * differs only in location in schema, otherwise currently (as of
954              * RFC6020) it is same, so we could freely reuse path.
955              */
956             emitAugment(aug);
957         }
958
959         private void emitAugment(final AugmentStatement augmentation) {
960             super.writer.startAugmentNode(augmentation.rawArgument());
961             emitIfFeatures(augmentation.getIfFeatures());
962             emitWhen(augmentation.getWhenStatement());
963             emitDocumentedNodeWithStatus(augmentation);
964             emitDataNodeContainer(augmentation);
965             emitCases(augmentation.getCases());
966             emitUnknownStatementNodes(augmentation);
967             emitNotifications(augmentation.getNotifications());
968             emitActions(augmentation.getActions());
969             super.writer.endNode();
970         }
971
972         private void emitUnknownStatementNodes(final DeclaredStatement<?> decaredStmt) {
973             final Collection<? extends DeclaredStatement<?>> unknownStmts = Collections2
974                     .filter(decaredStmt.declaredSubstatements(), Predicates.instanceOf(UnknownStatement.class));
975             for (final DeclaredStatement<?> unknonwnStmt : unknownStmts) {
976                 emitUnknownStatementNode(unknonwnStmt);
977             }
978         }
979
980         private void emitUnknownStatementNode(final DeclaredStatement<?> unknonwnStmt) {
981             final StatementDefinition def = unknonwnStmt.statementDefinition();
982             if (def.getArgumentName() == null) {
983                 super.writer.startUnknownNode(def);
984             } else {
985                 super.writer.startUnknownNode(def, unknonwnStmt.rawArgument());
986             }
987             emitUnknownStatementNodes(unknonwnStmt);
988             super.writer.endNode();
989         }
990
991         private void emitWhen(final WhenStatement whenStatement) {
992             if (whenStatement != null) {
993                 super.writer.startWhenNode(whenStatement.rawArgument());
994                 emitDocumentedNode(whenStatement);
995                 super.writer.endNode();
996             }
997         }
998
999         private void emitRpc(final RpcStatement rpc) {
1000             super.writer.startRpcNode(rpc.rawArgument());
1001             emitOperationBody(rpc);
1002             emitUnknownStatementNodes(rpc);
1003             super.writer.endNode();
1004         }
1005
1006         private void emitOperationBody(final OperationGroup operationStmt) {
1007             emitIfFeatures(operationStmt.getIfFeatures());
1008             emitStatusNode(operationStmt.getStatus());
1009             emitDescriptionNode(operationStmt.getDescription());
1010             emitReferenceNode(operationStmt.getReference());
1011
1012             for (final TypedefStatement typedef : operationStmt.getTypedefs()) {
1013                 emitTypedefNode(typedef);
1014             }
1015             for (final GroupingStatement grouping : operationStmt.getGroupings()) {
1016                 emitGrouping(grouping);
1017             }
1018             emitInput(operationStmt.getInput());
1019             emitOutput(operationStmt.getOutput());
1020         }
1021
1022         private void emitActions(final Collection<? extends ActionStatement> collection) {
1023             for (final ActionStatement actionDefinition : collection) {
1024                 emitAction(actionDefinition);
1025             }
1026         }
1027
1028         private void emitAction(final ActionStatement actionDefinition) {
1029             super.writer.startActionNode(actionDefinition.rawArgument());
1030             emitOperationBody(actionDefinition);
1031             emitUnknownStatementNodes(actionDefinition);
1032             super.writer.endNode();
1033         }
1034
1035         private void emitInput(final InputStatement inputStatement) {
1036             if (isExplicitStatement(inputStatement)) {
1037                 super.writer.startInputNode();
1038                 emitMustNodes(inputStatement.getMusts());
1039                 emitDataNodeContainer(inputStatement);
1040                 emitUnknownStatementNodes(inputStatement);
1041                 super.writer.endNode();
1042             }
1043         }
1044
1045         private void emitOutput(final OutputStatement output) {
1046             if (isExplicitStatement(output)) {
1047                 super.writer.startOutputNode();
1048                 emitMustNodes(output.getMusts());
1049                 emitDataNodeContainer(output);
1050                 emitUnknownStatementNodes(output);
1051                 super.writer.endNode();
1052             }
1053         }
1054
1055         private static boolean isExplicitStatement(final DeclaredStatement<?> stmt) {
1056             return stmt != null && stmt.getStatementSource() == StatementSource.DECLARATION;
1057         }
1058
1059         private void emitNotifications(final Collection<? extends NotificationStatement> collection) {
1060             for (final NotificationStatement notification : collection) {
1061                 emitNotificationNode(notification);
1062             }
1063         }
1064
1065         private void emitNotificationNode(final NotificationStatement notification) {
1066             super.writer.startNotificationNode(notification.rawArgument());
1067             emitIfFeatures(notification.getIfFeatures());
1068             emitMustNodes(notification.getMusts());
1069             emitDocumentedNodeWithStatus(notification);
1070             emitDataNodeContainer(notification);
1071             emitUnknownStatementNodes(notification);
1072             super.writer.endNode();
1073         }
1074
1075         private void emitDeviation(final DeviationStatement deviation) {
1076             super.writer.startDeviationNode(deviation.rawArgument());
1077             emitDeviateStatements(deviation.getDeviateStatements());
1078             emitUnknownStatementNodes(deviation);
1079             super.writer.endNode();
1080         }
1081
1082         private void emitDeviateStatements(final Collection<? extends DeviateStatement> deviateStatements) {
1083             for (final DeviateStatement deviateStatement : deviateStatements) {
1084                 emitDeviate(deviateStatement);
1085             }
1086         }
1087
1088         private void emitDeviate(final DeviateStatement deviateStatement) {
1089             super.writer.startDeviateNode(deviateStatement.rawArgument());
1090             /*
1091              * :FIXME Currently, DeviateStatementImpl contains implementation
1092              * for all deviate types (i.e. add, replace, delete). However it
1093              * would be better to create subinterfaces of DeviateStatement for
1094              * each deviate type (i.e. AddDeviateStatement,
1095              * ReplaceDeviateStatement,..) and create argument specific supports
1096              * (i.e. definitions) for each deviate type (very similarly like by
1097              * TypeStatement).
1098              */
1099             for (final DeclaredStatement<?> child : deviateStatement.declaredSubstatements()) {
1100                 if (child instanceof MustStatement) {
1101                     emitMust((MustStatement) child);
1102                 } else if (child instanceof DefaultStatement) {
1103                     emitDefaultNode((DefaultStatement) child);
1104                 } else if (child instanceof UniqueStatement) {
1105                     emitUnique((UniqueStatement) child);
1106                 } else if (child instanceof UnitsStatement) {
1107                     emitUnitsNode((UnitsStatement) child);
1108                 } else if (child instanceof TypeStatement) {
1109                     emitType((TypeStatement) child);
1110                 } else if (child instanceof MinElementsStatement) {
1111                     emitMinElementsNode((MinElementsStatement) child);
1112                 } else if (child instanceof MaxElementsStatement) {
1113                     emitMaxElementsNode((MaxElementsStatement) child);
1114                 } else if (child instanceof MandatoryStatement) {
1115                     emitMandatoryNode((MandatoryStatement) child);
1116                 } else if (child instanceof ConfigStatement) {
1117                     emitConfigNode((ConfigStatement) child);
1118                 } else if (child instanceof UnknownStatement) {
1119                     emitUnknownStatementNode((UnknownStatement<?>) child);
1120                 }
1121             }
1122             super.writer.endNode();
1123         }
1124     }
1125
1126     static class EffectiveSchemaContextEmitter extends SchemaContextEmitter {
1127
1128         EffectiveSchemaContextEmitter(final YangModuleWriter writer, final Map<QName, StatementDefinition> extensions,
1129                 final YangVersion yangVersion, final boolean emitInstantiated) {
1130             super(writer, extensions, yangVersion, emitInstantiated, true);
1131         }
1132
1133         void emitModule(final Module input) {
1134             super.writer.startModuleNode(input.getName());
1135             emitModuleHeader(input);
1136             emitLinkageNodes(input);
1137             emitMetaNodes(input);
1138             emitRevisionNodes(input);
1139             emitBodyNodes(input);
1140             super.writer.endNode();
1141         }
1142
1143         private void emitModuleHeader(final Module input) {
1144             emitYangVersionNode(input.getYangVersion());
1145             emitNamespace(input.getNamespace());
1146             emitPrefixNode(input.getPrefix());
1147         }
1148
1149         @SuppressWarnings("unused")
1150         private void emitSubmodule(final String input) {
1151             /*
1152              * FIXME: BUG-2444: Implement submodule export
1153              *
1154              * submoduleHeaderNodes linkageNodes metaNodes revisionNodes
1155              * bodyNodes super.writer.endNode();
1156              */
1157         }
1158
1159         @SuppressWarnings("unused")
1160         private void emitSubmoduleHeaderNodes(final Module input) {
1161             /*
1162              * FIXME: BUG-2444: Implement submodule headers properly
1163              *
1164              * :yangVersionNode //Optional
1165              *
1166              * :belongsToNode
1167              */
1168         }
1169
1170         private void emitMetaNodes(final Module input) {
1171             emitOrganizationNode(input.getOrganization());
1172             emitContact(input.getContact());
1173             emitDescriptionNode(input.getDescription());
1174             emitReferenceNode(input.getReference());
1175         }
1176
1177         private void emitLinkageNodes(final Module input) {
1178             for (final ModuleImport importNode : input.getImports()) {
1179                 emitImport(importNode);
1180             }
1181             /*
1182              * FIXME: BUG-2444: Emit include statements
1183              */
1184         }
1185
1186         private void emitRevisionNodes(final Module input) {
1187             /*
1188              * FIXME: BUG-2444: emit revisions properly, when parsed model will
1189              * provide enough information
1190              */
1191             emitRevision(input.getRevision());
1192
1193         }
1194
1195         private void emitBodyNodes(final Module input) {
1196
1197             for (final ExtensionDefinition extension : input.getExtensionSchemaNodes()) {
1198                 emitExtension(extension);
1199             }
1200             for (final FeatureDefinition definition : input.getFeatures()) {
1201                 emitFeature(definition);
1202             }
1203             for (final IdentitySchemaNode identity : input.getIdentities()) {
1204                 emitIdentity(identity);
1205             }
1206             for (final Deviation deviation : input.getDeviations()) {
1207                 emitDeviation(deviation);
1208             }
1209
1210             emitDataNodeContainer(input);
1211
1212             for (final AugmentationSchema augmentation : input.getAugmentations()) {
1213                 emitAugment(augmentation);
1214             }
1215             for (final RpcDefinition rpc : input.getRpcs()) {
1216                 emitRpc(rpc);
1217             }
1218
1219             emitNotifications(input.getNotifications());
1220         }
1221
1222         private void emitDataNodeContainer(final DataNodeContainer input) {
1223             for (final TypeDefinition<?> typedef : input.getTypeDefinitions()) {
1224                 emitTypedefNode(typedef);
1225             }
1226             for (final GroupingDefinition grouping : input.getGroupings()) {
1227                 emitGrouping(grouping);
1228             }
1229             for (final DataSchemaNode child : input.getChildNodes()) {
1230                 emitDataSchemaNode(child);
1231             }
1232             for (final UsesNode usesNode : input.getUses()) {
1233                 emitUsesNode(usesNode);
1234             }
1235         }
1236
1237         private void emitDataSchemaNode(final DataSchemaNode child) {
1238             if (!super.emitInstantiated && (child.isAddedByUses() || child.isAugmenting())) {
1239                 // We skip instantiated nodes.
1240                 return;
1241             }
1242
1243             if (child instanceof ContainerSchemaNode) {
1244                 emitContainer((ContainerSchemaNode) child);
1245             } else if (child instanceof LeafSchemaNode) {
1246                 emitLeaf((LeafSchemaNode) child);
1247             } else if (child instanceof LeafListSchemaNode) {
1248                 emitLeafList((LeafListSchemaNode) child);
1249             } else if (child instanceof ListSchemaNode) {
1250                 emitList((ListSchemaNode) child);
1251             } else if (child instanceof ChoiceSchemaNode) {
1252                 emitChoice((ChoiceSchemaNode) child);
1253             } else if (child instanceof AnyXmlSchemaNode) {
1254                 emitAnyxml((AnyXmlSchemaNode) child);
1255             } else if (child instanceof AnyDataSchemaNode) {
1256                 emitAnydata((AnyDataSchemaNode) child);
1257             } else {
1258                 throw new UnsupportedOperationException("Not supported DataSchemaNode type " + child.getClass());
1259             }
1260         }
1261
1262         private void emitYangVersionNode(final String input) {
1263             super.writer.startYangVersionNode(input);
1264             super.writer.endNode();
1265         }
1266
1267         private void emitImport(final ModuleImport importNode) {
1268             super.writer.startImportNode(importNode.getModuleName());
1269             emitDescriptionNode(importNode.getDescription());
1270             emitReferenceNode(importNode.getReference());
1271             emitPrefixNode(importNode.getPrefix());
1272             emitRevisionDateNode(importNode.getRevision());
1273             super.writer.endNode();
1274         }
1275
1276         @SuppressWarnings("unused")
1277         private void emitInclude(final String input) {
1278             /*
1279              * FIXME: BUG-2444: Implement proper export of include statements
1280              * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
1281              *
1282              *
1283              * :revisionDateNode :super.writer.endNode();)
1284              */
1285         }
1286
1287         private void emitNamespace(final URI uri) {
1288             super.writer.startNamespaceNode(uri);
1289             super.writer.endNode();
1290
1291         }
1292
1293         private void emitPrefixNode(final String input) {
1294             super.writer.startPrefixNode(input);
1295             super.writer.endNode();
1296
1297         }
1298
1299         @SuppressWarnings("unused")
1300         private void emitBelongsTo(final String input) {
1301             /*
1302              * FIXME: BUG-2444: Implement proper export of belongs-to statements
1303              * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
1304              *
1305              *
1306              * :super.writer.startBelongsToNode(IdentifierHelper.getIdentifier(
1307              * String :input));
1308              *
1309              *
1310              * :prefixNode :super.writer.endNode();
1311              *
1312              */
1313
1314         }
1315
1316         private void emitOrganizationNode(final String input) {
1317             if (!Strings.isNullOrEmpty(input)) {
1318                 super.writer.startOrganizationNode(input);
1319                 super.writer.endNode();
1320             }
1321         }
1322
1323         private void emitContact(final String input) {
1324             if (!Strings.isNullOrEmpty(input)) {
1325                 super.writer.startContactNode(input);
1326                 super.writer.endNode();
1327             }
1328         }
1329
1330         private void emitDescriptionNode(@Nullable final String input) {
1331             if (!Strings.isNullOrEmpty(input)) {
1332                 super.writer.startDescriptionNode(input);
1333                 super.writer.endNode();
1334             }
1335         }
1336
1337         private void emitReferenceNode(@Nullable final String input) {
1338             if (!Strings.isNullOrEmpty(input)) {
1339                 super.writer.startReferenceNode(input);
1340                 super.writer.endNode();
1341             }
1342         }
1343
1344         private void emitUnitsNode(@Nullable final String input) {
1345             if (!Strings.isNullOrEmpty(input)) {
1346                 super.writer.startUnitsNode(input);
1347                 super.writer.endNode();
1348             }
1349         }
1350
1351         private void emitRevision(final Date date) {
1352             super.writer.startRevisionNode(date);
1353
1354             //
1355             // FIXME: BUG-2444: FIXME: BUG-2444: BUG-2417: descriptionNode
1356             // //FIXME: BUG-2444: Optional
1357             // FIXME: BUG-2444: FIXME: BUG-2444: BUG-2417: referenceNode
1358             // //FIXME: BUG-2444: Optional
1359             super.writer.endNode();
1360
1361         }
1362
1363         private void emitRevisionDateNode(@Nullable final Date date) {
1364             if (date != null) {
1365                 super.writer.startRevisionDateNode(date);
1366                 super.writer.endNode();
1367             }
1368         }
1369
1370         private void emitExtension(final ExtensionDefinition extension) {
1371             super.writer.startExtensionNode(extension.getQName());
1372             emitArgument(extension.getArgument(), extension.isYinElement());
1373             emitStatusNode(extension.getStatus());
1374             emitDescriptionNode(extension.getDescription());
1375             emitReferenceNode(extension.getReference());
1376             emitUnknownStatementNodes(extension.getUnknownSchemaNodes());
1377             super.writer.endNode();
1378
1379         }
1380
1381         private void emitArgument(final @Nullable String input, final boolean yinElement) {
1382             if (input != null) {
1383                 super.writer.startArgumentNode(input);
1384                 emitYinElement(yinElement);
1385                 super.writer.endNode();
1386             }
1387
1388         }
1389
1390         private void emitYinElement(final boolean yinElement) {
1391             super.writer.startYinElementNode(yinElement);
1392             super.writer.endNode();
1393
1394         }
1395
1396         private void emitIdentity(final IdentitySchemaNode identity) {
1397             super.writer.startIdentityNode(identity.getQName());
1398             emitBaseIdentities(identity.getBaseIdentities());
1399             emitStatusNode(identity.getStatus());
1400             emitDescriptionNode(identity.getDescription());
1401             emitReferenceNode(identity.getReference());
1402             super.writer.endNode();
1403         }
1404
1405         private void emitBaseIdentities(final Set<IdentitySchemaNode> identities) {
1406             for (final IdentitySchemaNode identitySchemaNode : identities) {
1407                 emitBase(identitySchemaNode.getQName());
1408             }
1409         }
1410
1411         private void emitBase(final QName qName) {
1412             super.writer.startBaseNode(qName);
1413             super.writer.endNode();
1414         }
1415
1416         private void emitFeature(final FeatureDefinition definition) {
1417             super.writer.startFeatureNode(definition.getQName());
1418
1419             // FIXME: BUG-2444: FIXME: BUG-2444: Expose ifFeature
1420             // *(ifFeatureNode )
1421             emitStatusNode(definition.getStatus());
1422             emitDescriptionNode(definition.getDescription());
1423             emitReferenceNode(definition.getReference());
1424             super.writer.endNode();
1425
1426         }
1427
1428         @SuppressWarnings("unused")
1429         private void emitIfFeature(final String input) {
1430             /*
1431              * FIXME: BUG-2444: Implement proper export of include statements
1432              * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
1433              *
1434              */
1435         }
1436
1437         private void emitTypedefNode(final TypeDefinition<?> typedef) {
1438             super.writer.startTypedefNode(typedef.getQName());
1439             // Differentiate between derived type and existing type
1440             // name.
1441             emitTypeNodeDerived(typedef);
1442             emitUnitsNode(typedef.getUnits());
1443             emitDefaultNode(typedef.getDefaultValue());
1444             emitStatusNode(typedef.getStatus());
1445             emitDescriptionNode(typedef.getDescription());
1446             emitReferenceNode(typedef.getReference());
1447             emitUnknownStatementNodes(typedef.getUnknownSchemaNodes());
1448             super.writer.endNode();
1449
1450         }
1451
1452         private void emitTypeNode(final SchemaPath parentPath, final TypeDefinition<?> subtype) {
1453             final SchemaPath path = subtype.getPath();
1454             if (isPrefix(parentPath.getPathFromRoot(), path.getPathFromRoot())) {
1455                 emitTypeNodeDerived(subtype);
1456             } else {
1457                 emitTypeNodeReferenced(subtype);
1458             }
1459         }
1460
1461         private void emitTypeNodeReferenced(final TypeDefinition<?> typeDefinition) {
1462             super.writer.startTypeNode(typeDefinition.getQName());
1463             super.writer.endNode();
1464
1465         }
1466
1467         private void emitTypeNodeDerived(final TypeDefinition<?> typeDefinition) {
1468             final TypeDefinition<?> b = typeDefinition.getBaseType();
1469             final TypeDefinition<?> baseType = b == null ? typeDefinition : b;
1470             super.writer.startTypeNode(baseType.getQName());
1471             emitTypeBodyNodes(typeDefinition);
1472             super.writer.endNode();
1473
1474         }
1475
1476         private void emitTypeBodyNodes(final TypeDefinition<?> typeDef) {
1477             if (typeDef instanceof UnsignedIntegerTypeDefinition) {
1478                 emitUnsignedIntegerSpecification((UnsignedIntegerTypeDefinition) typeDef);
1479             } else if (typeDef instanceof IntegerTypeDefinition) {
1480                 emitIntegerSpefication((IntegerTypeDefinition) typeDef);
1481             } else if (typeDef instanceof DecimalTypeDefinition) {
1482                 emitDecimal64Specification((DecimalTypeDefinition) typeDef);
1483             } else if (typeDef instanceof StringTypeDefinition) {
1484                 emitStringRestrictions((StringTypeDefinition) typeDef);
1485             } else if (typeDef instanceof EnumTypeDefinition) {
1486                 emitEnumSpecification((EnumTypeDefinition) typeDef);
1487             } else if (typeDef instanceof LeafrefTypeDefinition) {
1488                 emitLeafrefSpecification((LeafrefTypeDefinition) typeDef);
1489             } else if (typeDef instanceof IdentityrefTypeDefinition) {
1490                 emitIdentityrefSpecification((IdentityrefTypeDefinition) typeDef);
1491             } else if (typeDef instanceof InstanceIdentifierTypeDefinition) {
1492                 emitInstanceIdentifierSpecification((InstanceIdentifierTypeDefinition) typeDef);
1493             } else if (typeDef instanceof BitsTypeDefinition) {
1494                 emitBitsSpecification((BitsTypeDefinition) typeDef);
1495             } else if (typeDef instanceof UnionTypeDefinition) {
1496                 emitUnionSpecification((UnionTypeDefinition) typeDef);
1497             } else if (typeDef instanceof BinaryTypeDefinition) {
1498                 emitLength(((BinaryTypeDefinition) typeDef).getLengthConstraints());
1499             } else if (typeDef instanceof BooleanTypeDefinition || typeDef instanceof EmptyTypeDefinition) {
1500                 // NOOP
1501             } else {
1502                 throw new IllegalArgumentException("Not supported type " + typeDef.getClass());
1503             }
1504         }
1505
1506         private void emitIntegerSpefication(final IntegerTypeDefinition typeDef) {
1507             emitRangeNodeOptional(typeDef.getRangeConstraints());
1508         }
1509
1510         private void emitUnsignedIntegerSpecification(final UnsignedIntegerTypeDefinition typeDef) {
1511             emitRangeNodeOptional(typeDef.getRangeConstraints());
1512
1513         }
1514
1515         private void emitRangeNodeOptional(final List<RangeConstraint> list) {
1516             // FIXME: BUG-2444: Wrong decomposition in API, should be
1517             // LenghtConstraint
1518             // which contains ranges.
1519             if (!list.isEmpty()) {
1520                 super.writer.startRangeNode(toRangeString(list));
1521                 final RangeConstraint first = list.iterator().next();
1522                 emitErrorMessageNode(first.getErrorMessage());
1523                 emitErrorAppTagNode(first.getErrorAppTag());
1524                 emitDescriptionNode(first.getDescription());
1525                 emitReferenceNode(first.getReference());
1526                 super.writer.endNode();
1527             }
1528
1529         }
1530
1531         private void emitDecimal64Specification(final DecimalTypeDefinition typeDefinition) {
1532             emitFranctionDigitsNode(typeDefinition.getFractionDigits());
1533             emitRangeNodeOptional(typeDefinition.getRangeConstraints());
1534
1535         }
1536
1537         private void emitFranctionDigitsNode(final Integer fractionDigits) {
1538             super.writer.startFractionDigitsNode(fractionDigits);
1539             super.writer.endNode();
1540         }
1541
1542         private void emitStringRestrictions(final StringTypeDefinition typeDef) {
1543
1544             // FIXME: BUG-2444: Wrong decomposition in API, should be
1545             // LenghtConstraint
1546             // which contains ranges.
1547             emitLength(typeDef.getLengthConstraints());
1548
1549             for (final PatternConstraint pattern : typeDef.getPatternConstraints()) {
1550                 emitPatternNode(pattern);
1551             }
1552
1553         }
1554
1555         private void emitLength(final List<LengthConstraint> list) {
1556             if (!list.isEmpty()) {
1557                 super.writer.startLengthNode(toLengthString(list));
1558                 // FIXME: BUG-2444: Workaround for incorrect decomposition in
1559                 // API
1560                 final LengthConstraint first = list.iterator().next();
1561                 emitErrorMessageNode(first.getErrorMessage());
1562                 emitErrorAppTagNode(first.getErrorAppTag());
1563                 emitDescriptionNode(first.getDescription());
1564                 emitReferenceNode(first.getReference());
1565                 super.writer.endNode();
1566             }
1567         }
1568
1569         private static String toLengthString(final List<LengthConstraint> list) {
1570             final Iterator<LengthConstraint> it = list.iterator();
1571             if (!it.hasNext()) {
1572                 return "";
1573             }
1574
1575             final StringBuilder sb = new StringBuilder();
1576             boolean haveNext;
1577             do {
1578                 final LengthConstraint current = it.next();
1579                 haveNext = it.hasNext();
1580                 appendRange(sb, current.getMin(), current.getMax(), haveNext);
1581             } while (haveNext);
1582
1583             return sb.toString();
1584         }
1585
1586         private static String toRangeString(final List<RangeConstraint> list) {
1587             final Iterator<RangeConstraint> it = list.iterator();
1588             if (!it.hasNext()) {
1589                 return "";
1590             }
1591
1592             final StringBuilder sb = new StringBuilder();
1593             boolean haveNext;
1594             do {
1595                 final RangeConstraint current = it.next();
1596                 haveNext = it.hasNext();
1597                 appendRange(sb, current.getMin(), current.getMax(), haveNext);
1598             } while (haveNext);
1599
1600             return sb.toString();
1601         }
1602
1603         private static void appendRange(final StringBuilder sb, final Number min, final Number max,
1604                 final boolean haveNext) {
1605             sb.append(min);
1606             if (!min.equals(max)) {
1607                 sb.append("..");
1608                 sb.append(max);
1609             }
1610             if (haveNext) {
1611                 sb.append('|');
1612             }
1613         }
1614
1615         private void emitPatternNode(final PatternConstraint pattern) {
1616             super.writer.startPatternNode(pattern.getRawRegularExpression());
1617             // FIXME: BUG-2444: Optional
1618             emitErrorMessageNode(pattern.getErrorMessage());
1619             // FIXME: BUG-2444: Optional
1620             emitErrorAppTagNode(pattern.getErrorAppTag());
1621             emitDescriptionNode(pattern.getDescription());
1622             emitModifier(pattern.getModifier());
1623             super.writer.endNode();
1624         }
1625
1626         private void emitModifier(final ModifierKind modifier) {
1627             if (modifier != null) {
1628                 super.writer.startModifierNode(modifier);
1629                 super.writer.endNode();
1630             }
1631         }
1632
1633         private void emitDefaultNodes(final Collection<String> defaults) {
1634             for (final String defaultValue : defaults) {
1635                 emitDefaultNode(defaultValue);
1636             }
1637         }
1638
1639         private void emitDefaultNode(@Nullable final Object object) {
1640             if (object != null) {
1641                 super.writer.startDefaultNode(object.toString());
1642                 super.writer.endNode();
1643             }
1644         }
1645
1646         private void emitEnumSpecification(final EnumTypeDefinition typeDefinition) {
1647             for (final EnumPair enumValue : typeDefinition.getValues()) {
1648                 emitEnumNode(enumValue);
1649             }
1650         }
1651
1652         private void emitEnumNode(final EnumPair enumValue) {
1653             super.writer.startEnumNode(enumValue.getName());
1654             emitValueNode(enumValue.getValue());
1655             emitStatusNode(enumValue.getStatus());
1656             emitDescriptionNode(enumValue.getDescription());
1657             emitReferenceNode(enumValue.getReference());
1658             super.writer.endNode();
1659         }
1660
1661         private void emitLeafrefSpecification(final LeafrefTypeDefinition typeDefinition) {
1662             emitPathNode(typeDefinition.getPathStatement());
1663             if (YangVersion.VERSION_1_1 == super.yangVersion) {
1664                 emitRequireInstanceNode(typeDefinition.requireInstance());
1665             }
1666         }
1667
1668         private void emitPathNode(final RevisionAwareXPath revisionAwareXPath) {
1669             super.writer.startPathNode(revisionAwareXPath);
1670             super.writer.endNode();
1671         }
1672
1673         private void emitRequireInstanceNode(final boolean require) {
1674             super.writer.startRequireInstanceNode(require);
1675             super.writer.endNode();
1676         }
1677
1678         private void emitInstanceIdentifierSpecification(final InstanceIdentifierTypeDefinition typeDefinition) {
1679             emitRequireInstanceNode(typeDefinition.requireInstance());
1680         }
1681
1682         private void emitIdentityrefSpecification(final IdentityrefTypeDefinition typeDefinition) {
1683             emitBaseIdentities(typeDefinition.getIdentities());
1684         }
1685
1686         private void emitUnionSpecification(final UnionTypeDefinition typeDefinition) {
1687             for (final TypeDefinition<?> subtype : typeDefinition.getTypes()) {
1688                 // FIXME: BUG-2444: What if we have locally modified types here?
1689                 // is solution to look-up in schema path?
1690                 emitTypeNode(typeDefinition.getPath(), subtype);
1691             }
1692         }
1693
1694         private void emitBitsSpecification(final BitsTypeDefinition typeDefinition) {
1695             for (final Bit bit : typeDefinition.getBits()) {
1696                 emitBit(bit);
1697             }
1698         }
1699
1700         private void emitBit(final Bit bit) {
1701             super.writer.startBitNode(bit.getName());
1702             emitPositionNode(bit.getPosition());
1703             emitStatusNode(bit.getStatus());
1704             emitDescriptionNode(bit.getDescription());
1705             emitReferenceNode(bit.getReference());
1706             super.writer.endNode();
1707         }
1708
1709         private void emitPositionNode(@Nullable final Long position) {
1710             if (position != null) {
1711                 super.writer.startPositionNode(UnsignedInteger.valueOf(position));
1712                 super.writer.endNode();
1713             }
1714         }
1715
1716         private void emitStatusNode(@Nullable final Status status) {
1717             if (status != null) {
1718                 super.writer.startStatusNode(status);
1719                 super.writer.endNode();
1720             }
1721         }
1722
1723         private void emitConfigNode(final boolean config) {
1724             super.writer.startConfigNode(config);
1725             super.writer.endNode();
1726         }
1727
1728         private void emitMandatoryNode(final boolean mandatory) {
1729             super.writer.startMandatoryNode(mandatory);
1730             super.writer.endNode();
1731         }
1732
1733         private void emitPresenceNode(final boolean presence) {
1734             super.writer.startPresenceNode(presence);
1735             super.writer.endNode();
1736         }
1737
1738         private void emitOrderedBy(final boolean userOrdered) {
1739             if (userOrdered) {
1740                 super.writer.startOrderedByNode("user");
1741             } else {
1742                 super.writer.startOrderedByNode("system");
1743             }
1744             super.writer.endNode();
1745         }
1746
1747         private void emitMust(@Nullable final MustDefinition mustCondition) {
1748             if (mustCondition != null && mustCondition.getXpath() != null) {
1749                 super.writer.startMustNode(mustCondition.getXpath());
1750                 emitErrorMessageNode(mustCondition.getErrorMessage());
1751                 emitErrorAppTagNode(mustCondition.getErrorAppTag());
1752                 emitDescriptionNode(mustCondition.getDescription());
1753                 emitReferenceNode(mustCondition.getReference());
1754                 super.writer.endNode();
1755             }
1756
1757         }
1758
1759         private void emitErrorMessageNode(@Nullable final String input) {
1760             if (input != null && !input.isEmpty()) {
1761                 super.writer.startErrorMessageNode(input);
1762                 super.writer.endNode();
1763             }
1764         }
1765
1766         private void emitErrorAppTagNode(final String input) {
1767             if (input != null && !input.isEmpty()) {
1768                 super.writer.startErrorAppTagNode(input);
1769                 super.writer.endNode();
1770             }
1771         }
1772
1773         private void emitMinElementsNode(final Integer min) {
1774             if (min != null) {
1775                 super.writer.startMinElementsNode(min);
1776                 super.writer.endNode();
1777             }
1778         }
1779
1780         private void emitMaxElementsNode(final Integer max) {
1781             if (max != null) {
1782                 super.writer.startMaxElementsNode(max);
1783                 super.writer.endNode();
1784             }
1785         }
1786
1787         private void emitValueNode(@Nullable final Integer value) {
1788             if (value != null) {
1789                 super.writer.startValueNode(value);
1790                 super.writer.endNode();
1791             }
1792         }
1793
1794         private void emitDocumentedNode(final DocumentedNode.WithStatus input) {
1795             emitStatusNode(input.getStatus());
1796             emitDescriptionNode(input.getDescription());
1797             emitReferenceNode(input.getReference());
1798         }
1799
1800         private void emitGrouping(final GroupingDefinition grouping) {
1801             super.writer.startGroupingNode(grouping.getQName());
1802             emitDocumentedNode(grouping);
1803             emitDataNodeContainer(grouping);
1804             emitUnknownStatementNodes(grouping.getUnknownSchemaNodes());
1805             emitNotifications(grouping.getNotifications());
1806             emitActions(grouping.getActions());
1807             super.writer.endNode();
1808
1809         }
1810
1811         private void emitContainer(final ContainerSchemaNode child) {
1812             super.writer.startContainerNode(child.getQName());
1813
1814             //
1815
1816             emitConstraints(child.getConstraints());
1817             // FIXME: BUG-2444: whenNode //:Optional
1818             // FIXME: BUG-2444: *(ifFeatureNode )
1819             emitPresenceNode(child.isPresenceContainer());
1820             emitConfigNode(child.isConfiguration());
1821             emitDocumentedNode(child);
1822             emitDataNodeContainer(child);
1823             emitUnknownStatementNodes(child.getUnknownSchemaNodes());
1824             emitNotifications(child.getNotifications());
1825             emitActions(child.getActions());
1826             super.writer.endNode();
1827
1828         }
1829
1830         private void emitConstraints(final ConstraintDefinition constraints) {
1831             emitWhen(constraints.getWhenCondition());
1832             for (final MustDefinition mustCondition : constraints.getMustConstraints()) {
1833                 emitMust(mustCondition);
1834             }
1835         }
1836
1837         private void emitLeaf(final LeafSchemaNode child) {
1838             super.writer.startLeafNode(child.getQName());
1839             emitWhen(child.getConstraints().getWhenCondition());
1840             // FIXME: BUG-2444: *(ifFeatureNode )
1841             emitTypeNode(child.getPath(), child.getType());
1842             emitUnitsNode(child.getUnits());
1843             emitMustNodes(child.getConstraints().getMustConstraints());
1844             emitDefaultNode(child.getDefault());
1845             emitConfigNode(child.isConfiguration());
1846             emitMandatoryNode(child.getConstraints().isMandatory());
1847             emitDocumentedNode(child);
1848             emitUnknownStatementNodes(child.getUnknownSchemaNodes());
1849             super.writer.endNode();
1850
1851         }
1852
1853         private void emitLeafList(final LeafListSchemaNode child) {
1854             super.writer.startLeafListNode(child.getQName());
1855
1856             emitWhen(child.getConstraints().getWhenCondition());
1857             // FIXME: BUG-2444: *(ifFeatureNode )
1858             emitTypeNode(child.getPath(), child.getType());
1859             emitUnitsNode(child.getType().getUnits());
1860             // FIXME: BUG-2444: unitsNode /Optional
1861             emitMustNodes(child.getConstraints().getMustConstraints());
1862             emitConfigNode(child.isConfiguration());
1863             emitDefaultNodes(child.getDefaults());
1864             emitMinElementsNode(child.getConstraints().getMinElements());
1865             emitMaxElementsNode(child.getConstraints().getMaxElements());
1866             emitOrderedBy(child.isUserOrdered());
1867             emitDocumentedNode(child);
1868             emitUnknownStatementNodes(child.getUnknownSchemaNodes());
1869             super.writer.endNode();
1870
1871         }
1872
1873         private void emitList(final ListSchemaNode child) {
1874             super.writer.startListNode(child.getQName());
1875             emitWhen(child.getConstraints().getWhenCondition());
1876
1877             // FIXME: BUG-2444: *(ifFeatureNode )
1878             emitMustNodes(child.getConstraints().getMustConstraints());
1879             emitKey(child.getKeyDefinition());
1880             emitUniqueConstraints(child.getUniqueConstraints());
1881             emitConfigNode(child.isConfiguration());
1882             emitMinElementsNode(child.getConstraints().getMinElements());
1883             emitMaxElementsNode(child.getConstraints().getMaxElements());
1884             emitOrderedBy(child.isUserOrdered());
1885             emitDocumentedNode(child);
1886             emitDataNodeContainer(child);
1887             emitUnknownStatementNodes(child.getUnknownSchemaNodes());
1888             emitNotifications(child.getNotifications());
1889             emitActions(child.getActions());
1890             super.writer.endNode();
1891
1892         }
1893
1894         private void emitMustNodes(final Set<MustDefinition> mustConstraints) {
1895             for (final MustDefinition must : mustConstraints) {
1896                 emitMust(must);
1897             }
1898         }
1899
1900         private void emitKey(final List<QName> keyList) {
1901             if (keyList != null && !keyList.isEmpty()) {
1902                 super.writer.startKeyNode(keyList);
1903                 super.writer.endNode();
1904             }
1905         }
1906
1907         private void emitUniqueConstraints(final Collection<UniqueConstraint> uniqueConstraints) {
1908             for (final UniqueConstraint uniqueConstraint : uniqueConstraints) {
1909                 emitUnique(uniqueConstraint);
1910             }
1911         }
1912
1913         private void emitUnique(final UniqueConstraint uniqueConstraint) {
1914             super.writer.startUniqueNode(uniqueConstraint);
1915             super.writer.endNode();
1916         }
1917
1918         private void emitChoice(final ChoiceSchemaNode choice) {
1919             super.writer.startChoiceNode(choice.getQName());
1920             emitWhen(choice.getConstraints().getWhenCondition());
1921             // FIXME: BUG-2444: *(ifFeatureNode )
1922             // FIXME: BUG-2444: defaultNode //Optional
1923             emitConfigNode(choice.isConfiguration());
1924             emitMandatoryNode(choice.getConstraints().isMandatory());
1925             emitDocumentedNode(choice);
1926             for (final ChoiceCaseNode caze : choice.getCases()) {
1927                 // TODO: emit short case?
1928                 emitCaseNode(caze);
1929             }
1930             emitUnknownStatementNodes(choice.getUnknownSchemaNodes());
1931             super.writer.endNode();
1932         }
1933
1934         private void emitCaseNode(final ChoiceCaseNode caze) {
1935             if (!super.emitInstantiated && caze.isAugmenting()) {
1936                 return;
1937             }
1938             super.writer.startCaseNode(caze.getQName());
1939             emitWhen(caze.getConstraints().getWhenCondition());
1940             // FIXME: BUG-2444: *(ifFeatureNode )
1941             emitDocumentedNode(caze);
1942             emitDataNodeContainer(caze);
1943             emitUnknownStatementNodes(caze.getUnknownSchemaNodes());
1944             super.writer.endNode();
1945
1946         }
1947
1948         private void emitAnyxml(final AnyXmlSchemaNode anyxml) {
1949             super.writer.startAnyxmlNode(anyxml.getQName());
1950             emitBodyOfDataSchemaNode(anyxml);
1951             super.writer.endNode();
1952         }
1953
1954         private void emitAnydata(final AnyDataSchemaNode anydata) {
1955             super.writer.startAnydataNode(anydata.getQName());
1956             emitBodyOfDataSchemaNode(anydata);
1957             super.writer.endNode();
1958         }
1959
1960         private void emitBodyOfDataSchemaNode(final DataSchemaNode dataSchemaNode) {
1961             emitWhen(dataSchemaNode.getConstraints().getWhenCondition());
1962             // FIXME: BUG-2444: *(ifFeatureNode )
1963             emitMustNodes(dataSchemaNode.getConstraints().getMustConstraints());
1964             emitConfigNode(dataSchemaNode.isConfiguration());
1965             emitMandatoryNode(dataSchemaNode.getConstraints().isMandatory());
1966             emitDocumentedNode(dataSchemaNode);
1967             emitUnknownStatementNodes(dataSchemaNode.getUnknownSchemaNodes());
1968         }
1969
1970         private void emitUsesNode(final UsesNode usesNode) {
1971             if (super.emitUses && !usesNode.isAddedByUses() && !usesNode.isAugmenting()) {
1972                 super.writer.startUsesNode(usesNode.getGroupingPath().getLastComponent());
1973                 /*
1974                  * FIXME: BUG-2444: whenNode / *(ifFeatureNode ) statusNode //
1975                  * Optional F : descriptionNode // Optional referenceNode //
1976                  * Optional
1977                  */
1978                 for (final Entry<SchemaPath, SchemaNode> refine : usesNode.getRefines().entrySet()) {
1979                     emitRefine(refine);
1980                 }
1981                 for (final AugmentationSchema aug : usesNode.getAugmentations()) {
1982                     emitUsesAugmentNode(aug);
1983                 }
1984                 super.writer.endNode();
1985             }
1986         }
1987
1988         private void emitRefine(final Entry<SchemaPath, SchemaNode> refine) {
1989             final SchemaPath path = refine.getKey();
1990             final SchemaNode value = refine.getValue();
1991             super.writer.startRefineNode(path);
1992
1993             if (value instanceof LeafSchemaNode) {
1994                 emitRefineLeafNodes((LeafSchemaNode) value);
1995             } else if (value instanceof LeafListSchemaNode) {
1996                 emitRefineLeafListNodes((LeafListSchemaNode) value);
1997             } else if (value instanceof ListSchemaNode) {
1998                 emitRefineListNodes((ListSchemaNode) value);
1999             } else if (value instanceof ChoiceSchemaNode) {
2000                 emitRefineChoiceNodes((ChoiceSchemaNode) value);
2001             } else if (value instanceof ChoiceCaseNode) {
2002                 emitRefineCaseNodes((ChoiceCaseNode) value);
2003             } else if (value instanceof ContainerSchemaNode) {
2004                 emitRefineContainerNodes((ContainerSchemaNode) value);
2005             } else if (value instanceof AnyXmlSchemaNode) {
2006                 emitRefineAnyxmlNodes((AnyXmlSchemaNode) value);
2007             }
2008             super.writer.endNode();
2009
2010         }
2011
2012         private static <T extends SchemaNode> T getOriginalChecked(final T value) {
2013             final Optional<SchemaNode> original = SchemaNodeUtils.getOriginalIfPossible(value);
2014             Preconditions.checkArgument(original.isPresent(), "Original unmodified version of node is not present.");
2015             @SuppressWarnings("unchecked")
2016             final T ret = (T) original.get();
2017             return ret;
2018         }
2019
2020         private void emitDocumentedNodeRefine(final DocumentedNode original, final DocumentedNode value) {
2021             if (Objects.deepEquals(original.getDescription(), value.getDescription())) {
2022                 emitDescriptionNode(value.getDescription());
2023             }
2024             if (Objects.deepEquals(original.getReference(), value.getReference())) {
2025                 emitReferenceNode(value.getReference());
2026             }
2027         }
2028
2029         private void emitRefineContainerNodes(final ContainerSchemaNode value) {
2030             final ContainerSchemaNode original = getOriginalChecked(value);
2031
2032             // emitMustNodes(child.getConstraints().getMustConstraints());
2033             if (Objects.deepEquals(original.isPresenceContainer(), value.isPresenceContainer())) {
2034                 emitPresenceNode(value.isPresenceContainer());
2035             }
2036             if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
2037                 emitConfigNode(value.isConfiguration());
2038             }
2039             emitDocumentedNodeRefine(original, value);
2040
2041         }
2042
2043         private void emitRefineLeafNodes(final LeafSchemaNode value) {
2044             final LeafSchemaNode original = getOriginalChecked(value);
2045
2046             // emitMustNodes(child.getConstraints().getMustConstraints());
2047             if (Objects.deepEquals(original.getDefault(), value.getDefault())) {
2048                 emitDefaultNode(value.getDefault());
2049             }
2050             if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
2051                 emitConfigNode(value.isConfiguration());
2052             }
2053             emitDocumentedNodeRefine(original, value);
2054             if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
2055                 emitMandatoryNode(value.getConstraints().isMandatory());
2056             }
2057
2058         }
2059
2060         private void emitRefineLeafListNodes(final LeafListSchemaNode value) {
2061             final LeafListSchemaNode original = getOriginalChecked(value);
2062
2063             // emitMustNodes(child.getConstraints().getMustConstraints());
2064             if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
2065                 emitConfigNode(value.isConfiguration());
2066             }
2067             if (Objects.deepEquals(original.getConstraints().getMinElements(),
2068                     value.getConstraints().getMinElements())) {
2069                 emitMinElementsNode(value.getConstraints().getMinElements());
2070             }
2071             if (Objects.deepEquals(original.getConstraints().getMaxElements(),
2072                     value.getConstraints().getMaxElements())) {
2073                 emitMaxElementsNode(value.getConstraints().getMaxElements());
2074             }
2075             emitDocumentedNodeRefine(original, value);
2076
2077         }
2078
2079         private void emitRefineListNodes(final ListSchemaNode value) {
2080             final ListSchemaNode original = getOriginalChecked(value);
2081
2082             // emitMustNodes(child.getConstraints().getMustConstraints());
2083             if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
2084                 emitConfigNode(value.isConfiguration());
2085             }
2086             if (Objects.deepEquals(original.getConstraints().getMinElements(),
2087                     value.getConstraints().getMinElements())) {
2088                 emitMinElementsNode(value.getConstraints().getMinElements());
2089             }
2090             if (Objects.deepEquals(original.getConstraints().getMaxElements(),
2091                     value.getConstraints().getMaxElements())) {
2092                 emitMaxElementsNode(value.getConstraints().getMaxElements());
2093             }
2094             emitDocumentedNodeRefine(original, value);
2095
2096         }
2097
2098         private void emitRefineChoiceNodes(final ChoiceSchemaNode value) {
2099             final ChoiceSchemaNode original = getOriginalChecked(value);
2100
2101             // FIXME: BUG-2444: defaultNode //FIXME: BUG-2444: Optional
2102             if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
2103                 emitConfigNode(value.isConfiguration());
2104             }
2105             if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
2106                 emitMandatoryNode(value.getConstraints().isMandatory());
2107             }
2108             emitDocumentedNodeRefine(original, value);
2109
2110         }
2111
2112         private void emitRefineCaseNodes(final ChoiceCaseNode value) {
2113             final ChoiceCaseNode original = getOriginalChecked(value);
2114             emitDocumentedNodeRefine(original, value);
2115
2116         }
2117
2118         private void emitRefineAnyxmlNodes(final AnyXmlSchemaNode value) {
2119             final AnyXmlSchemaNode original = getOriginalChecked(value);
2120
2121             // FIXME: BUG-2444:
2122             // emitMustNodes(child.getConstraints().getMustConstraints());
2123             if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
2124                 emitConfigNode(value.isConfiguration());
2125             }
2126             if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
2127                 emitMandatoryNode(value.getConstraints().isMandatory());
2128             }
2129             emitDocumentedNodeRefine(original, value);
2130
2131         }
2132
2133         private void emitUsesAugmentNode(final AugmentationSchema aug) {
2134             /**
2135              * differs only in location in schema, otherwise currently (as of
2136              * RFC6020) it is same, so we could freely reuse path.
2137              */
2138             emitAugment(aug);
2139         }
2140
2141         private void emitAugment(final AugmentationSchema augmentation) {
2142             super.writer.startAugmentNode(augmentation.getTargetPath());
2143             // FIXME: BUG-2444: whenNode //Optional
2144             // FIXME: BUG-2444: *(ifFeatureNode )
2145
2146             emitStatusNode(augmentation.getStatus());
2147             emitDescriptionNode(augmentation.getDescription());
2148             emitReferenceNode(augmentation.getReference());
2149             for (final UsesNode uses : augmentation.getUses()) {
2150                 emitUsesNode(uses);
2151             }
2152
2153             for (final DataSchemaNode childNode : augmentation.getChildNodes()) {
2154                 if (childNode instanceof ChoiceCaseNode) {
2155                     emitCaseNode((ChoiceCaseNode) childNode);
2156                 } else {
2157                     emitDataSchemaNode(childNode);
2158                 }
2159             }
2160             emitUnknownStatementNodes(augmentation.getUnknownSchemaNodes());
2161             emitNotifications(augmentation.getNotifications());
2162             emitActions(augmentation.getActions());
2163             super.writer.endNode();
2164         }
2165
2166         private void emitUnknownStatementNodes(final List<UnknownSchemaNode> unknownNodes) {
2167             for (final UnknownSchemaNode unknonwnNode : unknownNodes) {
2168                 if (!unknonwnNode.isAddedByAugmentation() && !unknonwnNode.isAddedByUses()) {
2169                     emitUnknownStatementNode(unknonwnNode);
2170                 }
2171             }
2172         }
2173
2174         private void emitUnknownStatementNode(final UnknownSchemaNode node) {
2175             final StatementDefinition def = getStatementChecked(node.getNodeType());
2176             if (def.getArgumentName() == null) {
2177                 super.writer.startUnknownNode(def);
2178             } else {
2179                 super.writer.startUnknownNode(def, node.getNodeParameter());
2180             }
2181             emitUnknownStatementNodes(node.getUnknownSchemaNodes());
2182             super.writer.endNode();
2183         }
2184
2185         private StatementDefinition getStatementChecked(final QName nodeType) {
2186             final StatementDefinition ret = super.extensions.get(nodeType);
2187             Preconditions.checkArgument(ret != null, "Unknown extension %s used during export.", nodeType);
2188             return ret;
2189         }
2190
2191         private void emitWhen(final RevisionAwareXPath revisionAwareXPath) {
2192             if (revisionAwareXPath != null) {
2193                 super.writer.startWhenNode(revisionAwareXPath);
2194                 super.writer.endNode();
2195             }
2196             // FIXME: BUG-2444: descriptionNode //FIXME: BUG-2444: Optional
2197             // FIXME: BUG-2444: referenceNode //FIXME: BUG-2444: Optional
2198             // FIXME: BUG-2444: super.writer.endNode();)
2199
2200         }
2201
2202         private void emitRpc(final RpcDefinition rpc) {
2203             super.writer.startRpcNode(rpc.getQName());
2204             emitOperationBody(rpc);
2205             super.writer.endNode();
2206         }
2207
2208         private void emitOperationBody(final OperationDefinition rpc) {
2209             // FIXME: BUG-2444: *(ifFeatureNode )
2210             emitStatusNode(rpc.getStatus());
2211             emitDescriptionNode(rpc.getDescription());
2212             emitReferenceNode(rpc.getReference());
2213
2214             for (final TypeDefinition<?> typedef : rpc.getTypeDefinitions()) {
2215                 emitTypedefNode(typedef);
2216             }
2217             for (final GroupingDefinition grouping : rpc.getGroupings()) {
2218                 emitGrouping(grouping);
2219             }
2220             emitInput(rpc.getInput());
2221             emitOutput(rpc.getOutput());
2222             emitUnknownStatementNodes(rpc.getUnknownSchemaNodes());
2223         }
2224
2225         private void emitActions(final Set<ActionDefinition> actions) {
2226             for (final ActionDefinition actionDefinition : actions) {
2227                 emitAction(actionDefinition);
2228             }
2229         }
2230
2231         private void emitAction(final ActionDefinition action) {
2232             // :FIXME add addedByUses & addedByAugmentation in API and perform
2233             // check here..
2234             super.writer.startActionNode(action.getQName());
2235             emitOperationBody(action);
2236             super.writer.endNode();
2237         }
2238
2239         private void emitInput(@Nonnull final ContainerSchemaNode input) {
2240             if (isExplicitStatement(input)) {
2241                 super.writer.startInputNode();
2242                 emitConstraints(input.getConstraints());
2243                 emitDataNodeContainer(input);
2244                 emitUnknownStatementNodes(input.getUnknownSchemaNodes());
2245                 super.writer.endNode();
2246             }
2247
2248         }
2249
2250         private void emitOutput(@Nonnull final ContainerSchemaNode output) {
2251             if (isExplicitStatement(output)) {
2252                 super.writer.startOutputNode();
2253                 emitConstraints(output.getConstraints());
2254                 emitDataNodeContainer(output);
2255                 emitUnknownStatementNodes(output.getUnknownSchemaNodes());
2256                 super.writer.endNode();
2257             }
2258         }
2259
2260         private static boolean isExplicitStatement(final ContainerSchemaNode node) {
2261             return node instanceof EffectiveStatement && ((EffectiveStatement<?, ?>) node).getDeclared()
2262                     .getStatementSource() == StatementSource.DECLARATION;
2263         }
2264
2265         private void emitNotifications(final Set<NotificationDefinition> notifications) {
2266             for (final NotificationDefinition notification : notifications) {
2267                 emitNotificationNode(notification);
2268             }
2269         }
2270
2271         private void emitNotificationNode(final NotificationDefinition notification) {
2272             // :FIXME add addedByUses & addedByAugmentation in API and perform
2273             // check here..
2274
2275             super.writer.startNotificationNode(notification.getQName());
2276             // FIXME: BUG-2444: *(ifFeatureNode )
2277             emitConstraints(notification.getConstraints());
2278             emitDocumentedNode(notification);
2279             emitDataNodeContainer(notification);
2280             emitUnknownStatementNodes(notification.getUnknownSchemaNodes());
2281             super.writer.endNode();
2282
2283         }
2284
2285         private void emitDeviation(final Deviation deviation) {
2286             /*
2287              * FIXME: BUG-2444: Deviation is not modeled properly and we are
2288              * loosing lot of information in order to export it properly
2289              *
2290              * super.writer.startDeviationNode(deviation.getTargetPath());
2291              *
2292              * :descriptionNode //:Optional
2293              *
2294              *
2295              * emitReferenceNode(deviation.getReference());
2296              * :(deviateNotSupportedNode :1*(deviateAddNode :deviateReplaceNode
2297              * :deviateDeleteNode)) :super.writer.endNode();
2298              */
2299         }
2300     }
2301 }