Convert DocumentationGenerator to FileGenerator
[mdsal.git] / binding / maven-sal-api-gen-plugin / src / main / java / org / opendaylight / mdsal / binding / yang / wadl / generator / WadlTemplate.xtend
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  * Copyright (c) 2021 PANTHEON.tech, s.r.o.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9 package org.opendaylight.mdsal.binding.yang.wadl.generator
10
11 import static java.util.Objects.requireNonNull
12
13 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
14 import java.util.ArrayList
15 import java.util.List
16 import org.opendaylight.yangtools.yang.common.XMLNamespace
17 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
18 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
19 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
20 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext
21 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
22 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
23 import org.opendaylight.yangtools.yang.model.api.Module
24
25 final class WadlTemplate {
26     static val PATH_DELIMETER = '/'
27
28     val EffectiveModelContext context
29     val Module module
30     val List<DataSchemaNode> configData = new ArrayList
31     val List<DataSchemaNode> operationalData = new ArrayList
32
33     var List<LeafSchemaNode> pathListParams
34
35     new(EffectiveModelContext context, Module module) {
36         this.context = requireNonNull(context)
37         this.module = requireNonNull(module)
38
39         for (child : module.childNodes) {
40             if (child instanceof ContainerSchemaNode || child instanceof ListSchemaNode) {
41                 if (child.configuration) {
42                     configData.add(child)
43                 } else {
44                     operationalData.add(child)
45                 }
46             }
47         }
48     }
49
50     def body() {
51         if (!module.rpcs.empty || !configData.empty || !operationalData.empty) {
52             return application()
53         }
54         return null
55     }
56
57     private def application() '''
58         <?xml version="1.0"?>
59         <application xmlns="http://wadl.dev.java.net/2009/02" «module.importsAsNamespaces» xmlns:«module.prefix»="«module.namespace»">
60
61             <grammars>
62                 <include href="«module.name».yang"/>
63                 «FOR imprt : module.imports»
64                     <include href="«imprt.moduleName».yang"/>
65                 «ENDFOR»
66             </grammars>
67
68             <resources base="http://localhost:9998/restconf">
69                 «IF !operationalData.nullOrEmpty»
70                 <resource path="operational">
71                     «FOR schemaNode : operationalData»
72                         «schemaNode.firstResource(false)»
73                     «ENDFOR»
74                 </resource>
75                 «ENDIF»
76                 «IF !configData.nullOrEmpty»
77                 <resource path="config">
78                     «FOR schemaNode : configData»
79                         «schemaNode.mehodPost»
80                     «ENDFOR»
81                     «FOR schemaNode : configData»
82                         «schemaNode.firstResource(true)»
83                     «ENDFOR»
84                 </resource>
85                 «ENDIF»
86                 «IF !module.rpcs.nullOrEmpty»
87                 <resource path="operations">
88                     «FOR rpc : module.rpcs»
89                         <resource path="«module.name»:«rpc.QName.localName»">
90                             «methodPostRpc(rpc.input !== null, rpc.output !== null)»
91                         </resource>
92                     «ENDFOR»
93                 </resource>
94                 «ENDIF»
95             </resources>
96         </application>
97     '''
98
99     private def importsAsNamespaces(Module module) '''
100         «FOR imprt : module.imports»
101             xmlns:«imprt.prefix»="«context.findModule(imprt.moduleName, imprt.revision).get.namespace»"
102         «ENDFOR»
103     '''
104
105     private def String firstResource(DataSchemaNode schemaNode, boolean config) '''
106         <resource path="«module.name»:«schemaNode.createPath»">
107             «resourceBody(schemaNode, config)»
108         </resource>
109     '''
110
111     private def String resource(DataSchemaNode schemaNode, boolean config) '''
112         <resource path="«schemaNode.createPath»">
113             «resourceBody(schemaNode, config)»
114         </resource>
115     '''
116
117     private def String createPath(DataSchemaNode schemaNode) {
118         pathListParams = new ArrayList
119         var StringBuilder path = new StringBuilder
120         path.append(schemaNode.QName.localName)
121         if (schemaNode instanceof ListSchemaNode) {
122             for (listKey : schemaNode.keyDefinition) {
123                 pathListParams.add((schemaNode as DataNodeContainer).getDataChildByName(listKey) as LeafSchemaNode)
124                 path.append(PATH_DELIMETER).append('{').append(listKey.localName).append('}')
125             }
126         }
127         return path.toString
128     }
129
130     private def String resourceBody(DataSchemaNode schemaNode, boolean config) '''
131         «IF !pathListParams.nullOrEmpty»
132             «resourceParams»
133         «ENDIF»
134         «schemaNode.methodGet»
135         «val children = (schemaNode as DataNodeContainer).childNodes.filter[it|it.listOrContainer]»
136         «IF config»
137             «schemaNode.methodDelete»
138             «schemaNode.methodPut»
139             «FOR child : children»
140                 «child.mehodPost»
141             «ENDFOR»
142         «ENDIF»
143         «FOR child : children»
144             «child.resource(config)»
145         «ENDFOR»
146     '''
147
148     private def resourceParams() '''
149         «FOR pathParam : pathListParams»
150             «IF pathParam !== null»
151             «val type = pathParam.type.QName.localName»
152             <param required="true" style="template" name="«pathParam.QName.localName»" type="«type»"/>
153             «ENDIF»
154         «ENDFOR»
155     '''
156
157     private static def methodGet(DataSchemaNode schemaNode) '''
158         <method name="GET">
159             <response>
160                 «representation(schemaNode.QName.namespace, schemaNode.QName.localName)»
161             </response>
162         </method>
163     '''
164
165     private static def methodPut(DataSchemaNode schemaNode) '''
166         <method name="PUT">
167             <request>
168                 «representation(schemaNode.QName.namespace, schemaNode.QName.localName)»
169             </request>
170         </method>
171     '''
172
173     private static def mehodPost(DataSchemaNode schemaNode) '''
174         <method name="POST">
175             <request>
176                 «representation(schemaNode.QName.namespace, schemaNode.QName.localName)»
177             </request>
178         </method>
179     '''
180
181     private static def methodPostRpc(boolean input, boolean output) '''
182         <method name="POST">
183             «IF input»
184             <request>
185                 «representation(null, "input")»
186             </request>
187             «ENDIF»
188             «IF output»
189             <response>
190                 «representation(null, "output")»
191             </response>
192             «ENDIF»
193         </method>
194     '''
195
196     private static def methodDelete(DataSchemaNode schemaNode) '''
197         <method name="DELETE" />
198     '''
199
200     private static def representation(XMLNamespace prefix, String name) '''
201         «val elementData = name»
202         <representation mediaType="application/xml" element="«elementData»"/>
203         <representation mediaType="text/xml" element="«elementData»"/>
204         <representation mediaType="application/json" element="«elementData»"/>
205         <representation mediaType="application/yang.data+xml" element="«elementData»"/>
206         <representation mediaType="application/yang.data+json" element="«elementData»"/>
207     '''
208
209     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
210                 justification = "https://github.com/spotbugs/spotbugs/issues/811")
211     private static def boolean isListOrContainer(DataSchemaNode schemaNode) {
212         return schemaNode instanceof ListSchemaNode || schemaNode instanceof ContainerSchemaNode
213     }
214 }