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