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.Nullable;
24 import javax.annotation.concurrent.NotThreadSafe;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
28 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
29 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
31 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
33 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.Deviation;
35 import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
36 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
37 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
38 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
39 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.Module;
44 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
45 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
46 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
47 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
48 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
49 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
50 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
52 import org.opendaylight.yangtools.yang.model.api.Status;
53 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
54 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
55 import org.opendaylight.yangtools.yang.model.api.UsesNode;
56 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
57 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
58 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
59 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
60 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
61 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
62 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
63 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
64 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
65 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
66 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
67 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
68 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
69 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
70 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
71 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
72 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
73 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
74 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
75 import org.opendaylight.yangtools.yang.model.util.DerivedType;
76 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
77 import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
81 class SchemaContextEmitter {
83 private final Rfc6020ModuleWriter writer;
84 private final boolean emitInstantiated;
85 private final boolean emitUses;
86 private final Map<QName, StatementDefinition> extensions;
88 SchemaContextEmitter(final Rfc6020ModuleWriter writer, final Map<QName, StatementDefinition> extensions) {
89 this(writer, extensions,false, true);
92 SchemaContextEmitter(final Rfc6020ModuleWriter writer, final Map<QName, StatementDefinition> extensions, final boolean emitInstantiated, final boolean emitUses) {
93 this.writer = Preconditions.checkNotNull(writer);
94 this.emitInstantiated = emitInstantiated;
95 this.emitUses = emitUses;
96 this.extensions = Preconditions.checkNotNull(extensions);
99 static void writeToStatementWriter(final Module module, final SchemaContext ctx, final StatementTextWriter statementWriter) {
100 final Rfc6020ModuleWriter yangSchemaWriter = SchemaToStatementWriterAdaptor.from(statementWriter);
101 final Map<QName, StatementDefinition> extensions = ExtensionStatement.mapFrom(ctx.getExtensions());
102 new SchemaContextEmitter(yangSchemaWriter,extensions).emitModule(module);
105 void emitModule(final Module input) {
106 writer.startModuleNode(input.getName());
107 emitModuleHeader(input);
108 emitLinkageNodes(input);
109 emitMetaNodes(input);
110 emitRevisionNodes(input);
111 emitBodyNodes(input);
115 private void emitModuleHeader(final Module input) {
116 emitYangVersionNode(input.getYangVersion());
117 emitNamespace(input.getNamespace());
118 emitPrefixNode(input.getPrefix());
121 @SuppressWarnings("unused")
122 private void emitSubmodule(final String input) {
124 * FIXME: BUG-2444: Implement submodule export
126 * submoduleHeaderNodes linkageNodes metaNodes revisionNodes bodyNodes
131 @SuppressWarnings("unused")
132 private void emitSubmoduleHeaderNodes(final Module input) {
134 * FIXME: BUG-2444: Implement submodule headers properly
136 * :yangVersionNode //Optional
142 private void emitMetaNodes(final Module input) {
144 emitOrganizationNode(input.getOrganization()); // FIXME: BUG-2444: Optional
145 emitContact(input.getContact()); // FIXME: BUG-2444: Optional
146 emitDescriptionNode(input.getDescription());
147 emitReferenceNode(input.getReference());
150 private void emitLinkageNodes(final Module input) {
151 for (final ModuleImport importNode : input.getImports()) {
152 emitImport(importNode);
155 * FIXME: BUG-2444: Emit include statements
159 private void emitRevisionNodes(final Module input) {
161 * FIXME: BUG-2444: emit revisions properly, when parsed model will provide enough
164 emitRevision(input.getRevision());
168 private void emitBodyNodes(final Module input) {
170 for (final ExtensionDefinition extension : input.getExtensionSchemaNodes()) {
171 emitExtension(extension);
173 for (final FeatureDefinition definition : input.getFeatures()) {
174 emitFeature(definition);
176 for (final IdentitySchemaNode identity : input.getIdentities()) {
177 emitIdentity(identity);
180 emitDataNodeContainer(input);
182 for (final AugmentationSchema augmentation : input.getAugmentations()) {
183 emitAugment(augmentation);
185 for (final RpcDefinition rpc : input.getRpcs()) {
188 for (final NotificationDefinition notification : input.getNotifications()) {
189 emitNotificationNode(notification);
191 for (final Deviation deviation : input.getDeviations()) {
192 emitDeviation(deviation);
197 private void emitDataNodeContainer(final DataNodeContainer input) {
198 for (final TypeDefinition<?> typedef : input.getTypeDefinitions()) {
199 emitTypedefNode(typedef);
201 for (final GroupingDefinition grouping : input.getGroupings()) {
202 emitGrouping(grouping);
204 for (final DataSchemaNode child : input.getChildNodes()) {
205 emitDataSchemaNode(child);
207 for (final UsesNode usesNode : input.getUses()) {
208 emitUsesNode(usesNode);
212 private void emitDataSchemaNode(final DataSchemaNode child) {
213 if (!emitInstantiated && (child.isAddedByUses() || child.isAugmenting())) {
214 // We skip instantiated nodes.
218 if (child instanceof ContainerSchemaNode) {
219 emitContainer((ContainerSchemaNode) child);
220 } else if (child instanceof LeafSchemaNode) {
221 emitLeaf((LeafSchemaNode) child);
222 } else if (child instanceof LeafListSchemaNode) {
223 emitLeafList((LeafListSchemaNode) child);
224 } else if (child instanceof ListSchemaNode) {
225 emitList((ListSchemaNode) child);
226 } else if (child instanceof ChoiceSchemaNode) {
227 emitChoice((ChoiceSchemaNode) child);
228 } else if (child instanceof AnyXmlSchemaNode) {
229 emitAnyxml((AnyXmlSchemaNode) child);
231 throw new UnsupportedOperationException("Not supported DataSchemaNode type " + child.getClass());
235 private void emitYangVersionNode(final String input) {
236 writer.startYangVersionNode(input);
240 private void emitImport(final ModuleImport importNode) {
241 writer.startImportNode(importNode.getModuleName());
242 emitPrefixNode(importNode.getPrefix());
243 emitRevisionDateNode(importNode.getRevision());
247 @SuppressWarnings("unused")
248 private void emitInclude(final String input) {
250 * FIXME: BUG-2444: Implement proper export of include statements
251 * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
254 * :revisionDateNode :writer.endNode();)
258 private void emitNamespace(final URI uri) {
259 writer.startNamespaceNode(uri);
264 private void emitPrefixNode(final String input) {
265 writer.startPrefixNode(input);
270 @SuppressWarnings("unused")
271 private void emitBelongsTo(final String input) {
273 * FIXME: BUG-2444: Implement proper export of belongs-to statements
274 * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
277 * :writer.startBelongsToNode(IdentifierHelper.getIdentifier(String
288 private void emitOrganizationNode(final String input) {
289 writer.startOrganizationNode(input);
294 private void emitContact(final String input) {
295 writer.startContactNode(input);
300 private void emitDescriptionNode(@Nullable final String input) {
301 if (!Strings.isNullOrEmpty(input)) {
302 writer.startDescriptionNode(input);
307 private void emitReferenceNode(@Nullable final String input) {
308 if (!Strings.isNullOrEmpty(input)) {
309 writer.startReferenceNode(input);
314 private void emitUnitsNode(@Nullable final String input) {
315 if (!Strings.isNullOrEmpty(input)) {
316 writer.startUnitsNode(input);
321 private void emitRevision(final Date date) {
322 writer.startRevisionNode(date);
325 // FIXME: BUG-2444: FIXME: BUG-2444: BUG-2417: descriptionNode //FIXME: BUG-2444: Optional
326 // FIXME: BUG-2444: FIXME: BUG-2444: BUG-2417: referenceNode //FIXME: BUG-2444: Optional
331 private void emitRevisionDateNode(@Nullable final Date date) {
333 writer.startRevisionDateNode(date);
338 private void emitExtension(final ExtensionDefinition extension) {
339 writer.startExtensionNode(extension.getQName());
340 emitArgument(extension.getArgument(),extension.isYinElement());
341 emitStatusNode(extension.getStatus());
342 emitDescriptionNode(extension.getDescription());
343 emitReferenceNode(extension.getReference());
344 emitUnknownStatementNodes(extension.getUnknownSchemaNodes());
349 private void emitArgument(final @Nullable String input, final boolean yinElement) {
351 writer.startArgumentNode(input);
352 emitYinElement(yinElement);
358 private void emitYinElement(final boolean yinElement) {
359 writer.startYinElementNode(yinElement);
364 private void emitIdentity(final IdentitySchemaNode identity) {
365 writer.startIdentityNode(identity.getQName());
366 if (identity.getBaseIdentity() != null) {
367 emitBase(identity.getBaseIdentity().getQName());
369 emitStatusNode(identity.getStatus());
370 emitDescriptionNode(identity.getDescription());
371 emitReferenceNode(identity.getReference());
376 private void emitBase(final QName qName) {
377 writer.startBaseNode(qName);
382 private void emitFeature(final FeatureDefinition definition) {
383 writer.startFeatureNode(definition.getQName());
385 // FIXME: BUG-2444: FIXME: BUG-2444: Expose ifFeature *(ifFeatureNode )
386 emitStatusNode(definition.getStatus());
387 emitDescriptionNode(definition.getDescription());
388 emitReferenceNode(definition.getReference());
393 @SuppressWarnings("unused")
394 private void emitIfFeature(final String input) {
396 * FIXME: BUG-2444: Implement proper export of include statements
397 * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
402 private void emitTypedefNode(final TypeDefinition<?> typedef) {
403 writer.startTypedefNode(typedef.getQName());
404 // Differentiate between derived type and existing type
406 emitTypeNodeDerived(typedef);
407 emitUnitsNode(typedef.getUnits());
408 emitDefaultNode(typedef.getDefaultValue());
409 emitStatusNode(typedef.getStatus());
410 emitDescriptionNode(typedef.getDescription());
411 emitReferenceNode(typedef.getReference());
412 emitUnknownStatementNodes(typedef.getUnknownSchemaNodes());
417 private void emitTypeNode(final SchemaPath parentPath, final TypeDefinition<?> subtype) {
418 final SchemaPath path = subtype.getPath();
419 if (isPrefix(parentPath.getPathFromRoot(), path.getPathFromRoot())) {
420 emitTypeNodeDerived(subtype);
422 emitTypeNodeReferenced(subtype);
426 private void emitTypeNodeReferenced(final TypeDefinition<?> typeDefinition) {
427 writer.startTypeNode(typeDefinition.getQName());
432 private void emitTypeNodeDerived(final TypeDefinition<?> typeDefinition) {
433 final TypeDefinition<?> baseType;
434 if (typeDefinition.getBaseType() != null) {
435 baseType = typeDefinition.getBaseType();
437 baseType = typeDefinition;
439 writer.startTypeNode(baseType.getQName());
440 emitTypeBodyNodes(typeDefinition);
445 private void emitTypeBodyNodes(final TypeDefinition<?> typeDef) {
446 if (typeDef instanceof ExtendedType) {
447 emitTypeBodyNodes(DerivedType.from((ExtendedType) typeDef));
448 } else if (typeDef instanceof UnsignedIntegerTypeDefinition) {
449 emitUnsignedIntegerSpecification((UnsignedIntegerTypeDefinition) typeDef);
450 } else if (typeDef instanceof IntegerTypeDefinition) {
451 emitIntegerSpefication((IntegerTypeDefinition) typeDef);
452 } else if (typeDef instanceof DecimalTypeDefinition) {
453 emitDecimal64Specification((DecimalTypeDefinition) typeDef);
454 } else if (typeDef instanceof StringTypeDefinition) {
455 emitStringRestrictions((StringTypeDefinition) typeDef);
456 } else if (typeDef instanceof EnumTypeDefinition) {
457 emitEnumSpecification((EnumTypeDefinition) typeDef);
458 } else if (typeDef instanceof LeafrefTypeDefinition) {
459 emitLeafrefSpecification((LeafrefTypeDefinition) typeDef);
460 } else if (typeDef instanceof IdentityrefTypeDefinition) {
461 emitIdentityrefSpecification((IdentityrefTypeDefinition) typeDef);
462 } else if (typeDef instanceof InstanceIdentifierTypeDefinition) {
463 emitInstanceIdentifierSpecification((InstanceIdentifierTypeDefinition) typeDef);
464 } else if (typeDef instanceof BitsTypeDefinition) {
465 emitBitsSpecification((BitsTypeDefinition) typeDef);
466 } else if (typeDef instanceof UnionTypeDefinition) {
467 emitUnionSpecification((UnionTypeDefinition) typeDef);
468 } else if (typeDef instanceof BinaryTypeDefinition) {
469 // FIXME: BUG-2444: Is this realy NOOP?
470 // should at least support length statement
471 } else if (typeDef instanceof BooleanTypeDefinition || typeDef instanceof EmptyTypeDefinition) {
474 throw new IllegalArgumentException("Not supported type " + typeDef.getClass());
478 private void emitIntegerSpefication(final IntegerTypeDefinition typeDef) {
479 emitRangeNodeOptional(typeDef.getRangeConstraints());
482 private void emitUnsignedIntegerSpecification(final UnsignedIntegerTypeDefinition typeDef) {
483 emitRangeNodeOptional(typeDef.getRangeConstraints());
487 private void emitRangeNodeOptional(final List<RangeConstraint> list) {
488 // FIXME: BUG-2444: Wrong decomposition in API, should be LenghtConstraint
489 // which contains ranges.
490 if (!list.isEmpty()) {
491 writer.startRangeNode(toRangeString(list));
492 final RangeConstraint first = list.iterator().next();
493 emitErrorMessageNode(first.getErrorMessage());
494 emitErrorAppTagNode(first.getErrorAppTag());
495 emitDescriptionNode(first.getDescription());
496 emitReferenceNode(first.getReference());
502 private void emitDecimal64Specification(final DecimalTypeDefinition typeDefinition) {
503 emitFranctionDigitsNode(typeDefinition.getFractionDigits());
504 emitRangeNodeOptional(typeDefinition.getRangeConstraints());
508 private void emitFranctionDigitsNode(final Integer fractionDigits) {
509 writer.startFractionDigitsNode(fractionDigits);
513 private void emitStringRestrictions(final StringTypeDefinition typeDef) {
515 // FIXME: BUG-2444: Wrong decomposition in API, should be LenghtConstraint
516 // which contains ranges.
517 emitLength(typeDef.getLengthConstraints());
519 for (final PatternConstraint pattern : typeDef.getPatternConstraints()) {
520 emitPatternNode(pattern);
525 private void emitLength(final List<LengthConstraint> list) {
526 if (!list.isEmpty()) {
527 writer.startLengthNode(toLengthString(list));
528 // FIXME: BUG-2444: Workaround for incorrect decomposition in API
529 final LengthConstraint first = list.iterator().next();
530 emitErrorMessageNode(first.getErrorMessage());
531 emitErrorAppTagNode(first.getErrorAppTag());
532 emitDescriptionNode(first.getDescription());
533 emitReferenceNode(first.getReference());
539 private String toLengthString(final List<LengthConstraint> list) {
540 final StringBuilder lengthStr = new StringBuilder();
541 final Iterator<LengthConstraint> constIt = list.iterator();
542 while (constIt.hasNext()) {
543 final LengthConstraint current = constIt.next();
544 if (current.getMin() == current.getMax()) {
545 lengthStr.append(current.getMin());
547 lengthStr.append(current.getMin());
548 lengthStr.append("..");
549 lengthStr.append(current.getMax());
551 if (constIt.hasNext()) {
552 lengthStr.append("|");
555 return lengthStr.toString();
558 private String toRangeString(final List<RangeConstraint> list) {
559 final StringBuilder lengthStr = new StringBuilder();
560 final Iterator<RangeConstraint> constIt = list.iterator();
561 while (constIt.hasNext()) {
562 final RangeConstraint current = constIt.next();
563 if (current.getMin() == current.getMax()) {
564 lengthStr.append(current.getMin());
566 lengthStr.append(current.getMin());
567 lengthStr.append("..");
568 lengthStr.append(current.getMax());
570 if (constIt.hasNext()) {
571 lengthStr.append("|");
574 return lengthStr.toString();
577 private void emitPatternNode(final PatternConstraint pattern) {
578 writer.startPatternNode(pattern.getRegularExpression());
579 emitErrorMessageNode(pattern.getErrorMessage()); // FIXME: BUG-2444: Optional
580 emitErrorAppTagNode(pattern.getErrorAppTag()); // FIXME: BUG-2444: Optional
581 emitDescriptionNode(pattern.getDescription());
582 emitReferenceNode(pattern.getReference()); // FIXME: BUG-2444: Optional
586 private void emitDefaultNode(@Nullable final Object object) {
587 if (object != null) {
588 writer.startDefaultNode(object.toString());
594 private void emitEnumSpecification(final EnumTypeDefinition typeDefinition) {
595 for (final EnumPair enumValue : typeDefinition.getValues()) {
596 emitEnumNode(enumValue);
600 private void emitEnumNode(final EnumPair enumValue) {
601 writer.startEnumNode(enumValue.getName());
602 emitValueNode(enumValue.getValue());
603 emitStatusNode(enumValue.getStatus());
604 emitDescriptionNode(enumValue.getDescription());
605 emitReferenceNode(enumValue.getReference());
609 private void emitLeafrefSpecification(final LeafrefTypeDefinition typeDefinition) {
610 emitPathNode(typeDefinition.getPathStatement());
611 // FIXME: BUG-2444: requireInstanceNode /Optional removed with (RFC6020 - Errata ID
616 private void emitPathNode(final RevisionAwareXPath revisionAwareXPath) {
617 writer.startPathNode(revisionAwareXPath);
621 private void emitRequireInstanceNode(final boolean require) {
622 writer.startRequireInstanceNode(require);
626 private void emitInstanceIdentifierSpecification(final InstanceIdentifierTypeDefinition typeDefinition) {
627 emitRequireInstanceNode(typeDefinition.requireInstance());
630 private void emitIdentityrefSpecification(final IdentityrefTypeDefinition typeDefinition) {
631 emitBase(typeDefinition.getQName());
634 private void emitUnionSpecification(final UnionTypeDefinition typeDefinition) {
635 for (final TypeDefinition<?> subtype : typeDefinition.getTypes()) {
636 // FIXME: BUG-2444: What if we have locally modified types here?
637 // is solution to look-up in schema path?
638 emitTypeNode(typeDefinition.getPath(), subtype);
642 private void emitBitsSpecification(final BitsTypeDefinition typeDefinition) {
643 for (final Bit bit : typeDefinition.getBits()) {
648 private void emitBit(final Bit bit) {
649 writer.startBitNode(bit.getName());
650 emitPositionNode(bit.getPosition());
651 emitStatusNode(bit.getStatus());
652 emitDescriptionNode(bit.getDescription());
653 emitReferenceNode(bit.getReference());
657 private void emitPositionNode(@Nullable final Long position) {
658 if (position != null) {
659 writer.startPositionNode(UnsignedInteger.valueOf(position));
664 private void emitStatusNode(@Nullable final Status status) {
665 if (status != null) {
666 writer.startStatusNode(status);
671 private void emitConfigNode(final boolean config) {
672 writer.startConfigNode(config);
676 private void emitMandatoryNode(final boolean mandatory) {
677 writer.startMandatoryNode(mandatory);
681 private void emitPresenceNode(final boolean presence) {
682 writer.startPresenceNode(presence);
686 private void emitOrderedBy(final boolean userOrdered) {
688 writer.startOrderedByNode("user");
690 writer.startOrderedByNode("system");
695 private void emitMust(@Nullable final MustDefinition mustCondition) {
696 if(mustCondition != null && mustCondition.getXpath() != null) {
697 writer.startMustNode(mustCondition.getXpath());
698 emitErrorMessageNode(mustCondition.getErrorMessage());
699 emitErrorAppTagNode(mustCondition.getErrorAppTag());
700 emitDescriptionNode(mustCondition.getDescription());
701 emitReferenceNode(mustCondition.getReference());
707 private void emitErrorMessageNode(@Nullable final String input) {
708 if (input != null && !input.isEmpty()) {
709 writer.startErrorMessageNode(input);
714 private void emitErrorAppTagNode(final String input) {
715 if (input != null && !input.isEmpty()) {
716 writer.startErrorAppTagNode(input);
721 private void emitMinElementsNode(final Integer min) {
723 writer.startMinElementsNode(min);
728 private void emitMaxElementsNode(final Integer max) {
730 writer.startMaxElementsNode(max);
735 private void emitValueNode(@Nullable final Integer value) {
737 writer.startValueNode(value);
742 private void emitDocumentedNode(final DocumentedNode input) {
743 emitStatusNode(input.getStatus());
744 emitDescriptionNode(input.getDescription());
745 emitReferenceNode(input.getReference());
748 private void emitGrouping(final GroupingDefinition grouping) {
749 writer.startGroupingNode(grouping.getQName());
750 emitDocumentedNode(grouping);
751 emitDataNodeContainer(grouping);
752 emitUnknownStatementNodes(grouping.getUnknownSchemaNodes());
757 private void emitContainer(final ContainerSchemaNode child) {
758 writer.startContainerNode(child.getQName());
762 emitConstraints(child.getConstraints());
763 // FIXME: BUG-2444: whenNode //:Optional
764 // FIXME: BUG-2444: *(ifFeatureNode )
765 emitMustNodes(child.getConstraints().getMustConstraints());
766 emitPresenceNode(child.isPresenceContainer());
767 emitConfigNode(child.isConfiguration());
768 emitDocumentedNode(child);
769 emitDataNodeContainer(child);
770 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
775 private void emitConstraints(final ConstraintDefinition constraints) {
776 emitWhen(constraints.getWhenCondition());
777 for (final MustDefinition mustCondition : constraints.getMustConstraints()) {
778 emitMust(mustCondition);
783 private void emitLeaf(final LeafSchemaNode child) {
784 writer.startLeafNode(child.getQName());
785 emitWhen(child.getConstraints().getWhenCondition());
786 // FIXME: BUG-2444: *(ifFeatureNode )
787 emitTypeNode(child.getPath(), child.getType());
788 emitUnitsNode(child.getUnits());
789 emitMustNodes(child.getConstraints().getMustConstraints());
790 emitDefaultNode(child.getDefault());
791 emitConfigNode(child.isConfiguration());
792 emitMandatoryNode(child.getConstraints().isMandatory());
793 emitDocumentedNode(child);
794 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
799 private void emitLeafList(final LeafListSchemaNode child) {
800 writer.startLeafListNode(child.getQName());
802 emitWhen(child.getConstraints().getWhenCondition());
803 // FIXME: BUG-2444: *(ifFeatureNode )
804 emitTypeNode(child.getPath(), child.getType());
805 // FIXME: BUG-2444: unitsNode /Optional
806 emitMustNodes(child.getConstraints().getMustConstraints());
807 emitConfigNode(child.isConfiguration());
809 emitMinElementsNode(child.getConstraints().getMinElements());
810 emitMaxElementsNode(child.getConstraints().getMaxElements());
811 emitOrderedBy(child.isUserOrdered());
812 emitDocumentedNode(child);
813 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
818 private void emitList(final ListSchemaNode child) {
819 writer.startListNode(child.getQName());
820 emitWhen(child.getConstraints().getWhenCondition());
822 // FIXME: BUG-2444: *(ifFeatureNode )
823 emitMustNodes(child.getConstraints().getMustConstraints());
824 emitKey(child.getKeyDefinition());
825 // FIXME: BUG-2444: *(uniqueNode )
826 emitConfigNode(child.isConfiguration());
827 emitMinElementsNode(child.getConstraints().getMinElements());
828 emitMaxElementsNode(child.getConstraints().getMaxElements());
829 emitOrderedBy(child.isUserOrdered());
830 emitDocumentedNode(child);
831 emitDataNodeContainer(child);
832 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
837 private void emitMustNodes(final Set<MustDefinition> mustConstraints) {
838 for (final MustDefinition must : mustConstraints) {
843 private void emitKey(final List<QName> keyList) {
844 if (keyList != null && !keyList.isEmpty()) {
845 writer.startKeyNode(keyList);
850 @SuppressWarnings("unused")
851 private void emitUnique(final String input) {
852 // FIXME: BUG-2444: writer.startUniqueNode(uniqueArgStr)); Nodeend
856 private void emitChoice(final ChoiceSchemaNode choice) {
857 writer.startChoiceNode(choice.getQName());
858 emitWhen(choice.getConstraints().getWhenCondition());
859 // FIXME: BUG-2444: *(ifFeatureNode )
860 // FIXME: BUG-2444: defaultNode //Optional
861 emitConfigNode(choice.isConfiguration());
862 emitMandatoryNode(choice.getConstraints().isMandatory());
863 emitDocumentedNode(choice);
864 for (final ChoiceCaseNode caze : choice.getCases()) {
865 // TODO: emit short case?
868 emitUnknownStatementNodes(choice.getUnknownSchemaNodes());
872 private void emitCaseNode(final ChoiceCaseNode caze) {
873 if (!emitInstantiated && caze.isAugmenting()) {
876 writer.startCaseNode(caze.getQName());
877 emitWhen(caze.getConstraints().getWhenCondition());
878 // FIXME: BUG-2444: *(ifFeatureNode )
879 emitDocumentedNode(caze);
880 emitDataNodeContainer(caze);
881 emitUnknownStatementNodes(caze.getUnknownSchemaNodes());
886 private void emitAnyxml(final AnyXmlSchemaNode child) {
887 writer.startAnyxmlNode(child.getQName());
889 emitWhen(child.getConstraints().getWhenCondition());
890 // FIXME: BUG-2444: *(ifFeatureNode )
891 emitMustNodes(child.getConstraints().getMustConstraints());
892 emitConfigNode(child.isConfiguration());
893 emitMandatoryNode(child.getConstraints().isMandatory());
894 emitDocumentedNode(child);
895 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
900 private void emitUsesNode(final UsesNode usesNode) {
901 if (emitUses && !usesNode.isAddedByUses() && !usesNode.isAugmenting()) {
902 writer.startUsesNode(usesNode.getGroupingPath().getLastComponent());
907 * statusNode // Optional F
908 * : descriptionNode // Optional
909 * referenceNode // Optional
911 for (final Entry<SchemaPath, SchemaNode> refine : usesNode.getRefines().entrySet()) {
914 for (final AugmentationSchema aug : usesNode.getAugmentations()) {
915 emitUsesAugmentNode(aug);
921 private void emitRefine(final Entry<SchemaPath, SchemaNode> refine) {
922 final SchemaPath path = refine.getKey();
923 final SchemaNode value = refine.getValue();
924 writer.startRefineNode(path);
926 if (value instanceof LeafSchemaNode) {
927 emitRefineLeafNodes((LeafSchemaNode) value);
928 } else if (value instanceof LeafListSchemaNode) {
929 emitRefineLeafListNodes((LeafListSchemaNode) value);
930 } else if (value instanceof ListSchemaNode) {
931 emitRefineListNodes((ListSchemaNode) value);
932 } else if (value instanceof ChoiceSchemaNode) {
933 emitRefineChoiceNodes((ChoiceSchemaNode) value);
934 } else if (value instanceof ChoiceCaseNode) {
935 emitRefineCaseNodes((ChoiceCaseNode) value);
936 } else if (value instanceof ContainerSchemaNode) {
937 emitRefineContainerNodes((ContainerSchemaNode) value);
938 } else if (value instanceof AnyXmlSchemaNode) {
939 emitRefineAnyxmlNodes((AnyXmlSchemaNode) value);
945 private <T extends SchemaNode> T getOriginalChecked(final T value) {
946 final Optional<SchemaNode> original = SchemaNodeUtils.getOriginalIfPossible(value);
947 Preconditions.checkArgument(original.isPresent(), "Original unmodified version of node is not present.");
948 @SuppressWarnings("unchecked")
949 final T ret = (T) original.get();
953 private void emitDocumentedNodeRefine(final DocumentedNode original, final DocumentedNode value) {
954 if (Objects.deepEquals(original.getDescription(), value.getDescription())) {
955 emitDescriptionNode(value.getDescription());
957 if (Objects.deepEquals(original.getReference(), value.getReference())) {
958 emitReferenceNode(value.getReference());
962 private void emitRefineContainerNodes(final ContainerSchemaNode value) {
963 final ContainerSchemaNode original = getOriginalChecked(value);
965 // emitMustNodes(child.getConstraints().getMustConstraints());
966 if (Objects.deepEquals(original.isPresenceContainer(), value.isPresenceContainer())) {
967 emitPresenceNode(value.isPresenceContainer());
969 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
970 emitConfigNode(value.isConfiguration());
972 emitDocumentedNodeRefine(original, value);
976 private void emitRefineLeafNodes(final LeafSchemaNode value) {
977 final LeafSchemaNode original = getOriginalChecked(value);
979 // emitMustNodes(child.getConstraints().getMustConstraints());
980 if (Objects.deepEquals(original.getDefault(), value.getDefault())) {
981 emitDefaultNode(value.getDefault());
983 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
984 emitConfigNode(value.isConfiguration());
986 emitDocumentedNodeRefine(original, value);
987 if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
988 emitMandatoryNode(value.getConstraints().isMandatory());
993 private void emitRefineLeafListNodes(final LeafListSchemaNode value) {
994 final LeafListSchemaNode original = getOriginalChecked(value);
996 // emitMustNodes(child.getConstraints().getMustConstraints());
997 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
998 emitConfigNode(value.isConfiguration());
1000 if (Objects.deepEquals(original.getConstraints().getMinElements(), value.getConstraints().getMinElements())) {
1001 emitMinElementsNode(value.getConstraints().getMinElements());
1003 if (Objects.deepEquals(original.getConstraints().getMaxElements(), value.getConstraints().getMaxElements())) {
1004 emitMaxElementsNode(value.getConstraints().getMaxElements());
1006 emitDocumentedNodeRefine(original, value);
1010 private void emitRefineListNodes(final ListSchemaNode value) {
1011 final ListSchemaNode original = getOriginalChecked(value);
1013 // emitMustNodes(child.getConstraints().getMustConstraints());
1014 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
1015 emitConfigNode(value.isConfiguration());
1017 if (Objects.deepEquals(original.getConstraints().getMinElements(), value.getConstraints().getMinElements())) {
1018 emitMinElementsNode(value.getConstraints().getMinElements());
1020 if (Objects.deepEquals(original.getConstraints().getMaxElements(), value.getConstraints().getMaxElements())) {
1021 emitMaxElementsNode(value.getConstraints().getMaxElements());
1023 emitDocumentedNodeRefine(original, value);
1027 private void emitRefineChoiceNodes(final ChoiceSchemaNode value) {
1028 final ChoiceSchemaNode original = getOriginalChecked(value);
1030 // FIXME: BUG-2444: defaultNode //FIXME: BUG-2444: Optional
1031 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
1032 emitConfigNode(value.isConfiguration());
1034 if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
1035 emitMandatoryNode(value.getConstraints().isMandatory());
1037 emitDocumentedNodeRefine(original, value);
1041 private void emitRefineCaseNodes(final ChoiceCaseNode value) {
1042 final ChoiceCaseNode original = getOriginalChecked(value);
1043 emitDocumentedNodeRefine(original, value);
1047 private void emitRefineAnyxmlNodes(final AnyXmlSchemaNode value) {
1048 final AnyXmlSchemaNode original = getOriginalChecked(value);
1050 // FIXME: BUG-2444: emitMustNodes(child.getConstraints().getMustConstraints());
1051 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
1052 emitConfigNode(value.isConfiguration());
1054 if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
1055 emitMandatoryNode(value.getConstraints().isMandatory());
1057 emitDocumentedNodeRefine(original, value);
1061 private void emitUsesAugmentNode(final AugmentationSchema aug) {
1063 * differs only in location in schema, otherwise currently (as of
1064 * RFC6020) it is same, so we could freely reuse path.
1069 private void emitAugment(final AugmentationSchema augmentation) {
1070 writer.startAugmentNode(augmentation.getTargetPath());
1071 // FIXME: BUG-2444: whenNode //Optional
1072 // FIXME: BUG-2444: *(ifFeatureNode )
1074 emitStatusNode(augmentation.getStatus());
1075 emitDescriptionNode(augmentation.getDescription());
1076 emitReferenceNode(augmentation.getReference());
1077 for(final UsesNode uses: augmentation.getUses()) {
1081 for (final DataSchemaNode childNode : augmentation.getChildNodes()) {
1082 if (childNode instanceof ChoiceCaseNode) {
1083 emitCaseNode((ChoiceCaseNode) childNode);
1085 emitDataSchemaNode(childNode);
1088 emitUnknownStatementNodes(augmentation.getUnknownSchemaNodes());
1092 private void emitUnknownStatementNodes(final List<UnknownSchemaNode> unknownNodes) {
1093 for (final UnknownSchemaNode unknonwnNode : unknownNodes) {
1094 emitUnknownStatementNode(unknonwnNode);
1098 private void emitUnknownStatementNode(final UnknownSchemaNode node) {
1099 final StatementDefinition def = getStatementChecked(node.getNodeType());
1100 if (def.getArgumentName() == null) {
1101 writer.startUnknownNode(def);
1103 writer.startUnknownNode(def, node.getNodeParameter());
1105 emitUnknownStatementNodes(node.getUnknownSchemaNodes());
1109 private StatementDefinition getStatementChecked(final QName nodeType) {
1110 final StatementDefinition ret = extensions.get(nodeType);
1111 Preconditions.checkArgument(ret != null, "Unknown extension %s used during export.",nodeType);
1115 private void emitWhen(final RevisionAwareXPath revisionAwareXPath) {
1116 if(revisionAwareXPath != null) {
1117 writer.startWhenNode(revisionAwareXPath);
1120 // FIXME: BUG-2444: descriptionNode //FIXME: BUG-2444: Optional
1121 // FIXME: BUG-2444: referenceNode //FIXME: BUG-2444: Optional
1122 // FIXME: BUG-2444: writer.endNode();)
1126 private void emitRpc(final RpcDefinition rpc) {
1127 writer.startRpcNode(rpc.getQName());
1128 // FIXME: BUG-2444: *(ifFeatureNode )
1129 emitStatusNode(rpc.getStatus());
1130 emitDescriptionNode(rpc.getDescription());
1131 emitReferenceNode(rpc.getReference());
1133 for(final TypeDefinition<?> typedef : rpc.getTypeDefinitions()) {
1134 emitTypedefNode(typedef);
1136 for(final GroupingDefinition grouping : rpc.getGroupings()) {
1137 emitGrouping(grouping);
1139 emitInput(rpc.getInput());
1140 emitOutput(rpc.getOutput());
1141 emitUnknownStatementNodes(rpc.getUnknownSchemaNodes());
1146 private void emitInput(@Nullable final ContainerSchemaNode input) {
1147 if (input != null) {
1148 writer.startInputNode();
1149 emitDataNodeContainer(input);
1150 emitUnknownStatementNodes(input.getUnknownSchemaNodes());
1156 private void emitOutput(@Nullable final ContainerSchemaNode input) {
1157 if (input != null) {
1158 writer.startOutputNode();
1159 emitDataNodeContainer(input);
1160 emitUnknownStatementNodes(input.getUnknownSchemaNodes());
1166 private void emitNotificationNode(final NotificationDefinition notification) {
1167 writer.startNotificationNode(notification.getQName());
1168 // FIXME: BUG-2444: *(ifFeatureNode )
1169 emitDocumentedNode(notification);
1170 emitDataNodeContainer(notification);
1171 emitUnknownStatementNodes(notification.getUnknownSchemaNodes());
1177 //FIXME: Probably should be moved to utils bundle.
1178 private static <T> boolean isPrefix(final Iterable<T> prefix, final Iterable<T> other) {
1179 final Iterator<T> prefixIt = prefix.iterator();
1180 final Iterator<T> otherIt = other.iterator();
1181 while(prefixIt.hasNext()) {
1182 if(!otherIt.hasNext()) {
1185 if(!Objects.deepEquals(prefixIt.next(), otherIt.next())) {
1192 private void emitDeviation(final Deviation deviation) {
1194 * FIXME: BUG-2444: Deviation is not modeled properly and we are loosing lot of
1195 * information in order to export it properly
1197 * writer.startDeviationNode(deviation.getTargetPath());
1199 * :descriptionNode //:Optional
1202 * emitReferenceNode(deviation.getReference());
1203 * :(deviateNotSupportedNode :1*(deviateAddNode :deviateReplaceNode
1204 * :deviateDeleteNode)) :writer.endNode();