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.text.SimpleDateFormat
11 import java.util.Collection
16 import java.util.StringTokenizer
17 import org.opendaylight.yangtools.yang.common.QName
18 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode
19 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
20 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
21 import org.opendaylight.yangtools.yang.model.api.ChoiceNode
22 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
23 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
24 import org.opendaylight.yangtools.yang.model.api.Deviation
25 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition
26 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition
27 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
28 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode
29 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
30 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
31 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
32 import org.opendaylight.yangtools.yang.model.api.Module
33 import org.opendaylight.yangtools.yang.model.api.ModuleImport
34 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
35 import org.opendaylight.yangtools.yang.model.api.RpcDefinition
36 import org.opendaylight.yangtools.yang.model.api.SchemaNode
37 import org.opendaylight.yangtools.yang.model.api.SchemaPath
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
46 private static var Module module = null
48 def static String generateYangSnipet(SchemaNode schemaNode) {
49 if (schemaNode == null)
53 «IF schemaNode instanceof DataSchemaNode»
54 «writeDataSchemaNode(schemaNode as DataSchemaNode)»
56 «IF schemaNode instanceof EnumTypeDefinition.EnumPair»
57 «writeEnumPair(schemaNode as EnumTypeDefinition.EnumPair)»
59 «IF schemaNode instanceof ExtensionDefinition»
60 «writeExtension(schemaNode as ExtensionDefinition)»
62 «IF schemaNode instanceof FeatureDefinition»
63 «writeFeature(schemaNode as FeatureDefinition)»
65 «IF schemaNode instanceof GroupingDefinition»
66 «writeGroupingDef(schemaNode as GroupingDefinition)»
68 «IF schemaNode instanceof IdentitySchemaNode»
69 «writeIdentity(schemaNode as IdentitySchemaNode)»
71 «IF schemaNode instanceof NotificationDefinition»
72 «writeNotification(schemaNode as NotificationDefinition)»
74 «IF schemaNode instanceof RpcDefinition»
75 «writeRPC(schemaNode as RpcDefinition)»
77 «IF schemaNode instanceof TypeDefinition<?>»
78 «writeTypeDefinition(schemaNode as TypeDefinition<?>)»
80 «IF schemaNode instanceof UnknownSchemaNode»
81 «writeUnknownSchemaNode(schemaNode as UnknownSchemaNode)»
86 def static String generateYangSnipet(Set<? extends SchemaNode> nodes) {
87 if (nodes.nullOrEmpty)
92 «IF node instanceof NotificationDefinition»
93 «writeNotification(node as NotificationDefinition)»
94 «ELSEIF node instanceof RpcDefinition»
95 «writeRPC(node as RpcDefinition)»
101 def static writeEnumPair(EnumPair pair) {
102 var boolean hasEnumPairValue = pair.value != null
104 enum «pair.name»«IF !hasEnumPairValue»;«ELSE»{
111 def static String writeModuleImports(Set<ModuleImport> moduleImports) {
112 if (moduleImports.nullOrEmpty)
116 «FOR moduleImport : moduleImports SEPARATOR "\n"»
117 «IF moduleImport != null && !moduleImport.moduleName.nullOrEmpty»
118 import «moduleImport.moduleName» { prefix "«moduleImport.prefix»"; }
124 def static formatDate(Date moduleRevision) {
125 val SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd")
126 return dateFormat.format(moduleRevision)
129 def static writeRevision(Date moduleRevision, String moduleDescription) {
130 val revisionIndent = 12
133 revision «formatDate(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) {
213 rpc «rpc.QName.localName» {
214 «IF !rpc.description.nullOrEmpty»
217 «IF !rpc.groupings.nullOrEmpty»
218 «writeGroupingDefs(rpc.groupings)»
220 «IF rpc.input != null»
221 «writeRpcInput(rpc.input)»
223 «IF rpc.output != null»
224 «writeRpcOutput(rpc.output)»
226 «IF !rpc.reference.nullOrEmpty»
230 «IF rpc.status != null»
237 def static writeRpcInput(ContainerSchemaNode input) {
243 «IF input instanceof DataSchemaNode && !input.childNodes.nullOrEmpty»
244 «writeDataSchemaNodes(input.childNodes)»
251 def static writeRpcOutput(ContainerSchemaNode output) {
257 «IF output instanceof DataSchemaNode && !output.childNodes.nullOrEmpty»
258 «writeDataSchemaNodes(output.childNodes)»
264 def static writeNotifications(Set<NotificationDefinition> notifications) {
266 «FOR notification : notifications»
267 «IF notification != null»
268 «writeNotification(notification)»
274 def static writeNotification(NotificationDefinition notification) {
276 notification «notification.QName.localName» {
277 «IF !notification.description.nullOrEmpty»
279 "«notification.description»";
281 «IF !notification.childNodes.nullOrEmpty»
282 «writeDataSchemaNodes(notification.childNodes)»
284 «IF !notification.availableAugmentations.nullOrEmpty»
285 «writeAugments(notification.availableAugmentations)»
287 «IF !notification.groupings.nullOrEmpty»
288 «writeGroupingDefs(notification.groupings)»
290 «IF !notification.uses.nullOrEmpty»
291 «writeUsesNodes(notification.uses)»
293 «IF !notification.reference.nullOrEmpty»
295 "«notification.reference»";
297 «IF notification.status != null»
298 status «notification.status»;
304 def static writeUnknownSchemaNodes(List<UnknownSchemaNode> unknownSchemaNodes) {
305 if (unknownSchemaNodes.nullOrEmpty)
309 «FOR unknownSchemaNode : unknownSchemaNodes»
310 «writeUnknownSchemaNode(unknownSchemaNode)»
315 def static writeUnknownSchemaNode(UnknownSchemaNode unknownSchemaNode) {
316 if (unknownSchemaNode == null)
320 anyxml «unknownSchemaNode.QName.localName» {
321 «IF !unknownSchemaNode.description.nullOrEmpty»
323 "«unknownSchemaNode.description»";
325 «IF !unknownSchemaNode.reference.nullOrEmpty»
327 "«unknownSchemaNode.reference»";
329 «IF unknownSchemaNode.status != null»
330 status «unknownSchemaNode.status»;
336 def static writeUsesNodes(Set<UsesNode> usesNodes) {
337 if (usesNodes == null) {
342 «FOR usesNode : usesNodes»
343 «IF usesNode != null»
344 «writeUsesNode(usesNode)»
350 def static writeUsesNode(UsesNode usesNode) {
351 val hasRefines = !usesNode.refines.empty
354 uses «usesNode.groupingPath.pathFromRoot.head.localName»«IF !hasRefines»;«ELSE» {«ENDIF»
356 «writeRefines(usesNode.refines)»
362 def static writeRefines(Map<SchemaPath, SchemaNode> refines) {
364 «FOR path : refines.keySet»
365 «val schemaNode = refines.get(path)»
366 «writeRefine(path, schemaNode)»
371 def static writeRefine(SchemaPath path, SchemaNode schemaNode) {
373 refine «path.pathFromRoot.last» {
374 «IF schemaNode instanceof DataSchemaNode»
375 «writeDataSchemaNode(schemaNode as DataSchemaNode)»
381 def static writeTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
383 «FOR typeDefinition : typeDefinitions»
384 «IF typeDefinition != null»
385 «writeTypeDefinition(typeDefinition)»
391 def static writeTypeDefinition(TypeDefinition<?> typeDefinition) {
393 type «typeDefinition.QName.localName»;
397 def static writeIdentities(Set<IdentitySchemaNode> identities) {
398 if (identities.nullOrEmpty)
401 «FOR identity : identities»
402 «writeIdentity(identity)»
407 def static writeIdentity(IdentitySchemaNode identity) {
408 if (identity == null)
411 identity «identity.QName.localName» {
412 «IF identity.baseIdentity != null»
413 base "«writeIdentityPrefix(identity.baseIdentity)»«identity.baseIdentity»";
415 «IF !identity.description.nullOrEmpty»
417 "«identity.description»";
419 «IF !identity.reference.nullOrEmpty»
421 "«identity.reference»";
423 «IF identity.status != null»
424 status «identity.status»;
430 def static writeIdentityPrefix(IdentitySchemaNode identity) {
434 if(identity.QName.prefix.nullOrEmpty || module.prefix.nullOrEmpty)
437 val identityPrefix = identity.QName.prefix
439 if(!module.prefix.equals(identity.QName.prefix))
440 return identityPrefix + ":"
444 def static writeFeatures(Set<FeatureDefinition> features) {
446 «FOR feature : features»
448 «writeFeature(feature)»
454 def static writeFeature(FeatureDefinition featureDef) {
456 feature «featureDef.QName.localName» {
457 «IF !featureDef.description.nullOrEmpty»
459 "«featureDef.description»";
461 «IF !featureDef.reference.nullOrEmpty»
463 "«featureDef.reference»";
465 «IF featureDef.status != null»
466 status «featureDef.status»;
472 def static writeExtensions(List<ExtensionDefinition> extensions) {
474 «FOR anExtension : extensions»
475 «IF anExtension != null»
476 «writeExtension(anExtension)»
482 def static writeExtension(ExtensionDefinition extensionDef) {
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) {
584 grouping «groupingDef.QName.localName» {
585 «IF !groupingDef.groupings.nullOrEmpty»
586 «writeGroupingDefs(groupingDef.groupings)»
588 «IF !groupingDef.childNodes.nullOrEmpty»
589 «writeDataSchemaNodes(groupingDef.childNodes)»
591 «IF !groupingDef.unknownSchemaNodes.nullOrEmpty»
592 «writeUnknownSchemaNodes(groupingDef.unknownSchemaNodes)»
598 def static writeContSchemaNode(ContainerSchemaNode contSchemaNode) {
600 container «contSchemaNode.getQName.localName» {
601 «IF !contSchemaNode.childNodes.nullOrEmpty»
602 «writeDataSchemaNodes(contSchemaNode.childNodes)»
604 «IF !contSchemaNode.availableAugmentations.nullOrEmpty»
605 «writeAugments(contSchemaNode.availableAugmentations)»
607 «IF !contSchemaNode.groupings.nullOrEmpty»
608 «writeGroupingDefs(contSchemaNode.groupings)»
610 «IF !contSchemaNode.uses.nullOrEmpty»
611 «writeUsesNodes(contSchemaNode.uses)»
613 «IF !contSchemaNode.unknownSchemaNodes.nullOrEmpty»
614 «writeUnknownSchemaNodes(contSchemaNode.unknownSchemaNodes)»
620 def static writeAnyXmlSchemaNode(AnyXmlSchemaNode anyXmlSchemaNode) {
622 anyxml «anyXmlSchemaNode.getQName.localName»;
626 def static writeLeafSchemaNode(LeafSchemaNode leafSchemaNode) {
628 leaf «leafSchemaNode.getQName.localName» {
629 type «leafSchemaNode.type.getQName.localName»;
634 def static writeLeafListSchemaNode(LeafListSchemaNode leafListSchemaNode) {
636 leaf-list «leafListSchemaNode.getQName.localName» {
637 type «leafListSchemaNode.type.getQName.localName»;
642 def static writeChoiceCaseNode(ChoiceCaseNode choiceCaseNode) {
644 case «choiceCaseNode.getQName.localName» {
645 «FOR childNode : choiceCaseNode.childNodes»
646 «writeDataSchemaNode(childNode)»
652 def static writeChoiceNode(ChoiceNode choiceNode) {
654 choice «choiceNode.getQName.localName» {
655 «FOR child : choiceNode.cases»
656 «writeDataSchemaNode(child)»
662 def static writeListSchemaNode(ListSchemaNode listSchemaNode) {
664 list «listSchemaNode.getQName.localName» {
665 key «FOR listKey : listSchemaNode.keyDefinition SEPARATOR " "»"«listKey.localName»"
667 «IF !listSchemaNode.childNodes.nullOrEmpty»
668 «writeDataSchemaNodes(listSchemaNode.childNodes)»
670 «IF !listSchemaNode.availableAugmentations.nullOrEmpty»
671 «writeAugments(listSchemaNode.availableAugmentations)»
673 «IF !listSchemaNode.groupings.nullOrEmpty»
674 «writeGroupingDefs(listSchemaNode.groupings)»
676 «IF !listSchemaNode.uses.nullOrEmpty»
677 «writeUsesNodes(listSchemaNode.uses)»
679 «IF !listSchemaNode.unknownSchemaNodes.nullOrEmpty»
680 «writeUnknownSchemaNodes(listSchemaNode.unknownSchemaNodes)»
686 def static CharSequence writeDataSchemaNode(DataSchemaNode child) {
688 «IF child instanceof ContainerSchemaNode»
689 «writeContSchemaNode(child as ContainerSchemaNode)»
691 «IF child instanceof AnyXmlSchemaNode»
692 «writeAnyXmlSchemaNode(child as AnyXmlSchemaNode)»
694 «IF child instanceof LeafSchemaNode»
695 «writeLeafSchemaNode(child as LeafSchemaNode)»
697 «IF child instanceof LeafListSchemaNode»
698 «writeLeafListSchemaNode(child as LeafListSchemaNode)»
700 «IF child instanceof ChoiceCaseNode»
701 «writeChoiceCaseNode(child as ChoiceCaseNode)»
703 «IF child instanceof ChoiceNode»
704 «writeChoiceNode(child as ChoiceNode)»
706 «IF child instanceof ListSchemaNode»
707 «writeListSchemaNode(child as ListSchemaNode)»
712 static def String formatSchemaPath(String moduleName, Iterable<QName> schemaPath) {
713 var currentElement = schemaPath.head
714 val StringBuilder sb = new StringBuilder()
715 sb.append(moduleName)
717 for(pathElement : schemaPath) {
718 if(!currentElement.namespace.equals(pathElement.namespace)) {
719 currentElement = pathElement
721 sb.append(pathElement)
725 sb.append(pathElement.localName)
731 static def String formatToParagraph(String text, int nextLineIndent) {
732 if (text == null || text.isEmpty())
735 var String formattedText = text;
736 val StringBuilder sb = new StringBuilder();
737 val StringBuilder lineBuilder = new StringBuilder();
738 var boolean isFirstElementOnNewLineEmptyChar = false;
739 val lineIndent = computeNextLineIndent(nextLineIndent);
741 formattedText = formattedText.replace("*/", "*/");
742 formattedText = formattedText.replace("\n", "");
743 formattedText = formattedText.replace("\t", "");
744 formattedText = formattedText.replaceAll(" +", " ");
746 val StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
748 while (tokenizer.hasMoreElements()) {
749 val String nextElement = tokenizer.nextElement().toString();
751 if (lineBuilder.length() + nextElement.length() > 80) {
752 if (lineBuilder.charAt(lineBuilder.length() - 1) == ' ') {
753 lineBuilder.setLength(0);
754 lineBuilder.append(lineBuilder.substring(0, lineBuilder.length() - 1));
756 if (lineBuilder.charAt(0) == ' ') {
757 lineBuilder.setLength(0);
758 lineBuilder.append(lineBuilder.substring(1));
761 sb.append(lineBuilder);
762 lineBuilder.setLength(0);
765 if (nextLineIndent > 0) {
766 sb.append(lineIndent)
769 if (nextElement.toString().equals(" "))
770 isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
772 if (isFirstElementOnNewLineEmptyChar) {
773 isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
775 lineBuilder.append(nextElement);
778 sb.append(lineBuilder);
781 return sb.toString();
784 def private static formatToAugmentPath(Iterable<QName> schemaPath) {
785 val StringBuilder sb = new StringBuilder();
787 for(pathElement : schemaPath) {
788 val prefix = pathElement.prefix
789 val localName = pathElement.localName
799 private static def computeNextLineIndent(int nextLineIndent) {
800 val StringBuilder sb = new StringBuilder()
802 while (i < nextLineIndent) {