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.ChoiceNode;
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.ExtendedType;
76 import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
80 class SchemaContextEmitter {
82 private final Rfc6020ModuleWriter writer;
83 private final boolean emitInstantiated;
84 private final boolean emitUses;
85 private final Map<QName, StatementDefinition> extensions;
87 SchemaContextEmitter(final Rfc6020ModuleWriter writer, final Map<QName, StatementDefinition> extensions) {
88 this(writer, extensions,false, true);
91 SchemaContextEmitter(final Rfc6020ModuleWriter writer, final Map<QName, StatementDefinition> extensions, final boolean emitInstantiated, final boolean emitUses) {
92 this.writer = Preconditions.checkNotNull(writer);
93 this.emitInstantiated = emitInstantiated;
94 this.emitUses = emitUses;
95 this.extensions = Preconditions.checkNotNull(extensions);
98 static void writeToStatementWriter(final Module module, final SchemaContext ctx, final StatementTextWriter statementWriter) {
99 final Rfc6020ModuleWriter yangSchemaWriter = SchemaToStatementWriterAdaptor.from(statementWriter);
100 final Map<QName, StatementDefinition> extensions = ExtensionStatement.mapFrom(ctx.getExtensions());
101 new SchemaContextEmitter(yangSchemaWriter,extensions).emitModule(module);
104 void emitModule(final Module input) {
105 writer.startModuleNode(input.getName());
106 emitModuleHeader(input);
107 emitLinkageNodes(input);
108 emitMetaNodes(input);
109 emitRevisionNodes(input);
110 emitBodyNodes(input);
114 private void emitModuleHeader(final Module input) {
115 emitYangVersionNode(input.getYangVersion());
116 emitNamespace(input.getNamespace());
117 emitPrefixNode(input.getPrefix());
120 @SuppressWarnings("unused")
121 private void emitSubmodule(final String input) {
123 * FIXME: BUG-2444: Implement submodule export
125 * submoduleHeaderNodes linkageNodes metaNodes revisionNodes bodyNodes
130 @SuppressWarnings("unused")
131 private void emitSubmoduleHeaderNodes(final Module input) {
133 * FIXME: BUG-2444: Implement submodule headers properly
135 * :yangVersionNode //Optional
141 private void emitMetaNodes(final Module input) {
143 emitOrganizationNode(input.getOrganization()); // FIXME: BUG-2444: Optional
144 emitContact(input.getContact()); // FIXME: BUG-2444: Optional
145 emitDescriptionNode(input.getDescription());
146 emitReferenceNode(input.getReference());
149 private void emitLinkageNodes(final Module input) {
150 for (final ModuleImport importNode : input.getImports()) {
151 emitImport(importNode);
154 * FIXME: BUG-2444: Emit include statements
158 private void emitRevisionNodes(final Module input) {
160 * FIXME: BUG-2444: emit revisions properly, when parsed model will provide enough
163 emitRevision(input.getRevision());
167 private void emitBodyNodes(final Module input) {
169 for (final ExtensionDefinition extension : input.getExtensionSchemaNodes()) {
170 emitExtension(extension);
172 for (final FeatureDefinition definition : input.getFeatures()) {
173 emitFeature(definition);
175 for (final IdentitySchemaNode identity : input.getIdentities()) {
176 emitIdentity(identity);
179 emitDataNodeContainer(input);
181 for (final AugmentationSchema augmentation : input.getAugmentations()) {
182 emitAugment(augmentation);
184 for (final RpcDefinition rpc : input.getRpcs()) {
187 for (final NotificationDefinition notification : input.getNotifications()) {
188 emitNotificationNode(notification);
190 for (final Deviation deviation : input.getDeviations()) {
191 emitDeviation(deviation);
196 private void emitDataNodeContainer(final DataNodeContainer input) {
197 for (final TypeDefinition<?> typedef : input.getTypeDefinitions()) {
198 emitTypedefNode(typedef);
200 for (final GroupingDefinition grouping : input.getGroupings()) {
201 emitGrouping(grouping);
203 for (final DataSchemaNode child : input.getChildNodes()) {
204 emitDataSchemaNode(child);
206 for (final UsesNode usesNode : input.getUses()) {
207 emitUsesNode(usesNode);
211 private void emitDataSchemaNode(final DataSchemaNode child) {
212 if (!emitInstantiated && (child.isAddedByUses() || child.isAugmenting())) {
213 // We skip instantiated nodes.
217 if (child instanceof ContainerSchemaNode) {
218 emitContainer((ContainerSchemaNode) child);
219 } else if (child instanceof LeafSchemaNode) {
220 emitLeaf((LeafSchemaNode) child);
221 } else if (child instanceof LeafListSchemaNode) {
222 emitLeafList((LeafListSchemaNode) child);
223 } else if (child instanceof ListSchemaNode) {
224 emitList((ListSchemaNode) child);
225 } else if (child instanceof ChoiceNode) {
226 emitChoice((ChoiceNode) child);
227 } else if (child instanceof AnyXmlSchemaNode) {
228 emitAnyxml((AnyXmlSchemaNode) child);
230 throw new UnsupportedOperationException("Not supported DataSchemaNode type " + child.getClass());
234 private void emitYangVersionNode(final String input) {
235 writer.startYangVersionNode(input);
239 private void emitImport(final ModuleImport importNode) {
240 writer.startImportNode(importNode.getModuleName());
241 emitPrefixNode(importNode.getPrefix());
242 emitRevisionDateNode(importNode.getRevision());
246 @SuppressWarnings("unused")
247 private void emitInclude(final String input) {
249 * FIXME: BUG-2444: Implement proper export of include statements
250 * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
253 * :revisionDateNode :writer.endNode();)
257 private void emitNamespace(final URI uri) {
258 writer.startNamespaceNode(uri);
263 private void emitPrefixNode(final String input) {
264 writer.startPrefixNode(input);
269 @SuppressWarnings("unused")
270 private void emitBelongsTo(final String input) {
272 * FIXME: BUG-2444: Implement proper export of belongs-to statements
273 * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
276 * :writer.startBelongsToNode(IdentifierHelper.getIdentifier(String
287 private void emitOrganizationNode(final String input) {
288 writer.startOrganizationNode(input);
293 private void emitContact(final String input) {
294 writer.startContactNode(input);
299 private void emitDescriptionNode(@Nullable final String input) {
300 if (!Strings.isNullOrEmpty(input)) {
301 writer.startDescriptionNode(input);
306 private void emitReferenceNode(@Nullable final String input) {
307 if (!Strings.isNullOrEmpty(input)) {
308 writer.startReferenceNode(input);
313 private void emitUnitsNode(@Nullable final String input) {
314 if (!Strings.isNullOrEmpty(input)) {
315 writer.startUnitsNode(input);
320 private void emitRevision(final Date date) {
321 writer.startRevisionNode(date);
324 // FIXME: BUG-2444: FIXME: BUG-2444: BUG-2417: descriptionNode //FIXME: BUG-2444: Optional
325 // FIXME: BUG-2444: FIXME: BUG-2444: BUG-2417: referenceNode //FIXME: BUG-2444: Optional
330 private void emitRevisionDateNode(@Nullable final Date date) {
332 writer.startRevisionDateNode(date);
337 private void emitExtension(final ExtensionDefinition extension) {
338 writer.startExtensionNode(extension.getQName());
339 emitArgument(extension.getArgument(),extension.isYinElement());
340 emitStatusNode(extension.getStatus());
341 emitDescriptionNode(extension.getDescription());
342 emitReferenceNode(extension.getReference());
343 emitUnknownStatementNodes(extension.getUnknownSchemaNodes());
348 private void emitArgument(final @Nullable String input, final boolean yinElement) {
350 writer.startArgumentNode(input);
351 emitYinElement(yinElement);
357 private void emitYinElement(final boolean yinElement) {
358 writer.startYinElementNode(yinElement);
363 private void emitIdentity(final IdentitySchemaNode identity) {
364 writer.startIdentityNode(identity.getQName());
365 if (identity.getBaseIdentity() != null) {
366 emitBase(identity.getBaseIdentity().getQName());
368 emitStatusNode(identity.getStatus());
369 emitDescriptionNode(identity.getDescription());
370 emitReferenceNode(identity.getReference());
375 private void emitBase(final QName qName) {
376 writer.startBaseNode(qName);
381 private void emitFeature(final FeatureDefinition definition) {
382 writer.startFeatureNode(definition.getQName());
384 // FIXME: BUG-2444: FIXME: BUG-2444: Expose ifFeature *(ifFeatureNode )
385 emitStatusNode(definition.getStatus());
386 emitDescriptionNode(definition.getDescription());
387 emitReferenceNode(definition.getReference());
392 @SuppressWarnings("unused")
393 private void emitIfFeature(final String input) {
395 * FIXME: BUG-2444: Implement proper export of include statements
396 * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
401 private void emitTypedefNode(final TypeDefinition<?> typedef) {
402 writer.startTypedefNode(typedef.getQName());
403 // Differentiate between derived type and existing type
405 emitTypeNodeDerived(typedef);
406 emitUnitsNode(typedef.getUnits());
407 emitDefaultNode(typedef.getDefaultValue());
408 emitStatusNode(typedef.getStatus());
409 emitDescriptionNode(typedef.getDescription());
410 emitReferenceNode(typedef.getReference());
411 emitUnknownStatementNodes(typedef.getUnknownSchemaNodes());
416 private void emitTypeNode(final SchemaPath parentPath, final TypeDefinition<?> subtype) {
417 final SchemaPath path = subtype.getPath();
418 if (isPrefix(parentPath.getPathFromRoot(), path.getPathFromRoot())) {
419 emitTypeNodeDerived(subtype);
421 emitTypeNodeReferenced(subtype);
425 private void emitTypeNodeReferenced(final TypeDefinition<?> typeDefinition) {
426 writer.startTypeNode(typeDefinition.getQName());
431 private void emitTypeNodeDerived(final TypeDefinition<?> typeDefinition) {
432 final TypeDefinition<?> baseType;
433 if (typeDefinition.getBaseType() != null) {
434 baseType = typeDefinition.getBaseType();
436 baseType = typeDefinition;
438 writer.startTypeNode(baseType.getQName());
439 emitTypeBodyNodes(typeDefinition);
444 private void emitTypeBodyNodes(final TypeDefinition<?> typeDef) {
445 if (typeDef instanceof ExtendedType) {
446 emitTypeBodyNodes(NormalizatedDerivedType.from((ExtendedType) typeDef));
447 } else 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());
538 private 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 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 ChoiceNode 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 ChoiceNode) {
932 emitRefineChoiceNodes((ChoiceNode) 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 <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 ChoiceNode value) {
1027 final ChoiceNode 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 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(@Nullable final ContainerSchemaNode input) {
1146 if (input != null) {
1147 writer.startInputNode();
1148 emitDataNodeContainer(input);
1149 emitUnknownStatementNodes(input.getUnknownSchemaNodes());
1155 private void emitOutput(@Nullable final ContainerSchemaNode input) {
1156 if (input != null) {
1157 writer.startOutputNode();
1158 emitDataNodeContainer(input);
1159 emitUnknownStatementNodes(input.getUnknownSchemaNodes());
1165 private void emitNotificationNode(final NotificationDefinition notification) {
1166 writer.startNotificationNode(notification.getQName());
1167 // FIXME: BUG-2444: *(ifFeatureNode )
1168 emitDocumentedNode(notification);
1169 emitDataNodeContainer(notification);
1170 emitUnknownStatementNodes(notification.getUnknownSchemaNodes());
1176 //FIXME: Probably should be moved to utils bundle.
1177 private static <T> boolean isPrefix(final Iterable<T> prefix, final Iterable<T> other) {
1178 final Iterator<T> prefixIt = prefix.iterator();
1179 final Iterator<T> otherIt = other.iterator();
1180 while(prefixIt.hasNext()) {
1181 if(!otherIt.hasNext()) {
1184 if(!Objects.deepEquals(prefixIt.next(), otherIt.next())) {
1191 private void emitDeviation(final Deviation deviation) {
1193 * FIXME: BUG-2444: Deviation is not modeled properly and we are loosing lot of
1194 * information in order to export it properly
1196 * writer.startDeviationNode(deviation.getTargetPath());
1198 * :descriptionNode //:Optional
1201 * emitReferenceNode(deviation.getReference());
1202 * :(deviateNotSupportedNode :1*(deviateAddNode :deviateReplaceNode
1203 * :deviateDeleteNode)) :writer.endNode();