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.ChoiceNode
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.TypeDefinition
38 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode
39 import org.opendaylight.yangtools.yang.model.api.UsesNode
40 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition
41 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair
42 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil
46 // FIXME: this is not thread-safe and seems to be unused!
47 private static var Module module = null
49 def static String generateYangSnipet(SchemaNode schemaNode) {
50 if (schemaNode == null)
54 «IF schemaNode instanceof DataSchemaNode»
55 «writeDataSchemaNode(schemaNode as DataSchemaNode)»
57 «IF schemaNode instanceof EnumTypeDefinition.EnumPair»
58 «writeEnumPair(schemaNode as EnumTypeDefinition.EnumPair)»
60 «IF schemaNode instanceof ExtensionDefinition»
61 «writeExtension(schemaNode as ExtensionDefinition)»
63 «IF schemaNode instanceof FeatureDefinition»
64 «writeFeature(schemaNode as FeatureDefinition)»
66 «IF schemaNode instanceof GroupingDefinition»
67 «writeGroupingDef(schemaNode as GroupingDefinition)»
69 «IF schemaNode instanceof IdentitySchemaNode»
70 «writeIdentity(schemaNode as IdentitySchemaNode)»
72 «IF schemaNode instanceof NotificationDefinition»
73 «writeNotification(schemaNode as NotificationDefinition)»
75 «IF schemaNode instanceof RpcDefinition»
76 «writeRPC(schemaNode as RpcDefinition)»
78 «IF schemaNode instanceof TypeDefinition<?>»
79 «writeTypeDefinition(schemaNode as TypeDefinition<?>)»
81 «IF schemaNode instanceof UnknownSchemaNode»
82 «writeUnknownSchemaNode(schemaNode as UnknownSchemaNode)»
87 def static String generateYangSnipet(Set<? extends SchemaNode> nodes) {
88 if (nodes.nullOrEmpty)
93 «IF node instanceof NotificationDefinition»
94 «writeNotification(node as NotificationDefinition)»
95 «ELSEIF node instanceof RpcDefinition»
96 «writeRPC(node as RpcDefinition)»
102 def static writeEnumPair(EnumPair pair) {
103 var boolean hasEnumPairValue = pair.value != null
105 enum «pair.name»«IF !hasEnumPairValue»;«ELSE»{
112 def static String writeModuleImports(Set<ModuleImport> moduleImports) {
113 if (moduleImports.nullOrEmpty)
117 «FOR moduleImport : moduleImports SEPARATOR "\n"»
118 «IF moduleImport != null && !moduleImport.moduleName.nullOrEmpty»
119 import «moduleImport.moduleName» { prefix "«moduleImport.prefix»"; }
125 def static writeRevision(Date moduleRevision, String moduleDescription) {
126 val revisionIndent = 12
129 revision «SimpleDateFormatUtil.getRevisionFormat.format(moduleRevision)» {
130 description "«formatToParagraph(moduleDescription, revisionIndent)»";
135 def static String generateYangSnipet(Module module) {
138 module «module.name» {
139 yang-version «module.yangVersion»;
140 namespace "«module.QNameModule.namespace.toString»";
141 prefix "«module.prefix»";
143 «IF !module.imports.nullOrEmpty»
144 «writeModuleImports(module.imports)»
146 «IF module.revision != null»
147 «writeRevision(module.revision, module.description)»
149 «IF !module.childNodes.nullOrEmpty»
151 «writeDataSchemaNodes(module.childNodes)»
153 «IF !module.groupings.nullOrEmpty»
155 «writeGroupingDefs(module.groupings)»
157 «IF !module.augmentations.nullOrEmpty»
159 «writeAugments(module.augmentations)»
161 «IF !module.deviations.nullOrEmpty»
163 «writeDeviations(module.deviations)»
165 «IF !module.extensionSchemaNodes.nullOrEmpty»
167 «writeExtensions(module.extensionSchemaNodes)»
169 «IF !module.features.nullOrEmpty»
171 «writeFeatures(module.features)»
173 «IF !module.identities.nullOrEmpty»
175 «writeIdentities(module.identities)»
177 «IF !module.notifications.nullOrEmpty»
179 «writeNotifications(module.notifications)»
181 «IF !module.rpcs.nullOrEmpty»
183 «writeRPCs(module.rpcs)»
185 «IF !module.unknownSchemaNodes.nullOrEmpty»
187 «writeUnknownSchemaNodes(module.unknownSchemaNodes)»
189 «IF !module.uses.nullOrEmpty»
191 «writeUsesNodes(module.uses)»
197 def static writeRPCs(Set<RpcDefinition> rpcDefs) {
207 def static writeRPC(RpcDefinition rpc) {
209 rpc «rpc.QName.localName» {
210 «IF !rpc.description.nullOrEmpty»
213 «IF !rpc.groupings.nullOrEmpty»
214 «writeGroupingDefs(rpc.groupings)»
216 «IF rpc.input != null»
217 «writeRpcInput(rpc.input)»
219 «IF rpc.output != null»
220 «writeRpcOutput(rpc.output)»
222 «IF !rpc.reference.nullOrEmpty»
226 «IF rpc.status != null»
233 def static writeRpcInput(ContainerSchemaNode input) {
239 «IF input instanceof DataSchemaNode && !input.childNodes.nullOrEmpty»
240 «writeDataSchemaNodes(input.childNodes)»
247 def static writeRpcOutput(ContainerSchemaNode output) {
253 «IF output instanceof DataSchemaNode && !output.childNodes.nullOrEmpty»
254 «writeDataSchemaNodes(output.childNodes)»
260 def static writeNotifications(Set<NotificationDefinition> notifications) {
262 «FOR notification : notifications»
263 «IF notification != null»
264 «writeNotification(notification)»
270 def static writeNotification(NotificationDefinition notification) {
272 notification «notification.QName.localName» {
273 «IF !notification.description.nullOrEmpty»
275 "«notification.description»";
277 «IF !notification.childNodes.nullOrEmpty»
278 «writeDataSchemaNodes(notification.childNodes)»
280 «IF !notification.availableAugmentations.nullOrEmpty»
281 «writeAugments(notification.availableAugmentations)»
283 «IF !notification.groupings.nullOrEmpty»
284 «writeGroupingDefs(notification.groupings)»
286 «IF !notification.uses.nullOrEmpty»
287 «writeUsesNodes(notification.uses)»
289 «IF !notification.reference.nullOrEmpty»
291 "«notification.reference»";
293 «IF notification.status != null»
294 status «notification.status»;
300 def static writeUnknownSchemaNodes(List<UnknownSchemaNode> unknownSchemaNodes) {
301 if (unknownSchemaNodes.nullOrEmpty)
305 «FOR unknownSchemaNode : unknownSchemaNodes»
306 «writeUnknownSchemaNode(unknownSchemaNode)»
311 def static writeUnknownSchemaNode(UnknownSchemaNode unknownSchemaNode) {
312 if (unknownSchemaNode == null)
316 anyxml «unknownSchemaNode.QName.localName» {
317 «IF !unknownSchemaNode.description.nullOrEmpty»
319 "«unknownSchemaNode.description»";
321 «IF !unknownSchemaNode.reference.nullOrEmpty»
323 "«unknownSchemaNode.reference»";
325 «IF unknownSchemaNode.status != null»
326 status «unknownSchemaNode.status»;
332 def static writeUsesNodes(Set<UsesNode> usesNodes) {
333 if (usesNodes == null) {
338 «FOR usesNode : usesNodes»
339 «IF usesNode != null»
340 «writeUsesNode(usesNode)»
346 def static writeUsesNode(UsesNode usesNode) {
347 val hasRefines = !usesNode.refines.empty
350 uses «usesNode.groupingPath.pathFromRoot.head.localName»«IF !hasRefines»;«ELSE» {«ENDIF»
352 «writeRefines(usesNode.refines)»
358 def static writeRefines(Map<SchemaPath, SchemaNode> refines) {
360 «FOR path : refines.keySet»
361 «val schemaNode = refines.get(path)»
362 «writeRefine(path, schemaNode)»
367 def static writeRefine(SchemaPath path, SchemaNode schemaNode) {
369 refine «path.pathFromRoot.last» {
370 «IF schemaNode instanceof DataSchemaNode»
371 «writeDataSchemaNode(schemaNode as DataSchemaNode)»
377 def static writeTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
379 «FOR typeDefinition : typeDefinitions»
380 «IF typeDefinition != null»
381 «writeTypeDefinition(typeDefinition)»
387 def static writeTypeDefinition(TypeDefinition<?> typeDefinition) {
389 type «typeDefinition.QName.localName»;
393 def static writeIdentities(Set<IdentitySchemaNode> identities) {
394 if (identities.nullOrEmpty)
397 «FOR identity : identities»
398 «writeIdentity(identity)»
403 def static writeIdentity(IdentitySchemaNode identity) {
404 if (identity == null)
407 identity «identity.QName.localName» {
408 «IF identity.baseIdentity != null»
409 base "(«writeIdentityNs(identity.baseIdentity)»)«identity.baseIdentity»";
411 «IF !identity.description.nullOrEmpty»
413 "«identity.description»";
415 «IF !identity.reference.nullOrEmpty»
417 "«identity.reference»";
419 «IF identity.status != null»
420 status «identity.status»;
426 def static writeIdentityNs(IdentitySchemaNode identity) {
430 val identityNs = identity.QName.namespace
432 if(!module.namespace.equals(identityNs))
433 return identityNs + ":"
437 def static writeFeatures(Set<FeatureDefinition> features) {
439 «FOR feature : features»
441 «writeFeature(feature)»
447 def static writeFeature(FeatureDefinition featureDef) {
449 feature «featureDef.QName.localName» {
450 «IF !featureDef.description.nullOrEmpty»
452 "«featureDef.description»";
454 «IF !featureDef.reference.nullOrEmpty»
456 "«featureDef.reference»";
458 «IF featureDef.status != null»
459 status «featureDef.status»;
465 def static writeExtensions(List<ExtensionDefinition> extensions) {
467 «FOR anExtension : extensions»
468 «IF anExtension != null»
469 «writeExtension(anExtension)»
475 def static writeExtension(ExtensionDefinition extensionDef) {
477 extension «extensionDef.QName.localName» {
478 «IF !extensionDef.description.nullOrEmpty»
480 "«extensionDef.description»";
482 «IF !extensionDef.argument.nullOrEmpty»
483 argument "«extensionDef.argument»";
485 «IF !extensionDef.reference.nullOrEmpty»
487 "«extensionDef.reference»";
489 «IF extensionDef.status != null»
490 status «extensionDef.status»;
496 def static writeDeviations(Set<Deviation> deviations) {
498 «FOR deviation : deviations»
499 «IF deviation != null»
500 «writeDeviation(deviation)»
506 def static writeDeviation(Deviation deviation) {
508 deviation «deviation.targetPath» {
509 «IF !deviation.reference.nullOrEmpty»
511 "«deviation.reference»";
513 «IF deviation.deviate != null && !deviation.deviate.name.nullOrEmpty»
514 deviation «deviation.deviate.name»;
520 def static writeAugments(Set<AugmentationSchema> augments) {
522 «FOR augment : augments»
524 «writeAugment(augment)»
530 def static writeDataSchemaNodes(Collection<DataSchemaNode> dataSchemaNodes) {
532 «FOR schemaNode : dataSchemaNodes»
533 «writeDataSchemaNode(schemaNode)»
538 def static CharSequence writeGroupingDefs(Set<GroupingDefinition> groupingDefs) {
540 «FOR groupingDef : groupingDefs»
541 «IF groupingDef != null»
542 «writeGroupingDef(groupingDef)»
548 def static writeAugment(AugmentationSchema augment) {
550 augment «formatToAugmentPath(augment.targetPath.pathFromRoot)» {
551 «IF augment.whenCondition != null && !augment.whenCondition.toString.nullOrEmpty»
552 when "«augment.whenCondition.toString»";
554 «IF !augment.description.nullOrEmpty»
556 "«augment.description»";
558 «IF !augment.reference.nullOrEmpty»
560 "«augment.reference»";
562 «IF augment.status != null»
563 status «augment.status»;
565 «IF !augment.childNodes.nullOrEmpty»
566 «writeDataSchemaNodes(augment.childNodes)»
568 «IF !augment.uses.nullOrEmpty»
569 «writeUsesNodes(augment.uses)»
575 def static writeGroupingDef(GroupingDefinition groupingDef) {
577 grouping «groupingDef.QName.localName» {
578 «IF !groupingDef.groupings.nullOrEmpty»
579 «writeGroupingDefs(groupingDef.groupings)»
581 «IF !groupingDef.childNodes.nullOrEmpty»
582 «writeDataSchemaNodes(groupingDef.childNodes)»
584 «IF !groupingDef.unknownSchemaNodes.nullOrEmpty»
585 «writeUnknownSchemaNodes(groupingDef.unknownSchemaNodes)»
591 def static writeContSchemaNode(ContainerSchemaNode contSchemaNode) {
593 container «contSchemaNode.getQName.localName» {
594 «IF !contSchemaNode.childNodes.nullOrEmpty»
595 «writeDataSchemaNodes(contSchemaNode.childNodes)»
597 «IF !contSchemaNode.availableAugmentations.nullOrEmpty»
598 «writeAugments(contSchemaNode.availableAugmentations)»
600 «IF !contSchemaNode.groupings.nullOrEmpty»
601 «writeGroupingDefs(contSchemaNode.groupings)»
603 «IF !contSchemaNode.uses.nullOrEmpty»
604 «writeUsesNodes(contSchemaNode.uses)»
606 «IF !contSchemaNode.unknownSchemaNodes.nullOrEmpty»
607 «writeUnknownSchemaNodes(contSchemaNode.unknownSchemaNodes)»
613 def static writeAnyXmlSchemaNode(AnyXmlSchemaNode anyXmlSchemaNode) {
615 anyxml «anyXmlSchemaNode.getQName.localName»;
619 def static writeLeafSchemaNode(LeafSchemaNode leafSchemaNode) {
621 leaf «leafSchemaNode.getQName.localName» {
622 type «leafSchemaNode.type.getQName.localName»;
627 def static writeLeafListSchemaNode(LeafListSchemaNode leafListSchemaNode) {
629 leaf-list «leafListSchemaNode.getQName.localName» {
630 type «leafListSchemaNode.type.getQName.localName»;
635 def static writeChoiceCaseNode(ChoiceCaseNode choiceCaseNode) {
637 case «choiceCaseNode.getQName.localName» {
638 «FOR childNode : choiceCaseNode.childNodes»
639 «writeDataSchemaNode(childNode)»
645 def static writeChoiceNode(ChoiceNode choiceNode) {
647 choice «choiceNode.getQName.localName» {
648 «FOR child : choiceNode.cases»
649 «writeDataSchemaNode(child)»
655 def static writeListSchemaNode(ListSchemaNode listSchemaNode) {
657 list «listSchemaNode.getQName.localName» {
658 key «FOR listKey : listSchemaNode.keyDefinition SEPARATOR " "»"«listKey.localName»"
660 «IF !listSchemaNode.childNodes.nullOrEmpty»
661 «writeDataSchemaNodes(listSchemaNode.childNodes)»
663 «IF !listSchemaNode.availableAugmentations.nullOrEmpty»
664 «writeAugments(listSchemaNode.availableAugmentations)»
666 «IF !listSchemaNode.groupings.nullOrEmpty»
667 «writeGroupingDefs(listSchemaNode.groupings)»
669 «IF !listSchemaNode.uses.nullOrEmpty»
670 «writeUsesNodes(listSchemaNode.uses)»
672 «IF !listSchemaNode.unknownSchemaNodes.nullOrEmpty»
673 «writeUnknownSchemaNodes(listSchemaNode.unknownSchemaNodes)»
679 def static CharSequence writeDataSchemaNode(DataSchemaNode child) {
681 «IF child instanceof ContainerSchemaNode»
682 «writeContSchemaNode(child as ContainerSchemaNode)»
684 «IF child instanceof AnyXmlSchemaNode»
685 «writeAnyXmlSchemaNode(child as AnyXmlSchemaNode)»
687 «IF child instanceof LeafSchemaNode»
688 «writeLeafSchemaNode(child as LeafSchemaNode)»
690 «IF child instanceof LeafListSchemaNode»
691 «writeLeafListSchemaNode(child as LeafListSchemaNode)»
693 «IF child instanceof ChoiceCaseNode»
694 «writeChoiceCaseNode(child as ChoiceCaseNode)»
696 «IF child instanceof ChoiceNode»
697 «writeChoiceNode(child as ChoiceNode)»
699 «IF child instanceof ListSchemaNode»
700 «writeListSchemaNode(child as ListSchemaNode)»
705 static def String formatSchemaPath(String moduleName, Iterable<QName> schemaPath) {
706 var currentElement = schemaPath.head
707 val StringBuilder sb = new StringBuilder()
708 sb.append(moduleName)
710 for(pathElement : schemaPath) {
711 if(!currentElement.namespace.equals(pathElement.namespace)) {
712 currentElement = pathElement
714 sb.append(pathElement)
718 sb.append(pathElement.localName)
724 static def String formatToParagraph(String text, int nextLineIndent) {
725 if (text == null || text.isEmpty())
728 var String formattedText = text;
729 val StringBuilder sb = new StringBuilder();
730 val StringBuilder lineBuilder = new StringBuilder();
731 var boolean isFirstElementOnNewLineEmptyChar = false;
732 val lineIndent = computeNextLineIndent(nextLineIndent);
734 formattedText = formattedText.replace("*/", "*/");
735 formattedText = formattedText.replace("\n", "");
736 formattedText = formattedText.replace("\t", "");
737 formattedText = formattedText.replaceAll(" +", " ");
739 val StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
741 while (tokenizer.hasMoreElements()) {
742 val String nextElement = tokenizer.nextElement().toString();
744 if (lineBuilder.length() + nextElement.length() > 80) {
745 if (lineBuilder.charAt(lineBuilder.length() - 1) == ' ') {
746 lineBuilder.setLength(0);
747 lineBuilder.append(lineBuilder.substring(0, lineBuilder.length() - 1));
749 if (lineBuilder.charAt(0) == ' ') {
750 lineBuilder.setLength(0);
751 lineBuilder.append(lineBuilder.substring(1));
754 sb.append(lineBuilder);
755 lineBuilder.setLength(0);
758 if (nextLineIndent > 0) {
759 sb.append(lineIndent)
762 if (nextElement.toString().equals(" "))
763 isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
765 if (isFirstElementOnNewLineEmptyChar) {
766 isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
768 lineBuilder.append(nextElement);
771 sb.append(lineBuilder);
774 return sb.toString();
777 def private static formatToAugmentPath(Iterable<QName> schemaPath) {
778 val StringBuilder sb = new StringBuilder();
780 for(pathElement : schemaPath) {
781 val ns = pathElement.namespace
782 val localName = pathElement.localName
793 private static def computeNextLineIndent(int nextLineIndent) {
794 val StringBuilder sb = new StringBuilder()
796 while (i < nextLineIndent) {