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