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());
538 private static String toLengthString(final List<LengthConstraint> list) {
539 final StringBuilder lengthStr = new StringBuilder();
540 final Iterator<LengthConstraint> constIt = list.iterator();
541 while (constIt.hasNext()) {
542 final LengthConstraint current = constIt.next();
543 if (current.getMin() == current.getMax()) {
544 lengthStr.append(current.getMin());
546 lengthStr.append(current.getMin());
547 lengthStr.append("..");
548 lengthStr.append(current.getMax());
550 if (constIt.hasNext()) {
551 lengthStr.append("|");
554 return lengthStr.toString();
557 private static String toRangeString(final List<RangeConstraint> list) {
558 final StringBuilder lengthStr = new StringBuilder();
559 final Iterator<RangeConstraint> constIt = list.iterator();
560 while (constIt.hasNext()) {
561 final RangeConstraint current = constIt.next();
562 if (current.getMin() == current.getMax()) {
563 lengthStr.append(current.getMin());
565 lengthStr.append(current.getMin());
566 lengthStr.append("..");
567 lengthStr.append(current.getMax());
569 if (constIt.hasNext()) {
570 lengthStr.append("|");
573 return lengthStr.toString();
576 private void emitPatternNode(final PatternConstraint pattern) {
577 writer.startPatternNode(pattern.getRegularExpression());
578 emitErrorMessageNode(pattern.getErrorMessage()); // FIXME: BUG-2444: Optional
579 emitErrorAppTagNode(pattern.getErrorAppTag()); // FIXME: BUG-2444: Optional
580 emitDescriptionNode(pattern.getDescription());
581 emitReferenceNode(pattern.getReference()); // FIXME: BUG-2444: Optional
585 private void emitDefaultNode(@Nullable final Object object) {
586 if (object != null) {
587 writer.startDefaultNode(object.toString());
593 private void emitEnumSpecification(final EnumTypeDefinition typeDefinition) {
594 for (final EnumPair enumValue : typeDefinition.getValues()) {
595 emitEnumNode(enumValue);
599 private void emitEnumNode(final EnumPair enumValue) {
600 writer.startEnumNode(enumValue.getName());
601 emitValueNode(enumValue.getValue());
602 emitStatusNode(enumValue.getStatus());
603 emitDescriptionNode(enumValue.getDescription());
604 emitReferenceNode(enumValue.getReference());
608 private void emitLeafrefSpecification(final LeafrefTypeDefinition typeDefinition) {
609 emitPathNode(typeDefinition.getPathStatement());
610 // FIXME: BUG-2444: requireInstanceNode /Optional removed with (RFC6020 - Errata ID
615 private void emitPathNode(final RevisionAwareXPath revisionAwareXPath) {
616 writer.startPathNode(revisionAwareXPath);
620 private void emitRequireInstanceNode(final boolean require) {
621 writer.startRequireInstanceNode(require);
625 private void emitInstanceIdentifierSpecification(final InstanceIdentifierTypeDefinition typeDefinition) {
626 emitRequireInstanceNode(typeDefinition.requireInstance());
629 private void emitIdentityrefSpecification(final IdentityrefTypeDefinition typeDefinition) {
630 emitBase(typeDefinition.getQName());
633 private void emitUnionSpecification(final UnionTypeDefinition typeDefinition) {
634 for (final TypeDefinition<?> subtype : typeDefinition.getTypes()) {
635 // FIXME: BUG-2444: What if we have locally modified types here?
636 // is solution to look-up in schema path?
637 emitTypeNode(typeDefinition.getPath(), subtype);
641 private void emitBitsSpecification(final BitsTypeDefinition typeDefinition) {
642 for (final Bit bit : typeDefinition.getBits()) {
647 private void emitBit(final Bit bit) {
648 writer.startBitNode(bit.getName());
649 emitPositionNode(bit.getPosition());
650 emitStatusNode(bit.getStatus());
651 emitDescriptionNode(bit.getDescription());
652 emitReferenceNode(bit.getReference());
656 private void emitPositionNode(@Nullable final Long position) {
657 if (position != null) {
658 writer.startPositionNode(UnsignedInteger.valueOf(position));
663 private void emitStatusNode(@Nullable final Status status) {
664 if (status != null) {
665 writer.startStatusNode(status);
670 private void emitConfigNode(final boolean config) {
671 writer.startConfigNode(config);
675 private void emitMandatoryNode(final boolean mandatory) {
676 writer.startMandatoryNode(mandatory);
680 private void emitPresenceNode(final boolean presence) {
681 writer.startPresenceNode(presence);
685 private void emitOrderedBy(final boolean userOrdered) {
687 writer.startOrderedByNode("user");
689 writer.startOrderedByNode("system");
694 private void emitMust(@Nullable final MustDefinition mustCondition) {
695 if(mustCondition != null && mustCondition.getXpath() != null) {
696 writer.startMustNode(mustCondition.getXpath());
697 emitErrorMessageNode(mustCondition.getErrorMessage());
698 emitErrorAppTagNode(mustCondition.getErrorAppTag());
699 emitDescriptionNode(mustCondition.getDescription());
700 emitReferenceNode(mustCondition.getReference());
706 private void emitErrorMessageNode(@Nullable final String input) {
707 if (input != null && !input.isEmpty()) {
708 writer.startErrorMessageNode(input);
713 private void emitErrorAppTagNode(final String input) {
714 if (input != null && !input.isEmpty()) {
715 writer.startErrorAppTagNode(input);
720 private void emitMinElementsNode(final Integer min) {
722 writer.startMinElementsNode(min);
727 private void emitMaxElementsNode(final Integer max) {
729 writer.startMaxElementsNode(max);
734 private void emitValueNode(@Nullable final Integer value) {
736 writer.startValueNode(value);
741 private void emitDocumentedNode(final DocumentedNode input) {
742 emitStatusNode(input.getStatus());
743 emitDescriptionNode(input.getDescription());
744 emitReferenceNode(input.getReference());
747 private void emitGrouping(final GroupingDefinition grouping) {
748 writer.startGroupingNode(grouping.getQName());
749 emitDocumentedNode(grouping);
750 emitDataNodeContainer(grouping);
751 emitUnknownStatementNodes(grouping.getUnknownSchemaNodes());
756 private void emitContainer(final ContainerSchemaNode child) {
757 writer.startContainerNode(child.getQName());
761 emitConstraints(child.getConstraints());
762 // FIXME: BUG-2444: whenNode //:Optional
763 // FIXME: BUG-2444: *(ifFeatureNode )
764 emitMustNodes(child.getConstraints().getMustConstraints());
765 emitPresenceNode(child.isPresenceContainer());
766 emitConfigNode(child.isConfiguration());
767 emitDocumentedNode(child);
768 emitDataNodeContainer(child);
769 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
774 private void emitConstraints(final ConstraintDefinition constraints) {
775 emitWhen(constraints.getWhenCondition());
776 for (final MustDefinition mustCondition : constraints.getMustConstraints()) {
777 emitMust(mustCondition);
782 private void emitLeaf(final LeafSchemaNode child) {
783 writer.startLeafNode(child.getQName());
784 emitWhen(child.getConstraints().getWhenCondition());
785 // FIXME: BUG-2444: *(ifFeatureNode )
786 emitTypeNode(child.getPath(), child.getType());
787 emitUnitsNode(child.getUnits());
788 emitMustNodes(child.getConstraints().getMustConstraints());
789 emitDefaultNode(child.getDefault());
790 emitConfigNode(child.isConfiguration());
791 emitMandatoryNode(child.getConstraints().isMandatory());
792 emitDocumentedNode(child);
793 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
798 private void emitLeafList(final LeafListSchemaNode child) {
799 writer.startLeafListNode(child.getQName());
801 emitWhen(child.getConstraints().getWhenCondition());
802 // FIXME: BUG-2444: *(ifFeatureNode )
803 emitTypeNode(child.getPath(), child.getType());
804 // FIXME: BUG-2444: unitsNode /Optional
805 emitMustNodes(child.getConstraints().getMustConstraints());
806 emitConfigNode(child.isConfiguration());
808 emitMinElementsNode(child.getConstraints().getMinElements());
809 emitMaxElementsNode(child.getConstraints().getMaxElements());
810 emitOrderedBy(child.isUserOrdered());
811 emitDocumentedNode(child);
812 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
817 private void emitList(final ListSchemaNode child) {
818 writer.startListNode(child.getQName());
819 emitWhen(child.getConstraints().getWhenCondition());
821 // FIXME: BUG-2444: *(ifFeatureNode )
822 emitMustNodes(child.getConstraints().getMustConstraints());
823 emitKey(child.getKeyDefinition());
824 // FIXME: BUG-2444: *(uniqueNode )
825 emitConfigNode(child.isConfiguration());
826 emitMinElementsNode(child.getConstraints().getMinElements());
827 emitMaxElementsNode(child.getConstraints().getMaxElements());
828 emitOrderedBy(child.isUserOrdered());
829 emitDocumentedNode(child);
830 emitDataNodeContainer(child);
831 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
836 private void emitMustNodes(final Set<MustDefinition> mustConstraints) {
837 for (final MustDefinition must : mustConstraints) {
842 private void emitKey(final List<QName> keyList) {
843 if (keyList != null && !keyList.isEmpty()) {
844 writer.startKeyNode(keyList);
849 @SuppressWarnings("unused")
850 private void emitUnique(final String input) {
851 // FIXME: BUG-2444: writer.startUniqueNode(uniqueArgStr)); Nodeend
855 private void emitChoice(final ChoiceSchemaNode choice) {
856 writer.startChoiceNode(choice.getQName());
857 emitWhen(choice.getConstraints().getWhenCondition());
858 // FIXME: BUG-2444: *(ifFeatureNode )
859 // FIXME: BUG-2444: defaultNode //Optional
860 emitConfigNode(choice.isConfiguration());
861 emitMandatoryNode(choice.getConstraints().isMandatory());
862 emitDocumentedNode(choice);
863 for (final ChoiceCaseNode caze : choice.getCases()) {
864 // TODO: emit short case?
867 emitUnknownStatementNodes(choice.getUnknownSchemaNodes());
871 private void emitCaseNode(final ChoiceCaseNode caze) {
872 if (!emitInstantiated && caze.isAugmenting()) {
875 writer.startCaseNode(caze.getQName());
876 emitWhen(caze.getConstraints().getWhenCondition());
877 // FIXME: BUG-2444: *(ifFeatureNode )
878 emitDocumentedNode(caze);
879 emitDataNodeContainer(caze);
880 emitUnknownStatementNodes(caze.getUnknownSchemaNodes());
885 private void emitAnyxml(final AnyXmlSchemaNode child) {
886 writer.startAnyxmlNode(child.getQName());
888 emitWhen(child.getConstraints().getWhenCondition());
889 // FIXME: BUG-2444: *(ifFeatureNode )
890 emitMustNodes(child.getConstraints().getMustConstraints());
891 emitConfigNode(child.isConfiguration());
892 emitMandatoryNode(child.getConstraints().isMandatory());
893 emitDocumentedNode(child);
894 emitUnknownStatementNodes(child.getUnknownSchemaNodes());
899 private void emitUsesNode(final UsesNode usesNode) {
900 if (emitUses && !usesNode.isAddedByUses() && !usesNode.isAugmenting()) {
901 writer.startUsesNode(usesNode.getGroupingPath().getLastComponent());
906 * statusNode // Optional F
907 * : descriptionNode // Optional
908 * referenceNode // Optional
910 for (final Entry<SchemaPath, SchemaNode> refine : usesNode.getRefines().entrySet()) {
913 for (final AugmentationSchema aug : usesNode.getAugmentations()) {
914 emitUsesAugmentNode(aug);
920 private void emitRefine(final Entry<SchemaPath, SchemaNode> refine) {
921 final SchemaPath path = refine.getKey();
922 final SchemaNode value = refine.getValue();
923 writer.startRefineNode(path);
925 if (value instanceof LeafSchemaNode) {
926 emitRefineLeafNodes((LeafSchemaNode) value);
927 } else if (value instanceof LeafListSchemaNode) {
928 emitRefineLeafListNodes((LeafListSchemaNode) value);
929 } else if (value instanceof ListSchemaNode) {
930 emitRefineListNodes((ListSchemaNode) value);
931 } else if (value instanceof ChoiceSchemaNode) {
932 emitRefineChoiceNodes((ChoiceSchemaNode) value);
933 } else if (value instanceof ChoiceCaseNode) {
934 emitRefineCaseNodes((ChoiceCaseNode) value);
935 } else if (value instanceof ContainerSchemaNode) {
936 emitRefineContainerNodes((ContainerSchemaNode) value);
937 } else if (value instanceof AnyXmlSchemaNode) {
938 emitRefineAnyxmlNodes((AnyXmlSchemaNode) value);
944 private static <T extends SchemaNode> T getOriginalChecked(final T value) {
945 final Optional<SchemaNode> original = SchemaNodeUtils.getOriginalIfPossible(value);
946 Preconditions.checkArgument(original.isPresent(), "Original unmodified version of node is not present.");
947 @SuppressWarnings("unchecked")
948 final T ret = (T) original.get();
952 private void emitDocumentedNodeRefine(final DocumentedNode original, final DocumentedNode value) {
953 if (Objects.deepEquals(original.getDescription(), value.getDescription())) {
954 emitDescriptionNode(value.getDescription());
956 if (Objects.deepEquals(original.getReference(), value.getReference())) {
957 emitReferenceNode(value.getReference());
961 private void emitRefineContainerNodes(final ContainerSchemaNode value) {
962 final ContainerSchemaNode original = getOriginalChecked(value);
964 // emitMustNodes(child.getConstraints().getMustConstraints());
965 if (Objects.deepEquals(original.isPresenceContainer(), value.isPresenceContainer())) {
966 emitPresenceNode(value.isPresenceContainer());
968 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
969 emitConfigNode(value.isConfiguration());
971 emitDocumentedNodeRefine(original, value);
975 private void emitRefineLeafNodes(final LeafSchemaNode value) {
976 final LeafSchemaNode original = getOriginalChecked(value);
978 // emitMustNodes(child.getConstraints().getMustConstraints());
979 if (Objects.deepEquals(original.getDefault(), value.getDefault())) {
980 emitDefaultNode(value.getDefault());
982 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
983 emitConfigNode(value.isConfiguration());
985 emitDocumentedNodeRefine(original, value);
986 if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
987 emitMandatoryNode(value.getConstraints().isMandatory());
992 private void emitRefineLeafListNodes(final LeafListSchemaNode value) {
993 final LeafListSchemaNode original = getOriginalChecked(value);
995 // emitMustNodes(child.getConstraints().getMustConstraints());
996 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
997 emitConfigNode(value.isConfiguration());
999 if (Objects.deepEquals(original.getConstraints().getMinElements(), value.getConstraints().getMinElements())) {
1000 emitMinElementsNode(value.getConstraints().getMinElements());
1002 if (Objects.deepEquals(original.getConstraints().getMaxElements(), value.getConstraints().getMaxElements())) {
1003 emitMaxElementsNode(value.getConstraints().getMaxElements());
1005 emitDocumentedNodeRefine(original, value);
1009 private void emitRefineListNodes(final ListSchemaNode value) {
1010 final ListSchemaNode original = getOriginalChecked(value);
1012 // emitMustNodes(child.getConstraints().getMustConstraints());
1013 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
1014 emitConfigNode(value.isConfiguration());
1016 if (Objects.deepEquals(original.getConstraints().getMinElements(), value.getConstraints().getMinElements())) {
1017 emitMinElementsNode(value.getConstraints().getMinElements());
1019 if (Objects.deepEquals(original.getConstraints().getMaxElements(), value.getConstraints().getMaxElements())) {
1020 emitMaxElementsNode(value.getConstraints().getMaxElements());
1022 emitDocumentedNodeRefine(original, value);
1026 private void emitRefineChoiceNodes(final ChoiceSchemaNode value) {
1027 final ChoiceSchemaNode original = getOriginalChecked(value);
1029 // FIXME: BUG-2444: defaultNode //FIXME: BUG-2444: Optional
1030 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
1031 emitConfigNode(value.isConfiguration());
1033 if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
1034 emitMandatoryNode(value.getConstraints().isMandatory());
1036 emitDocumentedNodeRefine(original, value);
1040 private void emitRefineCaseNodes(final ChoiceCaseNode value) {
1041 final ChoiceCaseNode original = getOriginalChecked(value);
1042 emitDocumentedNodeRefine(original, value);
1046 private void emitRefineAnyxmlNodes(final AnyXmlSchemaNode value) {
1047 final AnyXmlSchemaNode original = getOriginalChecked(value);
1049 // FIXME: BUG-2444: emitMustNodes(child.getConstraints().getMustConstraints());
1050 if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
1051 emitConfigNode(value.isConfiguration());
1053 if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
1054 emitMandatoryNode(value.getConstraints().isMandatory());
1056 emitDocumentedNodeRefine(original, value);
1060 private void emitUsesAugmentNode(final AugmentationSchema aug) {
1062 * differs only in location in schema, otherwise currently (as of
1063 * RFC6020) it is same, so we could freely reuse path.
1068 private void emitAugment(final AugmentationSchema augmentation) {
1069 writer.startAugmentNode(augmentation.getTargetPath());
1070 // FIXME: BUG-2444: whenNode //Optional
1071 // FIXME: BUG-2444: *(ifFeatureNode )
1073 emitStatusNode(augmentation.getStatus());
1074 emitDescriptionNode(augmentation.getDescription());
1075 emitReferenceNode(augmentation.getReference());
1076 for(final UsesNode uses: augmentation.getUses()) {
1080 for (final DataSchemaNode childNode : augmentation.getChildNodes()) {
1081 if (childNode instanceof ChoiceCaseNode) {
1082 emitCaseNode((ChoiceCaseNode) childNode);
1084 emitDataSchemaNode(childNode);
1087 emitUnknownStatementNodes(augmentation.getUnknownSchemaNodes());
1091 private void emitUnknownStatementNodes(final List<UnknownSchemaNode> unknownNodes) {
1092 for (final UnknownSchemaNode unknonwnNode : unknownNodes) {
1093 if (!unknonwnNode.isAddedByAugmentation() && !unknonwnNode.isAddedByUses()) {
1094 emitUnknownStatementNode(unknonwnNode);
1099 private void emitUnknownStatementNode(final UnknownSchemaNode node) {
1100 final StatementDefinition def = getStatementChecked(node.getNodeType());
1101 if (def.getArgumentName() == null) {
1102 writer.startUnknownNode(def);
1104 writer.startUnknownNode(def, node.getNodeParameter());
1106 emitUnknownStatementNodes(node.getUnknownSchemaNodes());
1110 private StatementDefinition getStatementChecked(final QName nodeType) {
1111 final StatementDefinition ret = extensions.get(nodeType);
1112 Preconditions.checkArgument(ret != null, "Unknown extension %s used during export.",nodeType);
1116 private void emitWhen(final RevisionAwareXPath revisionAwareXPath) {
1117 if(revisionAwareXPath != null) {
1118 writer.startWhenNode(revisionAwareXPath);
1121 // FIXME: BUG-2444: descriptionNode //FIXME: BUG-2444: Optional
1122 // FIXME: BUG-2444: referenceNode //FIXME: BUG-2444: Optional
1123 // FIXME: BUG-2444: writer.endNode();)
1127 private void emitRpc(final RpcDefinition rpc) {
1128 writer.startRpcNode(rpc.getQName());
1129 // FIXME: BUG-2444: *(ifFeatureNode )
1130 emitStatusNode(rpc.getStatus());
1131 emitDescriptionNode(rpc.getDescription());
1132 emitReferenceNode(rpc.getReference());
1134 for(final TypeDefinition<?> typedef : rpc.getTypeDefinitions()) {
1135 emitTypedefNode(typedef);
1137 for(final GroupingDefinition grouping : rpc.getGroupings()) {
1138 emitGrouping(grouping);
1140 emitInput(rpc.getInput());
1141 emitOutput(rpc.getOutput());
1142 emitUnknownStatementNodes(rpc.getUnknownSchemaNodes());
1147 private void emitInput(@Nullable final ContainerSchemaNode input) {
1148 if (input != null) {
1149 writer.startInputNode();
1150 emitDataNodeContainer(input);
1151 emitUnknownStatementNodes(input.getUnknownSchemaNodes());
1157 private void emitOutput(@Nullable final ContainerSchemaNode input) {
1158 if (input != null) {
1159 writer.startOutputNode();
1160 emitDataNodeContainer(input);
1161 emitUnknownStatementNodes(input.getUnknownSchemaNodes());
1167 private void emitNotificationNode(final NotificationDefinition notification) {
1168 writer.startNotificationNode(notification.getQName());
1169 // FIXME: BUG-2444: *(ifFeatureNode )
1170 emitDocumentedNode(notification);
1171 emitDataNodeContainer(notification);
1172 emitUnknownStatementNodes(notification.getUnknownSchemaNodes());
1178 //FIXME: Probably should be moved to utils bundle.
1179 private static <T> boolean isPrefix(final Iterable<T> prefix, final Iterable<T> other) {
1180 final Iterator<T> prefixIt = prefix.iterator();
1181 final Iterator<T> otherIt = other.iterator();
1182 while(prefixIt.hasNext()) {
1183 if(!otherIt.hasNext()) {
1186 if(!Objects.deepEquals(prefixIt.next(), otherIt.next())) {
1193 private void emitDeviation(final Deviation deviation) {
1195 * FIXME: BUG-2444: Deviation is not modeled properly and we are loosing lot of
1196 * information in order to export it properly
1198 * writer.startDeviationNode(deviation.getTargetPath());
1200 * :descriptionNode //:Optional
1203 * emitReferenceNode(deviation.getReference());
1204 * :(deviateNotSupportedNode :1*(deviateAddNode :deviateReplaceNode
1205 * :deviateDeleteNode)) :writer.endNode();