2 * Copyright (c) 2014 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.sal.binding.generator.impl
10 import java.util.Collection
15 import java.util.StringTokenizer
16 import org.opendaylight.yangtools.yang.common.QName
17 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode
18 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
19 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
20 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode
21 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
22 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
23 import org.opendaylight.yangtools.yang.model.api.Deviation
24 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition
25 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition
26 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
27 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode
28 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
29 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
30 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
31 import org.opendaylight.yangtools.yang.model.api.Module
32 import org.opendaylight.yangtools.yang.model.api.ModuleImport
33 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
34 import org.opendaylight.yangtools.yang.model.api.RpcDefinition
35 import org.opendaylight.yangtools.yang.model.api.SchemaNode
36 import org.opendaylight.yangtools.yang.model.api.SchemaPath
37 import org.opendaylight.yangtools.yang.model.api.Status
38 import org.opendaylight.yangtools.yang.model.api.TypeDefinition
39 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode
40 import org.opendaylight.yangtools.yang.model.api.UsesNode
41 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition
42 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair
43 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil
44 import com.google.common.base.CharMatcher
48 // FIXME: this is not thread-safe and seems to be unused!
49 private static var Module module = null
51 private static val CharMatcher NEWLINE_OR_TAB = CharMatcher.anyOf("\n\t")
53 def static String generateYangSnipet(SchemaNode schemaNode) {
54 if (schemaNode == null)
58 «IF schemaNode instanceof DataSchemaNode»
59 «writeDataSchemaNode(schemaNode)»
61 «IF schemaNode instanceof EnumTypeDefinition.EnumPair»
62 «writeEnumPair(schemaNode)»
64 «IF schemaNode instanceof ExtensionDefinition»
65 «writeExtension(schemaNode)»
67 «IF schemaNode instanceof FeatureDefinition»
68 «writeFeature(schemaNode)»
70 «IF schemaNode instanceof GroupingDefinition»
71 «writeGroupingDef(schemaNode)»
73 «IF schemaNode instanceof IdentitySchemaNode»
74 «writeIdentity(schemaNode)»
76 «IF schemaNode instanceof NotificationDefinition»
77 «writeNotification(schemaNode)»
79 «IF schemaNode instanceof RpcDefinition»
80 «writeRPC(schemaNode)»
82 «IF schemaNode instanceof TypeDefinition<?>»
83 «writeTypeDefinition(schemaNode)»
85 «IF schemaNode instanceof UnknownSchemaNode»
86 «writeUnknownSchemaNode(schemaNode)»
91 def static String generateYangSnipet(Set<? extends SchemaNode> nodes) {
92 if (nodes.nullOrEmpty)
97 «IF node instanceof NotificationDefinition»
98 «writeNotification(node)»
99 «ELSEIF node instanceof RpcDefinition»
100 «writeRPC(node as RpcDefinition)»
106 def static writeEnumPair(EnumPair pair) {
107 var boolean hasEnumPairValue = pair.value != null
109 enum «pair.name»«IF !hasEnumPairValue»;«ELSE»{
116 def static String writeModuleImports(Set<ModuleImport> moduleImports) {
117 if (moduleImports.nullOrEmpty)
121 «FOR moduleImport : moduleImports SEPARATOR "\n"»
122 «IF moduleImport != null && !moduleImport.moduleName.nullOrEmpty»
123 import «moduleImport.moduleName» { prefix "«moduleImport.prefix»"; }
129 def static writeRevision(Date moduleRevision, String moduleDescription) {
130 val revisionIndent = 12
133 revision «SimpleDateFormatUtil.getRevisionFormat.format(moduleRevision)» {
134 description "«formatToParagraph(moduleDescription, revisionIndent)»";
139 def static String generateYangSnipet(Module module) {
142 module «module.name» {
143 yang-version «module.yangVersion»;
144 namespace "«module.QNameModule.namespace.toString»";
145 prefix "«module.prefix»";
147 «IF !module.imports.nullOrEmpty»
148 «writeModuleImports(module.imports)»
150 «IF module.revision != null»
151 «writeRevision(module.revision, module.description)»
153 «IF !module.childNodes.nullOrEmpty»
155 «writeDataSchemaNodes(module.childNodes)»
157 «IF !module.groupings.nullOrEmpty»
159 «writeGroupingDefs(module.groupings)»
161 «IF !module.augmentations.nullOrEmpty»
163 «writeAugments(module.augmentations)»
165 «IF !module.deviations.nullOrEmpty»
167 «writeDeviations(module.deviations)»
169 «IF !module.extensionSchemaNodes.nullOrEmpty»
171 «writeExtensions(module.extensionSchemaNodes)»
173 «IF !module.features.nullOrEmpty»
175 «writeFeatures(module.features)»
177 «IF !module.identities.nullOrEmpty»
179 «writeIdentities(module.identities)»
181 «IF !module.notifications.nullOrEmpty»
183 «writeNotifications(module.notifications)»
185 «IF !module.rpcs.nullOrEmpty»
187 «writeRPCs(module.rpcs)»
189 «IF !module.unknownSchemaNodes.nullOrEmpty»
191 «writeUnknownSchemaNodes(module.unknownSchemaNodes)»
193 «IF !module.uses.nullOrEmpty»
195 «writeUsesNodes(module.uses)»
201 def static writeRPCs(Set<RpcDefinition> rpcDefs) {
211 def static writeRPC(RpcDefinition rpc) {
212 var boolean isStatusDeprecated = rpc.status == Status::DEPRECATED
214 «IF isStatusDeprecated»
215 @deprecated - status DEPRECATED
217 rpc «rpc.QName.localName» {
218 «IF !rpc.description.nullOrEmpty»
221 «IF !rpc.groupings.nullOrEmpty»
222 «writeGroupingDefs(rpc.groupings)»
224 «IF rpc.input != null»
225 «writeRpcInput(rpc.input)»
227 «IF rpc.output != null»
228 «writeRpcOutput(rpc.output)»
230 «IF !rpc.reference.nullOrEmpty»
234 «IF isStatusDeprecated»
241 def static writeRpcInput(ContainerSchemaNode input) {
247 «IF !input.childNodes.nullOrEmpty»
248 «writeDataSchemaNodes(input.childNodes)»
255 def static writeRpcOutput(ContainerSchemaNode output) {
261 «IF !output.childNodes.nullOrEmpty»
262 «writeDataSchemaNodes(output.childNodes)»
268 def static writeNotifications(Set<NotificationDefinition> notifications) {
270 «FOR notification : notifications»
271 «IF notification != null»
272 «writeNotification(notification)»
278 def static writeNotification(NotificationDefinition notification) {
279 var boolean isStatusDeprecated = notification.status == Status::DEPRECATED
281 «IF isStatusDeprecated»
282 @deprecated - status DEPRECATED
284 notification «notification.QName.localName» {
285 «IF !notification.description.nullOrEmpty»
287 "«notification.description»";
289 «IF !notification.childNodes.nullOrEmpty»
290 «writeDataSchemaNodes(notification.childNodes)»
292 «IF !notification.availableAugmentations.nullOrEmpty»
293 «writeAugments(notification.availableAugmentations)»
295 «IF !notification.groupings.nullOrEmpty»
296 «writeGroupingDefs(notification.groupings)»
298 «IF !notification.uses.nullOrEmpty»
299 «writeUsesNodes(notification.uses)»
301 «IF !notification.reference.nullOrEmpty»
303 "«notification.reference»";
305 «IF isStatusDeprecated»
306 status «notification.status»;
312 def static writeUnknownSchemaNodes(List<UnknownSchemaNode> unknownSchemaNodes) {
313 if (unknownSchemaNodes.nullOrEmpty)
317 «FOR unknownSchemaNode : unknownSchemaNodes»
318 «writeUnknownSchemaNode(unknownSchemaNode)»
323 def static writeUnknownSchemaNode(UnknownSchemaNode unknownSchemaNode) {
327 def static writeUsesNodes(Set<UsesNode> usesNodes) {
328 if (usesNodes == null) {
333 «FOR usesNode : usesNodes»
334 «IF usesNode != null»
335 «writeUsesNode(usesNode)»
341 def static writeUsesNode(UsesNode usesNode) {
342 val hasRefines = !usesNode.refines.empty
345 uses «usesNode.groupingPath.pathFromRoot.head.localName»«IF !hasRefines»;«ELSE» {«ENDIF»
347 «writeRefines(usesNode.refines)»
353 def static writeRefines(Map<SchemaPath, SchemaNode> refines) {
355 «FOR path : refines.keySet»
356 «val schemaNode = refines.get(path)»
357 «writeRefine(path, schemaNode)»
362 def static writeRefine(SchemaPath path, SchemaNode schemaNode) {
364 refine «path.pathFromRoot.last» {
365 «IF schemaNode instanceof DataSchemaNode»
366 «writeDataSchemaNode(schemaNode)»
372 def static writeTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
374 «FOR typeDefinition : typeDefinitions»
375 «IF typeDefinition != null»
376 «writeTypeDefinition(typeDefinition)»
382 def static writeTypeDefinition(TypeDefinition<?> typeDefinition) {
383 var boolean isStatusDeprecated = typeDefinition.status == Status::DEPRECATED
385 «IF isStatusDeprecated»
386 @deprecated - status DEPRECATED
388 type «typeDefinition.QName.localName»«IF !isStatusDeprecated»;«ELSE» {
389 status «typeDefinition.status»;
395 def static writeIdentities(Set<IdentitySchemaNode> identities) {
396 if (identities.nullOrEmpty)
399 «FOR identity : identities»
400 «writeIdentity(identity)»
405 def static writeIdentity(IdentitySchemaNode identity) {
406 if (identity == null)
409 identity «identity.QName.localName» {
410 «IF identity.baseIdentity != null»
411 base "(«writeIdentityNs(identity.baseIdentity)»)«identity.baseIdentity»";
413 «IF !identity.description.nullOrEmpty»
415 "«identity.description»";
417 «IF !identity.reference.nullOrEmpty»
419 "«identity.reference»";
421 «IF identity.status != null»
422 status «identity.status»;
428 def static writeIdentityNs(IdentitySchemaNode identity) {
432 val identityNs = identity.QName.namespace
434 if(!module.namespace.equals(identityNs))
435 return identityNs + ":"
439 def static writeFeatures(Set<FeatureDefinition> features) {
441 «FOR feature : features»
443 «writeFeature(feature)»
449 def static writeFeature(FeatureDefinition featureDef) {
451 feature «featureDef.QName.localName» {
452 «IF !featureDef.description.nullOrEmpty»
454 "«featureDef.description»";
456 «IF !featureDef.reference.nullOrEmpty»
458 "«featureDef.reference»";
460 «IF featureDef.status != null»
461 status «featureDef.status»;
467 def static writeExtensions(List<ExtensionDefinition> extensions) {
469 «FOR anExtension : extensions»
470 «IF anExtension != null»
471 «writeExtension(anExtension)»
477 def static writeExtension(ExtensionDefinition extensionDef) {
478 var boolean isStatusDeprecated = extensionDef.status == Status::DEPRECATED
481 «IF isStatusDeprecated»
482 @deprecated - status DEPRECATED
484 extension «extensionDef.QName.localName» {
485 «IF !extensionDef.description.nullOrEmpty»
487 "«extensionDef.description»";
489 «IF !extensionDef.argument.nullOrEmpty»
490 argument "«extensionDef.argument»";
492 «IF !extensionDef.reference.nullOrEmpty»
494 "«extensionDef.reference»";
496 «IF extensionDef.status != null»
497 status «extensionDef.status»;
503 def static writeDeviations(Set<Deviation> deviations) {
505 «FOR deviation : deviations»
506 «IF deviation != null»
507 «writeDeviation(deviation)»
513 def static writeDeviation(Deviation deviation) {
515 deviation «deviation.targetPath» {
516 «IF !deviation.reference.nullOrEmpty»
518 "«deviation.reference»";
520 «IF deviation.deviate != null && !deviation.deviate.name.nullOrEmpty»
521 deviation «deviation.deviate.name»;
527 def static writeAugments(Set<AugmentationSchema> augments) {
529 «FOR augment : augments»
531 «writeAugment(augment)»
537 def static writeDataSchemaNodes(Collection<DataSchemaNode> dataSchemaNodes) {
539 «FOR schemaNode : dataSchemaNodes»
540 «writeDataSchemaNode(schemaNode)»
545 def static CharSequence writeGroupingDefs(Set<GroupingDefinition> groupingDefs) {
547 «FOR groupingDef : groupingDefs»
548 «IF groupingDef != null»
549 «writeGroupingDef(groupingDef)»
555 def static writeAugment(AugmentationSchema augment) {
557 augment «formatToAugmentPath(augment.targetPath.pathFromRoot)» {
558 «IF augment.whenCondition != null && !augment.whenCondition.toString.nullOrEmpty»
559 when "«augment.whenCondition.toString»";
561 «IF !augment.description.nullOrEmpty»
563 "«augment.description»";
565 «IF !augment.reference.nullOrEmpty»
567 "«augment.reference»";
569 «IF augment.status != null»
570 status «augment.status»;
572 «IF !augment.childNodes.nullOrEmpty»
573 «writeDataSchemaNodes(augment.childNodes)»
575 «IF !augment.uses.nullOrEmpty»
576 «writeUsesNodes(augment.uses)»
582 def static writeGroupingDef(GroupingDefinition groupingDef) {
583 var boolean isStatusDeprecated = groupingDef.status == Status::DEPRECATED
585 «IF isStatusDeprecated»
586 @deprecated - status DEPRECATED
588 grouping «groupingDef.QName.localName» {
589 «IF !groupingDef.groupings.nullOrEmpty»
590 «writeGroupingDefs(groupingDef.groupings)»
592 «IF !groupingDef.childNodes.nullOrEmpty»
593 «writeDataSchemaNodes(groupingDef.childNodes)»
595 «IF isStatusDeprecated»
596 status «groupingDef.status»;
598 «IF !groupingDef.unknownSchemaNodes.nullOrEmpty»
599 «writeUnknownSchemaNodes(groupingDef.unknownSchemaNodes)»
605 def static writeContSchemaNode(ContainerSchemaNode contSchemaNode) {
606 var boolean isStatusDeprecated = contSchemaNode.status == Status::DEPRECATED
608 «IF isStatusDeprecated»
609 @deprecated - status DEPRECATED
611 container «contSchemaNode.getQName.localName» {
612 «IF !contSchemaNode.childNodes.nullOrEmpty»
613 «writeDataSchemaNodes(contSchemaNode.childNodes)»
615 «IF !contSchemaNode.availableAugmentations.nullOrEmpty»
616 «writeAugments(contSchemaNode.availableAugmentations)»
618 «IF !contSchemaNode.groupings.nullOrEmpty»
619 «writeGroupingDefs(contSchemaNode.groupings)»
621 «IF !contSchemaNode.uses.nullOrEmpty»
622 «writeUsesNodes(contSchemaNode.uses)»
624 «IF isStatusDeprecated»
625 status «contSchemaNode.status»;
627 «IF !contSchemaNode.unknownSchemaNodes.nullOrEmpty»
628 «writeUnknownSchemaNodes(contSchemaNode.unknownSchemaNodes)»
634 def static writeAnyXmlSchemaNode(AnyXmlSchemaNode anyXmlSchemaNode) {
635 var boolean isStatusDeprecated = anyXmlSchemaNode.status == Status::DEPRECATED
637 «IF isStatusDeprecated»
638 @deprecated - status DEPRECATED
640 anyxml «anyXmlSchemaNode.getQName.localName»«IF !isStatusDeprecated»;«ELSE» {
641 status «anyXmlSchemaNode.status»;
647 def static writeLeafSchemaNode(LeafSchemaNode leafSchemaNode) {
648 var boolean isStatusDeprecated = leafSchemaNode.status == Status::DEPRECATED
650 «IF isStatusDeprecated»
651 @deprecated - status DEPRECATED
653 leaf «leafSchemaNode.getQName.localName» {
654 type «leafSchemaNode.type.getQName.localName»;
655 «IF isStatusDeprecated»
656 status «leafSchemaNode.status»;
662 def static writeLeafListSchemaNode(LeafListSchemaNode leafListSchemaNode) {
663 var boolean isStatusDeprecated = leafListSchemaNode.status == Status::DEPRECATED
665 «IF isStatusDeprecated»
666 @deprecated - status DEPRECATED
668 leaf-list «leafListSchemaNode.getQName.localName» {
669 type «leafListSchemaNode.type.getQName.localName»;
670 «IF isStatusDeprecated»
671 status «leafListSchemaNode.status»;
677 def static writeChoiceCaseNode(ChoiceCaseNode choiceCaseNode) {
678 var boolean isStatusDeprecated = choiceCaseNode.status == Status::DEPRECATED
680 «IF isStatusDeprecated»
681 @deprecated - status DEPRECATED
683 case «choiceCaseNode.getQName.localName» {
684 «FOR childNode : choiceCaseNode.childNodes»
685 «writeDataSchemaNode(childNode)»
687 «IF isStatusDeprecated»
688 status «choiceCaseNode.status»;
694 def static writeChoiceNode(ChoiceSchemaNode choiceNode) {
695 var boolean isStatusDeprecated = choiceNode.status == Status::DEPRECATED
697 «IF isStatusDeprecated»
698 @deprecated - status DEPRECATED
700 choice «choiceNode.getQName.localName» {
701 «FOR child : choiceNode.cases»
702 «writeDataSchemaNode(child)»
704 «IF isStatusDeprecated»
705 status «choiceNode.status»;
711 def static writeListSchemaNode(ListSchemaNode listSchemaNode) {
712 var boolean isStatusDeprecated = listSchemaNode.status == Status::DEPRECATED
715 «IF isStatusDeprecated»
716 @deprecated - status DEPRECATED
718 list «listSchemaNode.getQName.localName» {
719 key «FOR listKey : listSchemaNode.keyDefinition SEPARATOR " "»"«listKey.localName»"
721 «IF !listSchemaNode.childNodes.nullOrEmpty»
722 «writeDataSchemaNodes(listSchemaNode.childNodes)»
724 «IF !listSchemaNode.availableAugmentations.nullOrEmpty»
725 «writeAugments(listSchemaNode.availableAugmentations)»
727 «IF !listSchemaNode.groupings.nullOrEmpty»
728 «writeGroupingDefs(listSchemaNode.groupings)»
730 «IF !listSchemaNode.uses.nullOrEmpty»
731 «writeUsesNodes(listSchemaNode.uses)»
733 «IF isStatusDeprecated»
734 status «listSchemaNode.status»;
736 «IF !listSchemaNode.unknownSchemaNodes.nullOrEmpty»
737 «writeUnknownSchemaNodes(listSchemaNode.unknownSchemaNodes)»
743 def static CharSequence writeDataSchemaNode(DataSchemaNode child) {
745 «IF child instanceof ContainerSchemaNode»
746 «writeContSchemaNode(child)»
748 «IF child instanceof AnyXmlSchemaNode»
749 «writeAnyXmlSchemaNode(child)»
751 «IF child instanceof LeafSchemaNode»
752 «writeLeafSchemaNode(child)»
754 «IF child instanceof LeafListSchemaNode»
755 «writeLeafListSchemaNode(child)»
757 «IF child instanceof ChoiceCaseNode»
758 «writeChoiceCaseNode(child)»
760 «IF child instanceof ChoiceSchemaNode»
761 «writeChoiceNode(child)»
763 «IF child instanceof ListSchemaNode»
764 «writeListSchemaNode(child)»
769 static def String formatSchemaPath(String moduleName, Iterable<QName> schemaPath) {
770 var currentElement = schemaPath.head
771 val StringBuilder sb = new StringBuilder()
772 sb.append(moduleName)
774 for(pathElement : schemaPath) {
775 if(!currentElement.namespace.equals(pathElement.namespace)) {
776 currentElement = pathElement
778 sb.append(pathElement)
782 sb.append(pathElement.localName)
788 static def String formatToParagraph(String text, int nextLineIndent) {
789 if (text == null || text.isEmpty())
792 var String formattedText = text;
793 val StringBuilder sb = new StringBuilder();
794 val StringBuilder lineBuilder = new StringBuilder();
795 var boolean isFirstElementOnNewLineEmptyChar = false;
796 val lineIndent = computeNextLineIndent(nextLineIndent);
798 formattedText = NEWLINE_OR_TAB.removeFrom(formattedText);
799 formattedText = formattedText.replaceAll(" +", " ");
801 val StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
803 while (tokenizer.hasMoreElements()) {
804 val String nextElement = tokenizer.nextElement().toString();
806 if (lineBuilder.length() + nextElement.length() > 80) {
807 if (lineBuilder.charAt(lineBuilder.length() - 1) == ' ') {
808 lineBuilder.setLength(0);
809 lineBuilder.append(lineBuilder.substring(0, lineBuilder.length() - 1));
811 if (lineBuilder.charAt(0) == ' ') {
812 lineBuilder.setLength(0);
813 lineBuilder.append(lineBuilder.substring(1));
816 sb.append(lineBuilder);
817 lineBuilder.setLength(0);
820 if (nextLineIndent > 0) {
821 sb.append(lineIndent)
824 if (nextElement.toString().equals(" "))
825 isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
827 if (isFirstElementOnNewLineEmptyChar) {
828 isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
830 lineBuilder.append(nextElement);
833 sb.append(lineBuilder);
836 return sb.toString();
839 def private static formatToAugmentPath(Iterable<QName> schemaPath) {
840 val StringBuilder sb = new StringBuilder();
842 for(pathElement : schemaPath) {
843 val ns = pathElement.namespace
844 val localName = pathElement.localName
854 private static def computeNextLineIndent(int nextLineIndent) {
855 val StringBuilder sb = new StringBuilder()
857 while (i < nextLineIndent) {