2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
3 * Copyright (c) 2021 PANTHEON.tech, s.r.o.
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
9 package org.opendaylight.mdsal.binding.yang.wadl.generator
11 import static java.util.Objects.requireNonNull
13 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
14 import java.util.ArrayList
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
25 final class WadlTemplate {
26 static val PATH_DELIMETER = '/'
28 val EffectiveModelContext context
30 val List<DataSchemaNode> configData = new ArrayList
31 val List<DataSchemaNode> operationalData = new ArrayList
33 var List<LeafSchemaNode> pathListParams
35 new(EffectiveModelContext context, Module module) {
36 this.context = requireNonNull(context)
37 this.module = requireNonNull(module)
39 for (child : module.childNodes) {
40 if (child instanceof ContainerSchemaNode || child instanceof ListSchemaNode) {
41 if (child.configuration) {
44 operationalData.add(child)
51 if (!module.rpcs.empty || !configData.empty || !operationalData.empty) {
57 private def application() '''
59 <application xmlns="http://wadl.dev.java.net/2009/02" «module.importsAsNamespaces» xmlns:«module.prefix»="«module.namespace»">
62 <include href="«module.name».yang"/>
63 «FOR imprt : module.imports»
64 <include href="«imprt.moduleName».yang"/>
68 <resources base="http://localhost:9998/restconf">
69 «IF !operationalData.nullOrEmpty»
70 <resource path="operational">
71 «FOR schemaNode : operationalData»
72 «schemaNode.firstResource(false)»
76 «IF !configData.nullOrEmpty»
77 <resource path="config">
78 «FOR schemaNode : configData»
79 «schemaNode.mehodPost»
81 «FOR schemaNode : configData»
82 «schemaNode.firstResource(true)»
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)»
99 private def importsAsNamespaces(Module module) '''
100 «FOR imprt : module.imports»
101 xmlns:«imprt.prefix»="«context.findModule(imprt.moduleName, imprt.revision).get.namespace»"
105 private def String firstResource(DataSchemaNode schemaNode, boolean config) '''
106 <resource path="«module.name»:«schemaNode.createPath»">
107 «resourceBody(schemaNode, config)»
111 private def String resource(DataSchemaNode schemaNode, boolean config) '''
112 <resource path="«schemaNode.createPath»">
113 «resourceBody(schemaNode, config)»
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('}')
130 private def String resourceBody(DataSchemaNode schemaNode, boolean config) '''
131 «IF !pathListParams.nullOrEmpty»
134 «schemaNode.methodGet»
135 «val children = (schemaNode as DataNodeContainer).childNodes.filter[it|it.listOrContainer]»
137 «schemaNode.methodDelete»
138 «schemaNode.methodPut»
139 «FOR child : children»
143 «FOR child : children»
144 «child.resource(config)»
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»"/>
157 private static def methodGet(DataSchemaNode schemaNode) '''
160 «representation(schemaNode.QName.namespace, schemaNode.QName.localName)»
165 private static def methodPut(DataSchemaNode schemaNode) '''
168 «representation(schemaNode.QName.namespace, schemaNode.QName.localName)»
173 private static def mehodPost(DataSchemaNode schemaNode) '''
176 «representation(schemaNode.QName.namespace, schemaNode.QName.localName)»
181 private static def methodPostRpc(boolean input, boolean output) '''
185 «representation(null, "input")»
190 «representation(null, "output")»
196 private static def methodDelete(DataSchemaNode schemaNode) '''
197 <method name="DELETE" />
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»"/>
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