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.yang.wadl.generator
10 import java.io.BufferedWriter
12 import java.io.OutputStreamWriter
14 import java.nio.charset.StandardCharsets
15 import java.util.ArrayList
16 import java.util.HashSet
19 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
20 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
21 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
22 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
23 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
24 import org.opendaylight.yangtools.yang.model.api.Module
25 import org.opendaylight.yangtools.yang.model.api.SchemaContext
26 import org.sonatype.plexus.build.incremental.BuildContext
27 import org.sonatype.plexus.build.incremental.DefaultBuildContext
29 class WadlRestconfGenerator {
32 static val BuildContext CTX = new DefaultBuildContext();
33 static val PATH_DELIMETER = '/'
34 var SchemaContext context;
35 var List<DataSchemaNode> configData;
36 var List<DataSchemaNode> operationalData;
38 var List<LeafSchemaNode> pathListParams;
40 new(File targetPath) {
41 if (!targetPath.exists) targetPath.mkdirs
45 def generate(SchemaContext context, Set<Module> modules) {
46 val result = new HashSet;
47 this.context = context
48 for (module : modules) {
49 val dataContainers = module.childNodes.filter[it|it.listOrContainer]
50 if (!dataContainers.empty || !module.rpcs.nullOrEmpty) {
51 configData = new ArrayList
52 operationalData = new ArrayList
54 for (data : dataContainers) {
55 if (data.configuration) {
58 operationalData.add(data)
63 val destination = new File(path, '''«module.name».wadl''')
64 val fw = new OutputStreamWriter(CTX.newFileOutputStream(destination), StandardCharsets.UTF_8)
65 val bw = new BufferedWriter(fw)
66 bw.append(application);
69 result.add(destination)
75 private def application() '''
77 <application xmlns="http://wadl.dev.java.net/2009/02" «module.importsAsNamespaces» xmlns:«module.prefix»="«module.namespace»">
85 private def importsAsNamespaces(Module module) '''
86 «FOR imprt : module.imports»
87 xmlns:«imprt.prefix»="«context.findModuleByName(imprt.moduleName, imprt.revision).namespace»"
91 private def grammars() '''
93 <include href="«module.name».yang"/>
94 «FOR imprt : module.imports»
95 <include href="«imprt.moduleName».yang"/>
100 private def resources() '''
101 <resources base="http://localhost:9998/restconf">
102 «resourceOperational»
108 private def resourceOperational() '''
109 «IF !operationalData.nullOrEmpty»
110 <resource path="operational">
111 «FOR schemaNode : operationalData»
112 «schemaNode.firstResource(false)»
118 private def resourceConfig() '''
119 «IF !configData.nullOrEmpty»
120 <resource path="config">
121 «FOR schemaNode : configData»
122 «schemaNode.mehodPost»
124 «FOR schemaNode : configData»
125 «schemaNode.firstResource(true)»
131 private def resourceOperations() '''
132 «IF !module.rpcs.nullOrEmpty»
133 <resource path="operations">
134 «FOR rpc : module.rpcs»
135 <resource path="«module.name»:«rpc.QName.localName»">
136 «methodPostRpc(rpc.input != null, rpc.output !== null)»
143 private def String firstResource(DataSchemaNode schemaNode, boolean config) '''
144 <resource path="«module.name»:«schemaNode.createPath»">
145 «resourceBody(schemaNode, config)»
149 private def String resource(DataSchemaNode schemaNode, boolean config) '''
150 <resource path="«schemaNode.createPath»">
151 «resourceBody(schemaNode, config)»
155 private def String createPath(DataSchemaNode schemaNode) {
156 pathListParams = new ArrayList
157 var StringBuilder path = new StringBuilder
158 path.append(schemaNode.QName.localName)
159 if (schemaNode instanceof ListSchemaNode) {
160 for (listKey : schemaNode.keyDefinition) {
161 pathListParams.add((schemaNode as DataNodeContainer).getDataChildByName(listKey) as LeafSchemaNode)
162 path.append(PATH_DELIMETER)
164 path.append(listKey.localName)
171 private def String resourceBody(DataSchemaNode schemaNode, boolean config) '''
172 «IF !pathListParams.nullOrEmpty»
175 «schemaNode.methodGet»
176 «val children = (schemaNode as DataNodeContainer).childNodes.filter[it|it.listOrContainer]»
178 «schemaNode.methodDelete»
179 «schemaNode.mehodPut»
180 «FOR child : children»
184 «FOR child : children»
185 «child.resource(config)»
189 private def resourceParams() '''
190 «FOR pathParam : pathListParams»
191 «IF pathParam != null»
192 «val type = pathParam.type.QName.localName»
193 <param required="true" style="template" name="«pathParam.QName.localName»" type="«type»"/>
198 private def methodGet(DataSchemaNode schemaNode) '''
201 «representation(schemaNode.QName.namespace, schemaNode.QName.localName)»
206 private def mehodPut(DataSchemaNode schemaNode) '''
209 «representation(schemaNode.QName.namespace, schemaNode.QName.localName)»
214 private def mehodPost(DataSchemaNode schemaNode) '''
217 «representation(schemaNode.QName.namespace, schemaNode.QName.localName)»
222 private def methodPostRpc(boolean input, boolean output) '''
226 «representation(null, "input")»
231 «representation(null, "output")»
237 private def methodDelete(DataSchemaNode schemaNode) '''
238 <method name="DELETE" />
241 private def representation(URI prefix, String name) '''
242 «val elementData = name»
243 <representation mediaType="application/xml" element="«elementData»"/>
244 <representation mediaType="text/xml" element="«elementData»"/>
245 <representation mediaType="application/json" element="«elementData»"/>
246 <representation mediaType="application/yang.data+xml" element="«elementData»"/>
247 <representation mediaType="application/yang.data+json" element="«elementData»"/>
250 private def boolean isListOrContainer(DataSchemaNode schemaNode) {
251 return (schemaNode instanceof ListSchemaNode || schemaNode instanceof ContainerSchemaNode)