2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.model.export;
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.base.Strings;
14 import com.google.common.primitives.UnsignedInteger;
16 import java.util.Date;
17 import java.util.Iterator;
18 import java.util.List;
20 import java.util.Map.Entry;
21 import java.util.Objects;
23 import javax.annotation.Nonnull;
24 import javax.annotation.Nullable;
25 import javax.annotation.concurrent.NotThreadSafe;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
29 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
30 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
32 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
34 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.Deviation;
36 import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
37 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
38 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
39 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
40 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.Module;
45 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
46 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
47 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
48 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
49 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
50 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
51 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
52 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
53 import org.opendaylight.yangtools.yang.model.api.Status;
54 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
55 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
56 import org.opendaylight.yangtools.yang.model.api.UsesNode;
57 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
58 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
59 import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
60 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
61 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
62 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
63 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
64 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
65 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
66 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
67 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
68 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
69 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
70 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
71 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
72 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
73 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
74 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
75 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
76 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
77 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
78 import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
82 class SchemaContextEmitter {
84 private final Rfc6020ModuleWriter writer;
85 private final boolean emitInstantiated;
86 private final boolean emitUses;
87 private final Map<QName, StatementDefinition> extensions;
89 SchemaContextEmitter(final Rfc6020ModuleWriter writer, final Map<QName, StatementDefinition> extensions) {
90 this(writer, extensions,false, true);
93 SchemaContextEmitter(final Rfc6020ModuleWriter writer, final Map<QName, StatementDefinition> extensions, final boolean emitInstantiated, final boolean emitUses) {
94 this.writer = Preconditions.checkNotNull(writer);
95 this.emitInstantiated = emitInstantiated;
96 this.emitUses = emitUses;
97 this.extensions = Preconditions.checkNotNull(extensions);
100 static void writeToStatementWriter(final Module module, final SchemaContext ctx, final StatementTextWriter statementWriter) {
101 final Rfc6020ModuleWriter yangSchemaWriter = SchemaToStatementWriterAdaptor.from(statementWriter);
102 final Map<QName, StatementDefinition> extensions = ExtensionStatement.mapFrom(ctx.getExtensions());
103 new SchemaContextEmitter(yangSchemaWriter,extensions).emitModule(module);
106 void emitModule(final Module input) {
107 writer.startModuleNode(input.getName());
108 emitModuleHeader(input);
109 emitLinkageNodes(input);
110 emitMetaNodes(input);
111 emitRevisionNodes(input);
112 emitBodyNodes(input);
116 private void emitModuleHeader(final Module input) {
117 emitYangVersionNode(input.getYangVersion());
118 emitNamespace(input.getNamespace());
119 emitPrefixNode(input.getPrefix());
122 @SuppressWarnings("unused")
123 private void emitSubmodule(final String input) {
125 * FIXME: BUG-2444: Implement submodule export
127 * submoduleHeaderNodes linkageNodes metaNodes revisionNodes bodyNodes
132 @SuppressWarnings("unused")
133 private void emitSubmoduleHeaderNodes(final Module input) {
135 * FIXME: BUG-2444: Implement submodule headers properly
137 * :yangVersionNode //Optional
143 private void emitMetaNodes(final Module input) {
145 emitOrganizationNode(input.getOrganization()); // FIXME: BUG-2444: Optional
146 emitContact(input.getContact()); // FIXME: BUG-2444: Optional
147 emitDescriptionNode(input.getDescription());
148 emitReferenceNode(input.getReference());
151 private void emitLinkageNodes(final Module input) {
152 for (final ModuleImport importNode : input.getImports()) {
153 emitImport(importNode);
156 * FIXME: BUG-2444: Emit include statements
160 private void emitRevisionNodes(final Module input) {
162 * FIXME: BUG-2444: emit revisions properly, when parsed model will provide enough
165 emitRevision(input.getRevision());
169 private void emitBodyNodes(final Module input) {
171 for (final ExtensionDefinition extension : input.getExtensionSchemaNodes()) {
172 emitExtension(extension);
174 for (final FeatureDefinition definition : input.getFeatures()) {
175 emitFeature(definition);
177 for (final IdentitySchemaNode identity : input.getIdentities()) {
178 emitIdentity(identity);
181 emitDataNodeContainer(input);
183 for (final AugmentationSchema augmentation : input.getAugmentations()) {
184 emitAugment(augmentation);
186 for (final RpcDefinition rpc : input.getRpcs()) {
189 for (final NotificationDefinition notification : input.getNotifications()) {
190 emitNotificationNode(notification);
192 for (final Deviation deviation : input.getDeviations()) {
193 emitDeviation(deviation);
198 private void emitDataNodeContainer(final DataNodeContainer input) {
199 for (final TypeDefinition<?> typedef : input.getTypeDefinitions()) {
200 emitTypedefNode(typedef);
202 for (final GroupingDefinition grouping : input.getGroupings()) {
203 emitGrouping(grouping);
205 for (final DataSchemaNode child : input.getChildNodes()) {
206 emitDataSchemaNode(child);
208 for (final UsesNode usesNode : input.getUses()) {
209 emitUsesNode(usesNode);
213 private void emitDataSchemaNode(final DataSchemaNode child) {
214 if (!emitInstantiated && (child.isAddedByUses() || child.isAugmenting())) {
215 // We skip instantiated nodes.
219 if (child instanceof ContainerSchemaNode) {
220 emitContainer((ContainerSchemaNode) child);
221 } else if (child instanceof LeafSchemaNode) {
222 emitLeaf((LeafSchemaNode) child);
223 } else if (child instanceof LeafListSchemaNode) {
224 emitLeafList((LeafListSchemaNode) child);
225 } else if (child instanceof ListSchemaNode) {
226 emitList((ListSchemaNode) child);
227 } else if (child instanceof ChoiceSchemaNode) {
228 emitChoice((ChoiceSchemaNode) child);
229 } else if (child instanceof AnyXmlSchemaNode) {
230 emitAnyxml((AnyXmlSchemaNode) child);
232 throw new UnsupportedOperationException("Not supported DataSchemaNode type " + child.getClass());
236 private void emitYangVersionNode(final String input) {
237 writer.startYangVersionNode(input);
241 private void emitImport(final ModuleImport importNode) {
242 writer.startImportNode(importNode.getModuleName());
243 emitPrefixNode(importNode.getPrefix());
244 emitRevisionDateNode(importNode.getRevision());
248 @SuppressWarnings("unused")
249 private void emitInclude(final String input) {
251 * FIXME: BUG-2444: Implement proper export of include statements
252 * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
255 * :revisionDateNode :writer.endNode();)
259 private void emitNamespace(final URI uri) {
260 writer.startNamespaceNode(uri);
265 private void emitPrefixNode(final String input) {
266 writer.startPrefixNode(input);
271 @SuppressWarnings("unused")
272 private void emitBelongsTo(final String input) {
274 * FIXME: BUG-2444: Implement proper export of belongs-to statements
275 * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
278 * :writer.startBelongsToNode(IdentifierHelper.getIdentifier(String
289 private void emitOrganizationNode(final String input) {
290 writer.startOrganizationNode(input);
295 private void emitContact(final String input) {
296 writer.startContactNode(input);
301 private void emitDescriptionNode(@Nullable final String input) {
302 if (!Strings.isNullOrEmpty(input)) {
303 writer.startDescriptionNode(input);
308 private void emitReferenceNode(@Nullable final String input) {
309 if (!Strings.isNullOrEmpty(input)) {
310 writer.startReferenceNode(input);
315 private void emitUnitsNode(@Nullable final String input) {
316 if (!Strings.isNullOrEmpty(input)) {
317 writer.startUnitsNode(input);
322 private void emitRevision(final Date date) {
323 writer.startRevisionNode(date);
326 // FIXME: BUG-2444: FIXME: BUG-2444: BUG-2417: descriptionNode //FIXME: BUG-2444: Optional
327 // FIXME: BUG-2444: FIXME: BUG-2444: BUG-2417: referenceNode //FIXME: BUG-2444: Optional
332 private void emitRevisionDateNode(@Nullable final Date date) {
334 writer.startRevisionDateNode(date);
339 private void emitExtension(final ExtensionDefinition extension) {
340 writer.startExtensionNode(extension.getQName());
341 emitArgument(extension.getArgument(),extension.isYinElement());
342 emitStatusNode(extension.getStatus());
343 emitDescriptionNode(extension.getDescription());
344 emitReferenceNode(extension.getReference());
345 emitUnknownStatementNodes(extension.getUnknownSchemaNodes());
350 private void emitArgument(final @Nullable String input, final boolean yinElement) {
352 writer.startArgumentNode(input);
353 emitYinElement(yinElement);
359 private void emitYinElement(final boolean yinElement) {
360 writer.startYinElementNode(yinElement);
365 private void emitIdentity(final IdentitySchemaNode identity) {
366 writer.startIdentityNode(identity.getQName());
367 if (identity.getBaseIdentity() != null) {
368 emitBase(identity.getBaseIdentity().getQName());
370 emitStatusNode(identity.getStatus());
371 emitDescriptionNode(identity.getDescription());
372 emitReferenceNode(identity.getReference());
377 private void emitBase(final QName qName) {
378 writer.startBaseNode(qName);
383 private void emitFeature(final FeatureDefinition definition) {
384 writer.startFeatureNode(definition.getQName());
386 // FIXME: BUG-2444: FIXME: BUG-2444: Expose ifFeature *(ifFeatureNode )
387 emitStatusNode(definition.getStatus());
388 emitDescriptionNode(definition.getDescription());
389 emitReferenceNode(definition.getReference());
394 @SuppressWarnings("unused")
395 private void emitIfFeature(final String input) {
397 * FIXME: BUG-2444: Implement proper export of include statements
398 * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
403 private void emitTypedefNode(final TypeDefinition<?> typedef) {
404 writer.startTypedefNode(typedef.getQName());
405 // Differentiate between derived type and existing type
407 emitTypeNodeDerived(typedef);
408 emitUnitsNode(typedef.getUnits());
409 emitDefaultNode(typedef.getDefaultValue());
410 emitStatusNode(typedef.getStatus());
411 emitDescriptionNode(typedef.getDescription());
412 emitReferenceNode(typedef.getReference());
413 emitUnknownStatementNodes(typedef.getUnknownSchemaNodes());
418 private void emitTypeNode(final SchemaPath parentPath, final TypeDefinition<?> subtype) {
419 final SchemaPath path = subtype.getPath();
420 if (isPrefix(parentPath.getPathFromRoot(), path.getPathFromRoot())) {
421 emitTypeNodeDerived(subtype);
423 emitTypeNodeReferenced(subtype);
427 private void emitTypeNodeReferenced(final TypeDefinition<?> typeDefinition) {
428 writer.startTypeNode(typeDefinition.getQName());
433 private void emitTypeNodeDerived(final TypeDefinition<?> typeDefinition) {
434 final TypeDefinition<?> baseType;
435 if (typeDefinition.getBaseType() != null) {
436 baseType = typeDefinition.getBaseType();
438 baseType = typeDefinition;
440 writer.startTypeNode(baseType.getQName());
441 emitTypeBodyNodes(typeDefinition);
446 private void emitTypeBodyNodes(final TypeDefinition<?> typeDef) {
447 if (typeDef instanceof UnsignedIntegerTypeDefinition) {
448 emitUnsignedIntegerSpecification((UnsignedIntegerTypeDefinition) typeDef);
449 } else if (typeDef instanceof IntegerTypeDefinition) {
450 emitIntegerSpefication((IntegerTypeDefinition) typeDef);
451 } else if (typeDef instanceof DecimalTypeDefinition) {
452 emitDecimal64Specification((DecimalTypeDefinition) typeDef);
453 } else if (typeDef instanceof StringTypeDefinition) {
454 emitStringRestrictions((StringTypeDefinition) typeDef);
455 } else if (typeDef instanceof EnumTypeDefinition) {
456 emitEnumSpecification((EnumTypeDefinition) typeDef);
457 } else if (typeDef instanceof LeafrefTypeDefinition) {
458 emitLeafrefSpecification((LeafrefTypeDefinition) typeDef);
459 } else if (typeDef instanceof IdentityrefTypeDefinition) {
460 emitIdentityrefSpecification((IdentityrefTypeDefinition) typeDef);
461 } else if (typeDef instanceof InstanceIdentifierTypeDefinition) {
462 emitInstanceIdentifierSpecification((InstanceIdentifierTypeDefinition) typeDef);
463 } else if (typeDef instanceof BitsTypeDefinition) {
464 emitBitsSpecification((BitsTypeDefinition) typeDef);
465 } else if (typeDef instanceof UnionTypeDefinition) {
466 emitUnionSpecification((UnionTypeDefinition) typeDef);
467 } else if (typeDef instanceof BinaryTypeDefinition) {
468 // FIXME: BUG-2444: Is this realy NOOP?
469 // should at least support length statement
470 } else if (typeDef instanceof BooleanTypeDefinition || typeDef instanceof EmptyTypeDefinition) {
473 throw new IllegalArgumentException("Not supported type " + typeDef.getClass());
477 private void emitIntegerSpefication(final IntegerTypeDefinition typeDef) {
478 emitRangeNodeOptional(typeDef.getRangeConstraints());
481 private void emitUnsignedIntegerSpecification(final UnsignedIntegerTypeDefinition typeDef) {
482 emitRangeNodeOptional(typeDef.getRangeConstraints());
486 private void emitRangeNodeOptional(final List<RangeConstraint> list) {
487 // FIXME: BUG-2444: Wrong decomposition in API, should be LenghtConstraint
488 // which contains ranges.
489 if (!list.isEmpty()) {
490 writer.startRangeNode(toRangeString(list));
491 final RangeConstraint first = list.iterator().next();
492 emitErrorMessageNode(first.getErrorMessage());
493 emitErrorAppTagNode(first.getErrorAppTag());
494 emitDescriptionNode(first.getDescription());
495 emitReferenceNode(first.getReference());
501 private void emitDecimal64Specification(final DecimalTypeDefinition typeDefinition) {
502 emitFranctionDigitsNode(typeDefinition.getFractionDigits());
503 emitRangeNodeOptional(typeDefinition.getRangeConstraints());
507 private void emitFranctionDigitsNode(final Integer fractionDigits) {
508 writer.startFractionDigitsNode(fractionDigits);
512 private void emitStringRestrictions(final StringTypeDefinition typeDef) {
514 // FIXME: BUG-2444: Wrong decomposition in API, should be LenghtConstraint
515 // which contains ranges.
516 emitLength(typeDef.getLengthConstraints());
518 for (final PatternConstraint pattern : typeDef.getPatternConstraints()) {
519 emitPatternNode(pattern);
524 private void emitLength(final List<LengthConstraint> list) {
525 if (!list.isEmpty()) {
526 writer.startLengthNode(toLengthString(list));
527 // FIXME: BUG-2444: Workaround for incorrect decomposition in API
528 final LengthConstraint first = list.iterator().next();
529 emitErrorMessageNode(first.getErrorMessage());
530 emitErrorAppTagNode(first.getErrorAppTag());
531 emitDescriptionNode(first.getDescription());
532 emitReferenceNode(first.getReference());
537 private static String toLengthString(final List<LengthConstraint> list) {
538 final StringBuilder lengthStr = new StringBuilder();
539 final Iterator<LengthConstraint> constIt = list.iterator();
540 while (constIt.hasNext()) {
541 final LengthConstraint current = constIt.next();
542 if (current.getMin() == current.getMax()) {
543 lengthStr.append(current.getMin());
545 lengthStr.append(current.getMin());
546 lengthStr.append("..");
547 lengthStr.append(current.getMax());
549 if (constIt.hasNext()) {
550 lengthStr.append("|");
553 return lengthStr.toString();
556 private static String toRangeString(final List<RangeConstraint> list) {
557 final StringBuilder lengthStr = new StringBuilder();
558 final Iterator<RangeConstraint> constIt = list.iterator();
559 while (constIt.hasNext()) {
560 final RangeConstraint current = constIt.next();
561 if (current.getMin() == current.getMax()) {
562 lengthStr.append(current.getMin());
564 lengthStr.append(current.getMin());
565 lengthStr.append("..");
566 lengthStr.append(current.getMax());
568 if (constIt.hasNext()) {
569 lengthStr.append("|");
572 return lengthStr.toString();
575 private void emitPatternNode(final PatternConstraint pattern) {
576 writer.startPatternNode(pattern.getRawRegularExpression());
577 emitErrorMessageNode(pattern.getErrorMessage()); // FIXME: BUG-2444: Optional
578 emitErrorAppTagNode(pattern.getErrorAppTag()); // FIXME: BUG-2444: Optional
579 emitDescriptionNode(pattern.getDescription());
580 emitReferenceNode(pattern.getReference()); // FIXME: BUG-2444: Optional
584 private void emitDefaultNode(@Nullable final Object object) {
585 if (object != null) {
586 writer.startDefaultNode(object.toString());
592 private void emitEnumSpecification(final EnumTypeDefinition typeDefinition) {
593 for (final EnumPair enumValue : typeDefinition.getValues()) {
594 emitEnumNode(enumValue);
598 private void emitEnumNode(final EnumPair enumValue) {
599 writer.startEnumNode(enumValue.getName());
600 emitValueNode(enumValue.getValue());
601 emitStatusNode(enumValue.getStatus());
602 emitDescriptionNode(enumValue.getDescription());
603 emitReferenceNode(enumValue.getReference());
607 private void emitLeafrefSpecification(final LeafrefTypeDefinition typeDefinition) {
608 emitPathNode(typeDefinition.getPathStatement());
609 // FIXME: BUG-2444: requireInstanceNode /Optional removed with (RFC6020 - Errata ID
614 private void emitPathNode(final RevisionAwareXPath revisionAwareXPath) {
615 writer.startPathNode(revisionAwareXPath);
619 private void emitRequireInstanceNode(final boolean require) {
620 writer.startRequireInstanceNode(require);
624 private void emitInstanceIdentifierSpecification(final InstanceIdentifierTypeDefinition typeDefinition) {
625 emitRequireInstanceNode(typeDefinition.requireInstance());
628 private void emitIdentityrefSpecification(final IdentityrefTypeDefinition typeDefinition) {
629 emitBase(typeDefinition.getIdentity().getQName());
632 private void emitUnionSpecification(final UnionTypeDefinition typeDefinition) {
633 for (final TypeDefinition<?> subtype : typeDefinition.getTypes()) {
634 // FIXME: BUG-2444: What if we have locally modified types here?
635 // is solution to look-up in schema path?
636 emitTypeNode(typeDefinition.getPath(), subtype);
640 private void emitBitsSpecification(final BitsTypeDefinition typeDefinition) {
641 for (final Bit bit : typeDefinition.getBits()) {
646 private void emitBit(final Bit bit) {
647 writer.startBitNode(bit.getName());
648 emitPositionNode(bit.getPosition());
649 emitStatusNode(bit.getStatus());
650 emitDescriptionNode(bit.getDescription());
651 emitReferenceNode(bit.getReference());
655 private void emitPositionNode(@Nullable final Long position) {
656 if (position != null) {
657 writer.startPositionNode(UnsignedInteger.valueOf(position));
662 private void emitStatusNode(@Nullable final Status status) {
663 if (status != null) {
664 writer.startStatusNode(status);
669 private void emitConfigNode(final boolean config) {
670 writer.startConfigNode(config);
674 private void emitMandatoryNode(final boolean mandatory) {
675 writer.startMandatoryNode(mandatory);
679 private void emitPresenceNode(final boolean presence) {
680 writer.startPresenceNode(presence);
684 private void emitOrderedBy(final boolean userOrdered) {
686 writer.startOrderedByNode("user");
688 writer.startOrderedByNode("system");
693 private void emitMust(@Nullable final MustDefinition mustCondition) {
694 if (mustCondition != null && mustCondition.getXpath() != null) {
695 writer.startMustNode(mustCondition.getXpath());
696 emitErrorMessageNode(mustCondition.getErrorMessage());
697 emitErrorAppTagNode(mustCondition.getErrorAppTag());
698 emitDescriptionNode(mustCondition.getDescription());
699 emitReferenceNode(mustCondition.getReference());
705 private void emitErrorMessageNode(@Nullable final String input) {
706 if (input != null && !input.isEmpty()) {
707 writer.startErrorMessageNode(input);
712 private void emitErrorAppTagNode(final String input) {
713 if (input != null && !input.isEmpty()) {
714 writer.startErrorAppTagNode(input);
719 private void emitMinElementsNode(final Integer min) {
721 writer.startMinElementsNode(min);
726 private void emitMaxElementsNode(final Integer max) {
728 writer.startMaxElementsNode(max);
733 private void emitValueNode(@Nullable final Integer value) {
735 writer.startValueNode(value);
740 private void emitDocumentedNode(final DocumentedNode.WithStatus input) {
741 emitStatusNode(input.getStatus());
742 emitDescriptionNode(input.getDescription());
743 emitReferenceNode(input.getReference());
746 private void emitGrouping(final GroupingDefinition grouping) {
747 writer.startGroupingNode(grouping.getQName());
748 emitDocumentedNode(grouping);
749 emitDataNodeContainer(grouping);
750 emitUnknownStatementNodes(grouping.getUnknownSchemaNodes());
755 private void emitContainer(final ContainerSchemaNode child) {
756 writer.startContainerNode(child.getQName());
760 emitConstraints(child.getConstraints());
761 // FIXME: BUG-2444: whenNode //:Optional
762 // FIXME: BUG-2444: *(ifFeatureNode )
763 emitPresenceNode(child.isPresenceContainer());
764 emitConfigNode(child.isConfiguration());
765 emitDocumentedNode(child);
766 emitDataNodeContainer(child);
767 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
772 private void emitConstraints(final ConstraintDefinition constraints) {
773 emitWhen(constraints.getWhenCondition());
774 for (final MustDefinition mustCondition : constraints.getMustConstraints()) {
775 emitMust(mustCondition);
780 private void emitLeaf(final LeafSchemaNode child) {
781 writer.startLeafNode(child.getQName());
782 emitWhen(child.getConstraints().getWhenCondition());
783 // FIXME: BUG-2444: *(ifFeatureNode )
784 emitTypeNode(child.getPath(), child.getType());
785 emitUnitsNode(child.getUnits());
786 emitMustNodes(child.getConstraints().getMustConstraints());
787 emitDefaultNode(child.getDefault());
788 emitConfigNode(child.isConfiguration());
789 emitMandatoryNode(child.getConstraints().isMandatory());
790 emitDocumentedNode(child);
791 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
796 private void emitLeafList(final LeafListSchemaNode child) {
797 writer.startLeafListNode(child.getQName());
799 emitWhen(child.getConstraints().getWhenCondition());
800 // FIXME: BUG-2444: *(ifFeatureNode )
801 emitTypeNode(child.getPath(), child.getType());
802 // FIXME: BUG-2444: unitsNode /Optional
803 emitMustNodes(child.getConstraints().getMustConstraints());
804 emitConfigNode(child.isConfiguration());
806 emitMinElementsNode(child.getConstraints().getMinElements());
807 emitMaxElementsNode(child.getConstraints().getMaxElements());
808 emitOrderedBy(child.isUserOrdered());
809 emitDocumentedNode(child);
810 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
815 private void emitList(final ListSchemaNode child) {
816 writer.startListNode(child.getQName());
817 emitWhen(child.getConstraints().getWhenCondition());
819 // FIXME: BUG-2444: *(ifFeatureNode )
820 emitMustNodes(child.getConstraints().getMustConstraints());
821 emitKey(child.getKeyDefinition());
822 // FIXME: BUG-2444: *(uniqueNode )
823 emitConfigNode(child.isConfiguration());
824 emitMinElementsNode(child.getConstraints().getMinElements());
825 emitMaxElementsNode(child.getConstraints().getMaxElements());
826 emitOrderedBy(child.isUserOrdered());
827 emitDocumentedNode(child);
828 emitDataNodeContainer(child);
829 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
834 private void emitMustNodes(final Set<MustDefinition> mustConstraints) {
835 for (final MustDefinition must : mustConstraints) {
840 private void emitKey(final List<QName> keyList) {
841 if (keyList != null && !keyList.isEmpty()) {
842 writer.startKeyNode(keyList);
847 @SuppressWarnings("unused")
848 private void emitUnique(final String input) {
849 // FIXME: BUG-2444: writer.startUniqueNode(uniqueArgStr)); Nodeend
853 private void emitChoice(final ChoiceSchemaNode choice) {
854 writer.startChoiceNode(choice.getQName());
855 emitWhen(choice.getConstraints().getWhenCondition());
856 // FIXME: BUG-2444: *(ifFeatureNode )
857 // FIXME: BUG-2444: defaultNode //Optional
858 emitConfigNode(choice.isConfiguration());
859 emitMandatoryNode(choice.getConstraints().isMandatory());
860 emitDocumentedNode(choice);
861 for (final ChoiceCaseNode caze : choice.getCases()) {
862 // TODO: emit short case?
865 emitUnknownStatementNodes(choice.getUnknownSchemaNodes());
869 private void emitCaseNode(final ChoiceCaseNode caze) {
870 if (!emitInstantiated && caze.isAugmenting()) {
873 writer.startCaseNode(caze.getQName());
874 emitWhen(caze.getConstraints().getWhenCondition());
875 // FIXME: BUG-2444: *(ifFeatureNode )
876 emitDocumentedNode(caze);
877 emitDataNodeContainer(caze);
878 emitUnknownStatementNodes(caze.getUnknownSchemaNodes());
883 private void emitAnyxml(final AnyXmlSchemaNode child) {
884 writer.startAnyxmlNode(child.getQName());
886 emitWhen(child.getConstraints().getWhenCondition());
887 // FIXME: BUG-2444: *(ifFeatureNode )
888 emitMustNodes(child.getConstraints().getMustConstraints());
889 emitConfigNode(child.isConfiguration());
890 emitMandatoryNode(child.getConstraints().isMandatory());
891 emitDocumentedNode(child);
892 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
897 private void emitUsesNode(final UsesNode usesNode) {
898 if (emitUses && !usesNode.isAddedByUses() && !usesNode.isAugmenting()) {
899 writer.startUsesNode(usesNode.getGroupingPath().getLastComponent());
904 * statusNode // Optional F
905 * : descriptionNode // Optional
906 * referenceNode // Optional
908 for (final Entry<SchemaPath, SchemaNode> refine : usesNode.getRefines().entrySet()) {
911 for (final AugmentationSchema aug : usesNode.getAugmentations()) {
912 emitUsesAugmentNode(aug);
918 private void emitRefine(final Entry<SchemaPath, SchemaNode> refine) {
919 final SchemaPath path = refine.getKey();
920 final SchemaNode value = refine.getValue();
921 writer.startRefineNode(path);
923 if (value instanceof LeafSchemaNode) {
924 emitRefineLeafNodes((LeafSchemaNode) value);
925 } else if (value instanceof LeafListSchemaNode) {
926 emitRefineLeafListNodes((LeafListSchemaNode) value);
927 } else if (value instanceof ListSchemaNode) {
928 emitRefineListNodes((ListSchemaNode) value);
929 } else if (value instanceof ChoiceSchemaNode) {
930 emitRefineChoiceNodes((ChoiceSchemaNode) value);
931 } else if (value instanceof ChoiceCaseNode) {
932 emitRefineCaseNodes((ChoiceCaseNode) value);
933 } else if (value instanceof ContainerSchemaNode) {
934 emitRefineContainerNodes((ContainerSchemaNode) value);
935 } else if (value instanceof AnyXmlSchemaNode) {
936 emitRefineAnyxmlNodes((AnyXmlSchemaNode) value);
942 private static <T extends SchemaNode> T getOriginalChecked(final T value) {
943 final Optional<SchemaNode> original = SchemaNodeUtils.getOriginalIfPossible(value);
944 Preconditions.checkArgument(original.isPresent(), "Original unmodified version of node is not present.");
945 @SuppressWarnings("unchecked")
946 final T ret = (T) original.get();
950 private void emitDocumentedNodeRefine(final DocumentedNode original, final DocumentedNode value) {
951 if (Objects.deepEquals(original.getDescription(), value.getDescription())) {
952 emitDescriptionNode(value.getDescription());
954 if (Objects.deepEquals(original.getReference(), value.getReference())) {
955 emitReferenceNode(value.getReference());
959 private void emitRefineContainerNodes(final ContainerSchemaNode value) {
960 final ContainerSchemaNode original = getOriginalChecked(value);
962 // emitMustNodes(child.getConstraints().getMustConstraints());
963 if (Objects.deepEquals(original.isPresenceContainer(), value.isPresenceContainer())) {
964 emitPresenceNode(value.isPresenceContainer());
966 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
967 emitConfigNode(value.isConfiguration());
969 emitDocumentedNodeRefine(original, value);
973 private void emitRefineLeafNodes(final LeafSchemaNode value) {
974 final LeafSchemaNode original = getOriginalChecked(value);
976 // emitMustNodes(child.getConstraints().getMustConstraints());
977 if (Objects.deepEquals(original.getDefault(), value.getDefault())) {
978 emitDefaultNode(value.getDefault());
980 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
981 emitConfigNode(value.isConfiguration());
983 emitDocumentedNodeRefine(original, value);
984 if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
985 emitMandatoryNode(value.getConstraints().isMandatory());
990 private void emitRefineLeafListNodes(final LeafListSchemaNode value) {
991 final LeafListSchemaNode original = getOriginalChecked(value);
993 // emitMustNodes(child.getConstraints().getMustConstraints());
994 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
995 emitConfigNode(value.isConfiguration());
997 if (Objects.deepEquals(original.getConstraints().getMinElements(), value.getConstraints().getMinElements())) {
998 emitMinElementsNode(value.getConstraints().getMinElements());
1000 if (Objects.deepEquals(original.getConstraints().getMaxElements(), value.getConstraints().getMaxElements())) {
1001 emitMaxElementsNode(value.getConstraints().getMaxElements());
1003 emitDocumentedNodeRefine(original, value);
1007 private void emitRefineListNodes(final ListSchemaNode value) {
1008 final ListSchemaNode original = getOriginalChecked(value);
1010 // emitMustNodes(child.getConstraints().getMustConstraints());
1011 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
1012 emitConfigNode(value.isConfiguration());
1014 if (Objects.deepEquals(original.getConstraints().getMinElements(), value.getConstraints().getMinElements())) {
1015 emitMinElementsNode(value.getConstraints().getMinElements());
1017 if (Objects.deepEquals(original.getConstraints().getMaxElements(), value.getConstraints().getMaxElements())) {
1018 emitMaxElementsNode(value.getConstraints().getMaxElements());
1020 emitDocumentedNodeRefine(original, value);
1024 private void emitRefineChoiceNodes(final ChoiceSchemaNode value) {
1025 final ChoiceSchemaNode original = getOriginalChecked(value);
1027 // FIXME: BUG-2444: defaultNode //FIXME: BUG-2444: Optional
1028 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
1029 emitConfigNode(value.isConfiguration());
1031 if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
1032 emitMandatoryNode(value.getConstraints().isMandatory());
1034 emitDocumentedNodeRefine(original, value);
1038 private void emitRefineCaseNodes(final ChoiceCaseNode value) {
1039 final ChoiceCaseNode original = getOriginalChecked(value);
1040 emitDocumentedNodeRefine(original, value);
1044 private void emitRefineAnyxmlNodes(final AnyXmlSchemaNode value) {
1045 final AnyXmlSchemaNode original = getOriginalChecked(value);
1047 // FIXME: BUG-2444: emitMustNodes(child.getConstraints().getMustConstraints());
1048 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
1049 emitConfigNode(value.isConfiguration());
1051 if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
1052 emitMandatoryNode(value.getConstraints().isMandatory());
1054 emitDocumentedNodeRefine(original, value);
1058 private void emitUsesAugmentNode(final AugmentationSchema aug) {
1060 * differs only in location in schema, otherwise currently (as of
1061 * RFC6020) it is same, so we could freely reuse path.
1066 private void emitAugment(final AugmentationSchema augmentation) {
1067 writer.startAugmentNode(augmentation.getTargetPath());
1068 // FIXME: BUG-2444: whenNode //Optional
1069 // FIXME: BUG-2444: *(ifFeatureNode )
1071 emitStatusNode(augmentation.getStatus());
1072 emitDescriptionNode(augmentation.getDescription());
1073 emitReferenceNode(augmentation.getReference());
1074 for (final UsesNode uses: augmentation.getUses()) {
1078 for (final DataSchemaNode childNode : augmentation.getChildNodes()) {
1079 if (childNode instanceof ChoiceCaseNode) {
1080 emitCaseNode((ChoiceCaseNode) childNode);
1082 emitDataSchemaNode(childNode);
1085 emitUnknownStatementNodes(augmentation.getUnknownSchemaNodes());
1089 private void emitUnknownStatementNodes(final List<UnknownSchemaNode> unknownNodes) {
1090 for (final UnknownSchemaNode unknonwnNode : unknownNodes) {
1091 if (!unknonwnNode.isAddedByAugmentation() && !unknonwnNode.isAddedByUses()) {
1092 emitUnknownStatementNode(unknonwnNode);
1097 private void emitUnknownStatementNode(final UnknownSchemaNode node) {
1098 final StatementDefinition def = getStatementChecked(node.getNodeType());
1099 if (def.getArgumentName() == null) {
1100 writer.startUnknownNode(def);
1102 writer.startUnknownNode(def, node.getNodeParameter());
1104 emitUnknownStatementNodes(node.getUnknownSchemaNodes());
1108 private StatementDefinition getStatementChecked(final QName nodeType) {
1109 final StatementDefinition ret = extensions.get(nodeType);
1110 Preconditions.checkArgument(ret != null, "Unknown extension %s used during export.",nodeType);
1114 private void emitWhen(final RevisionAwareXPath revisionAwareXPath) {
1115 if (revisionAwareXPath != null) {
1116 writer.startWhenNode(revisionAwareXPath);
1119 // FIXME: BUG-2444: descriptionNode //FIXME: BUG-2444: Optional
1120 // FIXME: BUG-2444: referenceNode //FIXME: BUG-2444: Optional
1121 // FIXME: BUG-2444: writer.endNode();)
1125 private void emitRpc(final RpcDefinition rpc) {
1126 writer.startRpcNode(rpc.getQName());
1127 // FIXME: BUG-2444: *(ifFeatureNode )
1128 emitStatusNode(rpc.getStatus());
1129 emitDescriptionNode(rpc.getDescription());
1130 emitReferenceNode(rpc.getReference());
1132 for (final TypeDefinition<?> typedef : rpc.getTypeDefinitions()) {
1133 emitTypedefNode(typedef);
1135 for (final GroupingDefinition grouping : rpc.getGroupings()) {
1136 emitGrouping(grouping);
1138 emitInput(rpc.getInput());
1139 emitOutput(rpc.getOutput());
1140 emitUnknownStatementNodes(rpc.getUnknownSchemaNodes());
1145 private void emitInput(@Nonnull final ContainerSchemaNode input) {
1146 if (isExplicitStatement(input)) {
1147 writer.startInputNode();
1148 emitDataNodeContainer(input);
1149 emitUnknownStatementNodes(input.getUnknownSchemaNodes());
1155 private void emitOutput(@Nonnull final ContainerSchemaNode output) {
1156 if (isExplicitStatement(output)) {
1157 writer.startOutputNode();
1158 emitDataNodeContainer(output);
1159 emitUnknownStatementNodes(output.getUnknownSchemaNodes());
1165 private static boolean isExplicitStatement(final ContainerSchemaNode node) {
1166 return node instanceof EffectiveStatement
1167 && ((EffectiveStatement) node).getDeclared().getStatementSource() == StatementSource.DECLARATION;
1170 private void emitNotificationNode(final NotificationDefinition notification) {
1171 writer.startNotificationNode(notification.getQName());
1172 // FIXME: BUG-2444: *(ifFeatureNode )
1173 emitDocumentedNode(notification);
1174 emitDataNodeContainer(notification);
1175 emitUnknownStatementNodes(notification.getUnknownSchemaNodes());
1181 //FIXME: Probably should be moved to utils bundle.
1182 private static <T> boolean isPrefix(final Iterable<T> prefix, final Iterable<T> other) {
1183 final Iterator<T> prefixIt = prefix.iterator();
1184 final Iterator<T> otherIt = other.iterator();
1185 while (prefixIt.hasNext()) {
1186 if (!otherIt.hasNext()) {
1189 if (!Objects.deepEquals(prefixIt.next(), otherIt.next())) {
1196 private void emitDeviation(final Deviation deviation) {
1198 * FIXME: BUG-2444: Deviation is not modeled properly and we are loosing lot of
1199 * information in order to export it properly
1201 * writer.startDeviationNode(deviation.getTargetPath());
1203 * :descriptionNode //:Optional
1206 * emitReferenceNode(deviation.getReference());
1207 * :(deviateNotSupportedNode :1*(deviateAddNode :deviateReplaceNode
1208 * :deviateDeleteNode)) :writer.endNode();