Generate WADL for RPCs
[yangtools.git] / code-generator / maven-sal-api-gen-plugin / src / main / java / org / opendaylight / yangtools / yang / wadl / generator / WadlRestconfGenerator.xtend
1 package org.opendaylight.yangtools.yang.wadl.generator
2
3 import java.io.BufferedWriter
4 import java.io.File
5 import java.io.OutputStreamWriter
6 import java.util.ArrayList
7 import java.util.HashSet
8 import java.util.List
9 import java.util.Set
10 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
11 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
12 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
13 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
14 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
15 import org.opendaylight.yangtools.yang.model.api.Module
16 import org.opendaylight.yangtools.yang.model.api.SchemaContext
17 import org.sonatype.plexus.build.incremental.BuildContext
18 import org.sonatype.plexus.build.incremental.DefaultBuildContext
19
20 class WadlRestconfGenerator {
21         
22         File path
23         static val BuildContext CTX = new DefaultBuildContext();
24         var SchemaContext context;
25         var List<DataSchemaNode> configData;
26         var List<DataSchemaNode> operationalData;
27         var Module module;
28         var List<LeafSchemaNode> pathListParams;
29         val PATH_DELIMETER = "/"
30
31         new(File targetPath) {
32                 if (!targetPath.exists) targetPath.mkdirs
33                 path = targetPath
34         }
35
36         def generate(SchemaContext context, Set<Module> modules) {
37         val result = new HashSet;
38                 this.context = context
39                 for (module : modules) {
40                         val dataContainers = module.childNodes.filter[it|it instanceof ContainerSchemaNode || it instanceof ListSchemaNode]
41                         if (!dataContainers.empty || !module.rpcs.nullOrEmpty) {
42                                 configData = new ArrayList
43                                 operationalData = new ArrayList
44                                 
45                                 for (data : dataContainers) {
46                                         if (data.configuration) {
47                                                 configData.add(data)    
48                                         } else {
49                                                 operationalData.add(data)
50                                         }
51                                 }
52                                 
53                                 this.module = module
54                                 val destination = new File(path, '''«module.name».wadl''')
55                     val fw = new OutputStreamWriter(CTX.newFileOutputStream(destination))
56                     val bw = new BufferedWriter(fw)
57                     bw.append(application);
58                     bw.close();
59                     fw.close();
60                         result.add(destination)
61                         }
62                 }
63                 return result
64         }
65         
66         private def application() '''
67                 <?xml version="1.0"?>
68                 <application xmlns="http://wadl.dev.java.net/2009/02" «module.importsAsNamespaces» xmlns:«module.prefix»="«module.namespace»">
69                 
70                         «grammars»
71                         
72                         «resources»
73                 </application>
74         '''
75         
76         private def importsAsNamespaces(Module module) '''
77                 «FOR imprt : module.imports»
78                         xmlns:«imprt.prefix»="«context.findModuleByName(imprt.moduleName, imprt.revision).namespace»"
79                 «ENDFOR»
80         '''
81         
82         private def grammars() '''
83                 <grammars>
84                         <include href="«module.name».yang"/>
85                         «FOR imprt : module.imports»
86                                 <include href="«imprt.moduleName».yang"/>
87                         «ENDFOR»
88                 </grammars>
89         '''
90         
91         private def resources() '''
92                 <resources base="http://localhost:9998/restconf">
93                         «resourceOperational»
94                         «resourceConfig»
95                         «resourceOperations»
96                 </resources>
97         '''
98         
99         private def resourceOperational() '''
100                 «IF !operationalData.nullOrEmpty»
101                         <resource path="operational">
102                                 «FOR schemaNode : operationalData»
103                                         «schemaNode.firstResource(false)»
104                                 «ENDFOR»
105                         </resource>
106                 «ENDIF»
107         '''
108         
109         private def resourceConfig() '''
110                 «IF !configData.nullOrEmpty»
111                         <resource path="config">
112                                 «FOR schemaNode : configData»
113                                         «schemaNode.firstResource(true)»
114                                 «ENDFOR»
115                         </resource>
116                 «ENDIF»
117         '''
118         
119         private def resourceOperations() '''
120                 «IF !module.rpcs.nullOrEmpty»
121                         <resource path="operations">
122                                 «FOR rpc : module.rpcs»
123                                         <resource path="«module.name»:«rpc.QName.localName»">
124                                                 «methodPostRpc(rpc.input != null, rpc.output !== null)»
125                                         </resource>
126                                 «ENDFOR»
127                         </resource>
128                 «ENDIF»
129         '''
130         
131         private def String firstResource(DataSchemaNode schemaNode, boolean config) '''
132                 <resource path="«module.name»:«schemaNode.createPath»">
133                         «IF !pathListParams.nullOrEmpty»
134                                 «resourceParams»
135                         «ENDIF»
136                         «schemaNode.methodGet»
137                         «IF config»
138                                 «schemaNode.mehodPut»
139                                 «schemaNode.mehodPost»
140                         «ENDIF»
141                         
142                         «IF schemaNode instanceof DataNodeContainer»
143                                 «val children = (schemaNode as DataNodeContainer).childNodes.filter[it|it instanceof ContainerSchemaNode || it instanceof ListSchemaNode]»
144                                 «IF !children.empty»
145                                         «FOR child : children»
146                                                 «child.resource(config)»
147                                         «ENDFOR»
148                                 «ENDIF»
149                         «ENDIF»
150                 </resource>
151         '''
152                 
153         private def String resource(DataSchemaNode schemaNode, boolean config) '''
154                 <resource path="«schemaNode.createPath»">
155                         «IF !pathListParams.nullOrEmpty»
156                                 «resourceParams»
157                         «ENDIF»
158                         «schemaNode.methodGet»
159                         «IF config»
160                                 «schemaNode.mehodPut»
161                                 «schemaNode.mehodPost»
162                         «ENDIF»
163                         
164                         «IF schemaNode instanceof DataNodeContainer»
165                                 «val children = (schemaNode as DataNodeContainer).childNodes.filter[it|it instanceof ContainerSchemaNode || it instanceof ListSchemaNode]»
166                                 «IF !children.empty»
167                                         «FOR child : children»
168                                                 «child.resource(config)»
169                                         «ENDFOR»
170                                 «ENDIF»
171                         «ENDIF»
172                 </resource>
173         '''
174         
175         private def String createPath(DataSchemaNode schemaNode) {
176                 pathListParams = new ArrayList
177                 var StringBuilder path = new StringBuilder
178                 path.append(schemaNode.QName.localName)
179                 if (schemaNode instanceof ListSchemaNode) {
180                         val listKeys = (schemaNode as ListSchemaNode).keyDefinition
181                         for (listKey : listKeys) {
182                                 pathListParams.add((schemaNode as DataNodeContainer).getDataChildByName(listKey) as LeafSchemaNode) 
183                                 path.append(PATH_DELIMETER + "{" + listKey.localName + "}")
184                         }
185                 }
186                 return path.toString
187         }
188         
189         private def resourceParams() '''
190                 «FOR pathParam : pathListParams»
191                         «val prefix = pathParam.type.QName.prefix»
192                         «val type = if (prefix.nullOrEmpty) pathParam.type.QName.localName else prefix + ":" + pathParam.type.QName.localName»
193                         <param required="true" style="template" name="«pathParam.QName.localName»" type="«type»"/>
194                 «ENDFOR»
195         '''
196         
197         private def methodGet(DataSchemaNode schemaNode) '''
198                 <method name="GET">
199                         <response>
200                                 <representation mediaType="application/xml" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
201                                 <representation mediaType="text/xml" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
202                                 <representation mediaType="application/json" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
203                                 <representation mediaType="application/yang.data+xml" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
204                                 <representation mediaType="application/yang.data+json" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
205                         </response>
206                 </method>
207         '''
208         
209         private def mehodPut(DataSchemaNode schemaNode) '''
210                 <method name="PUT">
211                         <request>
212                                 <representation mediaType="application/xml" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
213                                 <representation mediaType="text/xml" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
214                                 <representation mediaType="application/json" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
215                                 <representation mediaType="application/yang.data+xml" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
216                                 <representation mediaType="application/yang.data+json" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
217                         </request>
218                 </method>
219         '''
220         
221         private def mehodPost(DataSchemaNode schemaNode) '''
222                 <method name="POST">
223                         <request>
224                                 <representation mediaType="application/xml" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
225                                 <representation mediaType="text/xml" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
226                                 <representation mediaType="application/json" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
227                                 <representation mediaType="application/yang.data+xml" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
228                                 <representation mediaType="application/yang.data+json" element="«schemaNode.QName.prefix»:«schemaNode.QName.localName»"/>
229                         </request>
230                 </method>
231         '''
232         
233         private def methodPostRpc(boolean input, boolean output) '''
234                 <method name="POST">
235                         «IF input»
236                         <request>
237                                 <representation mediaType="application/xml" element="input"/>
238                                 <representation mediaType="text/xml" element="input"/>
239                                 <representation mediaType="application/json" element="input"/>
240                                 <representation mediaType="application/yang.data+xml" element="input"/>
241                                 <representation mediaType="application/yang.data+json" element="input"/>
242                         </request>
243                         «ENDIF»
244                         «IF output»
245                         <response>
246                                 <representation mediaType="application/xml" element="output"/>
247                                 <representation mediaType="text/xml" element="output"/>
248                                 <representation mediaType="application/json" element="output"/>
249                                 <representation mediaType="application/yang.data+xml" element="output"/>
250                                 <representation mediaType="application/yang.data+json" element="output"/>
251                         </response>
252                         «ENDIF»
253                 </method>
254         '''
255
256 }