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) {
318 def static writeUsesNodes(Set<UsesNode> usesNodes) {
319 if (usesNodes == null) {
324 «FOR usesNode : usesNodes»
325 «IF usesNode != null»
326 «writeUsesNode(usesNode)»
332 def static writeUsesNode(UsesNode usesNode) {
333 val hasRefines = !usesNode.refines.empty
336 uses «usesNode.groupingPath.pathFromRoot.head.localName»«IF !hasRefines»;«ELSE» {«ENDIF»
338 «writeRefines(usesNode.refines)»
344 def static writeRefines(Map<SchemaPath, SchemaNode> refines) {
346 «FOR path : refines.keySet»
347 «val schemaNode = refines.get(path)»
348 «writeRefine(path, schemaNode)»
353 def static writeRefine(SchemaPath path, SchemaNode schemaNode) {
355 refine «path.pathFromRoot.last» {
356 «IF schemaNode instanceof DataSchemaNode»
357 «writeDataSchemaNode(schemaNode)»
363 def static writeTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
365 «FOR typeDefinition : typeDefinitions»
366 «IF typeDefinition != null»
367 «writeTypeDefinition(typeDefinition)»
373 def static writeTypeDefinition(TypeDefinition<?> typeDefinition) {
375 type «typeDefinition.QName.localName»;
379 def static writeIdentities(Set<IdentitySchemaNode> identities) {
380 if (identities.nullOrEmpty)
383 «FOR identity : identities»
384 «writeIdentity(identity)»
389 def static writeIdentity(IdentitySchemaNode identity) {
390 if (identity == null)
393 identity «identity.QName.localName» {
394 «IF identity.baseIdentity != null»
395 base "(«writeIdentityNs(identity.baseIdentity)»)«identity.baseIdentity»";
397 «IF !identity.description.nullOrEmpty»
399 "«identity.description»";
401 «IF !identity.reference.nullOrEmpty»
403 "«identity.reference»";
405 «IF identity.status != null»
406 status «identity.status»;
412 def static writeIdentityNs(IdentitySchemaNode identity) {
416 val identityNs = identity.QName.namespace
418 if(!module.namespace.equals(identityNs))
419 return identityNs + ":"
423 def static writeFeatures(Set<FeatureDefinition> features) {
425 «FOR feature : features»
427 «writeFeature(feature)»
433 def static writeFeature(FeatureDefinition featureDef) {
435 feature «featureDef.QName.localName» {
436 «IF !featureDef.description.nullOrEmpty»
438 "«featureDef.description»";
440 «IF !featureDef.reference.nullOrEmpty»
442 "«featureDef.reference»";
444 «IF featureDef.status != null»
445 status «featureDef.status»;
451 def static writeExtensions(List<ExtensionDefinition> extensions) {
453 «FOR anExtension : extensions»
454 «IF anExtension != null»
455 «writeExtension(anExtension)»
461 def static writeExtension(ExtensionDefinition extensionDef) {
463 extension «extensionDef.QName.localName» {
464 «IF !extensionDef.description.nullOrEmpty»
466 "«extensionDef.description»";
468 «IF !extensionDef.argument.nullOrEmpty»
469 argument "«extensionDef.argument»";
471 «IF !extensionDef.reference.nullOrEmpty»
473 "«extensionDef.reference»";
475 «IF extensionDef.status != null»
476 status «extensionDef.status»;
482 def static writeDeviations(Set<Deviation> deviations) {
484 «FOR deviation : deviations»
485 «IF deviation != null»
486 «writeDeviation(deviation)»
492 def static writeDeviation(Deviation deviation) {
494 deviation «deviation.targetPath» {
495 «IF !deviation.reference.nullOrEmpty»
497 "«deviation.reference»";
499 «IF deviation.deviate != null && !deviation.deviate.name.nullOrEmpty»
500 deviation «deviation.deviate.name»;
506 def static writeAugments(Set<AugmentationSchema> augments) {
508 «FOR augment : augments»
510 «writeAugment(augment)»
516 def static writeDataSchemaNodes(Collection<DataSchemaNode> dataSchemaNodes) {
518 «FOR schemaNode : dataSchemaNodes»
519 «writeDataSchemaNode(schemaNode)»
524 def static CharSequence writeGroupingDefs(Set<GroupingDefinition> groupingDefs) {
526 «FOR groupingDef : groupingDefs»
527 «IF groupingDef != null»
528 «writeGroupingDef(groupingDef)»
534 def static writeAugment(AugmentationSchema augment) {
536 augment «formatToAugmentPath(augment.targetPath.pathFromRoot)» {
537 «IF augment.whenCondition != null && !augment.whenCondition.toString.nullOrEmpty»
538 when "«augment.whenCondition.toString»";
540 «IF !augment.description.nullOrEmpty»
542 "«augment.description»";
544 «IF !augment.reference.nullOrEmpty»
546 "«augment.reference»";
548 «IF augment.status != null»
549 status «augment.status»;
551 «IF !augment.childNodes.nullOrEmpty»
552 «writeDataSchemaNodes(augment.childNodes)»
554 «IF !augment.uses.nullOrEmpty»
555 «writeUsesNodes(augment.uses)»
561 def static writeGroupingDef(GroupingDefinition groupingDef) {
563 grouping «groupingDef.QName.localName» {
564 «IF !groupingDef.groupings.nullOrEmpty»
565 «writeGroupingDefs(groupingDef.groupings)»
567 «IF !groupingDef.childNodes.nullOrEmpty»
568 «writeDataSchemaNodes(groupingDef.childNodes)»
570 «IF !groupingDef.unknownSchemaNodes.nullOrEmpty»
571 «writeUnknownSchemaNodes(groupingDef.unknownSchemaNodes)»
577 def static writeContSchemaNode(ContainerSchemaNode contSchemaNode) {
579 container «contSchemaNode.getQName.localName» {
580 «IF !contSchemaNode.childNodes.nullOrEmpty»
581 «writeDataSchemaNodes(contSchemaNode.childNodes)»
583 «IF !contSchemaNode.availableAugmentations.nullOrEmpty»
584 «writeAugments(contSchemaNode.availableAugmentations)»
586 «IF !contSchemaNode.groupings.nullOrEmpty»
587 «writeGroupingDefs(contSchemaNode.groupings)»
589 «IF !contSchemaNode.uses.nullOrEmpty»
590 «writeUsesNodes(contSchemaNode.uses)»
592 «IF !contSchemaNode.unknownSchemaNodes.nullOrEmpty»
593 «writeUnknownSchemaNodes(contSchemaNode.unknownSchemaNodes)»
599 def static writeAnyXmlSchemaNode(AnyXmlSchemaNode anyXmlSchemaNode) {
601 anyxml «anyXmlSchemaNode.getQName.localName»;
605 def static writeLeafSchemaNode(LeafSchemaNode leafSchemaNode) {
607 leaf «leafSchemaNode.getQName.localName» {
608 type «leafSchemaNode.type.getQName.localName»;
613 def static writeLeafListSchemaNode(LeafListSchemaNode leafListSchemaNode) {
615 leaf-list «leafListSchemaNode.getQName.localName» {
616 type «leafListSchemaNode.type.getQName.localName»;
621 def static writeChoiceCaseNode(ChoiceCaseNode choiceCaseNode) {
623 case «choiceCaseNode.getQName.localName» {
624 «FOR childNode : choiceCaseNode.childNodes»
625 «writeDataSchemaNode(childNode)»
631 def static writeChoiceNode(ChoiceSchemaNode choiceNode) {
633 choice «choiceNode.getQName.localName» {
634 «FOR child : choiceNode.cases»
635 «writeDataSchemaNode(child)»
641 def static writeListSchemaNode(ListSchemaNode listSchemaNode) {
643 list «listSchemaNode.getQName.localName» {
644 key «FOR listKey : listSchemaNode.keyDefinition SEPARATOR " "»"«listKey.localName»"
646 «IF !listSchemaNode.childNodes.nullOrEmpty»
647 «writeDataSchemaNodes(listSchemaNode.childNodes)»
649 «IF !listSchemaNode.availableAugmentations.nullOrEmpty»
650 «writeAugments(listSchemaNode.availableAugmentations)»
652 «IF !listSchemaNode.groupings.nullOrEmpty»
653 «writeGroupingDefs(listSchemaNode.groupings)»
655 «IF !listSchemaNode.uses.nullOrEmpty»
656 «writeUsesNodes(listSchemaNode.uses)»
658 «IF !listSchemaNode.unknownSchemaNodes.nullOrEmpty»
659 «writeUnknownSchemaNodes(listSchemaNode.unknownSchemaNodes)»
665 def static CharSequence writeDataSchemaNode(DataSchemaNode child) {
667 «IF child instanceof ContainerSchemaNode»
668 «writeContSchemaNode(child)»
670 «IF child instanceof AnyXmlSchemaNode»
671 «writeAnyXmlSchemaNode(child)»
673 «IF child instanceof LeafSchemaNode»
674 «writeLeafSchemaNode(child)»
676 «IF child instanceof LeafListSchemaNode»
677 «writeLeafListSchemaNode(child)»
679 «IF child instanceof ChoiceCaseNode»
680 «writeChoiceCaseNode(child)»
682 «IF child instanceof ChoiceSchemaNode»
683 «writeChoiceNode(child)»
685 «IF child instanceof ListSchemaNode»
686 «writeListSchemaNode(child)»
691 static def String formatSchemaPath(String moduleName, Iterable<QName> schemaPath) {
692 var currentElement = schemaPath.head
693 val StringBuilder sb = new StringBuilder()
694 sb.append(moduleName)
696 for(pathElement : schemaPath) {
697 if(!currentElement.namespace.equals(pathElement.namespace)) {
698 currentElement = pathElement
700 sb.append(pathElement)
704 sb.append(pathElement.localName)
710 static def String formatToParagraph(String text, int nextLineIndent) {
711 if (text == null || text.isEmpty())
714 var String formattedText = text;
715 val StringBuilder sb = new StringBuilder();
716 val StringBuilder lineBuilder = new StringBuilder();
717 var boolean isFirstElementOnNewLineEmptyChar = false;
718 val lineIndent = computeNextLineIndent(nextLineIndent);
720 formattedText = formattedText.replace("*/", "*/");
721 formattedText = NEWLINE_OR_TAB.removeFrom(formattedText);
722 formattedText = formattedText.replaceAll(" +", " ");
724 val StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
726 while (tokenizer.hasMoreElements()) {
727 val String nextElement = tokenizer.nextElement().toString();
729 if (lineBuilder.length() + nextElement.length() > 80) {
730 if (lineBuilder.charAt(lineBuilder.length() - 1) == ' ') {
731 lineBuilder.setLength(0);
732 lineBuilder.append(lineBuilder.substring(0, lineBuilder.length() - 1));
734 if (lineBuilder.charAt(0) == ' ') {
735 lineBuilder.setLength(0);
736 lineBuilder.append(lineBuilder.substring(1));
739 sb.append(lineBuilder);
740 lineBuilder.setLength(0);
743 if (nextLineIndent > 0) {
744 sb.append(lineIndent)
747 if (nextElement.toString().equals(" "))
748 isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
750 if (isFirstElementOnNewLineEmptyChar) {
751 isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
753 lineBuilder.append(nextElement);
756 sb.append(lineBuilder);
759 return sb.toString();
762 def private static formatToAugmentPath(Iterable<QName> schemaPath) {
763 val StringBuilder sb = new StringBuilder();
765 for(pathElement : schemaPath) {
766 val ns = pathElement.namespace
767 val localName = pathElement.localName
777 private static def computeNextLineIndent(int nextLineIndent) {
778 val StringBuilder sb = new StringBuilder()
780 while (i < nextLineIndent) {