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 com.google.common.base.CharMatcher
11 import java.util.Collection
16 import java.util.StringTokenizer
17 import org.opendaylight.yangtools.yang.common.QName
18 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil
19 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode
20 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
21 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
22 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode
23 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
24 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
25 import org.opendaylight.yangtools.yang.model.api.Deviation
26 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition
27 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition
28 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
29 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode
30 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
31 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
32 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
33 import org.opendaylight.yangtools.yang.model.api.Module
34 import org.opendaylight.yangtools.yang.model.api.ModuleImport
35 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
36 import org.opendaylight.yangtools.yang.model.api.RpcDefinition
37 import org.opendaylight.yangtools.yang.model.api.SchemaNode
38 import org.opendaylight.yangtools.yang.model.api.SchemaPath
39 import org.opendaylight.yangtools.yang.model.api.Status
40 import org.opendaylight.yangtools.yang.model.api.TypeDefinition
41 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode
42 import org.opendaylight.yangtools.yang.model.api.UsesNode
43 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition
44 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair
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 rpc «rpc.QName.localName» {
215 «IF !rpc.description.nullOrEmpty»
218 «IF !rpc.groupings.nullOrEmpty»
219 «writeGroupingDefs(rpc.groupings)»
221 «IF rpc.input != null»
222 «writeRpcInput(rpc.input)»
224 «IF rpc.output != null»
225 «writeRpcOutput(rpc.output)»
227 «IF !rpc.reference.nullOrEmpty»
231 «IF isStatusDeprecated»
238 def static writeRpcInput(ContainerSchemaNode input) {
244 «IF !input.childNodes.nullOrEmpty»
245 «writeDataSchemaNodes(input.childNodes)»
252 def static writeRpcOutput(ContainerSchemaNode output) {
258 «IF !output.childNodes.nullOrEmpty»
259 «writeDataSchemaNodes(output.childNodes)»
265 def static writeNotifications(Set<NotificationDefinition> notifications) {
267 «FOR notification : notifications»
268 «IF notification != null»
269 «writeNotification(notification)»
275 def static writeNotification(NotificationDefinition notification) {
276 var boolean isStatusDeprecated = notification.status == Status::DEPRECATED
278 notification «notification.QName.localName» {
279 «IF !notification.description.nullOrEmpty»
281 "«notification.description»";
283 «IF !notification.childNodes.nullOrEmpty»
284 «writeDataSchemaNodes(notification.childNodes)»
286 «IF !notification.availableAugmentations.nullOrEmpty»
287 «writeAugments(notification.availableAugmentations)»
289 «IF !notification.groupings.nullOrEmpty»
290 «writeGroupingDefs(notification.groupings)»
292 «IF !notification.uses.nullOrEmpty»
293 «writeUsesNodes(notification.uses)»
295 «IF !notification.reference.nullOrEmpty»
297 "«notification.reference»";
299 «IF isStatusDeprecated»
300 status «notification.status»;
306 def static writeUnknownSchemaNodes(List<UnknownSchemaNode> unknownSchemaNodes) {
307 if (unknownSchemaNodes.nullOrEmpty)
311 «FOR unknownSchemaNode : unknownSchemaNodes»
312 «writeUnknownSchemaNode(unknownSchemaNode)»
317 def static writeUnknownSchemaNode(UnknownSchemaNode unknownSchemaNode) {
321 def static writeUsesNodes(Set<UsesNode> usesNodes) {
322 if (usesNodes == null) {
327 «FOR usesNode : usesNodes»
328 «IF usesNode != null»
329 «writeUsesNode(usesNode)»
335 def static writeUsesNode(UsesNode usesNode) {
336 val hasRefines = !usesNode.refines.empty
339 uses «usesNode.groupingPath.pathFromRoot.head.localName»«IF !hasRefines»;«ELSE» {«ENDIF»
341 «writeRefines(usesNode.refines)»
347 def static writeRefines(Map<SchemaPath, SchemaNode> refines) {
349 «FOR path : refines.keySet»
350 «val schemaNode = refines.get(path)»
351 «writeRefine(path, schemaNode)»
356 def static writeRefine(SchemaPath path, SchemaNode schemaNode) {
358 refine «path.pathFromRoot.last» {
359 «IF schemaNode instanceof DataSchemaNode»
360 «writeDataSchemaNode(schemaNode)»
366 def static writeTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
368 «FOR typeDefinition : typeDefinitions»
369 «IF typeDefinition != null»
370 «writeTypeDefinition(typeDefinition)»
376 def static writeTypeDefinition(TypeDefinition<?> typeDefinition) {
377 var boolean isStatusDeprecated = typeDefinition.status == Status::DEPRECATED
379 type «typeDefinition.QName.localName»«IF !isStatusDeprecated»;«ELSE» {
380 status «typeDefinition.status»;
386 def static writeIdentities(Set<IdentitySchemaNode> identities) {
387 if (identities.nullOrEmpty)
390 «FOR identity : identities»
391 «writeIdentity(identity)»
396 def static writeIdentity(IdentitySchemaNode identity) {
397 if (identity == null)
400 identity «identity.QName.localName» {
401 «IF identity.baseIdentity != null»
402 base "(«writeIdentityNs(identity.baseIdentity)»)«identity.baseIdentity»";
404 «IF !identity.description.nullOrEmpty»
406 "«identity.description»";
408 «IF !identity.reference.nullOrEmpty»
410 "«identity.reference»";
412 «IF identity.status != null»
413 status «identity.status»;
419 def static writeIdentityNs(IdentitySchemaNode identity) {
423 val identityNs = identity.QName.namespace
425 if(!module.namespace.equals(identityNs))
426 return identityNs + ":"
430 def static writeFeatures(Set<FeatureDefinition> features) {
432 «FOR feature : features»
434 «writeFeature(feature)»
440 def static writeFeature(FeatureDefinition featureDef) {
442 feature «featureDef.QName.localName» {
443 «IF !featureDef.description.nullOrEmpty»
445 "«featureDef.description»";
447 «IF !featureDef.reference.nullOrEmpty»
449 "«featureDef.reference»";
451 «IF featureDef.status != null»
452 status «featureDef.status»;
458 def static writeExtensions(List<ExtensionDefinition> extensions) {
460 «FOR anExtension : extensions»
461 «IF anExtension != null»
462 «writeExtension(anExtension)»
468 def static writeExtension(ExtensionDefinition extensionDef) {
470 extension «extensionDef.QName.localName» {
471 «IF !extensionDef.description.nullOrEmpty»
473 "«extensionDef.description»";
475 «IF !extensionDef.argument.nullOrEmpty»
476 argument "«extensionDef.argument»";
478 «IF !extensionDef.reference.nullOrEmpty»
480 "«extensionDef.reference»";
482 «IF extensionDef.status != null»
483 status «extensionDef.status»;
489 def static writeDeviations(Set<Deviation> deviations) {
491 «FOR deviation : deviations»
492 «IF deviation != null»
493 «writeDeviation(deviation)»
499 def static writeDeviation(Deviation deviation) {
501 deviation «deviation.targetPath» {
502 «IF !deviation.reference.nullOrEmpty»
504 "«deviation.reference»";
506 «IF deviation.deviate != null && !deviation.deviate.name.nullOrEmpty»
507 deviation «deviation.deviate.name»;
513 def static writeAugments(Set<AugmentationSchema> augments) {
515 «FOR augment : augments»
517 «writeAugment(augment)»
523 def static writeDataSchemaNodes(Collection<DataSchemaNode> dataSchemaNodes) {
525 «FOR schemaNode : dataSchemaNodes»
526 «writeDataSchemaNode(schemaNode)»
531 def static CharSequence writeGroupingDefs(Set<GroupingDefinition> groupingDefs) {
533 «FOR groupingDef : groupingDefs»
534 «IF groupingDef != null»
535 «writeGroupingDef(groupingDef)»
541 def static writeAugment(AugmentationSchema augment) {
543 augment «formatToAugmentPath(augment.targetPath.pathFromRoot)» {
544 «IF augment.whenCondition != null && !augment.whenCondition.toString.nullOrEmpty»
545 when "«augment.whenCondition.toString»";
547 «IF !augment.description.nullOrEmpty»
549 "«augment.description»";
551 «IF !augment.reference.nullOrEmpty»
553 "«augment.reference»";
555 «IF augment.status != null»
556 status «augment.status»;
558 «IF !augment.childNodes.nullOrEmpty»
559 «writeDataSchemaNodes(augment.childNodes)»
561 «IF !augment.uses.nullOrEmpty»
562 «writeUsesNodes(augment.uses)»
568 def static writeGroupingDef(GroupingDefinition groupingDef) {
569 var boolean isStatusDeprecated = groupingDef.status == Status::DEPRECATED
571 grouping «groupingDef.QName.localName» {
572 «IF !groupingDef.groupings.nullOrEmpty»
573 «writeGroupingDefs(groupingDef.groupings)»
575 «IF !groupingDef.childNodes.nullOrEmpty»
576 «writeDataSchemaNodes(groupingDef.childNodes)»
578 «IF isStatusDeprecated»
579 status «groupingDef.status»;
581 «IF !groupingDef.unknownSchemaNodes.nullOrEmpty»
582 «writeUnknownSchemaNodes(groupingDef.unknownSchemaNodes)»
588 def static writeContSchemaNode(ContainerSchemaNode contSchemaNode) {
589 var boolean isStatusDeprecated = contSchemaNode.status == Status::DEPRECATED
591 container «contSchemaNode.getQName.localName» {
592 «IF !contSchemaNode.childNodes.nullOrEmpty»
593 «writeDataSchemaNodes(contSchemaNode.childNodes)»
595 «IF !contSchemaNode.availableAugmentations.nullOrEmpty»
596 «writeAugments(contSchemaNode.availableAugmentations)»
598 «IF !contSchemaNode.groupings.nullOrEmpty»
599 «writeGroupingDefs(contSchemaNode.groupings)»
601 «IF !contSchemaNode.uses.nullOrEmpty»
602 «writeUsesNodes(contSchemaNode.uses)»
604 «IF isStatusDeprecated»
605 status «contSchemaNode.status»;
607 «IF !contSchemaNode.unknownSchemaNodes.nullOrEmpty»
608 «writeUnknownSchemaNodes(contSchemaNode.unknownSchemaNodes)»
614 def static writeAnyXmlSchemaNode(AnyXmlSchemaNode anyXmlSchemaNode) {
615 var boolean isStatusDeprecated = anyXmlSchemaNode.status == Status::DEPRECATED
617 anyxml «anyXmlSchemaNode.getQName.localName»«IF !isStatusDeprecated»;«ELSE» {
618 status «anyXmlSchemaNode.status»;
624 def static writeLeafSchemaNode(LeafSchemaNode leafSchemaNode) {
625 var boolean isStatusDeprecated = leafSchemaNode.status == Status::DEPRECATED
627 leaf «leafSchemaNode.getQName.localName» {
628 type «leafSchemaNode.type.getQName.localName»;
629 «IF isStatusDeprecated»
630 status «leafSchemaNode.status»;
636 def static writeLeafListSchemaNode(LeafListSchemaNode leafListSchemaNode) {
637 var boolean isStatusDeprecated = leafListSchemaNode.status == Status::DEPRECATED
639 leaf-list «leafListSchemaNode.getQName.localName» {
640 type «leafListSchemaNode.type.getQName.localName»;
641 «IF isStatusDeprecated»
642 status «leafListSchemaNode.status»;
648 def static writeChoiceCaseNode(ChoiceCaseNode choiceCaseNode) {
649 var boolean isStatusDeprecated = choiceCaseNode.status == Status::DEPRECATED
651 case «choiceCaseNode.getQName.localName» {
652 «FOR childNode : choiceCaseNode.childNodes»
653 «writeDataSchemaNode(childNode)»
655 «IF isStatusDeprecated»
656 status «choiceCaseNode.status»;
662 def static writeChoiceNode(ChoiceSchemaNode choiceNode) {
663 var boolean isStatusDeprecated = choiceNode.status == Status::DEPRECATED
665 choice «choiceNode.getQName.localName» {
666 «FOR child : choiceNode.cases»
667 «writeDataSchemaNode(child)»
669 «IF isStatusDeprecated»
670 status «choiceNode.status»;
676 def static writeListSchemaNode(ListSchemaNode listSchemaNode) {
677 var boolean isStatusDeprecated = listSchemaNode.status == Status::DEPRECATED
680 list «listSchemaNode.getQName.localName» {
681 key «FOR listKey : listSchemaNode.keyDefinition SEPARATOR " "»"«listKey.localName»"
683 «IF !listSchemaNode.childNodes.nullOrEmpty»
684 «writeDataSchemaNodes(listSchemaNode.childNodes)»
686 «IF !listSchemaNode.availableAugmentations.nullOrEmpty»
687 «writeAugments(listSchemaNode.availableAugmentations)»
689 «IF !listSchemaNode.groupings.nullOrEmpty»
690 «writeGroupingDefs(listSchemaNode.groupings)»
692 «IF !listSchemaNode.uses.nullOrEmpty»
693 «writeUsesNodes(listSchemaNode.uses)»
695 «IF isStatusDeprecated»
696 status «listSchemaNode.status»;
698 «IF !listSchemaNode.unknownSchemaNodes.nullOrEmpty»
699 «writeUnknownSchemaNodes(listSchemaNode.unknownSchemaNodes)»
705 def static CharSequence writeDataSchemaNode(DataSchemaNode child) {
707 «IF child instanceof ContainerSchemaNode»
708 «writeContSchemaNode(child)»
710 «IF child instanceof AnyXmlSchemaNode»
711 «writeAnyXmlSchemaNode(child)»
713 «IF child instanceof LeafSchemaNode»
714 «writeLeafSchemaNode(child)»
716 «IF child instanceof LeafListSchemaNode»
717 «writeLeafListSchemaNode(child)»
719 «IF child instanceof ChoiceCaseNode»
720 «writeChoiceCaseNode(child)»
722 «IF child instanceof ChoiceSchemaNode»
723 «writeChoiceNode(child)»
725 «IF child instanceof ListSchemaNode»
726 «writeListSchemaNode(child)»
731 static def String formatSchemaPath(String moduleName, Iterable<QName> schemaPath) {
732 var currentElement = schemaPath.head
733 val StringBuilder sb = new StringBuilder()
734 sb.append(moduleName)
736 for(pathElement : schemaPath) {
737 if(!currentElement.namespace.equals(pathElement.namespace)) {
738 currentElement = pathElement
740 sb.append(pathElement)
744 sb.append(pathElement.localName)
750 static def String formatToParagraph(String text, int nextLineIndent) {
751 if (text == null || text.isEmpty())
754 var String formattedText = text;
755 val StringBuilder sb = new StringBuilder();
756 val StringBuilder lineBuilder = new StringBuilder();
757 var boolean isFirstElementOnNewLineEmptyChar = false;
758 val lineIndent = computeNextLineIndent(nextLineIndent);
760 formattedText = NEWLINE_OR_TAB.removeFrom(formattedText);
761 formattedText = formattedText.replaceAll(" +", " ");
763 val StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
765 while (tokenizer.hasMoreElements()) {
766 val String nextElement = tokenizer.nextElement().toString();
768 if (lineBuilder.length() + nextElement.length() > 80) {
769 if (lineBuilder.charAt(lineBuilder.length() - 1) == ' ') {
770 lineBuilder.setLength(0);
771 lineBuilder.append(lineBuilder.substring(0, lineBuilder.length() - 1));
773 if (lineBuilder.charAt(0) == ' ') {
774 lineBuilder.setLength(0);
775 lineBuilder.append(lineBuilder.substring(1));
778 sb.append(lineBuilder);
779 lineBuilder.setLength(0);
782 if (nextLineIndent > 0) {
783 sb.append(lineIndent)
786 if (nextElement.toString().equals(" "))
787 isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
789 if (isFirstElementOnNewLineEmptyChar) {
790 isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
792 lineBuilder.append(nextElement);
795 sb.append(lineBuilder);
798 return sb.toString();
801 def private static formatToAugmentPath(Iterable<QName> schemaPath) {
802 val StringBuilder sb = new StringBuilder();
804 for(pathElement : schemaPath) {
805 val ns = pathElement.namespace
806 val localName = pathElement.localName
816 private static def computeNextLineIndent(int nextLineIndent) {
817 val StringBuilder sb = new StringBuilder()
819 while (i < nextLineIndent) {