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.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
43 import com.google.common.base.CharMatcher
47 // FIXME: this is not thread-safe and seems to be unused!
48 private static var Module module = null
50 private static val CharMatcher NEWLINE_OR_TAB = CharMatcher.anyOf("\n\t")
52 def static String generateYangSnipet(SchemaNode schemaNode) {
53 if (schemaNode == null)
57 «IF schemaNode instanceof DataSchemaNode»
58 «writeDataSchemaNode(schemaNode)»
60 «IF schemaNode instanceof EnumTypeDefinition.EnumPair»
61 «writeEnumPair(schemaNode)»
63 «IF schemaNode instanceof ExtensionDefinition»
64 «writeExtension(schemaNode)»
66 «IF schemaNode instanceof FeatureDefinition»
67 «writeFeature(schemaNode)»
69 «IF schemaNode instanceof GroupingDefinition»
70 «writeGroupingDef(schemaNode)»
72 «IF schemaNode instanceof IdentitySchemaNode»
73 «writeIdentity(schemaNode)»
75 «IF schemaNode instanceof NotificationDefinition»
76 «writeNotification(schemaNode)»
78 «IF schemaNode instanceof RpcDefinition»
79 «writeRPC(schemaNode)»
81 «IF schemaNode instanceof TypeDefinition<?>»
82 «writeTypeDefinition(schemaNode)»
84 «IF schemaNode instanceof UnknownSchemaNode»
85 «writeUnknownSchemaNode(schemaNode)»
90 def static String generateYangSnipet(Set<? extends SchemaNode> nodes) {
91 if (nodes.nullOrEmpty)
96 «IF node instanceof NotificationDefinition»
97 «writeNotification(node)»
98 «ELSEIF node instanceof RpcDefinition»
99 «writeRPC(node as RpcDefinition)»
105 def static writeEnumPair(EnumPair pair) {
106 var boolean hasEnumPairValue = pair.value != null
108 enum «pair.name»«IF !hasEnumPairValue»;«ELSE»{
115 def static String writeModuleImports(Set<ModuleImport> moduleImports) {
116 if (moduleImports.nullOrEmpty)
120 «FOR moduleImport : moduleImports SEPARATOR "\n"»
121 «IF moduleImport != null && !moduleImport.moduleName.nullOrEmpty»
122 import «moduleImport.moduleName» { prefix "«moduleImport.prefix»"; }
128 def static writeRevision(Date moduleRevision, String moduleDescription) {
129 val revisionIndent = 12
132 revision «SimpleDateFormatUtil.getRevisionFormat.format(moduleRevision)» {
133 description "«formatToParagraph(moduleDescription, revisionIndent)»";
138 def static String generateYangSnipet(Module module) {
141 module «module.name» {
142 yang-version «module.yangVersion»;
143 namespace "«module.QNameModule.namespace.toString»";
144 prefix "«module.prefix»";
146 «IF !module.imports.nullOrEmpty»
147 «writeModuleImports(module.imports)»
149 «IF module.revision != null»
150 «writeRevision(module.revision, module.description)»
152 «IF !module.childNodes.nullOrEmpty»
154 «writeDataSchemaNodes(module.childNodes)»
156 «IF !module.groupings.nullOrEmpty»
158 «writeGroupingDefs(module.groupings)»
160 «IF !module.augmentations.nullOrEmpty»
162 «writeAugments(module.augmentations)»
164 «IF !module.deviations.nullOrEmpty»
166 «writeDeviations(module.deviations)»
168 «IF !module.extensionSchemaNodes.nullOrEmpty»
170 «writeExtensions(module.extensionSchemaNodes)»
172 «IF !module.features.nullOrEmpty»
174 «writeFeatures(module.features)»
176 «IF !module.identities.nullOrEmpty»
178 «writeIdentities(module.identities)»
180 «IF !module.notifications.nullOrEmpty»
182 «writeNotifications(module.notifications)»
184 «IF !module.rpcs.nullOrEmpty»
186 «writeRPCs(module.rpcs)»
188 «IF !module.unknownSchemaNodes.nullOrEmpty»
190 «writeUnknownSchemaNodes(module.unknownSchemaNodes)»
192 «IF !module.uses.nullOrEmpty»
194 «writeUsesNodes(module.uses)»
200 def static writeRPCs(Set<RpcDefinition> rpcDefs) {
210 def static writeRPC(RpcDefinition rpc) {
212 rpc «rpc.QName.localName» {
213 «IF !rpc.description.nullOrEmpty»
216 «IF !rpc.groupings.nullOrEmpty»
217 «writeGroupingDefs(rpc.groupings)»
219 «IF rpc.input != null»
220 «writeRpcInput(rpc.input)»
222 «IF rpc.output != null»
223 «writeRpcOutput(rpc.output)»
225 «IF !rpc.reference.nullOrEmpty»
229 «IF rpc.status != null»
236 def static writeRpcInput(ContainerSchemaNode input) {
242 «IF !input.childNodes.nullOrEmpty»
243 «writeDataSchemaNodes(input.childNodes)»
250 def static writeRpcOutput(ContainerSchemaNode output) {
256 «IF !output.childNodes.nullOrEmpty»
257 «writeDataSchemaNodes(output.childNodes)»
263 def static writeNotifications(Set<NotificationDefinition> notifications) {
265 «FOR notification : notifications»
266 «IF notification != null»
267 «writeNotification(notification)»
273 def static writeNotification(NotificationDefinition notification) {
275 notification «notification.QName.localName» {
276 «IF !notification.description.nullOrEmpty»
278 "«notification.description»";
280 «IF !notification.childNodes.nullOrEmpty»
281 «writeDataSchemaNodes(notification.childNodes)»
283 «IF !notification.availableAugmentations.nullOrEmpty»
284 «writeAugments(notification.availableAugmentations)»
286 «IF !notification.groupings.nullOrEmpty»
287 «writeGroupingDefs(notification.groupings)»
289 «IF !notification.uses.nullOrEmpty»
290 «writeUsesNodes(notification.uses)»
292 «IF !notification.reference.nullOrEmpty»
294 "«notification.reference»";
296 «IF notification.status != null»
297 status «notification.status»;
303 def static writeUnknownSchemaNodes(List<UnknownSchemaNode> unknownSchemaNodes) {
304 if (unknownSchemaNodes.nullOrEmpty)
308 «FOR unknownSchemaNode : unknownSchemaNodes»
309 «writeUnknownSchemaNode(unknownSchemaNode)»
314 def static writeUnknownSchemaNode(UnknownSchemaNode unknownSchemaNode) {
315 if (unknownSchemaNode == null)
319 anyxml «unknownSchemaNode.QName.localName» {
320 «IF !unknownSchemaNode.description.nullOrEmpty»
322 "«unknownSchemaNode.description»";
324 «IF !unknownSchemaNode.reference.nullOrEmpty»
326 "«unknownSchemaNode.reference»";
328 «IF unknownSchemaNode.status != null»
329 status «unknownSchemaNode.status»;
335 def static writeUsesNodes(Set<UsesNode> usesNodes) {
336 if (usesNodes == null) {
341 «FOR usesNode : usesNodes»
342 «IF usesNode != null»
343 «writeUsesNode(usesNode)»
349 def static writeUsesNode(UsesNode usesNode) {
350 val hasRefines = !usesNode.refines.empty
353 uses «usesNode.groupingPath.pathFromRoot.head.localName»«IF !hasRefines»;«ELSE» {«ENDIF»
355 «writeRefines(usesNode.refines)»
361 def static writeRefines(Map<SchemaPath, SchemaNode> refines) {
363 «FOR path : refines.keySet»
364 «val schemaNode = refines.get(path)»
365 «writeRefine(path, schemaNode)»
370 def static writeRefine(SchemaPath path, SchemaNode schemaNode) {
372 refine «path.pathFromRoot.last» {
373 «IF schemaNode instanceof DataSchemaNode»
374 «writeDataSchemaNode(schemaNode)»
380 def static writeTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
382 «FOR typeDefinition : typeDefinitions»
383 «IF typeDefinition != null»
384 «writeTypeDefinition(typeDefinition)»
390 def static writeTypeDefinition(TypeDefinition<?> typeDefinition) {
392 type «typeDefinition.QName.localName»;
396 def static writeIdentities(Set<IdentitySchemaNode> identities) {
397 if (identities.nullOrEmpty)
400 «FOR identity : identities»
401 «writeIdentity(identity)»
406 def static writeIdentity(IdentitySchemaNode identity) {
407 if (identity == null)
410 identity «identity.QName.localName» {
411 «IF identity.baseIdentity != null»
412 base "(«writeIdentityNs(identity.baseIdentity)»)«identity.baseIdentity»";
414 «IF !identity.description.nullOrEmpty»
416 "«identity.description»";
418 «IF !identity.reference.nullOrEmpty»
420 "«identity.reference»";
422 «IF identity.status != null»
423 status «identity.status»;
429 def static writeIdentityNs(IdentitySchemaNode identity) {
433 val identityNs = identity.QName.namespace
435 if(!module.namespace.equals(identityNs))
436 return identityNs + ":"
440 def static writeFeatures(Set<FeatureDefinition> features) {
442 «FOR feature : features»
444 «writeFeature(feature)»
450 def static writeFeature(FeatureDefinition featureDef) {
452 feature «featureDef.QName.localName» {
453 «IF !featureDef.description.nullOrEmpty»
455 "«featureDef.description»";
457 «IF !featureDef.reference.nullOrEmpty»
459 "«featureDef.reference»";
461 «IF featureDef.status != null»
462 status «featureDef.status»;
468 def static writeExtensions(List<ExtensionDefinition> extensions) {
470 «FOR anExtension : extensions»
471 «IF anExtension != null»
472 «writeExtension(anExtension)»
478 def static writeExtension(ExtensionDefinition extensionDef) {
480 extension «extensionDef.QName.localName» {
481 «IF !extensionDef.description.nullOrEmpty»
483 "«extensionDef.description»";
485 «IF !extensionDef.argument.nullOrEmpty»
486 argument "«extensionDef.argument»";
488 «IF !extensionDef.reference.nullOrEmpty»
490 "«extensionDef.reference»";
492 «IF extensionDef.status != null»
493 status «extensionDef.status»;
499 def static writeDeviations(Set<Deviation> deviations) {
501 «FOR deviation : deviations»
502 «IF deviation != null»
503 «writeDeviation(deviation)»
509 def static writeDeviation(Deviation deviation) {
511 deviation «deviation.targetPath» {
512 «IF !deviation.reference.nullOrEmpty»
514 "«deviation.reference»";
516 «IF deviation.deviate != null && !deviation.deviate.name.nullOrEmpty»
517 deviation «deviation.deviate.name»;
523 def static writeAugments(Set<AugmentationSchema> augments) {
525 «FOR augment : augments»
527 «writeAugment(augment)»
533 def static writeDataSchemaNodes(Collection<DataSchemaNode> dataSchemaNodes) {
535 «FOR schemaNode : dataSchemaNodes»
536 «writeDataSchemaNode(schemaNode)»
541 def static CharSequence writeGroupingDefs(Set<GroupingDefinition> groupingDefs) {
543 «FOR groupingDef : groupingDefs»
544 «IF groupingDef != null»
545 «writeGroupingDef(groupingDef)»
551 def static writeAugment(AugmentationSchema augment) {
553 augment «formatToAugmentPath(augment.targetPath.pathFromRoot)» {
554 «IF augment.whenCondition != null && !augment.whenCondition.toString.nullOrEmpty»
555 when "«augment.whenCondition.toString»";
557 «IF !augment.description.nullOrEmpty»
559 "«augment.description»";
561 «IF !augment.reference.nullOrEmpty»
563 "«augment.reference»";
565 «IF augment.status != null»
566 status «augment.status»;
568 «IF !augment.childNodes.nullOrEmpty»
569 «writeDataSchemaNodes(augment.childNodes)»
571 «IF !augment.uses.nullOrEmpty»
572 «writeUsesNodes(augment.uses)»
578 def static writeGroupingDef(GroupingDefinition groupingDef) {
580 grouping «groupingDef.QName.localName» {
581 «IF !groupingDef.groupings.nullOrEmpty»
582 «writeGroupingDefs(groupingDef.groupings)»
584 «IF !groupingDef.childNodes.nullOrEmpty»
585 «writeDataSchemaNodes(groupingDef.childNodes)»
587 «IF !groupingDef.unknownSchemaNodes.nullOrEmpty»
588 «writeUnknownSchemaNodes(groupingDef.unknownSchemaNodes)»
594 def static writeContSchemaNode(ContainerSchemaNode contSchemaNode) {
596 container «contSchemaNode.getQName.localName» {
597 «IF !contSchemaNode.childNodes.nullOrEmpty»
598 «writeDataSchemaNodes(contSchemaNode.childNodes)»
600 «IF !contSchemaNode.availableAugmentations.nullOrEmpty»
601 «writeAugments(contSchemaNode.availableAugmentations)»
603 «IF !contSchemaNode.groupings.nullOrEmpty»
604 «writeGroupingDefs(contSchemaNode.groupings)»
606 «IF !contSchemaNode.uses.nullOrEmpty»
607 «writeUsesNodes(contSchemaNode.uses)»
609 «IF !contSchemaNode.unknownSchemaNodes.nullOrEmpty»
610 «writeUnknownSchemaNodes(contSchemaNode.unknownSchemaNodes)»
616 def static writeAnyXmlSchemaNode(AnyXmlSchemaNode anyXmlSchemaNode) {
618 anyxml «anyXmlSchemaNode.getQName.localName»;
622 def static writeLeafSchemaNode(LeafSchemaNode leafSchemaNode) {
624 leaf «leafSchemaNode.getQName.localName» {
625 type «leafSchemaNode.type.getQName.localName»;
630 def static writeLeafListSchemaNode(LeafListSchemaNode leafListSchemaNode) {
632 leaf-list «leafListSchemaNode.getQName.localName» {
633 type «leafListSchemaNode.type.getQName.localName»;
638 def static writeChoiceCaseNode(ChoiceCaseNode choiceCaseNode) {
640 case «choiceCaseNode.getQName.localName» {
641 «FOR childNode : choiceCaseNode.childNodes»
642 «writeDataSchemaNode(childNode)»
648 def static writeChoiceNode(ChoiceSchemaNode choiceNode) {
650 choice «choiceNode.getQName.localName» {
651 «FOR child : choiceNode.cases»
652 «writeDataSchemaNode(child)»
658 def static writeListSchemaNode(ListSchemaNode listSchemaNode) {
660 list «listSchemaNode.getQName.localName» {
661 key «FOR listKey : listSchemaNode.keyDefinition SEPARATOR " "»"«listKey.localName»"
663 «IF !listSchemaNode.childNodes.nullOrEmpty»
664 «writeDataSchemaNodes(listSchemaNode.childNodes)»
666 «IF !listSchemaNode.availableAugmentations.nullOrEmpty»
667 «writeAugments(listSchemaNode.availableAugmentations)»
669 «IF !listSchemaNode.groupings.nullOrEmpty»
670 «writeGroupingDefs(listSchemaNode.groupings)»
672 «IF !listSchemaNode.uses.nullOrEmpty»
673 «writeUsesNodes(listSchemaNode.uses)»
675 «IF !listSchemaNode.unknownSchemaNodes.nullOrEmpty»
676 «writeUnknownSchemaNodes(listSchemaNode.unknownSchemaNodes)»
682 def static CharSequence writeDataSchemaNode(DataSchemaNode child) {
684 «IF child instanceof ContainerSchemaNode»
685 «writeContSchemaNode(child)»
687 «IF child instanceof AnyXmlSchemaNode»
688 «writeAnyXmlSchemaNode(child)»
690 «IF child instanceof LeafSchemaNode»
691 «writeLeafSchemaNode(child)»
693 «IF child instanceof LeafListSchemaNode»
694 «writeLeafListSchemaNode(child)»
696 «IF child instanceof ChoiceCaseNode»
697 «writeChoiceCaseNode(child)»
699 «IF child instanceof ChoiceSchemaNode»
700 «writeChoiceNode(child)»
702 «IF child instanceof ListSchemaNode»
703 «writeListSchemaNode(child)»
708 static def String formatSchemaPath(String moduleName, Iterable<QName> schemaPath) {
709 var currentElement = schemaPath.head
710 val StringBuilder sb = new StringBuilder()
711 sb.append(moduleName)
713 for(pathElement : schemaPath) {
714 if(!currentElement.namespace.equals(pathElement.namespace)) {
715 currentElement = pathElement
717 sb.append(pathElement)
721 sb.append(pathElement.localName)
727 static def String formatToParagraph(String text, int nextLineIndent) {
728 if (text == null || text.isEmpty())
731 var String formattedText = text;
732 val StringBuilder sb = new StringBuilder();
733 val StringBuilder lineBuilder = new StringBuilder();
734 var boolean isFirstElementOnNewLineEmptyChar = false;
735 val lineIndent = computeNextLineIndent(nextLineIndent);
737 formattedText = formattedText.replace("*/", "*/");
738 formattedText = NEWLINE_OR_TAB.removeFrom(formattedText);
739 formattedText = formattedText.replaceAll(" +", " ");
741 val StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
743 while (tokenizer.hasMoreElements()) {
744 val String nextElement = tokenizer.nextElement().toString();
746 if (lineBuilder.length() + nextElement.length() > 80) {
747 if (lineBuilder.charAt(lineBuilder.length() - 1) == ' ') {
748 lineBuilder.setLength(0);
749 lineBuilder.append(lineBuilder.substring(0, lineBuilder.length() - 1));
751 if (lineBuilder.charAt(0) == ' ') {
752 lineBuilder.setLength(0);
753 lineBuilder.append(lineBuilder.substring(1));
756 sb.append(lineBuilder);
757 lineBuilder.setLength(0);
760 if (nextLineIndent > 0) {
761 sb.append(lineIndent)
764 if (nextElement.toString().equals(" "))
765 isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
767 if (isFirstElementOnNewLineEmptyChar) {
768 isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
770 lineBuilder.append(nextElement);
773 sb.append(lineBuilder);
776 return sb.toString();
779 def private static formatToAugmentPath(Iterable<QName> schemaPath) {
780 val StringBuilder sb = new StringBuilder();
782 for(pathElement : schemaPath) {
783 val ns = pathElement.namespace
784 val localName = pathElement.localName
794 private static def computeNextLineIndent(int nextLineIndent) {
795 val StringBuilder sb = new StringBuilder()
797 while (i < nextLineIndent) {